【回复讨论即得200IC币】
在NXP恩智浦智能车比赛中,电磁直立组是近年来新增的一项有趣项目。比赛是要求仿照两轮自平衡电动车的行进模式,让车模以两个后轮驱动进行直立行走。
在电磁组比赛中,利用了原来C型车模双后轮驱动的特点,实现两轮自平衡行走。相对于传统的四轮行走的车模竞赛模式,车模直立行走在硬件设计、控制软件开发以及现场调试等方面提出了更高的要求。
接下来由19年的参赛者:一城烟雨一楼台,分享自己参赛时,从零基础,到理解平衡车,实战比赛的学习心得。
直立车模的调试分为三个部分:1.直立环 2.速度环3.转向环有人说速度环可以省略,我认为在你的转向环调得好的情况下可以省略,因为失去了速度环的车模就会一直处于加速状态(在弯道时由于摩擦的作用会使速度降下来),这就会导致在直道入弯时的速度无法控制,在转向环不强的时候很容易飞出赛道。
先上直立环的代码,当然这种代码网上很多,形式也都差不多。
/@@************************************************************************** 函数功能:小车平衡电机占空比控制,直立PD控制 入口参数:倾角角度、角速度 返回 值:平衡控制用PWM **************************************************************************/ int Balance_Ctrl_Pwm(float Angfloat Gyro) { float Bias=Ang-QingJiaoZhongZhi; //中值,求出平衡的角度中值 和机械相关 int balance; float kp = 42 kd = - 26; balance= -(int)(kp*Bias+Gyro*kd); //计算平衡控制的电机PWM PD控制 kp是P系数 kd是D系数 return balance; }
然后再来说一下PD两个参数的调试。先调试kp,需要把kd置为0。首先需要确定正负,我们先随便给一个正值例如kp=10吧。然后我们相对于车模的平衡角度倾斜车模,如果车轮的转向和你倾斜车模的方向一致则可以确定kp应取正值,否则kp取负值。然后再来确定大小 逐渐增大Kp直至车身出现大幅低频摇摆的直立在地上,然后把这个数值乘以0.6基本就是一个比较稳定kp值。调试kd时同样需要把kp置为0。首先需要确定正负:例如先给他个kd=2;当你转动车模时车轮的转向与你车模转向一直则kd是正值,否则就是负值,注意pd与车模的平衡角度无关。大小的话同样也是逐渐增大直至出现低幅高频抖动时停止,也是把这个数值乘以0.6即可。
注意:这里涉及到一个负反馈调节因为直立环是要保证正常站立。因为当实际角度脱离平衡角度时,轮子只有给车身一个更大的同方向的力才会使车身保持平衡。如果还是不理解可以拿支笔放在手指上试试,手指怎样移动才会使笔立在手指上?
速度环也是一个标准的负反馈例子。例如:我们想让车模加速,速度环就会降低车轮的速度使车身前倾,就会导致直立环起作用让车轮加速保持直立。这就完成了一个加速过程。需要注意的是速度环会干扰直立环,如果速度环的强度过大,车身就会非常不稳定。我在调用该函数时每一百次直立环才会调用一次速度环,这样就降低了速度环对直立环的干扰。
/@@**************************************************************************函数功能:速度PI控制 修改前进后退速度,请修Target_Velocity,比如,改成60就比较慢了入口参数:左轮编码器、右轮编码器返回 值:速度控制PWM**************************************************************************/float Target_Velocity = 0;extern float kp_steep;int Velocity_Ctrl_Pwm(int encoder_leftint encoder_right){ static float VelocityEncoder_LeastEncoder; static float Encoder_Integral; float sudumax = 2700; float kp=kp_steepki = kp/200; //速度PI控制 Encoder_Least =(encoder_left+encoder_right)-Target_Velocity; //获取最新速度偏差==测量速度(左右编码器之和)-目标速度(此处为零) Encoder *= 0.7; //一阶低通滤波器 Encoder += Encoder_Least*0.3; //一阶低通滤波器 Encoder_Integral +=Encoder; //积分出位移 积分时间:?ms if(Encoder_Integral>2000) Encoder_Integral=2000; //积分限幅 if(Encoder_Integral<-2000) Encoder_Integral=-2000; //积分限幅 Velocity=Encoder*kp+Encoder_Integral*ki; //速度控制 if(flag_zhongdian!=0) Encoder_Integral=0; //电机关闭后清除积分 //输出限幅 if(Velocity > sudumax) Velocity = sudumax; else if(Velocity < -sudumax) Velocity = -sudumax; return (int)Velocity;}
转向环其实有很多方法。我是用的比较简单的一种办法:动态的pid算法,P的系数是电磁传过来的偏差,D的系数是MPU6050的Z轴加速度(因为车模静止时我所在的地区Z轴加速度为2,所以在代码最后gyro+ 2进行了一次加速度补偿)。速度越快P越大D越小。当电磁传过来的偏差小于5时,判为直道,采用很小的P。可有效地减少直道上的晃动。我一开始这样做发现过弯时会有特别严重的抖动,经常飞出赛道,因此在最后加了个判断
if((My_Abs(Turn_Target) - My_Abs(Turn_Target_last)) >= 37) //入弯防抖 else if((My_Abs(Turn_Target_last) - My_Abs(Turn_Target)) >= -40) //出弯防抖
变量 RoadPianCha 是左右横电感和斜电感的差除以左右电感的和。也就是说这个变量的范围是 0-100。
/@@**************************************************************************函数功能:转向控制 修改转向速度,请修改Turn_MaxPwm即可入口参数:左轮编码器、右轮编码器、Z轴陀螺仪返回 值:转向控制PWM作 者:**************************************************************************/int Turn_Ctrl_Pwm2(int encoder_leftint encoder_rightfloat gyro)//转向控制{ static float Turn_TargetTurnTurn_Target_last; float Turn_MaxPwmKpKd; // if(My_Abs(RoadPianCha) <= 2) // RoadPianCha = 0; Turn_Target_last = Turn_Target; Turn_Target=RoadPianCha - (encoder_left-encoder_right)/5; if(My_Abs(RoadPianCha) >= 5) { Kp = 41.0 * (200+encoder_left + encoder_right)/200.0; Kd = -4.2/ ((200+encoder_left + encoder_right)/200.0); Turn_MaxPwm = 2000; } else { Kp =3; Kd = -5; Turn_MaxPwm =200; } if((My_Abs(Turn_Target) - My_Abs(Turn_Target_last)) >= 37) //入弯防抖 { // Target_Velocity = 100; Kp = Kp * 3.2; Kd = Kd * 2.3; } else if((My_Abs(Turn_Target_last) - My_Abs(Turn_Target)) >= -40) //出弯防抖 { // Target_Velocity = 1000; Kp = Kp * 1.7; Kd = Kd * 3.4; } if(Turn_Target>Turn_MaxPwm) Turn_Target=Turn_MaxPwm; //转向速度限幅 if(Turn_Target<-Turn_MaxPwm) Turn_Target=-Turn_MaxPwm; //=转向PD控制器==// Turn= -Turn_Target*Kp + (gyro+ 2)*Kd; //结合Z轴陀螺仪进行PD控制 return (int)Turn;}
最后关于这几个环串起来:在主函数中开一个定时器(时间大概为1-2毫米)把这几个函数轮番调用下面的是我定时器触发函数
////====数据处理====平衡控制==速度环控制==转向环控制void PIT1_isr (void){ flag1ms++; if(flag1ms%2 == 1) { Get_Dip_Angle(); //角度获取 Balance_Pwm = Balance_Ctrl_Pwm(Angle_BalanceGyro_Balance); //===平衡PID控制 if(flag1ms >= 100) { flag_100ms++; flag1ms = 0; Velocity_Pwm = Velocity_Ctrl_Pwm( Encoder_Left Encoder_Right); //===速度环PID控制 记住,速度反馈是正反馈,就是小车快的时候要慢下来就需要再跑快一点 } } else { Encoder_Right = FTM_AB_Get(FTM1); //脉冲为前进+,后退为- Encoder_Left = -FTM_AB_Get(FTM2); Get_AD_data(); //获取电感,测距的AD值 AD_chuli(); //处理AD值,得出最终偏差 Turn_Pwm = Turn_Ctrl_Pwm2(Encoder_Left Encoder_RightGyro_Turn); //===转向环PID控制 } //输出电机PWM————负脉冲向前 Moto_Left=Balance_Pwm+Velocity_Pwm+Turn_Pwm; //===计算左轮电机最终PWM Moto_Right=Balance_Pwm+Velocity_Pwm-Turn_Pwm; //===计算右轮电机最终PWM //end PIT_TFLG(1) |= PIT_TFLG_TIF_MASK; //清中断标志位 }
版权声明:本文为CSDN博主「一城烟雨 一楼台」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/weixin_42803127/article/details/102856398
可以复制下来。。
做平衡车也可以举一反三