PID control of position

I need to control the rotational position of a small gearhead motor. The motor has a quadrature encoder which supplies about 1024 pulses per revolution. The motor shaft needs to be positioned over a range of about 15 turns or 15000 encoder counts. The motor is connected to a MD23 board and I'm able to control the motor and read its position over the i2c connection.

I'm planning to use the PID_Beta6 library. Should I set the SETPOINT to the desired encoder count and supply the actual encoder value as INPUT or make the SETPOINT zero and supply the difference between current and desired encoder values as INPUT? Does it matter?

I am using a Duemilanove (AT328). Any idea of the time required to process a PID update? What would be a reasonable value for SetSampleTime?

I don't think PID is what you need as it's designed for continous control as when you are using the encoder feedback pulses to determine speed and the PID would control to a fixed setpoint desired RPM.

Sound like you want to have the motor turn a predetermined amount and then stop based on the total count and direction from the encoder. I would think you would just use a software counter that is incremented or decremented based on the encoder feedback and stop the motor when the number of encoder steps have passed?

Not sure what kind of motor driver a MD23 is, do you have a link? If this is a simple DC or AC motor then it might be somewhat tricky being able to stop at a precise position. A stepper motor would be the easiest to be able to turn a predetermined number of turns and stop.


See for some data on the board. The motor is a small brushed DC motor with 1:141 planetary gearbox. At full speed the output shaft is about 60rpm.

The reason for considering PID is that there is considerable inertia in the load driven by the motor so whatever I do has to deal with overshoot. Perhaps PID is overkill or not appropriate?

Perhaps PID is overkill or not appropriate?

I think it's not appropriate. Again do you wish to move a certain amount and then stop or continuous speed? Continuous speed would certainly be something PIC control would handle fine, but moving a certain direction and speed and stopping at precise position is not PID type control.


I need to move and stop, move and stop... It is desirable to move as quickly as possible and stop at precise shaft positions.

A stepper would work well except I haven't found an inexpensive source of small steppers with an appropriate gear reduction. My load is about 300 grams and the gearhead motor with encoder is about 60mm by 16mm diameter but easily moves the load. It is much smaller than even a NEMA-17 stepper and does not require continuous power to maintain its position.

I agree with Lefty (what are the odds?!) that the PID Library is probably WAY overkill for this.

that being said, you could totally do it.

Setpoint = desired position Input = current position (no need to compute the difference. the pid does that internally) Output = signal to the motor. since you'll need to be able to spin the motor in both directions, you may need to use a technique similar to the one I detailed here:

Lastly, with respect to tuning parameters. if you do the output method described above, you should be able to get away with a P-Only controller. that is: P_Param = something, I_Param=0, D_Param = 0

Now let's circle back to why you probably don't need to use a pid. You could get the same performance as the P-only controller by doing this:

motorSpeed = (some_factor) * (Desired_Position - Current_Position)
 //spin one way at motorSpeed
 //spin the other way at -motorSpeed

I'm all for people using the pid library, but it is quite big. I'd say try the above code first, then move onto pid if needed.


Before posting here I wrote some code similar to your example. It works but due to the inertia of the load there is considerable damped oscillation about the stopping point. Also, I was hoping that the "D" term might let me achieve faster positioning.

The motor needs to rotate in both directions (forward, stop, forward, stop, reverse, stop...) so I definitely need to be able to command it both ways.

Any suggestions regarding an appropriate update interval if I use your PID library?

Also, I was hoping that the “D” term might let me achieve faster positioning.

That’s a great point. PD is used pretty often in motor control applications. I had forgotten that. The bulk of my pid experience is in control of large chemical processes.

Any suggestions regarding an appropriate update interval if I use your PID library?

As a rule of thumb, I like to have the pid evaluate at least 10 times before it gets to the new setpoint. this isn’t an industry standard or anything, but in my experience it works.

Another method would be to start small (10mS say) and make it larger and larger until performance degrades.


