设计一款完全自主运行的玩具汽车,使其能够自主探索环境、避开障碍物,并能进行实时决策
扫描二维码
随时随地手机看文章
我们的团队利用树莓派 5 开发了一款自主式遥控汽车,该车具备车道保持功能,通过闭环光学编码器驱动器保持恒定速度,并会在沿着赛道设置的红色纸制“停止标志”处自动停车。该车使用 USB 摄像头进行视觉识别,使用 OpenCV 进行车道检测,使用定制的 Linux 内核模块(利用 gpiod)进行编码器计时,并使用 PD 控制器进行模拟转向。这项工作借鉴了用户 raja_961 的 Instructable 文章“使用树莓派和 OpenCV 的自主车道保持汽车”,以及我们在文中多次提及的 Hackster 上的先前 ELEC 424 项目。
设计流程
1. 让相机正常工作
我们面临的第一个挑战是将摄像头配置为在 Pi 5 上进行实时处理。我们使用了一个安装在汽车上的 USB 摄像头,并通过 OpenCV 将拍摄分辨率设置为 320×240,这样既能保证帧率又能保持图像细节的最佳平衡。更高的分辨率会导致控制循环的响应速度不够快,从而引入过多的处理延迟。感兴趣区域被裁剪为每帧的下半部分,因为车道标线始终位于汽车正前方的地面之上,而高于中间点的部分都是噪音。在运行过程中,我们通过 SSH 并使用 X 转发将车道检测覆盖层和航向线传输到笔记本电脑上,这对于调试非常有用,无需将显示器连接到汽车上。
2. 让汽车保持直线行驶
我们为转向系统采用了 PD 控制器,将车道检测得到的角位移误差映射到 6% 至 9% 之间的转向占空比范围内,其中 7.5% 为直线行驶状态。我们起初使用较小的比例增益和零导数增益,然后逐渐增加 Kp 直至车辆开始左右摇摆。之后我们引入 Kd 来抑制这种摇摆,最终确定 Kp = 0.02 和 Kd = 0.08。我们通过每帧记录误差、P 响应和 D 响应,并在每次运行后查看所得图表来验证这些值。
3. 《阅读之路》
将相机画面转换为可用的转向角度时,每个画面都会转换到 HSV 颜色空间,并通过掩码处理来分离出蓝色的油漆带,其色调范围设定为 90 到 130。该掩码会通过坎尼边缘检测来确定油漆带的边界,然后 OpenCV 的 HoughLinesP 函数会从画面的下半部分提取线段。根据线段的斜率和水平位置将其分为左侧和右侧的候选线段,然后将每侧的线段平均为一条直线。这些平均线的 x 坐标在图像区域的顶部估计出车道中心,而该中心相对于画面中点的角偏移量则成为控制转向控制器的误差值。
4. 保持稳定的节奏
速度控制通过一个定制的 Linux 内核模块来实现,该模块会在连接到光学编码器输出的 GPIO 引脚上注册一个中断。每次下降沿都会触发中断处理程序,该程序使用 ktime_get() 来记录事件时间,并计算自上一次脉冲以来的间隔时间。一个 2 毫秒的去抖动阈值可过滤掉编码器槽中的噪声。所得的间隔时间会作为模块参数暴露给用户空间,位于 /sys/module/op_encoder_driver/parameters/last_interval_ns,主 Python 脚本会每帧读取该参数。如果测量的周期超过 50,000,000 纳秒的目标值,节流占空比就会被略微提高;如果低于该值,则会将其略微降低。在启动时,ESC 通过发送 10% 占空比的高信号持续 2 秒,然后发送 5% 的低信号持续 2 秒,最后回到中立位置来校准,这会设置 ESC 预期的 PWM 范围并产生两次确认的哔声。
5. 懂得何时停止
停止标志检测使用与车道检测相同的 HSV 流程,不过这次是针对红色而非蓝色进行遮蔽处理。由于红色在 HSV 颜色环中是环绕分布的,所以需要结合两个遮蔽区域——一个用于低色调(0 到 10),另一个用于高色调(170 到 180)——并且只计算画面底部一半的像素,因为停止标志纸直接放置在汽车正前方的地面上。检测仅每隔三帧运行一次,以避免影响车道保持性能。如果红色像素计数超过 2000 的阈值且无冷却时间激活,则记录一个停止事件。在第一个停止标志区域,汽车会暂停三秒钟,然后在 60 帧的冷却时间内恢复行驶,以防止立即再次触发。在第二个停止标志区域,汽车会永久停止,并通过一个保证清理的块使 ESC 重新回到中立位置。
我们的车辆
统计图
本文编译自hackster.io





