IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> 智能车竞赛技术报告 | 智能车视觉 - 山东大学(威海) - 山魂五队 -> 正文阅读

[人工智能]智能车竞赛技术报告 | 智能车视觉 - 山东大学(威海) - 山魂五队

简 介: 本文详细介绍了山东大学(威海)山魂五队在第十六届“恩智浦”杯全国大学生智能汽车竞赛智能视觉组中的系统方案,包括硬件电路设计、机械结构设计、巡线算法以及识别算法的设计等。本小车采用大赛组委会统一指定的C型车模,AI小车以单片机MIMXRT1064DVL6A为控制核心,总钻风摄像头和电感共同采集赛道信息进行寻迹、在省赛中搭建二维云台配合openart mini完成寻迹过程中的智能识别任务、在国赛中使用Openart mini快速完成多分类任务,并让车模做出对应动作。在硬件电路的设计上主要应用了低压差线性稳压电路、运算放大器以及半桥驱动H桥电路;在寻迹算法设计中使用大津法获取图像阈值进行二值化、使用八临域算法寻找赛道边界,之后用ADRC算法使小车追踪目标值达到理想效果;在智能识别算法设计中,我们搭建卷积神经网络、训练神经网络模型来识别标靶、数字以及二维码。在算法实现时,我们使用 IAR 集成编译环境编写C语言代码,采用openmvIDE作为编译器编写python代码,通过数据采集、数据增强等方法训练出nncu模型和tflite模型,设计出了一款能完成所有识别任务的智能小车。

关键词 摄像头寻迹智能识别ADRC

简 介: This paper introduces in detail the system scheme of Shanhun team 5 of Shandong University (Weihai) in the intelligent vision group of the 16th NXP Cup National College Students’ intelligent automobile competition, including hardware circuit design, mechanical structure design, line patrol algorithm and recognition algorithm design. The car adopts the C-type car model uniformly designated by the competition organizing committee. The AI car takes the single-chip microcomputer mimxrt1064dvl6a as the control core, the total drill air camera and inductor jointly collect the track information for tracking, build a two-dimensional PTZ in the provincial competition, cooperate with openart mini to complete the intelligent identification task in the tracking process, and use openart mini to quickly complete the multi classification task in the national competition, And let the model make corresponding actions. In the design of hardware circuit, low voltage differential linear voltage stabilizing circuit, operational amplifier and half bridge drive H-bridge circuit are mainly used; In the design of tracking algorithm, the Otsu method is used to obtain the image threshold for binarization, the eight neighborhood algorithm is used to find the track boundary, and then the ADRC algorithm is used to make the car track the target value to achieve the ideal effect; In the design of intelligent recognition algorithm, we build convolutional neural network and training neural network model to identify targets, numbers and two-dimensional codes. In the implementation of the algorithm, we use IAR integrated compilation environment to write C language code, use openmv ide as the compiler to write Python code, train nncu model and tflite model through data acquisition and data enhancement, and design an intelligent car that can complete all recognition tasks.

关键词 Camera trackingintelligent recognitionADRC

学 校:山东大学(威海)
队伍名称:山魂五队???
参赛队员:赵泽洋 王自豪??
李梅爽????
指导老师:王小利????

?


??全国大学生智能汽车竞赛是由教育部高等学校自动化专业教学指导委员会主办全国大学生智能汽车竞赛。该竞赛以“立足培养,重在参与,鼓励探索,追求卓越” 为指导思想,旨在促进高等学校素质教育,培养大学生的综合知识运用能力、基本工程实践能力和创新意识。智能车竞赛涉及多个领域:自动控制、模糊识别、传感器技术、电子电气、计算机技术、机械与汽车等多个学科,为大学生提供了一个充分展示想象力和创造力的舞台,吸引着越来越多来自不同专业的大学生参与其中,激发了大学生的创新思维,对于其实践、创新能力和团队精神的培养具有十分最重要的价值。该竞赛分竞速赛、创意赛和技术方案竞赛三类比赛。

??人工智能是计算机科学的一个分支,该领域的研究包括机器人、语言识别、图像识别、自然语言处理和专家系统等。人工智能从诞生以来,理论和技术日益成熟,应用领域也不断扩大。随着计算机技术的发展,人工智能在本世纪大放光彩,智能识别也越来越多的应用在生活中的各个领域,作为一个与时俱进的比赛,第十六届“恩智浦”杯全国大学生智能车竞赛引入了“智能视觉”组别,在竞速的基础上加入了识别tag码、动植物、数字等任务,并要求小车做出相应的动作。

??与以往单纯的嵌入式控制不同,识别彩色图片需要用到卷积神经网络。要完成所有比赛的既定任务,我们需要在基础控制的基础上,训练神经网络之后使相关运算结果参与小车决策。所以本组别是一个兼容智能小车寻迹与控制和人工智能的组别,这对小车的硬件性能要求、软件逻辑、训练模型的稳定性以及正确率都有很高的要求。

??本文按照硬件设计与实现、识别算法设计与实现、寻迹算法设计与实现的顺序详尽的描述了山魂五队车模的设计,对其中创造、发明以及分析的内容进行了标注以及解释。
?

第一章 统方案设计概述


1.1系统框图

▲ 图1.1系统结构框图

▲ 图1.1系统结构框图

1.2系统介绍

??本智能小车的总体工作模式为:用总钻风摄像头以及七路电磁传感器、激光测距等传感器采集赛道信息后做相应处理,以处理后的信息为基础进行寻迹,用编码器来检测小车速度,获取小车的实时位置以及状态;通过PID算法控制前轮舵机转向角度以及后轮电机来调整小车的位置以及速度,使得小车在赛道上以较好的姿态快速运行。当总钻风在小车运行时看到tag码或者三叉路口,则小车停止寻迹,主控芯片MIMXRT1064DVL6A与openart mini进行通信,初始化openart mini、控制二维云台并且与之配合完成识别任务。为了让小车完成此任务,我们力求系统稳定简洁高效,无论在硬件还是在软件上面都尽量简化结构、力求高效。
?

第二章 模整体结构设计


2.1基础车模介绍

??第十六届“恩智浦”杯智能车竞赛“智能视觉”组的指定车模是C车模,其对称性好,舵机安装方便,车模具有快速灵敏,精度高、响应快、动力强劲、抓地力强、刚性足以及中心低等优势。C车模尺寸为29×18×9.8cm,轮胎尺寸为29×60mm,通过对轮胎适当的填充海绵和进行软化封胎处理,使车模具有较好的减震性,可以提供更大的摩擦力。C车车模采用后轮双驱为动力,前轮舵机做转向控制:驱动电机为RS-380,额定电压7.2V,最大功率可达20 W,额定功率0.016kW,空载电流<630mA,额定转速16200rpm,额定转矩可达10.9N×m,外形储存29.2×37.8mm;舵机型号为S3010舵机,6V电压时扭力可达6.5kg×cm,动作速度为0.16±0.02sec/60°,响应快、精度高。

2.2传感器的选择

??为保证车模可以及时获取赛道信息、及时作出响应,我们采用总钻风摄像头作为寻迹传感器,七路电磁传感器作辅助寻迹,配合激光测距、编码器等位置、速度传感器,完成“智能视觉”的基础寻迹任务。对于智能识别任务,我们采用openart mini作为识别传感器、激光测距作为找标靶位置的传感器,配合云台以及小车的移动,完成找靶标、识别图片等任务。

2.3电池的选择

??为满足各种执行器以及传感器供电需要,考虑小车重心问题,我们采用两节航模锂电池进行供电,为了保证小车有足够的爆发以及续航能力,我们选用容量为52000、c数为35的航模锂电池。为保证安全,我们购买了电池保护板并绘制分电板为主板和驱动供电。通过合理选择电池位置以调节车体重心,使得小车重心符合后驱车运动规律,加减速性能较好。

2.4小车机械结构设计

2.4.1车模转向结构设计

舵机的安装

??舵机安装方式有立式和卧式两种,比较两种方式发现,立式安装在舵机旋转相同的角度时转过的角度更小,所以立式安装舵机转向响应更快。舵机安装时要保证左右对称,这样可以保证舵机左右转向时力臂相等且处于最大范围,提升了舵机的响应速度。经理论分析,功率等于速度与扭矩的乘机,加大转向速度必然减少输出扭矩,扭矩过小会造成迟钝,所以安装时必须考虑到转向机构的响应速度与舵机扭矩之间的关系,获得最佳转向效果。

车轮定位

??车模的两个后轮同轴受到限位,无法调整,与智能车的前进方向保持平行,因此要改变智能车与地面的接触方式,调试出利于车转向、直线的四轮定位,只能通过调整前轮倾角各定位参数来实现。它的安装位置主要是由主销内倾、主销后倾和前轮前束三个项目决定

主销后倾

??主销后倾是指在纵向平面内主销轴线与地面垂直线之间的夹角,向前为负,向后为正。它在车辆转弯时会产生与车轮偏转方向相反的回正力矩,使车轮自动恢复到原来的中间位置上。所以,主销后倾角越大,车速越高,前轮自动回正的能力就越强,模型车通过增减黄色垫片的数量来改变主销后倾角。由于竞赛所用的转向舵机力矩不大,过大的主销后倾角会使转向变得沉重,转弯迟滞。所以我们修改主销后倾大致1~2°。调整后如图2.1。

