avoid ps2 controller timeout during long functions

Hello to all hobby (or pro) R2D2 artists :slight_smile:

i am working on a robot (guess what based on the Category this topic is in) and i want to control it with a PS2 controller.

so far so good. i can read the controller and move the servos.
but some functions include a bunch of delays to slow down the movements or speed it up, depending on the setting.
this means that executing some of those functions takes approx. 2-4 seconds. during this time no information of the controller is read and it appears to me that it kind of "times out" during this time.

in the text of the example it even says i should read the controller values at least once a second, which i can not do with the functions i want to use.

after the code of the function is through it seems like the controller vals are read again but it also triggers basically all functions associated with the buttons during this time. it makes no difference if i say ButtonPressed, ButtonReleased or use a combination of Button and ButtonPress (hold down one button, e.g. L2 and press a second Button e.g. ArrowUp).

is there a way to circumvent this? either by extending the time until timeout, use a function to read the values during function execution and just dont execute any of those during that time (i have no idea how i would do that), or read the values but prevent the execution of the associated functions during that time?! !?

i am using the PS2X_Lib.

following code is the loop, i spare you all the rest of the functions for easier reading. since the functions are just called when a button is presed or released it should not influence the Controller code except for the delays causing the time-out (at least i think that is what happens)

next disclaimer ;): all the "newButtonState" stuff is me trying to avoid the readings and execution, which failed so far.
i tried using an "if statement" to group all of that and just check which button was changed. same result.

void loop() {
  /* You must Read Gamepad to get new values and set vibration values
     ps2x.read_gamepad(small motor on/off, larger motor strenght from 0-255)
     if you don't enable the rumble, use ps2x.read_gamepad(); with no values
     You should call this at least once a second
  */

  ps2x.read_gamepad(); //read controller and set large motor to spin at 'vibrate' speed


if(ps2x.Button(PSB_L2) ){
    if (ps2x.NewButtonState(PSB_START)) {
      if (ps2x.ButtonReleased(PSB_START)) {       //will be TRUE as long as button is pressed
        Serial.println("Start was released");
      }
    }
    if (ps2x.NewButtonState(PSB_SELECT)) {
      if (ps2x.ButtonReleased(PSB_SELECT)) {
        Serial.println("Select was released");
      }
    }
    if (ps2x.NewButtonState(PSB_PAD_UP)) {
      if (ps2x.ButtonReleased(PSB_PAD_UP)) {     //will be TRUE as long as button is pressed
        Serial.print("Up arrow: Height up: ");
        l_up();
        Serial.println(height[l]);
      }
    }
    if (ps2x.NewButtonState(PSB_PAD_RIGHT)) {
      if (ps2x.ButtonReleased(PSB_PAD_RIGHT)) {
        Serial.print("Right arrow: Speed_up: ");
        speed_up();
        Serial.println(Speed[s]);
      }
    }
    if (ps2x.NewButtonState(PSB_PAD_LEFT)) {
      if (ps2x.ButtonReleased(PSB_PAD_LEFT)) {
        Serial.print("LEFT arrow: Speed_dwn: ");
        speed_dwn();
        Serial.println(Speed[s]);
      }
    }
    if (ps2x.NewButtonState(PSB_PAD_DOWN)) {
      if (ps2x.ButtonReleased(PSB_PAD_DOWN)) {
        Serial.print("DOWN arrow: Height_dwn: ");
        l_dwn();
        Serial.println(height[l]);
      }
    }
      if (ps2x.ButtonPressed(PSB_CIRCLE)) {             //will be TRUE if button was JUST pressed
    Serial.println("Circle just pressed");
    leg_up(1);
  }
  //if (ps2x.NewButtonState(PSB_CROSS))              //will be TRUE if button was JUST pressed OR released
  if (ps2x.ButtonPressed(PSB_CROSS)) {
    Serial.println("X just changed");
    sort_legs();
  }
  if (ps2x.ButtonPressed(PSB_SQUARE)) {            //will be TRUE if button was JUST released
    Serial.println("Square just released");
  }
}
  
  //vibrate = ps2x.Analog(PSAB_CROSS);  //this will set the large motor vibrate speed based on how hard you press the blue (X) button
  /*
    if (ps2x.NewButtonState()) {        //will be TRUE if any button changes state (on to off, or off to on)
    if (ps2x.Button(PSB_L3)) {
      Serial.println("L3 pressed");
    }
    if (ps2x.Button(PSB_R3)) {
      Serial.println("R3 pressed");
    }
    if (ps2x.Button(PSB_L1)) {
      Serial.println("L1 pressed");
    }
    if (ps2x.Button(PSB_R1)) {
      Serial.println("R1 pressed");
    }
    if (ps2x.Button(PSB_TRIANGLE)) {
      Serial.println("Triangle pressed");
      pwm1.setPWM(0, 0, 200);
      delay(1000);
      pwm1.setPWM(0, 0, 350);
      delay(1000);
    }

    }
  */


  if (ps2x.Button(PSB_R2)) { //print stick values if either is TRUE
    Vx = 0.00;
    Vy = 0.00;
    Vz = 0.00;
    Serial.print("Stick Values:");
    Serial.print(ps2x.Analog(PSS_LY) - 127, DEC); //Left stick, Y axis. Other options: LX, RY, RX
    Serial.print(",");
    Serial.print(ps2x.Analog(PSS_LX) - 128, DEC);
    Serial.print(",");
    Serial.print(ps2x.Analog(PSS_RY) - 127, DEC);
    Serial.print(",");
    Serial.println(ps2x.Analog(PSS_RX) - 128, DEC);
    Serial.print("Übergabe an JOY vars: ");
    JoyX = ps2x.Analog(PSS_LY) - 127, DEC;
    JoyY = ps2x.Analog(PSS_LX) - 128, DEC;
    JoyZ = ps2x.Analog(PSS_RX) - 128, DEC;
    Serial.print(Vx);
    Serial.print(Vy);
    Serial.println();
    /* VECTOR WIEDER AUF 0 SETZEN! da ist der fehler!! */

    walk();
  }
  if (ps2x.ButtonReleased(PSB_R2)) {
    sort_legs();
  }


  delay(100);
}

