芯查查logo
  • 数据服务
    1. 新产品
    2. 物料选型
    3. 查替代
    4. 丝印反查
    5. 查品牌
    6. PCN/PDN
    7. 查方案
    8. 查代理
    9. 数据合作
  • SaaS/方案
      SaaS产品
    1. 供应链波动监控
    2. 半导体产业链地图
    3. BOM管理
    4. 解决方案
    5. 汽车电子
    6. 政府机构
    7. 数据API
  • 商城
  • 行业资讯
    1. 资讯
    2. 直播
  • 论坛社区
    1. 论坛
    2. 学习
    3. 测评中心
    4. 活动中心
    5. 积分商城
  • 查一下
  • 开通会员
平衡车之PID参数调节笔记心得
原创 精华 发布时间:2023/02/06 22:59
版块:
单片机/MCU论坛
简介:平衡车目前只完成了直立功能,调节完PID参数后记录一下自己的心得体会。后续的一些其他功能添加在完成之后都会以开源的形式发出来。

      很久之前就想要搞一搞平衡小车体验一下PID算法控制的精妙之处,但是一直因为各种原因拖到了年前才搭好了硬件,过年期间又耽搁了,直到这几天才开始调试软件。期间也是遇到了各种各样的问题,因为之前也没玩过这个,所以就找了各种原因走了很多的弯路,在此就简简单单记录一下自己调节PID参数的一个整个过程,还有自己在调试过程中走过的弯路。

     PID控制即比例-积分-微分控制,即通过对偏差进行比例-积分-微分控制,使得当前值趋于目标值的一个过程。刚开始因为只是让小车简单的立起来所以就只是用了一个直立环和速度环的串及PID控制,控制效果还是很OK的!控制结构框图如下:

      直立环顾名思义就是让小车能够立在原地,但是仅仅依靠直立环还不足以让小车稳定的立在原地这时就要加上速度控制。从串级PID系统的结构框图也可以看出直立环输入的是小车的偏转角度,速度环输入的是编码器输出的脉冲数。(单位时间内采集到的脉冲数量和小车速度是呈正比的关系)两者输出的都是WPM值。

      开始调节之前我潜意识的认为当小车向一边偏倒的时候就需要控制电机向相反的方向加速,这样才会使小车重新回到平衡位置,这个想法其实是错误的,向相反的方向加速只会使小车倒下的更快。正确的应该是使小车向倒下的放下加速运动这样小车才会回到平衡位置。

      如果小车出现倾角,在直立环的控制作用之下就会使小车在倾斜的方向加速,我们可以利用小车的这个特性来进行速度控制。控制速度实际上就变成了控制小车的倾角。速度黄使正反馈过程,当倾斜加速时,想要速度慢下来,速度环PWM就必须输出更大,让小车快速摆正。如使用负反馈,当小车以一定速度运行时,通过减速让小车慢下的时候小车就会因为惯性向前倒下。

       PID参数调节

    Kp:对系统动态性能的影响,kp增大时会使系统响应速度变快但同时也会增大系统的震荡。对稳态性能影响,在系统稳定的前提之下,加大kp可以减少稳态误差,但不能消除稳态误差。

       ki:动态性能,ki太小系统不能稳定,且震荡次数较多,ki太大对系统的影响将消弱。稳态性能,积分控制有助于消除系统稳态误差,提高系统的控制精度,但ki太大,积分作用太弱,则不能减少余差。

       kd:动态性能,kd的增加可以改善系统的动态特性,如减少超调量,缩短调节时间等。适当加大比例控制,可以减少稳态误差,提高控制精度。但kd值偏大还是偏小都会适得其反。另外微分作用又可能放大系统的噪声,降低系统的抗干扰能力。

     首先要确立小车的机械中值,所谓的机械中值就是小车在那个角度可以自己保持平衡,一般都是零度附近。还有就是小车的机械中值对于后面调节PID参数让小车保持平衡的影戏并不是很大,这个机械中值也不需要多么准确。可以让小车向一边偏,然后我们用手将小车向另外一边推,观察小车在那个角度的时候向另一边倒下记录这个角度,按照同样的方式测得另外一个角度,取平均值即为小车的机械角度。不必在机械角度的测量上浪费太多时间。

     直立环极性调节:直立环使用PD控制器,需要调节Balance_Kp和Balance_Kd这两个参数。直立环极性调节的时候需要屏蔽掉速度环。

     Balance_Kp极性正确:小车向一个方向倾斜时,向倾斜方向加速。

     Balance_Kp极性错误:小车向倾斜时,向倾斜的反方向加速。

     Balance_Kd极性正确:小车倾斜时,小车朝倾斜方向运动。

     Balance_Kd极性错误:倾斜时,向相反方向运动。

     Balance_Kp如果极性错误在下列语句的Balance_Kp前加上“-”即可。


      balance=Balance_Kp*Angle_bias-Gyro_bias*Balance_Kd;

     Balance_Kd,极性错误直接在函数开头给Balance_Kd赋负数即可。

     直立环的极性调节还是比较简单的,是比较容易完成的。

      速度环极性调节:速度环使用PI控制,需要调节Velocity_Kp和Velocity_Ki这两个参数。积分项又偏差的积分得到,所以积分控制于比例控制的极性相同。并且根据工程经验Velocity_Ki == Velocity_Kp/200 。所以只需调节Velocity_Kp的参数和极性就可以了。调节的时候同样需要屏蔽直立环。

      极性正确,当转动小车车轮的时候小车两边的轮子会同时加速到最快速度。

      极性错误,当转动小车一边的车轮的时候,另外一端的轮子会以同样的速度朝相反的方向加速。

      当极性错误时,在下列代码的Encoder_bias前加上负号可以了。

       velocity=-Encoder_bias*Velocity_Kp-Encoder_Integral*Velocity_Ki;

      我在调节速度环的极性的时候遇到了,轻轻转动一下车轮,车轮就会立刻全速向转动方向转动,开始还有有点懵逼的,但是后来发i现这是由于p,i的值设置的大,将p,i值设置的比较小的时候就以明显的观测到车轮加速的过程了。

      完成了极性的确定,接下来就是调节参数的大小了。

     直立环参数大小调节:

     先把所有的参数调为0之后就可以开始调节直立环参数大小了。首先调节Balance_Kp,每次增大Balance_Kp直至小车出现低频抖动,保留此时的值。增大Balance_Kd直至出现高频抖动,此时记录直立环参数,乘于0.6作为直立环最终的参数。

     速度环参数大小调节:

     把上述所得的直立环最终参数保留,即乘于0.6的参数。然后开始调节速度环。每次增大Velocity_Kp值,其中Velocity_Ki值也要设定为Velocity_Kp的1/200,观察小车能否立在原地。若增大到小车出现抖动,而且用手推小车会发生大幅灰白,说明此参数不可取,应减少到适合的数值。

      我在调节速度环的时候发现,参数增大到一定程度后再增大参数并不能使小车很稳的立在原地,反而会使小车抗干扰的能力降低,小车出现一点偏转时就会发生大幅的摆动然后倒下。这时候就要减小参数达到小车比较稳且抗干扰能力较强的一个数值。

      在调节速度环参数的时候还出现了,烧进去程序,刚初始化完成之后小车车轮就开始朝一个方向快速转动,这个也是正常现象,因为程序比较简单只是实现小车的直立并没有加上其他的控制,比如小车的拿起和放下检测。在直立环的作用之下,拿起来的小车注定会出现一个角度的偏差所以会使小车在速度环的作用之下加速运转。每次程序烧进去后将下车平放在地上初始化,就可以正确的观测到该有的现象了。这个刚烧进去程序初始化后轮子就疯狂转的问题也困扰了我好久,排查了很多都没发现问题所在。后来在调试的差不多的时候才后知后觉,也浪费了很多的时间。

      参数调节各个环节的现象可以参考B站的这个视频,现象很清晰,作者也有参数调节的讲解,就是声音有点小。  https://www.bilibili.com/video/BV1zo4y1D7bx/?spm_id_from=333.337.search-card.all.click&vd_source=e2baf97d96dd059e49ec3a996bd33ea8 。

      直立环控制函数:


       /**************************************************************************
Function: Vertical PD control
Input   : Angle:angle;Gyro:angular velocity
Output  : none
函数功能:直立PD控制		
入口参数:Angle:角度;Gyro:角速度
返回  值:无
**************************************************************************/	
int Balance(float Angle,float Gyro)
{  
	 float Balance_Kp= 390 ,Balance_Kd= -1.68;//直立环PD参数
   float Angle_bias,Gyro_bias;
	 int balance;
	 Angle_bias=Middle_angle-Angle;                       //求出平衡的角度中值 和机械相关
	 Gyro_bias=0-Gyro;
	 balance=Balance_Kp*Angle_bias-Gyro_bias*Balance_Kd;   		//计算平衡控制的电机PWM  PD控制   kp是P系数 kd是D系数 
	 return balance;
}

       速度环控制函数:


        /**************************************************************************
Function: Speed PI control
Input   : encoder_left:Left wheel encoder reading;encoder_right:Right wheel encoder reading
Output  : Speed control PWM
函数功能:速度控制PWM		
入口参数:encoder_left:左轮编码器读数;encoder_right:右轮编码器读数
返回  值:速度控制PWM
**************************************************************************/
int Velocity(int encoder_left,int encoder_right)  
{  
	  float Velocity_Kp= 360 ,Velocity_Ki= 1.8 ;//速度环PI参数
    static float velocity,Encoder_Least,Encoder_bias;
	  static float Encoder_Integral;
   //=============速度PI控制器=======================//	
		Encoder_Least =0-(encoder_left+encoder_right);                    //获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零) 
		Encoder_bias *= 0.8;		                                                //一阶低通滤波器       
		Encoder_bias += Encoder_Least*0.2;	                                    //一阶低通滤波器  
																																			//相当于上次偏差的0.8 + 本次偏差的0.2,减缓速度差值,减少对直立的干扰  
		Encoder_Integral +=Encoder_bias;                                       //积分出位移 积分时间:10ms
		if(Encoder_Integral>10000)  	Encoder_Integral=10000;             //积分限幅
		if(Encoder_Integral<-10000)	  Encoder_Integral=-10000;            //积分限幅	
		velocity=-Encoder_bias*Velocity_Kp-Encoder_Integral*Velocity_Ki;              //速度控制	
		if(Turn_Off(Angle_Balance)==1||Flag_Stop==1)   Encoder_Integral=0;      //电机关闭后清除积分
	  return velocity;
}

       所有控制代码:

        int EXTI15_10_IRQHandler(void) 
{    
	 static u8 Flag_Target;						//控制函数相关变量,提供10ms基准
   int Balance_Pwm,Velocity_Pwm;		//平衡环PWM变量,速度环PWM变量
	 int Motor_Left,Motor_Right;      //电机PWM变量 应是Motor的 向Moto致敬	
	 if(INT==0)		
	 {   
			EXTI->PR=1<<12;                         //清除中断标志位   
			Flag_Target=!Flag_Target;
			Get_Angle();                            //更新姿态	5ms读取一次
			Encoder_Left=-(Read_Encoder(2)*0.026);          //读取左轮编码器的值,前进为正,后退为负
			Encoder_Right=-(Read_Encoder(4)*0.026);         //读取右轮编码器的值,前进为正,后退为负
			//printf("左右编码器读数:%d , %d\r\n",Encoder_Left,Encoder_Right);																				//左轮A相接TIM2_CH1,右轮A相接TIM4_CH2,故这里两个编码器的极性相同
			if(Flag_Target==1)                      //实际上10ms控制一次
				return 0;	                                               
			Key();                                  //扫描按键状态 单击可启停电机
			
			Balance_Pwm =Balance(Angle_Balance,Gyro_Balance); //平衡PID控制	  Gyro_Balance平衡角速度极性:前倾为正,后倾为负
			Velocity_Pwm=Velocity(Encoder_Left,Encoder_Right);//速度环PID控制	 记住,速度反馈是正反馈,就是小车快的时候要慢下来就需要再跑快一点
			
			Motor_Left=Velocity_Pwm+Balance_Pwm;              //计算左轮电机最终PWM
			Motor_Right=Velocity_Pwm+Balance_Pwm;             //计算右轮电机最终PWM
			
			//printf("%d\r\n",Velocity_Pwm);
			
			Motor_Left=PWM_Limit(Motor_Left,6900,-6900);
			Motor_Right=PWM_Limit(Motor_Right,6900,-6900);		//PWM限幅
			printf("平衡倾角为:%f \r\n",Angle_Balance);
			if(Turn_Off(Angle_Balance)==0)
			{				//如果不存在异常
				Set_Pwm(Motor_Left,Motor_Right);                //赋值给PWM寄存器 
				//printf("左右pwm赋值为:%d ,%d",Motor_Left,Motor_Right);
			}
			
			//printf("左右编码器的值为:%d , %d \r\n",Encoder_Left,Encoder_Right);
	 }       	
	 return 0;	  
} 


