基于RT-Thread操作系统的 基础四轮组智能车设计与实践

Posted 卓晴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于RT-Thread操作系统的 基础四轮组智能车设计与实践相关的知识,希望对你有一定的参考价值。

学 校: 同济大学
队伍名称: 智行·龙卷风
参赛队员: 杨怡,韦炳宇,许泽华
带队教师: 张志明,余有灵

 

§01


1.1全国大学生智能车竞赛介绍

全国大学生智能汽车竞赛是以智能汽车为研究对象的创意性科技竞赛,是面向全国大学生的一种具有探索性工程实践活动,是教育部倡导的大学生科技竞赛之一。该竞赛以“立足培养,重在参与,鼓励探索,追求卓越”为指导思想,旨在促进高等学校素质教育,培养大学生的综合知识运用能力、基本工程实践能力和创新意识,激发大学生从事科学研究与探索的兴趣和潜能,倡导理论联系实际、求真务实的学风和团队协作的人文精神,为优秀人才的脱颖而出创造条件。

该竞赛过程包括理论设计、实际制作、整车调试、现场比赛等环节,要求学生组成团队,协同工作,初步体会一个工程性的研究开发项目从设计到实现的全过程。竞赛融科学性、趣味性和观赏性为一体,是以迅猛发展、前景广阔的汽车电子为背景,涵盖自动控制、模式识别、传感技术、电子、电气、计算机、机械与汽车等多学科专业的创意性比赛。

1.2全国大学生智能车竞赛基础四轮组介绍

基础四轮组比赛是在PVC赛道上进行,官方比赛赛道示意图如图1.1和图1.2中所示,赛道采用黑色边线和电磁进行导引。

▲ 图1.1 第十六届全国大学生智能车竞赛基础四轮组

▲ 全国大学生智能车竞赛基础四轮组赛场

选手制作的车模完成从车库触发沿着赛道运行两周,然后在返回车库。赛道元素包含多个环岛、岔路、坡道、斑马线、车库等。车模需要连续运行两圈,每次需要分别通过三岔路口的两条岔路。比赛时间从车模驶出车库到重新回到车库为止。如果车模没有能够停止在车库内停车区内,比赛时间加罚五秒钟。为此参赛车模需要无误地判断出赛道元素并顺利通过,以最短的时间完成比赛。

1.3 RT-Thread操作系统介绍

1.3.1 嵌入式实时操作系统

嵌入式实时操作系统(Embedded Real-time Operation System,一般称作RTOS),是指当外界事件或数据产生时,能够接受并以足够快的速度予以处理,其处理的结果又能在规定的时间之内来控制生产过程或对处理系统作出快速响应,并控制所有实时任务协调一致运行的嵌入式操作系统 。其主要特点是提供及时响应和高可靠性,核心是任务调度,任务调度的核心是调度算法。主流的RTOS国外的有μClinux、μC/OS-II、eCos、FreeRTOS等,国内的有RT-Thread、Huawei LiteOS等。

1.3.2 RT-Thread 概述

RT-Thread,全称是 Real Time-Thread,是一款我国具有完全自主知识产权的开源嵌入式实时多线程操作系统,3.1.0 以后的版本遵循 Apache License 2.0 开源许可协议。它的基本属性之一是支持多任务,事实上,多个任务同时执行只是一种错觉,一个处理器核心在某一时刻只能运行一个任务。由于每次对一个任务的执行时间很短、任务与任务之间通过任务调度器进行非常快速地切换(调度器根据优先级决定此刻该执行的任务),就造成了这样一种错觉。在 RT-Thread 系统中,任务是通过线程实现的,RT-Thread 中的线程调度器也就是以上提到的任务调度器。经过了15年的迭代和丰富,伴随着物联网的兴起,现已经成为市面上装机量最大(超6亿台)、开发者数量最多、软硬件生态最好的物联网操作系统之一。

1.3.3 RT-Thread 架构

RT-Thread主要采用C语言编写,容易理解,移植方便,同时具有良好的可剪裁性,其架构图如图1.3中所示。Nano 版本(极简内核)仅需要 3KB Flash、1.2KB RAM 内存资源,适用于资源受限的微控制器(MCU)系统。完整版可以实现直观快速的模块化裁剪,无缝地导入丰富的软件功能包,实现类似 android 的图形界面及触摸滑动效果、智能语音交互效果等复杂功能,适用于资源丰富的物联网设备。相较于 Linux 操作系统,RT-Thread 体积小,成本低,功耗低、启动快速。除此以外 RT-Thread 还具有实时性高、占用资源小等特点,非常适用于各种资源受限(如成本、功耗限制等)的场合。

▲ 图1.3 RT-Thread系统的架构

其中RT-Thread 内核,是 RT-Thread 的核心部分,包括了多线程及其调度、信号量、邮箱、消息队列、内存管理、定时器等。