▲ 图2.1 调整后的主销后倾

▲ 图2.1 调整后的主销后倾

主销内倾

??主销内倾是将主销的上端向内倾斜。从车前方看去,主销轴线与通过前轮中心的垂线之间形成一个夹角,即主销内倾角。轮胎调整为倾斜以后直线行走的时候是轮胎内侧着地,而当过弯的时候,由于惯性车体会要向弯道外侧倾斜,而这时候的外侧轮胎如果倾斜角度事先调整得当则正好可以胎面着地,从而使车辆在弯道获得最佳抓地力。使车轮转向后能及时自动回正和转向轻便。调整后如图2.2。

▲ 图2.2 调整后的主销内倾

▲ 图2.2 调整后的主销内倾

前轮前束

??车轮前束是指两轮之间的后距离数值与前距离数值之差,也指前轮中心线与纵向中心线的夹角。从上往下看,两个车轮指向的方向在前端指向内称为车轮前束,指向外的则称为车轮后束。前轮前束的作用是保证汽车的行驶性能,减少轮胎的磨损。前轮在滚动时,其惯性力自然将轮胎向内偏斜,如果前束适当,轮胎滚动时的偏斜方向就会抵消,轮胎内外侧磨损的现象会减少。调整后如图2.3。

▲ 图2.3 调整后的前轮前束

▲ 图2.3 调整后的前轮前束

2.4.2小车智能视觉部分车模结构设计

??在智能视觉组别的任务中,有识别赛道上的二维码、赛道前方的数字牌、赛道左右的动植物标靶的任务,我们在设计车模时选择使用一个openart mini摄像头传感器和二维云台的组合来完成任务;为完成激光打靶任务,我们采用工业级5MW激光。

??对于智能识别部分,任务要求需要完成识别、激光打靶等任务,因此需要激光发射器以及二维云台。为减小增加云台后对车模重心的影响,同时考虑云台精度等问题,二维云台中x轴转向舵机采用280°PWM伺服舵机FT2331M:该舵机工作电压3V8.4V,6V供电时扭矩可达4.5kg×cm,重量20g,齿轮虚位≤5°,尺寸23×12×27.5mm,是一款高精度的小型舵机;二维云台中y轴转向舵机采用270°PWM伺服舵机LH-S0090:该舵机工作电压4.8V6V,6V供电时扭矩可达1.8kg×cm,重量9g,齿轮虚位≤7°,尺寸为23×12×22.5mm。激光发射器采用通用工业激光,2.5~15V通用供电,功率5mW。

??为降低重心,我们将X轴转向舵机放在紧贴车模底盘的位置,从舵盘引出支撑杆到一定高度后安装Y轴舵机,我们自己设计舵机摆臂并将openartmini固定在舵机摆臂上,这样可以使识别摄像头完成二维运动,实现使用一个摄像头传感器感知赛道上以及赛道周围的信息。舵机摆臂的三维图如下所示:

▲ 图2.4舵机的三维摆臂

▲ 图2.4舵机的三维摆臂

??通过合理设计云台结构,使用两个小舵机和激光发射器、openartmini即完成了复杂的识别任务,减轻了车模重量、减少了传感器数量。最终云台结构实物图如下图所示:

▲ 图2.5云台结构实物图

▲ 图2.5云台结构实物图

2.4.3车模重心设计

??为提高车模的抓地力、防止车模过弯时侧翻,我们合理的配置了车模的重心。由于车模是双后驱,前方转向,所以要求小车尽量前轻后重,查阅大量资料我们得知后驱车模最好的前后重量比例为4:6.由于小车前部架有二维云台,导致车模前后重量比例不合适,我们在车模的后方适当的加一些配重块,使车模拥有合适的重心。

2.4.4车模传感器的设计安装

??本车模设计主要使用了MT9V034 总钻风灰度摄像头,电感与测距传感器Tfmini-Plus等传感器。关于MT9V034 总钻风灰度摄像头的安装,我们采取碳素杆固定的方式,将其架设在镜头中心距地面30cm左右的位置,以获取较好的视野;关于电感的安装,我们采取铜柱固定的方式,将其架设在车模前端,在不遮挡总钻风摄像头视野的情况下获取精准的电磁信号。关于测距传感器安装,我们将其安装在车模舵机前端,以获取实时数据辅助坡道的识别。以上传感器大体安装位置如图所示

▲ 图2.6 车模实物结构图

▲ 图2.6 车模实物结构图

2.4.5系统电路板的固定及连接

??本车模电磁板使用铜柱固定,并使用软排线将其与主板连接,主板与分电板采取打孔的方式,利用铜柱固定于车模底盘,以获取较好的重心。运放板与驱动板则使用胶枪分别粘贴至电磁板下方与电机上方。

2.5小车整体图片

??本次智能车大赛设计的智能车的外形大致如图所示:

▲ 图2.7侧视图

▲ 图2.7侧视图

▲ 图2.8俯视图

▲ 图2.8俯视图

?

第三章 件电路设计


??硬件是软件系统的基础,一个良好、稳定、安全的硬件环境可以提高小车的整体性能,也能保证小车车能平稳快速的行驶。我们在整个小车硬件系统设计过程中严格按照规范进行。本着可靠、高效的原则,在满足传感器和执行器要求的情况下,尽量使用原理简单、能耗低的电路,设计电路时在保证电路稳定性的前提下使电路板整洁美观。

3.1单片机系统设计

??单片机最小系统是智能车系统的核心控制部件,单片机也被称为单片微控器,属于一种集成式电路芯片。在单片机中主要包含CPU、只读存储器ROM和随机存储器RAM等,多样化数据采集与控制系统能够让单片机完成各项复杂的运算,无论是对运算符号进行控制,还是对系统下达运算指令都能通过单片机完成。由于智能识别任务需要很多外设以及执行器,为了达到快速处理复杂赛道信息、同时控制多种执行机构的目的,我们采用具有更高性能NXP I.MX RT1064芯片。原理图如图3.1所示:

▲ 图3.1:单片机系统原理图

▲ 图3.1:单片机系统原理图

3.2主板设计

??主板的是小车的主控制板,其作用为为单片机系统提供电源以及引出外设。

3.2.1主板电源部分设计

??电源模块为系统的CPU、传感器、执行器提供所需要的电源。设计中,除了考虑电压范围和电流容量等基本参数之外,还需要考虑电路的复杂程度、电源转换效率、以及如何防止干扰等问题。可靠而且稳定的的电源方案是整个系统稳定可靠运行的基础。

??系统的总供电由额定电压为7.4V、满电电压为8.4V的两串航模锂电池提供,分电板带有均衡功能的电池保护板,可以直接为电机供电。为了满足不同电路模块对电压以及电流的需求,本电路的电源模块包括多个稳压模块:

5 V供电:

??由于最小单片机系统、编码器、运算放大器、openart mini、TTL串口、激光等多种外设都需要5V供电,由于使用5V供电的外设中存在大电流器件,我们分别使用MIC29300-50WU、LD29150-50R将7.4-8.4V的电压稳压在5V为外设供电。

??MIC29300是一款大电流低压线性稳压芯片,其可以提供最大3A的负载电流,并且保证公差不超过1%,我们选择封装为TO-220,电路简单并且大小负载都可以使用。我们使用该芯片为两个编码器、运算放大器和一个单片机核心板供电,电路原理图如图所示:

▲ 图3.2:MIC29300-50WU稳压原理图

▲ 图3.2:MIC29300-50WU稳压原理图

??LD29150-50R是一种高电流、高精度、低压差稳压器,它具有400毫伏电压降和非常低的接地电流,最大负载电流可达1.5A,温度为25℃时公差在1%以内。我们选择该芯片为openart mini、串口以及打靶激光供电,电路图如图所示:

▲ 图3.3:LD29150-50R稳压原理图

▲ 图3.3:LD29150-50R稳压原理图

3.3V供电:

??对于液晶、摄像头、按键等外设需要3.3V供电。对于液晶以及按键,我们使用LD29150-33R将电源电压降至3.3V输出。LD29150-33R与LD29150-50R是同一系列芯片,参数以及特性不重复介绍。其原理图如下图所示:

▲ 图3.4:LD29150-33R稳压原理图

▲ 图3.4:LD29150-33R稳压原理图

??对于摄像头,我们采用Flexio通信。由于RT1064的时序问题,若摄像头先于单片机上电,则RT1064会时序紊乱导致无法初始化,在单片机最小系统中给出了专门的RC引脚,在单片机初始化后会拉高RC引脚的电平。所以我们采用RT9013-33GB单独为其供电。RT9013是一款高性能的500毫安LDO稳压器,其使能端高电平有效,所以该芯片可以作为低压继电器使用。其快速开启时间小于40μs,纹波抑制率高,既满足了摄像头对电压稳定性的严格要求,又解决了RT1064的上电时序问题。其原理图如下图所示:

