简 介: 本文详细介绍了太原工业学院“晋速—轩辕星”在第十六届全国大学生智能汽车竞赛智能视觉组的系统方案。本次比赛采用大赛组委会统一指定的新 C 型车模,以NXP公司生产的RT1064为核心控制器,要求智能车识别道路两边黑线,以最快速度完成整个比赛,智能车采用总钻风摄像头对赛道信息检测,根据黑色边线提取赛道中线;通过编码器检测智能车的实时速度,使用 PID 控制算法调节电机的转速和舵机的打角,实现智能车在运动过程中速度和方向的闭环控制;为了提高模型车的速度和稳定性,使用上位机、按键、IPS显示模块等调试工具,进行了大量硬件与软件测试。在此基础上,分模块详细介绍了系统硬件电路的设计与实现,主要包括:主控制器硬件设计、电源模块硬件设计、电机驱动模块、模数转换模块、AI识别,共五大模块,以及对车模的结构优化思路。
关键词
: 智能车 RT1064,总钻风摄像头,PID控制,AI识别
学 校:太原工业学院
队伍名称:晋速-轩辕星
参赛队员:常源
宁亚强
石伟
带队教师:左义海
寇元超
第一章 引 言
本文以第十六届全国大学生智能汽车竞赛为背景,该比赛受教育部高等教育司委托,由教育部高等自动化专业教学指导分委员会(以下简称自动化分教指委)主办全国大学生智能汽车竞赛。该竞赛以智能汽车为研究对象的创意性科技竞赛,是面向全国大学生的一种具有探索性工程实践活动,是教育部倡导的大学生科技竞赛之一,为加强大学生实践、创新能力和团队精神的培养,促进高等教育教学改革。该竞赛以“立足培养,重在参与,鼓励探索,追求卓越”为指导思想,旨在促进高等学校素质教育,培养大学生的综合知识运用能力、基本工程实践能力和创新意 识,激发大学生从事科学研究与探索的兴趣和潜能,倡导理论联系实际、求真务实的学风和团队协作的人文精神,为优秀人才的脱颖而出创造条件。
该竞赛由竞赛秘书处为各参赛队提供/购置规定范围内的标准硬软件技术平台,竞赛过程包括理论设计、实际制作、整车调试、现场比赛等环节,要求学生组成团队,协同工作,初步体会一个工程性的研究开发项目从设计到实现的全过程。该竞赛融科学性、趣味性和观赏性为一体,是以迅猛发展、前景广阔的汽车电子为背景,涵盖自动控制、模式识别、传感技术、电子、电气、计算机、机械与汽车等多学科专业的创意性比赛。该竞赛规则透明,评价标准客观,坚持公开、公平、公正的原则,保证竞赛向健康、普及,持续的方向发展。
本次比赛中,本组使用大赛组委会统一提供的竞赛车模,采用恩智浦公司RT1064作为核心控制单元,自主构思控制方案及系统设计,包括传感器信号采集处理、控制算法及执行、动力电机驱动、舵机控制,AI识别等,最终实现一套能够自主识别路线,并且可以实时输出车体状态的智能车控制硬件系统。
本报告将从硬件到软件一一的为大家呈现该系统的设计方案和制作过程。
第二章 全国大学生智能汽车竞赛
2.1第十六届全国智能汽车竞赛规则介绍
2.1.1车模
车模必须使用竞赛指定车模中新C车模。
车模制作完毕后,车模长宽高均没有限制,车模轮胎必须2/3以上有花纹。
2.1.2微控制器与传感器
车模微控制器使用STC,Infineon,NXP系列单片机。
允许使用各类电磁、红外光电、摄像头、激光、超声传感器器件进行赛道和环境检测。
我们在实际制作过程使用了NXP系列单片机RT1064。使用总钻风摄像头识别赛道;为了提高出入环准确度,专门增加了电感识别赛道;为了实现AI识别任务,专门使用了OpenART mini识别动物水果数字以及AprilTag码;为了实现激光打靶,专门使用了激光传感器;为了实现电机闭环,提高控制精度,车模使用了 AB 项正交解码编码器,并且不断调试和电机的齿轮距,使其在保证啮合程度的基础上减小阻力。
2.1.3比赛赛道
比赛是在 PVC 赛道上进行,赛道采用黑色边线和电磁进行导引。赛道中可能 存在的元素包括表 2 中所有的元素(直线赛道、曲线弯道、十字交叉路口、坡道、环岛以及三岔)。
2.1.4比赛任务
选手制作的车模完成从车库触发沿着赛道运行两周,然后在返回车库。比赛时间从车模冲过起跑线到重新回到起跑线为止,中途会遇到三岔路口,路口会有数字,根据第一圈识别数字,偶数走左边的道路,基数走右边的道路,第二圈走与第一圈相反的道路;在直道随机位置还会出现两个AprilTag(一个代表偶数,一个代表基数),如果遇到偶数OpenART mini向左转识别动物或水果,遇到基数OpenART mini向右转识别动物或水果,如果是动物则在以AprilTag为中心的一米范围内停留3秒钟,如果是水果则完成激光打靶,激光照射中心至少一秒钟。如果没有完成识别任务则会进行相应的罚时。最后如果车模没有能够停止在车库内停车区内,比赛时间加罚十五秒钟。没能够进库触发裁判系统,则没有完成任务,没有成绩。
▲ 图 2.1.4 车模出发和返回进入车库
第三章 机械结构部份的设计及调整
智能车机械部分设计主要包括制作和调整两部分内容,制作部分的内容主要是对车模没有的部分进行设计,包括传感器支架、电路板固定、防撞、测速码盘安装等。调整部分则主要是针对智能车车模本身已经有的机械部分,在规则允许范围内进行调整,改装,提高其运动性能,以适应高速行驶和快速控制,这部分主要包括舵机安装、底盘调整、避震调整、四轮定位、电池位置的摆放、重心的调整等。本章内容主要对电路板安装、传感器支架以及机械调校部分进行介绍。
3.1车模机械结构制作部分设计
大赛提供的都是通用的车模都是运动型模型车通用车模,并没有提供专门为智能车安装电路、传感器等电路部分的部件,因此这部分机械结构需要自行设计制作并安装。我们需要自制覆有铜层的PCB板子,在对原有的机械结构进行一定的修改,另外,为了提高车模的运动性能,对一些机械结构还需要调整,比如前轮前束等。
3.1.1 车体机械建模
此次竞赛的赛车车模选用由东莞市博思电子数码科技有限公司提供的新 C 型车模。车模外形如图 3.1 所示。
▲ 图 3.1 车模整体照片
3.1.2 前轮定位
C 型车模前轮可以调整的角度有主销前倾、内倾、前束等,这些角度的调整根据每个车的机械性能不同而不同调整,我们的智能车由于重心位置在中心偏后,因此前轮压力较小,转向负担不大,因此为了增加抓地力和稳定性,选择了主销内倾和前束的调整。另外,由于车模本身的精度限制,这部分角度的调整并不是主要的,仅仅是为了避免负面影响以及修正车模本身的不对称和不平衡问题。
主销内倾角是指在横向平面内主销轴线与地面垂直线之间的夹角,它的作用也是使前轮自动回正。角度越大前轮自动回正的作用就越强,但转向时也就越费力,轮胎磨损增大;反之,角度越小前轮自动回正的作用就越弱。通常汽车的主销内倾角不大于 8°。对于模型车,通过调整前桥的螺杆的长度可以改变主销内倾角的大小,由于过大的内倾角也会增大转向阻力,增加轮胎磨损,所以在调整时可以近似调整为 0°-3°左右,不宜太大。主销内倾和主销后倾都有使汽车转向自动回正,保持直线行驶的功能。不同之处是主销内倾的回正与车速无关,主销后倾的回正与车速有关,因此高速时主销后倾的回正作用大,低速时主销内倾的回正作用大。
3.1.3 车轮外倾角
前轮外倾角是指通过车轮中心的汽车横向平面与车轮平面的交线与地面垂线之间的夹角,对汽车的转向性能有直接影响,它的作用是提高前轮的转向安全性和转向操纵的轻便性。在汽车的横向平面内,轮胎呈“八”字型时称为“负外倾”,而呈现“V”字形张开时称为正外倾。如果车轮垂直地面一旦满载就易产生变形,可能引起车轮上部向内倾侧,导致车轮联接件损坏。所以事先将车轮校偏一个正外倾角度,一般这个角度约在 1°左右,以减少承载轴承负荷,增加零件使用寿命,提高汽车的安全性能。模型车提供了专门的外倾角调整配件,近似调节其外倾角。由于竞赛中模型主要用于竞速,所以要求尽量减轻重量,其底盘和前桥上承受的载荷不大,所以外倾角调整为 0°即可,并且要与前轮前束匹配。
3.1.4 底盘高度的调整
在保证顺利通过坡道的前提下,底盘尽量降低,从整体上降低模型车的重心,可使模型车转弯时更加稳定、高速。
3.1.5 编码器的安装
编码器主要用来测量小车速度,必须保证齿轮完全啮合才能使得测量结果准确,同时在实际调试过程中我们还发现,编码器掉齿、卡顿等现象时有发生,为提高编码器测速的稳定性及准确性,我们用胶水将编码器粘牢,再进一步保证编码器齿轮与电机完全切合。如图3.1.5所示。
▲ 图3.1.5 编码器的安装
3.1.6 摄像头的安装
同时为了降低整辆车的重心,综合考虑各种利弊,最终我们决定通过尼龙组件和碳纤维管的固定方式来固定摄像头,这样既保证了整个摄像头系统的稳定性,也保证了整个系统有很高的定位精度和刚度,使摄像头能更好的拆装和维修,具有赛场快速的保障能力。如图3.1.6所示。
▲ 图3.1.6 摄像头的安装
第四章 方案的设计
4.1 四轮系统概述
系统整体结构如图所示。RT1064微处理器通过采集总钻风摄像头的硬件二值化信号,得到赛道边沿信息;通过采集龙邱1024线编码器对车轮转速的脉冲计数,得到车行进的速度数据。通过OpenART和RT1064建立通信实现AI识别。通过微处理器对图像处理,对角度、速度进行 PID 控制,最后 PWM 波输出驱动电机、舵机。
第五章 硬件电路的设计
智能车电路部分主要的模块包括:单片机最小系统、电源模块、传感器模块、驱动模块以及其他周边调试模块。各模块的总体设计原则是:紧凑、易于拆换、稳定可靠。但根据各模块的不同,又有不同的设计要求。
智能视觉的整个硬件电路由四块板组成,分为最小系统板、主板、驱动板,摄像头转接板。最小系统板选用逐飞店铺购买的RT1064核心板;主板自行设计,板上附带了蓝牙插口、摄像头排座口、IPS显示器插口、夏普红外插口、运放插口、驱动信号插口、编码器插口、激光插口、OpenART mini插口及一些预留备用口与拨码开关、五轴按键调试工具。
5.1单片机最小系统
最小系统的可靠性与稳定性是小车能完成预设功能的最关键的部分。在原理图与PCB的设计过程中,考虑到各个功能模块的电特性以及之间的耦合作用。以及制作4层板的难度,所以我们直接选用逐飞科技现卖的RT1064核心板。
5.2 电源模块
电源分为开关电源和线性电源,线性电源的电压反馈电路是工作在线性状态,开关电源是指用于电压调整的管子工作在饱和和截至区即开关状态的。线性电源一般是将输出电压取样然后与参考电压送入比较电压放大器,此电压放大器的输出作为电压调整管的输入,用以控制调整管使其结电压随输入的变化而变化,从而调整其输出电压,但开关电源是通过改变调整管的开和关的时间即占空比来改变输出电压的。
经过筛选我们最终选择LM2940S-5.0芯片为核心板以及所有需要5V供电的传感器提供5V电源,选择RT9013-33GB芯片为所有需要3.3V供电的传感器提供3V3电源。
考虑到核心板、蓝牙、运放模块等需要5V的供电,我们使用 LM2940S-5.0 作为 5V稳压芯片。如图5.2.1所示。
▲ 图5.2.1 5v供电
考虑到摄像头、IPS显示屏、调参模块等需要3.3V的供电,而且需要考虑上电时序的问题,所以我们使用两块RT9013-33GB 作为 3.3V稳压芯片。一块用于摄像头供电,一块用于其他3.3V外设。如图5.2.2所示。
▲ 图5.2.2 3.3v供电
S3010舵机采用 4.0-6.0V 进行供电,在设计前通过查阅大量资料对比得出, 当舵机供电越低时,其使用寿命越长,但此时响应速度越慢,当整车速度较快时,舵机响应速度跟不上小车速度;当采用 6V 供电时,舵机响应速度加快,可让小车转向更为灵敏。通过对比两种方案优劣后,在设计时舵机采用 6V 供电,经过系列筛选后最终选择使用AS1015芯片。如图5.2.3所示。
▲ 图5.2.3舵机供电模块
5.3摄像头与运放模块
今年的摄像头高度不限制,而且最初规则说不排除有阳光,是摄像头最难受的一年,面对早晨在实验室打开窗帘透射进来的阳光,脸上暖暖的,心头凉凉的。摄像头可分为数字摄像头和模拟摄像头两大类。数字摄像头可以将视频采集设备产生的模拟视频信号转换成数字信号,进而将其传送到MCU处理。模拟摄像头捕捉到的视频信号必须经过特定的视频捕捉卡将模拟信号转换成数字模式,并加以压缩后才可以转换到MCU上运用。因为阳光的问题我们尝试了硬件二值化的鹰眼摄像头,模拟摄像头,总旋风摄像头,但是还是不能稳定的在阳光下奔跑,于是退而求其次,用物理方式减小阳光对摄像头的影响。最终还经过一系列的对比筛选,最终还是选择了总钻风摄像头。
▲ 图5.3-1摄像头模块
运放用来放大电磁感应传感器的传来的赛道信号,并将其检波以供AD采集和信号处理。在做运放的时候我们首先用INA2332芯片,放大效果较好,输出也比较稳定,但是外围电路十分复杂导致电路板体积较大,焊接麻烦。之后选用OPA2350芯片,电路简单,放大效果优良。运放板通过使用小封装元件跟集成二极管来减小电路板体积。原理图如图5.3-2所示。
▲ 图5.3-2 运放原理图
5.4电机驱动模块
采用N沟道MOSFET和专用栅极驱动芯片设计。市面上常见的集成H桥式电机驱动芯片中,33886型芯片性能较为出色,该芯片具有完善的过流、欠压、过温保护等功能,内部MOSFET导通电阻为120毫欧,具有最大5A的连续工作电流。如图5.4所示。
▲ 图5.4 电机驱动
5.5激光驱动模块
使用方框中的NE555电路生成125HZ的PWM,然后PWM连接到方框2中的PWM引脚上,只要EN引脚给高激光头就会发射出125HZ的信号。
▲ 图5.5 激光驱动模块
第六章 车模软件算法
6.1 四轮车模的控制
图像的处理是必不可少的一部分,高效的软件程序是智能车高速平稳自动寻线的基础。我们设计的智能车系统采用总钻风摄像头进行赛道识别,利用单片机的快速处理能力进行图像采集以及信息处理。 配合采集行数达到失真矫正的效果,不断优化算法和路径。在智能车的转向和速度控制方面,我们使用经典高效的增量式 PID 算法,配合鲁棒控制,实现快速加减速,配合使用理论计算和实际参数补偿的办法,使智能车能够稳定快速寻线。
6.1.1 原始图像的特点
在获得到的图像之后,因为环境光线、噪点、赛道远处的不清楚的影响,图像可利用的信息大大的减小,对车模行进的影响会大大的提高,一些赛道的交叉,十字,起跑线的存在,导致车模对赛道信息处理不正确。因此,在获取到图像的时候,必须排除图像上的干扰信息,在排除图像的干扰信息之后,为车模的控制提供尽可能多的准确的赛道信息。
在获取图像之后,我们主要做的是提取赛道的有用信息:赛道两边的边沿位置,元素的特征点,十字的转角点,赛道重心的偏移,赛道中心偏移的变化率,赛道类型的判别。
单片机通过比较每一行的黑白跳变点(跳变点按从右到左的顺序)记录下来,保存到两个二维数组里(分别表示上升沿、下降沿)。通过遍历上升沿和下降沿可以完成赛道边沿的提取。
▲ 图6.1.1-1
▲ 图6.1.1-2
▲ 图6.1.1-3
▲ 图6.1.1-4
▲ 图6.1.1-5
6.1.2赛道边沿提取
在获取到图像之后,就需要对图像提取赛道的边界,从而获得的赛道的有效信息:
(1) 直接逐行扫描原始图像,提取黑白跳变点;
(2) 赛道宽度有一个范围,在确定的赛道宽度范围内提取有效赛道边沿,这样可以滤除不在宽度范围内的干扰;
(3)利用赛道的连续性,根据上一行白块的位置和边沿的位置来确定本行的边沿点;
(4) 求边沿点时,因为近处的图像稳定,远处图像不稳定,所以采用由近及远的办法;
(5) 进出十字的时候,通过校正计算出边沿角度可较好的滤除十字并补线;
6.1.3 中心的计算
通过之前提取的赛道边沿数据推算中心:当左右边沿点总数较少时返回;若只有单边有边沿点数据,则通过校正对单边数据按法线平移赛道宽度一半的距离;当能找到与一边能匹配上的另一边沿点时则直接求其中心作为中心点。推算完中心点后,对中心点进行均匀化,方便之后的控制。
6.1.4 PID的控制算法介绍
【通用原理部分,此处省略3000字…】
6.1.7 电机的控制
对于速度的控制,采用了编码器闭环的策略,编码器来反馈实际速度,小车根据实际速度与目标速度的差值,再通过PID算法的计算,最后根据计算得到的值修改输出大小,以保证小车速度一直都是稳定的,这就是闭环的优点。
6.1.8 舵机的控制
舵机的控制就是根据处理图形之后返回的合适的偏差的进行一个打角,在偏移量的计算当中,我们通过对整副图中线加权的方式来计算偏移量。给每一行设定一个权值,最后通过所有有效行的加权来计算出当前图像的偏移量。PD 控制当中的偏差就是之前通过整幅图加权的方式得出。每一行加权的权重是经过长期整定的,最后得出了一套合理的,适应性强的权值。
6.1.9 速度的控制
通过对编码器的数据的滤波处理,获得车子的车子速度,输入给速度环,速度环的输出为一个角度,在输入到车子的直立环内,也就是速度环的不同的输出改变直立环的角度期望。因为速度环和转向环最后的输出都是给电机的,就涉及到马达的复用问题,为了保持车模的直立不倒,应该在车模速度可控的前提下尽量对车模平衡造成最小的干扰,平衡控制采用大约5ms 一个周期,而速度控制则采用大约50ms 一个周期,这样的方法就可以使速度即可控,平衡也不被打破。直立车的速度环用这种控制方法滞后性较强,难以保持较好的跟随性,但 是直立车对速度环的要求不是太高,速度误差在可以接受的范围内即可。
6.1.10环岛的策略
通过大量的对比和观察,我们可以发现圆环与其他普通赛道之间的区别,首先 在圆环处,可以在一条边线上搜索到两个拐点,而在另一条边线上搜索不到边 线,并且图像的一条边界有丢线的现象,而另外一边则比较完整,并且圆环一般会出现在直道上,此时我们最上面的拐点补出一条弧线,以此进入环岛。
我们的电感排布采用的是“三横两竖”的排布方式,通过环岛的特性可以知道,在环岛处的电感值应大于其他地方的电感值,根据这一特性,我们可以识别出环岛的位置。因为中间电感对环岛的值敏感,所以我们使用中间电感来进行环岛的识别。在通过竖感和横感偏差的拟合,拟合出一个合适的偏差,通过这个偏差来实现环岛的进入。如图6.2.4。
▲ 图 6.2.4-1 环岛
根据上面的思路就可以做到环岛的进入,为防止环岛的二次判断和出环路径的正确,需要对出环做特殊的处理。下面是环岛处理流程:
▲ 图 6.2.4-2 环岛流程图
6.1.11AI识别的策略
通过总钻风摄像头识别到AprliTag码的特征后进行停车,然后OpenART mini摄像头进行识别AprliTag码确定是基数还是偶数;OpenART mini摄像头识别到AprliTag码后会进行动物和水果的识别,我们根据动物和水果周围的边框对图片进行定位,确定位置后识别图片,识别到图片保证正确后进行相应的任务;识别到动物停留三秒,识别到水果进行激光打靶,为了确保激光打靶打在把心中央,我们根据图片的大小返回中心坐标,将数值传给舵机转相应的角度。识别三岔的数字时,我们先停车进行识别,依旧是根据数字周围的边框对图片进行定位,确定位置后识别图片,识别数字如果是偶数选择左边的道路行进,如果是基数选择右边的道路行进,第二圈遇到三岔时则走第一圈的相反道路。
但是,天有不测风云,由于疫情原因,国赛改变为线上比赛的形式,对于智能视觉组来说规则改动很大,换句话说就是要重新再来。线上赛将跑赛道和识别分开进行,分别进行积分,在规定时间内根据累加的积分进行比赛,一决胜负,发车机会只有三次,这对于车模的稳定性有很强的要求。对于识别,规则改为:如果是偶数,则往前行进大约30厘米,然后退回到原地;如果是奇数,往后退行大约30厘米,然后返回原地;如果动作错误或不做动作,则扣5分;识别AprilTag,如果是偶数,车模先往前行进大约10厘米,然后再返回原地。如果Apriltag是奇数,则车模先后退大约10厘米,然后返回原地;如果动作错误或不做动作,则扣5分;识别到水果,车模激光管发送激光对水果图片下方的键盘进行照射打靶,激光光斑需打在图片垂直映射下来的键盘上即可(打在屏幕上会产生镜面反射,不容易判断是否进行了打靶),照射时间超过1秒钟。如果动作错误或不做动作,则扣10分;识别到动物,车模的摄像头左右摇摆两次,摇摆的角度大于90°或者车模前轮转向左右摆动两次。如果动作错误或不做动作,则扣10分;最后进行识别积分累加。最终总成绩 = 跑赛道最好成绩 + 识别最好成绩。
▲ 图6.1.11 AprilTag及动物水果的位置
▲ 图 6.1.11数字的位置
▲ 图6.1.11 识别到数字水果以动物
第七章 系统开发及调试工具
7.1 软件开发的平台
程序开放在 IAR Embedded Workbench IDE 下进行, Embedded Workbench for ARM是 IAR Systems公司为 ARM 微处理器开发的一个集成开发环境(下面简称 IAR EWARM)。比较其他的 ARM 开发环境, IAR EWARM 具有入门容易、使用方便和代码
紧凑等特点。如图7.1。
▲ 图 7.1 IAR软件
IAR EWARM中包含一个全软件的模拟程序(Simulator) 。用户不需要任何硬件支持就可以模拟各种ARM内核、外部设备甚至中断的软件运行环境。从中可以了解和评估IAR EWARM的功能和使用方法。
7.2 上位机调试助手
上位机的调试我们一般采用的是山外虚拟示波器,通过上位机返回的数据进行分析处理,通过对数据的分析处理找到问题的所在,更好的解决问题,比盲目的修改参数效率高。如图7.2。
▲ 图7.2 示波器
7.3 人机交互界面
因为比赛中可能会对一些参数做出修改,根据赛道情况做出不同的策略。比赛场上时间紧张,尽量要做到不必要的时间浪费,所以能不下程序就尽量不下,所以做出一个快捷的调参界面,我们通过五轴按键和拨码开关还修改参数。如图7.3:
▲ 图 7.3 调参页面
第八章 车模技术检测
结论
自报名参加第十六届全国大学生智能汽车竞赛以来,我们小组成员从查找资料、设计机构、组装车模、编写程序一步一步的进行,最后终于完成了最初目标,定下了现在这个设计方案。
在此份技术报告中,我们主要介绍了准备比赛时的基本思路,包括机械、 电路以及最重要的控制算法的创新思想。在机械结构方面,我们分析了整车质量分布,调整重心位置,优化机械结构。在电路方面,我们以模块形式分类,在最小系统、主板、电机驱动等模块分别设计,在查找资料的基础上各准备了几套方案;然后我们分别实验,最后以报告中所提到的形式决定了我们最终的电路图。在程序方面,我们使用 C 语言编程,利用比赛推荐的开发工具调试程序,经过小组成员不断讨论、改进,终于设计出一套比较通用稳定的程序。
在备战的过程中,场地和经费方面都得到了学校的大力支持,在此特别感谢一直支持和关注智能车比赛的学校领导以及各位指导老师、指导学长,同时也感谢比赛组委会能组织这样一项有意义的比赛。在做比赛的过程中,我们不止锻炼了我们的学习能力,也锤炼了我们的意志力。我们相信经过这漫长的备赛时间,小组成员的不断摩擦与碰撞,日后即使碰到再难的事情,我们都能迎难而上。现在,我们小组每个人将自己做比赛的经验汇总成这么一份技术报告,它倒映着我们难眠的日夜,流淌着我们辛劳的汗水,凝聚着我们宝贵的心血;它更是珍贵的回忆,而这段难以忘怀的经历将促使我们砥砺前行。
参考文献
[1] 臧杰,阎岩.汽车构造[M].北京:机械工业出版社,2005
[2] 孙同景,陈贵友.十六位单片机原理及嵌入式开发技术[M].北京:机械工业出版社,2008
[3] 王威.HCS12微控制器原理及应用[M].北京:北京航空航天大学出版社,2007
[4] 桌晴,黄开胜,邵贝贝.学做智能车[M]. 北京:北京航空大学出版社,2007
[5] 张靖武.单片机原理应用与PROTEUS仿真[J].电子工业出版社,2009.8(1):19-28
[5] 刘畅生,张耀进.新型集成电路简明手册及典型应用[J].西安电子科技大学出版社,2005
[6] 夏路易,石宗义著.电路原理图与电路板设计[M].北京: 北京希望电子出版社, 2002.6
[7] 邵贝贝 .单片机嵌入式应用的在线开发方法[M]. 北京:清华大学出版社, 2004
[8] 张化光,何希勤.模糊自适应控制理论及其应用[M].北京:北京航空大学出版社,2002
[9] 王柏盛.C程序设计[J].北京:高等教育出版社.2004.4(1):65-98
[10] 智能车论坛
[11] 卓晴公众号
附录 A:程序源代码
//舵机控制
void Steer_dianci( float E )
{PID_Steer.error =(int) E;float Kp,Kd;float EC;EC = regression(0,9,AD_ERR_DATA); if(flag_barn_out == 0){if(y_barn.out==0 && AD_ML>=10&&AD_MR>=10) y_barn.out=1; }if(flag_barn_out == 1){if(z_barn.out==0 && AD_ML>=10&&AD_MR>=10) z_barn.out=1; }if(y_barn.out==0&&z_barn.out==0) pwm_duty(PWM4_MODULE2_CHA_C30, steer_mdl );if(z_barn.out == 1 ) pwm_duty(PWM4_MODULE2_CHA_C30, steer_mdl+95 );if(y_barn.out == 1 ) pwm_duty(PWM4_MODULE2_CHA_C30, steer_mdl-95 );if( PID_Steer.error > 0 ){ Kp = PID_Steer.proportiongain_left * PID_Steer.error ;Kd = PID_Steer.derivativegain_left * EC;PID_Steer.result = Kp + Kd;}if( PID_Steer.error < 0 ) //右拐{Kp = PID_Steer.proportiongain_right * PID_Steer.error ;Kd = PID_Steer.derivativegain_right * EC;PID_Steer.result = Kp + Kd;}PID_Steer.lasterror = PID_Steer.error;if(barn_key == 2 || barn_key==3 || barn_key==4 ) PID_Steer.result=-PID_Steer.result;if(barn_key == 4 && flag_barn_on==0) PID_Steer.result=-95;if(barn_key == 4 && flag_barn_on==1) PID_Steer.result=95;if(barn_key == 5) PID_Steer.result=0;if( PID_Steer.result > 100 ) PID_Steer.result = 100;if( PID_Steer.result < -100 ) PID_Steer.result = -100;if(y_barn.out >= 2 || z_barn.out >= 2) pwm_duty(PWM4_MODULE2_CHA_C30, (int)(steer_mdl + PID_Steer.result));
}
void steer_2p(void)
{float Kp,Kd;PID_Steer.lasterror = PID_Steer.error; /**动态前瞻**/if(speed_key == 1){if(z_barn.out >1||y_barn.out>1 )if(mode == 0 &&flag_rap==0){if((count_left+count_right)/2 > V_Min)mdl_eye =(int)( eye - ((count_left+count_right)/2 - V_Min)*eye_k1);// < 19?19:(int)( Eye - ((Value_L+Value_R)/2 - V_Min)*0.1);if((count_left+count_right)/2 <= V_Min)mdl_eye = eye+1;if(mdl_eye<21) mdl_eye=21;} }if(flag_barn_out>1&&(y_barn.out==0&&z_barn.out==0)) {y_barn.out=3;z_barn.out=3;}/**出库**/if(flag_barn_out<=1){if(flag_barn_out == 0){if(y_barn.out != 1&&y_barn.out != 0) {PID_Steer.error = (int) (mdl_line-zhong[mdl]);}}if(flag_barn_out == 1) {if(z_barn.out != 1&&z_barn.out != 0) {PID_Steer.error = (int) (mdl_line-zhong[mdl]);} }} else {PID_Steer.error = (int) (mdl_line-zhong[mdl]);} //左拐if( PID_Steer.error >= 0 ) {Kp = ((PID_Steer.error*PID_Steer.error)*z_kp+m_kp) * (PID_Steer.error);Kd = z_kd * ( PID_Steer.error - PID_Steer.lasterror);PID_Steer.result = Kp + Kd;} //右拐if( PID_Steer.error < 0 ) {Kp = ((PID_Steer.error*PID_Steer.error)*y_kp+m_kp) * (PID_Steer.error);Kd = y_kd * ( PID_Steer.error - PID_Steer.lasterror);PID_Steer.result = Kp + Kd;if( PID_Steer.result > 98 ) PID_Steer.result = 98;if( PID_Steer.result < -96 ) PID_Steer.result = -96;
if((y_barn.out==3||z_barn.out==3)&&(PID_Steer.result-pwm_last>110||PID_Steer.result-pwm_last<-110))
// PID_Steer.result=pwm_last;/**出库**/if(flag_barn_out == 0){if( y_barn.out == 1 ) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl - 95)); }if(flag_barn_out == 1){if( z_barn.out == 1 ) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl + 95)); }/**进库**/if(flag_barn_on == 0){if(y_barn.find == 2) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl+15+PID_Steer.result)); else if(y_barn.find == 3 || y_barn.find == 4) pwm_duty(PWM4_MODULE2_CHA_C30,steer_mdl-90); else if(y_barn.find != 2 && y_barn.find != 3 && y_barn.out >1) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl + PID_Steer.result)); }else{if(z_barn.find == 2) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl-15+PID_Steer.result)); else if(z_barn.find == 3 || z_barn.find == 4) pwm_duty(PWM4_MODULE2_CHA_C30,steer_mdl+90); else if(z_barn.find != 2 && z_barn.find != 3 && z_barn.out >1) pwm_duty(PWM4_MODULE2_CHA_C30,(int)(steer_mdl + PID_Steer.result));}if(z_barn.on == 1 || y_barn.on == 1) pwm_duty(PWM4_MODULE2_CHA_C30,steer_mdl); pwm_last = PID_Steer.result;
}//参数显示if(flag_page == 2 && mode_flag == 0){
ips200_showuint8(210,18,flag_page,RED);ips200_showstr(0,1,"carbarn",RED);ips200_showstr(24,2,"mdl",RED);ips200_showuint8(64,2,barn_mdl,BLUE);ips200_showstr(24,3,"z_s1",RED);ips200_showuint8(64,3,z_barn.site1,BLUE);ips200_showstr(24,4,"z_s2",RED);ips200_showuint8(64,4,z_barn.site2,BLUE);ips200_showstr(116,3,"z_s3",RED);ips200_showuint8(156,3,z_barn.site3,BLUE);ips200_showstr(116,4,"mils",RED);ips200_showuint16(156,4,z_barn.mils,BLUE);ips200_showstr(24,5,"y_s1",RED);ips200_showuint8(64,5,y_barn.site1,BLUE);ips200_showstr(24,6,"y_s2",RED);ips200_showuint8(64,6,y_barn.site2,BLUE);ips200_showstr(116,5,"y_s3",RED);ips200_showuint8(156,5,y_barn.site3,BLUE); ips200_showstr(116,6,"mils",RED);ips200_showuint16(156,6,y_barn.mils,BLUE);ips200_showstr(24,7,"on",RED);ips200_showuint8(64,7,flag_barn_on,BLUE);ips200_showstr(116,7,"out",RED);ips200_showuint8(156,7,flag_barn_out,BLUE);ips200_showstr(24,8,"yonls",RED);ips200_showuint16(64,8,y_barn.on_mils,BLUE);
ips200_showstr(116,8,"zonls",RED);ips200_showuint16(156,8,z_barn.on_mils,BLUE); ips200_showstr(24,9,"speed",RED);ips200_showint8(64,9,barn_speed,BLACK);ips200_showstr(24,11,"Line",BLACK);ips200_showstr(24,12,"line",RED);ips200_showfloat(64,12,mdl_line,2,1,BLACK);if(flag_adjust==0) ips200_drawcross(14,40,RED,10);if(flag_adjust==1) ips200_drawcross(14,56,RED,10);if(flag_adjust==2) ips200_drawcross(14,72,RED,10);if(flag_adjust==3) ips200_drawcross(106,56,RED,10);if(flag_adjust==4) ips200_drawcross(106,72,RED,10);if(flag_adjust==5) ips200_drawcross(14,88,RED,10); if(flag_adjust==6) ips200_drawcross(14,104,RED,10); if(flag_adjust==7) ips200_drawcross(106,88,RED,10);if(flag_adjust==8) ips200_drawcross(106,104,RED,10); if(flag_adjust==9) ips200_drawcross(14,120,RED,10);if(flag_adjust==10) ips200_drawcross(106,120,RED,10);if(flag_adjust==11) ips200_drawcross(14,136,RED,10);if(flag_adjust==12) ips200_drawcross(106,136,RED,10);if(flag_adjust==13) ips200_drawcross(14,152,RED,10);if(flag_adjust==14) ips200_drawcross(14,200,RED,10);
}
}
}
识别动物水果代码:
import pyb
import sensor, image, time, math
import os, nncu
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.set_brightness(2000)
sensor.skip_frames(time = 20)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
clock = time.clock()net_path = "_qm_model_10_0.7857_7966.nncu"
labels = [line.rstrip() for line in open("/sd/labels_animal_fruits.txt")]
net = nncu.load(net_path, load_to_fb=True) #
while(True):img = sensor.snapshot()for r in img.find_rects(threshold = 50000): img.draw_rectangle(r.rect(), color = (255, 0, 0)) img1 = img.copy(r.rect()) # net.classify()for obj in nncu.classify(net , 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(labels, obj.output()), key = lambda x: x[1], reverse = True)for i in range(1):print("%s = %f" % (sorted_list[i][0], sorted_list[i][1]))
● 相关图表链接:
- 图 2.1.4 车模出发和返回进入车库
- 图 3.1 车模整体照片
- 图3.1.5 编码器的安装
- 图3.1.6 摄像头的安装
- 图5.2.1 5v供电
- 图5.2.2 3.3v供电
- 图5.2.3舵机供电模块
- 图5.3-1摄像头模块
- 图5.3-2 运放原理图
- 图5.4 电机驱动
- 图5.5 激光驱动模块
- 图6.1.1-1
- 图6.1.1-2
- 图6.1.1-3
- 图6.1.1-4
- 图6.1.1-5
- 图 6.2.4-1 环岛
- 图 6.2.4-2 环岛流程图
- 图6.1.11 AprilTag及动物水果的位置
- 图 6.1.11数字的位置
- 图6.1.11 识别到数字水果以动物
- 图 7.1 IAR软件
- 图7.2 示波器
- 图 7.3 调参页面