1.3.4 RT-Thread与智能车竞赛

对于第十六届智能车竞赛来说,MM32SPIN27、CH32V103由于内存较小,因此主要适配RT-Thread Nano版本的,这样可以减少RAM的开销。RT1064、RT1021、MM32F3277在智能车系统开发过程中使用RT-Thread的好处在于一方面可以充分发挥不同芯片的性能,让智能车跑的更加顺畅,另一方面提供了更高程度的抽象,屏蔽了不同单片机底层硬件细节,使得代码逻辑更为清晰,编写调试效率更高,移植性也更好。

1.4 智能车制作情况与本报告框架

经过近一年的准备,我们在小车机械结构设计、硬件电路设计、软件算法设计等方面都有收获和进展,灵活应用了RT-Thread系统的多线程并发、软定时器、线程间同步——信号量、线程间通信——邮箱、时间片轮转等特性,制作出了结构合理、系统稳定、可以顺利完成比赛任务的基础四轮小车。凭借着稳定的发挥,我们一路冲出校赛,在华东分赛区的预赛与决赛阶段都成功完成任务,取得预赛第12、决赛第7的较好成绩,最终排名为华东赛区基础四轮组第7名,决赛成绩103.007s。

本技术报告的框架大致如图1.4所示。

▲ 图1.4 技术报告框架结构

在第一章对全国大学生智能车竞赛、基础四轮组别、RT-Thread系统进行介绍,简单说明智能车制作的情况和报告框架。第二章介绍了智能车机械结构和基本硬件电路设计,第三章说明基础四轮车软件算法开发的基本流程,将传统大while()+中断模式与基于RT-Thread系统模式开发进行比较,得出后者具有巨大优势的结论,并详细介绍如何利用RT-Thread的多线程管理、定时器、邮箱、信号量等内核特性去更好的完成小车任务,总结部分进一步深入,讲述如何利用模块化思维、系统级的通信方式进行嵌入式任务的开发。第四章介绍RT-Thread操作系统的学习和迁移过程,其中4.3.4小节重点介绍了FinSH的详细移植过程。第五章对本次智能车制作和比赛过程进行总结与反思。

 

§02 能车硬件


智能车的机械结构和控制电路对赛车的性能影响巨大。具备一个好的机械结构平台,车身转向的灵敏性、直道行驶的稳定性、较高速度的抓地性才能得到很好地实现。因此,我们在不违反比赛规则的情况下对小车的结构进行设计和改进以使其具有良好的机械性能。同时,我们在整个系统设计过程中严格按照竞赛规范进行,本着可靠、高效的原则,在满足各个要求的情况下,尽量使设计的电路简单,PCB的效果简洁。

2.1 小车机械结构总体布局

第十六届全国大学生智能车竞赛基础四轮组指定采用新B车模,车架长28.5cm,宽16.5cm,高6.0cm; 底盘采用高强度玻纤板,具有较强的弹性和刚性;前轮调整方式简单,全车滚珠轴承、前后轮轴高度可调。驱动电机为RS540,伺服电机为SD-5舵机;轮胎经过软化剂处理,增强其耐磨性和摩擦力,车模整体质量较轻,车模照片分别如图2.1、图2.2、图2.3所示:

▲ 图2.1 四轮车模俯视图

▲ 图2.2 车模侧视图与前视图

车模机械结构具有如下特点:

  • 舵机采用竖直姿态,方便控制;
  • 更换新的舵机连接杆,提高舵机控制的灵敏性;
  • 元件及电池布局在车身中心部分,提高车子的对称性;
  • 对前轮进行调整,在保证直行稳定性的同时具有较好的过弯能力;
  • 采用双电感安装板双前瞻设计,一前一后,提高小车的前瞻性;
  • 安装支架高度尽量降低,最大程度降低车身重心。

2.2小车组件的安装

2.2.1电路板及电池的安装

车模的驱动板安装在车身的后侧,主板安装在车身中心偏后方,为使得整个车身的重心尽量落在车身中心以减少因速度快而产生甩尾和侧滑的现象,将两个电磁信号板安装与主板左右对称处,电池安装于主板下方偏前处,无线串口和电磁信号板均采用直插式封装,方便拆装。具体如图2.4所示:

▲ 图2.4 四轮组车模电路板及电池安装位置

2.2.2 转向舵机的安装

舵机采用竖式安装的方法,便于调节舵机的位置和控制转向,安装时,为了提高舵机控制的灵敏性,减少其延迟的时间,我们特地更换了新的舵机安装支架,使得舵机的安装位置更加契合要求,同时调整转向连杆的长度等因素,使得转动时的扭矩能够达到最佳的转向效果。

2.2.3 前轮的调节