▲ 图3.5:RT9013-33GB稳压原理图

▲ 图3.5:RT9013-33GB稳压原理图

5.89V供电:

??完成任务时我们需要三个舵机,其中一个转向舵机两个云台舵机,为保证转向舵机的正常使用以及反应速度,我们使用SY8205FCC电压可调稳压器将电源电压输出为5.89V。SY8205FCC是一个高效率快速响应的同步降压调节器,其最大负载电流可达5A,输入电压范围大,传导损耗小、转换效率高,且电压可调。其大电流和电压精确可调的特别非常适合伺服电机供电。其原理图如下图所示:

▲ 图3.6:SY8205FCC稳压原理图

▲ 图3.6:SY8205FCC稳压原理图

3.2.2主板外设部分设计

??主板外设部分设计主要由外设接口以及简单的开关电路组成,将外设接口引出方便外设与单片机系统进行连接。
??外设包括:编码器、摄像头、按键、液晶、蜂鸣器、打靶激光、TTL串口、无线串口、电磁采集接口等,其中特殊的接口有:摄像头接口采用Flexio通信方式、液晶屏采用IPS200液晶屏、七路电磁采集接口采用七路ADC接口、控制电机引脚采用四路PWM控制接口。为控制蜂鸣器以及打靶激光,我们采用一个I/O接口控制S8050导通,具体电路如下图所示:

▲ 图3.7:蜂鸣器以及激光控制原理图

▲ 图3.7:蜂鸣器以及激光控制原理图

3.2.3主板图片

??通过合理设计电路,在保证电路所有功能都可以实现的情况下尽量使电路板整洁美观,我们设计出如下电路图:

▲ 图3.8:主板实物图

▲ 图3.8:主板实物图

3.3驱动板设计

??驱动板的作用是可以用单片机发出的信号来控制两个380电机的转速,我们在编程时选择用PWM的占空比来控制电机转速,为达到此目的,我们选用经典半桥电路来控制电机;由于电机是由带保护板的锂电池直接供电,所以电源电压为7.4-8.4V,为满足半桥芯片以及其他电路的供电需求,驱动板中还应设有稳压模块;电机的转速与电流有着直接的关系,为了更加直接的控制电机旋转,我们需要实时采集流经电机的电流大小,因此才驱动板中加入了电流采集模块。

3.3.1驱动板供电设计

??除电机直接空锂电池供电外,电流采集模块以及隔离芯片需要3.3V供电,H桥驱动芯片需要12V供电,因此驱动板的供电设计应该包含这两个稳压模块。
??3.3V供电:

??本电路中的3.3V供电主要将锂电池的7.4-8.4V电压转化为稳定的3.3V电压。该模块主要为隔离芯片和电流环模块供电,所需电流不大,为了电路简洁我们选用AMS1117-3.3来进行供电。AMS1117-3.3是一款低压差三端稳压器,负载电流最大可以达到800mA,外部电路简单并且芯片稳定性好、电压精度高,满足设计要求。具体电路如下图所示:

▲ 图3.9:驱动板3.3V稳压电路

▲ 图3.9:驱动板3.3V稳压电路

12 V供电:

??由于半桥驱动中需要提供高于电源电压的电压来导通MOS来驱动电路,我们选择将电源电压稳定在12V,电压足以导通MOS的同时给半桥驱动芯片供电。我们选择MC34063作为稳压芯片。MC34063是一款直流-直流转换器,适用于升压、降压以及逆变开关电路,输出电压3-40V可调,满足设计要求。工作电路原理图如下图所示:

▲ 图3.10:驱动板12V升压电路

▲ 图3.10:驱动板12V升压电路

3.3.2 H桥

??H桥电路是使用四个MOS管来控制电机正传或反转的电路,连接电源正极和连接电源负极的两个MOS管同时导通时,电流则流经两个MOS管给电机通电。由于启动电机所需的瞬时电流可达到10A以上,所以我们需要选择大电流MOS管,本设计中MOS管选择IR7843,其封装容易焊接且允许通过电流大,满足设计要求。为了用单片机输出的信号控制MOS管的导通,我们选取了半桥驱动芯片IR2104s,通过控制给驱动芯片信号的占空比来平均通电时间从而控制平均电压来控制电机转速。半桥驱动电路的原理图如下所示:

▲ 图3.11:半桥驱动电路原理图

▲ 图3.11:半桥驱动电路原理图

3.3.3电流采集电路

??为了精准控制电机转速,我们采用电机电流闭环的方式控制电机。所以我们需要检测电流的大小并传输给单片机的AD采集口。在检测电流时我们采用INA282电流检测芯片。该芯片将通过采样电阻采集到的的电压信号放大50倍加在基准电压的二分之一上,可检测双向电流,该芯片输出电压范围在-14V-80V。由于单片机AD采集口的可检测最大值为3.3V,所以我们选择3.3V供电,基准电压为3.3V。电流采集模块原理图如下图所示:

▲ 图3.12:电流采集电路原理图

▲ 图3.12:电流采集电路原理图

3.3.4驱动板实物图

▲ 图3.13:驱动板实物图

▲ 图3.13:驱动板实物图

3.4分电板设计

??设计分电板的目的是为了为航模锂电池加保护板并使航模锂电池可以通过开关控制分别为主板和驱动板供电。分电板上主要包括锂电池保护板、电池输入接口、电压检测接口、主板供电开关、主板供电接口、驱动板供电开关、驱动板供电接口。分电板原理图、实物图如图所示:

▲ 图3.14:分电板电路原理图

▲ 图3.14:分电板电路原理图

▲ 图3.15:分电板实物图

▲ 图3.15:分电板实物图

3.5运算放大器电路设计

??赛道中提供20KHz的交流电信号,我们采用电感电容对信号进行采集后,经过检波和放大到合适单片机AD采集的电压信号。运算放大器芯片我们采用OPA4377,该芯片是一款高频低噪声的运算放大器芯片,该芯片工作电压为2.2-5.5V,一片有四路轨对轨输出的运算放大器,外部电路简洁体积小,满足设计要求。设计电路时在每一个输出口都加入滤波电路使得运算放大器输出更加稳定,并加入二极管防止电流倒灌。四路运算放大器的电路原理图、运算放大器电路实物图如下图所示:

▲ 图3.16:运算放大器电路原理图

▲ 图3.16:运算放大器电路原理图

▲ 图3.17:运算放大器实物图

▲ 图3.17:运算放大器实物图

3.6按键板设计

??按键板是独立于其他电路板的按键模块,包括五个按键电路,方便调试小车,按键板的实物图如图所示:

▲ 图3.18:按键板实物图

▲ 图3.18:按键板实物图

3.7电磁杆设计

??电磁杆电路中包括七路方向和位置不同的电感以及软排线信号接口,电磁板实物图如下图所示:

▲ 图3.19:按键板实物图

▲ 图3.19:按键板实物图

3.8整体电路拼版效果

▲ 图3.20:整体电路拼版效果

▲ 图3.20:整体电路拼版效果

?

第四章 能识别算法说明及云台动作逻辑


??在本届智能车比赛的智能视觉组别中,小车除了基础的寻迹任务之外,还需要完成一些智能识别的任务。这些任务也是本小车的核心任务。对于小车需要完成的智能识别任务,我们将其分为三个部分:

  • 对数字牌的识别:选定岔路行进方向。
  • 对赛道Apriltag的识别:判定标靶方向。
  • 对动植物的识别:根据标靶图案不同做出相应的动作。

4.1对数字牌的识别

4.1.1寻找识别目标

??关于数字标靶的寻找,逐飞的例程是基于QVGA分辨率下使用find_rects()函数找矩形。

▲ 图 4.1数字标靶

▲ 图 4.1数字标靶

??使用此法在近距离可以快速精准的找到标靶,如下图所示:

▲ 图 4.2 直接使用例程法寻找标靶

▲ 图 4.2 直接使用例程法寻找标靶

??但是此标靶搜寻方法存在一些问题,比如对停车位置要求比较严格,在赛道三岔路上必须距离标靶比较近才能识别到,如果距离较远不易找到标靶。这个问题在降低查找阈值后效果有所提升,但容易误识别。

▲ 图 4.3距离较远时找框困难

▲ 图 4.3距离较远时找框困难

??上文提到,Open ART mini最高只支持320×240(QVGA)的画质。其在640×480分辨率下内存溢出、画面撕裂严重。

??Openmv IDE中有sensor.set_windowing()函数可将相机的分辨率设置为当前分辨率的子分辨率。此函数对Open ART mini的QVGA画质和QQVGA分辨率无效,但是对VGA分辨率有效。故识别数字时可以切换成VGA画质,并进行画面裁剪,只选取画面其中一部分进行识别,进而缓解内存溢出的现象。

??经过尝试,我们在保证画面尽可能大的前提下,发现将子分辨率设置为400×220时,画面撕裂感明显减少。下图为和图4.3相同位置下Open ART mini的视野情况。

▲ 图 4.4 切换画质后更易识别到标靶

▲ 图 4.4 切换画质后更易识别到标靶

