智能车竞赛实战:基于RISC-V与CMOS摄像头的嵌入式系统开发全解析
2026/9/6 0:06:12 网站建设 项目流程

1. 从赛道到代码:一场智能车竞赛的完整复盘

刚结束的第十六届全国大学生智能汽车竞赛,像一场持续了数月的技术马拉松,终于冲过了终点线。从最初拿到赛题规则时的茫然,到中期调车调参的焦头烂额,再到最后赛场上的惊心动魄,整个过程浓缩了嵌入式开发、自动控制、机器视觉和团队协作的几乎所有核心挑战。我所在的队伍选择了基础四轮组,主控芯片没有随大流用STM32,而是尝试了基于RISC-V架构的CH32V103R8T6,这让我们在硬件和底层驱动上多花了不少功夫,但也收获了更深入的理解。这篇总结,我想抛开那些官方的技术报告模板,从一个一线队员的视角,聊聊我们是怎么把一堆芯片、传感器和代码,变成一辆能在赛道上自主狂奔的智能车的。无论你是准备参赛的新手,还是对嵌入式AI小车感兴趣的爱好者,希望这些踩过的坑和总结的经验,能给你一条更清晰的路径。

2. 整体方案设计与核心思路拆解

2.1 赛题理解与组别选择背后的逻辑

第十六届的规则在继承经典元素的同时,也引入了一些新变化。比如基础四轮组,赛道元素更加复杂,增加了环岛、十字路口、坡道等组合,对路径识别的鲁棒性和控制算法的适应性提出了更高要求。我们选择基础四轮组,主要是基于团队技术栈的考量:摄像头图像处理是我们的强项,而平衡节能、双车接力等组别对机械、控制的要求维度不同。选择往往比努力更重要,在备赛初期,花时间吃透规则、评估自身团队在视觉、控制、机械、电路等方面的能力长短板,是决定后续所有工作方向的基础。

注意:不要盲目追求“热门”或“高端”组别。比如摄像头三轮组对图像处理和控制耦合要求极高,节能组对硬件能效和软件优化是极致考验。选择与团队核心能力最匹配的组别,才能最大化备赛效率。

2.2 “RISC-V+CMOS摄像头”核心架构选型

我们的硬件核心是CH32V103R8T6 MCU和一款全局快门的MT9V034 数字摄像头。选型理由如下:

  1. MCU:为什么是CH32V103R8T6?

    • 性价比与可控性:在芯片普遍紧缺和价格上涨的背景下,这款基于RISC-V内核的MCU提供了不错的性能(108MHz主频)和丰富的外设(ADC、定时器、DMA等),且价格相对稳定。更重要的是,其开发环境(MounRiver Studio)和底层库相对简洁,迫使我们去更深入地理解寄存器配置和时序,而不是过度依赖黑盒化的HAL库。这对于学习嵌入式本质是有益的。
    • 挑战与机遇:挑战在于社区资源远不如STM32丰富,很多驱动需要自己移植或从头编写。机遇也在于此,没有现成的“保姆式”代码,逼着我们搞清楚了从时钟树配置、GPIO初始化到中断优先级管理的每一个细节,这种能力在赛后看来是无价的。
  2. 传感器:摄像头 vs. 电磁?

    • 我们坚定选择了摄像头方案。虽然电磁方案受光线影响小,稳定性高,但摄像头方案的信息密度是碾压级的。它能识别赛道边界、中心线、元素(环岛、十字等),为控制算法提供前瞻性和预判能力。MT9V034全局快门可以有效避免果冻效应,在车体高速晃动时依然能获取清晰的图像,这是成功的关键。
    • 核心思路:将复杂的赛道环境,通过摄像头转化为二值化的图像矩阵,再从中提取出用于决策的“特征”——通常是左右赛道边界线。一切控制都基于这个抽象的“赛道模型”。

2.3 系统框架:从像素到电机PWM的信号流

我们的软件系统是一个典型的“感知-决策-控制”闭环,但具体实现上分层清晰:

[图像采集 (DMA)] -> [图像处理 (二值化,寻线)] -> [路径计算 (中线,曲率)] -> [控制决策 (PID, 状态机)] -> [执行输出 (电机PWM, 舵机PWM)]

每一层都通过清晰的接口(变量、结构体)耦合,方便单独调试和优化。例如,图像处理模块只负责输出一个包含左右边线位置的数组,控制模块不关心这个数组是如何得来的。这种模块化设计在后期调参时节省了大量时间。

3. 核心模块实现与关键技术细节

