【9.19

编程入门 行业动态 更新时间:2024-10-10 12:21:40

【9.19

【9.19

        这几天全在搞PID了,总起来写一篇。真是太费手啦,一直调一直调,最后结果也不是特别的满意,但是剩下的在反复调试后基本确定是硬件问题了,如果有大佬看到这篇文章,认为有改进空间的麻烦在评论区指点一下 ✧(≖ ◡ ≖✿)。

        在调的过程中也参考了许多许多的资料,这里附一个个人感觉比较好的“平衡小车调试总结”(当然也不是说别的不好,只是这个给我帮助比较大,当然也不是说别的帮助不大(°ー°〃))。

        我想我写的这篇不应该是教学吧,更偏向是个人调试过程中的一些感悟,希望能给遇到相似问题的小伙伴一些参考和帮助吧 ≡ω≡。

一、检查硬件

        检查接线是否接好,检查小车整体结构是否较为对称,检查电池电压是否到了12V。这些看起来很简单的事情却是最重要的,如果在硬件上出现了问题,会导致PID无论怎么调都不能达到较为满意的效果的,导致长时间的调参全部变成无用功。

        电池电压一定要好好检查!!!我的就是有一节电池没有电(新买的电池怎么会没有电呀     (;′⌒`)),以7点多伏的电压调直立环,总是感觉响应程度不够,且死区很大,现象是当小车向一侧偏的时候,直立环的kp无论调多大都不能让小车重新平衡(如果不理解看后面直立环部分就懂了)。同时我在查资料过程中发现有些哪怕是电压只少了1V也很导致后面调不好,所以最好换上满电的电池(我的是三节18650,电量总起来11.5V,亲测这样是可以的)就这样一个小问题耽误了我两天时间,大家一定要好好检查呀 X﹏X。

二、确定机械中值

        机械中值就是平衡车平衡时的俯仰角,后续让小车保持直立的指标就是让小车的俯仰角靠近这个角度。想象一下,当你仅仅是把平衡车放到桌面上,总能找到一个角度使小车短暂的平衡,不向两侧倾倒,此时小车的俯仰角就是所求的机械中值。

        机械中值的灵敏度很大,如果大小偏移哪怕一度,都会导致后续的调试出现很大的困难,导致平衡小车的平衡状态比较差,所以这一步一定要重视。

        方法如下:先要用串口或者OLED打印出实时的俯仰角,保证随时可以看到;然后将轮子PWM输入固定为0(就是不要让轮子转)。然后用手轻托一侧缓慢抬高,时刻注意角度值,直到手上没有托举的力,小车自己向另一侧倒,记录下此时的角度,然后同理从另一侧做同样的操作,再次记录下角度,两个角度取平均作为小车的机械中值。

三、直立环PD调试

        在调试直立环时,要保证速度环和转向环都为零

1、确定kp值的范围

        先要看输出PWM的定时器所设置的自动重装值(ARR)是多少,意味着当PWM的CCR(比较值)要在0到ARR的范围内,当CCR等于ARR的时候电机就是全速运转了。假设设置的ARR为7200(大多都是这个值),再考虑到当平衡小车自平衡时前后摆动角度大概在±10度左右,所以假设倾角为10度时电机达到最大速度,可以推出kp的值在0-720(7200/10=720)是合理的。

2、确定kp的极性

        然后确定kp的极性,先将kp暂时取范围的一半,也就是kp=360。倾斜小车看轮子是不是向倾斜方向转动,如果是就说明极性正确,如果不是就需要kp = -kp,这样就完成了极性的确定。

        (我看了好多教学都先确定的极性,让我随便取一个值,我想一个像我一样小白也不知道咋随便取这个值吧 (@_@;),所以我这里先确定的kp范围,帮大家确定了这个值︿( ̄︶ ̄)︿)

3、调节kp大小        

        准备工作做完接下来开始调参。先从kp=360开始,逐步递增,每次递增100,直到到达合适的状态。每次测试都要将小车以一个平衡的角度放置,如果放下之后小车一倾斜就向倾斜的方向一直跑,说明kp值偏小了;如果小车开始大幅度震荡,说明kp值偏大了(应该也不会看到这种情况,因为是从小递增的);最完美的情况是小车在原地保持低频摆动,但实际上小车的机械结构很难达到那么完美,只要能达到一段时间(在保证摆动幅度的情况下时间自然是越长越好)的低频摆动,然后向一侧前进也是可以的。

        我的是调到的kp=800才满意,所以稍微超一些范围也是可以的(毕竟调好之后也不会摆到±10度)

4、调节kd大小

        首先也是确定极性,一般来说和kp是一样的,也可以将kp置零,kd给个1观察轮子是不是向小车倾斜的方向转,如果是那么说明极性正确。

        通过观察角速度的数据可得一般不会超过4位数,由于满速是7200,再去想一下直立环、速度环、转向环都是相加的关系,总和不能超过7200(超过就没有调节意义了),所以总和考虑kd应该取0-2,。

        还是递增测试,步长0.1就可以。理想结果是小车在原地实现高频震荡直立(频率过高记得快关电压,小心电机烧了),考虑到一般的机械结构不会那么完美,所以能直立5s以上就是比较完美的了,一直向一个地方前进是正常现象。  

直立环函数:

/**************************************************************************
函数功能:直立PD控制
入口参数:角度、角速度
返回  值:直立控制PWM
作    者:南京迈辰微
**************************************************************************/
int Car_Balance(float Angle,float Gyro)
{  float Bias;int balance;Bias=Angle-ZHONGZHI;                       //===求出平衡的角度中值 和机械相关balance=Balance_Kp*Bias+Gyro*Balance_Kd;   //===计算平衡控制的电机PWM  PD控制   //kp是P系数 kd是D系数 return balance;
}

四、速度环PI调试

        速度环相对于直立环要好调,根据前辈们工程经验,kp是ki的200倍是最好的,所以两个参数就合成一个参数调了,后续我只提kp的变化,大家要知道ki要同步调节。

        速度环是根据电机编码器返回的脉冲数结合当前小车的倾角,反馈出一个值加和到总的PWM值上,对小车速度进行调节。

1、确定kp值的范围

        在速度环的计算中,kp是当前电机编码器脉冲数与输出PWM值的比例系数,电机编码器脉冲数是指在采样间隔时间内的脉冲数,所以kp范围要通过脉冲数和采样间隔时间综合计算。

        假设采样间隔时间为t毫秒(也就是读取编码器值的中断触发时间,我的t=5ms),在t毫秒内读取的编码器脉冲数为n(这个是两个轮子脉冲数之和,为了这个值较大一点好计算),经过测试最大的n值为n1(我的大概在60左右),再考虑到电机满速的PWM值为7200,所以kp的范围在   0-7200/n1,(对于我的就是0-120,实际上我取到了130,前面也都是估算的数字,以测试结果为准)

2、确定kp极性

        暂时设置直立环、转向环为0,同样可以取kp为范围的一半,因为速度环时根据小车轮子实时转速来确定结果的,所以在轮子不转的时候倾斜小车是不会自己开始转的,所以不能用直立环测试极性的方法了。应该用手转动一个轮子,看另一个轮子的转动方向,如果与手转动的方向一致,说明极性正确,反之需要加负号。

3、调节kp大小

       一般情况下速度环kp给个差不多的值之后小车就已经能站起来了,不会往一个方向倒了,如果不可以的话要考虑一下是不是前面的环节出了问题。

        同样是从范围中值开始递增(记得还原直立环的数值),根据自己值的大小取一个合适的步长。需要考虑两个指标,一个是直立时小车的稳定程度,另一个是响应速度,就是当小车在直立的情况下用手拨动小车,看他用多长时间能恢复直立。

        kp值过大时会出现过调节,平衡车会左右大幅度摆动,此时响应速度应该是较快的;kp过小时,平衡车可能会来回徘徊,直立状态较好,但是响应速度慢;最完美的情况应该是小车在原地偶尔抖动一下,且响应速度较快,静若处子动若脱兔那种感觉ヽ(✿゚▽゚)ノ,但是实际上那种情况也是比较难,就在调试过程中取到一个最好的情况就好,我的直立时也不会很稳,响应也还可以。我觉得可以牺牲一些站立时的平稳度,提高一下响应速度,因为如果响应速度越快,小车在前进时的最大速度就会越大。

速度环函数:

/**************************************************************************
函数功能:速度PI控制 修改前进后退速度,请修Target_Velocity,比如,改成60就比较慢了
入口参数:左轮编码器、右轮编码器
返回  值:速度控制PWM
作    者:南京迈辰微
**************************************************************************/
int Car_Velocity(int encoder_left,int encoder_right)
{  static float Velocity,Encoder_Least,Encoder,Movement;static float Encoder_Integral,Target_Velocity;//=============遥控前进后退部分=======================// Target_Velocity=Speed;                 if(1==Flag_Qian)    	Movement=Target_Velocity;	         //===前进标志位置1 else if(1==Flag_Hou)	Movement=-Target_Velocity;         //===后退标志位置1else  Movement=0;	//=============速度PI控制器=======================//	Encoder_Least =(Encoder_A+Encoder_B)-0;                    //===获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零) Encoder *= 0.8;		                                         //===一阶低通滤波器       Encoder += Encoder_Least*0.2;	                             //===一阶低通滤波器    Encoder_Integral +=Encoder;                                //===积分出位移 积分时间:10msEncoder_Integral=Encoder_Integral-Movement;                //===接收遥控器数据,控制前进后退if(Encoder_Integral>10000)  	Encoder_Integral=10000;      //===积分限幅if(Encoder_Integral<-10000)	Encoder_Integral=-10000;       //===积分限幅	Velocity=Encoder*Velocity_Kp+Encoder_Integral*Velocity_Ki;                          //===速度控制	return Velocity;
}

五、转向环PD调试

        前面已经实现了小车的站立功能,转向环就更简单了,就是让两个轮子出现差速,同时保证小车直立就可以了。根据工程经验kp是kd的100倍,其实也不是很严格,我就用了40倍也还可以,kp是决定转向速度的,kd相当于保持直立的,调到合适的范围就好。同样下面只提kp,kd随之变化。

1、确定kp范围

        满速7200,两个轮一个加转向环输出值,一个减去,所以输出值最好不要超过3000,由此调节kp的值。

2、确定极性

        注释其他环,给个中值,手动让小车转向,如果阻碍转向说明极性正确,反之取反。

3、调节参数大小

        这个其实没有什么参考,只要你觉得速度可以且不倒就行,自行调节。

转向环函数:

/**************************************************************************
函数功能:转向控制  修改转向速度,请修改Turn_Amplitude即可
入口参数:左轮编码器、右轮编码器、Z轴陀螺仪
返回  值:转向控制PWM
作    者:南京迈辰微
**************************************************************************/
int Car_Turn(int encoder_a,int encoder_b,float gyro)//转向控制
{static float Turn_Target,Turn,Encoder_temp,Turn_Convert=10,Turn_Count;float Turn_Amplitude=100,Kp=20,Kd=0;     //=============遥控左右旋转部分=======================////这一部分主要是根据旋转前的速度调整速度的起始速度,增加小车的适应性if(1==Flag_Left||1==Flag_Right)                      {if(++Turn_Count==1)Encoder_temp=myabs(encoder_a+encoder_b);      Turn_Convert=55/Encoder_temp;if(Turn_Convert<0.6)Turn_Convert=0.6;if(Turn_Convert>3)Turn_Convert=3;}	else{Turn_Convert=10;Turn_Count=0;Encoder_temp=0;}			if(1==Flag_Left)	           Turn_Target+=Turn_Convert;else if(1==Flag_Right)	     Turn_Target-=Turn_Convert; else Turn_Target=0;if(Turn_Target>Turn_Amplitude)  Turn_Target=Turn_Amplitude;    //===转向	速度限幅if(Turn_Target<-Turn_Amplitude) Turn_Target=-Turn_Amplitude;if(Flag_Qian==1||Flag_Hou==1)  Kd=-0.5;        else Kd=0;   //转向的时候取消陀螺仪的纠正 有点模糊PID的思想//=============转向PD控制器=======================//Turn=-Turn_Target*Kp-gyro*Kd;                 //===结合Z轴陀螺仪进行PD控制return Turn;
}

六、死区问题

        这个问题也是困扰我好久,就简单谈谈我的看法。电机总会有个死区,当输入PWM值过小时电机并不转,要达到一个阈值才会开始转动。所以在两个轮子上都加上死区大小可以避免电机不转的问题(可以从小到大增加PWM的值看到哪个值开始转,记得要把平衡车放到地上测,考虑摩擦力)。我的问题就是找不到一个合适的值,死区偏小就会响应不及时,出现来回徘徊的情况,偏大就会原地抖动,可能是电机质量问题吧(摆烂O__O')。

电机控制函数:

void Set_Pwm(int motoA,int motoB)
{if(motoA<0){AIN1(1);AIN2(0);}else{AIN1(0);AIN2(1);}TIM4->CCR4=Motor_dead+(myabs(motoA))*times;			if(motoB<0){BIN1(1);BIN2(0);}else{BIN1(0);BIN2(1);}TIM4->CCR3=Motor_dead+(myabs(motoB))*times;	}

七、时序问题

        这个我没有遇到,是在看资料过程中看到的。对平衡车的控制间隔时间应该是越小越好,因为mpu6050的采样频率不能小于5ms,所以中断时间在5ms是最好的。并且要注意如果在中断函数里放OLED的显示程序会拖慢程序运行时间,导致间隔变长,影响平衡效果。

八、我的成果演示视频

stm32平衡小车遥控演示(谁来治治他的“帕金森”!)_哔哩哔哩_bilibili

九、一点感悟

        一点一点看着自己调的平衡车站起来走起来的感觉真的很好ㄟ(≧◇≦)ㄏ,由于前面调试流程不够了解,我调试的过程很不流畅,调着速度环又去改直立环,又去改死区。。。这里简单总结一下:

直立环kp:比例项,控制直立平衡的响应速度,过调会摆动。

直立环kd:微分项,相当于限制角度变化的速度,提高了频率,所以能使低频抖动调成高频抖动。

速度环kp:比例项,使小车在有一个倾角时,调整轮速,保持这个倾角,防止倒下。

速度环ki:积分项:如果一直不能到达想保持的角度,积累差值,尽快达到想要保持的角度。

死区:防止小车调节时反映慢,一有调节量能马上开始调节。

        最后结果如果不满意可以参考我的理解结合自己的对参数进行小幅度、单一的调试,不要一下动几个参数,容易找不到原因,最好单个调,哪怕你很自信,打击的就是这种盲目自信的人,比如我(^-^)V

中断程序:

void EXTI2_IRQHandler(void)
{if(EXTI_GetITStatus(EXTI_Line2)!= RESET)   //时间到了{EXTI_ClearITPendingBit(EXTI_Line2); // 清除中断标志位LED_Flash(50);//250ms闪烁一次Timer_100ms++;Timer_1S++;Encoder_A = -Read_Encoder(2);              //===读取编码器的值,因为两个电机的旋转了180度的,所以对其中一个取反,保证输出极性一致Encoder_B = Read_Encoder(3);               //===读取编码器的值Car_Read_Angle();//获取小车的平衡角度Balance_Pwm = Car_Balance(Car_Angle_Balance,Gyro_Balance);//直立环Velocity_Pwm = Car_Velocity(Encoder_A,Encoder_B);//速度环if(1==Flag_Left||1==Flag_Right)    Turn_Pwm =Car_Turn(Encoder_A,Encoder_B,Gyro_Turn);        //===转向环PID控制else Turn_Pwm=-0.4*Gyro_Turn;PWMA = Balance_Pwm + Velocity_Pwm + Turn_Pwm;PWMB = Balance_Pwm + Velocity_Pwm - Turn_Pwm;//判断摔倒if(Car_Angle_Balance >= 60||Car_Angle_Balance <= -60){PWMA = 0;PWMB = 0;Motor_dead = 0;}
}

over!!!

        平衡小车告一段落了,后续可能会抽时间完善一些功能,比如巡线、避障啥的。这个文章相当长了,感觉写这个有点花时间了 (°ー°〃),不过写完的感觉还是很好的。后面做的可能是个偏大型的东西了,现在还没思路呢。就这样吧,(数学建模的还没写还没写 (* ̄(エ) ̄),疯狂拖,看看国庆有时间没,或者等结果出来再写,有底气一点hhh)

        下班!!

更多推荐

【9.19

本文发布于:2024-03-07 06:13:43,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1717046.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!