??另外,可从长宽比,边的长度等角度对识别到的矩形进行限制,减少误识别现象的发生。

??find_rects()函数内部较为复杂,查找矩形时帧率较低,那么有没有一个好方法可以加快帧率呢?

??省赛要求数字牌和动植物牌周围框的颜色已确定为紫色,RGB值为(68, 0, 98)。故可以查找框的颜色,把标靶框出来并对内部调用神经网络进行分类。

??Openmv IDE中有find_blobs()函数,用于查找图像中所有色块,并返回一个包括每个色块的色块对象的列表。而且循环运行find_blobs()函数时的帧率明显高于循环运行find_rects()函数的帧率。

??Openmv IDE中具有颜色阈值编辑器,可以拖动滑块在LAB色域上选取合适的范围。

▲ 图 4.5 Openmv IDE中颜色阈值编辑器

▲ 图 4.5 Openmv IDE中颜色阈值编辑器

??查找颜色方法可以比矩形更快地识别出结果。而且可识别更远的距离。但是稳定性较差。如果Openmv ART mini偏色,则无法识别。

4.1.2数字目标的识别

??逐飞的例程中数据集较少,我们需要制作自己的数据集。数字图片内容比较固定,可以使用python在电子版图片的基础上旋转等数据增强方法扩大数据集,也可以通过不同角度不同亮度下实拍来扩大数据集。

??该卷积神经网络结构简单,含有三个卷积层,三个池化层构成。卷积神经网络结构如下图所示:

▲ 图 4.6 数字神经网络结构

▲ 图 4.6 数字神经网络结构

4.2对赛道二维码的识别

??AprilTag的识别,可在Openmv IDE中使用image.find_apriltags()函数来直接寻找。对画质有限看的比较近的Open ART mini来说很难有提升的空间,但是可以通过一些方式增加识别的成功率,降低误判率。

▲ 图 4.7 Open ART mini识别ApirlTag

▲ 图 4.7 Open ART mini识别ApirlTag

??我们最初计划在智能车在运动过程中一直开启AprilTag识别,识别到AprilTag后通信给主板主板立即刹车。但是Open ART mini在执行image.find_apriltags()函数时帧率较低,只有20几帧(这是Openmv IDE中运行显示的帧率,脱机后会翻倍)车速较低时还能识别到,速度高了可能导致图像模糊进而无法识别。

??我们尝试改变快门速度或曝光时间。Openmv ART mini不支持修改快门速度。而Openmv IDE中有修改曝光时间的函数sensor.set_auto_exposure(),但是该函数对Openmv ART mini无效(我们怀疑可能逐飞当时移植时存在少许问题)。故只能改变方案采用总钻风识别AprilTag刹车后Open ART mini开启识别的方案。

总钻风如何识别AprilTag:

??经过测试,我们发现Openmv ART mini对AprilTag误识别现象较为严重。当其看到复杂背景时很容易发生误识别。关于降低误判率,我们做了以下几点:

??AprilTag的识别由主板控制开启:平时智能车跑动时不开启AprilTag识别,当总钻风看到AprilTag后向Open ART mini通信开启AprilTag识别。识别完成后Open ART mini关闭AprilTag识别。从而避免了智能车正常行驶时的AprilTag误识别现象。

??AprilTag的数字ID限制:省赛规定了AprilTag的数字ID值的范围是09,可以选择只识别这个范围内的AprilTag。此方法可以有效排除数字ID值1034范围内的AprilTag误识别现象。

??角度限制:apriltag.x_rotation()、apriltag.y_rotation()、apriltag.z_rotation()分别返回以弧度计的AprilTag在X、Y、Z平面上的旋度,可通过下列公式转化为角度。

??然后可以根据Openmv ART mini在智能车上的位置设置合适的角度限制,通过此法可以消除绝大多数误识别现象。

??降低亮度:比赛使用逐飞科技提供的的AprilTag,该材质反光严重,识别时降低亮度可有效提升识别率。

▲ 图 4.8 低亮度下反光情况 图 4.9 正常亮度下反光情况

▲ 图 4.8 低亮度下反光情况 图 4.9 正常亮度下反光情况

4.3对动植物的识别

4.3.1寻找识别目标

??识别动植物标靶的方法与识别数字时类似,可分为find_rects()和find_blobs()两种方法。

??find_rects()函数效果如下:

▲ 图4.10找矩形识别动植物

▲ 图4.10找矩形识别动植物

??find_rects()函数仅对背景为纯白色的图片有效,如图片为复杂背景,则无法识别。

??find_blobs()函数效果如下:

▲ 图 4.11 找颜色识别动植物

▲ 图 4.11 找颜色识别动植物

??find_blobs()函数对所有图片均可以识别

4.3.2 对动植物目标的识别

??动植物数据集已经确定,包含五类动物五类植物,每类约90张。

▲ 图 4.12 部分动植物数据集

▲ 图 4.12 部分动植物数据集

??关于动植物标靶的识别,逐飞的例程是使用nncu工具量化模型,在Openmv IDE中基于QVGA画质下使用find_rects()函数找矩形,然后对矩形内部的图像用神经网络进行预测。
??解决问题的关键在于训练一个过拟合的神经网络,以确保在训练集上的识别成功率。为此我们在已有的图片基础上使用数据增强获得了大量图片以用作数据集。数据增强包括旋转、调整亮度对比度、改变RGB值、增加(高斯)模糊等方法。

▲ 图 4.13 原图

▲ 图 4.13 原图

▲ 图 4.14数字增强后的图片(部分)

▲ 图 4.14数字增强后的图片(部分)

??使用此法能很容易训练出一个成功率几乎100%的神经网络。

4.3.3水果——摘取水果

??规则要求若识别到植物时需要进行打靶操作,打靶有两种方案,分别是闭环打靶和开环打靶。

闭环打靶

▲ 图 4.15闭环打靶示意图

▲ 图 4.15闭环打靶示意图

??已知标靶中心为Cx,与openmv中心水平间距为(Cx-160),可将此误差代入增量式PID中构建打靶闭环控制云台下舵机转动。直至误差近似为0(即Cx与160大致重合)。

??该方法较为准确,但有一些缺陷,一是闭环校正过程用时较长,二是虽然Openmv正对靶心时激光可能无法正射中靶心,需要设置补偿值。

开环打靶

??由于二维云台中配备了激光雷达,可以利用激光雷达进行辅助打靶。该方法相较于闭环打靶而言速度明显提升
??以标靶在赛道右边为例,用激光从右前扫至右后,寻找两个跳变点,可用下列公式求出靶的中心。

??补偿值通常为一固定值,取决于扫描快慢。

4.3.4动物——停车避让

??规则要求识别到动物后需要停车三秒,可用定时器来实现这一功能。

4.4单独识别策略(国赛策略)

??国赛将车模的运行功能与任务识别功能分别进行考察,分别进行积分。车模需要在两分钟的时间内尽可能多的识别数字、tag、动物、植物,并做出对应的动作。每做对一个动作得5分,做错动作需要在不得分的基础上再扣5分。其中识别过程中也有白框干扰,需要将其排除。

??为了尽可能快的识别,我们采用了QQVGA分辨率(160×120)。保持openmv art mini的高帧率。

??国赛任务与省赛任务最大的不同在于,省赛时明确了何时开启何种分类,而国赛是完全随机。如果使用识别动植物的神经网络来识别数字肯定会发生错误。

??要想完成识别任务,一种最简单的思路是训练一个多分类器,这是我们的第一套方案,流程图如下图所示:

![▲ ]](https://img-blog.csdnimg.cn/8f6f4e08d8b14905860f95627203795f.png#pic_center =560x)

▲ ]

??该方案的优点在于完成所有分类任务的平均用时最短:tag的识别没有经过网络可以快速地判断出来,其余结果也只需经过一次神经网络。缺点在于分类器的误判现象较多,可以通过调节卷积神经网络结构来提高分类器的识别正确率。如增加卷积网络层数,增加dropout层来降低网络大小。

??另一种思路是将上述的多分类器进行拆分两个小的多分类器,对比数字和动植物而言,数字种类显然更少。我们的第二套方案是采用了全局数字分类器和动植物白框三分类器,流程图如下图所示:

▲

▲ ]

??全局数字分类器的输入时openart mini拍取的第一帧图片截取的160×80区域,如下图红色方框内的区域:

??因为不需要找框,第一步运行时间明显缩短。神经网络可直接对这一区域进行识别,输出为0~9和非数字。
??方案二相对于方案一而言,看似多了一个网络,动植物识别速度有所减慢,tag识别速度几乎不变,但数字识别速度明显加快,且识别准确率明显上升,代价可以接受。
??识别效果如下图所示:

4.19识别效果图组



?

第五章 于嵌入式的巡线算法


??随着赛道元素越来越复杂,传统的 CCD 已经难以满足比赛需求,我们选择采用逐飞科技设计的 MT9V034 总钻风灰度摄像头,该摄像头具有全局快门及软件二值化的特性,相比于硬件二值化的黑白摄像头,通过优化算法可以提升图像获取速度,同时可利用数据也更加丰富。