3.1 CH32V103R8T6的底层驱动构建

这是所有工作的地基。由于缺乏成熟的生态,我们相当于自己搭建了一个微型“操作系统”。

  1. 时钟系统配置

    • CH32V103最高可运行在108MHz。我们选择使用外部8MHz晶振,通过PLL倍频到96MHz作为系统主频。这一步需要在启动文件startup_ch32v10x.S和系统初始化函数中正确配置相关的时钟控制寄存器。
    • 关键点:必须确保为外设(如定时器、ADC、摄像头接口)分配的时钟源和分频系数正确,否则后续所有时序都会错乱。我们曾因为ADC时钟配置错误,导致采样值完全不可信,排查了大半天。
  2. GPIO与中断配置

    • 摄像头的数据引脚(D0-D7)、行场同步信号(VSYNC, HREF)需要配置为浮空输入模式,并开启上升沿/下降沿中断。
    • DMA应用:这是提升性能的关键。我们配置了DMA通道,将摄像头数据端口(GPIO组)直接搬运到内存中的图像缓冲区。在VSYNC(帧同步)中断中启动DMA,在HREF(行同步)中断中配合DMA完成一行数据的接收。这样CPU几乎不参与数据搬运,解放出来进行图像处理。
  3. 定时器与PWM生成

    • 使用高级定时器TIM1产生四路PWM,分别控制两个电机的正反转和速度(实际上用了两路PWM加两个GPIO方向控制,实现双极性驱动)。
    • 使用通用定时器TIM2配置为编码器模式,直接读取电机编码器的脉冲数,用于计算实际速度,构成速度闭环。
    • PID计算中断:另一个通用定时器TIM3被配置为固定频率(如1kHz)的中断,在这个中断服务函数中进行速度PID和方向PID的计算,并更新PWM占空比。中断优先级要合理设置,确保控制周期稳定。

3.2 图像采集与二值化处理优化

图像处理的速度和稳定性直接决定了车的上限。

  1. 稳定采集

    • 除了使用DMA,还要注意信号消抖。摄像头VSYNC和HREF信号在硬件连接较长时可能有毛刺。我们在中断服务函数入口添加了简单的延时判断,连续采样几次引脚状态,确认是稳定电平变化后才执行后续操作,避免了误触发。
  2. 动态阈值二值化

    • 固定阈值在光线变化时效果很差。我们采用了大津法(OTSU)自适应局部阈值
    • 大津法:在每帧图像开始处理前,对整帧或感兴趣区域(ROI)的灰度直方图进行计算,自动得出一个最佳分割阈值。计算量稍大,但全局效果稳定。
    • 自适应阈值:将图像分成若干小网格,对每个网格单独计算阈值(如取均值或中值)。这种方法对光照不均的赛道适应性更强。我们最终采用了网格自适应,因为赛场顶光往往会造成赛道中间亮、两边暗。
    • 优化技巧:不必对整幅图像(例如188*120)进行阈值计算。可以只对图像下方几行(车近处的赛道)和上方几行(远处的前瞻)分别计算阈值,既能适应光照变化,又减少了计算量。

3.3 赛道元素识别与状态机设计

识别出直道、弯道、十字、环岛等元素,是进行智能决策的前提。

  1. 边界搜索与中线提取

    • 采用经典的“爬边线”算法。从图像底部中心开始,向左向右搜索黑白跳变点,作为初始边线。然后逐行向上,以上一行的边线位置为起点进行小范围搜索,得到当前行的边线。将所有边线点拟合成两条曲线,其中间线即为引导线。
    • 丢线处理:当某一行搜索不到边线时,不能简单停止。我们采用“记忆外推”策略,用之前几行边线的斜率或曲率,预测当前行的可能位置,扩大搜索窗口。如果连续多行丢线,则触发“丢线状态”,控制策略切换到保守模式(如减速、按上一有效曲率转向)。
  2. 元素识别逻辑

    • 十字路口:当左右边线同时大幅向外发散,且中间区域在一定行数内持续为白色(赛道色)时,判定为十字。我们的策略是进入十字后,保持进入前的角度和速度直行通过,同时抑制边线搜索,防止误搜到十字的横向边线。
    • 环岛:这是难点。我们通过识别边线的“突变”来判断环岛入口。当单边边线(例如右边线)突然向内凹陷(形成弧口),而另一边线相对正常时,初步判定为环岛入口。随后进入一个专门的“环岛状态机”。
    • 环岛状态机设计
      • 状态1(进入):识别到入口特征,开始记录内侧边线轨迹。
      • 状态2(循迹):不再跟踪外侧边线,而是以识别到的内侧弧线作为单边引导线,同时结合陀螺仪(MPU6050)的Z轴角速度积分,判断车身是否已绕行约270度。
      • 状态3(出岛):当角度积分达到预设值,且图像重新出现正常的双边线时,切换回普通循迹模式。
      • 关键:出岛判断必须图像和陀螺仪数据融合,单靠任何一个都容易出错(提前出岛或卡在岛内)。