Well I still don’t see how PID would apply. What would the setpoint represent in this application, that is, can it hold number of revolutions desired as well as the position to stop within a revolution? What does the PV represent from the encoder, just rate of speed or speed and position? I just think there are more then a single PV and single setpoint involved here. Or maybe I just can’t apply classic PID to the desired application. It would seem that there would have to be some dynamic control on top of the PID to make it work?

It would seem more like a batch control operation. It’s at say position 25 degrees and the new move should be 648 degrees clockwise and stop and then next move might be 932 degrees counterclock wise and stop?

I was assuming that the encoder was returning an absolute position between 0-15000, with the setpoint being a desired position somewhere in that range.

in that scenario, the pid would keep adjusting its output (motor speed/direction) until input (position) = setpoint (desired position)

For my motor the encoder is a quadrature unit so it provides direction and count data but not, strictly speaking, absolute position. The motor control board keeps track of the pulses and maintains the position as a 32-bit signed value. You can read the current position (actually cumulative angle moved since the last reset) via i2c.

Since the motor will be running backwards and forwards the position range will be approximately 0-15000.

I was assuming that the encoder was returning an absolute position between 0-15000, with the setpoint being a desired position somewhere in that range.

He stated in his first posting that he desired movement up to 5 revolutions in either direction and then stop at some point.

A quadurature encoder is not an absolute encoder and even if it was, an absolute encoder only handles 0-360 degree range then repeats each complete revolution regardless of its resolution. Just seems that there would be a need for some external hardware or software to convert the raw encoder data to fit a classic single setpoint value.


I think this is one of those situations where assumptions are a killer. all my statements are based on an assumed input variable. something that represents the absolute motor position somewhere in that 5 revolution range. I know that that's not what a motor sends, but it's usually pretty easy to take when the motor DOES send and turn it into something like that.

I think it might be time to show some code Ken :) that way we'll be on the same page.

That is exactly the situation. The encoder+motor control board maintains a value that is the position of the motor in the range of 0-15000. The board looks after accumulating the quadrature encoder's step and direction information so that all the Arduino software needs to do is request the position value.

Things sorta work with the PID library but not as well as my previous efforts of merely comparing current position versus desired and commanding the motor appropriately. Without a large value for P the motor stops somewhat before the setpoint. If P is too large things are unstable.

Without a large value for P the motor stops somewhat before the setpoint. If P is too large things are unstable.

you may be experiencing a phenomenon known as "offset." it can occur in non-I controllers if the internal baseline (known as the bias) is improperly initialized.

Not sure if that is what is happening here, but just a thought. Before you switch the pid to Auto, make sure the output variable = 0 (assuming that 0 is "all stop")

Hi all!

I have no information about this MD23 board. Regarding to the position control, I must say that there is no need to write any PID loop for position. The simplest way to do that is to set an speed set-point equal to the position error or just proportional to this error. Most industrial CNC's and some simple PLC-based position controllers work like this. The only trick uses to be the speed loop, which uses to require PI control, and the instantenous position set-point.

Best Regards,


I made the suggested change to setting Output prior to enabling Auto for the PID library. This appears to have fixed the offset problem. After a few hours of "tuning", everything works well but not significantly better than my original simple code. The simple code with non-linear proportional control works reasonably well and is about 4K smaller than the PID library.

I've learned a lot but think that I'll stick with my original code. Thanks to everyone for their advice!


This are good news, then! Congratulations for all this learning! ;)

If you read any classic Control Systems book, you will see that this is like a DC motor position control. According to this, you can regulate speed and sometimes current and spped is the first order derivate of position... :P Too hard, isn't it?

Ok! So just an speed set-point proportional to error is good!!! You only need to set a good proportional constant because if it is too high the system becames unstable: the motor will continuously oscillate around one position.

Good Luck!


I'm building a robotic arm with 4 dc motors and encoders. Should I use the PID beta6 library from the playground to do this or does someone recommend something else? I need to control position and speed for each motor.