5.1程序运行流程

??使用C语言[3]结合嵌入式系统的特点编写程序,程序运行流程如下图所示。

▲ 图5.1 程序整体运行流程

▲ 图5.1 程序整体运行流程

5.2图像采集与应用

5.2.1图像的失真与校正

??由于 CMOS 图像传感器针对赛道平面所采集到的图像是一幅符合透视原理的梯形图像,图像会产生桶形失真(如图5.2),这使得摄像头看到的信息与真实赛道信息有所差异,我们在尝试了逆透视算法后依据效果决定直接采用原始图像,按照控制变量的系统调试思想,我们决定固定偏差获取方法,优化系统控制方案。

▲ 图5.2 二值化图像

▲ 图5.2 二值化图像

5.2.2图像二值化方案的优化

??摄像头直接获取到的是灰度图像,也即每个像素点的取值范围在[0,255],直接利用该信息具有一定的处理难度,也会延长程序的调试周期,因此我们决定先使用大津法对图像进行二值化,再对二值图像做后续处理。经过算法时间复杂度优化,在光线均匀时获取一副二值化图像的时间在0.4 ms以内。为了应对光线条件不理想的情况(反光、阳光直射、光线不充足等),我们对阈值进行了动态分割,实际应用发现能解决一定程度上的光线问题。

5.2.3赛道原始边界的获取

??考虑到当车体位于赛道内时图像相对单调,综合各算法的复杂程度与应用范围,我们决定采用简单的边缘追踪算法——八邻域边缘追踪算法。具体算法执行流程如下。
??(1)获取图像的有效底和有效顶,两者之间的区域为有效图像;
??(2)根据近处信息更可靠的原则,优先在有效底找起始边界,并从此边界开始运行八邻域算法获取左右轮廓;
??(3)在找到轮廓的同时利用轮廓信息并行判断该行边界;
??(4)轮廓搜到有效顶时即停止搜寻;
??(5)利用灰度信息对边界坐标进行校正。

5.2.4赛道边界的修正及中线的获取

??原始边界只是固定算法运行得到的信息,当赛道变得相对复杂(十字、环岛、车库前)时,原始的边线没法满足使用要求,据此我们设计了赛道边界的修正方案。
??但在获得原始边界后,我们可以提取出原始边界的部分信息:拐点、边线连续性、边线直线判断等,可用于赛道边界的修正及中线的获取。

??(1)十字补线:关于十字元素,我们将其分为三个状态,远距离十字状态,十字前,十字内。
??远距离十字状态(如图5.3):当车模距离十字元素较远时(以左转入十字为例),仅能查询到右侧单端拐点,此时结合左侧丢线条件。即可判定为远距离十字状态,此时利用右侧拐点附近边线斜率即可完成补线。

▲ 图5.3 远距离十字状态图像

▲ 图5.3 远距离十字状态图像

??十字前(如图5.4):当车模距离十字元素较近,但仍处于十字外时,我们可以查询到左右两侧边线的上下拐点,利用上下拐点附近的边线斜率即可完成补线。

▲ 图5.4 十字前图像

▲ 图5.4 十字前图像

??十字内(如图5.5):当车模处于十字元素中时,我们仅能查询到左右两侧边线的上下拐点,利用上拐点附近的边线斜率即可完成补线。

▲ 图5.5 十字内图像

▲ 图5.5 十字内图像

??(2)第一次斑马线补线(如图5.6):当斑马线跳变条件通过时,若此时查询到单侧拐点,且另一侧边线连续,斑马线计次为0,则说明此时第一次经过车库,利用赛道连续边线与赛道半宽的方式,补出赛道中线,即可不受车库干扰,开启第二圈的运行。

▲ 图5.6 斑马线补线图像

▲ 图5.6 斑马线补线图像

??(3)环岛入环前补线(如图5.7):车模途径环岛前时,需对中线进行操作,若查询到单侧拐点且另一侧边线连续时,直接利用赛道连续边线与赛道半宽,补出赛道中线,可避免入环前的环岛干扰。

▲ 图5.7 入环前补线图像

▲ 图5.7 入环前补线图像

??(4)弯道中线补线(如图5.8):由于采用了140*70的图像宽度与高度,并将摄像头架设至30cm高进行循迹,若单纯的由左右边线获取中线,获取的中线会出现断裂的现象,不利于车模循迹,我们利用当前赛道的曲率与宽度进行计算出弯道实际宽度,并利用完整单侧边线与赛道半宽补出弯道实际中线。

▲ 图5.8 弯道补线图像

▲ 图5.8 弯道补线图像

5.3赛道类型识别与处理

??根据提取到的赛道中线,可将赛道分为以下几个元素,并根据赛道元素进行相应的控制。

5.3.1直道的识别及处理

??直道的左右边界对称度高,有效边线信息多。对于赛道中的直道,车速应该相对更高,且直道是方向控制中最好处理的一种情况,因为只要小车没有偏离赛道,就可以不进行偏转,而当智能车偏离赛道时也只需要一个较小的偏转,让智能车能缓慢回归赛道就可以。

5.3.2普通弯道的识别及处理

??弯道会有一侧丢失信息,另一侧呈现边界斜率递增的情况。遇到弯道时,转向角只受弯道的弯曲程度影响,但是距离弯道多远就开始转弯却需要受到当前速度的影响,而且速度越快,越是要提前得多,所以智能车转弯提前多少(也即偏差计算行)就由速度控制。同时弯道内部的速度给定与弯道曲率有最直接的关系,识别为弯道时,我们依据曲率给定基础速度,依据E和EC给定速度变化量。弯道图像如图5.9所示。

▲ 图5.9 弯道图像

▲ 图5.9 弯道图像

5.3.3环岛的识别及处理

??环岛的特征比较明显,一侧为直道,一侧有圆形区域。但是由于在完全进入环岛弯之前图像始终包含直道、弯道双重信息,所以必须在识别为环岛后重新找有效底、有效顶、左右边线,同时对弯道的缺损区域进行补线以实现中线的合理运算,由于环岛补线与实际弯道外侧线有一定差异,所以环岛单独给定所有的控制参量。环岛补线如图5.10所示。

▲ 图5.10 环岛补线

▲ 图5.10 环岛补线

5.3.4坡道的识别及处理

??坡道图像相比直道有一段斜率转折区,根据此信息和测距传感器返回值进行坡道判断。我们在坡道将前瞻拉近,并将控制系统做相应改变。坡前图像如图5.11所示。

▲ 图5.11 坡前图像

▲ 图5.11 坡前图像

5.3.5岔路的识别及处理

??岔路的特征比较明显,图像两端均有赛道出现,且中间出现一个黑色菱形,据此特征即可判定当前赛道元素为岔路,由于智能视觉组任务要求,我们在识别出岔路元素后立刻停车,并利用串口向openmv art mini发送标志位,开启数字识别,待收到openmv art mini识别到相关内容后返回的标志位后,选择正确支路前进即可。关于进入岔路的方式,我们采取应进入支路边线+赛道半宽=新中线的方式将车模引导进入岔路。岔路前图像如图5.12所示。

▲ 图5.12 岔路前图像

▲ 图5.12 岔路前图像

5.3.6 April_Tag的识别及处理

??April_Tag的特征比较明显,在正常的赛道区间内,出现了黑白跳变,为了防止出现与斑马线之间相互误判的情况。我们查询了横向跳变与纵向跳变,最终确定了April_Tag的存在。由于智能视觉组任务要求,我们在识别出April_Tag元素后立刻停车,并利用串口向openmv art mini发送标志位,开启April_Tag识别,待收到openmv art mini识别到相关内容后返回的标志位后,控制云台舵机转向,进而识别水果与动物。April_Tag图像如图5.13所示。

▲ 图5.13 April_Tag图像

▲ 图5.13 April_Tag图像

5.3.7 车库的识别及处理

??车库的特征比较明显,当赛道中间出现多个横向黑白跳变,且一侧边线丢失,即可判定为车库元素,在第一次经过车库时,采取中线补线的方式,使车模得以直行,在第二次经过车库时(以右端车库为例),利用如图所示三点拟合二次曲线补线进入车库。入库图像如图5.14所示

▲ 图5.14 入库图像

▲ 图5.14 入库图像

5.4电磁巡线算法

??在今年的比赛中为了避免光线或图像出现异常进入失控状态,基于电磁线的铺设,我们在大津法阈值满足一定条件时采取切换至电磁巡线。本车电磁巡线算法采用七个电感基于差比积差比和相结合拟合的偏差曲线,同时辅以模糊PD控制器,获得了良好的控制效果。在一些电磁信息极具特征的区域(如十字、环岛),图像信息与电磁信息结合,可以增强赛道识别系统的鲁棒性。

5.5 控制方案选择

??我们使用位置式 PD 算法控制舵机打脚,使用ADRC 算法控制电机稳定在目标速度。

