个人总结:板球控制系统之串级PID整定方法,速度环与位置环,40S任务10S完成

其实单环我们先出了所有题目,但是效果显然没有串级PID的效果好,有人需要的话可以把程序包发出来,板球运行视屏也有
另外:天下舵机参差不齐(哪怕型号相同),想要好的效果就多写两行程序:X,Y轴两套PID参数,当然,一套参数也能出结果


单环-位置环

能做题,但一般的机械结构都需要最后做一些补偿,这里就不赘述了。贴两行控制程序

//PID函数
double PID_Realize(double roll,double SetAngle,PID_Date *pid)
{
	 double incrementSpeed;
	 pid->SetSpeed = SetAngle;
	 pid->ActualSpeed= roll;
	 pid->err=pid->SetSpeed-pid->ActualSpeed;
	 incrementSpeed=pid->Kp*pid->err+pid->Ki*pid->sum+pid->Kd*(pid->err-pid->err_next);
	 pid->err_last=pid->err_next;
	 pid->err_next=pid->err;
	 pid->sum+=pid->err;
	
	 return incrementSpeed;
}
	
   PWM_X = PID_Realize(now_x_position,X_Angle,&pid_x);	//X轴舵机输出PWM
   PWM_Y = PID_Realize(now_y_position,Y_Angle,&pid_y);	//Y轴舵机输出PWM

   /**********************************************************************************************
   最终可以完成任务,但系统总体的鲁棒性很差,稍微有些外界干扰,最后小球的位置
   都可能有所偏差
   ***********************************************************************************************/

串级PID-速度环作为内环

程序贴在下方,大概描述一下PID调节过程
我们采用两种方式做出了串级

  • 内环PI 外环PD
  • 内环PD 外环PI

第一种不需要积分限幅,而第二种我们最后做了积分分离

由于第二种更容易理论解释,所以本文中讲述的是第二种方式

pid_x
pid_y 为外环两组PID结构体

pid_spe_x
pid_spe_y 为外环两组PID结构体

SX_PWM为X轴舵机速度期望
SY_PWM为Y轴舵机速度期望

  1. 第一步速度期望SX_PWM,SY_PWM都设置为零,只给速度环PID的KP,在一定范围内,可以达到效果:动一下小球,小球快速停下来,在我的系统里参数为60~80,最终我给了X方向上速度环KP65,Y方向上速度环KP是75。

  2. 速度限幅,调内环KD,下面程序限幅为±1.6(一次中断的时间小球最多走1.6像素点距离)。在幅值内任意给几个速度,我们测试了0.8,1.6,-1.6,通过现象来整定内环KD。小球在板子上基本匀速即可,不要有太大震荡。

  3. 内环速度已经稳定了,现在可以把外环输出给内环做期望速度了,SY_PWM = Kalman4(PID_Realize(now_y_position,set_goal_y,&pid_y));然后开始调节外环KP。

  4. 外环KP直接从内环KP/100开始向上调。set_goal_y给定为板子上九点某一点。差不多小球停在期望坐标周围就可以了。当然优秀的机械结构,这道题目基本算是做完了。

  5. 在上一条,我们达到了小球在目标点附近的效果,此时加入分段积分,即外环KI,判断当小球在目标点附近时加入积分。让小球进入最终死区。别忘了把积分效果清零哦。

整个串级处理程序:放在了定时中断里

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	static u8 times=0;
	static double data_cloud_xy[2][3]={0};
	if(htim==(&TIM4_Handler))
    	{
		  image_binarize(rgb_data_buf);		//二值化处理程序,用时2.17ms
		  Find_Nine_Point();					//找到九个点坐标,0.90ms
		  if(((int)now_x_position+(int)now_y_position)==0)			//找不到球重新找球
		   find_ball();
		  else
		   find_next_ball(data_cloud_xy[0][times],data_cloud_xy[1][times]); 
		  times=(times+1)%2;
		  data_cloud_xy[0][times] = ball_start.x;
		  data_cloud_xy[1][times] = ball_start.y;
		  
		  if(times==0){
		   
		   now_x_position = Kalman1(0.95*data_cloud_xy[0][0]+0.05*data_cloud_xy[0][1]);//+0.05*data_cloud[0][1];
		   now_y_position = Kalman2(0.95*data_cloud_xy[1][0]+0.05*data_cloud_xy[1][1]);//+0.05*data_cloud[1][1];
		   
		   
		   
		   spe_x = now_x_position - data_cloud_xy[0][2];		//X轴方向速度			一次中断运行的距离
		   spe_y = now_y_position - data_cloud_xy[1][2];		//Y轴方向速度
		   
		//   if(fabs(spe_x)<0.3)spe_x=0;					//用来做速度为0的速度环 测试
		//   if(fabs(spe_y)<0.3)spe_y=0;
		   
		   data_cloud_xy[0][2] = now_x_position;
		   data_cloud_xy[1][2] = now_y_position;
		 
		 										//速度限幅
		   if(Kalman3(PID_Realize(now_x_position,set_goal_x,&pid_x))>=1.6)
		   {
		   	 SX_PWM = 1.6;
		   }
		   else if(Kalman3(PID_Realize(now_x_position,set_goal_x,&pid_x))<=-1.6)
		   {
		   	 SX_PWM = -1.6;
		   }
		   else{ SX_PWM = Kalman3(PID_Realize(now_x_position,set_goal_x,&pid_x));}
		   
		   
		   if(Kalman4(PID_Realize(now_y_position,set_goal_y,&pid_y))>1.6)
		   {
		   	 SY_PWM = 1.6;
		   }
		   else if(Kalman4(PID_Realize(now_y_position,set_goal_y,&pid_y))<-1.6)
		   {
		   	 SY_PWM = -1.6;
		   }
		   else{ SY_PWM = Kalman4(PID_Realize(now_y_position,set_goal_y,&pid_y));}
		   
		   									
		   PWM_X = PID_Realize(spe_x,SX_PWM,&pid_spe_x);	//X,Y舵机输出
		   PWM_Y = PID_Realize(spe_y,SY_PWM,&pid_spe_y);
		   
		   if(system_flag==1)
		   {
		  	 Motor_Contor(PWM_X,PWM_Y);
		   }
		   else{							//消除历史积分
			    Motor_Stop();
			    pid_x.sum = 0;
			    pid_y.sum = 0;
			    pid_spe_x.sum = 0;
			    pid_spe_y.sum = 0;
			    
			    pid_x.err_next = 0;
			    pid_y.err_next = 0;
			    pid_x.err_last = 0;
			    pid_y.err_last = 0;
			    
			    pid_spe_x.err_next = 0;
			    pid_spe_y.err_next = 0;
			    pid_spe_x.err_last = 0;
			    pid_spe_y.err_last = 0;
			   } 	
			 //Repoter_XY(now_x_position*10,PWM_X,set_goal_x*10,now_y_position*10,PWM_Y,set_goal_y*10);	//回传参数,用于观察PID曲线效果
		 f=ov_frame;
		 ov_frame=0;
		 }
	}
}

预祝大家的串级PID顺利调好。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值