3.4 控制算法:PID与更高级的策略

  1. 双闭环PID控制

    • 速度环(内环):输入是目标速度(由路径曲率映射得到:弯道慢,直道快)和编码器反馈的实际速度,输出是电机PWM。使用PI控制器即可,积分项能消除静差,但要注意积分饱和,需要做抗饱和处理。
    • 方向环(外环):输入是期望路径的横向偏差(中线与图像中心的偏差)和偏差变化率,输出是舵机目标角度(或直接是舵机PWM)。使用PD控制器。微分项能预测偏差趋势,让转向更平滑,抑制过冲。
    • 参数整定心得:先调方向环,再调速度环。在车静止时,用手推动小车产生横向偏差,观察舵机能否快速、无超调地将车轮回正。然后低速在直道上跑,微调参数使车能沿直线行驶。最后上弯道,重点调整微分系数,抑制振荡。
  2. 前瞻与曲率预瞄

    • 简单的偏差控制是“滞后”的,因为它基于车当前位置的误差。我们引入了“前瞻点”概念。从图像中线上选取一个距离车头一定距离的点(例如图像顶部往下20行),计算该点与图像中心的横向偏差。用这个前瞻偏差来控制舵机,相当于让车提前转向,过弯更加流畅自然。
    • 曲率计算:通过拟合出的中线,计算其曲率。曲率可以直接映射为目标速度(大曲率->低速),也可以作为前馈量加入到方向环控制中,实现“弯道提前打舵”。

4. 系统调试与性能优化全记录

4.1 开发调试环境搭建

  1. 硬件调试器:我们使用WCH-Link通过SWD接口对CH32V103进行程序下载和在线调试。MounRiver Studio内置的调试功能基本够用,可以查看变量、设置断点。
  2. 软件调试“后门”
    • 无线串口:在车上加装一个蓝牙串口模块(如HC-05),将关键数据(如图像行数据、边线位置、PID输出、状态机状态)实时发送到电脑上位机。
    • 上位机软件:我们基于Python的PyQt5和OpenCV自己编写了一个简单的上位机。它能绘制出摄像头看到的二值化图像、提取的边线、计算出的中线,并以波形图形式显示速度、偏差等数据。这是调试效率提升十倍的关键。你可以直观地看到车“眼中”的世界,以及控制算法是如何理解的。
    • 参数在线调参:在上位机中制作滑动条,通过无线串口动态修改车上的PID参数、阈值等,并立即观察效果,避免了反复修改代码、编译、下载的繁琐过程。

4.2 机械结构与参数调校

“软件决定上限,机械决定下限。”再好的算法,如果车装得歪歪扭扭,也跑不好。

  1. 重心与陀螺仪安装:电池、主板等重物尽量放低、居中。MPU6050陀螺仪模块必须用海绵胶牢牢固定在车体中心,并与车身轴线平行,避免振动干扰。
  2. 前轮前束与主销内倾:对于舵机转向的车,前轮通常设置为微小的“内八字”(前束),这有助于提高直行稳定性。这些微调需要耐心,每次只动一点,然后上路测试直行是否跑偏。
  3. 轮胎处理:新轮胎表面光滑,抓地力不足。我们用细砂纸轻轻打磨轮胎表面,增加摩擦力。胎压也要一致,不能一软一硬。

4.3 代码级优化技巧

当算法逻辑正确后,优化就是为了跑得更快。

  1. 减少计算量

    • 缩小ROI:车在高速运行时,远处图像细节来不及处理。我们动态调整图像处理的行数,车速越快,处理的图像行数越少(只关注近处赛道),保证控制周期稳定在5ms以内。
    • 查表法:将一些频繁计算的结果预先算好,存入数组。例如,atan2sqrt函数非常耗时,我们可以根据偏差和偏差变化率,预先计算一个PD控制量的二维查找表。
    • 整数运算:在MCU上,浮点运算速度远慢于整数运算。我们将所有PID参数、误差等变量都乘以一个放大系数(如1024),用int32_t类型进行整数运算,最后输出时再缩小。精度完全足够。
  2. 提高系统稳定性

    • 看门狗:一定要开启独立看门狗(IWDG)。在main函数循环和关键任务中定期“喂狗”。一旦程序跑飞或陷入死循环,看门狗能复位系统,至少让车停下来,而不是撞毁。
    • 堆栈大小设置:在启动文件中适当调大堆栈(Stack_Size)。复杂的函数调用和局部变量可能造成栈溢出,导致各种难以复现的诡异错误。