??在工程实际中,应用最为广泛的调节器控制规律为比例、积分、微分控制,简称PID控制,又称PID调节。PID控制器问世至今已有近70年历史,它以其 结构简单、稳定性好、工作可靠、调整方便而成为工业控制的主要技术之一。当被控对象的结构和参数不能完全掌握,或得不到精确的数学模型时,控制理论的其它技术难以采用时,系统控制器的结构和参数必须依靠经验和现场调试来确定,这时应用PID控制技术最为方便。即当我们不完全了解一个系统和被控对象,或不能通过有效的测量手段来获得系统参数时,最适合用PID控制技术。PID控制,实际中也有PI和PD控制。
??PID控制器是一种线性控制器,它根据给定值与实际输出值构成控制偏差。将偏差的比例§、积分(I)和微分(D)通过线性组合构成控制量,对被控对象进行控制,故称PID控制器,原理框图如图5.15所示。

【通用原理部分,此处省略3000字...】

?

第六章 发工具


6.1RT1064开发工具

6.1.1开发环境以及安装调试过程

??在对程序进行开发和软硬件联调的过程中需要一整套的软件开发与调试工具。程序的开发是在 IAR Embedded Workbench 下进行的,包括源程序的编写、编译和链接,并最终生成可执行文件。包括集成开发环境 IDE、处理器专家库、全芯片显示工具、项目工程管理器、C 交叉编译器、汇编器、链接器以及调试器。使用 DAPLink V2.5 来下载程序,把编译好的程序下载到单片机里运行。如图6.1.

▲ 图6.1 IAR界面

▲ 图6.1 IAR界面

??Embedded Workbench for ARM的安装步骤参照如下列图组所示:

6.1.2上位机

??采用山外的上位机软件获取图像,使用山外的虚拟示波器获取当前电机闭环参数,通过不断调整参数和调试波形,我们得到了适合的当前小车的 ADRC 参数,让电机响应快而且速度稳定。如图6.3所示。

▲ 图6.3调试工具界面

▲ 图6.3调试工具界面

6.2openart mini开发工具

6.2.1开发环境——pycharm安装以及调试

??PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业Web开发。主要界面如下图

▲ 图6.4 pycharm界面

▲ 图6.4 pycharm界面

??由于深度学习方面的知识主要采用Python作为主要编程语言,故我们选择了PyCharm作为编译器,进行程序的调试。一个好的环境对于深度学习十分重要,在编写程序之前,我们首先为python配置好环境,按照逐飞推荐的NumPy,TensorFlow以及Keras的版本,利用pip下载安装。

??PyCharm安装步骤见下面①②③④⑤⑥图组。

6.2.2开发环境——Openmv IDE安装以及调试

??OpenMV IDE是用来编程OpenMV Cam的工具。它具有一个由QtCreator支持的功能强大的文本编辑器, 一个帧缓冲器查看器,直方图显示器,以及一个用于OpenMV调试输出的集成串行终端。界面如下图所示:

▲ 图6.6Openmv IDE界面

▲ 图6.6Openmv IDE界面

??在OpenMV IDE的文件菜单下,我们可以使用所有的标准文本编辑器选项。新建,打开,保存,另存为,打印等。完成编辑代码并准备运行脚本后,只需单击OpenMV IDE左下角的绿色运行按钮即可。该脚本将被发送到您的OpenMV编译成Python字节码,并由OpenMV执行。

6.2.3开发环境——nncu安装以及调试

▲ 图6.7 nncu调试界面

▲ 图6.7 nncu调试界面

??NNCU (NN toolkit for MCU)提供了全套的工具,该软件解压后便可使用,无需安装。我们可以方便地在 NXP RT1064上运行神经网络。NNCU 有以下主要功能:
??? 支持 Keras 模型和初步支持 ONNX 模型
??? 充分发挥 CMSIS-NN 的潜力(是未优化代码的 5 倍性能) ? 高质量的量化,带有完整测试系统
??? 包含对 CMSIS-NN 的扩展以支持更复杂的模型和辅助量化
??? 简易的 GUI
??? 大量示例(目前有 10余个) ? 分类,回归,阴阳检测,异常检测,人脸验证

??NNCU 提供以下工具:模型分析、量化与转换工具
??? 测试向量制作工具
??? GUI 界面
??? 附带示例与迷你数据集
??? 量化质量测试工具
??? 转换后模型解释器
??? MCU 测试工程与更新工具

?

第七章 型车主要技术参数说明


  • 模型车基本参数 长 300mm

  • 宽 180mm

  • 高 340mm

  • 车重 1323g

  • 带载 大于12W

  • 传感器 电感 7个

  • Openart mini 1个

  • TFmini激光测距 1个

  • 总钻风摄像头 1个

  • 编码器 2个

  • 除了车模原有的驱动电机、舵机之外伺服电机个数 0

  • 赛道信息检测 检测精度 1.65cm

  • 检测频率 200Hz

?

论与感悟


??在此份技术报告中,我们主要介绍了准备比赛时的基本思路,包括机械、电路、控制算法的创新思想。在机械结构方面,我们分析了舵机转向系统的改进办法,对前轮倾角进行一系列的改动。在电路方面,我们以模块形式分类,在最小系统、主板、电机驱动、电池使用、电磁采集等模块分别设计,经过不断实验,最后决定了最终的电路图。在循迹程序方面,我们使用C语言编程,利用开发工具调试程序,经过小组成员不断讨论、改进,终于设计出一套比较通用稳定的程序。在这套算法中,我们结合路况调整车速,做到直道加速、弯道减速,保证在最短时间内跑完全程。

??智能视觉组部分因为没有往届的经验作参考,早期我们自己研究过Tensorflow Lite训练并量化模型、Caffe深度学习框架。中期采用Openmvart mini,按照逐飞的例程采用了nncu工具可以训练出分类效果不错的模型,对比了nncu模型和tflite模型的优缺点。之后学习了上海交通大学Autop的开源程序,这对于缺乏学习资料的我们来说是一笔宝贵的财富。我们国赛数字识别策略也采用的全局分类器,取得了相当不错效果。

?


??在备战过程中,我们遇到了很多挫折,一次次的校内赛见证了我们这个小队艰难的蜕变。非常感谢山威智能车队这个像家一样的地方,更要感谢一直支持和关注智能车比赛的学校和学院领导以及各位指导老师、指导学长。感谢比赛组委会能组织这样一项有意义,堪称工科生盛会的比赛,即使面对如此大的疫情压力,依然保证了比赛的顺利进行。也感谢哈尔滨工程大学志愿者与老师们为本次比赛的付出,没有你们的辛勤付出,本届国赛也无法顺利的举办。

??在备战过程中,我们也遇到了许多可以共同进步的车友,感谢安徽大学安大一队的一路陪伴与技术分享,感谢哈尔滨工业大学紫丁香七队的思路分享,感谢上海交通大学Autop战队的无私开源,也感谢所有帮助过我们的车友,希望我们都能有一个美好的未来,也祝智能车竞赛能够越办越好!

?

考文献


[1].https://zhuanlan.zhihu.com/p/391252945第16届智能车智能视觉组-上海交通大学AuTop战队开源汇总[2] 王淑娟,蔡惟铮,齐明.模拟电子技术基础 [M].北京:高等教育出版社.2009
[2]孙同景,陈桂友 Freescale 9S12 十六位单片机原理及嵌入式开发技术,
??北京-机械工业出版社,2008
[3]卓晴,黄开胜,邵贝贝 学做智能车 北京-北京航空航天大学出版社,2007
[4]李宁,刘启新 电机自动控制系统 北京-机械工业出版社,2003
[5]赵先奎 汽车前轮定位 黑龙江 黑龙江出入境检验检疫局,2008
[6]邱锡鹏 神经网络与深度学习 北京:机械工业出版社 2020.3

	void midline_remedy()
	{
	  float real_width,wan_angle;
	
	  wan_buxian=0;
	  if(curve_flag_right==1)
	  {
	    wan_buxian=1;
	    for(int i=CAMERA_H-1;i>0;i--)
	    {
	      if(i>=5&&i<CAMERA_H-6)
	      {
	        uint8 j=5;
	        for(;j>1;j--)
	        {
	          if(left_black[i-j+1]<138 && left_black[i-j+1]-left_black[i-j+2]>=0)
	            break;
	        }
	        wan_angle=(MAX(30,atan(((float)(left_black[i-j]-left_black[i+5])/(5+j))/2+((float)(left_black[i-j+1]-left_black[i+4])/(3+j))/2)*180/3.1416)-30)*90/60;
	      }
	      else if(i<5)
	        wan_angle=(MAX(30,atan((float)(left_black[2]-left_black[7])/5)*180/3.1416)-30)*90/60;
	      else
	        wan_angle=(MAX(30,atan((float)(left_black[CAMERA_H-6]-left_black[CAMERA_H-1])/5)*180/3.1416)-30)*90/60;
	
	      real_width=Track_width[i]/cos(wan_angle*3.1416/180);
	      middle_line[i]=MAX(0,MIN(left_black[i]+(int)((real_width)/2),CAMERA_W-1));
	    }
	  }
	
	  if(curve_flag_left==1)
	  {
	    wan_buxian=1;
	    for(int i=CAMERA_H-1;i>0;i--)
	    {
	      if(i>=5&&i<CAMERA_H-6)
	      {
	        uint8 j=5;
	        for(;j>1;j--)
	        {
	          if(right_black[i-j+1]>0 && right_black[i-j+1] -right_black[i-j+2]<=0)
	            break;
	        }
	        wan_angle=(MAX(30,atan(((float)(right_black[i+5]-right_black[i-j])/(5+j))/2+((float)(right_black[i+4]-right_black[i-j+1])/(3+j))/2)*180/3.1416)-30)*90/60;
	      }
	      else if(i<5)
	        wan_angle=(MAX(30,atan((float)(right_black[7]-right_black[2])/5)*180/3.1416)-30)*90/60;
	      else
	        wan_angle=(MAX(30,atan((float)(right_black[CAMERA_H-1]-right_black[CAMERA_H-6])/5)*180/3.1416)-30)*90/60;
	
	      real_width=Track_width[i]/cos(wan_angle*3.1416/180);
	      middle_line[i]=MAX(0,MIN(right_black[i]-(int)((real_width)/2),CAMERA_W-1));
	    }
	  }
	}
