# Encoder values for PID control

I'm working on a two-wheeled robot and I'm trying to implement a PID control for the motors. But I have a problem, all sources I found online said I have to calculate the error with my encoder values.

For the robot I'm programming I got 2 functions. One that gets the absolute encoder values and one that gets the speed in ticks/s.

The sources I found didn't specify if I use absolute encoder values or the speed encoder values. I tried both already but it didn't work out too well, so I would like to know if some already have some experience with a motor PID control using the encoders.

This is my PID code I wanted to use:

e_func_r = v_des-v_act_r;

r_mot_r = r_old_r
+ (1/K_P)*(e_func_r-e_old_r)
+ K_I*(e_func_r+e_old_r)/2
+ K_D*(e_func_r-2*e_old_r+e_old2_r);

if(r_mot_r >= 100)
{
r_mot_r = 100;
}
if(r_mot_r <= -100)
{
r_mot_r = 100;
}

r_old_r  = r_mot_r;
e_old2_r = e_old_r;
e_old_r  = e_func_r;

• In your question you are talking about two different kind of controls, one is controlling the position of the encoder (absolute value), and the second one is control on the velocity ticks/s. I don't know what exactly you want to do and what kind of mistakes you get, it would be better to upload your PID code in order to see it. The controller that I made was for velocity but I was actually doing it for the amount of current that I was sending to the motors (PWM). More specific I had a function that calculated the angular velocity of the motor from the PWM that I sent and on that value I cont – nionios Dec 14 '18 at 8:27
• I added my code for the PID control. How did you calculate the angular velocity? – Qilos Dec 14 '18 at 10:04
• You have to provide some information about the values that you send, receive. Are the v_des / v_act_r measured in the same measurement unit? I mean are both in rpms / ticks/s etc. – nionios Dec 14 '18 at 11:07
• HI Qilos and welcome, you need to provide more info to get some help. Do you want to control the position or the speed of the wheel? What is the error you see that tells you that it doesn't "work out to well"? What are the coefficients you used in your PID, maybe they are poorly tunned ? – N. Staub Dec 14 '18 at 13:54

## 2 Answers

The "PID code" you have is not a PID controller. At all. You should have error terms defined as:

error = setpoint - feedback; // Setpoint and feedback should be in the same units.
deltaTime = TimeSinceLastCall(); // Platform/language specific.

proportionalError = error;
integralError = integralError + error*deltaTime;
derivativeError = (error-prevError)/deltaTime;
prevError = error;

controlSignal = (kP*proportionalError) + (kI*integralError) + (kD*derivativeError);


That's a PID controller. I'm not going to go through the code that you posted point-by-point because it's very wrong, to the point that I can't understand how it was intended to work, so I don't really have a rebuttal or explanation to try to help point out where it went wrong. If you want a PID controller, use the error terms as I provided above.

Also, with the original code, the motor control signal is always accumulating. It shouldn't do this, it should instead just be the output of the PID controller. You have:

r_mot_r = r_old_r + <controller output>


when it should just be

r_mot_r = <controller output>


as in:

r_mot_r = controlSignal


where controlSignal is the term I defined in the block of code at the top of this post.

I'll point out that two-wheeled vehicles are non-holonomic platforms, which means you can't just position the actuators (wheels) independently and arrive at a given position and orientation. Going forward 10 blocks and then turning left is not the same as turning left and then going forward 10 blocks! You are going to find that your robot will never go straight without having some kind of absolute position feedback. Wheel encoder feedback is okay for (very) short term, but you will experience drift.

• The error value in the example can only be a numerical value, for example “4”. The amount of information which can be stored in numbers is low. There is not enough entropy in it. As a result, the pid controller on top of such input parameter won't be able to bring the system into a stable state. It's similar to drive a car without observing the street. – Manuel Rodriguez Jan 2 '19 at 7:54
• @ManuelRodriguez - What are you going on about?? The error value in the example can only be a numerical value - Yes of course; this is code intended for use in an actual control system. Please post your own answer and show us how you solve the problem without numbers. Also, the statement the pid controller on top of [a numerical] input parameter won't be able to bring the system into a stable state is completely false. If you're going to make statements like that, please cite some facts. – Chuck Jan 2 '19 at 14:35
• It seems that we have both the opinion that the error value in the sourcecode needs to be a numerical one. That's a good starting point. This restriction is a result from the posted equation. I think, the transformation from a wheeled robot problem into a mathematical equation wasn't handled optimal here. – Manuel Rodriguez Jan 2 '19 at 16:33
• @ManuelRodriguez - Please post the optimal formulation or transformation. – Chuck Jan 2 '19 at 16:36
• @Chuck Thanks for your answer but i dont know if you really can call my controller code wrong, i got it from a book about robotics and it worked finally. The response of the controller is quite fast but one motor gets faster to the desired speed than the other why the robot goes straight after approximatly 1 second but before that it has a little curve. How can i eliminate that error between the motors so that the curve disappears? – Qilos Jan 8 '19 at 15:31

Looking at the code in Embedded Robotics by Thomas Bräunl, DOI: 10.1.1.474.8129 this appears to be an 'optimised' (i.e. difficult to follow) version of an integer PID controller for velocity control.

It sounds like you want control position rather than velocity though, so you need a position PID controller, as described by Chuck♦, which is more directly applicable to your problem and easier to understand.

If you do want a velocity controller however, read on...

The code in question is on page 93, Program 5.7: PID controller code:

static int r_old=0, e_old=0, e_old2=0;
...
e_func = v_des - v_act;    /* error in velocity */
r_mot  = r_old + Kp*(e_func-e_old) + Ki*(e_func+e_old)/2
+ Kd*(e_func - 2* e_old + e_old2);
/* motor output */
r_mot = min(r_mot, +100);  /* limit motor output */
r_mot = max(r_mot, -100);  /* limit motor output */
r_old  = r_mot;            /* store this motor output */
e_old2 = e_old;            /* store last velocity error */
e_old  = e_func;           /* store this velocity error */


In this snippet I've restored the static line (which is important as it shows this is an integer controller and not a floating point controller), left the original max functions in place, as they are easier to understand, and added comments.

In this code, the v_des is the desired velocity per controller period, the v_act is the current actual velocity per controller period.

Your changes appear to be:

• The addition of the _r suffix (presumably to designate the right motor, and I assume there is similar code for the left motor)
• Replacing the max function with a pair of hard coded if statements
• Defining $$K_P$$ in terms of it's reciprocal.

The problem is the last change combined with the fact that we are using integer arithmetic.

Calculating 1/K_P will evaluate to either 0 for K_P>1) and 1 for K_P==1, assuming sensible values of $$K_P>0$$.

So you are effectively turning your Proportional Integral Derivative controller into a Integral Derivative controller for any value of $$K_P$$ other than 1.

If you went back to using K_P directly rather than trying to use (1/K_P) then you should be able to tune your motor for velocity control.