5. 赛场实战问题排查与应急方案

无论实验室跑得多好,赛场永远是另一回事。以下是我们遇到和观察到的高频问题:

问题现象可能原因排查步骤与解决方案
发车后原地不动或抽搐1. 电机驱动桥未使能或损坏。
2. 编码器接线松动,速度反馈为0导致PID输出异常。
3. 程序未正常进入主循环。
1. 检查电机驱动芯片的使能引脚电平,测量电机两端电压。
2. 晃动编码器接线,在调试器查看编码器计数值是否变化。
3. 检查启动代码,添加LED闪烁指示,确认程序运行。
直道左右摇摆(振荡)1. 方向环PID微分系数D太小或为负。
2. 机械松动,舵机连杆有虚位。
3. 图像处理延时过大,控制滞后。
1.首要降低P值,增加D值。D是抑制振荡的关键。
2. 用手轻轻晃动前轮,检查是否有松动。
3. 通过上位机查看从图像采集到舵机输出的总延时,优化代码。
过弯时冲出赛道1. 弯道速度过快。
2. 前瞻距离设置太短,转向不及时。
3. 图像在弯道丢线,策略未正确处理。
1. 建立曲率-速度映射表,弯道曲率越大,目标速度越低。
2. 增加前瞻点距离,让车“看得更远”。
3. 加强弯道处的丢线处理逻辑,如使用预测线。
元素(十字、环岛)误识别或漏识别1. 光线变化导致二值化阈值失效。
2. 元素识别条件阈值设置不合理。
3. 车体经过元素时姿态不稳定,图像抖动。
1. 必须使用动态阈值。
2. 在赛场不同光照下大量测试,记录数据,调整识别条件的阈值(如白色连续行数、边线发散角度)。
3. 在元素识别期间,适当降低速度,提高图像稳定性。
跑着跑着突然复位1. 电源不稳定,电压跌落触发欠压复位。
2. 程序堆栈溢出。
3. 看门狗未及时喂狗。
1. 用示波器监测电池电压,大电流负载时是否跌落到MCU最低工作电压以下。加大电容稳压。
2. 增加堆栈大小,检查是否有大型局部数组。
3. 检查看门狗喂狗函数是否在所有可能的主循环路径中都被调用。
无线调试突然断开1. 赛场无线环境复杂,2.4GHz频段干扰。
2. 蓝牙模块供电不足。
1. 准备备用方案:将关键数据通过IO口输出到逻辑分析仪,或使用SD卡离线记录数据。
2. 为蓝牙模块单独使用LDO供电,避免电机启动时拉低电压。

赛场最后24小时检查清单

  1. 硬件:所有螺丝点胶固定;所有线缆用扎带或热熔胶固定,避免松脱;电池电量满格,电极片用酒精擦拭干净;轮胎清洁无灰尘;传感器镜头擦拭干净。
  2. 软件:准备多个版本的固件(激进速度版、稳定完赛版);确认拨码开关或按键可以切换版本;将最重要的PID参数、速度映射表放在易修改的位置(如通过按键加减调整)。
  3. 心理:制定比赛策略。前一两圈求稳,确保完赛拿到基础成绩。后面几圈再尝试逐步提升速度。永远把稳定性放在速度前面。

回顾整个备赛过程,最大的收获不是奖状,而是这套从问题定义、方案设计、模块实现、集成调试到现场排错的完整工程实践能力。选择CH32V103让我们被迫深入底层,虽然过程痛苦,但回过头看,那些对着数据手册调寄存器的夜晚,才是真正理解嵌入式系统如何工作的时刻。智能车竞赛就像一个微缩的机器人项目,它教会你的,远不止如何让一辆小车跑起来,而是如何让一个复杂的软硬件系统可靠、智能地工作。如果再来一次,我可能还是会选那个“麻烦”的RISC-V芯片,因为你知道,你吃透的每一点,都是别人拿不走的资本。最后一个小建议:尽早开始做“系统集成”,不要等每个模块都完美了再拼起来。车只有跑起来,你才知道真正的问题在哪里。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询