尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

智能车竞赛三年实战经验:硬件选型、PID调参与状态机设计

智能车竞赛三年实战经验:硬件选型、PID调参与状态机设计 打开电脑里以“26”命名的工程文件夹时我愣了一下。从大二第一次碰直立车模到如今准备最后一场国赛三年时间几十个版本的代码、十几块烧坏的板子、好几个通宵的调试夜都压缩在这个小小的目录里。第六届、第七届、第八届我的智能车生涯终于走到了最后一届。这篇文章不是抒情散文而是我三年备赛过程中踩坑最多、最想让后来人避开的工程经验总结涉及整车架构、传感器标定、PID调节、状态机决策、技术报告写作和赛前风险控制。无论你是第一次组队的新人还是已经进入国赛冲刺阶段的队伍希望这份手册能让你少走一些弯路。1. 智能车竞赛到底比的是什么1.1 一场介于课程设计与真实嵌入式开发之间的比赛全国大学生智能车竞赛的赛题年年变化但核心始终只有一个让车模在未知赛道上尽快、尽可能稳定地跑完一圈。它不像单纯的理论考试更像一个完整的小型嵌入式项目——你需要考虑硬件选型、传感器数据处理、控制算法、电源稳定性、机械结构甚至还有团队协作和时间管理。从比赛分组来看常见的有摄像头组、电磁组、越野组、独轮组等。摄像头组依靠图像识别赛道元素速度上限高但受光线影响明显电磁组更依赖模拟信号处理抗干扰能力是关键越野组则更考验车辆的机械强度和动力系统的可靠性。不同组别的技术栈差异很大但底层的控制思想、调试方法论是通用的。1.2 最后一届视角为什么说智能车值得投入很多同学问我智能车竞赛耗费大量时间值不值得。我的答案是如果只是冲着加分和保研去你会很痛苦如果你是把它当成一个真实的工程项目去对待它会让你提前理解“系统”而不是单个知识点。你会在一个赛季里同时接触到 MCU 外设、传感器、控制理论、电路设计和项目管理这种综合性训练是普通课程设计替代不了的。到了我的最后一届我更深刻体会到智能车最大的价值不在于那张证书而在于你被迫建立起来的工程直觉知道什么时候该调参什么时候该重写什么时候该果断放弃一个方案。2. 赛前硬件选型与整车架构搭建2.1 车模与主控芯片的选择逻辑车模的选择建议直接根据官方规则来一般每个赛季都会指定车模型号比如常见的 C 车模、B 车模、L 车模。这里要特别提醒一点不要等到规则明确后再准备硬件可以先用上一赛季的车模做算法预研等新规则出来后再针对性地调整机械结构。主控芯片方面近几年的趋势是恩智浦的 TC264 / TC377、ST 的 STM32H7 系列。选择主控时要重点考虑以下几点是否有足够的硬件外设ADC 通道数、定时器、DMA、摄像头接口。社区资料是否丰富遇到问题能否快速查到解决方案。是否支持浮点运算这会直接影响 PID 算法的执行效率。调试工具是否方便比如是否支持 J-Link、DAP-Link。以我常用的 TC264 为例它主频高、外设丰富非常适合摄像头组的需求。不过要注意TC264 的很多外设配置和 STM32 差异较大第一次上手时建议先跑通官方例程再逐步修改。2.2 传感器方案与整车布局传感器是智能车的“眼睛”和“耳朵”。摄像头组常见的是总钻风摄像头MT9V034它输出灰度图像适合做赛道元素识别电磁组则使用工字电感或空心电感采集赛道中心的电磁信号。整车布局上有几个容易忽略的点电池尽量放在车模中央偏后的位置降低重心减少过弯时侧倾。摄像头高度要合适太高会拍到赛道外信息太低则无法看到远处弯道。编码器要安装稳固避免打滑或松动否则速度环会出现低频抖动。所有线束都要做防拉处理赛场上最常见的翻车原因之一就是线束松动。下面是一个典型的摄像头组整车结构示意[摄像头] | [主控板 电源模块] | [舵机] --- 前轮转向 | [编码器] --- [电机驱动] --- 后轮2.3 电源系统的稳定性设计电源是整个车模最容易出问题但最容易被忽视的环节。电机瞬间启动电流很大如果电源纹波过大会导致单片机复位、摄像头图像花屏甚至舵机抖动。我的经验是电机驱动电源和逻辑电源分开走线尽量使用 DC-DC 模块给主控供电而不是直接从电池两端取电。同时在主控电源入口加一个 100uF 电解电容和若干个 100nF 陶瓷电容用于滤除低频和高频噪声。调试阶段一定要用示波器观察供电电压波形不要等到现场才排查。这里特别强调修改电路后要先在测试台上跑 30 分钟以上确认电源稳定后再上车测试。3. 软件开发环境与工程化管理3.1 开发工具链推荐相比硬件选型开发工具链往往被新队伍忽视。智能车主控开发常用以下工具组合集成开发环境AURIX Development Studio简称 ADS用于 TC264/TC377Keil/IAR 用于 STM32。下载调试器J-Link 或 DAP-Link。串口调试助手用于在上位机上实时观察传感器数据和 PID 输出。版本管理工具Git Gitee/GitHub 私有仓库。这里强烈建议队伍从一开始就使用 Git 管理代码。智能车代码迭代非常快经常会出现“今天改了一版跑得没昨天好”的情况没有版本管理就只能凭记忆回退浪费大量时间。3.2 代码目录结构规范很多队伍的比赛代码就是一个大 main.c几千行堆在一起最后连自己都不敢改。我的建议是至少在赛季中期把代码按模块拆分smart_car/ ├── application/ │ ├── main.c // 入口初始化外设 │ ├── control_task.c // 控制任务周期性调用 │ └── decision_task.c // 赛道元素状态机 ├── drivers/ │ ├── motor.c // 电机 PWM 输出 │ ├── servo.c // 舵机控制 │ ├── encoder.c // 编码器读取 │ └── camera.c // 摄像头配置与图像采集 ├── modules/ │ ├── filter.c // 滤波算法 │ ├── pid.c // PID 控制器 │ └── speed_planner.c // 速度规划 ├── algorithm/ │ ├── image_process.c // 图像处理 │ └── element_detect.c // 元素识别 └── config/ ├── pin_config.h // 引脚映射 └── control_config.h // 控制参数这样的结构虽然前期会多花一点时间但到了后期调参和移植时会节省大量时间。每次改动只涉及对应模块不会牵一发动全身。3.3 调试信息的打印与日志智能车调试的本质是“数据可视化”。如果看不到传感器数据调参就全靠猜。建议在串口调试助手中实时打印以下信息当前车速编码器换算后目标速度速度规划输出赛道偏移量摄像头或电磁计算得到PID 三项输出值当前状态机所处的元素状态有了这些数据你才能准确地定位问题是传感器噪声大还是 PID 参数不合适还是状态机跳转错误。4. 核心算法从传感器数据到控制指令4.1 传感器数据的滤波与归一化传感器数据质量决定了整个控制系统的上限。以电磁组为例电感采集到的原始电压往往带有较多噪声不能直接用于偏差计算。常用的滤波方法包括中值滤波适合去除随机脉冲噪声。滑动平均滤波能平滑信号但会带来一定滞后。低通滤波一阶 RC 滤波实现简单实时性好。一阶低通滤波的 C 语言实现如下// 文件路径modules/filter.c typedef struct { float output; // 上一次输出 float alpha; // 滤波系数0~1 } LowPassFilter_t; float LowPassFilter_Update(LowPassFilter_t *f, float input) { f-output f-alpha * input (1.0f - f-output) * f-output; return f-output; }滤波系数 alpha 的选择很关键太大会导致滤波效果差太小会导致信号严重滞后。一般建议先设为 0.3 左右再根据实际波形调整。4.2 从赛道信息计算偏差无论是摄像头组的图像处理还是电磁组的信号采集最终目标都是计算出一个“偏差值”——代表车身相对于赛道中心线的偏移程度。以电磁组为例常见的做法是使用水平排列的多个电感计算左右电感的电压差// 文件路径algorithm/direction.c float Direction_GetError(float left_value, float right_value) { // 归一化到 -1 ~ 1 float sum left_value right_value; if (sum 0.001f) { return 0.0f; } return (right_value - left_value) / sum; }这个偏差值会作为方向 PID 控制器的输入。注意归一化后的偏差可以有效避免因电源电压波动导致的数据漂移这是很多新手队伍容易忽略的细节。4.3 方向控制让舵机“看准弯道”方向控制通常使用位置式 PD 控制器因为舵机本身是比例环节加上微分项可以提前预测误差变化趋势让转向更平滑。一个常见的实现typedef struct { float kp; float kd; float last_error; } ServoPD_t; float ServoPD_Calc(ServoPD_t *pd, float error, float dt) { float derivative (error - pd-last_error) / dt; float output pd-kp * error pd-kd * derivative; pd-last_error error; return output; }需要提醒的是方向控制的 kd 项要谨慎过大的微分增益会在过弯时引起舵机振荡表现为前轮“抖舵”反而影响稳定性。4.4 速度控制让车模“稳住节奏”速度控制比方向控制复杂一些因为电机存在惯性而且赛道上不同元素需要不同的速度。工程上常用增量式 PID 控制电机转速typedef struct { float kp; float ki; float kd; float last_error; float integral; } SpeedPID_t; float SpeedPID_Calc(SpeedPID_t *pid, float target, float current, float dt) { float error target - current; pid-integral error * dt; // 积分限幅防止积分饱和 float integral_max 100.0f; if (pid-integral integral_max) pid-integral integral_max; if (pid-integral -integral_max) pid-integral -integral_max; float derivative (error - pid-last_error) / dt; float output pid-kp * error pid-ki * pid-integral pid-kd * derivative; pid-last_error error; return output; }增量式 PID 的输出是“增量”需要在外部累加得到实际 PWM而位置式 PID 直接输出 PWM。两者都可以用于电机控制但增量式 PID 在积分饱和处理上更方便。在实际测试中速度环参数一般先调 P让电机能跟上目标速度再调 I消除稳态误差最后调 D减小超调。整个过程需要使用串口打印实际速度曲线而不是凭感觉。4.5 赛道元素识别与状态机到了国赛阶段赛道上的十字、环岛、坡道、断路等元素是决定成绩的关键。识别这些元素的核心思想是“状态机”而不是简单的 if-else 堆叠。状态机可以避免因为连续元素的干扰而产生误判。以环岛为例一个简化的状态机如下typedef enum { ELEM_NONE, // 无元素 ELEM_RING_ENTER, // 进入环岛 ELEM_RING_INSIDE, // 环岛内部 ELEM_RING_EXIT, // 出环岛 } RingState_t; RingState_t ring_state ELEM_NONE; void Element_Task(void) { switch (ring_state) { case ELEM_NONE: if (Detect_CurveRight()) { ring_state ELEM_RING_ENTER; SpeedPlanner_SetTarget(1.5f); // 入环减速 } break; case ELEM_RING_ENTER: if (Detect_RingInside()) { ring_state ELEM_RING_INSIDE; SpeedPlanner_SetTarget(1.8f); // 环内提速 } break; case ELEM_RING_INSIDE: if (Detect_RingExit()) { ring_state ELEM_RING_EXIT; SpeedPlanner_SetTarget(2.0f); // 出环恢复 } break; case ELEM_RING_EXIT: // 完全出环后恢复无元素状态 if (Detect_Straight()) { ring_state ELEM_NONE; } break; default: ring_state ELEM_NONE; break; } }每个元素的识别函数都要经过大量实车测试确保“该识别的时候一定能识别不该识别的时候一定不能误判”。这也是为什么建议把状态机和速度规划独立成任务模块方便针对单个元素进行测试。5. 调参与试车一整天都在和参数较劲5.1 调参顺序先方向后速度先低速后高速很多新手第一次上车就跑高速结果翻了车然后花很长时间排查机械问题。正确的调参顺序是先关闭速度规划固定一个较低的目标速度比如 1.0 m/s。调方向 PD让车模能稳定地沿赛道中心线行驶。逐渐提高目标速度观察弯道是否切内、出弯是否甩尾。速度规划加入后再针对每个元素单独调整进弯/出弯速度。最后做极限测试确认系统的稳定裕度。5.2 参数不合理的典型表现现象可能原因处理思路直线频繁蛇形摆动方向控制 P 过大或 D 过小减小 P适当增大 D过弯转向不足冲出赛道方向 P 过小或速度过快增大方向 P降低进弯速度舵机高频抖舵方向 D 过大或机械间隙减小 D检查舵机连杆虚位电机明显顿挫速度环 P 过大或编码器信号异常减小 P检查编码器安装速度稳态误差大速度环 I 不足适当增大 I调参过程中一定要做到“一次只改一个参数”并且记录每次修改前后的效果。很多队伍喜欢同时改好几个参数结果出了问题根本不知道是哪一项导致的。5.3 数据记录让调试变得可回溯建议在车上加一个 Micro SD 卡模块把每次跑圈的完整数据速度、偏差、元素状态、舵机输出记录下来。赛后回放数据可以清楚地看到失控前发生了什么。这比在现场反复试跑效率高得多。前几届我都是靠肉眼观察发现问题就只能盲改。后来学会用数据回放很多疑难杂症迎刃而解比如发现某个固定弯道前速度没有降下来是因为元素检测模块的触发条件过于苛刻——这些靠肉眼根本无法判断。6. 技术报告与答辩准备不要忽视“软实力”6.1 技术报告的结构建议进入国赛的队伍往往还需要提交技术报告和进行现场答辩。技术报告不是代码说明书而是展示你们解决问题的完整思路。我的建议结构如下系统总体设计整车框架、控制流程、核心指标。硬件电路设计电源、驱动、传感器接口以及关键器件的选型理由。软件算法设计图像处理/信号处理、PID 控制、速度规划、状态机。系统调试与优化调参过程、数据分析、遇到的问题和解决方案。总结与展望系统的不足以及可改进的方向。6.2 答辩最容易踩的坑答辩时评委最看重的是“你们是否真正理解了系统的每个环节”。最常见的扣分点是只写“我用了 PID”说不清为什么用位置式而不是增量式。只贴代码没有算法流程图和公式推导。对硬件参数一问三不知比如 ADC 采样率、PWM 频率是多少。说自己实现了某个功能但代码逻辑存在明显问题。建议队伍内部分工准备写报告的队员要覆盖自己负责的模块并且至少把关键代码再“讲”一遍。模拟答辩时可以让队员互相提问专门挑最细的环节。7. 常见疑难问题与排查手册7.1 一套可复用的排查思路当车模出现异常时按以下顺序排查不要“想到什么查什么”电源是否正常用示波器看主控供电电压确认无跌落、无毛刺。传感器数据是否正常在串口助手观察原始数据波动范围。算法输出是否正常确认偏差计算、PID 输出是否符合预期。执行机构是否正常舵机、电机是否按指令动作。机械是否有异常检查车轮、连杆、轴承是否松动。大部分问题都可以通过这种“从源头到执行端”的顺序定位。7.2 高频问题速查表问题现象常见原因解决思路摄像头画面花屏电源纹波大、排线松动检查电源滤波重新插拔排线并固定单片机偶尔复位供电瞬间跌落加大储能电容电机与逻辑电源隔离电磁值漂移严重电感未固定、邻近电磁干扰热熔胶固定减少电机驱动线对信号线的干扰舵机不回正机械虚位、陀螺仪零漂检查连杆用大电流舵机驱动模块车模加速时甩尾速度环响应慢、后轮抓地不足增大速度环 P检查轮胎磨损连续元素误判状态机缺少防抖条件增加连续 N 帧确认机制7.3 避免“赛前夜改代码”每届比赛都有队伍在赛前夜改参数、改算法结果第二天一败涂地。我的建议是赛前三天进入“代码冻结”状态只进行参数微调不修改任何逻辑结构。同时准备好一个“稳定保守版”固件万一新版本有问题随时可以刷回稳定版本。这个教训是我大二那年换来的。当时在赛前夜觉得某个弯道处理逻辑可以优化修改后没有充分测试结果第二天在比赛场上连续冲出赛道白白浪费了一整年的努力。从那以后我再也不敢在赛前改逻辑了。8. 最后一届一些工程与团队经验8.1 时间线管理从备赛到国赛一个完整的智能车赛季通常持续 8 到 10 个月。建议的时间安排是第一阶段前期 1-2 个月熟悉主控芯片、传感器跑通最小系统。第二阶段中期 2-3 个月完成底层驱动实现基本循迹。第三阶段后期 2-3 个月识别元素、优化速度、反复测试。第四阶段冲刺 1 个月模拟比赛强化稳定性写技术报告。每个阶段都要有明确的验收标准否则容易出现前松后紧最后匆忙赶进度。8.2 团队协作的核心经验智能车队伍一般三到四人分工建议为硬件两人、软件两人但同时每个人都要了解整体架构。最关键的一点是每周至少进行一次“整车联调”而不是各管各的直到比赛前才合在一起。联调时发现问题当场定位当场记录。不要指望“今晚回去改一下明天就好”很多问题需要反复验证尤其是涉及机械和电气交叉的疑难杂症。8.3 风险控制给自己留一条退路最后想谈谈“风险控制”。赛场上不确定因素很多光线变化、场地摩擦系数不同、临时更换电池等。每一条都可能让一个月的努力白费。因此备赛后期一定要做“最坏情况测试”在低亮度、高亮度、逆光环境下分别测试摄像头稳定余量。在赛场可能使用的多个电池之间测试一致性。跑完一圈后立刻检查电机、驱动板温度确认热稳定性。准备一套备用传感器和备用主控板并提前测试过可以无缝替换。越到后期比的不再是谁更快而是谁更稳。这句话是我三年来最深刻的理解。写到这距离我最后一场智能车比赛还有一个月。窗外已经是夏天实验室的风扇呼呼作响队友还在焊板子示波器上的波形不停跳动。我不知道30天后的结果如何但我知道这三年我收获的东西远不止一张获奖证书。从第一次烧坏主控的懊恼到第一次完整跑完一圈的狂喜再到如今能够独立调试一整套系统这段经历教会了我工程思维的真正含义。如果这篇长文能帮你少烧一块板子、少熬一个通宵、少在赛场上犯一个低级错误那这份记录就有了意义。希望你们也能在某一个夏天的夜晚看着自己的车模稳稳地冲过终点线然后由衷地觉得这一切都值得。
返回列表