# Motor controller software design

I have to design a PID controller for a differential drive robot.

• The hardware board consists of a AVR atmega168 running at 16mhz.
• Driven by two 24v scooter motors with 256 CPR encoders
• The motors spin roughly at about 4700 RPM and has a 51.56:1 gear ratio

So far I can read the encoder direction and the tick count. But I have no idea how to convert this to speed. And eventually a PID controller. I also want to be able to rotate the robot at a given angle. Can someone please help me to get started ?

Currently I am having problems figuring out a suitable timer calculation for this.

• well .. you can differentiate position to get speed; if you measure the angle at say, 50 times per second, then you know how far it's turned in 1/50th of a second, so 50 times that would be degrees (or whatever angular unit you use) per second. Nov 19, 2011 at 1:00
• change in count/angle over time? Nov 19, 2011 at 1:02
• Are the encoders before or after the gearboxes? (Presumably before, but ...) Nov 19, 2011 at 9:57
• please break up into separate specific questions Mar 30, 2012 at 11:40
• For a PID controller: you may wish to read this pair of blog entries I wrote: embeddedrelated.com/showarticle/121.php Mar 30, 2012 at 11:41

Thanks everyone for the useful comments.

I achieved what I wanted by implementing a simple velocity PID controller.

Through two interrupts (for each encoder) I calculated how much encoder ticks have been accumulated at a given time interval. The interval i used was 10ms and this was achieved by using the timer compare feature on timer1 of the AVR mcu. Encoder ticks were calculated by taking the difference of the previous encoder ticks and the current ticks. This was then used as the velocity PV of the PID controller. The PID controller sampling rate was also done at 10ms. Just to keep things simple.

I wrote a simple MATLAB gui to graph the SP, PV of the step response of the PID controller. This is how I manually tuned the PID controller. It may not be the best way but certainly the simplest way I could think of to tune the controller.

I will document this on my blog post when I get a chance and will put a link to it on this post so it will be helpful for anyone.

Your question is a little ambiguous. Are you asking how to use a timer on the microcontroller, or are you asking how to calculate angular speed given the count from an encoder and elapsed time given by a timer?

The atmega168 should have at least two timers on it. If my memory serves me correctly there are two 8-bit timers and one 16-bit timer. These are integrated peripherals in the micro which can run in the background leaving your micro's CPU free to do other stuff.

One way to do this is: (a) Initialize and start the timer and reset the encoder counter (b) write an interrupt service routine (ISR) that gets called when as the timer ends, restarts the timer, and calculates angular speed. (c) Write another ISR that is triggered by the encoder output tick and that increments a global tick counter. (d) in the timer ISR you know the elapsed time since the last call since when you initialized the timer you specified this. You have the number of encoder ticks since the last timer ISR call. Therefore, you can calculate the ticks per unit time. You should know from the mechanical details of your robot the number of ticks per unit angle of wheel rotation, thus, you should be able to calculate the angular speed of the wheel. Reset the tick counter within the timer ISR after performing the speed calculation so that next time the timer ISR is called you will have the new count of encoder ticks.

This gets you the average angular speed within the timer period. Adjust the period of the timer to work well for your application.

This is only one way of doing this. I can imagine others. I found this algorithm worked well for me before however.

This is going to be fairly tricky to do for two motors, as you have to watch two encoder channels per motor. Not impossible, but a lot of really careful coding to be sure you don't miss any transitions of either channel of the encoder on either motor (ie, you have 4 things to watch for events, and while there's correlation between the channels there's none between the motors). There would be some temptation to give each motor its own microcontroller or use a quadrature counter chip to capture the feedback (or make your own in a cheap CPLD).

Since you want to be able to turn precise angles presumably by differential rotation of the two wheels, I'd consider making a pair of position controllers rather than a speed controllers, each of which would rotate its motor to equalize the counts achieved to the counts in a desired position register. To simplify things, your primary command interface could be a signed number (of at least 16 bits, but probably 24 or even 32) to be added to the desired position each controller is seeking.

At a higher level, you would then have a motion planner, which would periodically use this to update the desired positions. When moving at a fixed velocity, you just issue a command for another n steps every m milliseconds, when speeding up or slowing down you toss in fewer. To turn you send a positive number to one and a less positive (or for on the spot, negative) to the other. Conceptually this is the same regardless if your communicating between logical blocks in a program on one processor, or commanding slave processors.