Problems with setting Setpoint and Input for encoder in Pid Position Control

Hi,

For my project, I'm using a PS2 controller left joystick to control my robot going up a slope.

The Goal: I want the robot to brake and maintain its position whenever I release the joystick ( value is 128 when I release joystick). Therefore, I want the PID to execute its task to achieve (Input == Setpoint) until I move the joystick again to continue moving upwards or downwards.

Problem: When I apply PID, I need to set the Input and Setpoint. The Setpoint is the encoder position when I release the joystick (the position when I want the robot to brake and hold its position) However the Input is also the encoder position that is continuously read from the encoder.

Question: How can I program the Setpoint such that the Setpoint does not get updated with the new encoder position, Input? Is there a better way to do this?

Thanks.

The code I'm using is pasted below:

void loop()
{

  int pwmSpeed;

  int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);
    
  Input = encoder0Pos; 
  
  if (Y_axis == 128)
  {
    
    Setpoint = encoder0Pos;
    myPID.Compute();
    analogWrite(pwm, Output);
    
  }
  
  else if (Y_axis > 128)
  {
    pwmSpeed = Y_axis;
    digitalWrite(dir,HIGH);           // set DIR pin HIGH or LOW
    analogWrite(pwm, pwmSpeed);            //analogWrite(pin, value)     
  }
  else
  {
    pwmSpeed = abs(Y_axis-255);
    digitalWrite(dir, LOW);
    analogWrite(pwm, pwmSpeed); 

  }
  
}

Hi,

When your joystick ENTERS the centre position, 128, store the encoder output. You may need to use a tolerance on the 128 as the joystick will not always stop on exactly 128 each time you centre it. When the joystick value is outside the centre position then continue the normal control.

Tom... :)

Hi Tom,

Thanks for the reply.

I did try that and the motor just keeps moving randomly and it didnt follow the joystick anymore. If you could please have a look at my code above. Do you think the Setpoint = encoder0Pos in the IF statement clashes with Input = encoder0Pos in the void loop()? I have some experience with programming but I'm not an expert.

The robot is going up a slope with some weight and therefore the encoder will continuously providing signal to the arduino. But I just need to record the encoder value at the instant when the joystick's value is 128. Not sure why the above code doesnt perform as expected. Am I missing something?

I will take note on the tolerance and modify it in my code.

Hi,

When you have a joystick value of 128, you are continually reading that, which is correct, but you should not be updating the setpoint continually.

Only set the setpoint when the joystick BECOMES 128, not WHILE it is 128.

Also you are using the PID as a speed regulator to your joystick, then trying to use it as a position regulator, the PID characteristics will be different.

Tom.... :)

Your sketch is incomplete. I suspect you have left out the output range setting for your PID and you certainly have not arranged for moving in both directions. Show the whole sketch.

Hi,

Johnwasser, here’s the whole sketch. I’ve tested with PID all equals to zero and I even tried to change it, but somehow the robot doesn’t respond as expected.

Tom, I know that the problem comes from the fact that I’m not sure how to specifically store the encoder value at the instant it BECOMES 128. Do I have to use millis() and compare the signals before and after? But when the robot is initially powered up, the joystick is it rest and it already shows 128 as the first signal.

Thanks.

#define pwm 6           //red wire 
#define dir 7           //yellow wire

#define encoder0PinA  2
#define encoder0PinB  3
volatile unsigned int encoder0Pos = 100;

//PID
#include <PID_v1.h>

//PS2 controller
#include <SoftwareSerial.h>
#include <Cytron_PS2Shield.h>

Cytron_PS2Shield ps2(10, 11); // SoftwareSerial: Rx and Tx pin

//PID
double Setpoint, Input, Output;
double Kp=0, Ki=0, Kd=0;
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);

void setup()
{

  //Motor
  pinMode(pwm,OUTPUT);
  pinMode(dir,OUTPUT);

  //encoder
  pinMode(encoder0PinA, INPUT);
  digitalWrite(encoder0PinA, HIGH); 
  pinMode(encoder0PinB, INPUT);
  digitalWrite(encoder0PinB, HIGH);
  attachInterrupt(0, doEncoder, CHANGE);
 
  
  ps2.begin(9600); // This baudrate must same with the jumper setting at PS2 shield
  Serial.begin(9600); // Set monitor baudrate to 9600

   //turn the PID on
   myPID.SetMode(AUTOMATIC);
}

void loop()
{

  int pwmSpeed;
 
  int Y_axis = ps2.readButton(PS2_JOYSTICK_LEFT_Y_AXIS);
//  Serial.print("Y_axis:");
//  Serial.println(Y_axis);
  
  
  Input = encoder0Pos; 
//  Serial.print("Input:");            
//  Serial.println(Input);
  

  if (Y_axis == 128)
  {
    
    Setpoint = encoder0Pos;
    Serial.print("Setpoint:");
    Serial.println(Setpoint);
    myPID.Compute();
    analogWrite(pwm, Output);
    Serial.print("OUTPUT:");
    Serial.println(Output);

  }
  
  else if (Y_axis > 128)
  {
    pwmSpeed = Y_axis;
    digitalWrite(dir,HIGH);           // set DIR pin HIGH or LOW
    analogWrite(pwm, pwmSpeed);            //analogWrite(pin, value)     
    //Serial.println (encoder0Pos);
  }
  else
  {
    pwmSpeed = abs(Y_axis-255);
//    Serial.print("pwmSpeed: ");
//    Serial.println(pwmSpeed);
    digitalWrite(dir, LOW);
    analogWrite(pwm, pwmSpeed); 

  }
  
}

void doEncoder() {
  int A =  digitalRead(encoder0PinA);
  int B =  digitalRead(encoder0PinB);
  if (A == B) {encoder0Pos++;  }
  else {encoder0Pos--;}
  }

Please, can anyone help me out?

I dont have that much experience in programming. Or should I post this in the programming section instead?

Thanks.