在嵌入式与人工智能交叉的竞赛领域,全国大学生智能汽车竞赛(简称“智能车竞赛”)一直被视为检验学生综合工程能力的试金石。第二十一届赛事中,一个名为“智慧医疗地瓜小车”的团队以专科院校身份斩获国赛一等奖,并以19秒的优异成绩完成赛道任务,成为一大亮点。这个成绩背后,远不止是“专科第一”的标签,更是一套从机械结构、硬件选型、控制算法到视觉识别深度融合的完整技术解决方案。
对于希望参与智能车竞赛,特别是“智慧医疗”这类创意赛项的开发者而言,理解如何将一个创意(如医疗物资配送)落地为稳定、高速、精准的竞赛平台,是核心挑战。本文将围绕“智慧医疗地瓜小车”这一获奖案例,深入剖析其技术实现路径。我们将从竞赛规则解读与任务拆解开始,逐步深入到硬件平台搭建、核心控制算法设计、视觉识别系统集成,最后完成系统联调与性能优化。文章旨在为后续参赛者提供一个可参考、可复现的技术框架,而不仅仅是展示结果。
1. 理解“智慧医疗”赛项:规则、任务与技术核心
“智慧医疗”是智能车竞赛中的创意组赛项之一,其核心是模拟医院场景下的自动化物流任务。参赛小车需要具备自主导航、物资识别、抓取与投放、以及应对复杂地形(如坡道、弯道、障碍)的能力。成绩评定通常综合任务完成时间、动作准确性和系统稳定性。
1.1 典型任务流程拆解
以常见的医院物资配送场景为例,一个完整的比赛任务流程可能包含以下环节:
- 启动与初始定位:小车从起点出发,可能需要识别起点标识或通过传感器确定自身初始姿态。
- 循迹导航:沿铺设的赛道(可能是电磁线、二维码、色带或视觉特征路径)行驶,这是智能车的基础能力。
- 目标识别与定位:行驶至“药房”或“病房”区域,通过摄像头识别特定的物资标识(如不同颜色的方块、数字、图形或AprilTag标签)。
- 机械臂操作:控制机械臂或抓取机构,准确抓取目标物资。这涉及运动学解算和精准的位置闭环控制。
- 物资转运与投放:携带物资行驶至“护士站”或指定投放区。
- 精准投放:将物资放入指定颜色的篮子或对应编号的格子里,可能要求姿态准确。
- 返回与结束:完成所有物资配送后返回终点或发出结束信号。
整个流程必须在无人干预下自动完成,任何环节的失误(如跑出赛道、识别错误、抓取失败)都会导致罚时或任务失败。
1.2 关键技术挑战与对应解决方案
| 技术挑战 | 具体表现 | 常见解决方案思路 |
|---|---|---|
| 高速稳定循迹 | 弯道甩尾、直道抖动、坡道打滑。 | 采用PID控制算法,结合编码器测速和陀螺仪进行姿态融合,实现速度与方向的解耦控制。 |
| 视觉识别实时性与准确性 | 识别延迟大、光照变化影响、目标遮挡。 | 选用轻量级神经网络(如MobileNet, YOLOv5-tiny)或传统图像处理(颜色滤波、轮廓查找),在嵌入式平台(如K210, OpenMV, Raspberry Pi + NPU)上部署。 |
| 机械臂精准控制 | 抓取位置偏差、抖动、运动轨迹不平滑。 | 使用舵机或步进电机配合PID位置环,预先标定运动学参数,采用点到点的轨迹规划。 |
| 多任务调度与状态管理 | 导航、识别、抓取等任务并行或顺序混乱。 | 设计基于状态机的系统框架,明确各状态间的转换条件和执行动作。 |
| 系统集成与调试 | 传感器干扰、电源噪声、各模块通信延迟。 | 采用模块化设计,统一通信协议(如UART, CAN),做好电源滤波与地线隔离。 |
“地瓜小车”能在19秒内完成复杂任务,必然在上述一个或多个挑战点上做出了优化。
2. 硬件平台设计与选型:打造可靠的“身体”
硬件是算法落地的基础。一个优秀的硬件平台需要在性能、功耗、重量、成本和可靠性之间取得平衡。
2.1 主控单元:系统的大脑
主控芯片负责传感器数据融合、控制算法执行、任务调度和决策。常见选择有:
- STM32系列(如F4, H7):在竞赛中经久不衰,资源丰富,生态完善,实时性强,适合做底层电机控制、传感器读取。但对于复杂视觉处理能力不足。
- ESP32系列:集成Wi-Fi/蓝牙,双核处理器,性价比高,适合需要无线通信或简单图像处理的场景。
- 专用视觉模块(如K210, OpenMV):内置视觉加速单元,能直接运行神经网络,专门处理图像识别任务,通常通过串口与主控通信。
- Linux单板机(如树莓派, NanoPi):计算能力强,可运行完整操作系统和复杂算法,但实时性需精心设计,功耗和体积较大。
“地瓜小车”可能的架构:采用“双核”或“主从”架构。一个STM32作为“下位机”,专责电机驱动、编码器反馈、陀螺仪数据读取和PID运算,保证控制的实时性和稳定性。一个K210或树莓派作为“上位机”,运行视觉识别算法,识别路径和物资目标,并通过串口向STM32发送指令(如“左转30度”、“前方发现红色物资”)。这种架构兼顾了实时控制与智能识别。
2.2 感知系统:小车的“眼睛”和“耳朵”
- 循迹传感器:
- 电磁传感器:检测通电线产生的磁场,抗光线干扰强,但路径固定。
- 摄像头:通过图像识别赛道边界(色带、虚线),灵活性高,可获取更多环境信息,是“智慧医疗”等创意组的主流选择。
- 红外对管/灰度传感器:简单可靠,成本低,但受环境光影响大。
- 姿态传感器:MPU6050(陀螺仪+加速度计)几乎是标配,用于进行传感器融合(如互补滤波、卡尔曼滤波),得到车身倾角和转向角速度,对维持高速过弯稳定性至关重要。
- 测速传感器:光电编码器安装在电机轴上,提供精确的车轮转速和行程反馈,是速度闭环控制的基础。
- 视觉识别传感器:全局快门摄像头(如OV7725)比卷帘快门摄像头在运动时果冻效应更小,识别更准确。
2.3 执行机构:小车的“手脚”
- 驱动电机:直流减速电机是最常见选择,需要关注扭矩、转速和减速比是否匹配小车重量和赛道需求。
- 电机驱动:TB6612、DRV8833等集成驱动芯片,比传统的L298N效率更高,发热更小。
- 转向机构:对于差速小车,通过左右轮差速实现转向。对于舵机转向小车,则需要一个伺服舵机控制前轮角度。
- 抓取机构:根据物资形状设计,可能使用舵机驱动的夹子、铲子或吸盘。舵机应选择扭矩足够、控制精度高的型号(如MG996R)。
2.4 电源管理:能量心脏
- 电池:常用2S或3S的锂聚合物电池(7.4V或11.1V),容量根据比赛时长选定(如2000mAh)。
- 电压转换:需要多路稳压电路(如LM2596, AMS1117)为不同模块提供稳定电压(如5V给舵机、摄像头,3.3V给主控和传感器)。电机驱动电源应与控制电路电源隔离,防止电机启停产生的电压波动干扰微控制器。
注意:在PCB设计或焊接时,电机驱动部分的大电流走线要足够宽,电源输入端和电机输出端最好并联大容量(如470uF)的电解电容进行滤波,这是避免单片机莫名复位的关键。
3. 核心控制算法:实现稳定与速度的平衡
控制算法是小车的灵魂,决定了它能否“跑得又快又稳”。
3.1 差速模型与运动学分析
对于两轮差速驱动的小车,其运动学模型是算法的基础。通过编码器获取左右轮的速度v_left和v_right,可以计算出小车的线速度v和角速度ω:
v = (v_right + v_left) / 2 ω = (v_right - v_left) / (轮间距)反之,给定期望的线速度和角速度,可以解算出左右轮的目标速度:
v_right_target = v + (ω * 轮间距) / 2 v_left_target = v - (ω * 轮间距) / 23.2 PID控制器的实现与调参
PID是控制领域的基石,在智能车上主要用在两个环路上:
速度环(内环):控制电机转速。输入是编码器测量的实际速度,输出是PWM占空比。保证小车能精确地按照指令加速、减速和匀速。
// 伪代码示例:增量式PID速度控制 float Speed_PID_Calculate(PID_TypeDef *pid, float target, float measure) { float error = target - measure; float increment = pid->Kp * (error - pid->last_error) + pid->Ki * error + pid->Kd * (error - 2*pid->last_error + pid->prev_error); pid->prev_error = pid->last_error; pid->last_error = error; return increment; // 返回PWM增量 }方向环(外环):控制小车沿赛道中心行驶。输入是摄像头或电磁传感器计算出的横向偏差(如中心线偏移像素值),输出是目标角速度或直接作为速度环的差分。
// 伪代码示例:位置式PID方向控制 float Direction_PID_Calculate(PID_TypeDef *pid, float error) { pid->integral += error; pid->integral = constrain(pid->integral, -pid->integral_limit, pid->integral_limit); // 积分限幅 float derivative = error - pid->last_error; float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; pid->last_error = error; return output; // 返回角速度或转向舵量 }
调参经验:
- 先内环后外环:先调好速度环,让小车能稳定跟随速度指令,再调方向环。
- 先P后I最后D:比例系数P决定响应速度,积分I消除静差,微分D抑制超调。
- 关注积分饱和:长时间存在误差会导致积分项过大,需设置积分限幅。
- 不同赛道段用不同参数:直道需要更“硬”的参数来保持直线,弯道可能需要更“软”的参数来平滑过渡。可以设计参数表,根据偏差大小或赛道元素动态切换。
3.3 传感器融合与姿态估计
仅靠编码器存在累计误差,仅靠陀螺仪存在零漂。通过互补滤波或卡尔曼滤波将编码器测得的角度(通过轮速积分)与陀螺仪测得的角度速度进行融合,可以得到更准确、更稳定的车身朝向角(Yaw)。
// 简易互补滤波示例 float angle_complementary_filter(float gyro_rate, float accel_angle, float dt) { static float angle = 0; // 陀螺仪积分得到角度(动态好,但会漂移) angle += gyro_rate * dt; // 用加速度计测得的倾角进行校正(静态准,但动态噪声大) angle = 0.98 * angle + 0.02 * accel_angle; // 权重系数可根据实际情况调整 return angle; }准确的姿态估计对于高速过弯时防止侧滑、以及实现“入弯减速、出弯加速”的优化策略非常有帮助。
4. 视觉识别系统:智慧医疗的“眼睛”
视觉系统负责解读环境,是完成“智慧”任务的关键。
4.1 图像采集与预处理
- 初始化摄像头:设置合适的分辨率(如QVGA 320x240)、帧率和曝光。分辨率太高处理慢,太低丢失细节。
- 图像预处理:通常包括:
- 畸变校正(如果镜头畸变明显)。
- ROI(感兴趣区域)裁剪:只处理图像中可能出现赛道的下半部分,提升处理速度。
- 颜色空间转换:从RGB转到HSV或Lab空间,使颜色分割更稳定。
- 滤波:使用高斯滤波或中值滤波去除噪声。
4.2 赛道识别(循迹)
对于基于色带的赛道,一种经典方法是:
# OpenMV 或 K210 上的示例思路 import sensor, image, time sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.skip_frames(time = 2000) while(True): img = sensor.snapshot() # 1. 转换为HSV空间 img_hsv = img.to_hsv() # 2. 根据赛道颜色阈值进行二值化 # 假设赛道是蓝色 blue_threshold = (30, 70, 10, 60, 10, 50) # (H min, H max, S min, S max, V min, V max) blue_blobs = img_hsv.find_blobs([blue_threshold], pixels_threshold=100, area_threshold=100) # 3. 寻找最大的色块,并计算其中心点 if blue_blobs: largest_blob = max(blue_blobs, key=lambda b: b.pixels()) img.draw_rectangle(largest_blob.rect()) img.draw_cross(largest_blob.cx(), largest_blob.cy()) # 4. 计算偏差:图像中心x坐标 - 色块中心x坐标 deviation = largest_blob.cx() - img.width()//2 # 通过串口将deviation发送给主控STM32 # uart.write(str(deviation)+'\n')更复杂的赛道可能包含交叉、环岛等元素,需要设计状态机来识别和处理。
4.3 物资目标识别
“智慧医疗”中的物资可能是不同颜色的方块、特定数字或AprilTag标签。
- 颜色识别:与赛道识别类似,通过HSV阈值过滤特定颜色,再通过形状特征(轮廓面积、宽高比、矩形度)筛选。
- 数字/字符识别:可以使用轻量级CNN(如TinyML模型)或模板匹配。在嵌入式端,通常需要预先训练并量化模型,然后部署。
- AprilTag识别:AprilTag是一种视觉基准系统,类似二维码,但更适用于远距离、小尺寸识别。有现成的库(如AprilTag3)可以输出Tag的ID和精确的3D位姿,对于机械臂抓取定位极其有用。
# AprilTag识别示例(需安装相应库) import sensor, image, time, math from apriltag import apriltag sensor.reset() sensor.set_pixformat(sensor.GRAYSCALE) # AprilTag识别通常用灰度图 sensor.set_framesize(sensor.QQVGA) # 分辨率可以低一些 sensor.skip_frames(time = 2000) detector = apriltag.Detector() while(True): img = sensor.snapshot() tags = detector.detect(img) for tag in tags: img.draw_rectangle(tag.rect()) img.draw_cross(tag.cx(), tag.cy()) print("Tag ID: %d, Center: (%d, %d)" % (tag.id(), tag.cx(), tag.cy())) # 还可以获取四个角点,用于计算距离和角度4.4 视觉与控制的协同
视觉识别结果需要转化为控制指令。例如,识别到物资在图像左侧,则控制小车向左微调方向;识别到AprilTag并计算出距离为30cm,则控制机械臂运动到对应坐标。这需要在上位机(视觉模块)中实现一个简单的决策逻辑,并通过串口协议与下位机(主控)通信。 一个简单的通信协议可以设计为:
[帧头][指令类型][数据长度][数据内容][校验和][帧尾]例如:0xAA 0x01 0x04 0xFF 0x00 0x14 0x00 0xXX 0x55表示“发现红色物资,位于X偏差=255(中心右),距离=20cm”。
5. 系统集成、调试与19秒优化策略
将所有模块组合成一个稳定可靠的系统,并优化到19秒的水平,是最后的攻坚战。
5.1 软件框架:状态机设计
一个清晰的状态机是复杂任务有序执行的关键。每个状态代表小车的一个行为模式,状态转移由传感器输入或时间条件触发。
typedef enum { STATE_START, STATE_LINE_TRACKING, STATE_FIND_TARGET, STATE_APPROACH_TARGET, STATE_GRAB, STATE_TRANSPORT, STATE_DROP, STATE_RETURN, STATE_FINISH } CarState_t; CarState_t current_state = STATE_START; void StateMachine_Run(void) { switch(current_state) { case STATE_START: if(检测到起点信号) current_state = STATE_LINE_TRACKING; break; case STATE_LINE_TRACKING: PID_LineTracking(); // 执行循迹 if(视觉识别到目标区域标志) current_state = STATE_FIND_TARGET; break; case STATE_FIND_TARGET: // 在目标区域缓慢移动并扫描 if(识别到特定物资) { current_state = STATE_APPROACH_TARGET; 记录目标位置信息; } break; // ... 其他状态处理 } }5.2 调试方法与工具
- 分段调试:不要一次性集成所有功能。先调通小车直行、转弯,再调视觉识别,最后调机械臂。
- 数据可视化:通过蓝牙、Wi-Fi或串口无线模块,将小车的关键数据(如偏差、速度、PID输出、识别结果)发送到电脑,用上位机软件(如SerialPlot、匿名地面站)绘制曲线,直观分析。
- 参数固化与存储:将调试好的PID参数、视觉阈值、机械臂坐标等存入单片机的Flash或EEPROM,避免每次上电重新设置。
- 日志输出:在关键函数和状态切换处添加日志输出,通过串口打印,帮助定位程序卡死或逻辑错误的位置。
5.3 向19秒冲刺:性能优化点
“地瓜小车”能达到19秒,必然在以下多个方面做了极致优化:
- 机械减重与重心优化:使用碳纤维、3D打印(轻质材料)结构件,降低小车质量。合理布局电池、主板等重物,降低重心,提升过弯稳定性。
- 动力与传动优化:选择合适减速比电机,确保直道有极速,弯道有扭矩。检查轮胎抓地力,必要时使用海绵胎或进行表面处理。
- 控制算法优化:
- 前瞻控制:视觉循迹时,不是看车头正下方的图像,而是看前方一定距离的“预瞄点”,使转向更平滑,允许更高的入弯速度。
- 速度规划:为整个赛道建立速度地图。直道全速,入弯前提前减速,弯心保持稳定速度,出弯提前加速。这需要精确的赛道元素识别(识别出前方是弯道)。
- 路径切割:在保证不冲出赛道的前提下,过弯时走内道,缩短总路径长度。
- 视觉处理优化:
- 降低分辨率与ROI:在保证识别率的前提下,使用尽可能低的分辨率和小的ROI。
- 算法轻量化:使用积分图、查找表等技巧加速传统图像处理。神经网络选择深度可分离卷积等轻量结构。
- 异步处理与流水线:图像采集、处理、通信可能放在不同线程或通过DMA进行,避免互相阻塞。
- 任务流程优化:
- 并行操作:在机械臂抓取物资的同时,小车可以开始缓慢转向对准下一个目标点。
- 动作去冗余:优化机械臂运动轨迹,减少无效行程。抓取和投放动作设计得干净利落。
- 起始策略:设计一个快速、精准的起步动作,抢出零点几秒。
6. 常见问题排查与竞赛心得
即使设计再完善,调试过程中也会遇到各种问题。
6.1 硬件与基础控制问题
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 小车启动后原地抖动或转向 | 电机线序接反;编码器A/B相接反;PID参数极性错误。 | 1. 单独测试每个电机正反转是否正确。 2. 抬起小车,观察编码器计数方向与轮子实际转向是否一致。 3. 检查方向环PID输出加到左右轮速度时的符号。 |
| 循迹时左右摇摆(振荡) | 方向环PID微分项D太小或为负;方向环比例项P过大。 | 1. 逐步增大微分项D。 2. 适当减小比例项P。 3. 检查传感器数据是否有噪声,增加软件滤波。 |
| 过弯时冲出赛道 | 速度过快;转向响应不足;重心太高导致侧翻。 | 1. 在弯道前增加减速逻辑。 2. 增大方向环P或D。 3. 降低车身重心,检查轮胎抓地力。 |
| 编码器计数不准或丢失 | 连接线接触不良;编码器供电不稳;软件去抖算法不佳。 | 1. 用示波器查看编码器脉冲波形。 2. 检查编码器电源电压,并并联滤波电容。 3. 在中断服务函数中增加去抖延时或硬件滤波。 |
6.2 视觉识别问题
| 问题现象 | 可能原因 | 排查步骤 |
|---|---|---|
| 识别不到赛道或目标 | 环境光照变化导致颜色阈值失效;摄像头焦距未调好;目标超出视野。 | 1. 在不同光线下重新标定颜色阈值,或使用自适应阈值算法。 2. 手动调整摄像头焦距,确保图像清晰。 3. 打印当前图像和二值化后的图像,观察处理结果。 |
| 识别延迟大,小车反应慢 | 图像处理算法过于复杂;串口通信波特率低或数据格式冗余。 | 1. 优化算法,减少循环和浮点运算。 2. 提高串口波特率(如921600)。 3. 精简通信协议,只发送必要数据。 |
| 识别结果跳动(抖动) | 图像噪声大;识别算法本身不稳定(如轮廓查找受干扰)。 | 1. 增加图像预处理中的滤波强度。 2. 对识别结果进行滑动平均滤波。 3. 增加面积、宽高比等形状约束条件。 |
6.3 系统集成与稳定性问题
- 问题:程序偶尔跑飞或复位。
- 排查:检查电源,电机启动瞬间是否导致电压骤降。用示波器观察单片机电源引脚波形。确保电机驱动电源与控制电源隔离良好。
- 问题:机械臂动作不精准。
- 排查:检查舵机供电是否充足(单独供电),舵机脉冲信号是否稳定。进行机械臂运动学标定,建立像素坐标到真实空间坐标的映射关系。
- 问题:任务执行顺序错乱。
- 排查:检查状态机的转移条件是否严谨,是否有遗漏的状态。增加调试信息,打印当前状态和触发转移的事件。
参加智能车竞赛,技术是基础,但团队协作、项目管理、文档撰写和临场调试能力同样重要。从“地瓜小车”的成功可以看出,即使在资源相对有限的条件下,通过对技术的深入理解、对细节的极致打磨和系统性的工程思维,同样可以在高水平竞赛中取得突破性成绩。对于后来者,建议尽早确定技术方案,留足调试时间,重视基础控制,再逐步叠加智能功能,最终实现速度、精度与稳定性的统一。