DC motor with PID closed loop control - Almost there!

So I have been trying to make a PID loop controlled high precision DC geared motor.

Here are the parts I'm currently using:

Arduino Mega Robogaia encoder counter - http://www.robogaia.com/two-axis-encoder-counter-mega-shield-version-2.html Ladyada motor controller 12 DC Geared motor with US Digital encoder - http://www.phidgets.com/products.php?product_id=3262E_0

I'm using the arduino PID library and I nearly have everything working fine. I have tuned it so it is relatively stable, but when it comes to rest at the final set point the output of the PID does not go to zero. It stays at a value just low enough for the motor to not overcome internal friction, but high enough to cause a buzzing in the motor. Here is a video:


I tried putting in an if statement to set the output to zero if the error between the set point and the actual position was zero, but that didn't work flawlessly.

My ultimate goal is to replace the stepper motors on my pan-tilt camera rig with DC motors with encoders. Here is a video of that project if you are interested: https://vimeo.com/51856361

Any help appreciated!

If the I term is non zero the output will reach the destination (otherwise the integral grows and grows). If there is resistance the motor will have to do continuous work to keep position - this may be why its buzzing (your PWM frequency).

Alternatively perhaps its oscillating a little? that might cause a buzz if rapid enough. Tune down the D term to see if it affects it.

I made a simple closed-loop servo once with just a P-term and it worked (bit of jitter)...

So there is no load on the motor, it isn't attached to anything other than the gearbox, and it isn't drifting, the encoder is really accurate so I can see there is no position change. I think what is happening is the motor is getting closer and closer to the setpoint and the output of the pid reduces, but once it gets to a level where the position no longer apears to change it keeps the output steady (just below stiction breakaway), even though it probably needs no output at all. I think one solution would be to up my PWM frequency to something above 20kHz, so that the buzz is inaudible. Also I have added some code to stop power to the motor should the error become low enough for a certain amount of time.

Does anyone know the highest pwm speed possible with an arduino mega and a adafruit motor shield?


Hmm, there's probably a standard workaround for this - add a regular task to reduce the drive level towards zero (the PID should be well able to override this via the I-term).

Hi I'm also working on position control of DC motor with PID. I'm just in the beginning of the work, so may I ask you sth?

  1. you said you are using really accurate encoder, then what is the resolution value? I'm using one with 1024, and I'm curious that it is too accurate that arduino cannot catch the signal. (maybe you used encoder counter not arduino so it might not be the problem.)

  2. If it is possible, can you share the link of PID library or sort of things?

Anyway, thanx for the helpful topic.

My encoder CPR is 360, but the motor rpm is close to 4000 so I have used an encoder counter, it is linked in my first post.

Here is a link to the PID library I am using.


So I changed out my driver for one with a max PWM frequency of 100kHz and I changed a little code to make the arduino mega pwm at 30kHz rather than the default (around 500Hz I think).

The results are good, the motor is silent once it has reached the setpoint, the only noises now is the gear mechanism I think. I'll post a video soon.

4000rpm and 260cpr should be within the capabilities of the Arduino if you use direct port manipulation in the encoder interrupt routine, its about 42us per incoming pulse...

I am also working in PID position control for a dc motor. Which driver of 100kHz are you using?

Brother, Im trying something very similar, can you share your code please. :)