单片机/MCU论坛 STM单片机 DIY设计 PID
2023/02/06 22:59
  • 举报
😁😂😃😄😅😆😉😊😋😌😍😏😒😓😔😖😘😚😜😝😞😠😡😢😣😤😥😨😩😪😫😭😰😱😲😳😵😷😸😹😺😻😼😽😾😿🙀🙅🙆🙇🙈🙉🙊🙋🙌🙍🙎🙏✂✅✈✉✊✋✌✏✒✔✖✨✳✴❄❇❌❎❓❔❕❗❤➕➖➗➡➰🚀🚃🚄🚅🚇🚉🚌🚏🚑🚒🚓🚕🚗🚙🚚🚢🚤🚥🚧🚨🚩🚪🚫🚬🚭🚲🚶🚹🚺🚻🚼🚽🚾🛀Ⓜ🅰🅱🅾🅿🆎🆑🆒🆓🆔🆕
@好友

全部评论

加载中
游客登录通知
已选择 0 人
自定义圈子
移动
发布帖子
发布动态
发布问答
发布者
搞机佬
创作者认证
最新帖子
芯查查技术沙龙第4期—ADI智能音频解决方案分享完美落幕LDO串联或并联二极管有什么用?电路保护与特殊应用解析缝纫机伺服0.3秒启停稳如磐石:三招驯服“针位漂移”顽疾伺服电机过载预警:从电流纹波揪出轴承暗伤的猎杀方案芯片丝印反查求助
热门版块
查看更多
麦博大学堂
问型号
问技术
问行情
电子元器件
汽车电子工程师论坛
工业电子专区
新手入门指南
单片机/MCU论坛
PCB设计

173

收藏

分享

微信扫码
分享给好友

评论