This post was last edited by DDZZ669 on 2021-5-20 22:34 The previous articles (Basics of Motor Control) introduced the principles of motor encoders, timer output PWM, timer encoder mode speed measurement, etc. Based on the previous articles, this article continues to learn motor control, uses the PID algorithm to control the speed of the motor, and conducts experimental tests. # 1 PID Basics PID is the abbreviation of Proportional, Integral, and Differential. PID is a classic closed-loop control algorithm with the advantages of simple principle, easy implementation, wide application, independent control parameters, and relatively simple parameter selection. PID will be of great use wherever a physical quantity needs to be "kept stable" (such as maintaining balance, stabilizing temperature, speed, etc.).
## 1.1 PID algorithm classification PID algorithm can be divided into two categories: position PID and incremental PID. In actual programming applications, it is necessary to use a discrete PID algorithm to adapt to the computer environment. Let's take motor speed control as an example to look at the basic principles of the two PID algorithms. ### Position PID Position PID is the deviation between the actual position of the current system and the expected position to be achieved, and PID control is performed
- Proportional P: e(k) This error - Integral I: ∑e(i) Accumulated error - Differential D: e(k) - e(k-1) This error - Last error Because of the error integral ∑e(i), it is accumulated all the time, that is, the current output u(k) is related to all past states. **The pseudo code of the positional PID algorithm is as follows**: ```c //Positional PID (pseudo code) previous_err = 0; integral = 0; loop: //According to the target value and the measured value (such as the set speed of the motor and the speed after the encoder is read), cyclically calculate and update the output value (such as PWM) error = setpoint - measured_value; /*Error term: target value - measured value*/ integral += error * dt; /*Integral term: accumulation of error term*/ derivative = (error - previous_error) / dt; /*Derivative term: rate of change of error*/ output = Kp*error + Ki*integral + Kd*derivative; /*The three terms are multiplied by the PID coefficient to obtain the output*/ previous_err = err; //Update error wait(dt); //Wait for a fixed calculation period goto loop; ``` ### Incremental PID ![539052](/data/attachment/forum/202105/19/001435fhskf6pkyvcpz777.png.thumb.jpg) - Proportional P: e(k) - e(k-1) Current error - Last error - Integral I: e(k) Current error d - Differential D: e(k) - 2e(k-1)+e(k-2) Current error - 2×Last error + Last error Note that the incremental PID first calculates Δu(k), and then adds it to the last output to get the output result. The incremental PID has no error accumulation, and the determination of the control increment Δu(k) is only related to the last three sampling values. **The pseudo code of the incremental PID algorithm is as follows**: ```c //Incremental PID (pseudo code) previous02_error = 0; //Previous deviation previous01_error = 0; //Last deviation integral = 0; //Integral and pid_out = 0; //PID incremental accumulation and loop: error = setpointmeasured_value; /*Error term: target value - measured value*/ proportion = error - previous01_error; /*Proportional term: error term - last deviation*/ integral = error * dt; /*Integral term: accumulation of error term*/ derivative = (error2*previous01_error + previous02_error) / dt;/*Derivative term: rate of change of last error and the previous error*/ /*Or written as: derivative = ( (errorprevious01_error)/dt - (previous01_error - previous02_error)/dt )*/ pid_delta = Kp × error + Ki × integral + Kd × derivative; //Calculate the PID increment pid_out = pid_out + pid_delta; //Calculate the final PID output previous02_error = previous01_error; //Update the previous deviation previous01_error = error; //Update the previous deviation wait(dt); //Wait for a fixed calculation cycle goto loop; ``` ## 1.2 The role of each PID item Take this spring as an example (assuming there is no gravity, only air resistance), first at the **equilibrium position (target position)**, pull it, and then let go, then it will oscillate.
### P Proportional **P means proportional**. Here is an analogy to the elastic force (restoring force) of the spring: `F=k*Δx` - When the object is farther away from the equilibrium position, the elastic force is greater, and vice versa, the closer to the equilibrium position, the smaller the force. - When the block is above the equilibrium position, the elasticity is downward, and when the block is below the equilibrium position, the elasticity is upward, that is, the elastic force always makes the block exert force towards the equilibrium position. ### D Differential/derivative/rate of change is only controlled by P, the block is always oscillating up and down, and the whole system is not particularly stable. This is because the air resistance is too small. Imagine putting it in water, the block should be stationary soon. This is because of the effect of **resistance**. **The effect of D is equivalent to resistance**: - It is related to the speed of change (the amount of change per unit time). The greater the change, the greater the resistance it exerts - Its direction has nothing to do with the target value. For example, *when the block passes the equilibrium position from bottom to top*, its direction is always downward, that is, it first prevents the block from approaching the equilibrium position, and then prevents the block from moving away from the equilibrium position (compared with the effect of P, which always prevents the block from moving away from the equilibrium position) - Its role is to reduce the overshoot of the system (reduce the oscillation of the system at the equilibrium position) ### I Integration/error accumulation With the power of P and the resistance of D, the block can stabilize quickly, so what is the role of I? Imagine that if there are other external forces, at a certain moment, when the block is about to reach the equilibrium position, the power of P and the external force (the constant force in the opposite direction of P) are offset, then the block will stop near this place (because the force of D is also approaching 0 at this time, and will soon become 0), and it will never reach the equilibrium position. At this time, the error integral of I is very necessary: - It calculates the accumulation of errors, as long as there is an error, it will continue to increase, it may be small at the beginning, but as long as the equilibrium position is not reached, the value will become larger and larger- Its role is to eliminate the static error of the system## 1.3 PID parameter tuning practical application, when adjusting PID parameters, the trial and error method is generally used, and the PID parameter tuning formula is as follows: > Parameter tuning to find the best, check from small to large, > > **First the proportion and then the integral, and finally add the differential, > > The curve oscillates frequently, the **proportional** dial should be enlarged, > > The curve floats around a large bend, the **proportional** dial is turned down, > > The curve deviation is slow to recover, the **integral** time is reduced, > > The curve fluctuation period is long, the **integral** time is further extended, > > The curve oscillates quickly, first reduce the **differential**, > > The dynamic difference is large and the fluctuation is slow, the **differential** time should be extended, > > The ideal curve has two waves, the first high and the second low 4 to 1, > > One look, two adjustments and more analysis, the adjustment quality will not be low. # 2 Motor PID speed control The above introduces the basic knowledge of PID, and then use position PID to realize the control of DC motor speed. ## 2.1 Program### Custom PID structure```c typedef struct { float target_val; //Target value float err; //Deviation value float err_last; //Last deviation value float Kp,Ki,Kd; //Proportional, integral, differential coefficients float integral; //Integral value float output_val; //Output value}PID; ``` ### PID algorithm implementation (position PID) ```c float PID_realize(float actual_val) { /*Calculate the error between the target value and the actual value*/ pid.err = pid.target_val - actual_val; /*Integral term*/ pid.integral += pid.err; /*PID algorithm implementation*/ pid.output_val = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last); /*Error transmission*/ pid.err_last = pid.err; /*Return the current actual value*/ return pid.output_val; } ``` ### Periodic call PID calculation```c //Callback function of periodic timer void AutoReloadCallback() { int sum = 0;/*Encoder value (PID input)*/ int res_pwm = 0;/*PWM value (PID output)*/ /*Read the speed value measured by the encoder*/ sum = read_encoder(); /*Perform PID calculation and get the PWM output value*/ res_pwm = PID_realize(sum); /*Control the motor rotation according to the PWM value*/ set_motor_rotate(res_pwm); /*Send the actual value to the upper computer channel 1*/ set_computer_value(SEND_FACT_CMD, CURVES_CH1, &sum, 1); } ``` ## 2.2 The host computer uses the "PID Debugging Assistant" of **Wildfire Multi-Function Debugging Assistant** to conduct experiments, which is used to display the motor speed curve during PID adjustment.
## 2.3 Experimental Demonstration The target speed value is set to 50 (the target value 50 here uses the number of pulses captured by the encoder in 10ms). By adjusting the PID parameters, we can test whether the motor can reach the target speed quickly. ### Adjust P first. Use 10 to see the effect. From the speed curve, we can see that the target speed cannot be reached and the difference with the target speed is large. | P | I | D | | ---- | ---- | ---- | | 10 | 0 | 0 |
The P value is increased to 100. From the speed curve, we can see that the target speed still cannot be reached. | P | I | D | | ---- | ---- | ---- | | 100 | 0 | 0 |
If only P is used, there will be static error and the target value can never be reached. In this case, the integral term should be used to eliminate the static error. ### Adjust I again. P remains at 100 and I is set to 0.2. As can be seen from the speed curve, the target speed can be reached, but the following speed is slow. | P | I | D | | ---- | ---- | ---- | | 100 | 0.2 | 0 |
Keep P at 100 and increase I to 1.0. As can be seen from the speed curve, the target speed can be reached and the following speed is accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 1.0 | 0 |
Keep P at 100, and continue to increase I to 3.0. From the speed curve, we can see that the target speed can be reached and the following speed is further accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 3.0 | 0 |
Keep P at 100, and continue to increase I to 6.0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance.### Finally, adjust D. Keep P at 100, I at 6.0, and D at 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
Keep P at 100, I at 6.0, and increase D to 6.0. From the speed curve, the overshoot amplitude is reduced a bit. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo video0 |
## 3 Demo Video0 |
## 3 Demo Video1 Program### Custom PID structure```c typedef struct { float target_val; //Target value float err; //Deviation value float err_last; //Last deviation value float Kp,Ki,Kd; //Proportional, integral, differential coefficients float integral; //Integral value float output_val; //Output value}PID; ``` ### PID algorithm implementation (position PID) ```c float PID_realize(float actual_val) { /*Calculate the error between the target value and the actual value*/ pid.err = pid.target_val - actual_val; /*Integral term*/ pid.integral += pid.err; /*PID algorithm implementation*/ pid.output_val = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last); /*Error transmission*/ pid.err_last = pid.err; /*Return the current actual value*/ return pid.output_val; } ``` ### Periodically call PID calculation```c //Callback function of periodic timer void AutoReloadCallback() { int sum = 0;/*Encoder value (PID input)*/ int res_pwm = 0;/*PWM value (PID output)*/ /*Read the speed value measured by the encoder*/ sum = read_encoder(); /*Perform PID operation and get the PWM output value*/ res_pwm = PID_realize(sum); /*Control the motor rotation according to the PWM value*/ set_motor_rotate(res_pwm); /*Send the actual value to channel 1 of the upper computer*/ set_computer_value(SEND_FACT_CMD, CURVES_CH1, &sum, 1); } ``` ## 2.2 The upper computer uses the "PID Debugging Assistant" of **Wildfire Multi-Function Debugging Assistant** to conduct experiments, which is used to display the motor speed curve during PID adjustment.
## 2.3 Experimental demonstration The target speed value is set to 50 (the target value 50 here uses the number of pulses captured by the encoder in 10ms). By adjusting the PID parameters, we can test whether the motor can reach the target speed quickly. ### Adjust P first. Use 10 as the P value to see the effect. From the speed curve, we can see that the target speed cannot be reached and the speed is far from the target speed. | P | I | D | | ---- | ---- | ---- | | 10 | 0 | 0 |
The P value is increased to 100. From the speed curve, we can see that the target speed cannot be reached. | P | I | D | | ---- | ---- | ---- | | 100 | 0 | 0 |
If only P is used, there will be static error, and the target value cannot be reached. At this time, the integral term should be used to eliminate the static error. ### Adjust IP again. Keep P at 100 and use I at 0.2. As can be seen from the speed curve, the target speed can be reached, but the following speed is slow. | P | I | D | | ---- | ---- | ---- | | 100 | 0.2 | 0 |
Keep P at 100 and increase I to 1.0. As can be seen from the speed curve, the target speed can be reached and the following speed is accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 1.0 | 0 |
Keep P at 100 and continue to increase I to 3.0. As can be seen from the speed curve, the target speed can be reached and the following speed is further accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 3.0 | 0 |
Keep P at 100, and continue to increase I to 6.0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P remains at 100, I remains at 6.0, and D increases to 6.0. From the speed curve, the overshoot amplitude is reduced a bit. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo video1 Program### Custom PID structure```c typedef struct { float target_val; //Target value float err; //Deviation value float err_last; //Last deviation value float Kp,Ki,Kd; //Proportional, integral, differential coefficients float integral; //Integral value float output_val; //Output value}PID; ``` ### PID algorithm implementation (position PID) ```c float PID_realize(float actual_val) { /*Calculate the error between the target value and the actual value*/ pid.err = pid.target_val - actual_val; /*Integral term*/ pid.integral += pid.err; /*PID algorithm implementation*/ pid.output_val = pid.Kp * pid.err + pid.Ki * pid.integral + pid.Kd * (pid.err - pid.err_last); /*Error transmission*/ pid.err_last = pid.err; /*Return the current actual value*/ return pid.output_val; } ``` ### Periodically call PID calculation```c //Callback function of periodic timer void AutoReloadCallback() { int sum = 0;/*Encoder value (PID input)*/ int res_pwm = 0;/*PWM value (PID output)*/ /*Read the speed value measured by the encoder*/ sum = read_encoder(); /*Perform PID operation and get the PWM output value*/ res_pwm = PID_realize(sum); /*Control the motor rotation according to the PWM value*/ set_motor_rotate(res_pwm); /*Send the actual value to channel 1 of the upper computer*/ set_computer_value(SEND_FACT_CMD, CURVES_CH1, &sum, 1); } ``` ## 2.2 The upper computer uses the "PID Debugging Assistant" of **Wildfire Multi-Function Debugging Assistant** to conduct experiments, which is used to display the motor speed curve during PID adjustment.
## 2.3 Experimental demonstration The target speed value is set to 50 (the target value 50 here uses the number of pulses captured by the encoder in 10ms). By adjusting the PID parameters, we can test whether the motor can reach the target speed quickly. ### Adjust P first. Use 10 as the P value to see the effect. From the speed curve, we can see that the target speed cannot be reached and the speed is far from the target speed. | P | I | D | | ---- | ---- | ---- | | 10 | 0 | 0 |
The P value is increased to 100. From the speed curve, we can see that the target speed cannot be reached. | P | I | D | | ---- | ---- | ---- | | 100 | 0 | 0 |
If only P is used, there will be static error, and the target value cannot be reached. At this time, the integral term should be used to eliminate the static error. ### Adjust IP again. Keep P at 100 and use I at 0.2. As can be seen from the speed curve, the target speed can be reached, but the following speed is slow. | P | I | D | | ---- | ---- | ---- | | 100 | 0.2 | 0 |
Keep P at 100 and increase I to 1.0. As can be seen from the speed curve, the target speed can be reached and the following speed is accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 1.0 | 0 |
Keep P at 100 and continue to increase I to 3.0. As can be seen from the speed curve, the target speed can be reached and the following speed is further accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 3.0 | 0 |
Keep P at 100, and continue to increase I to 6.0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P remains at 100, I remains at 6.0, and D increases to 6.0. From the speed curve, the overshoot amplitude is reduced a bit. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo videooutput_val; } ``` ### Periodic call PID calculation```c //Callback function of periodic timer void AutoReloadCallback() { int sum = 0;/*Encoder value (PID input)*/ int res_pwm = 0;/*PWM value (PID output)*/ /*Read the speed value measured by the encoder*/ sum = read_encoder(); /*Perform PID operation to get PWM output value*/ res_pwm = PID_realize(sum); /*Control motor rotation according to PWM value*/ set_motor_rotate(res_pwm); /*Send actual value to channel 1 of the upper computer*/ set_computer_value(SEND_FACT_CMD, CURVES_CH1, &sum, 1); } ``` ## 2.2 The upper computer uses the "PID Debugging Assistant" of **Wildfire Multi-Function Debugging Assistant** to conduct experiments, which is used to display the motor speed curve during PID adjustment.
## 2.3 Experimental demonstration The target speed value is set to 50 (the target value 50 here uses the number of pulses captured by the encoder in 10ms). By adjusting the PID parameters, we can test whether the motor can reach the target speed quickly. ### Adjust P first. Use 10 as the P value to see the effect. From the speed curve, we can see that the target speed cannot be reached and the speed is far from the target speed. | P | I | D | | ---- | ---- | ---- | | 10 | 0 | 0 |
The P value is increased to 100. From the speed curve, we can see that the target speed cannot be reached. | P | I | D | | ---- | ---- | ---- | | 100 | 0 | 0 |
If only P is used, there will be static error, and the target value cannot be reached. At this time, the integral term should be used to eliminate the static error. ### Adjust IP again. Keep P at 100 and use I at 0.2. As can be seen from the speed curve, the target speed can be reached, but the following speed is slow. | P | I | D | | ---- | ---- | ---- | | 100 | 0.2 | 0 |
Keep P at 100 and increase I to 1.0. As can be seen from the speed curve, the target speed can be reached and the following speed is accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 1.0 | 0 |
Keep P at 100 and continue to increase I to 3.0. As can be seen from the speed curve, the target speed can be reached and the following speed is further accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 3.0 | 0 |
Keep P at 100, and continue to increase I to 6.0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P remains at 100, I remains at 6.0, and D increases to 6.0. From the speed curve, the overshoot amplitude is reduced a bit. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo videooutput_val; } ``` ### Periodic call PID calculation```c //Callback function of periodic timer void AutoReloadCallback() { int sum = 0;/*Encoder value (PID input)*/ int res_pwm = 0;/*PWM value (PID output)*/ /*Read the speed value measured by the encoder*/ sum = read_encoder(); /*Perform PID operation to get PWM output value*/ res_pwm = PID_realize(sum); /*Control motor rotation according to PWM value*/ set_motor_rotate(res_pwm); /*Send actual value to channel 1 of the upper computer*/ set_computer_value(SEND_FACT_CMD, CURVES_CH1, &sum, 1); } ``` ## 2.2 The upper computer uses the "PID Debugging Assistant" of **Wildfire Multi-Function Debugging Assistant** to conduct experiments, which is used to display the motor speed curve during PID adjustment.
## 2.3 Experimental demonstration The target speed value is set to 50 (the target value 50 here uses the number of pulses captured by the encoder in 10ms). By adjusting the PID parameters, we can test whether the motor can reach the target speed quickly. ### Adjust P first. Use 10 as the P value to see the effect. From the speed curve, we can see that the target speed cannot be reached and the speed is far from the target speed. | P | I | D | | ---- | ---- | ---- | | 10 | 0 | 0 |
The P value is increased to 100. From the speed curve, we can see that the target speed cannot be reached. | P | I | D | | ---- | ---- | ---- | | 100 | 0 | 0 |
If only P is used, there will be static error, and the target value cannot be reached. At this time, the integral term should be used to eliminate the static error. ### Adjust IP again. Keep P at 100 and use I at 0.2. As can be seen from the speed curve, the target speed can be reached, but the following speed is slow. | P | I | D | | ---- | ---- | ---- | | 100 | 0.2 | 0 |
Keep P at 100 and increase I to 1.0. As can be seen from the speed curve, the target speed can be reached and the following speed is accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 1.0 | 0 |
Keep P at 100 and continue to increase I to 3.0. As can be seen from the speed curve, the target speed can be reached and the following speed is further accelerated. | P | I | D | | ---- | ---- | ---- | | 100 | 3.0 | 0 |
Keep P at 100, and continue to increase I to 6.0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P remains at 100, I remains at 6.0, and D increases to 6.0. From the speed curve, the overshoot amplitude is reduced a bit. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo video0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P is kept at 100, I is kept at 6.0, and D is increased to 6.0. From the speed curve, the overshoot amplitude is reduced a little. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo Video0. From the speed curve, we can see that the target speed can be reached and the following speed is also very fast, but there is a little overshoot. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 0 |
For overshoot, you can try adding differential. Differential D is equivalent to the effect of resistance### Finally, adjust D P to 100, I to 6.0, and D to 3.0. From the speed curve, it seems that there is no obvious change. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 3.0 |
P is kept at 100, I is kept at 6.0, and D is increased to 6.0. From the speed curve, the overshoot amplitude is reduced a little. | P | I | D | | ---- | ---- | ---- | | 100 | 6.0 | 6.0 |
## 3 Demo Video
## 4 Summary This article briefly introduces the basic principles and parameter tuning of PID. If you want to adjust the PID parameters well, continuous practice and debugging are still needed.