Introduction
Have you ever heard about PID controller?
Refer to: Wikipedia Definition
It is a controller that is widely used in industrial to control various process variables such as temperature, pressure, force, feed rate, flow rate, chemical composition (component concentrations), weight, position, speed, and practically every other variable for which a measurement exists.
In this article, I focus on using PID to control position and speed of Brushed DC motor.
What decides performance of a PID controller?
Performance of PID is decided by Kp, Ki and Kd gain (coefficients for the proportional, integral, and derivative terms). Each system has its own optimal PID gain. Finding the best PID gains is difficult task. Therefore, we usually use an acceptable gain. This link give an illustration of impact of Kp, Ki and Kd on system
The process of finding value of these parameters is called "tuning". PID controller can manually tuning and auto-tuning...
- Manually tuning: This method requires experienced personnel
- Auto-tuning: the tuning is done by a software.
PID gain from auto-tuning is not the best gain. You can manually fine-tune based on PID gain from auto-tuning.
Thing used in this project
- Arduino Uno or Mega + USB cable
- PHPoC Shield R2 or PHPoC WiFi Shield R2
- DC Motor Controller - PES-2604
- A DC motor with encoder
- Power supply for DC motors (DC Adapter 4 ~ 18V)
- Power supply for Arduino (USB cable or DC adapter)
- Jumper wires
System Architecture of PID Controller
PID is closed-loop system, we need a feedback from DC motor. Therefore, to use PID control, DC motor need to has an encoder.
Encoder will output the signal, which is used to calculated the real position and speed. The calculation of position and speed is performed by DC motor controller. DC motor sends the calculated value (called feedback value) back to Arduino. Library on Arduino will perform adjustment based on the feedback value, desired value, Kp, Ki and Kd gain, and staling factor. after adjusting, Arduino send command along with PWM duty-cycle value to DC motor controller, DC motor will output PWM signal to control DC motor. This process is repeated in a infinite loop.
Wiring
- Stack PHPoC Shield or PHPoC WiFi Shield on Arduino
- Stack DC motor controller PES-2604 on PHPoC Shield or PHPoC WiFi Shield
- Connect the terminal block of DC motor controller to DC motor and power supply for DC motor as follows:
- Terminal Block - VM <----> (+) wire - power supply for DC motor
- Terminal Block - GND <----> (-) wire - power supply for DC motor
- Terminal Block - M1+ <----> (+) wire - DC motor
- Terminal Block - M1- <----> (-) wire - DC motor
- (Optional) Connect the encoder port of DC motor controller to encoder pin of DC motor as follows:
- Encoder 1 - 5V <----> Vcc - Encoder of DC motor
- Encoder 1 - GND <----> GND - Encoder of DC motor
- Encoder 1 - 1A <----> A phase - Encoder of DC motor
- Encoder 1 - 1B <----> B phase - Encoder of DC motor
Encoder 1 is located on the upper row of encoder port. More detail is here
Examples
Note that, different motor has different characteristics. You may need to adjust some parameters such as:
- Scaling factor: void setScaleFactor(float scaleFactor)
- PWM Period: void setPeriod(long period)
- Limit of integral: setIntegralLimit(long min, long max)
- Limit of integral Term: void setIntegralTermLimit(long min, long max)
to meet your system requirement.
Position Control
Source Code (you can also find this code on Arduino IDE -> File -> Examples -> Pid Controller -> DcPIDPosition)
Code:
// PID Controller - Control Position of DC Motor Example // Tutorial is available here: https://forum.phpoc.com/blogs/iot-lover/1289-arduino-pid-controller-auto-tuning-library-and-example-for-dc-motor #include <Phpoc.h> #include <PhpocExpansion.h> #include <Pid.h> DcMotorPID dcPid1(1, 1); //DcMotorPID dcPid2(1, 2); long targetPosition; long position; int count = 0; void setup(){ Serial.begin(9600); while(!Serial) ; //Phpoc.begin(PF_LOG_SPI | PF_LOG_NET); Phpoc.begin(); Expansion.begin(460800); dcPid1.setPeriod(10000); dcPid1.setEncoderPSR(64); dcPid1.setDecay(0); dcPid1.setFilterFrequency(5000); dcPid1.setScaleFactor(16); // depending on motor, should test manually to have the best value dcPid1.setIntegralLimit(-6000, 6000); dcPid1.begin(PID_POSITION); /*----------- check enc pol-------------- */ int pwm = 0; long position = 0; while(!position) { pwm += 10; dcPid1.setWidth(pwm); position = dcPid1.getEncoderPosition(); delay(1); } if(position < 0) dcPid1.setEncoderPolarity(-1); dcPid1.setWidth(0); //dcPid1.setGain(24.099171193725, 10.78947680748, 0.0617886); /* PID auto-tuning */ dcPid1.beginTune(); while(!dcPid1.loopTune()) ; dcPid1.setEncoderPosition(0); //Serial.print(F("PID TUNED Kp: ")); Serial.println(dcPid1.getKp()); //Serial.print(F("PID TUNED Ki: ")); Serial.println(dcPid1.getKi()); //Serial.print(F("PID TUNED Kd: ")); Serial.println(dcPid1.getKd()); Serial.print(F("Target_Position")); Serial.print(" "); Serial.println(F("Real_Position")); } void loop(){ if(count == 0) targetPosition = 3000; else if(count == 1000) targetPosition = 4000; else if(count == 2000) targetPosition = -2000; if(count < 3000) { position = dcPid1.loop(targetPosition); //position = dcPid1.getEncoderPosition(); Serial.print(targetPosition); Serial.print(" "); Serial.println(position); count++; } }
- Compile and upload code to Arduino
- Open Serial Monitor
- Wait until motor stops
- Copy the log in Serial Monitor, paste it to Excel, and plot it
In the example, setpoint of position is changed. No overshoot occurs
Note that: Since the result is depended on characteristics of each DC motor, if the result is not so good, you can adjust other parameters such as Scaling Factor, Limit of integral, Limit of integral term, PWM Period.
Speed Control
Source Code (you can also find this code on Arduino IDE -> File -> Examples -> Pid Controller -> DcPIDSpeed)
Code:
// PID Controller - Control Position of DC Motor Example // Tutorial is available here: https://forum.phpoc.com/blogs/iot-lover/1289-arduino-pid-controller-auto-tuning-library-and-example-for-dc-motor #include <Phpoc.h> #include <PhpocExpansion.h> #include <Pid.h> DcMotorPID dcPid1(1, 1); //DcMotorPID dcPid2(1, 2); int targetSpeed; int speed; int count = 0; void setup(){ Serial.begin(9600); while(!Serial) ; //Phpoc.begin(PF_LOG_SPI | PF_LOG_NET); Phpoc.begin(); Expansion.begin(460800); dcPid1.setPeriod(10000); dcPid1.setEncoderPSR(64); dcPid1.setDecay(0); dcPid1.setFilterFrequency(5000); dcPid1.setScaleFactor(8); // depending on motor, should test manually to have the best value dcPid1.setIntegralLimit(-80000, 80000); dcPid1.setIntegralTermLimit(-2000, 2000); dcPid1.begin(PID_SPEED); //dcPid1.setGain(1, 0.1, 0); /* PID auto-tuning */ dcPid1.beginTune(); while(!dcPid1.loopTune()) ; //Serial.print(F("PID TUNED Kp: ")); Serial.println(dcPid1.getKp()); //Serial.print(F("PID TUNED Ki: ")); Serial.println(dcPid1.getKi()); //Serial.print(F("PID TUNED Kd: ")); Serial.println(dcPid1.getKd()); delay(2000); Serial.print(F("Target Speed")); Serial.print(" "); Serial.println(F("Real Speed")); } } void loop(){ if(count == 0) targetSpeed = 3000; else if(count == 1000) targetSpeed = 5000; else if(count == 2000) targetSpeed = 1000; if(count < 3000) { speed = dcPid1.loop(targetSpeed); //speed = dcPid1.getSpeed(); Serial.print(targetSpeed); Serial.print(" "); Serial.println(speed); count++; } else { dcPid1.setWidth(0); } }
- Compile and upload code to Arduino
- Open Serial Monitor
- Wait until motor stops
- Copy the log in Serial Monitor, paste it to Excel, and plot it
In the example, setpoint of speed is changed.
Note that: Since the result is depended on characteristics of each DC motor, if the result is not so good, you can adjust other parameters such as Scaling Factor, Limit of integral, Limit of integral term, PWM Period.
Library Code
PID_Controller.zip
I attached the example code and library.
Please check it again.
If you have any question, please feel free to comment here!
PHPoC Shield R2 or PHPoC WiFi Shield R2 and using another controller? like L298N
and i checked the "library code" but there is only [ATTACH]n1618[/ATTACH]
thank you
For library download, could you please recheck it?