Hi Arne,

I’ve never worked with those controllers, so I can’t really say why the functions have to be called every second (might be a quirk in the library which I don’t assume, might also have something to do with the controller’s internal registers). I am, however, going to offer some potential solutions you could implement to circumvent the issue, ordered by intrusiveness:

  • You could replace the long delays with loops with a millis()-read in the condition. Since the read will probably not take 1 second, you could just try something along these lines:
uint32_t tMillis = millis() + 1000;
// Do whatever read you need to do
ps2x.ButtonPressed(PSB_PAD_LEFT)
while( millis() < tMillis );
  • If you want to seperate the functions from the ‘management’ that is reading the controller, you could constantly call it in your main loop and save states in variables. That sounds unnecessarily complicated, though.
  • Since R2 is probably gonna be relatively large, you could just use a NANO as a translator which outputs the states on GPIO-pins or via I2C/SPI/UART. Probably a bit overkill, but you could effectively leave your code unchanged and just replace the library name.Hope that helped you along. Happy making!

Daniel

that helped :slight_smile:

my “sledgehammer” solution would have been to just put the “read” line in my loops to get the readings without doing anything with it. that will, however bring other complications… with that a change in the button state would not trigger the execution of the respective function. but it would prevent the “time out” or “overflow” or whatever it is that exactly happens there when its not called often enough.

but as far as i understand your “timer” its also the case in your solution… controller is read but nothing is done with the values (as it should be, because the execution of the respective function is still on going).

but that is easy enough to handle in my application. :slight_smile:

(now i just need to fix some minor errors in my math :smiley: )

[btw: nice signature :smiley: ]