The first two articles, respectively introduces the PID speed control and the PID position control, were used to control the motor to the desired speed for rotation, and rotates at the desired position (laps), the expectations here are only one, but, if want to expect the speed of rotation to the desired position (start and stop of the deceleration process does not consider), how to control? It is necessary to combine the two, that is, PID cascade control to control the motor.

Cascade PID structure diagram

The typical PID cascade control structure is position loop + speed loop + current loop, as shown in the figure below.

In PID cascade control, the outermost input is the expected value of the whole control system, and the output value of the outer PID is the expected value of the inner PID.

The premise of three-ring control is hardware support. For example, position loop and speed loop need real-time motor rotation position and rotation speed as feedback, which requires the motor to be equipped with an encoder for speed measurement and rotation position measurement. The current loop needs a current sampling circuit to obtain the current of the motor in real time as feedback.

If there is no current sampling circuit, the current loop can be removed and only the position loop + speed loop can be used. The expectation of the system is still the rotation position, and the inner loop can adjust the rotation speed.

In addition, if you just want to control the speed of the motor to achieve motor speed regulation, you can use speed ring + current ring, the system is still expected to rotate the position, the inner ring can adjust the current of the motor, enhance the anti-interference ability of the system rotation adjustment.

Position loop + speed loop practice

Since my motor has no current measurement circuit, this paper uses position loop + speed loop to learn PID cascade control. This is the picture below:

PID Parameter Definition

Since it is cascade PID control, each level OF PID must have its own parameters. The position PID+ speed PID is used in this experiment, and the parameters are defined as follows:

/* Global variables that define position PID and speed PID structure size */
PID pid_location;
PID pid_speed;

/** * @brief PID Parameter initialization * @note None * @retval None */
void PID_param_init(a)
{
	/* Position-dependent initialization parameters */
	pid_location.target_val = TOTAL_RESOLUTION*10;				
	pid_location.output_val = 0.0;
	pid_location.err = 0.0;
	pid_location.err_last = 0.0;
	pid_location.integral = 0.0;

	pid_location.Kp = 0.05;
	pid_location.Ki = 0;
	pid_location.Kd = 0;

	/* Speed related initialization parameters */
	pid_speed.target_val=10.0;				
	pid_speed.output_val=0.0;
	pid_speed.err=0.0;
	pid_speed.err_last=0.0;
	pid_speed.integral=0.0;

	pid_speed.Kp = 80.0;
	pid_speed.Ki = 2.0;
	pid_speed.Kd = 100.0;
}
Copy the code

The realization of position PID

Two things to note here:

Closed loop dead zone setting

Closed-loop dead zone refers to the minimum control quantity of the actuator, which can no longer be adjusted to meet the control accuracy. If the control is still continuously adjusted, the system will frequently act before and after the target value and cannot be stabilized.

For example, the control precision of a system is 1, but the target value needs to be 1.5, no matter how to adjust, the final result can only be controlled at 1 or 2, never reaching the preset value. The range of 1.5L decimal point is the closed loop dead zone, the system is uncontrollable, the error will always exist, prone to shock phenomenon.

For systems with low accuracy requirements, closed-loop dead zone can be set. For example, if the allowable error range is set to 0.5, the final result is considered to have no error at 1 or 2. Then, the difference between the target value and the actual value is forced to be set to 0, which means that the closed-loop dead zone is limited.

The setting of integral separation

Anti-integral saturation is realized by integral separation. Integral saturation refers to the fact that when the actuator reaches the limit output capacity, it still cannot reach the target value and the static difference cannot be eliminated in a long period of time.

PWM output, for example, to 100%, still can not meet the desired location, then if has error accumulation, after a period of time, PID accumulated a great deal of numerical integral item, if this time arrived at the target, or reset the target, as a result of the integral due to the cumulative error is large, the system does not adjust immediately to the target, May cause overshoot or dissonance.

One way to solve integral saturation is to use integral separation. In this method, the integral term is used only when the accumulated error is less than a certain threshold value. If the accumulated error is too large, the accumulated error will not be continued, which is equivalent to only using PD controller.

Control flow chart

PID control flow with closed-loop dead zone and integral separation is shown as follows:

The complete location PID code is as follows:

/** * @brief position PID algorithm implementation * @param actual_VAL: actual value * @note None * @retval Output after PID calculation */
#define LOC_DEAD_ZONE 60 /* Position loop dead zone */
#define LOC_INTEGRAL_START_ERR 200 /* The corresponding error range for integral separation */
#define LOC_INTEGRAL_MAX_VAL 800   /* Limit the integral range to prevent saturation of the integral */
float location_pid_realize(PID *pid, float actual_val)
{
	/* Calculate the error between the target value and the actual value */
	pid->err = pid->target_val - actual_val;

	/* Set closed loop dead zone */
	if((pid->err >= -LOC_DEAD_ZONE) && (pid->err <= LOC_DEAD_ZONE))
	{
		pid->err = 0;
		pid->integral = 0;
		pid->err_last = 0;
	}

	/* Integral term, integral separation, if the deviation is large, remove the integral effect */
	if(pid->err > -LOC_INTEGRAL_START_ERR && pid->err < LOC_INTEGRAL_START_ERR)
	{
		pid->integral += pid->err;  
        /* Limit the integral range to prevent saturation of the integral */
		if(pid->integral > LOC_INTEGRAL_MAX_VAL)
		{
			pid->integral = LOC_INTEGRAL_MAX_VAL;
		}
		else if(pid->integral < -LOC_INTEGRAL_MAX_VAL) { pid->integral = -LOC_INTEGRAL_MAX_VAL; }}/*PID algorithm implementation */
	pid->output_val = pid->Kp * pid->err +
	                  pid->Ki * pid->integral +
	                  pid->Kd * (pid->err - pid->err_last);

	/* Error transfer */
	pid->err_last = pid->err;

	/* Returns the current actual value */
	return pid->output_val;
}
Copy the code