为了进一步提高车的性能,在保证车身在直行稳定的情况下能够更加轻便的过弯,能够有较大的过弯角度,经过查阅资料和实践的检验,我们最终采用前轮外倾,主销后倾,前轮前束的机械结构 .

(1) 前轮外倾: 是指前轮安装后,其上端向外倾斜,于是前轮的旋转平面与纵向垂直平面间形成一个夹角,称之为前轮外倾角。通过前轮外倾的调节,使得前轮外倾和主销内倾相配合,可以减小主销偏距,使转向轻便。

▲ 图2.5 起来跑外倾示意图

(2) 主销后倾: 在车身纵向平面内,主销轴线上端略向后倾斜,这种现象称为主销后倾。在纵向垂直平面内,主销轴线与垂线之间的夹角叫主销后倾角。通过设置主销后倾,可以保持小车直线行驶时的稳定性,并使小车转弯后能自动回正。一般来说,后倾角越大,车速越高,车轮的稳定性越强。但是后倾角过大会造成转向沉重,所以主销后倾角不宜过大,通过实际的实践体验,我们最终将主销后倾角设置为2°~3°。

▲ 图2.6 主销后倾示意图

(3) 前轮前束: 是指前轮前端面与后端面在汽车横向方向的距离差,也可指车身前进方向与前轮平面之间的夹角,此时也称前束角。通过选择适当的前束角,可使前束引起的侧向力与车轮外倾引起的侧倾推力相互抵消,从而避免了额外的轮胎磨耗和动力的消耗,同时前轮前束还可以保证小车稳定的直线行驶,使转向轮具有自动回正的效果。经过多次尝试,智能车前轮前束的调整如图2.7所示:

▲ 图2.7 前轮前束示意图

▲ 图2.8 调整后的四轮组车模前轮前束

2.2.4 电磁电感安装板的安装与固定

为了使车具有较好的前瞻性,电磁电感安装板应尽量前置,但若距离过长,在车身行驶的过程中便极容易丢线,为了在不丢线的同时尽量提高其前瞻性,我们采用的是长短前瞻结合的方式,当长前瞻丢线时,切换到短前瞻进行控制,这样的好处的前瞻长,留给车的控制时间长,有更长的时间做出反应,提高了赛车的速度上限,同时短前瞻的应用又保证了车在过急弯的时候仍能够检测赛道并继续正常行驶。在具体安装时,我们采用碳素杆进行固定,减少支架的重量对于车身对称性和平衡性的影响。支架后半部分用两个支架安装板固定位置,前半部分从车前再引出两个固定支架,构成三角形结构,提高其稳定性,减少车在行进过程中支架的颠簸,进而提高电感测量数据的稳定性。具体安装分别如图2.9、图2.10所示:

▲ 图2.9 电磁从梦境安装板是示意图

▲ 图1.10 前侧采用三角形结构固定

2.3硬件电路设计

硬件电路系统是智能车运动控制系统的核心组件,为保证智能车稳定运行的基础,需要一个良好、稳定的硬件环境才能使得小车能平稳快速的行驶在比赛赛道上。

2.3.1 单片机系统

核心单片机子系统采用英飞凌半导体公司设计生产的TC264D芯片。该芯片采用双核TriCore架构,最高主频为200MHz,高达2.5MB的闪存与240KB的RAM,完全满足智能车控制的算力需求。为方便使用与后续更换,我们使用了逐飞科技公司生产的TC264单片机系统板,原理图如图 2.11 所示:

2.3.2 电源模块设计

硬件电路的电源由18650锂电池提供(额定电压7.4V,容量2000mAh)。由于不同电路模块中所需要的工作电压和电流量各不相同,所以我们采用了三个稳压电路将电源电压转换成各模块需要的电压。

  1. 使用MIC29302WU芯片将电源电压转换成6V电压,用于智能车舵机供电。输出电压计算公式为:
Vout=1.240*(R3/R5+1) (1)
电路如图2.12所示:

▲ 图2.12 直流6V稳压电路原理图

  1. 使用LM1085输出5V电压,用于蜂鸣器,通信串口供电。LM1085芯片的输入电压为5.5V到10V时,输出电压的典型值为5V。电路如图2.13所示:

▲ 图2.13 直流5V稳压电路原理图

  1. 使用TPS76833将5V电压转换成3.3V电压,用于单片机、信号放大电路、显示屏等模块的供电。TPS76833芯片的输入电压为2.7V到10V时,输出电压为3.3V。电路如图2.14所示:

▲ 图2.14 直流3.3V稳压电路原理图

2.3.3 信号采集及放大电路模块的设计

对赛道上电磁信号的采集和处理是智能车最重要的模块之一,根据变化的磁场信号做出灵敏的检测对控制智能车在赛道上稳定运行起着至关重要的作用。

