Designing a PID Motor Controller using PIC16F876
From the first robot I ever made, I have always felt that when designing the motors, wheels and drive train, it will almost always be important to know where you are – that is, to have some sort of encoder feedback. So the first robot I built used stepper motors, but I found that they were difficult to deal with because of the complex drive circuit required, and they are usually under-powered. It’s also difficult to get a smooth speed ramp with them, and if they ‘skip’, that is, you send them five pulses and they only move three or four because of over-torque, an obstacle, etc, then you will never know it. Not to mention the processing overhead required to generate two pulse-trains with different frequencies (one for each wheel). The next logical step is to go with a servo motor (the word servo designates any motor that has a position-feedback mechanism. For this article, I will be referring to a standard brush DC motor with encoder feedback, rather than the hobby R/C servos with potentiometer feedback). Having closed-loop control of a motor with true encoder feedback allows a much higher degree of accuracy when controlling and reading the position of your motor. The challenges involved with this method are:
- Adding an encoder to your motor or wheel
- Allocating the processing power to keep track of all these pulses and actively control the motor.
- Designing or finding the power side of the motor driver circuit, such as an H-bridge
Recently it seems like it is getting easier to find fairly good motors with built-in encoders, or encoders that can easily be attached to a drive shaft or wheel, that make the first item easier than it has been in the past. Several people have published quadrature black/white printable patterns to stick on to wheel, to provide encoder feedback. Check out the excellent SRS Encoder article by David Anderson, http://www.seattlerobotics.org/encoder/200109/dpa.html. This article has the postscript code to make encoders as well. As for the second and third items, allocating a chip or board just for controlling your motor, there are several options:
- Buy an LM629 precision motor control chip for $30. This chip does full PID control of position, velocity and acceleration. Requires ~15 lines of I/O to talk to it, and takes about 75-100mA of current just to run this chip. Need to design your own board to mate it to an H-Bridge circuit and a master processor such as a PIC or large Stamp.
- Buy a Motor Mind II, for $30. This is a speed controller and H-bridge combined, which is a good value. Great for controlling velocity of motors up to 2 Amps, but since it only has a tachometer input, rather than full quadrature encoder input, you never really know which direction the motor is going, just the speed of the pulses. This means that for accurately tracking position, and for “locking on” to a certain position or coordinate, the Motor Mind is not the best choice.
- Make a home-brew PID controller and H-bridge combination board
As you may have guessed, I opted for number 3: Make my own. Actually my first choice, as mentioned above, was to go with stepper motors. Then I went with two LM629s paired with LMD18200 3A H-bridges. Because of the 8-bit data bus on the LM629, I needed a lot of I/O lines to talk to it, so I used a 40-pin PIC. Those five chips alone cost me over $95, and I hadn’t even made a board yet! I ended up assembling the parts on a PIC proto board I got free from Microchip when I attended a seminar. It was point-to-point soldered and ugly, but the thrill I got when it was finally working has really stuck in my mind, and motivated me to make this solution cheaper and simpler by doing some development of my own. Since PICs are cheap, I thought if I spent enough time and research, I could program a PIC to do almost everything that LM629 does. I also figured that since I’m going to invest the time and money to research the PID algorithms and make a custom board, that I may as well make it as flexible and useable as possible, so others can use it in their designs.
The base processor is a PIC16F876, which is a 28-pin PIC processor, running at 20MHz. It is paired with an LMD18200 H-bridge, which can drive 3A continuous loads, 5A peak. I have set the base requirements for the software and hardware as follows (many of these requirements came from the goal of emulating the capabilities of the LM629 chip):
- 32-bit registers to hold fixed point position variables (up to +/8 million encoder counts)
- Optional “tachometer” mode, which allows using the circuit with single encoders, rather than full quadrature encoders. For many applications, speed control is enough, and it greatly simplifies finding/making quad encoders
- 16-bit factors to hold Kp, Ki, and Kd constants
- 10-bit PWM resolution for motor output power/speed control
- High speed encoder capture logic (up to 254,000 counts/sec, or encoder pulses as fast as 2us wide). For an encoder with 1200 counts/revolution, speeds up to 12,700 rpm are possible
- True real-time PID control with adjustable filter constants
- Trapezoidal Trajectory Profile processing (constant accel ramp, constant velocity cruise, then constant decel rampdown)
- Storage of up to 24 trajectory profiles in flash EEPROM
- Fast PID recalculation, updating approx every 510 usec.
By starting with these requirements, I began formulating the skeleton of the software algorithms and hardware requirements, which eventually led to the selection of the particular processor to use, and the software feature set that I could support. I have designed the prototype PC board, and while waiting for it to arrive, I have successfully made a breadboard version of the circuit, as a platform for software development.
To capture the rapid quadrature encoder counts, I used the Timer/Counter inputs on the PIC. Unfortunately these inputs only count in the Up direction, so I used a D Flip-Flop to decode the encoder pulses into two streams: one for up-direction counts, and one for down-direction counts. Then every update cycle I simply subtract the down counts from the up counts, and get the net distance change. This distance change becomes the actual velocity, since it is a distance change in a fixed period of time. It is added to the current 32-bit position register. The error term is calculated by subtracting the current position from the target position. Here’s the current version of the schematic diagram (this is not finalized):
For more detail: Designing a PID Motor Controller using PIC16F876
We recommend EasyEDA for electronic circuit design.
From Schematic Drawing to PCB Production, Just Need One Tool
Cheap PCB Prototype: 10 pcs 2 layers only $10, quick delivery, 100% E-test
Current Project / Post can also be found using:
- pid controller using pic16f877a
- pic 16f876 control motor checkout