拐点查询函数源代码:
	void Get_growth_direction_cross()
	{
	  Advance_cross_flag=0;
	  
	  left_turn_down_new_cross[0]=0;
	  left_turn_down_new_cross[1]=0;
	  right_turn_down_new_cross[0]=0;
	  right_turn_down_new_cross[1]=0;
	  left_turn_up_new_cross[0]=0;
	  left_turn_up_new_cross[1]=0;
	  right_turn_up_new_cross[0]=0;
	  right_turn_up_new_cross[1]=0;
	  
	  find_left_turn_down_cross=0;
	  find_left_turn_up_cross=0;
	  find_right_turn_down_cross=0;
	  find_right_turn_up_cross=0;
	  ll_lost=rr_lost=0;
	  
	  
	  for(int ii=0;ii<l_end;ii++)
	  {
	    if((left_site[ii+2].y<left_site[ii].y)&&(left_site[ii+4].y<left_site[ii+2].y)&&(left_site[ii+6].x<left_site[ii+4].x)&&(left_site[ii+8].x<left_site[ii+6].x)
	       &&img[left_site[ii+4].y-4][left_site[ii+4].x-4]==white&&img[left_site[ii+4].y-3][left_site[ii+4].x-3]==white&&img[left_site[ii+4].y-2][left_site[ii+4].x-2]==white
	         &&left_site[ii+4].y>15&&left_site[ii+4].y<65&&left_site[ii+4].x<MT9V03X_W/2+40)
	    {
	      left_turn_down_new_cross[0]=left_site[ii+4].y;//锁定拐点的行列坐标
	      left_turn_down_new_cross[1]=left_site[ii+4].x;
	      break;
	    }
	  }
	  
	  for(int ii=l_start;ii<l_end;ii++)
	  {
	    if((left_site[ii+2].x>left_site[ii].x)&&(left_site[ii+4].x>left_site[ii+2].x)
	       &&(left_site[ii+6].y<left_site[ii+4].y&&left_site[ii+6].x-left_site[ii+4].x>=1)
	         &&(left_site[ii+8].y<left_site[ii+6].y&&left_site[ii+8].x-left_site[ii+6].x>=1))
	    {
	      left_turn_up_new_cross[0] =left_site[ii+4].y;//锁定拐点的行列坐标
	      left_turn_up_new_cross[1]=left_site[ii+4].x;
	      break;
	    }
	  }
	  
	  
	  for(int ii=0;ii<r_end;ii++)
	  {
	    if((right_site[ii+2].y<right_site[ii].y)&&(right_site[ii+4].y<right_site[ii+2].y)&&(right_site[ii+6].x>right_site[ii+4].x)&&(right_site[ii+8].x>right_site[ii+6].x)
	       &&img[right_site[ii+4].y-4][right_site[ii+4].x+4]==white&&img[right_site[ii+4].y-3][right_site[ii+4].x+3]==white&&img[right_site[ii+4].y-2][right_site[ii+4].x+2]==white
	         &&right_site[ii+4].y>15&&right_site[ii+4].y<65&&right_site[ii+4].x>MT9V03X_W/2-40)
	    {
	      right_turn_down_new_cross[0]=right_site[ii+4].y;//锁定拐点的行列坐标
	      right_turn_down_new_cross[1]=right_site[ii+4].x;
	      break;
	    }
	  }
	  
	  for(int ii=r_start;ii<r_end;ii++)
	  {
	    if((right_site[ii+2].x<right_site[ii].x)&&(right_site[ii+4].x<right_site[ii+2].x)
	       &&(right_site[ii+6].y<right_site[ii+4].y&&right_site[ii+6].x-right_site[ii+4].x<=-1)
	         &&(right_site[ii+8].y<right_site[ii+6].y&&right_site[ii+8].x-right_site[ii+6].x<=-1))
	    {
	      right_turn_up_new_cross[0]=right_site[ii+4].y;//锁定拐点的行列坐标
	      right_turn_up_new_cross[1]=right_site[ii+4].x;
	      break;
	    }
	  }
	  
	
	  if(left_turn_down_new_cross[0]!=0)
	  {
	    find_left_turn_down_cross=1;
	  }
	  if(right_turn_down_new_cross[0]!=0)
	  {
	    find_right_turn_down_cross=1;
	  }
	  if(left_turn_up_new_cross[0]!=0)
	  {
	    find_left_turn_up_cross=1;
	  }
	  if(right_turn_up_new_cross[0]!=0)
	  {
	    find_right_turn_up_cross=1;
	  }
	  //增加一个十字触发条件(超远或状态较差,冲弯状态差)
	  if(find_left_turn_down_cross==1&&find_right_turn_down_cross==0)//若仅有一端存在拐点(该情况常触发,但另一端丢线的情况仅会存在于十字)
	  {
	    for(int k=left_turn_down_new_cross[0]-5;k<left_turn_down_new_cross[0]+4;k++)      
	    {
	      if(right_black[k]>=MT9V03X_W-6)
	      {
	        rr_lost++;
	      }
	    }
	    if(rr_lost>=5)
	      Advance_cross_flag=1;
	  }
	  
	  if(find_left_turn_down_cross==0&&find_right_turn_down_cross==1)//若仅有一端存在拐点(该情况常触发,但另一端丢线的情况仅会存在于十字)
	  {
	    for(int k=right_turn_down_new_cross[0]-5;k<right_turn_down_new_cross[0]+4;k++)     
	    {
	      if(left_black[k]<=5)
	      {
	        ll_lost++;
	      }
	      
	    }
	    if(ll_lost>=5)
	      Advance_cross_flag=1;
	  }
	  if(find_left_turn_down_cross==1&&find_right_turn_down_cross==1)//两端均存在拐点时直接触发十字允许标志
	  {
	    Advance_cross_flag=1;
	  }
	}