Speed PID implementation

The implementation code of speed PID is similar to that of position PID:

/** * @brief speed PID algorithm implementation * @param actual_VAL: actual value * @note None * @retval Output after PID calculation */
#defineSPE_DEAD_ZONE 5.0 f/* Speed loop dead zone */
#define SPE_INTEGRAL_START_ERR 100 /* The corresponding error range for integral separation */
#define SPE_INTEGRAL_MAX_VAL 260   /* Limit the integral range to prevent saturation of the integral */
float speed_pid_realize(PID *pid, float actual_val)
{
	/* Calculate the error between the target value and the actual value */
	pid->err = pid->target_val - actual_val;

	/* Set closed loop dead zone */
	if( (pid->err>-SPE_DEAD_ZONE) && (pid->err<SPE_DEAD_ZONE ) )
	{
		pid->err = 0;
		pid->integral = 0;
		pid->err_last = 0;
	}
    
	/* Integral term, integral separation, if the deviation is large, remove the integral effect */
	if(pid->err > -SPE_INTEGRAL_START_ERR && pid->err < SPE_INTEGRAL_START_ERR)
	{
		pid->integral += pid->err;  
        /* Limit the integral range to prevent saturation of the integral */
		if(pid->integral > SPE_INTEGRAL_MAX_VAL)
		{
			pid->integral = SPE_INTEGRAL_MAX_VAL;
		}
		else if(pid->integral < -SPE_INTEGRAL_MAX_VAL) { pid->integral = -SPE_INTEGRAL_MAX_VAL; }}/*PID algorithm implementation */
	pid->output_val = pid->Kp * pid->err +
	                  pid->Ki * pid->integral +
	                  pid->Kd *(pid->err - pid->err_last);

	/* Error transfer */
	pid->err_last = pid->err;

	/* Returns the current actual value */
	return pid->output_val;
}
Copy the code

Cascade control code

// Cycle timer callback function
void AutoReloadCallback(a)
{
	static uint32_t location_timer = 0;    // Position loop period
	
	static __IO int encoderNow = 0;    /* Total current value */
    static __IO int encoderLast = 0;   /* Total value of last time */
	int encoderDelta = 0; /* The change in the encoder from the current moment to the previous moment */
	float actual_speed = 0;  /* Actual measured speed */
	int actual_speed_int = 0;
	
	int res_pwm = 0;/*PID calculated PWM value */
	static int i=0;
	
	/* [1] read the encoder */
	encoderNow = read_encoder() + EncoderOverflowCnt*ENCODER_TIM_PERIOD;/* Get the current cumulative value */
	encoderDelta = encoderNow - encoderLast; /* gets the change */
	encoderLast = encoderNow;/* Update the last cumulative value */
	
	/* [2] position PID operation, get PWM control value */
	if ((location_timer++ % 2) = =0)
	{
		float control_val = 0;   /* Current control value */
		
		/* Position PID calculation */
		control_val = location_pid_realize(&pid_location, encoderNow);  
		
        /* Target speed limit */
		speed_val_protect(&control_val);

		/* Set the target value of speed PID */
		set_pid_target(&pid_speed, control_val);    
	}
	  
	/* Rotational speed (turns in 1 second)= count value in unit time/total resolution * time coefficient, multiplied by 60 to turns in 1 minute */
    actual_speed = (float)encoderDelta / TOTAL_RESOLUTION * 10 * 60;
    
	/* [3] speed PID operation, get PWM control value */
	actual_speed_int = actual_speed;
	res_pwm = pwm_val_protect((int)speed_pid_realize(&pid_speed, actual_speed));
	
	/*【4】PWM control motor */
	set_motor_rotate(res_pwm);
	
	/* [5] Upload data to upper computer to display */
	set_computer_value(SEND_FACT_CMD, CURVES_CH1, &encoderNow, 1);   /* Send the actual motor position */ to channel 1
}
Copy the code

PID calculation is called by timer once every 10ms. It can be seen from the code that the control cycle of the inner ring (speed PID) is shorter than that of the outer ring (position PID). The position PID is calculated once every two cycles, because the inner ring controls the final output. This output corresponds to the control quantity in the actual scene (the final control in this experiment is the position). The position cannot be mutated and takes time to accumulate, so the output of the inner ring should be as fast as possible.

Video presentation

Video, test with different target speed to reach the target location, video test introduced the control effect of the second half: video: www.bilibili.com/video/BV1QK…

Open source code

This article and the previous several motor and PID complete program code has been shared open source: gitee.com/xxpcb/stm32…

This article is helpful to you. WelcomeRetweet, likeSupport oh ~