智能车比赛赛道铺设有中心电磁引导线,其中通有20kHz,100mA的交变电流。根据麦克斯韦电磁场理论,交变电流会在周围产生交变的电磁场。因此我们采用10mH的工字电感和6.8uF的小温差电容组成串联谐振电路,来实现对20kHz信号的选频和将赛道的电磁信号转换成电压,从而完成对信号的采集。接下来就是对收集到的电压信号进行滤波、放大、整流用于单片机ADC模块转换成数字量。放大电路和电感排布方案如图2.15中所示。

▲ 图2.15 电磁信号放大电路和电感排布方案

在上图的电感排布方案中,水平电感1、7主要用于检测弯道,在小车进入弯道过程中,可以根据两端感应电动势值判断智能车与赛道中心线的偏离方向及偏差量。电感4用于检测赛道中心的电磁线,当智能车偏离赛道中心线不多时,
该电感的变化程度较小,当偏离程度较大时,该电感的感应电动势值突然下降很快,因此可以根据该电感的变化情况更加精确地得出智能车与赛道中心线的偏离程度。电感3、4用于检测岔路。电感2、6主要用于引导智能车入环岛,在环岛路段,靠近环岛的那个竖直电感的感应电动势会比远离环岛的竖直电感的感应电动势大许多,可以使用这两个电感引导智能车进入环岛。

2.3.4 电机驱动电路

电机驱动电路采用双极性PWM全桥电路,可实现电机正反转以及可调占空比控制电机转速。该电路能控制电机正反转运行,具有启动快、调速精度高、动态性能好、调速静差小、调速范围大;能加速、减速、刹车、倒转;能在负载超过设定速度时,提供反向力矩、能克服电机轴承的静态摩擦力,产生非常低的转速等多方面优点。电路原理图如图2.16所示:

▲ 图2.16 双极性PWM全桥电机驱动电路

2.3.5 无线串口模块

采用NRF24L01 2.4GHz无线串口模块,用于主机与单片机之间的实时数据通信,实现实时观察车模的运行情况与无线调参等操作,节约调试时间,提高调试效率。

2.3.6编码器测速模块

我们的智能车使用龙邱智能科技的512 线 mini 型编码器,使用减速齿轮和联轴器加载到小车的动力轮上,进行小车的测速,工作电压范围 3.3V-5V。单片机通过读取编码器脉冲数来实现对智能车速度的测量。

2.3.7 PCB设计与实物图

设计各功能电路的PCB,打样后的PCB设计图和实物照片分别如下图中所示,包括:电路底板(图2.17),电磁信号放大板(图2.18),电机驱动板(图2.19),电磁信号放大板(图2.20)。

▲ 图2.17 电路板的PCB与实物图

▲ 图2.18 电磁信号放大版PCB与实物图

▲ 图2.19 电机驱动板的PCB与实物图

▲ 图2.20 电感安装板的PCB与实物

 

§03 RT-Thread软件


本章介绍基于RT-Thread的四轮组车模软件设计。

本章首先基于四轮车任务背景介绍软件算法,接下来分析裸机大while()+中断型开发模式的架构,并引出为什么要使用RT-Thread操作系统,后续部分从PID算法着手,相对全面地介绍基于RT-Thread的四轮车软件算法设计的各个方面。

3.1 软件算法背景介绍

四轮车组别的主要任务有数据采集类、信号处理算法类、人机交互类、控制类等,其中:

  • 数据采集类任务包括摄像头图像采集、电磁信号采集、小车编码器数据采集等。
  • 信号处理算法类任务主要包括图像处理(灰度、二值化),电磁信号处理(均值滤波、卡尔曼滤波、归一化)等。
  • 人机交互类任务主要包括图像显示、按键、拨码开关、LED、蜂鸣器、串口通讯等。
  • 控制类任务主要包括舵机与电机的控制,通过PID进行闭环计算,输出PWM波进行打角和转速的控制。
  • 其他的组别还会有更多的任务,如直立车车身姿态的控制、AI机器视觉等,此处和四轮车组任务无关,不再赘述。

这样一来,一辆四轮车就具备了巡线的基本功能,再加上对特殊赛道元素的正确判断,就能初步具备完赛的能力。

▲ 图3.1 四轮车组别主要任务

3.2 裸机大while()+中断型与RT-Thread系统开发对比分析

3.2.1 裸机大while()+中断模式介绍

传统的裸机大while()+中断模式又称为前后台系统,前台指中断,后台指main()函数里的主循环while(1)。初学编程的时候老师会强调,循环一定要有退出的条件,不可以死循环。但是在嵌入式开发不用操作系统的情况下,一般都是用main函数里while(1)无限循环的方式去编程的。中断可以打断main()函数,保证一定的实时性,而中断也可以被优先级更高的中断打断。

