智能车竞赛技术报告 | 智能车视觉 - 中原工学院 - 逐鹿 - 分母队
Posted 卓晴
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了智能车竞赛技术报告 | 智能车视觉 - 中原工学院 - 逐鹿 - 分母队相关的知识,希望对你有一定的参考价值。
队伍名称:逐鹿—分母队
参赛队员:王泽南
张志宇
徐程升
带队教师:但永平
耿世勇
第一章 引言
智能车辆是一个集环境感知、规划决策、多等级辅助驾驶等功能于一体的综合系统,它集中运用了计算机、现代传感、信息融合、通讯、人工智能及自动控制等技术,是典型的高新技术综合体。目前对智能车辆的研究主要致力于提高汽车的安全性、舒适性,以及提供优良的人车交互界面。近年来,智能车辆己经成为世界车辆工程领域研究的热点和汽车工业增长的新动力,很多发达国家都将其纳入到各自重点发展的智能交通系统当中。
全国大学生智能汽车竞赛以“立足培养、重在参与、鼓励探索、追求卓越”为宗旨,是一项鼓励创新的科技竞赛活动。智能车设计内容涵盖了控制、模式识别、传感技术、汽车电子、电气、计算机、机械、能源等多个学科的知识,对学生的知识融合和实践动手能力的培养,具有良好的推动作用。竞赛要求在规定的汽车模型平台上,使用微控制器作为核心控制模块,通过增加道路传感器、电机驱动模块以及编写相应控制程序,制作完成能够自主识别道路并且完成其余指定任务的模型汽车。
车模采用NXP公司生产的i.MX RT1064单片机作为核心控制器,使用Openart-mini作为视觉识别核心,通过摄像头和电感采集赛道信息,自行涉及并制作主控板、驱动板等功能电路,使用多套速度方案,按照规定路线前进并完成赛道特殊元素的识别,识别Tag码并停车进行图像的识别与打靶。车模设计制作过程中,深入研究车模特点,设计整体结构及控制系统,并根据实际运行情况及时调整。
硬件机械设计时,针对小车结构特点,在传感器、电路模块安装时多次尝试,及时优化;软件系统设计时,使用了经典PID以及模糊PID等方法,外加差速控制,实现转向及速度控制,赛道识别上使用了动态阈值,保证了适应性。。
RT-Thread,全称是 Real Time-Thread,顾名思义,它是一个嵌入式实时多线程操作系统,基本属性之一是支持多任务,允许多个任务同时运行并不意味着处理器在同一时刻真地执行了多个任务。事实上,一个处理器核心在某一时刻只能运行一个任务,由于每次对一个任务的执行时间很短、任务与任务之间通过任务调度器进行快速地切换(调度器根据优先级决定此刻该执行的任务),给人造成多个任务在一个时刻同时运行的错觉。在RT-Thread系统中,任务是通过线程实现的,RT-Thread中的线程调度器也就是以上提到的任务调度器。且RT-Thread拥有一个国内最大的嵌入式开源社区,同时被广泛应用于能源、车载、医疗、消费电子等多个行业,累积装机量达数千万台,成为国人自主开发、国内最成熟稳定和装机量最大的开源RTOS。
使用RT-thread操作系统的优势在于相比裸机开发的效率获得大幅提升,软件设计时引入嵌入式操作系统的任务调度,优化了程序执行的逻辑顺序,使用临界区资源保护,很好的增强了程序稳定性,避免了逻辑错误和冲突等。其次是RT-Thread的开源资料多,范围广。大多数问题都可以在RT-Thread社区内找到答案,对于国人相对友好。同时还有官方编写的文档《RT-Thread编程指南》,可以随时在其中查找内容,做到随用随查,搭配官方推出的视频教程以及官方和逐飞的demo例程,在极短的时间内就可以简单的入门。
本文第二章中简要介绍了车模的硬件结构设计,在第三章中列出了硬件系统的设计方案和具体原理,第四章详细说明了程序策略,第五章详细写出了图像识别使用的方法和优化策略,第六章则详细说明了使用RT-Thread相比裸机开发下的优势及其所发挥的作用,第七章主要内容是RT-Thread资料的使用以及解决问题的过程与步骤,第八章给出了车模制作过程中的情况,总结了RT-Thread所用到的功能,指出现存的一些问题与可能的解决方法。
第二章 车模机械设计
根据大赛组委会对智能视觉组进行车模和传感器的限定,本届智能视觉组我们使用C型车模和摄像头作为车模的构架。C型车模具有舵机与电机,是一种相对灵活的四轮车模,对于赛道的适应性高,而且稳定易于控制。由于智能视觉组对于尺寸方面没有任何限制,所以机械结构对于整车的性能至关重要,只有在车模拥有较好机械结构的前提下,控制算法才能发挥出其应有的效果。使智能车可以更好的适应高速运行的情况,保证其在高速时仍然具有较高的机械强度与灵活度,是本次比赛研究重点。在规则允许的范围内,我们对车模进行了优化改装,本章将介绍根据实际情况对车模机械做出的改进内容。
2.1. 前轮定位调整
四轮智能车出现直线走偏、转弯费力、轮胎磨损快等情况时大多与轮胎安装角度有关,涉及到一个非常重要的转向轮位置角度定位问题,叫做“前轮定位”。它的作用是保障智能车直线运行时的稳定性,使其转向轻便并减少轮胎的磨损。前轮是转向轮,它的安装位置由主销内倾、主销后倾、前轮外倾和前轮前束等四个项目决定,反映了转向轮、主销和前轴等三者在车架上的位置关系。
2.1.1. 主销后倾角
从侧面看车轮,转向主销(车轮转向时的旋转中心)向后倾倒,称为主销后倾角。设置主销后倾角后,主销中心线的接地点与车轮中心的地面投影点之间产生距离 (称作主销纵倾移距,与自行车的前轮叉梁向后倾斜的原理相同),使车轮的接地点位于转向主销延长线的后端,车轮就靠行驶中的滚动阻力被向后拉,使车轮的方向自然朝向行驶方向。设定很大的主销后倾角可提高直线行驶性能,同时主销纵倾移距也增大。但主销纵倾移距过大,会使转向沉重,而且由于路面干扰而加剧车轮的前后颠簸。
2.1.2. 主销内倾角
从车前后方向看轮胎时,主销轴向车身内侧倾斜,该角度称为主销内倾角。当车轮以主销为中心回转时,车轮的最低点将陷入路面以下,但实际上车轮下边缘不可能陷入路面以下,而是将转向车轮连同整个车模前部向上抬起一个相应的高度,这样车模本身的重力有使转向车轮回复到原来中间位置的效应,因而车模容易回正。此外,主销内倾角还使得主销轴线与路面交点到车轮中心平面与地面交线的距离减小,从而减小转向时舵机上的力,使转向更加轻便,同时也可减少从转向轮传到舵机上的冲击力。
2.1.3. 前轮外倾
从前后方向看车轮时,轮胎并非垂直安装,而是稍微倾倒呈现“八”字形张开,称为负外倾,而朝反方向张开时称正外倾。车模一般将外倾角设定得很小,接近垂直。若设定大外倾角会使轮胎磨偏,降低轮胎摩擦力。
2.1.4. 前轮前束
四轮定位前束值脚尖向内,所谓“内八字脚”的意思,指的是左右前轮分别向内。采用这种结构目的是修正上述前轮外倾角引起的车轮向外侧转动。如前所述,由于有外倾,转向变得容易。另一方面,由于车轮倾斜,左右前轮分别向外侧转动,为了修正这个问题,如果左右两轮带有向内的角度,则正负为零,左右两轮可保持直线行进,减少轮胎磨损。
在智能车程序基本完整,可以完成各类赛道元素后,根据实际情况对前轮定位进行调整。通过改变上横梁垫片的数目,增大后倾角。在智能车长期调试后,发现适当增大内倾角,可使转弯时车轮和地面有更大的接触面积,继而增大车与地面的摩擦程度,使车转向更灵活,减小因摩擦不够而引起的转向不足的情况。
2.2. 舵机安装调整
舵机摆杆的长度直接影响到舵机的转矩。由公式舵机转矩 = 舵机摆杆作用力 * 摆杆长度,得:舵机摆杆作用力越大,反应越灵敏,转向速度越快。转矩一定时,摆杆越长,输出的作用力越小,所以摆杆不能太长,不然会拉不动轮胎左右转向,从这个角度考虑拉杆越短越好。但是我们知道,拉杆越长的时候,舵机转一小圈,下面拉杆的会转很大的范围,也就是说,摆杆长度决定了舵机和拉杆变化的比例也就说明相应速度。所以我们又希望摆杆很长,这样轮子转向的响应速度就会很快。
综合考虑,我们选用的舵机摆杆的长度在 30mm 左右。同时考虑到阿克曼转向理论,理论转角如图 1.1,四个轮子路径的圆心大致上交会于后轴的延长线上瞬时转向中心,这样可以使车辆在过弯时转向轮处于纯滚动状态,减少过弯时的阻力,减小轮胎的磨损,提高车辆转弯性能。
根据杠杆原理,将与舵机连接的舵盘适当加长,再将转向传动杆连接在加长的输出盘的末端,就可以在舵机输出较小的转角下,取得更大的前轮转角,提高舵机的响应的速度。结合舵机重心,结构件安装等问题,最终使用了立式安装方式。
▲ 图1.1 阿克曼转角图
2.3. 底盘高度调整
降低车模底盘可以降低重心,车模重心低可以使车模运行更加稳定,获得 更好的转弯特性。所以,在保证车模可以通过灯盘的情况下,底盘尽可能的降低,可以使车更加快速稳定。对于C车模,修改前轮滚动的轴心和车模底盘的高度差,可以修改车模底盘的高度,所以通过在前轮固定处垫垫圈来降低车模底盘高度。
第三章 硬件系统设计及实现
3.1. 硬件方案设计
硬件电路在整个智能车系统中虽然是基础,但是也是整个体系中比较重要的一部分,是保障整个系统能够稳定运行的基础。硬件电路的设计不仅需要考虑功能性,而且需要对其稳定性及可靠性进行准确的设计,需要不断的测试与改进。
主要从系统的可靠性、稳定性、实用性、简洁、美观等方面来考虑硬件的整体设计。从初代板到最终板,我们经历了各种大大小小问题以及功能实现的讨论,才有了最终的硬件方案。
可靠性、稳定性以及实用性是一个系统能够完成预想功能的最大前提。在原理图与PCB的设计过程中,我们考虑到各个功能模块的电特性以及之间的耦合作用以及信号线之间的干扰。对易受干扰的模块做了电磁屏蔽作用,而其他部分则做了相应的接地、滤波、模拟与数字电路的隔离等工作。
简洁、美观是指在满足了可靠、稳定等的要求后,为了尽量减轻车模的负载,降低模型车的重心,应使电路设计尽量简洁,尽量减少元器件使用数量,缩小电路板面积,使电路部分重量轻,易于安装。在设计完原理图后,注重PCB板的布局,优化电路的走线,整齐排列元器件,最终做到电路板的简洁以及板子的观赏性。
3.2. 电源模块
电源模块是硬件系统稳定运行的关键保障,是能源供给的核心。整个硬件系 统的工作完全由电源供电的可靠性决定,电源供电不稳会导致电池损耗、单片机 复位、电感采集数据不稳定等问题。因此电源设计是硬件电路的重要一环。设计中,除了需要考虑电压范围和电流容量等基本参数之外,还要在电源转换效率、降低噪声、防止干扰和电路简单等方面进行优化。在 PCB 布局中电容的去耦作用尤为重要。本次竞赛的电源需求包括 3.3V、5V、6V、12V等。
3.2.1. 3.3V稳压模块
3.3V 供电我们使用 AMS1117芯片和RT9013-33作为稳压芯片,AMS1117是一款低压差的线性稳 压器,提供完善的过流保护和过热保护功能,它可以确保输出电压和参考源精度 在1%的精度范围内。其原理图如图3.1所示。
▲ 图 3.1 3.3V 稳压电路原理图
3.2.2. 5V稳压模块
5V稳压模块我们使用的是LM2940-5 稳压芯片,该芯片为输出电压固定的低压差三端稳压器;输出电压5V;输出电流1A;输出电流1A时,最小输入输出电压差小于0.8V;最大输入电压26V;工作温度-40~~+125℃;内含静态电流降低电路、电流限制、过热保护、电池反接和反插入保护电路。
5V电源电压的分配情况如下:
1) 将系统电源通过 LM2940-5 稳压管稳压到 5V,为单片机 5V 引脚单独供电;
2)将5V电压通过 RT9013-33 稳压芯片稳压到 3.3V,单独为 OLED、编码器、按键、蜂鸣器、运放芯片、陀螺仪、摄像头供电;
3)将系统电源通过 LM2940-5 稳压管稳压到 5V,为外部模块供电;
其原理图如图3.2.1、3.2.2、3.2.3所示。
▲ 图 3.2.1 5V 单片机电源原理图
▲ 图 3.2.2 5V 稳压电路原理图
▲ 图 3.2.3 5V 外设电源原理图
3.2.3. 6V舵机电源模块
6V电源模块我们采用的是AS1015芯片通过调节滑动变阻器使其输出的电压为6V左右来给舵机供电使用,其原理如图3.3所示。
▲ 图 3.3 舵机电源原理图
3.2.4. 12V升压模块
12V升压模块,我们采用的是MC34063升压模块,将系统电源通过MC34063升压升到12V,用于给驱动模块中的 IR2104 驱动电路供电。MC34063组成的升压电路原理如下图,当芯片内开关管(T1)导通时,电源经取样电阻Rsc、电感L1、MC34063的1脚和2脚接地,此时电感L1开始存储能量,而由C0对负载提供能量。当T1断开时,电源和电感同时给负载和电容Co提供能量。电感在释放能量期间,由于其两端的电动势极性与电源极性相同,相当于两个电源串联,因而负载上得到的电压高于电源电压。开关管导通与关断的频率称为芯片的工作频率。只要此频率相对负载的时间常数足够高,负载上便可获得连续的直流电压。
▲ MC34063升压电路原理图
其中比较器的反相输入端(脚5)通过外接分压电阻R1、R2监视输出电压。其中,输出电压U。=1.25(1+R2/R1)由公式可知输出电压。仅与R1、R2数值有关,因1.25V为基准电压,恒定不变。若R1、R2阻值稳定,U。亦稳定。其原理图如3.4所示。
▲ 图 3.4 12V升压原理图
3.3. 电机驱动模块
驱动电路是智能车对电机驱动及控制的保障。电机驱动的基本原理是H桥驱动原理,我们组采用的是H桥驱动电路。其中选择MOSFET时主要考虑的因素有:耐压、导通内阻和封装。智能汽车电源是额定电压为7.2V的电池组,由于电机工作时可能处于再生发电状态,所以驱动部分的元件耐压值最好取两倍电源电压值以上,即耐压在16V以上。而导通内阻则越小越好。封装越大功率越大,即同样导通电阻下通过电流更大,但封装越大栅极电荷越大,会影响导通速度。故MOSFET 应该基于以下一些原则:
(1)MOSFET 导通内阻要足够小;
(2)由于采用 PWM 进行控制,那么 MOSFET 需要频繁的开和关,所以选择的 MOSFET 需要有较高的开关频率;
(3)由于需要频繁的开关,其开关损耗也要很低才可以,开关响应速度要快;
(4)最大工作电流,耐压值等等都要足够大我们选用的MOSFET为IRLR7843TRPBF,耐压值为30V,最大电流为160A,导通内阻为3.1mΩ,并且在实际应用中发现该MOS容易发烫,应做好相应的散热。
在选择中专用栅极驱动芯片的时候,我们发现其中IR2104 型半桥驱动芯片可以驱动高端和低端两个N沟道 MOSFET,能提 供较大的栅极驱动电流,并具有硬件死区、硬件防同臂导通等功能。使用两片IR2104 型半桥驱动芯片可以组成完整的直流电机H桥式驱动电路。并且其功能完善,价格低廉容易采购,所以我们选择对它进行设计。其原理图如3.5所示。
▲ 图 3.5 H桥驱动电路原理图
3.3.1. 隔离芯片
我们采用的是74lvc245芯片芯片有20个引脚,DIR和OE非 是控制引脚,VCC和GND是电源引脚,A端和B端为8个输入输出口,在发送和接收方向上都具有非反向三态总线兼容输出,由OE控制输出,所以还具有隔离的作用。
其原理图如图3.6所示。
▲ 图 3.6 74lvc245电路原理图
3.4. 运放模块设计
为了能够准确的测量感应电压,还需对其进行进一步放大,一般将电压峰值 放大到 1-5V左右就可以进行幅度检测。我们选用 OPA4377运放芯片,OPA4377是一款低噪声 5.5MHz 带宽CMOS运放,具有低噪音,低功耗,失真小的特点。我们使用肖特基二极管1N5819为电路起到保护、钳制作用。其原理为肖特 基二极管1N5819由两个二极管反向串联组成的,一次只能有一个二极管导通, 而另一个处于截止状态,那么它的正反向压降就会被钳制在二极管正向导通压降 0.5-0.7以下,从而起到保护电路的目的.将周期性变化的波形的顶部或底部保持在某一确定的直流电平上。运放模块原理图如图3.7所示。
▲ 图 3.7 运放模块电路原理图
3.5. 激光打靶模块
因为在识别过程中,识别到水果的图片,要通过一个125Hz的激光去打靶来触发裁判系统,故我们组采用NE555电路来产生一个125Hz的PWM来实现此功能,当EN引脚给高电平激光就会发射125Hz的信号。其原理图如图3.8所示。
▲ 图 3.8 激光打靶模块电路原理图
3.6. 人机交互电路设计
人机交互模块由 TFT 屏幕、按键、蜂鸣器、无线串口、发光二极管等组成。主要用于调整车模运行方式、告知车模使用者车模状态及显示相关工作参数。其部分电路原理图如图所示。
3.7. 编码器模块
编码器模块的作用是计算出当前的车速,其原理图如图3.10所示。
▲ 图 3.10 编码器电路原理图
3.8. 云台电源
通过舵机电源给云台舵机供电,由Open art传过来的信号来实现转向以便于识别标靶。其原理图如图3.11所示。
▲ 图 3.11云台电路原理图
第四章 软件程序设计
比赛中采用RT1064单片机作为主控芯片,其特点在于快,主频高达600MHz,对于智能车上来说相当奢侈了,所以完全不需要担心计算的速度问题,主函数的执行速度经过测试大约在1ms到1.5ms左右,因此控制周期可以大大降低。
4.1. 摄像头控制流程
软件控制流程图如图 4.1 所示。对摄像头采集图像进行预处理,之后根据图像搜索赛道边界,并计算赛道中心,由此编写程序获得所需偏差,实现转向与速度控制。
▲ 图4.1 赛道图像处理流程图
4.1.1. 赛道图像采集
使用总钻风摄像头采集赛道信息,采集回188*90大小的赛道图像,图像采集帧数设置为100,实际测试对于我们的程序来说过高的帧数并没有显著的提升,为了保证稳定性所以没有继续加大帧数。图像的曝光度和增益等参数根据现场条件灵活选取。
4.1.2. 赛道图像预处理
对赛道图像进行预处理,首先对赛道信息的部分变量进行复位,再使用大津法进行阈值计算,根据该阈值判断每个像素点的黑白。详细计算过程不作为文章重点,在此不一一给出。
计算阈值后进行隔列处理,对于图像的188列间隔抽取导出到新数组,构成一个列数减半的图像。这样做的好处是在尽可能获取赛道特征的情况下,减少所需要的计算量。实际测试中发现对于赛道特征的提取完全没有影响,故采用该方案。
4.1.3. 扫线策略
采取继承式搜线策略,首先从理论中线开始,对离车身最近的一行进行从中间往两边扫线,使用这一行的实际中线开始,作为下一行的扫线起始点,依次类推,向远处扫到发现赛道边界或者遍历完整个图像为止。这样既获得了赛道边线的数据,也获得了赛道结束的位置,可以作为赛道类型的判断依据。
向左右扫线时可以在计算出来的阈值基础上进行一定程度的宽泛,从而增强程序的适应性,然后根据连续黑点可以判断出是赛道由黑变白,从而记录为赛道边界。
4.1.4. 中线计算与补线策略
赛道正常状态下可以直接根据左右边线进行平均计算出赛道中线值,特殊情况下需要使用到补线。
补线的方式分为以下几种:
①半宽补线:通过预先固定好摄像头角度,在理想情况下测出赛道在图像中的实际宽度,然后使用数组记录该图像对应的赛道宽度数据。半宽补线时要求至少赛道左或者右边界是完整的。补线时可以直接在左或右边界的基础上,加或者减半宽数据,获得所需要的中线。在车模运行中,入环岛前、出环岛时、出入岔口时和第一次经过车库时需要用到该补线方法。
②丢线补线:图像中出现左右同时丢线的情况,有可能是十字或者赛道反光,这时图像丢线区域仅为一小部分,通过在丢线区域前后进行中线计算,然后直接两点法做直线即可。
③环岛内补线:在环岛内,因为环岛的曲率有大有小,所以直接根据常规方法计算出的中线往往不能满足环岛内的行驶要求,所以要针对环岛内单独处理。通过在环岛内取最远处的边界点,与最近行的中心点,两点法连线做直线,获得一条斜拉的直线。实际测试发现使用根据曲率拟合的曲线和斜拉的直线表现出的效果没有区别,所以采用更为简单的斜拉直线。
4.1.5. 赛道偏差计算
赛道偏差使用加权平均的方法,对每行的中线与车身理论中线作差,获得计算后的赛道偏差。通过对每行设置不同的权重,可以使得车模获得不同的前瞻,以匹配不同的速度。
4.1.6. 赛道元素识别
在此对各元素特征进行简要概述:
①环岛:一边是直线另一边丢线数目满足条件即入环,陀螺仪计满数据即出环。
②岔路:赛道宽度变大且远处中间出现黑色部分,并且左右边线斜率在限定范围内,出岔路判断条件可宽松一些。
③Tag码和车库:均需要对黑白跳变点进行计数,Tag码跳变点数目相对车库更少,且车库处出现了丢线,故可以由此分辨处二者区别。
④其他元素:不需要特殊处理。
4.2. 转向舵机的位置式模糊PD控制
舵机部分我使用的是位置式模糊PD控制。因为对于舵机来说更需要实时性,所以采取了积分分离的位置式PD控制。
模糊控制则是为了减小车模运行时的晃动程度,尽可能的忽略小偏差带来的抖动,加强车模的稳定性和不同赛道的适应性。通过不同赛道上,偏差以及偏差变化率的大小不同,使用模糊控制可以计算出不同的Kp和Kd参数,使用这些参数再计算,可以在不同条件下得到不同的转弯性能。
比如在小S弯,使用模糊控制可以尽可能地减小车模在其中的抖动,实现小S直冲的效果。在180°弯则可以获得较强的转弯性能,配合基础Kp甚至可以实现内切过弯。其问题在于十字处,因为我们没有来得及针对十字特殊处理,所以如果出现过分的斜入十字,就会有可能导致十字处左拐或者右拐。
解决的方法是加上一个略大一点的基础Kp和Kd,略大一点也只是相对更改之前,和模糊计算出来的数值对比还是很小的。进而可以在对其他赛道影响不大的情况下解决这个问题。
4.3. 驱动电机的PID控制
电机部分分两次进行控制,一次是差速位置式PD计算,一次是控速增量式PI计算。差速PD计算是为了和舵机配合,所以也使用了模糊控制,使用相同的模糊规则表进行计算,使用单独的差速系数来控制差速的幅度,最终计算出一个目标速度。差速数值的计算方法程序会在附录中给出。
算出目标速度之后,就是通过增量式的PI控制电机,此处的PI参数由于时间关系,没有调整的足够精准,导致了大幅度加减速时会有影响,下文会指出。
4.4. 出入库与停车策略
4.4.1. 出入库
出库和入库采用直接调用预先编写好的路径程序,从而保证了出库和入库的路径不变,只需要确定出入库时的车身位置和姿态即可。
出库位置摆放好即可,入库则需要根据斑马线的位置,选择何时入库,通过多次测试就能得出最合适的位置。
4.4.2. Tag码停车
比赛任务要求车模在Tag码前停车,并进行相应的识别等任务。对于高速运动的车模来说,主要难度在于快速的停车,以尽可能地减少刹车距离,保证不冲出停车区域的同时,压缩所消耗的时间。
由于刚才所说的电机控制不够强力,所以不得不加入其他的方法来更快地减速。在此使用的是电机直接全速反转来减速,效果尚佳,缺点在于不够精准,容易导致车模后退一小段距离,需要再往前走回去。另外就是堵转时间较长,容易导致驱动电路发热或烧板。
第五章 图像识别部分
5.1. 任务简述
根据比赛要求,需要在比赛过程中需要部署神经网络识别动物、水果、数字、AprilTag码。根据识别的结果进行相应的动作。
识别任务属于典型的计算机视觉,借助于人工神经网络实现。传统的图像滤波很难实现所有的视觉任务,必须部署人工神经网络。同时在此也感谢逐飞科技在赛前提供的入门思路和教程给予了我们一定的启发
5.2. 平台
由于机器学习相关的开发环境搭建十分复杂,需要安装的软件包非常多。并且对于计算机的CPU可能由于在兼容性的问题而无法运行(一个不小心开发环境还会挂掉),并且陪伴我的笔记本属实寒酸,没有独立显卡,训练人工神经网络实在是有点力不从心。只好转战Google Colab。
5.2.1. 生成和训练平台
Colab全称为Colaboratory,是免费的Jupyter运行环境,并且完全在云端运行。并且提供了全套和最新的Keras软件支持包,完美契合人工神经网络的搭建的需求。简单来说,可以在这个网站上编程,调用最新Keras API搭建模型,而不需要安装任何支持包;并且模型的训练可以借助云端的算力,而不是计算机本身的算力。其实Colab提供的算力并不多。大概相当于一个装有中低端独立显卡的笔记本电脑。不过胜在使用方便。我生成和训练人工神经网络的模型几乎都在Colab上进行。
5.2.2. 部署和运行平台
经过训练的人工神经网络需要部署在小车上,也就是需要一个平台。在我们的方案中,将人工神经网络部署在OpenArt平台上。OpenArt可以加载经过量化的人工神经网络,将传感器采集的图片送入网络中进行识别。
5.3. 模型的生成和训练
5.3.1. 模型的种类和量化
最开始时按照逐飞给出的训练模型脚本和模型实例,使用输入层的尺寸为32323,再用逐飞给出的量化脚本进行量化。
不得不说,按照这样的方案来,识别率确实是惨不忍睹。分类结果基本上根据曝光度来决定。让我在很长一段时间内对能否顺利完成比赛任务产生了怀疑。
后发现在逐飞给出的资料中,发现tflite类型的文件也可以在OpenArt上部署,并且同样的模型在量化后识别率高出nncu类型的模型很多,之后就采用了tflite类型的模型进行部署。仅仅是采用tflite模型,识别率提高了很多。
5.3.2. 数字模型的生成和训练
相较于识别动物&水果模型,识别数字相而言较为轻松。对模型和训练集的要求都不高。在准备过程中数字一直是轻松省心的任务。
数字识别模型输入层尺寸48483也就是48*48像素的RGB色彩图片。其中加入比例系数为0.6的DropOut层。
通过阅读逐飞给出的生成模型脚本,可以发现,逐飞采用的方法是Keras-Tensorflow框架。只要对Keras-Tensorflow有一定的了解就可以根据自己的需求自己动手搭建人工神经网络。其中非常重要的一点就是输入层的大小,其实也就是传感器采集图像后送入网络的图片的尺寸;逐飞给出的实例中采用32323.属实是小了。用以识别数字已经比较勉强,识别动物和水果比较吃力。
经过实际测试,以OpenArt的算力,输入层为64643的普通结构的,参数大约在600K个左右的网络,识别速度绝对能达到要求。数字模型最终采用的结构如图所示:
▲ 图5.1 数字模型结构
由于识别对象只有十个即数字09,识别率很容易验证。在实际验证后,模型的准确率往往都是95%以上。除去光照造成的影响,完全可以识别出所有的数字。并且由于模型的尺寸很小(相较于动物水果模型),识别速度也很快。大约有34 fps。总结,数字识别部分只要不和动物水果模式一起使用,就没什么大的问题。识别率也很高。
5.3.3. 动物&水果模型
相较于数字识别,识别动物&水果难度大大提高,识别对象多了两个数量级。图片承载的信息也更加繁多。数字都是白底黑字,而动物水果背景丰富,内容更加多样。当卓老师公布全部907张图片之后,我心头一紧。图片数量多,内容复杂。想要做出能精确识别这十个种类并在计算机上运行,不难。但是经过量化后可以在移动端上运行,并不容易。
最终,动物&水果模型采用了量化后的MobilNet结构。并且准备了两个版本。
▲ 图5.2 版本一
▲ 图5.3 版本二
图5.2是MobeilNet模型在Alpha 参数为0.5并且加上系数为0.6的DropOut层时的模型结构;图5.3.2是MobeilNet模型在Alpha 参数为0.75并且加上系数为0.6的DropOut层时的模型结构。后者的参数达到了1.5M个。所占存储内存达到了1.8MB。“重量级模型”。
之所以会准备两个模型,是希望比赛时可以根据赛场状况调整。“重量级”准确率高,识别速度较慢,“轻量级”正相反。两者在识别中大概会有1s左右的差距。数据上的准确率其实两者相差无几。最后都是100%。Loss值都在0.001~0.0001这个区间。
▲ 图5.4 准确率数据
实际上,Alpha系数为0.75的重量级模型,实际测试中的准确率略胜一筹。但轻量级对于OpenArt的运行资源要求更少,更快,更稳定。
5.4. 模型的优化
5.4.1. 过拟合与DropOut
过拟合是机器学习中很难避免的问题。因为在机器学习的一些模型中,如果模型的参数太多,而训练样本又太少的话,这样训练出来的模型很容易产生过拟合现象。在训练bp网络时经常遇到的一个问题,过拟合指的是模型在训练数据上损失函数比较小,预测准确率较高(如果通过画图来表示的话,就是拟合曲线比较尖,不平滑,泛化能力不好),但是在测试数据上损失函数比较大,预测准确率较低。
实际上,在模型训练结束时数据上的准确率往往有90%,经过实际测往往是达不到这个准确率的。添加DropOut层用来对抗过拟合,在我们组的方案中是行之有效的方法。DropOut的作用很简单,训练时随机屏蔽一些网络,只根据剩余的网络进行预测,频闭的网络的数量占总数量的比值就是DropOut层唯一的参数。例如,系数为0.6的DropOut层即是说训练时每次屏蔽60%进行预测。因此,同样一个模型是否添加DropOut层,对模型最终的尺寸、占据的存储空间是不影响的。
起初没有添加过DropOut层,训练数据又明显的过拟合的趋势,后来逐步了解了一些对抗过拟合的方法,添加DropOut层就是最简单的一种。最开始DropOut层的参数是0.2。后来听取了一位同学的建议,直接调整到0.6,根据这个同学的说法就是,小型的网络很容易出现过拟合现象,DropOut系数可以给的大一些。经过实际的测试,0.6的比例系数是更合适的,对抗过拟合现象效果更加明显。
▲ 图5.5 无DropOut层准确率
▲ 图5.6 无DropOut层loss
图5.4.0和图5.4.1展示了在没有DropOut层作用的情况下,一个输入层尺寸为48483的模型在训练中准确率和Loss随着训练迭代的变化情况。基本上在训练进行到第10次迭代时就应开始过拟合,后续的训练都会增加过拟合程度。
▲ 图5.7 带DropOut层准确率
可以看出,增加了DropOut层有效的缓解了过拟合的问题,第10次迭代到第20次迭代都在有稳定的降低loss提升准确率。但是过拟合问题仍然存在。第30次迭代以后训练效果都不明显。
5.4.2. 数据增强
数据增强主要用来防止过拟合,用于dataset较小的时候。之前对神经网络有过了解的人都知道,虽然一个两层网络在理论上可以拟合所有的分布,但是并不容易学习得到。因此在实际中,我们通常会增加神经网络的深度和广度,从而让神经网络的学习能力增强,便于拟合训练数据的分布情况。在卷积神经网络中,有人实验得到,深度比广度更重要。
数据增强,简单来说就是对原有的数据经进行一些变换,得到新的数据集;这些变换包括:水平位移、垂直位移、伸缩、剪切、旋转等。除此之外还有例如ZCA白化、高斯噪声等适用于数据增强的算法。
高斯噪声是根据一张图片中某一个像素点周围其他像素点的色彩值,随机的反转中心像素点的色彩值,说白了就是人为的给图像添加噪声,破坏图像原有的“规律”使模型在训练时不会朝着这些无用的“规律”的方向过拟合。
▲ 图5.9 未增加高斯噪音 图5.10 已增加高斯噪音
由图5.9和图5.10分别表示了未增加高斯噪音和已经增加了高斯噪音的图片。为了适应模型训练,原图片已经经过了一些处理,图像边缘增加紫色边框,并且将分辨率将为96*96。
Keras支持数据增强,自带一部分常用的数据变化方法,例如伸缩、平移、旋转等,但不支持添加高斯噪音,需要在制作数据集的时候手动添加高斯噪音。Keras提供的imageDataGenerator类对象可以很方便的对数据进行变换。
▲ 图5.11 文档中的部分描述
图5.11是Keras中文文档中关于imageDataGenerator类对象的部分描述。
根据实际测试的结果,数据增强是对抗过拟合,提高模型准确率的一个重要且有效大的手段。但是过度夸张的数据增强,例如旋转角度过大,高斯噪声用力过猛,平移太狠之类都会反过来降低准确率。所以,数据增强并不是越夸张越好。
5.5. 定位靶标
除了图像识别以外的任务就是,寻找空间中的紫色边框。根据AprilTag码的内容,只能确定靶标在空间的大概位置,无法确定靶标和AprilTag码的相对位置,所以需要定位空间中的靶标。
其实就是找紫框。OpenArt有很多照搬OpenMV的机器视觉算法,其中就有找到图像中黑色矩形find_rect。逐飞给出的方法也是这个办法。但是这个方法是真的拉。对背景的要求太苛刻了。根据我的实际测试,这个方法很容易找例如门等类似矩形的东西。而对紫框视而不见。
后来改为find_blob.通过调整LAB通道阈值来滤除图像中除了紫色边框之外的成分。要特别注意的就是,光照条件对LAB的阈值影响很大。
▲ 图5.12原图像
▲ 图5.13过滤后图像
第六章 RT-Thread主要应用
首先我要感谢在本次比赛中,提供RT-Thread开源库的逐飞科技和RT-Thread官方。这为我们省去了大量的移植时间,并且能够较快的根据例程,学习并上手操作系统,学会其中的各个概念,故在此特别提出感谢。
智能车的难点主要在于赛道信息的采集处理和运动控制算法,大家往往都很重视程序各模块的效果,却经常忽视掉综合程序执行的逻辑顺序和总体效果。
举个例子来说,以智能视觉组的任务量来说,如果代码风格不够好,有较多冗余代码并且沿用了此前比较流行的NXP公司的K66单片机,那么就会导致程序的执行速度出现问题,并且是会发生在各模块程序组合作用下,一般不会在单模块调试阶段发现。那么这时就是因为程序的耦合导致了问题的加剧。哪怕是性能足够强悍的RT1064单片机,也需要在编程时多加注意程序的顺序或者逻辑。避免浪费算力。
下面就针对在智能车上,如何使用RT-Thread改善代码,优化程序。并和裸机状态做对比。
6.1. 多线程实现任务的同步进行
通过参考《RT-Thread编程指南》以及官方入门教程,完全可以做到几天入门。教程相当简单明了,只要基础的概念都有那么学习起来速度飞快,而且网络上的资料也十分充足。
智能车为了方便调试,经常需要在运行期间查看各个变量的值或者是摄像头采集回的图像,问题在于需要用到串口传输数据或者屏幕显示。这两个部分都比较占用程序运行时间,在裸机状态下,程序同时只能做一件事,如果加上屏幕显示函数,那么会导致程序运行时间变为原来的至少16倍也就是24ms。
那么就需要在保证车模运行的程序正常执行的前提下,再以较低的优先级加入调试用到的程序。在裸机开发下要实现只能通过查询的方法,效率相当低下。但是在操作系统中就不同了,只需要通过最简单的信号量(不仅限于信号量),即可实现。
主要原因是RT-Thread 的线程调度器是抢占式的,主要的工作就是从就绪线程列表中查找最高优先级线程,保证最高优先级的线程能够被运行,最高优先级的任务一旦就绪,总能得到 CPU 的使用权。所以只要把重要的程序设置成高优先级并使用信号量等方式,再把调试用的程序设置为低优先级,那么就可以让单片机仅仅在空闲状态下执行调试所用的程序。
举个例子:在智能车程序中常用做法是把摄像头采集完成时产生一个信号量,用来唤醒高优先级的图像处理线程,那么低优先级的调试函数就要被挂起。在实际应用中,由于摄像头图像处理程序所需要的时间相比图像显示程序时间极短,低一个数量级以上。所以使用多线程后的效果相比裸机状态下只使用显示函数的效果几乎一致,用作观察和调试完全没有影响。再加上串口调试的发送程序,影响更是微乎其微。除此之外,还可以通过对不同线程进行分优先级以及同优先级设定不同时间片等内容,进而可以进行更高度的自定义。
由此就可以实现多线程下,任务的同步进行。相比于裸机开发,使用RT-Thread操作系统可以说是“低耦合,高内聚”,极大程度上降低了程序之间的相互影响。
使用线程时要注意的主要有三点,上下文环境、线程的状态跃迁、线程运行时间长度。在创建线程时务必要注意设计要点,在智能车程序设计中,主要是要关注第二个,线程的状态跃迁。
这里说的状态跃迁指的是线程运行中状态的变化,从就绪态过渡到挂起态。实时系统一般被设计成一种优先级的系统,如果一个线程只有就绪态而无阻塞态,势必会影响到其他低优先级线程的执行。所以在进行线程设计时,就应该保证线程在不活跃的时候,必须让出处理器,即线程能够主动让出处理器资源,进入到阻塞状态。这需要设计者在设计线程的时候就明确的知道什么情况下需要让线程从就绪态跃迁到阻塞态。
6.2. 任务间的信息传递与通讯
在嵌入式系统中运行的代码主要包括线程和ISR,在它们的运行过程中,它们的运行步骤有时需要同步(按照预定的先后次序运行),它们访问的资源有时需要互斥(一个时刻只允许一个线程访问资源),它们之间有时也要彼此交换数据。这些需求,有的是因为应用需求,有的是多线程编程模型带来的需求。
操作系统必须提供相应的机制来完成这些功能,我们把这些机制统称为进(线)程间通信(Internal Process Communication IPC),RT-Thread中的IPC机制包括信号量、互斥量、事件、邮箱、消息队列。
6.2.1. 信号量的应用及智能车中的生产消费问题
在智能车软件设计中,常常需要让中断和其他程序间传递信息。在裸机开发下的做法一般都是设立全局变量的方式,然后使用查询的方法来达成信息的传递。这样做虽然可行,但是带来的是大量的全局变量。这不仅导致了程序的可读性下降,而且大大增加了程序之间互相耦合的现象,很容易出现“牵一发而动全身”的结果。
那么在使用RT-Thread操作系统的情况下,就可以灵活使用IPC机制来避免这些情况的出现,并且可以更好更简洁的传递有效信息。在这些机制中智能车最常用的就要属信号量了。
▲ 图6.1信号量工作示意图
信号量工作示意图如上图6.1所示,每个信号量对象都有一个信号量值和一个线程等待队列,信号量的值对应信号量对象的实例数目(资源数目),假如信号量值N,则表示共有 N 个信号量实例(资源)可以被使用,当信号量实例数目为零时,再请求该信号量的线程就会被挂起在该信号量的等待队列上,等待可用的信号量实例(资源)。
上文中提到过,摄像头采集完成会产生一个信号量,从而确保图像处理程序可以得到执行。那么在图像处理完成之后,需要立刻让车模作出反应,利用刚才计算好的数据进行姿态控制,由于电机必须相同时间间隔控制,所以就要对舵机进行控制。可以采用的方法是:图像处理程序执行结束后,再产生一个信号量,去执行更高优先级的舵机控制程序,让车模的反应更加迅速,并且避免了无效图像的产生。
例如:在裸机开发下,如果把舵机控制程序放到中断里。当程序执行速度过快时,容易出现图像采集加处理完成之后,计算出的数据还没有来得及调用,就开始了下一帧图像的采集和处理。这会导致车模错过一帧图像并且计算出的数据和当前控制效果关联性差。这也是为什么不能一味的追求快速的图像处理而忽略掉作为根基的控制效果。
这个问题其实就是生产者消费者的典型案例,图像处理程序是生产者,舵机控制程序是消费者;从另一方面看,摄像头采集程序是生产者,图像处理程序和舵机控制程序又是消费者,所以严格把握好程序执行的逻辑关系相当重要。程序执行的逻辑出了问题哪怕有再强的硬件和算力,都得不到最好的控制效果。
使用信号量就能解决掉这个问题,因为从根本上来说,这个问题主要就是舵机控制程序要求必须和图像处理程序保持同步。且在数据没用掉的时候,不允许开始新一轮的采集与计算,也就是互斥的关系。只需创建几个信号量,通过采集和释放信号量就能解决问题,具体的解决方案如图6.2。
▲ 图6.2信号量解决生产消费问题流程图
信号量是一种非常灵活的同步方式,可以运用在多种场合中。形成锁、同步、资源计数等关系,也能方便的用于线程与线程,中断与线程的同步中。在智能车上往往就是在线程同步时使用到的。
线程同步是信号量最简单的一类应用。例如,两个线程用来进行任务间的执行控制转 移,信号量的值初始化成具备0个信号量资源实例,而等待线程先直接在这个信号量上进行等待。
当信号线程完成它处理的工作时,释放这个信号量,以把等待在这个信号量上的线程唤醒,让它执行下一部分工作。这类场合也可以看成把信号量用于工作完成标志:信号线程完成它自己的工作,然后通知等待线程继续下一部分工作。
6.2.2. 邮箱的应用及可行的优化方案
邮箱服务是实时操作系统中一种典型的任务间通信方法,特点是开销比较低,效率较高。邮箱中的每一封邮件只能容纳固定的4字节内容(针对32位处理系统,指针的大小即为4个字节,所以一封邮件恰好能够容纳一个指针)。典型的邮箱也称作交换消息,如图6.3所示,线程或中断服务例程把一封4字节长度的邮件发送到邮箱中。而一个或多个线程可以从邮箱中接收这些邮件进行处理。
▲ 图6.3邮箱工作示意图
在智能车软件设计中,经常用到地址的传递,或者是变量的传递,之前所说的信号量就不能满足要求了,而邮箱恰巧可以实现该要求,而且4字节内容也足够传送一些关键数据,数组等则可以采用传送地址的方式来实现。
在智能车程序中仅仅使用了最简单的变量传递功能,实际使用中还有很多部分可以使用邮箱来简化程序,只是限于时间问题,未对程序完成优化,下文会写出具体的改进方案。
例如在智能车上用到的是用邮箱传递变量,控制蜂鸣器工作的时间在裸机状态下,要在控制蜂鸣器定时工作的前提下不影响主程序的执行,就必须通过在定时器里查询的方式控制蜂鸣器的工作与停止。这样必然会增加程序的复杂度和耦合程度。
但是使用邮箱的方法传递数据,可以直接使用邮箱传递的数据,对单独的蜂鸣器线程进行控制、延时等操作,通过线程间的切换来提高工作效率。
当然,在实际应用中,灵活使用邮箱
以上是关于智能车竞赛技术报告 | 智能车视觉 - 中原工学院 - 逐鹿 - 分母队的主要内容,如果未能解决你的问题,请参考以下文章
智能车竞赛技术报告 | 智能车视觉 - 青岛工学院 - 青工战斗
智能车竞赛技术报告 | 智能车视觉 - 三江学院 - 识别不别
智能车竞赛技术报告 | 智能车视觉 - 新余学院 - 开放艺术队
智能车竞赛技术报告 | 智能车视觉 - 石家庄学院 - 百事