I've read numerous posts (1 , 2, 3 ) about using PID to control motors. All examples I've seen deal with the control signal being in the same units as the measurement signal. For example, use PID to set PWM values and measure PWM values as feedback or read stepper motor values in encoder clicks and then set new motor values also in clicks.

What I'm not understanding is how does one use PWM as the control when the measurements are in Encoder Clicks as would be common on a DC brush motor with encoder. How does the output of the PID taking Clicks as input, outputs and setpoint get translated to an appropriate 0 to 255 PWM signal (Assuming 8-bit PWM)?

It seems like there's a fundamental disconnect between the encoder clicks which can be though of as velocity (change of distance over time) vs PWM control signal which is an amount of power provided to the motor.

My naive guess would be to:

  1. Determine the MAX encoder clicks per second at a given PWM value of 255 emperically.
  2. Determine the MIN encoder value for the PWM value right before the motor stops moving under load. (For example my Pololu motors need at least 60 PWM on my motor controller to actually turn, below that value they just 'whine'.)
  3. Linearly map the encoder readings from the MIN and MAX to an appropriate MIN and MAX PWM reading?
// Using the Arduino PID library
encoderLow = 60;   // determined empirically
encoderHigh = 8400;// determined empirically
PWMLow = 60; // determined empirically
PWMHigh = 255;  // PWM as which we reach encoderHigh

Input = reading_from_encoder();  // clicks per second
Setpoint = 1000; // also in clicks
PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
translated_pwm = map(Output, encoderLow, encoderHigh, PWMLow, PWMHigh) 
drive_motor(translated_pwm); // control signal to motor as PWM value.

Where Input (the feedback from the encoders), Setpoint, and Output are in clicks. Output is the control signal from the Arduino PID library


  1. Is this the normal approach?
  2. My map() function assumes a linear relationship between encoder values and PWM values. I doubt that's true. Is the PID going to compensate for the nonlinearities?
  3. What is the correct way to do this?

You are correct that for PID your output and input should be in the same unit, generally position or velocity. You will need a way to convert your encoder input to that unit, which should be the same unit as your setpoint.

The arduino PID library appears to abstract this for you.

| improve this answer | |
  • $\begingroup$ Thanks. I'm not sure I see how the Arduino library abstracts the conversion. It does reference 0-255 PWM values as a 'default' range, but I don't see anything that otherwise helps convert between the units of position or velocity for input and set points and output as a PWM signal. It seems to assuming input, output, and setpoint are all expressed in PWM values. ?? Perhaps I'm misunderstanding the code. $\endgroup$ – Phil Glau Aug 1 at 3:52

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.