Bidirectional PID Motor control - wont ease out

I am using an H Bridge and the standard PID library. Motor is changing directions fine, and the motion is smooth when it leaves.
However when it stops, the PID Output value goes suddently to 0 even if the input is decreasing gradually as it should. I wonder what am I missing?

I used various Kp and Ki, the same results.

Here is my function:

void ShoulderFunction(int ShoulderInput, double Kp, double Ki)
{
int DirectionShoulder = (ShoulderInput - ShoulderEncoderVal );
InputShoulder = abs (DirectionShoulder/100);///1000);

SetpointShoulder = 0;
// /*
//Serial.print(" DirectionShoulder = “);
// Serial.print( DirectionShoulder);
//Serial.print(” “);
Serial.print(” ShoulderEncoderVal = “);
Serial.print( ShoulderEncoderVal);
Serial.print(” ");
Serial.print("Knob= “);
Serial.print(newKnob);
Serial.print(” ");
Serial.print("InputShoulder= “);
Serial.print(InputShoulder);
Serial.print(” “);
Serial.print(“outputShoulder=”);
Serial.print(OutputShoulder);
Serial.println(” ");
// Serial.print(“BasePotVal=”);
// Serial.println(BasePotVal);
//*/
if ( DirectionShoulder > 3) // looking left
{ ShoulderPID.SetTunings (Kp, Ki, 0);
ShoulderPID.SetOutputLimits(1, 150) ;
ShoulderPID.SetMode(AUTOMATIC);
ShoulderPID.Compute();

analogWrite(ShoulderUpPin, (256 - OutputShoulder));
analogWrite(ShoulderDnPin, 256);
}

else if ( DirectionShoulder < -3) // looking Right
{
ShoulderPID.SetTunings (Kp, Ki, 0);
ShoulderPID.SetOutputLimits(1, 150) ;
ShoulderPID.SetMode(AUTOMATIC);
ShoulderPID.Compute();
analogWrite(ShoulderUpPin, 256);
analogWrite(ShoulderDnPin, (256 - OutputShoulder));
}
else {
//BaseRotEncoder.write(0);
StopShoulder();
}
}

void StopShoulder()

{ OutputShoulder = 0; /// do nothing zone
ShoulderPID.SetTunings (0, 0, 0);
ShoulderPID.SetMode(MANUAL);
analogWrite(ShoulderUpPin, 256);
analogWrite(ShoulderDnPin, 256);
}

Please help,

thanks

I would like to help but I’m not understanding exactly what ShoulderPID.Compute ( ) ; is affecting due to the variables being attached by reference elsewhere in your code.

If you are using PID_v1 you may want to make changes only when the calculation is actually happening.

if(ShoulderPID.Compute()){ // has the time period actually elapsed for the pid to do a computation?
    analogWrite(ShoulderUpPin, 256); // << not sure why this is here
    analogWrite(ShoulderDnPin, (256 - OutputShoulder));
}

Z

Thanks for your interest.

Shoulder is the shoulder of a robot arm with an encoder feedback.

The H Bridge stops motor at a logical 1, or an analog write of 256.
It reaches full speed at a LOW or analog write of 0. (The H bridge manufacturer recommended a min val of 1)

so when I go:
analogWrite(ShoulderUpPin, 256); // << not sure why this is here
analogWrite(ShoulderDnPin, (256 - OutputShoulder));

The first line tells the H Brige "dont go Up at all,
The second line tells it “go down the computed value”. This value increases in time nicely based on the Ki, giving me a ease in start.

When the direction changes the opposite happens.

Then there is the stop shoulder - do nothing zone, when is close to the target.
void StopShoulder()

{ OutputShoulder = 0; /// do nothing zone
ShoulderPID.SetTunings (0, 0, 0);
ShoulderPID.SetMode(MANUAL);
analogWrite(ShoulderUpPin, 256);// dont go up
analogWrite(ShoulderDnPin, 256);// dont go down
}

In this situation I reset the PID to manual so all values are dropped to 0, so I get new calculations when the UP or down conditions happen.
Hope this clarifies it.

Lots of lines for doing something rather simple, but thats the best I could do.

laptophead:
Thanks for your interest.

Shoulder is the shoulder of a robot arm with an encoder feedback.

The H Bridge stops motor at a logical 1, or an analog write of 256.
It reaches full speed at a LOW or analog write of 0. (The H bridge manufacturer recommended a min val of 1)

so when I go:
analogWrite(ShoulderUpPin, 256); // << not sure why this is here
analogWrite(ShoulderDnPin, (256 - OutputShoulder));

The first line tells the H Brige "dont go Up at all,
The second line tells it “go down the computed value”. This value increases in time nicely based on the Ki, giving me a ease in start.

When the direction changes the opposite happens.

Then there is the stop shoulder - do nothing zone, when is close to the target.
void StopShoulder()

{ OutputShoulder = 0; /// do nothing zone
ShoulderPID.SetTunings (0, 0, 0);
ShoulderPID.SetMode(MANUAL);
analogWrite(ShoulderUpPin, 256);// dont go up
analogWrite(ShoulderDnPin, 256);// dont go down
}

In this situation I reset the PID to manual so all values are dropped to 0, so I get new calculations when the UP or down conditions happen.
Hope this clarifies it.

Lots of lines for doing something rather simple, but thats the best I could do.

Helps allot. I’ll need to know which H-bridge you are using. I am not familiar with this method of driving the motors on. A schematic would help also. Thanks