▲ 图3.2 裸机大while() + 中断模式

3.2.2 裸机大while()+中断模式优劣势分析

在嵌入式编程发展的早期,是用裸机大while()+中断模式编程的。优点是上手容易,处理简单任务绰绰有余。
而随着计算性能的提高,嵌入式编程的发展是从简单到复杂、从单任务到多任务,加上物联网的兴起,要处理的任务也是越来越复杂。这种模式渐渐显露出弊端。

  1. 函数可能变得非常复杂,并且需要很长执行时间。且中断嵌套可能产生不可预测的执行时间和堆栈需求。
  2. 超级循环和 ISR 之间的数据交换是通过全局共享变量进行的,应用程序的程序员必须确保数据一致性。
  3. 超级循环可以与系统计时器(硬件计时器)轻松同步,但如果系统需要多种不同的周期时间,则会很难实现。
  4. 超过超级循环周期的耗时函数需要做拆分,增加软件开销,应用程序难以理解,超级循环使得应用程序变得非常复杂,因此难以扩展。

举个例子,逐飞科技做过这样一个实验。while(1)函数里放两个任务,一个是流水灯,一个是显示屏显示摄像头图像。两个任务分别运行时都非常流畅。但是同时运行时,图像刷新就变得十分卡顿。这是因为流水灯的delay()时间比较长,这段时间内cpu什么也不做,所以图像的刷新频率就显而易见的降了下来。这是一个典型的例子。随着小车工作的不断推进,while(1)里要放的任务可能越来越多,后面的任务不可避免会对前面的任务造成影响。只能按顺序执行,而不能进行有效的优先级区分。如果用中断,首先中断的数量可能会不足(比如tc264D只有4个pit中断),其次中断的嵌套也会使程序变得更加复杂,增加维护的难度。最重要的是,有很多的delay(),在这期间,cpu是什么也不做的,这是巨大的资源浪费,而且也会明显影响一些任务的执行频率。

当然,说了这么多,只用裸机大while()+中断模式能不能把车做好?答案是肯定的,历史上的许多神车都是用这种模式做出来的。但是,对于大多数同学,如果有一种效率更高,优势巨大的方法摆在面前,要不要用?答案也是肯定的。下面探讨一下相对于裸机大while()+中断模式,RT-Thread系统的巨大优势。

3.2.3 RT-Thread系统的优劣势分析

RT-Thread系统在1.3节已有详细介绍。这里着重对比传统裸机大while()+中断模式分析其优劣势。

优势有很多,正好克服了裸机大while()+中断模式的劣势。

更灵活的任务处理和更好的实时性。线程数量不受限制,优先级最大256个。首先RT-Thread系统先天就有着处理复杂任务、多任务并发的属性。可以把不同的任务拆分成不同的线程,根据优先级让系统自动调度,更好地可以对多任务进行区别对待。如果优先级配置得当,不同任务之间相互的影响可以降到最低。显著的优势在于,delay()时会将线程挂起,把cpu使用权交出去,这时候cpu可以处理其他任务,显著提高cpu的使用率。

更方便的模块化开发和团队合作。如果是团队协作开发,那么可以各自写各自的线程,最后汇总、配置优先级启动即可。模块化开发也是用了面向对象的观点,屏蔽了一些底层的实现细节,可以更专注于所要解决的任务上,代码逻辑更加清晰,后续的拓展和维护也相对省力。

可重用性。这个是比较显著的优势。不同的平台编程逻辑可能有很大不同,就智能车而言,不同的组别平台就各有不同,同一个组别每一届的平台也可能会有变化。所以对于许多打算做两年或想换组别的同学来说,就免去了痛苦的从头开始的过程,直接一键无痛移植。对于其他的比赛或项目而言,如果RT-Thread系统对该平台有适配,则熟悉的编程逻辑和风格可以让同学更加游刃有余。

丰富的软件生态。这一优点可能在智能车竞赛中不那么突出,但是如果做物联网的一些比赛,丰富的第三方库会让人拍手称快。也许目前智能车面对的任务还不够复杂,但任务越来越复杂是大趋势,一些复杂的项目也是用RT-Thread系统处理的。通过做智能车熟悉了RT-Thread操作系统,也有利于未来自身嵌入式编程的发展。

劣势则是使用有一定门槛,上手不如大while()+中断模式那么容易。不过花点时间了解一下嵌入式实时操作系统的一些特性,学习一下RT-Thread的内核使用,这个时间的投入还是非常划算的。且由于RT-Thread系统本身比较浅显易懂,再加上逐飞有比较详细的讲解和demo,所以学习和移植过程还是比较顺利的。我从刚开始接触RT-Thread到移植成功,只花了大半天时间,后续的调试又用了一个下午。对于有一点嵌入式开发经验的同学来说,可以预留出一天半时间来初步学习和移植。当然要想精进使用是需要不断学习的。所以同学不要觉得操作系统好像很高大上的样子,不明觉厉。当你开始阅读开发者文档,动手操作以后,可能就会觉得还是比较容易的。

3.3 RT-Thread系统在四轮车的部署方案

将3.1软件算法进一步抽象,总体可以概括为:“一核心,两关键,多辅助”。“一核心”指运动控制器,“两关键”指赛道环境的采集(电磁采集和摄像头图像采集、编码器采集)和控制量的输出(舵机和电机的PWM输出),“多辅助”指的是通过按键、拨码开关、led灯、显示屏、蜂鸣器、串口等一系列手段增强调试效率。使用RT-Thread的线程调度、时钟管理、线程间同步、线程间通信等内核特性,有效解决了裸机大while()加中断形式带来的管理单一、无法处理复杂多任务的执行、调试不方便等痛点,在抽象层面更高的平台上,使得多任务运行更加得心应手,编程逻辑更加清晰,调试手段更加多样灵活。

由于小车速度很快,且感知、决策、控制存在必然的顺序,所以必须保证三者的周期性唤醒及执行的先后顺序。所以用RT-Thread 操作系统提供的软定时器,timer1_pit_entry线程周期运行,周期为1个系统节拍。在定时器入口函数里面完成赛道环境的采集和处理,差比和计算,以及PWM波输出。

显示屏和串口作为display_entry线程,优先级设置为31。并且通过拨码开关决定是否显示。蜂鸣器作为buzzer_entry线程,优先级设置为20。并且通过邮箱决定是否响以及响的时间,邮箱大小为5个字节,采用 FIFO 方式进行线程等待。这里显示屏和串口优先级最低,而蜂鸣器优先级更高,比较合理。

利用FinSH在实际小车运行过程中,我们使用ps命令列出系统中所有线程信息,包括线程优先级、状态、栈的最大使用量等,以此监测智能车的线程运行情况。

下图3.3为大while+中断控制逻辑,3.4为RTT多线程同步操作系统在四轮小车上的部署方案。

▲ 图3.3 大 while +中断算法逻辑

▲ 图3.4 RT-Thread系统算法逻辑

3.4 PID运动控制器

一核心指的是运动控制器,本次比赛我们采用经典控制算法PID控制,如图3.5和图3.6中所示,根据系统输入与预定输出的偏差的大小运用比例、积分、微分计算出一个控制量,将这个控制量输入系统,获得输出量,通过反馈回路再次检测该输出量的偏差,循环上述过程,以使输出达到预定值。

▲ 图3.5 使用PID控制器的经典负反馈算法

▲ 图3.6 使用PID控制器的负反馈控制算法应用

位置式PID算法可由公式(2)表达:

而增量式PID算法可由位置式PID算法推导得到,如公式(3)中所示:

在PID算法中,比例环节P的作用是成比例地反映控制系统的偏差信号e(t),一旦产生偏差,比例控制环节立即产生控制作用以减小偏差。积分环节I的作用是消除静差,提高系统的无差度,在使用积分控制时,常常对积分项进行限幅以减少积分饱和的影响。微分环节D的作用是反映偏差信号的变化趋势,能够在偏差信号变化之前先引入一个有效的早期修正信号来提前修正偏差,加快系统的动作速度,减少调节时间。

位置式PID特点主要是一方面控制的输出与整个过去的状态有关,用到了误差的累加值(即用误差累加代替积分),另一方面公式输出直接对应对象的输出,对系统影响大。

而增量式PID特点有不需要累加误差,控制增量仅与最近几次的误差有关,不容易产生误差累积,仅输出控制量增量,误动作影响小,不会严重影响系统。

两者的主要区别在于,位置式PID控制算法是一种非递推算法,其输出直接控制执行机构,输出的量与执行机构的位置(例如阀门的开关量)一一对应。增量式PID控制算法是一种递推算法,输出的只是控制量的增量,技术输出的增量对应的是本次执行机构位置的增量而不是实际位置。PID控制并不一定要三者都出现,也可以只是PI、PD控制,关键决定于控制的对象。

舵机通常采用位置式PD算法,对于舵机的控制,因为不需要记录之前的误差因此这里将积分环节去掉,这样公式就变为。舵机控制代码实现如下:差因此这里将积分环节去掉,这样公式就变为。舵机控制代码实现如下:

//保存上次误差 
                      last_elect_val = curr_elect_val; 
                      //计算本次误差 
                      curr_elect_val=SET_POSITION-position; 
elect_val_delta = curr_elect_val - last_elect_val;   //电磁变化率 
 
                      smotor_duty=(int16)(__skp*curr_elect_val + __skd*elect_val_delta);//进行PD运算 
smotor_duty=(int32)limit_ab((int16)smotor_duty, LMAX_DUTY, RMAX_DUTY);//限幅, 
pwm_duty(SMOTOR_CHANNEL, SMOTOR_CENTER+smotor_duty);//控制舵机转动 

电机通常采用增量式PID算法,因为增量式PID不容易造成电机的正反转切换,对速度的调节更为平滑。电机控制代码实现如下:

ek2=ek1;//保存上上次误差 
    ek1=ek;//保存上次误差 
set_speed=SPEED; 
//进行增量式PID计算 
       out_increment=(int16)(kp*(ek-ek1)+ki*ek+kd*(ek-2*ek2+ek2));//计算增量 
       out +=out_increment;                    //输出增量 
       out =limit(out,GTM_ATOM0_PWM_DUTY_MAX/2 ); //输出限幅,不能超过占空比最大值 
 
       motor_duty=(int32)out;                  //强制转换为整数后赋值给电机占空比变量 
  if(motor_duty>=0)   //前进 
       { 
           pwm_duty(MOTOR2_CHANNEL, 0); 
           pwm_duty(MOTOR1_CHANNEL, motor_duty); 
       } 
       else                //后退 
       { 
           pwm_duty(MOTOR1_CHANNEL, 0); 
           pwm_duty(MOTOR2_CHANNEL, -motor_duty); 
       } 

(注:这里只展示PID算法部分,变量定义及初始化略)

3.5 电磁信号采集和处理

3.5.1 ADC介绍

模拟数字转换器即A/D转换器,或简称ADC,通常是指一个将模拟信号转变为数字信号的电子元件。通常的模数转换器是将一个输入电压信号转换为一个输出的数字信号。由于数字信号本身不具有实际意义,仅仅表示一个相对大小。故任何一个模数转换器都需要一个参考模拟量作为转换的标准,比较常见的参考标准为最大的可转换信号大小。而输出的数字量则表示输入信号相对于参考信号的大小。

3.5.2 ADC转换过程

ADC转换过程通常有采样(取样),保持,量化,编码四个阶段。

▲ 图3.7 ADC转换过程

(引自https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-standard/programming-manual/device/adc/adc)

3.5.3 ADC转换分辨率

通常以输出二进制或十进制数字的位数表示ADC分辨率的高低,因为位数越多,量化单位越小,对输入信号的分辨能力就越高。

例如:输入模拟电压的变化范围为0~5 V,输出8位二进制数可以分辨的最小模拟电压为5 V×2-8=20 mV;而输出12位二进制数可以分辨的最小模拟电压为5 V×2-12≈1.22 mV。

智能车ADC转换分辨率由板载ADC的具体型号决定,一般有8bit,12bit等。TC264D一般电磁循迹用8bit足够了。

3.5.4 电磁信号处理

首先要读取电磁信号,然后滤波,归一化处理。

读取电磁信号调用官方的库即可。这里注意adc句柄和通道号要与所画pcb的管脚定义相对应。

rt_adc_read(ADC_0, ADC0_CH0_A0); 

滤波方法有很多,常用的有均值滤波,平滑滤波,卡尔曼滤波等等。这里注意的是,不要贪多求全,适合自己的才是最好的。听上去很厉害的滤波方法可能效果不一定那么好,有的方法有可能是不收敛的。所以最好对自己使用的滤波方法心里有数。我们在加上三大滤波方法之后,发现滤波效果反而变差了,所以就只用了基本的均值滤波。其实现代码也很简单。

sum = 0; 
    for(i=0; i<count; i++) 
    { 
        sum += rt_adc_read(ADC_0, ADC0_CH0_A0); 
    } 
 
    sum = sum/count; 

归一化处理:每一个场地的电感数据,往往不尽相同,甚至出现极大的偏差,可能是场地地下钢筋等因素的影响,所以归一化是十分必要的。这样可以方便适应不同的赛道环境,使得比赛场上的电感值最接近平时调车时的电感值。归一化思路如下:先把车放在直道上,采集各电感的最大值(使该电感贴近或垂直电磁线)。写一个记录最大值、最小值的数组。进行以下运算。

需要注意的是:如果有限幅操作(1-100),则记录归一化数值时需要把车放在整个赛道上电感值最大的地方(如环岛),否则可能造成电感“饱和”的假象。如果没有限幅操作,则放在直道上读数即可。

for(int i=0;i<7;i++) 
        { 
            AD_G_S[i]=( (AD_data[i]-AD_min[i])*1.0/(s_AD_max[i]-AD_min[i])*100 ); 
            if(AD_G_S[i]>100) 
                AD_G_S[i]=100; 
            else if(AD_G_S[i]<1) 
                AD_G_S[i]=1; 
        } 

3.6 利用定时器实现巡线

循迹一般有电磁循迹和摄像头循迹两种方案。前者简单易上手,稳定性高,不容易受到赛道环境的影响。后者获取的信息量更大,上限更高,稳定性较低,受场地阳光等影响较大。由于今年四轮组要求摄像头高度不超过不容易受到赛道环境的影响。后者获取的信息量更大,上限更高,稳定性较低,受场地阳光等影响较大。由于今年四轮组要求摄像头高度不超过不容易受到赛道环境的影响。后者获取的信息量更大,上限更高,稳定性较低,受场地阳光等影响较大。由于今年四轮组要求摄像头高度不超过不容易受到赛道环境的影响。后者获取的信息量更大,上限更高,稳定性较低,受场地阳光等影响较大。由于今年四轮组要求摄像头高度不超过

循迹算法常用的是差比和算法,差比和偏差曲线与理想偏差曲线如图3.8中所示。

▲ 图3.8 差比和偏差曲线与理想偏差曲线

算法基本思路如下:

Position= (a-b)/(a+b)(a和b是左右电感的值) 

计算出的数值绝对值大小表示偏离赛道的程度,在一定范围内车模偏离赛道越远计算出来的值越大。下面利用这个数据就可以控制舵机,来使得车模一直沿着赛道中心线前进了。

//差比和 
    __S_diff=  (elect_L - elect_R)*100; 
__S_sum= (elect_L + elect_R); 
S_position=__S_diff/__S_sum; 
//丢线保护 
if(__S_sum<__LOSELINE){ 
                  if (elect_L >= elect_R) { 
                      pwm_duty(SMOTOR_CHANNEL, SMOTOR_CENTER-L_DUTY);//左打死 
                 } 
                 else { 
                     pwm_duty(SMOTOR_CHANNEL, SMOTOR_CENTER-R_DUTY); //右打死 
                 } 
              } 
else{ 
//计算本次误差 
curr_elect_val=SET_POSITION-position; 
} 

这样一来就可以实现电磁巡线的效果。

把这一系列电感采集与处理、pid计算、pwm输出放在一起,就可以实现初步的智能小车巡线了。下面展示这一功能的实现过程。放在定时器进程里面运行,来保证执行周期是固定的。创建定时器和创建线程的方法类似,创建线程的方法放在3.4.1部分详细说明。

rt_timer_create("timer1", timer1_pit_entry, RT_NULL, 1, RT_TIMER_FLAG_PERIODIC); 

这里timer1表示定时器的名称,限制在8个字符以内。

timer1_pit_entry表示时间到了之后需要执行的函数,可以理解为stm32里的超时回调函数。

RT_NULL表示不需要传递参数,

1表示定时器的超时时间为1个系统tick,系统周期为1毫秒,则1表示1毫秒。为什么要用1个系统tick?这样可以保证定时器足够精确。

RT_TIMER_FLAG_PERIODIC表示定时器以周期运行,如果设置为RT_TIMER_FLAG_ONE_SHOT则只会运行一次。

这些内容可以通过RTT官方文档和API手册来了解。

void timer_pit_init(void) 
{ 
    rt_timer_t timer; 
     
    //创建一个定时器 周期运行 
    timer = rt_timer_create("timer1", timer1_pit_entry, RT_NULL, 1, RT_TIMER_FLAG_PERIODIC); 
     
    //启动定时器 
    if(RT_NULL != timer) 
    { 
        rt_timer_start(timer); 
    } 
} 

创建好定时器以后,就可以编写定时器超时函数了。可以理解为周期性执行的线程,而之前无限次执行的线程一般周期性不能得到保证。

每进函数一次,time++。

if(0 == (time%5)) 保证5个周期进一次。
然后依次执行,电磁信号采集、归一化、舵机PID控制,采集编码器数据和电机的PID控制。

void timer1_pit_entry(void *parameter) 
{ 
    static uint32 time; 
time++; 
 
    if(0 == (time%5)) 
    { 
 
        //电磁信号采集、归一化、PID控制 
        elec_calculate(); 
 
        //采集编码器数据 
        encoder_get(); 
        //控制电机转动 
        motor_control(); 
    }     
以上是关于基于RT-Thread操作系统的 基础四轮组智能车设计与实践的主要内容,如果未能解决你的问题,请参考以下文章

17届智能车竞赛技术报告 | 乐师逐飞二队 - 基础四轮组

关于第十七届智能车竞赛“基础四轮组”的一点想法

智能车竞赛技术报告 | 基础四轮组 - 哈尔滨工程大学 - 济海追风5队

智能车竞赛技术报告 | 基础四轮组 - 大连理工大学 - 霹雳小队

基于RT-Thread开发智能视觉组智能车-乐山师范学院

基于RT-Thread开发智能视觉组智能车 - 温州大学 - 春华秋实