in short, I want to implement a PID controller that takes in distance and returns velocity.

Details: I am simulating robots following each other. I wish to maintain a constant distance, d between these robots. I can obtain the distance between the robots at any time and then I can adjust the velocity of the following robot accordingly. My problem is the formulation that achieves the transformation of the information provided by the PID to velocity so as to achieve this constant distance. My current attempt is to use the error provided by the PID as the velocity for the following robot, that is;

v2 = e(t) where v2 is the velocity of the second/following robot and e(t) is the error yielded by the PID at time t.

The problem with this approach is that it vehicle velocity is only as big as the error, so that way velocity only increases if the error increases, so if the constant distance I want is relatively small. I can never achieve this.

I also tried using the error as the acceleration, with the idea that the velocity should only grow as error grows and decrease in a similar fashion according to:

v2 = v2 + e(t) * dt

where 'dt' is the change in time.

But then when I get negative errors. I wish to avoid reversing or backward motion. So we can call it a stop-go implementation if possible. But ideally when the error in the desired distance reduces ultimately both velocities will be moving with the same velocity. Any approaches and suggestions will be highly appreciated. Thanks very much. I am doing all implementation tests in python. If more clarification is needed please let me know.


Forget PID at first. If we assume PID, we're skipping steps.

Write down what we know. From your description:

  • process variable : position
  • input : (other robot's position - following distance)
  • loop output : this robot's position
  • plant input : velocity
  • plant output : this robot's position
  • plant dynamics : simple integrator

Now we can draw a system diagram:


Note that we left out two very important things: limits on velocity and acceleration. But for now, let's neglect these so we can solve the inside case, when those limits are not reached. In reality, the performance experienced by the user will very much be determined by the edge cases where those limits are in effect.

In a typical PID, G=1 and F = the PID expression.

We can get both stability and zero steady state error for this system with just PI.

A PI controller has a form

F = Kp ( 1 + 1/((Ti)s) ) and G=1

For convenience of analysis, and let's use an alternate form. (The Kp will be different, but no loss of generality. This is still a PI controller)

F = (Kp/s)(1+(Tz)s) and G=1

This form makes the zero in the forward path clearly visible, at s=-1/Tz. The zero in the forward path will remain in the closed loop transfer function, and thus produce step response overshoot, which is not desired per the problem statement.

We can get the exact same loop stability by keeping the product FG constant, while eliminating the step response overshoot, (although slower response). Thus we refactor FG into:

F = (Kp/s) and G = (1+(Tz)s)

Now we have deviated from the PI controller, this is slightly different, even though it results in the same stability expression for the complete loop (denominator of closed loop transfer function).

As an optional last step, we can also rearrange the loop into the so-called pseudo-derivative form to get rid of the possibly-troublesome derivative, this rearrangement is shown below.

enter image description here

The rest of the work is about implementing decent saturation and anti-windup logic for the large signal issues. This isn't entirely trivial, and is the real "secret sauce" in some control situations.

  • $\begingroup$ hello. thanks @pete, but u have it backwards. Plant input is actually the distance for the following robot to the front robot. The output is supposed to be the velocity of the following robot. $\endgroup$
    – guthik
    Apr 30 at 12:21
  • $\begingroup$ @guthik, you sure you aren't thinking of the "controller input = distance" and "controller output = velocity"? $\endgroup$
    – Pete W
    Apr 30 at 12:50
  • $\begingroup$ i don't get what you are trying to mean by that $\endgroup$
    – guthik
    Apr 30 at 13:24
  • $\begingroup$ @guthik ... Ok, at the end of the day, are you are interested in the position of the robot, right? If so, the output of the plant is, by definition, position. The controller tells the plant what to do. example image $\endgroup$
    – Pete W
    Apr 30 at 13:29
  • $\begingroup$ oh yes. thats true. $\endgroup$
    – guthik
    Apr 30 at 14:19

Let me just reiterate some points that I understood from your problem:

  • e(t) is the distance from the target distance. So if e(t) = 0.5 and you want to maintain 1m distance b/w robots current distance is 1.5m correct?
  • You said PID is giving this error which I didn't understand. I believe your approach is correct just needs some corrections.

Instead of using just the error or acceleration you should use both. So you can use this code:

# you need to try different values and tune PID
kp = a 
kd = b
ki = c 
ki_error = 0
# defining a variable to keep error at (t-1) time  
prev_error = 0
def pid_control(e(t)):
    kp_error = kp * e(t)
    kd_error = kd * (e(t) - prev_error)/dt
    ki_error += ki * e(t)

    total_error = kp_error + kd_error + ki_error
    if total_error < 0 :
         total_error = 0 # for your problem of keeping the car going in reverse
    return total_error

Explanation :

  • kp_error will give higher error (thus higher velocity) the further apart they are
  • kd_error will give higher error (thus higher velocity) based on how quickly the error increases
  • ki_error will sum small error and will be able to keep a constant distance no matter how small

The problem with this approach is that it vehicle velocity is only as big as the error, so that way velocity only increases if the error increases, so if the constant distance I want is relatively small. I can never achieve this.

This hopefully will solve your problem if tuned properly. general rule of thumb is kp> kd> ki but feel free to tune further according to your needs.

  • $\begingroup$ hello thanks. yeah, if e(t) = 0.5 then the distance is 1.5m but if e(t) = -0.5 then distance is actually 0.5m. Am not confusing the error for the output. I have both the output and error. It seems you just made the error the output of the pid. But thanks nonetheless. $\endgroup$
    – guthik
    Apr 29 at 15:35
  • $\begingroup$ yes i have made the error the output of pid, but it is being modified by the values of kp, kd and ki. So, you could directly put the total_error as velocity. v2 = v2 + total_error. I had a similar project and it worked for me so you can try it. $\endgroup$ Apr 30 at 6:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.