Arduino : DC Motor Speed Control using PID
Welcome to the third instalment of the Arduino Series, where I will show you how to implement various concepts of Control Theory in order to control different aspects of a motor device.
Note: This task requires some basic PID knowledge (You can read more about this in the previous Arduino blog)
In this one, I will show you how to control a motor so that it will be able to reach and more importantly maintain a desired speed (in RPM). There can be cool applications of this technique , such as self-balancing systems This was again part of the same project that I did over summer, which was a self-control balancing flywheel pendulum. The basics of the PID system that we will be implementing is the same as the previous position control blog, with there being three tuning constants : Kp (Proportional) , Ki (Integral) and Kd (Derivative) . These constants will be tried and tested in order to get the right combination for a DC motor to be able to meet and maintain at a set RPM speed that the user can input.
The code involved will be very similar to the Position Control post but instead of calculating the position of the DC motor, we will be calculating the RPM speed using the encoder count readings. The formula that we will be using for converting encoder counts to RPM is as follows:
RPM = ((1/LOOPTIME x 1000) / CPR) x 60
where CPR stands for Counts Per Revolution and is PPR x 4 (since we are using quadrature encoder). The LOOPTIME is basically the inverse of frequency (1/f) and we want to times by 1000 to give it in kHz. This is also the loop time we want to set in the loop function when driving the motor and updating its info. The specific quadrature encoder that I used for my flywheel project was 1000 PPR and so CPR is 4000. Finally we times by 60 to make it per minute.
After we have declared our variables and set a required speed in RPM, everything else in the main code is the same as the previous position control post where we calculate our quadrature encoder counts (void Achange() and Bchange() ) and set our PID terms to produce an overall PWM value (void findMotorData())to drive a motor to reach a steady state. Please note that in this project of mine, I didn't use an integral term since it wasn't necessary when experimenting with the constant values. In the loop function, we update our PWM drive value every 100 milliseconds. Finally I added a debugging function (void printMotorInfo()) to update the serial port with the current RPM values of the motor at the end of the each loop.
Here is the full code: