做为第十六届智能车的FW,在半年的做车经历中把能踩的坑都踩了个遍。写这篇文章是为了留个纪念,也是为了帮新车友快速入门(可能完全0基础)。我自己的经验也不足,所以可能会存在一些漏洞,还请大佬指正。

车模的搭建

在调试的时候,我们多次换过车模的结构,最后发现车模的重心越低越好,质量分布要尽可能的集中。不到不得已的时候不要加配重,把车沿轴的转动惯量降到最低。车模结构还是挺重要的,重心低点能明显感觉车更稳。这是对电路设计也要提出一定的要求,省赛的时候见到有一辆车把电路集成到了一块板子上,而我们是三块板子(还非常大),所以更难搭出好的结构。新手设计的话没必要整那么难的,但要提前计划好每块板子的位置,尽可能的精简。我不是写程序的吗,怎么在考虑电路(bushi

(下图不是最终版,但比较接近)

车的整体方案

我自己是主要负责车的程序,所以就细说怎么让车动起来。我们的车是采用了最简单的并级PID,电磁引导的方案。(太菜了,摄像头不会,串级PID也不会QAQ)核心是用的灵动的MM32,Cortex-M0内核,后换到M3内核(笑死,3080都能买到,这个芯片买不到)。陀螺仪用了龙邱的MPU9250,后换到逐飞的ICM20602(问就是龙邱垃圾)。双车的通讯模块是Lc12s(问就是便宜)。

来简单说一下程序的整体框架。智能车程序和学弟们最开始学的51还是有些区别,底层的驱动函数已经是由商家帮忙写好了,不需要再从头开始用寄存器。下面的程序基本适用于任何芯片,只要理解每个函数的具体含义,以及程序整体的框架,套用不同芯片的具体例程,就能快速上手。我在给变量命名的时候基本没用缩写,所以还是比较容易看懂的。

//其他器件初始化一下就不用动了。最重要的是这三个定时器
tim_interrupt_init_ms(TIM_8, 1, 0);         //直立环中断
tim_interrupt_init_ms(TIM_6, 10, 1);        //速度环中断
tim_interrupt_init_ms(TIM_7, 5, 1);         //方向环中断

直立车的三个PID就都放在了这三个定时器中,固定时间判断直立,转向和方向的情况。而main函数里最后进到以下程序。不断循环这个就可以。(定时器是需要用到的最基本的中断,就是相当于定了3个闹钟,每个闹钟到点后放下手头活,去做指定的事)

while(1){run();            //车的循迹程序Branch();         //三岔路程序fixedCircle();    //环岛程序}
//车模运行控制算法
void run()
{if (Vol_left1_actual + Vol_right1_actual > Threshold_circle && err_angle < 10 && err_angle > -10)dirControlOut *= 0.05;                                  //屏蔽环岛if (Flag_dirPID == open)dirOut = dirControlOut;                                 //方向环开关duty_Left = angleControlOut - speedControlOut + dirOut;     //dirOut为正是左转duty_Right = angleControlOut - speedControlOut - dirOut;if (duty_Left > 0)            //加电机死区duty_Left = duty_Left + duty_death_left_P;if (duty_Left < 0)duty_Left = duty_Left + duty_death_left_N;if (duty_Right > 0)duty_Right = duty_Right + duty_death_left_P;if (duty_Right < 0)duty_Right = duty_Right + duty_death_left_N;if (duty_Left > duty_Max_P)    //输出限幅duty_Left = duty_Max_P;if (duty_Right > duty_Max_P)duty_Right = duty_Max_P;if (duty_Left < duty_Max_N)duty_Left = duty_Max_N;if (duty_Right < duty_Max_N)duty_Right = duty_Max_N;MotorCtrl(-duty_Left, -duty_Right);                         //输出到电机上
}

duty表示占空比,通过输出不同占空比的pwm波,到电机驱动上,就可以控制电机的转速。循迹函数中最主要的就是将三环的结果叠加到duty_Left和duty_Right,然后输出作用到电机上,其他都是辅助作用,先暂且不管。 接下来我就讲一下这三个环的具体内容。

直立环

直立环是最重要的一个部分,也是最先开始调的,第一次让车立起来,还是很有成就感的。我主要说一下程序的内容就好了,原理还是得看《第七届全国大学生“飞思卡尔”杯智能汽车竞赛 电磁组直立行车参考设计方案》。上古资料,但是特别详细,B站有配套的高糊视频。简单来说,就是通过采集到陀螺仪的原始数据,解算出车模的实际角度,得出角度误差。kp乘上这个误差(比例控制,就是差的越多,输出越多,很好理解)再叠加kd乘角速度(消除震荡,起到一个阻尼的作用,就是不让它转那么快)。

        另一个比较重要的就是角度的解算,这个的响应速度影响了车控制的平稳。我采用的是一阶互补滤波算法,后换到二阶。下面附上完整代码。

/*************************************** 互补滤波函数 (包含直立环PD)*********************************************/
/*angle_Filtering = K1 * angle_m+ (1-K1) * (angle_Filtering + gyro_m * dt);
angle_Filtering 是融合后的角度值
angle_acc是加速度测量简单计算得到的角度
angle + angle_gyro * dt是陀螺仪积分得到的角度
dtt为采样周期,单位s,就是直立环中断的时间,这里是0.001
K1是滤波器系数,取0.005。
一阶互补滤波也可以看做是加权平均。*/
void ComplementaryFiltering()
{if (icm_acc_x >= 0)icm_acc_x = -1;                                 //tan90°acc_x = - icm_acc_x * 9.8 / 4096.0;                 //转化单位acc_z = icm_acc_z * 9.8 / 4096.0;                   //转化单位gyro_y = icm_gyro_y / 16.4;                         //转化单位anglespeed = - (gyro_y - 0.25);                     //零点偏差angle_acc = atan((acc_z) / acc_x) * 57.3;           //加速度得到的角度,可加零点偏差angle_gyro = angle_Filtering + anglespeed * dtt;    //角速度得到的角度angle_Filtering = K1 * angle_acc + (1 - K1) * angle_gyro;err_angle = angle_Filtering - angle_balance;angleControlOut = P_angle * err_angle + D_angle * anglespeed;
}/*二阶互补滤波(原理是啥?学会了教教我!)*/
void ComplementaryFiltering2()
{if (icm_acc_x >= 0)icm_acc_x = -1;                             acc_x = - icm_acc_x * 9.8 / 4096.0;             //转化单位acc_z = icm_acc_z * 9.8 / 4096.0;               //转化单位gyro_y = icm_gyro_y / 16.4;                     //转化单位anglespeed = - (gyro_y - 0.25);                 //零点偏差angle_acc = atan((acc_z) / acc_x) * 57.3;       //加速度得到的角度,可加零点偏差x1 = (angle_acc - angle_Filtering) * (1 - K2) * (1 - K2);y1 = y1 + x1 * dtt;x2 = y1 + 2 * (1 - K2) * (angle_acc - angle_Filtering) + anglespeed;angle_Filtering = angle_Filtering + x2 * dtt;err_angle = angle_Filtering - angle_balance;angleControlOut = P_angle * err_angle + D_angle * anglespeed;
}

代码中的一些正负号和陀螺仪的安放位置有关,需要自己看。关于一阶的原理,注释里已经说的很详细了,二阶的我是没看懂QAQ。这个滤波算法就是一些固定的东西,icm_xxx为采集到的原始数据,把它们换一下就可以用了,甚至没必要搞懂原理(做比赛是为了学习,还是多看看好)。

注:一定要看“清华方案”把原理搞懂,再看代码会轻松一些。

中断里面长这个样子

void TIM8_UP_IRQHandler (void)
{uint32 state = TIM8->SR;                                                       // 读取中断状态TIM8->SR &= ~state;                                                                // 清空中断状态get_icm20602_accdata_spi();    //读陀螺仪的原始数据get_icm20602_gyro_spi();//ComplementaryFiltering();ComplementaryFiltering2();     //比赛时用了这个,原理可以不会,代进去数就算好了。
}

关于调参

emmm调参的话也应该看那个清华方案的配套视频,非常详细,大致流程就是先取kd为0,慢慢的加kp,差不多能立住在原地抖动时加kd。慢慢将参数调到车能立在原地且没有剧烈抖动。这时推一下车做测试,如果车要跑很长一段距离才能重新立住,说明参数小了,再慢慢加p和d。差不多稳一些就可以上另外两个环了,跑起来后参数还要略微修改。

速度环

关于这个,我自己也有些迷惑。我用的就是kp乘上速度误差,叠加ki乘误差的积分,这样简单的实现一个闭环。然鹅大佬们说直立车的速度环应该是开环控制,这个我是没搞明白。直接放上代码吧。

//速度闭环控制算法(PI)
void SpeedControl()
{actualSpeed = (speed_Left + speed_Right) * 0.5;err_speed = setSpeed - actualSpeed;                         //速度偏差speedIntegral = speedIntegral + err_speed * I_speed;        //积分if(speedIntegral>3000)  speedIntegral=3000;                 //限幅if(speedIntegral<-2000)  speedIntegral=-2000;               //限幅speedControlOutOld = speedControlOutNew;speedControlOutNew = err_speed * P_speed + speedIntegral;
}void OutputSpeedControl()                           //速度环平滑输出
{float fValue;fValue = speedControlOutNew - speedControlOutOld;speedControlOut = fValue * (speedControlPeriod + 1) / 10.0 + speedControlOutOld;if (speedControlOut > 4500)speedControlOut = 4500;                     //限幅if (speedControlOut < -4500)speedControlOut = -4500;                    //限幅
}
void TIM6_IRQHandler (void)
{uint32 state = TIM6->SR;                                                       // 读取中断状态TIM6->SR &= ~state;                                                                // 清空中断状态speedControlPeriod++;OutputSpeedControl();                           //速度环平滑输出   speed_Left = tim_encoder_get_count(TIM_3);              //左编码器 注意插槽位置!tim_counter_rst (TIM_3);speed_Right = -tim_encoder_get_count(TIM_4);            //右编码器 tim_counter_rst (TIM_4);Encoder_accumulate = Encoder_accumulate + speed_Left + speed_Right;Encoder_total = Encoder_total + speed_Left + speed_Right;if(speedControlPeriod > 10)                       //速度周期控制{SpeedControl();speedControlPeriod = 0;}}

编码器(encoder)是一个在轮子旋转时能产生脉冲的传感器,脉冲频率和车速成正比,这个都有例程的,自己康康就好。这里车实际速度我直接采用了编码器读到的值,这里没必要换算成实际速度。将读到的速度带到这个简单的PI即可。这里用了一个速度的平滑输出,即每10个速度环周期更新一次速度输出,这10个周期内将作用在电机上的占空比逐步递增/减过去。

方向环

电磁引导是采用电感与赛道上20kHz的电磁线,产生互感,再将信号整流放大,得到能被单片机检测到的电压。一个车上安装3-5个电感,根据这几个电压强度来判断当前车的位置。电感与电磁线所成的角度,距离都会反映到这个电压值。所以合理安排电感就能判断赛道上不同的元素。

这个采用了PD。。。反正我是没理解这个D参数怎么影响运行效果。而且我们的方向偏差就是生硬的采用了最外边两个电感的差值,速度快的时候效果不好。(第十六届只要完赛就是成功,还轮不到比速度QAQ)有一些比较好的算法,比如差比和什么的,自己去研究吧,我太菜(懒)了。

//方向闭环控制算法(PD)
void directionControl()
{dvar = BiasIndActual - BiasIndActual_last;dirControlOut = P_direction * BiasIndActual + D_direction * dvar;BiasIndActual_last = BiasIndActual;
}

最后

这次比赛我是学到了不少东西,但是有因为经验不足,耽误了太长时间,导致没有好的成绩。当初我让车动起来就花了2个月的时间,从一脸懵逼到上海之旅,感触还是挺深的,也希望这个文章能快速的帮小白入门(理解了之后就没那么难,M3的芯片从上手到去比赛只调了20个小时,相当于重新做了个直立车)。当然,我发现就算有学长帮助,也会把能踩的坑都踩一遍2333,这才能真正学习到吧。

完整代码我整理好之后放上来。

没想到有好多小伙伴想看看完整代码,但是我一直懒得上传hhhh。放到GitHub了,gitee太拉跨,一次只能传20个文件。

https://github.com/fomalhaut251/Balance-car.githttps://github.com/fomalhaut251/Balance-car.git


/********************************************************************************* 致谢:真诚感谢李子昊,刘希文,曾繁钦,高集殊,季炜,雷超等学长学姐对我们提供的支持与帮助.*        感谢一起交流的外校同学,尤其是中国矿业大学徐海学院的同学,在交流中学习到了很多.*       感谢往届的车友前辈,许多时候还是靠祖传方案才能快乐逮虾户.* * 说明:作者水平有限,采用了上古时期多个PID结果直接相加的方案.*      程序的变量名都比较长,但也便于理解,注释较全,希望能帮到学弟们.*       仅限初学者把直立车立起来走两步,元素处理也就图一乐,后续可能更新串级PID方案.*       欢迎技术交流讨论.* * 版权信息:* 中国矿业大学 机电工程学院 不显山车神队*  马梦雅,刘宇鑫,张书晨,陈振尧.*  (C)Copyright CUTM, 2021. *  ALL RIGHTS RESERVED.
********************************************************************************/

[智能车]平衡车/直立车的入门经验(代码讲解)相关推荐

  1. 直立车各环的调试_大学生智能车竞赛之直立车控制,我之初见(四)

    原标题:大学生智能车竞赛之直立车控制,我之初见(四) 直立车控制之转向环 我认为转向环的控制是智能车控制的核心,前文也有提到,直立环和速度环其实可以并为一个环的控制而且控制的方法基本就是 P. D 或 ...

  2. 第16届智能车竞赛双车接力组—直立车经验语录

    第16届智能车竞赛双车接力组-直立车经验语录 前言 直立环核心控制算法-串级PID 转向环控制算法 算法框架 搭车方法 波形拟合 调车方法 角速度环整定方法 角度环整定方法 速度环整定方法 转向环整定 ...

  3. 计算机毕业设计 SSM+Vue汽车租赁系统 网上租车系统 车辆租赁管理系统 在线租车平台Java Vue MySQL数据库 远程调试 代码讲解

  4. 计算机毕设 SpringBoot+Vue小区物业管理系统 物业管理信息系统 智能物业管理系统Java Vue MySQL数据库 远程调试 代码讲解

  5. 基于串级PID的直立车控制算法研究

    徐厚华 何哲嘉 向颖锋 2020-10-31 Saturday 00摘要   直立平衡车因其动力学系统同时具有多变量,非线性,不稳定,强耦合等特性,传统的单环PID控制平衡已经略显吃力.本文将采用内环 ...

  6. 直立车想节能——2020全国大学生智能车车竞赛经验记录之梦的开始

    如今回首,我不懂我一个通信工程的为什么要去做这个比赛哈哈哈,当时我是队友中兴趣最浓烈的,虽然结果一般,但是我真的觉得很有收获学到了很多,也不后悔!那么从这也算是梦的开始,不过到最后大梦一场,终究黄粱一 ...

  7. 全国大学生智能车竞赛经验分享—直立车

    摘自:https://mp.weixin.qq.com/s/Jqy12s5BpsjBn1TocK260w 全国大学生智能车竞赛经验分享-直立车 原创 慕羽⭐ 古月居 1月26日 直立车涉及到的很多的东 ...

  8. 直立车各环的调试_平衡小车调试指南(直立环 速度环)

    平衡小车之家出品 1 平衡小车调试指南 接下来将和大家一起以工程的思想去完成一个平衡小车的调试, 包括平衡小 车的直立环.速度环.转向环,一般我们是先调试直立环,再调试速度环,最好 调试转向环.另外需 ...

  9. 直立车各环的调试_平衡小车调试指南 直立环 速度环

    平衡小车之家出品 1 平衡小车调试指南 接下来将和大家一起以工程的思想去完成一个平衡小车的调试, 包括平衡小 车的直立环.速度环.转向环,一般我们是先调试直立环,再调试速度环,最好 调试转向环.另外需 ...

最新文章

  1. 音频数据建模全流程代码示例:通过讲话人的声音进行年龄预测
  2. c# 字符串是否相等
  3. 修饰符(public/private/default/protected)
  4. 常用日志门面和日志实现
  5. simplexml和xpath
  6. 《商业洞察力30讲》学习笔记(上)
  7. Python之celery的简介与使用
  8. 0x06 MySQL 单表查询
  9. SAP License:未分配差异新解
  10. WCF之旅读书笔记(2):WCF如何通过Binding进行通信
  11. matlab中回归系数,最小一乘回归系数估计及其MATLAB实现
  12. python函数名的应用、闭包和迭代器
  13. Quartz CronTrigger最完整配置说明
  14. php格式化 货币,php – 使用numberFormatter格式化货币
  15. D盘根目录出现msdia80.dll
  16. 服务器技术的发展方向
  17. 体育网站建设开发方案、开发流程
  18. Photoshop制作banner步骤过程
  19. Type-C扩展坞支持的手机类型
  20. 【Add_two_numbers】

热门文章

  1. 台式计算机和笔记本,大一买买笔记本还是台式电脑好?
  2. ***无人驾驶***整理的apollo 入门课程
  3. 常见实用网站集合(行业研究/政策研究/学习/办公/设计/编程)
  4. 2021年起重机司机(限桥式起重机)考试APP及起重机司机(限桥式起重机)免费试题
  5. 【转】Ceph对象存储(rgw)的IPv6环境配置
  6. uni-app 超好用的时间选择器组件(起止时间)
  7. uefi+guid分区与legacy+mbr分区_硬盘分区表格式GUID和MBR知识普及
  8. 用Python制作恋爱日志
  9. Excel工作表探密
  10. 红葡萄酒质量影响因素分析