ADRC源代码:
	#include "ADRC.h"
	#include "my_headfiles.h"
	#include "common.h"
	Fhan_Data ADRC_Left_Controller;
	Fhan_Data ADRC_Right_Controller;
	const float ADRC_Unit[3][15]=
	{               
	  {10 ,0.1,  1,                16,       37,      0.5,     0.01,    0.001 ,   1.6,      0.018,    5,    5,    0.8,   1.5,    20},
	  {10 ,0.1 , 1,                16,       37,      0.5,     0.01,    0.001 ,   1.6,      0.018,    5,    5,    0.8,   1.5,    20},
	  {50000  ,0.01 , 30,              100,       2000,       10000,      5    ,    0.002,   10,        0.001,    5,    5,    0.5,   1.05,   50},
	};
	
	float Constrain_Float(float amt, float low, float high){
	  return ((amt)<(low)?(low):((amt)>(high)?(high):(amt)));
	}
	
	int16 Sign_ADRC(float Input)
	{
	  int16 output=0;
	  if(Input>1E-9) output=1;
	  else if(Input<-1E-9) output=-1;
	  else output=0;
	  return output;
	}
	
	int16 Fsg_ADRC(float x,float d)
	{
	  int16 output=0;
	  output=(Sign_ADRC(x+d)-Sign_ADRC(x-d))/2;
	  return output;
	}
	
	void ADRC_Init(Fhan_Data *fhan_Input1,Fhan_Data *fhan_Input2)
	{
	  fhan_Input1->r=ADRC_Unit[0][0];
	  fhan_Input1->h=ADRC_Unit[0][1];
	  fhan_Input1->N0=(uint16)(ADRC_Unit[0][2]);
	  fhan_Input1->beta_01=ADRC_Unit[0][3];
	  fhan_Input1->beta_02=ADRC_Unit[0][4];
	  fhan_Input1->beta_03=ADRC_Unit[0][5];
	  fhan_Input1->b0=ADRC_Unit[0][6];
	  fhan_Input1->beta_0=ADRC_Unit[0][7];
	  fhan_Input1->beta_1=ADRC_Unit[0][8];
	  fhan_Input1->beta_2=ADRC_Unit[0][9];
	  fhan_Input1->N1=(uint16)(ADRC_Unit[0][10]);
	  fhan_Input1->c=ADRC_Unit[0][11];
	  
	  fhan_Input1->alpha1=ADRC_Unit[0][12];
	  fhan_Input1->alpha2=ADRC_Unit[0][13];
	  fhan_Input1->zeta=ADRC_Unit[0][14];
	  fhan_Input1->z1=0;
	  fhan_Input1->z2=0;
	  fhan_Input1->z3=0;
	  fhan_Input1->e0=0;
	  fhan_Input1->e1=0;
	  fhan_Input1->e2=0;
	  
	  
	  fhan_Input2->r=ADRC_Unit[1][0];
	  fhan_Input2->h=ADRC_Unit[1][1];
	  fhan_Input2->N0=(uint16)(ADRC_Unit[1][2]);
	  fhan_Input2->beta_01=ADRC_Unit[1][3];
	  fhan_Input2->beta_02=ADRC_Unit[1][4];
	  fhan_Input2->beta_03=ADRC_Unit[1][5];
	  fhan_Input2->b0=ADRC_Unit[1][6];
	  fhan_Input2->beta_0=ADRC_Unit[1][7];
	  fhan_Input2->beta_1=ADRC_Unit[1][8];
	  fhan_Input2->beta_2=ADRC_Unit[1][9];
	  fhan_Input2->N1=(uint16)(ADRC_Unit[1][10]);
	  fhan_Input2->c=ADRC_Unit[1][11];
	  
	  fhan_Input2->alpha1=ADRC_Unit[1][12];
	  fhan_Input2->alpha2=ADRC_Unit[1][13];
	  fhan_Input2->zeta=ADRC_Unit[1][14];
	  fhan_Input2->z1=0;
	  fhan_Input2->z2=0;
	  fhan_Input2->z3=0;
	  fhan_Input2->e0=0;
	  fhan_Input2->e1=0;
	  fhan_Input2->e2=0;
	}
	
	void Fhan_ADRC(Fhan_Data *fhan_Input,float expect_ADRC)//安排ADRC过渡过程
	{ 
	  fhan_Input->fh=-fhan_Input->r*fhan_Input->r*(fhan_Input->x1-expect_ADRC)-2*fhan_Input->r*fhan_Input->x2;
	  fhan_Input->x1+=fhan_Input->x2*fhan_Input->h;
	  fhan_Input->x2+=fhan_Input->fh*fhan_Input->h;
	  
	  motor[4]=fhan_Input->x1;
	  motor[5]=fhan_Input->x2;
	}
	
	float Fal_ADRC(float e,float alpha,float zeta)
	{
	  int16 s=0;
	  float fal_output=0;
	  s=(Sign_ADRC(e+zeta)-Sign_ADRC(e-zeta))/2;
	  fal_output=e*s/(powf(zeta,1-alpha))+powf(ABS(e),alpha)*Sign_ADRC(e)*(1-s);
	  return fal_output;
	}
	
	void ESO_ADRC(Fhan_Data *fhan_Input)
	{
	  fhan_Input->e=fhan_Input->z1-fhan_Input->y;
	  /*************扩展状态量更新**********/
	  fhan_Input->z1+=fhan_Input->h*(fhan_Input->z2-fhan_Input->beta_01*fhan_Input->e);
	  fhan_Input->z2+=fhan_Input->h*(fhan_Input->z3
	                                 -fhan_Input->beta_02*fhan_Input->e
	                                   +fhan_Input->b0*fhan_Input->u);
	  
	  motor[6]=fhan_Input->z1;
	  motor[7]=fhan_Input->z2;
	  fhan_Input->z3-=fhan_Input->h*(fhan_Input->beta_03*fhan_Input->e);
	  motor[0]=fhan_Input->z3;
	}
	
	void Nolinear_Conbination_ADRC(Fhan_Data *fhan_Input)
	{ 
	  float temp_e2=0;
	  temp_e2=Constrain_Float(fhan_Input->e2,-1000,1000);
	  fhan_Input->u0=fhan_Input->beta_1*Fal_ADRC(Constrain_Float(fhan_Input->e1,-500,500),fhan_Input->alpha1,fhan_Input->zeta)
	    +fhan_Input->beta_2*Fal_ADRC(temp_e2,fhan_Input->alpha2,fhan_Input->zeta)
	      +fhan_Input->beta_0*Fal_ADRC(Constrain_Float(fhan_Input->e0,-100,100),fhan_Input->alpha2,fhan_Input->zeta);
	}
	
	int ADRC_Control(Fhan_Data *fhan_Input,float expect_ADRC,float feedback_ADRC)
	{  
	  Fhan_ADRC(fhan_Input,expect_ADRC);
	  
	  fhan_Input->y=feedback_ADRC;
	  
	  ESO_ADRC(fhan_Input);
	  
	  fhan_Input->e0+=fhan_Input->e1*fhan_Input->h;
	  fhan_Input->e1=fhan_Input->x1-fhan_Input->z1;
	  fhan_Input->e2=fhan_Input->x2-fhan_Input->z2;
	  
	  Nolinear_Conbination_ADRC(fhan_Input);
	  
	  fhan_Input->u=Constrain_Float(fhan_Input->u0,-1000,1000);
	  return (int)(fhan_Input->u);
	}
识别部分代码
	event_count = 1
	#对指定ROI进行全局分类,这一部分实时运行。
	result = number_net.classify(img,roi = (0,leftuppoint,160,roiheight))[0].output()
	max_score = max(result)
	max_label = result.index(max_score)
	if test == 1:
	    img.draw_rectangle((0,leftuppoint,160,roiheight), color = (255, 0, 0))
	
	# 如果识别到了数字
	if(max_label<10 and max_score >= 1):
	    if test == 1:
	        print("number:{}".format(max_label))
	    if ((max_label)%2==1):
	        uart_array[1] = 3
	    elif((max_label)%2==0): #偶数左转
	        uart_array[1] = 4
	
	    if send_count == 0:
	        uart.write(bytearray(uart_array))
	        send_count = send_count + 1
	
	    print("识别到数字值为{}, 发送的数据uart_array = {}\n".format(max_label,uart_array[1]))
	    switch_mode = 0
	    mode_ctrl(switch_mode)   # 根据接受的数据控制模式
	    event_count = 0 # 默认为1识别到数字后置0,防止重复识别动植物。
	
	
	if event_count == 1: # 如果满足数字就不要识别动植物
	    for r in img.find_rects(threshold = 50000 ,roi = (0,leftuppoint,160,roiheight)): # 在图像中搜索矩形
	        if(r.w()*1.15>r.h() and r.h()*1.15>r.w() and r.w()>=50 and r.h()>=50):
	            if(test == 1):
	                print("找到紫框:{}".format(r))
	                img.draw_rectangle(r.rect(), color = (255, 0, 0))   # 绘制矩形外框,便于在IDE上查看识别到的矩形位置
	            img1 = img.copy(r.rect())   # 拷贝矩形框内的图像
	
	
	            ## 先判断是否为tag
	            if(img1.find_apriltags(families=image.TAG25H9) != []):  # 是TAG
	                for tag in img1.find_apriltags(families=image.TAG25H9):  #tag是一个字典
	                    tagID = tag.id()
	                    if((tagID)%2==1):
	                        uart_array[1] = 1
	                    elif((tagID)%2==0):
	                        uart_array[1] = 2
	
	                    if send_count == 0:
	                        uart.write(bytearray(uart_array))
	                        send_count = send_count + 1
	
	                    print("识别到TAG值为{}, 发送的数据uart_array = {}\n".format(tagID,uart_array[1]))
	                    switch_mode = 0
	                    mode_ctrl(switch_mode)   # 根据接受的数据控制模式
	                    event_count = 0
	
	            if(img1.find_apriltags(families=image.TAG25H9) == []):  # 不是TAG
	                for obj in nncu.classify(net6 , img1, min_scale=1.0, scale_mul=0.5, x_overlap=0.0, y_overlap=0.0):
	                    # print("**********\nTop 1 Detections at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
	                    sorted_list = sorted(zip(labels6, obj.output()), key = lambda x: x[1], reverse = True)
	                    # print(sorted_list) [('dog', 0.999969482421875), ('cat', 3.0517578125e-05), ('horse', 0.0), ......]
	                    for i in range(1):          # 打印准确率最高的结果
	                        print("%s = %f" % (sorted_list[i][0], sorted_list[i][1]))
	                        if sorted_list[i][0] == "animal" :
	                            uart_array[1] = 5
	                        elif sorted_list[i][0] == "fruit":
	                            uart_array[1] = 6
	                        elif sorted_list[i][0] == "white":
	                            break
	
	                        if send_count == 0:
	                            uart.write(bytearray(uart_array))
	                            send_count = send_count + 1
	
	                        print("识别到动植物 , 发送的数据uart_array = {}\n".format(uart_array[1]))
	                        switch_mode = 0
	                        mode_ctrl(switch_mode)   # 根据接受的数据控制模式
	                        event_count=0
	
	send_count = 0


● 相关图表链接:

  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2021-09-07 10:48:58  更:2021-09-07 10:49:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 15:49:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码