开发平台: NXP
许可协议: GNU General Public License, version 3 or later (GPL3+)
项目简介 自动驾驶汽车开始统治世界。所以让我们试着做我们自己的赛车!   项目中使用的工具物品 硬件 FRDM-K64F 带驱动器的齿轮步进电机 微伺服器 Alamak 车模 定制PCB 激光接近传感器 许多不同的SMD和非SMD组件(您可以在本文的底部找到下载列表) 4N25 光耦合器   软件、App和在线服务 MCUXpresso (MCUXpresso-IDE) Processing   手工工具和制造器械 3D 打印机 螺丝刀 焊接工具(最好是空气焊接工具)   故事 我们已经从上一个赛车比赛中获得了一些知识,所以我们决定做一些更困难的事情。所以我们将会制作一个新的主板,伺服电机上的摄像头,蓝牙通讯等等。   摄像头 这是整个车辆中最重要的部件。摄像机用于车辆在两条轨道边缘线之间的导航。甚至在法规中都规定摄像机应该是汽车导航的主要用途。我们使用的是单色线扫描相机,这意味着我们的相机只能看到一行黑色,灰色和白色像素,因为单色线扫描相机的分辨率为128x1。这种低分辨率可以通过尽可能的高的光谱速率和良好的光敏性来补偿。 在一年前的比赛中,我们发现了两个问题。首先,光线不仅来自相机的正前方,也来自相机的后方。这是因为相机芯片被放置在薄薄的PCB板上,让光线通过。所以为了解决这个问题,我们3D打印了黑色相机外壳,现在它看起来更酷炫了! 第二个问题是,我们把相机上下移动了很多次来找到正确的位置,使其在捕捉正确的转弯的同时不捕捉汽车的车身。我们在移动的过程中同时发现,不同类型的轨道的最佳位置不同。 下一个问题也是这样,如果我们不小心撞到相机,我们重新移动来找到正确的位置。所以我们增加了齿轮比为1:2的步进电机,使我们的相机能更快的移动。同时,可以在图中看到,我们添加了end Switch,这是因为伺服电机系统本身并不提供任何关于其初始位置的信息。当我们的汽车启动时,我们必须手动把它移到触碰末端开关的位置。从那一刻起我们就知道相机的摄影区间。 在这里,你可以看到所有3D打印部分的3D渲染(图中只有黑色细杆不是3D打印的) 接下来,让我们详细看一下硬件和软件。我们的目标是在一秒内捕获尽可能多图像的同时保持良好的对比度。因为如果对比度不合适,则会出现要么图像太暗看不到图片上的任何东西的情况,要么是图像太亮同样也看不到任何东西,但在这种情况对比度不合适的情况下,所有的物体都是白色的。此外,我们不能让我们的曝光时间太长,因为这会限制我们的帧率。帧率的计算公式为: 帧率= 1 /曝光 通过归一化值可以部分地解决这些问题。假设我们有值为0的黑色和值为1的白色。我们取过饱和图像,其最低值为0.8,最高值为1,这给出了<0.8,1>的值范围,我们要将其映射为<0,1>。这样我们的颜色从0.8变为0;0.9~0.5;以及从1到1。通过这个非常简单的过程,我们得到了没有饱和度的正常图像,但是这也会给图像带来大量的噪声,使得搜索线条变得非常困难。如果我们在场景中添加25%的光照,那么捕获的图像将进入<1,1>范围,我们将无法从中提取任何数据,甚至包括噪声数据。 那么,让我们回到如何正确的设置曝光这一步骤。我们的目标是实现最大的对比度。对比度的计算公式如下: 对比度=浅颜色-深颜色 当最浅的颜色是纯白,而最深的颜色是纯黑时,我们获得了最大的对比度。我们的相机是线性传感器,所以这意味着如果我们增加50%的曝光,那么最暗值和最亮值都应该增加50%。我们的目标是得到平均颜色0.5。考虑下面的例子<0,0.1>,这些值的平均值太低(10x),所以我们需要将曝光量除以0.1;<0,1>平均值是0.5,这完全没问题,我们什么都不用变;<1,1>平均值太高(2x),所以我们将曝光除以2。在此基础上,我们可以建立以下公式来调整曝光。 新曝光率 = 旧曝光率 / (最浅色 + 最深色) 这样调整之后,一切就绪。可以实现。 无论你的车去任何地方,色彩看起来都挺不错。最低限度是当你进入一个不是靠太阳而是靠荧光灯或其他东西照明的房间之前。你会开始看到一个巨大的闪烁,即使当灯光像往常一样照耀你的眼睛。为什么会这样呢? 我们的灯是由交流电供电的,它跟随50赫兹频率的正弦。如下所示(x轴以秒为单位): 您可以看到灯是在50 Hz下运行,但峰值在100 Hz。同样,对于光来说,真正重要的不是电压,而是功率,它看起来是这样的:  //原文中缺一张图片 我们现在可以非常清楚地看到实际是100赫兹。那么如何修复这个问题呢?我们需要使采样频率与电源频率同步,因此只有100,50,25,...Hz才是可行的频率。但是我们希望保持在尽可能高的频率,因为这些线条真的很重要,如果我们不高频拍照,我们很容易错过它们。但较低的频率(如50 Hz)在弱光情况下是有用的,在弱光水平下,我们需要曝光超过10ms。 所以让我们看看如何实现这个功能。我们将需要采取帧每10ms的速率曝光。但随之,我们在这里遇到了新的问题。帧捕获的开始和结束连接在一起成为单个事件。  //原文缺一张图片 如图所示,我们发送SI脉冲,并通过发送CLK脉冲逐个读取像素数据。但正如您在图片中看到的,在读取图像的18个像素后,将开始新的积分(图像捕获),我们希望这个步骤在更长时间后进行(前一幅图像的积分耗时6ms,我们希望保持同步在10ms,因此我们像多等待4ms)。我们可以通过虚拟读取清除CMOS来解决这个问题(忽略内容,并尽可能快地进行读取)。最终结果如下:我们对图像进行6ms积分,然后在新积分开始后读取并处理图像,因此在4ms后读取传感器,但忽略数据。在这之后,真实图像的长度为6ms的新的积分开始了。 当然,也有可能用更好的灯光照亮赛道。有有电容器些灯可以减少这种闪烁,或者他们可以储存一段时间一些能量的热和光。那么光动力就会是这样的:  //缺一张图片 或者它可以只是在阳光下,所以它将是完美的线条。当我们像这样得到足够稳定的光输出时,我们可以移除代码来修复闪烁,并尝试得到100fps以上。但是当赛程出现在我们不知道的环境中,我们应该一直围绕着这段代码。 让我们看看如何编程。K64F有四个可供选择的凹面,凹面代表可编程中断控制器。这是一个非常简单的设备,可以设置时间段选择触发中断。中断通常是一个小函数,它不被其他代码执行,而是由中断控制器执行。凹面是一种能够中断当前代码的执行,保存当前代码的状态,并在某些事件发生时执行一些中断功能的设备,如我们将凹面等待时间设置为等待时间。 我们的照相机需要两个凹面。一个用于10ms清除间隔,另一个用于设置积分间隔。 让我们看一下中断处理程序的示例代码: extern "C" { void PIT_CHANNEL_0_IRQHANDLER(void) { if(PIT->CHANNEL[0].TFLG & PIT_TFLG_TIF_MASK) { PIT->CHANNEL[0].TFLG = PIT_TFLG_TIF_MASK; // interrupt code goes here } } 首先我们需要编写的是外部的“C”,因为C++不遵循传统的低级代码实践,这会使我们很难找到中断函数。将其还原为旧的C模式可以使一切正常工作。然后是函数声明,它总是必须具有void参数的void返回类型,因为此函数不返回任何值,也不接受任何值。通道设置使用哪个凹点,在本例中我们使用的是PIT0。该函数做的第一件事是检查它是否被中断执行,如果不是,则退出。如果是,则清除中断标志。此标志使中断控制器触发此中断,如果该中断不被清除,则将以无休止的中断循环结束。后面是我们真正的中断代码。 现在我们需要看看如何从得到的图像中检测线条。我们正在寻找旁边有白色区域的黑线。我首先考虑了阈值和搜索区域,但是效果不是很好。我发现的最好的方法是使用派生,派生当黑白变化时给出峰值。派生效果不错,但要实现最佳检测质量,我们需要使用平均值。一开始有人可能会想到,这样做的方法是对相邻的导数求平均,但这是行不通的。原因如下: Derivation = (Der1 + Der2 + Der3)/3 此等式等于下一等式: Derivation = ((P1-P2)+(P2-P3)+(P3-P4))/3 当我们简化它时,可得到: Derivation = (P1-P4)/3 这并不能让我们摆脱噪音。所以我决定尝试不同的方法。对第一组像素进行平均,然后对第二组相邻像素进行平均,并对这些组的平均值进行推导: Derivation = (P1+P2+P3)/3 - (P4+P5+P6)/3 如果结果接近0,那么就意味着不可行。如果结果远离零,那么就意味着某处有线。基于派生是正还是负,我们就可以检测它是从白变黑还是从黑变白。 步进电机 步进电机采用4路信号A,B,C,D控制。每一个步进电机控制一个线圈。我们使用的是电机28BYJ-48,这是最好的半步工作模式,你可以在下面的图片上看到。也有全步模式。尝试之后感觉全步模式比半步模式表现更差。半步模式由8种不同的ABCD组合组成(您可以看到图像上的所有内容在8次分割后重复),而半步模式仅使用4种组合。电机通过从左向右发送脉冲而向前移动,通过从右向左发送脉冲而向相反方向移动。 当汽车启动时,电机的位置取决于汽车停机前电机的位置。但是用这种方法得到位置精确,因为有人可能会用手对电机施加足够大的力使其移动到不同的位置,而且这种位置节省会慢慢地破坏控制器的闪存。因此,最好的方法是在汽车行李箱处向下移动相机的方向发送这些脉冲,并且在每次移动时检查相机是否击中了末端开关(即安装在相机下面的小开关,它定义了相机的最低位置,也必须知道相机击中开关的角度,这样我们就可以进行所需的所有计算)。当相机按下结束开关后,开关闭合并向外微控制器发送信号,步进器停止移动,并表示我们现在处于位置0,也就是开始位置。    保险杠 我们从一年前学到的经验是保险杠非常重要。我们曾多次与墙壁和各种物体相撞,这几乎完全撞坏了我们的车。所以这一次我们增加了一个软管保险杠,软管和巨大的3D打印块相连。我们也把软管当作激光保持器。软管能够吸收部分碰撞,其余部分通过巨大的块转移到我们的车,所以碰撞不是仅靠车的边缘来处理的。 这里是保险杠的3D渲染,你可以看到它真的很巨型,它还包括激光支架。 激光 避障是一个必须的功能。为闪避放入轨道的白色立方体。我们的计划用激光找到这个障碍物,激光会用伺服电机绕着白色立方体旋转。这第一步,会准确的发出障碍物靠近时的信息,但是不能给出完美的位置。在我们找到障碍物后,我们将使用相机和步进电机正确地扫描它的位置。 为了使该部分正常工作,需要直接连接到电池以获得最大电压。...

继续阅读完整内容

支持我们的网站,请点击查看下方广告

正在加载广告...