G4P sliders not updating during multiple calculations in Button Controller

edited December 2015 in Library Questions

G4P sliders not updating during calculations in Button Controller

Here is the problem I am having and have not been able to resolve this problem. Tried several solutions but no luck and have been working on this issue for several days.

I created a Button in Setup with no problem and it executes with no issue. The commands in the button are as follows:

public void button1_click1(GButton source, GEvent event) { //_CODE_:button1:289466:
  ScriptEnabled = 1;

  move_to_xyz(13.64, 0, 3.5849);
  movePosition();
  delay(5000);

  move_to_xyz(14.64, 0, 3.5849);
  movePosition();
  delay(5000);

  GripperFixedPitchAngle();

  delay(5000);  
  ScriptEnabled = 0;

} //_CODE_:button1:289466:

The move_to_xyz(xxx, yyy, zzz) function calculates 6 angles for a robot and seems to work fine to calculate the values correctly. The movePosition() function commands the servos to move to the angles calculated from move_to_xyz(). The movePosition() function is shown below:

void movePosition() {
  float t0, t1, t2, t3;
  int flag0, flag1, flag2, flag3;

  flag0 = flag1 = flag2 = flag3 = 0;
  t0 = t1 = t2 = t3 = 0.0;

  GripperFixedPitchAngle();
  //updateFK();

  for( int ii = 0; ii < 6; ii++) {
    print(q[ii]*180/3.1451); print("    "); }
  println(); println();

  t0 = (float) q[0]*rad2deg;
  t1 = (float) q[1]*rad2deg;
  t2 = (float) q[2]*rad2deg;
  t3 = (float) q[3]*rad2deg;

  //Failsafe to avoid going beyond angle limits,i.e., set stops
  if(t0 < -80 || t0 > 80) flag0 = 1;
  if(t1 < 10 || t1 > 160) flag1 = 1;
  if(t2 < -150 || t2 > 45) flag2 = 1;
  if(t3 < 0 || t3 > 180) flag3 = 1;

  if((flag0+flag1+flag2+flag3) == 0 ) {
    slider1.setValue(t0);
    slider3.setValue(t2);
    slider2.setValue(t1);
    slider4.setValue(t3);
  } 
}

Changes to the slider result in command to the servos to move. Below is the code for the one of the sliders (all others are the same except that the servo number changes:

public void slider1_change1(GSlider source, GEvent event) { //_CODE_:slider1:790724:
    myPort.clear();
    myPort.write("0,"+slider1.getValueI()+"\n");   
    acknowledge();

    GripperFixedPitch();    

    if(FKenable == 1)  updateFK();

  }

} //_CODE_:slider1:790724:

The issue is that the sliders will not update until after the Button controller is completed and only the last move is displayed. Not sure how to fix the problem, i.e., getting the sliders to move so the arm can move at each move command is sent to the slider. By the way moving the sliders individually work fine to move the arm.

I also tried moving the commands to the draw() with the button just setting a flag but the sliders still did not update.

Any help would be appreciated.

Answers

  • edited December 2015

    The issue is that the sliders will not update until after the Button controller is completed and only the last move is displayed.

    The first thing to say is this is not a fault in G4P it is caused by Java's event handling mechanism.

    In Java when an event is generated it is placed on the end of the event queue (FIFO queue - first in first out). The events are processed in the order they were placed on the queue (i.e. the order generated) and an event is not processed until ALL preceding events have been processed.

    Your button click event handler will take at least 15 seconds to finish (due to 3 five second delays) and during that time generated events will be placed on the event queue but will NOT be processed until the current event has finished.

    The important thing here is that the code inside an event handler should execute as quickly as possible otherwise the application becomes sluggish.

    One possible solution would be to create a boolean variable to indicate when the button has been presses

    public void button1_click1(GButton source, GEvent event) { 
        buttonClick = true; // new boolean variable
    } 
    

    Create a separate method (NOT in the gui tab) for the code to be executed i.e.

    public void processButtonClick() {
      ScriptEnabled = 1;
    
      move_to_xyz(13.64, 0, 3.5849);
      movePosition();
      delay(5000);
    
      move_to_xyz(14.64, 0, 3.5849);
      movePosition();
      delay(5000);
    
      GripperFixedPitchAngle();
    
      delay(5000);  
      ScriptEnabled = 0;
    }
    

    Now in draw() add this code

    if(buttonClick){
        processButtonClick();
        buttonClick = false;
    }
    

    Obviously I can't test this but it has moved the length code execution out of the event thread which is good programming practice.

  • edited December 2015 Answer ✓

    It's still wrong! Function delay() shouldn't be relied on for controlling Processing's "Animation Thread" once draw() starts! [-X

    If it's some ongoing process w/ total time of 15 seconds for example, most correct way is do some piece of it for each draw() callback.

    However, if you really wanna stick w/ that delay() shortcut, at least do it via thread():
    https://Processing.org/reference/thread_.html

    boolean buttonClicked, buttonBusy;
    
    void draw() {
      if (buttonClicked) {
        thread("processButtonClick");
        buttonClicked = false;
      }
    }
    
    void button1_click1(GButton source, GEvent event) { 
      if (!buttonBusy)  buttonClicked = true;
      else System.err.println("Button Busy! Still processing servo...");
    }
    
    void processButtonClick() {
      buttonBusy = true;
    
      for (int i = 0; i != 1; ++i) {
        move_to_xyz(13.64 + i, 0, 3.5849);
        movePosition();
        delay(5000);
      }
    
      gripperFixedPitchAngle();
      delay(5000);
    
      buttonBusy = false;
    }
    
  • Thanks for the quick reply. I appreciate the added info and not just a possible solution. I figured the problem was I was missing something in the way things worked.

    Anyway back to the issue at hand - I changed the code as you suggested and no luck. The sliders still only change after second move. The delays where only there for debugging to make sure I had time to kill the power to arm if something went wrong so i tried reducing the time and even removing the dalays but same situation. If you are interested here is a link to the whole program as it stands. I modified it so that it is standalone.

    https://drive.google.com/folderview?id=0BwzZjH9KYYMDcmZhcTJHbU0tb1E&usp=sharing

    Thanks for your assistance - really would like to get this piece of it to work correctly.

  • @GoToLoop, Sorry I missed your comment. The above comment was in regards to @quark suggested change. I will post when i give it a try.

  • @GoToLoop, I changed your code and it work fine but when i add a second move it still only shows the second move. This occurs even shortening the delay or removing the delay. The issue is that when additional moves are added the sliders only update at last move.

  • edited December 2015

    Got no idea what had been changed! The example I've left above only allows to be re-invoked after 15 seconds! @-) Therefore I don't see how a 2nd "move" can be "added" during that delay() time. :-\"

  • Please archive the standalone sketch (Tools menu) and send the zip file to me by email. I will send PM with my email address. Don't know when I will get a chance to play with it, mght be this afternoon but if not it will be in New Year.

  • @GoToLoop - i changed i != 1 to i !=2 or 3. I then deleted the for loop and put in the individual moves. I also played around with the delays. That is how i changed the loop.

    Anyway I redid it this morning using the standalone that I posted and for some strange reason it is working now like a charm. Was late last night so I must have did something wrong. I even added a textarea to as a test. Just have to figure out how to put a new line into it. I am going to test the change on the realtime version and see what happens.

    Thanks for your help -

Sign In or Register to comment.