前言
各位参赛的同学们,大家好!新的一届智能车又来临了,和往届相比,第二十届智能车大赛的赛项发生了很大的变化。今天,我们将聚焦缩微电磁组,由龙邱工程师为大家带来缩微电磁组的全面讲解。讲解内容包括赛题解析,机械结构,硬件配置,软件基础与控制思路。
写这篇手册是帮助新同学快速的了解充满魅力的智能车大赛。同时,会在这里给大家分享我们缩微电磁组的方案与调车心得。我们深知,没有绝对的最优解,但在手册里,我们会毫无保留地分享我们在缩微电磁组积累的方案经验与调车心得。希望这些内容能为大家提供一条清晰的探索思路,让大家在备赛过程中少走弯路,更加从容地应对比赛挑战。
本手册分为七个主要部分:组别简介、硬件清单、开发工具、外设基础、通用控制算法、缩微电磁赛项分享以及备赛建议与资源推荐。建议读者按照章节顺序阅读,特别是新手同学,可先从硬件清单和开发工具部分入手,逐步深入到控制算法和赛项分享。
如果大家想要探讨智能车相关话题,欢迎加入我们的QQ讨论群。在这里,无论是智能车的硬件设计、软件编程,还是比赛策略、技术难题,都能展开交流。
龙邱20届智能车综合技术交流群 228227119 龙邱20届智能车缩微组交流群 1020922696
1. 组别简介
1.1. 规则信息来源
- 智能汽车竞赛官网:全国大学生智能汽车竞赛
- 卓老师 CSDN 博客:《第二十届全国大学生智能汽车竞速比赛规则》第二十届全国大学生智能汽车竞速比赛规则_20届智能车-CSDN博客
卓老师微信公众号推文及每篇公众号文章的评论区:TsinghuaJoking
1.2. 赛题要求
1.3. 规则解析
1.3.1. 主控平台
缩微电磁组可用的微控制器(MCU)型号包括:
AI8051U、AI8052U、STC32G12K128 和 STC8H8K64U。
1.3.2. 规则要点
- 折线夹角:折线夹角不小于 90°,日常调试时应考虑到直角弯。
- 供电限制:车模的运行电源来自超级电容,不能使用电池进行供电。
需要注意:自制的电路板需在正面覆铜面展示队伍信息,包括学校名称、队伍名称、制作日期。
赛道参考示例(电磁组没有断路区,无需区分黑白胶带):
2. 硬件清单
2.1. 车模
针对缩微电磁组所采用的自制车模,虽然没有对其尺寸规格设定明确限制,但考虑到所有折线内角均配置有锥桶,并且这些锥桶底边至电磁线的距离不少于 15 厘米,因此建议将车模宽度控制在 20 厘米以内,从而确保车模与锥桶间至少保持 5 厘米的安全间隙。
对于此类缩小版赛道环境,传统车模难以适应的主要原因在于其车身过长以及较大的转弯半径。因此,在设计缩微电磁车模时,应当着重于减少车辆长度及减小最小转弯半径,而对宽度的要求则相对宽松。
在满足上述宽度要求的前提下,还需注意将车体重心集中于转向中心附近,并尽可能降低重心高度,同时减轻车模重量,减小惯性的影响,使车模发挥更好的动态性能。
针对缩微赛项,龙邱设计了一款差速四轮车模方案供大家参考:
- 车模整体宽度 18.8 cm,转向中心空间充足,孔位丰富,方便安装各个模块,重心更好控制,降低重心高度的同时实现重心集中于转向中心处。
- 传动系统占用空间小,连接牢固,不易变形,运转顺畅,齿轮啮合丝滑。
- 车身广泛采用了碳纤维、铝合金材料,不仅强度高、稳定性好,而且重量轻。
- 充电线圈采用细线绕制的mini线圈,重量轻、尺寸小,配有线圈安装托盘,可直接固定在车模底部,便捷牢固,重心合理。
- 采用130 电机,重量轻,占用空间小,且预留较大可调孔位,便于更换电机。
- 定制硅胶胎皮,胎皮表面平整,边缘进行了圆角处理,免去了轮胎打磨处理的环节,摩擦力表现优异。
- 定制铝合金轮毂,重量轻,有效降低车模整体重量,良好的机械强度确保车模在复杂赛道环境下的稳定性和耐用性。
2.2. 器件清单
主板 | |||
超级电容放电电阻 | 给超级电容组快速放电 | 是 | 否 |
2.3. 模块详解
2.3.1. 迷你电磁一体板
鉴于缩微电磁组需要的模块较多,且缩微车模空间有限,故我们为缩微电磁组特制了一款电路板,集核心板、运放模块、主板为一体,尺寸仅有 64.06 * 50.77mm,缩小体积的同时也能够减轻重量,方便安装。
- 采用 AI8051 芯片,主频 42Mhz,LQFP48 封装,带有 Type-C接口,可直接使用 Type-C 数据线烧录程序,不需要单独购买核心板和下载器。
- 板载 6 路运放电路,可直接对 LC 谐振信号进行放大输出,不需要单独购买运放模块。
- 自带电源电压检测电路,可直接采集超级电容或电池电压。
- 板载OLED屏幕、陀螺仪、干簧管、编码器和电机驱动等接口,外设资源丰富。
2.3.2. DRV8701E 双路驱动
电机应该都比较熟悉,在电机两端施加电压,电机就会旋转,电压越大,转速越快。通过电压越大,转速越快这句话,我们可以想到用PWM来控制转速,但是直接把电机直接接在核心板IO口是不可行的(因为IO口电压比较低,而且电流太小),因而就需要电机驱动。
该驱动采用门极驱动芯片 DRV8701E + N-MOS 管 TPH1R403NL 方案,无需升压电路,输入电源 5.9V ~ 28V 均可使用,带过流保护功能。
控制方法:控制一个电机只需要输入一个 PWM 信号控制转速,通过一个普通 GPIO 输出高低电平来控制转向。
- PH-6P接口:隔离供电以及信号输入。
- XT30端子:直流电压输入,输入电压5-28V,一般大小为电机可承受的最大电压。
- 蓝色端子:直流电压输出,输出电压与输入PWM值正相关。
当PWM波的占空比越大时,蓝色端子输出的电压值与XT30端子的电压值越接近,反之则与0V越接近。
U xt30×脉宽 = U蓝×周期,两端同时除以周期,得到如下关系式:
U xt30×占空比 = U蓝。
例如当XT30端子的幅值为24V,占空比为50%时,与直流电压12V作用到电机上所产生的效果是一模一样的,即速度相同;即24V×50%=12V。
另外,既然满足这个关系,那PWM波的频率是不是可以随意了,答案当然不是,频率太低会导致电机运转不畅,振动大,噪音大;频率太高会导致驱动器开关损耗较大,甚至有电机会啸叫而不转的情况。一般1k~30k的PWM频率较为普遍,几百Hz的也有,实际上需要根据电机功率在测试时确定合适的PWM频率范围为宜。
可以观察到,输入信号除了供电(3V3、GND)以及PWM信号,还有一个输入叫“I/O”,这个信号的作用是控制蓝色端子输出正反电压的,这样就可以控制电机进行正反两个方向的旋转。连接并正确使用电机驱动板,其中2.0mm间距的白色接口为信号接口,需要连接到主控板,其VCC连接主控板电机接口的VCC,剩余引脚按顺序连接,GND可以不连接。XT30端口为供电端口,连接主控板上的电池口。蓝色的端口为电机连接口,这里没有正负之分。
驱动板采用GPIO与PWM相结合控制电机转动,其中GPIO引脚控制电机转动方向,PWM引脚控制电机转动速度,电机驱动板输出电压(蓝色端子的电压值)。
2.3.3. 电容组和放电电阻
超级电容组用来存储无线充电接收的电能,以供车模运行。
放电电阻用来给超级电容快速放电,正式比赛时每次充电前需要将剩余电能放掉。
超级电容组使用注意事项:
- 连接超级电容时正负极不要接反!!!
- 在接收的时候需要注意超级电容组的电压,防止过充!!!(充满后应及时拿开接收线圈或使发射端停止输出)
2.3.4. 无线充电接收端
接收模块电流可达25A,模块尺寸65.8mm * 38.2mm,过流大,尺寸小,方便安装。采用 LCC 谐振控制接收。
充电接收端使用注意事项:充电时一定要接超级电容组!!!
2.3.5. 无线充电发射端
无线充电发射开发板采用 AI8051 单片机控制,采用 LCC 谐振电路,四 MOS 独立控制,具备强大的发射功率,可以稳定输出 500W。确保了高接收效率的同时缩短了充电时长。
- 配套可烧录固件、测试视频和使用手册。
- 可通过按键调节输出总能量,有效避免电容过充。
- 自动切换待机和输出状态,无接收线圈时,发射端自动进入待机状态。有接收线圈时,发射端自动进入额定输出状态。
- 自带电流检测,保证输出安全闭环,当输出电流异常时,自动停止输出。
- 数据可视化,可显示供电电压、输出电流、无线充电输出状态等。
- 可修改充电程序,进行二次开发。
2.3.6. 无线充电线圈
鉴于原线圈本身具有较大的尺寸和重量,缩微车模空间有限且重心难以协调, 为了更好地让线圈适应车模底部的空间,我们将原来的粗线更换为细线,将形状从圆形改为偏方形,不仅减小了尺寸,而且性能不受影响,更适合在自制车模中使用,以实现合理的结构:
- 外部尺寸仅有11cm * 8.5cm,便于安装,节省空间,大幅提高空间利用率。
- 重量约29g,仅为原线圈的三分之一,能够节省电能消耗并减小惯性的影响,优化车模动态性能。
- 两种线圈在感抗值方面保持一致,充电效率未见差异。
- 线圈使用补充说明:
- 线圈焊接时不区分正负极。
- 仅更换车模上的接收线圈即可,发射端线圈无需更换,充电效率不受影响。
2.3.7. 姿态传感器
姿态传感器在智能车中的应用:
- 与转向环串级使用,达到更好的控制效果。
- 调整平衡车姿态,使车身平衡且能正常转向和前进。
- 作为角度环闭环控制的输入。
- 积分角度作为元素状态切换条件,例如确定环岛的进环、环内、出环时机。
姿态传感器主要由加速度计与陀螺仪两部分组成,加速度计用于测量物体的加速度,陀螺仪用于测量物体的角速度。通过对加速度和角速度的测量,可以推导出物体的角位移。
陀螺仪的欧拉角是用来描述物体在空间中的姿态(即旋转角度)的一种表示方法,包括滚转角(Roll)、俯仰角(Pitch)和偏航角(Yaw)。
滚转角(Roll)是物体绕X轴旋转的角度,用来描述物体绕自身左右倾斜的程度。当物体绕X轴正方向逆时针旋转时,滚转角为正值,绕X轴负方向顺时针旋转时,滚转角为负值。
俯仰角(Pitch)是物体绕Y轴旋转的角度,用来描述物体绕自身前后倾斜的程度。当物体绕Y轴正方向逆时针旋转时,俯仰角为正值,绕Y轴负方向顺时针旋转时,俯仰角为负值。
偏航角(Yaw)是物体绕Z轴旋转的角度,用来描述物体绕自身旋转的方向。当物体绕Z轴正方向逆时针旋转时,偏航角为正值,绕Z轴负方向顺时针旋转时,偏航角为负值。
通过测量陀螺仪的角速度,可以积分得到物体的欧拉角。欧拉角的变化可以用来控制物体的姿态,例如在飞行器中,通过调整滚转角、俯仰角和偏航角,可以实现飞行器的稳定控制和导航功能。
需要注意的是,欧拉角表示的是物体在空间中的绝对姿态,而非相对于某个参考物体的姿态。在实际应用中,为了避免欧拉角的奇异性问题,常常使用四元数或旋转矩阵等其他表示方法。
2.3.8. 编码器
在智能车中,编码器的主要功能是测量定时器中断周期内的脉冲数,用作速度控制回路中的实际反馈值。通过将此实际值与预设的目标值进行比较,并采用PID控制器来调整输出,从而实现精确的速度闭环控制。
编码器发送脉冲信号,定时器引脚接收脉冲信号,通过AB信号的差异或者根据方向引脚电平判断是正值还是负值,脉冲信号值会在定时器中累计,直到手动清除,所以每次读取编码器值后需要清除累计值,才可以获得实时速度值。
细心的读者可能会发现,相同转速下编码器值读取大小与读取时间间隔有关,读取时间间隔越大,累计值越大,读取到的值也会越大。
2.4. 接线说明
2.4.1. 电机驱动模块
2.4.2. 编码器模块
2.4.3. 电磁检测板
2.4.4. 运放与电感对应关系
此对应关系对应上述2LC电磁检测板接线方式。
3. 开发工具
3.1. 硬件设计软件
熟练掌握至少一种常用的电路设计软件,如 Altium Designer、 立创 EDA 等。了解软件的界面布局、基本操作流程和常用功能模块,如原理图设计、PCB 布局、布线、铺铜、规则检查、生成报表等。
能够使用软件进行简单的电路原理图绘制和 PCB 设计, 包括元件库的创建和管理、原理图的连接和标注、PCB 的布局规划和布线、铺铜等。掌握 PCB 布局和布线的基本技巧和方法,如元件的合理布局、信号线的走向和间距控制、电源线和地线的布线方式、过孔的使用和优化等。
了解 PCB 设计的基本原则和规范,如电气性能要求、信号完整性、电源完整性、电磁兼容性(EMC)等。能够根据电路的功能和性能要求,进行合理的 PCB 设计,确保 PCB 的电气性能和可靠性满足实际应用的需求。同时,要了解 PCB 制造工艺和生产流程,掌握 PCB 设计文件的输出和制作要求,能够与 PCB 制造商进行有效的沟通和协作,确保 PCB 的制造质量和生产进度。
我司提供的资料中包含 PDF 版原理图、基于 Altium Designer(AD)的原理图封装库和 PCB 封装库。同学们在自己制作 PCB 时可以使用 AD 导入我司提供的封装库文件,参考 PDF 版原理图完成电路板设计。主板原理图中包含了智能车竞赛中常用的外设模块端口,在自己制版时仅需要画出用到的外设接口即可,没有用到的接口不需要引出。
需要注意:自制的电路板需在正面覆铜面展示队伍信息,包括学校名称、队伍名称、制作日期。
3.2. 搭建开发环境
3.2.1. 安装 Keil 集成开发环境
通过查阅规格书(可在 STC 官网 深圳国芯人工智能有限公司-芯片手册 获取)可知,AI8051U型号可支持 32 位模式和 8 位模式。如果用户需要使用 32 位模式,则需要安装 Keil 的 C251 编译器;如果用户需要使用 8 位模式,则需要安装 Keil 的 C51 编译器;如果需要同时使用 32 位模式和 8 位模式,则 C251 和 C51 都需要安装。在此我们使用的是 32 位模式,故需要安装 Keil C251。
1、首先登录 Keil 官网,下载最新版的 C251 安装包,下载链接如下:
2、下载完成后双击安装包开始安装,点击“Next”:
3、勾选“I agree to all the terms of the preceding License Agreement”,然后点击“Next”:
4、选择安装目录,然后点击“Next”:
5、接下来随意填写即可,然后点击“Next”:
6、安装完成,点击“Finish”结束。
7、安装完成后需要破解,CSDN 上相关破解教程有很多,大家可以自行搜索(Keil C251破解),这里就不再赘述。
3.2.2. 安装 STC-ISP 烧录软件
进入 STC(宏晶科技)官网:深圳国芯人工智能有限公司-工具软件。
在置顶选项中找到“软件工具”,单击进入后即可下载最新版的 ISP 烧录软件。
3.2.3. 添加型号和头文件到 Keil
使用 Keil 之前需要先安装仿真驱动。仿真驱动的安装步骤如下:
- 首先打开 ISP 烧录软件,然后在软件右边功能区的“Keil 仿真设置”页面中,先选择对应的单片机型号(此处以 AI8051U 为例),然后点击“添加型号和头文件到 Keil 中 添加仿真器驱动到 Keil 中”按钮;
- 接下后会出现如下画面:
3、将目录定位到 Keil 软件的安装目录,然后确定。安装成功后会弹出如下的提示框:即表示驱动正确安装了。
3.2.4. 安装 CH340 串口驱动
进入以下网址下载安装即可:
3.2.5. 下载开源库
开源库获取途径:
- 龙邱20届智能车综合技术交流群:228227119
- 龙邱科技淘宝客服
库结构说明:
模块例程包括:GPIO 输入输出、ADC 数据采集、UART 串口收发、OLED 屏幕、定时器中断、编码器读取、电机控制、陀螺仪数据读取、EEPROM 掉电存储等诸多使用示例。
3.2.6. 拓展 Keil 的 C 代码中断号
在 Keil 目前的 C51、C251 编译环境下,中断向量号只支持 0~31,即中断地址必须小于0100H。程序里使用的中断向量号超过 31,编译时就会报错。随着芯片的功能越来越多、越来越强,STC 单片机的部分中断向量号已经超出 31。此前临时解决的方法是借用 13 号中断向量地址,通过汇编代码从当前中断地址跳转到 13 号中断地址执行。 此外,有网友提供了 keil 中断号拓展插件,安装到 C51、C251 目录下也可以解决中断向量号超 31 时编译报错的问题。
插件安装方法:
- 首先打开开源库文件夹中的“软件工具”文件夹,双击运行文件夹内的可执行文件:
- 点击“打开”按钮,选择 Keil 的安装目录,然后点击确定按钮:
- 安装成功后显示如下提示:
即表示安装完成。(注意:部分旧版本 Keil 编译器可能不支持此插件)
3.2.7. 点灯程序测试
- 首先打开 Keil 软件,点击置顶栏中的“Project”,点击“Open Project”:
- 选择开源库中的初始工程文件,打开工程:
- 打开工程后,在左侧边栏中找到“User”中的“main.c”双击打开,然后翻到第55行的LED灯闪烁测试程序,选中后取消注释。
- 然后点击“Build”即可编译程序,生成可下载进单片机的 hex 文件:
- 编译成功后窗口左下角会出现如下提示:
- 使用 Type-C 数据线连接主板或核心板,或者使用 USB 转 TTL 模块连接单片机串口。
- 打开 Aiapp – ISP 烧录软件,找到工程成功编译后生成的 hex 文件并打开。
- 接下来选中对应单片机串口,配置好频率(AI8051频率设置为42Mhz),点击左下角的“下载/编程“,给单片机通电复位即可完成下载。
3.3. 多功能调试助手
在日常的备赛过程中,上位机或图传等调试助手扮演着至关重要的角色,它能提供实时的数据反馈,帮助研发人员快速定位并解决问题。
合理利用工具使得开发者可以更加专注于智能车算法的设计和优化,而不用被琐碎的调试所困扰。从而提高开发效率,使团队能在短时间内完成更复杂的任务。
4. 外设基础
在使用外设时,首要步骤是明确这些设备与单片机之间连接的具体引脚。引脚查询方法:
- 查看电路板丝印层的标注。
- 查看电路板设计原理图。
4.1. GPIO 输入输出
GPIO是通用输入输出(General Purpose Input/Output)端口的简称。通俗来讲就是单片机可控制的引脚,所有的GPIO引脚都有基本的输入输出功能。
最基本的输出功能是由单片机控制引脚输出高、低电平,实现开关控制,如把GPIO引脚接入到LED灯,那就可以控制LED灯的亮灭,引脚接入到继电器或三极管,那就可以通过继电器或三极管控制外部大功率电路的通断。
最基本的输入功能是检测外部输入电平,如把GPIO引脚连接到按键,通过检测电平高低区分按键是否被按下。
此处应用的是引脚的输出功能,引脚的输出模式有以下几种:
- 推挽输出:推挽输出的最大特点是可以真正能真正的输出高电平和低电平,在两种电平下都具有驱动能力。
- 开漏输出:开漏输出最主要的特性就是高电平没有驱动能力,需要借助外部上拉电阻才能真正输出高电平。
补充说明:所谓的驱动能力,就是指输出电流的能力。对于驱动大负载(即负载内阻越小,负载越大)时,例如IO输出为5V,驱动的负载内阻为10欧姆,于是根据欧姆定律可以正常情况下负载上的电流为0.5A(推算出功率为2.5W)。显然一般的IO不可能有这么大的驱动能力,也就是没有办法输出这么大的电流。于是造成的结果就是输出电压会被拉下来,达不到标称的5V。当然如果只是数字信号的传递,下一级的输入阻抗理论上最好是高阻,也就是只需要传电压,基本没有电流,也就没有功率,于是就不需要很大的驱动能力。
4.2. ADC 采集
ADC 是“Analog-to-Digital Converter”的英文简称,能将模拟信号转变为数字信号。通常是将信号采样并保持以后,再进行量化和编码,这两个过程是在转化的同时实现的。具体的转化步骤在这里就不展开说了,如果是开发者使用,我们应该关注哪些参数:
- 分辨率—表示 AD 对输入信号的分辨能力,及数值部分的精度。一般模拟采样中使用 8 位还是 12 位的 ADC 说的就是分辨率。例如:输入模拟电压的变化范围为0~3.3 V,输出12位二进制数可以分辨的最小模拟电压为 3.3V / 4095 ≈ 0.806mV;
- 工作电压和基准电压(内部或者外部基准):工作电压是 AD 芯片工作的额定电压,关键的是基准电压,又叫参考电压,可以来之芯片内部又或者外部接入,其决定了 AD 的分辨率,所有基准电压一定要稳。
4.3. 定时器中断
定时器中断是一种基于定时器的中断,它允许在特定时间间隔内触发一个事件或一段代码。在智能汽车竞赛中,定时器中断常用于周期性任务,例如定时、传感器数据采集、转向环和速度环控制、编码器计距离或者陀螺仪角度积分。
例如设置中断周期为5ms,那么就会每5ms执行一次中断里的程序。
4.4. PWM
PWM是一种用数字信号模拟模拟信号的技术,它通过在一个固定的时间周期内改变信号的脉冲宽度来模拟电压或电流的变化。PWM信号通常用于控制各种设备,如电机、LED灯、伺服机构等,以调整它们的输出或工作状态。PWM信号具有两个主要参数:
- 周期/频率(Period):PWM信号的一个完整周期持续的时间,通常以微秒或毫秒为单位。电机通常选择 10kHz ~ 20kHz 的PWM频率,频率过低会导致电机噪音和发热,频率过高可能超出驱动芯片的响应能力;舵机通常要求 50Hz ~ 333Hz,其角度由高电平脉冲宽度(0.5ms ~ 2.5ms)决定。
- 占空比(Duty Cycle):高电平状态所占整个周期的百分比。它决定了PWM信号的平均电压或电流值。
PWM信号的占空比决定了目标设备的输出特性,例如电机的转速或LED的亮度。更大的占空比通常表示更高的输出值。在智能车竞赛中,PWM是实现电机速度控制和舵机转向调节的核心技术。通过调整PWM信号的占空比,可以精确控制电机的转速和舵机的转向角度。
4.5. 串口通信
单片机中的串口是一种用于数据传输的通信接口,它可以将数据以串行的方式进行传输。串口通常由两个引脚组成,即发送引脚(TX)和接收引脚(RX)。当单片机需要发送数据时,它将数据转换为串行格式,并通过TX引脚发送出去。接收方通过RX引脚接收数据,并将其转换为原始格式,从这里可以知道串口通信在连接时需要将发送引脚(TX)连接接收引脚(RX)。
串口通信可以通过硬件或软件实现,其中硬件串口通常具有更高的速度和可靠性,而软件串口则具有更高的灵活性和可定制性。在单片机中,串口通常用于与其他设备进行通信,例如遥控器、传感器、显示屏、上位机等。
串口协议是指在串行通信过程中,双方之间所遵守的通信规则和约定。UART串口协议包含以下内容:
- 数据帧格式:UART串口协议使用包含起始位、数据位(5至8位)、可选的奇偶校验位及1或2个停止位的数据帧来传输信息。具体格式需双方预先协商确定。
- 波特率:UART串口协议使用波特率来指定数据传输的速率。波特率表示每秒钟传输的位数。常见的波特率包括9600、19200、38400、57600和115200等。通信双方必须使用相同的波特率才能正确地接收和发送数据。
- 帧同步:UART串口协议使用起始位和停止位来标识每个数据帧的开始和结束。起始位是一个低电平信号,用于通知接收端数据帧的开始。停止位是一个高电平信号,用于通知接收端数据帧的结束。
- 错误检测:UART串口协议利用奇偶校验位检查数据位数量是否符合预期,并通过校验和验证整个数据帧的完整性,以此来发现传输过程中的错误。
- 数据流控制:UART串口协议支持硬件数据流控制和软件数据流控制。硬件数据流控制使用CTS和RTS信号来控制数据传输。软件数据流控制使用XON(ASCII码为0x11)和XOFF(ASCII码为0x13)字符来控制数据传输。
串口通信作为一种基础而强大的技术手段,广泛应用于智能车等自动化领域中,可以实现数据的传输,从而对系统进行实时监控和调试。
5. 通用控制算法
5.1. PID 算法简介
PID 算法是工业应用中最广泛算法之一,是一种常用的反馈控制算法,它是根据系统当前状态与期望状态之间的差异来调整控制器输出的方式。在闭环系统的控制中,可自动对控制系统进行准确且迅速的校正。PID 算法已经有 100 多年历史,在四轴飞行器,平衡小车、汽车定速巡航、温度控制器等场景均有应用。PID 是 Proportional-Integral-Derivative 的缩写,分别代表比例、积分和微分三个部分。
PID控制算法将比例、积分和微分三个部分的输出进行线性组合,得到最终的控制器输出。通过调整三个部分的权重和参数,可以实现对系统的精确控制。
其中:
Kp:比例增益,为调试参数。
Ki:积分增益,为调试参数。
Kd:微分增益,为调试参数。
Error:误差 = 设定值(输入)- 反馈值(测量元件输出值)。
根据实际系统的特性和需求,调整PID控制算法中的比例、积分和微分三个部分的权重和参数,以使系统能够以最佳的性能响应和控制的过程,我们一般称之为“调参”。
在调参过程中:
Kp 过大会对误差的变化做出过大的反应,从而导致系统动作幅度过大,容易引起振荡甚至不稳定。过小意味着对误差的调整力度不足,系统达到目标值的速度变慢,响应滞后。
Kp 即使设置得较好,仅靠 Kp 控制仍会存在部分问题:
Kp 控制对持续存在的小误差没有累计作用,无法完全消除系统的稳态误差。这是因为比例控制的输出直接与当前误差成正比,而当误差较小时,调整力度可能不足。需要Ki(积分)控制来消除这种误差。
Kp 控制对快速变化的误差反应不足,而Kd(微分)控制可以预测误差变化趋势,帮助提高系统动态性能,避免过冲,减少超调。
5.2. 电机闭环控制
给定占空比 → 测转速 → 比较实际转速和目标转速 → 重新调整占空比,这样的过程其实就是一个闭环控制,我们发现这个过程形成了一个回环:每次调整的占空比大小都是基于上一次结果得到的。相比开环控制,闭环控制多了信息反馈环节(测电机转速),我们根据反馈信息再做出进一步调整,接着获得调整后的反馈信息,再基于更新过的反馈信息进行新一轮的调控。
通常我们使用增量式 PID 算法来实现对电机的闭环控制。示例代码:
该过程建议选择一个相对开阔且具有较长直线段的区域,以尽量减少周围潜在的其他电磁源对电感值的干扰。
6.2. 差比和算法
- 头文件:
typedef struct PID { double Error; // 当前偏差 double LastError; // 上次偏差 double PrevError; // 上上次偏差 float KP; // 比例系数 float KI; // 积分系数 float KD; // 微分系数 }PID; extern PID left_MotorPID, right_MotorPID; // 左右电机结构体变量声明 #define MOTOR_MAX_DUTY 3000 // 电机最大占空比限制
- C文件:
PID left_MotorPID, right_MotorPID; // 定义左右电机 PID 结构体变量 /** * @brief 占空比限幅保护函数 * @return 限制后的占空比值 */ double limit_DutyCycle(double duty, double min, double max) { return duty >= max ? max : (duty <= min ? min : duty); } /** * @brief 增量式PID控制器实现 * @param pid 指向PID控制器的指针 * @param actual_Speed 实际速度值 * @param target_Speed 目标速度值 * @return 本次PID计算得到的增量值 */ double PID_Increment(PID *pid, double actual_Speed, double target_Speed) { double Increment = 0; // 设置PID参数 pid->KP = 18; pid->KI = 18; pid->KD = 0; pid->Error = target_Speed - actual_Speed; // 计算误差 // 计算增量 Increment = pid->KP * (pid->Error - pid->LastError) + pid->KI * pid->Error + pid->KD * (pid->Error - 2 * pid->LastError + pid->PrevError); // 更新误差记录 pid->PrevError = pid->LastError; pid->LastError = pid->Error; return Increment; } /** * @brief 电机控制函数 * 计算并更新左右电机的占空比 */ void control_Motors() { // 更新左电机占空比 left_MotorDuty += PID_Increment(&left_MotorPID, left_EncoderValue, left_TargetSpeed); left_MotorDuty = limit_DutyCycle(left_MotorDuty, -MOTOR_MAX_DUTY, MOTOR_MAX_DUTY); // 更新右电机占空比 right_MotorDuty += PID_Increment(&right_MotorPID, right_EncoderValue, right_TargetSpeed); right_MotorDuty = limit_DutyCycle(right_MotorDuty, -MOTOR_MAX_DUTY, MOTOR_MAX_DUTY); }
6. 缩微电磁赛项分享
6.1. 电感信号的处理
6.1.1. 中位值平均滤波
传感器数据常常受到环境噪声的影响,如电磁干扰、电机噪声以及由靠近电源线所引发的信号波动。
滤波技术中,常见的方法包括均值滤波、低通滤波、中值滤波和卡尔曼滤波等。选择哪种滤波方法取决于噪声的特性以及具体的应用需求。在电磁组中对于电感值的处理,中位值平均滤波法是一种比较常用且推荐的方法。
中位值平均滤波法结合了中值滤波与算术平均滤波的优点,其基本原理是对连续采集的 N 个样本点去除最大值和最小值后,再求剩余 N-2 个数值的算术平均值。这种方法能够在一定程度上抑制异常值对最终结果的影响,同时保持良好的平滑效果。
/** * 中位值平均滤波函数 * @param arr 输入数据数组 * @param times 数据采样次数 * @return 滤波后的平均值 */ int Median_Average_Filter(int* arr, int times) { int min = arr[0], max = arr[0], sum = 0; int i = 0; // 遍历数组,找出最大值、最小值并求和 for (i = 0; i < times; i++) { if (arr[i] < min) min = arr[i]; if (arr[i] > max) max = arr[i]; sum += arr[i]; } // 计算去掉最大值和最小值后的平均值 return (sum - min - max) / (times - 2); }
6.1.2. 归一化 & 限幅
归一化的目的是为了消除数据范围不一致性带来的负面影响。如果不进行归一化处理,各个电感数据范围的差异可能会导致控制算法难以调谐。通过归一化,可以将这些数据映射到一个统一的范围(如 1 ~ 100),从而简化后续的数据处理过程,并提高数据的一致性和稳定性。为后续的偏差计算和控制算法提供可靠的基础,进而提升控制系统的稳定性和准确性。
以下是电感值归一化处理的步骤:
- 对每个电感的幅值进行独立测量。首先将该电感对应的运算放大器(简称运放)调节至其最小输出状态,使该电感与电磁线呈平行关系(高度不进行人为调整,保持车模自然放置高度),记录此时的读数作为最小值;然后将运放调节至最大输出状态,移动车模位置,使该电感与电磁线之间呈垂直关系(高度不进行人为调整,保持车模自然放置高度),记录此状态下的读数作为最大值。
- 利用所测得的最大值和最小值,根据预设的归一化公式进行数据转换。
- 完成上述归一化过程后,使该电感与电磁线呈垂直关系,进一步微调运放,使其输出达到其最大值的70%。这一数值作为车模正常运行条件下的参考值。
/** * @brief 归一化函数,将输入值映射到1-100范围 * * @param value 输入初始电感值(此时为整型) * @return float 归一化后的值(1-100) */ float Adc_Normalize(int value, float min, float max) { float normalized = 0; normalized = (float)(value - min) / (max - min) * 100.0f; // 计算归一化值 // 限幅保护,确保返回值在1-100范围内 return normalized >= 100.0 ? 100.0 : (normalized < 1.0 ? 1.0 : normalized); }
差比和算法是一种常用的偏差计算方法,其标准形式为 (L - R) / (L + R),其中 L 和 R 分别表示左横电感和右横电感的读数。这种方法在处理普通赛道或轻微折线赛道时表现良好,能够提供相对准确的赛道位置偏差信息。然而,在面对较大角度折线或直角转弯时,这种简单的偏差计算方法显得力不从心,其计算结果变得不够准确,导致车模无法有效地调整姿态。
为了克服这一问题,我们引入了垂直电感分量,以增强系统在大角度折线或直角位置下的偏差检测能力。具体来说,我们在原有的偏差计算公式中加入了竖直方向上的电磁场分量 (L2) 和 (R2),它们分别代表左右侧竖直电感的读数。
通过将这些垂直方向上的电磁场分量纳入考虑范围,可以确保车模即使在这些复杂条件下也能获得精确且合理的偏差值。
初步改进后的差比和算法:
double eleSub = 0; // 分子
double eleAdd = 0; // 分母
double eleValue = 0; // 差比和
eleSub = (L - R) + (L2 - R2); // 水平差值和垂直差值的叠加
eleAdd = L + R + L2 + R2 + M; // 电感的综合总和
eleValue = (eleSub / eleAdd) * 300.0f; // 偏差值
6.3. 基于中间横电感的动态权重
假设中间横向电感 M 的取值范围为 0 ~ 100,其中在环岛处的电感值接近最大值 100;在普通直道或十字路口处的电感值约为 70;而在直角转弯处,该电感值会减小,且车辆转弯越迟、偏离轨道越远,相应的 M 值就越低。
基于中间横向电感 M 的值,可以计算出一个介于 0.0 ~ 1.0 之间的参数 k,该参数用于调整差比和计算中水平电感和垂直电感的权重。
// 函数:动态权重,分配水平循迹和竖直循迹占比
double Calculate_Weight_Mid(double M)
{
double k = 0;
if(M >= 80) // M >= 80,权重为 100%
{
k = 100.0;
}
else if (M >= 40 && M < 80) // 线性权重
{
k = 2.5*M - 100.0; // y=kx+b:根据 (40,0) 和 (80,100) 解二元一次方程组
}
else // M < 40,权重为 0%
{
k = 0.0;
}
k *= 0.01; // 将范围控制在:0.0 ~ 1.0
return k >= 1.0 ? 1.0 : (k <= 0.0 ? 0.0 : k); // 将 k 限幅保护在 0.0 ~ 1.0 之间
}
void Calculate_Error()
{
double Weight_H = 0; // 水平权重
double Weight_V = 0; // 竖直权重
Weight_H = Calculate_Weight_Mid(M); // M ↑,水平循迹比重 ↑
Weight_V = 1.0 - Weight_H;
}
具体而言,k 值作为水平电感的权重系数,而 1.0 – k 作为竖直电感的权重系数:
- 当M值较高(接近 100)时,k值接近 1.0,此时水平电感占据较大权重,垂直电感权重较小,适用于直道、十字路口及小角度弯道的轨迹跟踪;
- 当M值较小(接近 0)时,k值接近 0.0,这意味着水平电感权重减小,而垂直电感权重增大,适合处理大角度弯道及直角转弯情况下的轨迹跟踪。
通过这种方式,可以根据 M 的值动态调整差比和计算中水平电感和垂直电感的权重,以优化不同行驶条件下的路径跟踪性能。
需要注意的是,垂直电感的权重容易出现超调现象,这可能导致车辆在直角转弯处进入极端转向状态,从而引发甩尾甚至掉头。在调整参数的过程中,建议在直角弯附近手推车模,使用显示屏观察权重参数、偏差值的变化情况,确保权重变化和偏差值的合理性。
融入动态权重后的差比和算法:
eleSub = Weight_H * (L - R) + Weight_V * (L2 - R2);
eleAdd = Weight_H * (L + R) + Weight_V * (L2 + R2) + M;
eleValue = (eleSub / eleAdd) * 300.0f; // 偏差值
6.4. 基于竖直电感的偏差放大
假设两个竖电感的取值范围为 1 ~ 100,则在直道上的时候竖电感值为最小;在直角处竖电感的值是内侧剧烈突增,外侧微小增幅;在十字处竖电感的值是两侧均剧烈突增。
我们希望的是在直道上和十字处以水平电感寻迹为主,在直角处以竖直电感寻迹为主。而直角处独一无二的特征就是两个电感差值巨大,我们可以抓住这个特征来计算一个范围为 0.0 ~ 1.0 的权重系数 k,该系数的值随着竖电感的差值变大而变大,将 1.0 - k 的值乘到差比和算法的分母上,从而实现:
- 当 k 值小的时候,1.0 - k 的值接近于 1.0,差比和的分母不受影响,偏差不受影响;
- 当 k 值大的时候,1.0 - k 的值接近于 0.0,差比和的分母变小,偏差会进行放大。
double Calculate_Vertical() { double k = 0; double sum = 200.0; // 两个竖直电感最大值的和 k = fabs(L2 - R2) / sum; // 浮点型绝对值使用 fabs() // 分母不能为 0,所以最小保护为 0.1 return k >= 1.0 ? 1.0 : (k <= 0.1 ? 0.1 : k); // 将 k 限幅保护在 0.1 ~ 1.0 之间 }
融入动态权重和偏差放大后的差比和算法:
eleSub = Weight_H * (L - R) + Weight_V * (L2 - R2); eleAdd = (1 – Calculate_Vertical()) * (Weight_H * (L + R) + Weight_V * (L2 + R2) + M); eleValue = (eleSub / eleAdd) * 300.0f; // 偏差值
6.5. 转向环串级控制
当我们进行转向控制时,如果车模与赛道偏差较大,那么偏差环的输出值会很大,直接作用在差速上会导致车模转向角速度很快,会导致较大的超调,而且不论怎么修改参数效果始终不尽人意。
上面的转向控制就是单级PID,目标值和反馈值经过一次PID计算就得到输出值并直接作为控制量。但如果目标物理量和输出物理量之间不止差了一阶的话,中间阶次的物理量我们是无法控制的。比如:目标物理量是位置,输出物理量是加速度,则车模的角速度是无法控制的。
使用串级PID可以改善这一点,其信号框图如下:
图中的外环和内环就分别是一个单级PID,每个单级PID需要获取一个目标值和一个反馈值,然后产生一个输出值。串级PID中两个环相“串”的方式就是将外环的输出值作为内环的目标值。
通过串级PID可以有效缓解超调和震荡现象。
double Bias_PID[2] = {0.006, 0.06};
double Gyro_PID[2] = {0.007, 1.4};
double PlacePIDELE_Control(double NowPiont, double SetPoint, double *TURN_PID) // 位置式PID
{
double PP, DD;
double iError, LastError, Delat_iError, Actual;
iError = SetPoint - NowPiont; // 当前误差
Delat_iError = iError - LastError; // 本次误差与上次误差的差值
PP = *TURN_PID;
DD = *TURN_PID+1;
Actual = PP * iError + DD * Delat_iError; // PID 输出值
LastError = iError; //更新误差
return Actual;
}
void Dir_Control()
{
static int t = 0;
if(++t>=3)
{
t = 0;
eleOut_0 = PlacePIDELE_Control(elefValue, 0, Bias_PID); // 偏差环(外环)
}
// 偏差环输出值作为角速度环目标值
eleOut_1 = - PlacePIDELE_Control(gyro_zz, eleOut_0, Gyro_PID); // 角速度环(内环)
eleOut_1 = range_protect(eleOut_1, -100, 100);
}
6.6. 差速控制
电机差速控制是指通过控制车辆两侧电机的转速差异来实现车辆的转向和转弯。一般来说,当车辆需要向左转时,右侧电机的转速会比左侧电机的转速快,从而使车辆向左转弯。反之,当车辆需要向右转时,左侧电机的转速会比右侧电机的转速快,从而使车辆向右转弯。
在比赛中,单片机通过转向环的输出值,在基础速度的基础上,通过差速计算公式分别计算出左右轮的目标速度,然后结合电机PID闭环控制实现速度的精确调节。
double Base_Speed = 50; // 基础速度
double Left_Speed = 0; // 左轮目标速度
double Right_Speed = 0; // 右轮目标速度
void Calculate_Differential_Drive() // 差速计算
{
double k = 0; // 差速比例系数
eleOut_1 = range_protect(eleOut_1, -100, 100); // 转向环输出限幅
// 计算左右轮目标速度
if(eleOut_1 >= 0) // 左转
{
k = ele_Out_1 * 0.01; // 缩放至 0.0 ~ 1.0
Left_Speed = Base_Speed * (1 - k);
Right_Speed = Base_Speed * (1 + k*0.5); // 加少减多
}
else // 右转
{
k = -ele_Out_1 * 0.01; // 取相反数并缩放至 0.0 ~ 1.0
Left_Speed = Base_Speed * (1 + k*0.5); // 加少减多
Right_Speed = Base_Speed * (1 - k);
}
}
6.7. 元素处理技巧
6.7.1. 编码器计距离
编码器计距离在往届中广泛应用于出入库、坡道等元素的处理,也可以用于在一定距离内屏蔽某个元素的重复判断,防止误判。
float encoder_ave; // 平均速度
float distance; // 累计距离
void Distance_calculate()
{
encoder_ave = (encoder_L + encoder_R) / 2.0;
distance += encoder_ave;
}
6.7.2. 陀螺仪角度积分
陀螺仪角度积分在往届中广泛应用于环岛、出入库、避障等元素的处理。
float Gyro_z; // 偏航角速度
float Angle_gyro_z; // 积分角度
void Angle_calculate()
{
if(Gyro_z<32768)Gyro_z = - (Gyro_z / 16.4);
if(Gyro_z>=32768)Gyro_z = + (65535 - Gyro_z) / 16.4;
Angle_gyro_z += Gyro_z * 0.005; // 根据中断周期进行微调
}
6.8. 发车思路
初始目标速度设置为 0,使用 ADC 电压采集,换算超级电容的电压。
当电压达到一定值,便将目标速度更改为正常运行速度,给一个固定差速发车,使其进入赛道,这个过程类似于往届的出库动作。
发车后可通过编码器计距离、陀螺仪角度积分、电感特征值等方式使其退出发车状态,随后便可正常进行赛道循迹和元素判断。
6.9. 冲出赛道保护
if(L<5 && L2<5 && M<5 && R2<5 && R<5) // 电感值都很小
Base_Speed = 0; // 触发保护
else Base_Speed = 50; // 正常速度
7. 备赛建议与资源推荐
- 学习路径:C语言 → 单片机基础 → 传感器实验 → 算法移植。
- 团队分工:硬件(电路设计)、软件(算法调试)、机械(车模改装)。
- 学习资源:CSDN、往届技术报告、Gitee、GitHub、B 站学习视频。
- 基础解疑:官方Q群客服、官方淘宝客服。
结语
到这里,这篇手册分享就结束了。智能车大赛的魅力不仅在于追求胜利,更在于探索过程中的每一次自我突破。大家在参考我们方案的同时,别忘了充分发挥自己的创造力,去挖掘更多可能。
祝愿每一位同学都能在比赛中有所收获,享受智能车带来的乐趣。期待在赛场上看到你们的精彩表现,祝大家都能取得理想的成绩,加油!