2026年TI杯H题:完赛工程、技术方案与完整复盘
比赛已经结束。唯一最终工程为C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2026-8-1,最终MSPM0固件已由参赛者手动烧录。本文是唯一Obsidian入口,技术方案、最终代码、关键接口、完整时间线、失败经验和原始记录均已合并在本页。
页面导航
- 通用电赛经验:见第 7 章“跨项目通用电赛技术与调试经验”。
- 1 完赛最终代码与成果
- 2 技术方案与接口
- 3 系统交接与各任务结论
- 4 实验复盘:从 7 月 30 日到完赛
- 5 问题结论与实验记录模板
- 6 原始调试记录归档
- 7 跨项目通用电赛技术与调试经验
只想了解作品:看第1~2章。需要复现系统:看第3章。要吸取调参经验:看第4~5章。第6章是保留的原始现场记录,第7章汇总跨项目可复用经验。
信息边界
| 标记/位置 | 含义 | 使用方式 |
|---|---|---|
| 第 1~3 章 | 完赛工程、接口和任务结论 | 作为当前版本的复现主线 |
| 第 4~5 章 | 按时间和问题组织的实验复盘 | 用于理解为什么这样调参,以及哪些方案被放弃 |
| 第 6 章 | 原始现场记录 | 只用于追溯,不把其中的临时判断当成最终结论 |
| 第 7 章 | 可迁移的跨项目经验 | 迁移到新车/新板前,重新核对硬件和版本 |
路径、哈希、参数、端口和“已完成”状态属于本次比赛的现场事实;“可能原因”“建议方案”和论文贡献属于分析或后续计划。复现时先以最终代码和验收结果为准,再参考时间线中的推断。
1 完赛最终代码与成果
2026年TI杯H题比赛已经结束。参赛者确认:最终MSPM0代码已经由本人手动烧录,上位机、MaixCAM、MSPM0和其余工程资料均保存在同一个最终文件夹中。因此本笔记是赛后归档,不再把工程描述成“等待继续烧录/等待下一轮调试”。
1. 唯一最终归档目录
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2026-8-1
目录包含:
01_MSP主控:MSPM0G3507最终Keil工程、源代码、AXF、HEX和构建日志;02_MaixCAM视觉/当前部署:MaixCAM最终正式源代码和参数;03_机械结构:DCC、步进电机、接线和摇臂摆杆资料;04_设计文档与调参记录:调参轨迹、日志和版本过程;05_项目交接:交接手册和资料索引;06_RDKX5上位机:已展开的上位机/RDK X5比赛展示、录像和回放控制台源码;04_设计文档与调参记录/题目与设计报告:两份H题PDF及完善版设计资料;05_项目交接/交付压缩包:MaixCAM和RDK X5交付ZIP。
早期的备份-lora-before、7月30版、双车参考和2025压缩包已统一移到上一层90_历史归档,只用于追溯,不再代表完赛代码。
2. MSPM0最终代码
2.1 最终构建与烧录状态
- Keil工程:
01_MSP主控/project/Keil/EmbedBolt316.uvprojx; - 最终AXF时间:2026-08-01 17:13:14;
- 最终HEX时间:2026-08-01 17:13:15;
- 最终构建日志:
0 Error(s), 0 Warning(s); - 最终固件已由参赛者在比赛阶段手动烧录。
最终文件哈希:
EmbedBolt316.axf
SHA-256 4D84FA04098BD6C4F8EAABA2D8402806C376DEF5424CFEF5CB2EC2E9200D1340
EmbedBolt316.hex
SHA-256 5B492D8C0C08CB97949B261415E53160EAF85EAC384765E63FE31388C062E671
2.2 最终车辆参数
Base2直线速度 45 cm/s
Base2弯道速度 35 cm/s
入弯前20 cm平滑降速
Base4物理目标 150 cm
Base4编码器校正 ×1.25
Base4最终编码器目标 187.5 cm
Base4巡航速度 28 cm/s
Base4起步/末速 8 / 10 cm/s
Base4起步斜坡 900 ms
Base4末段减速距离 20 cm
Task5/6巡航速度 27 cm/s
Task5/6起步斜坡 1500 ms
第二弯门控 18 s后启用
入弯/接近出弯/出弯阈值 18 / 14 / 8 deg/s
A点宽黑阈值 5路
里程兜底 660 cm
640~660 cm末段速度 12→7.5 cm/s
最终代码还保留了完成/超时后向Maix发送CAR:CRUISE的兼容逻辑:车辆已经停止,但视觉闭环继续把球拉回保存目标,不因旧CAR:HOLD语义冻结。
GRAY_SENSOR_GANV_NO_MCU与GRAY_SENSOR_GANV_MCU两个旧灰度分支在最终MSP源码中均已不存在。
3. MaixCAM最终代码
正式入口:02_MaixCAM视觉/当前部署。
3.1 最终身份
app.yaml应用版本 1.5.0
config控制版本 TASK6-CAPTURE10-SAFE-PARK-20260801
标定版本 3PT-20260731-E
视觉中心 230 px
DCC机械中位 15241
相机配置 480×480,80 FPS传感器模式
最终文件哈希:
main.py
SHA-256 B4B23B3776F785E460ABF0EE53CF141F1129D0E317A7896C2A6E641E9E0BE80F
config.json
SHA-256 A69ED24D9355461AA67543C184AB5B26A2FDDEA0EB74DCA291A02BB1BE0E3311
app.yaml
SHA-256 BF9AE7431A45E95F036CE078EF572ACD368ADD4EB0E573BE0818159F4A23DB8F
3.2 最终功能
TASK:1、TASK:2为图传任务;TASK:3、TASK:4、TASK:5、TASK:6均进入滚球控制逻辑;- Task3完成
O → +5 cm → -5 cm并在负端保持; - Task4在车辆A到B过程中保持O点;
- Task5采用视觉位置/速度PD、MSP陀螺仪前馈、1500 ms缓启动和直线受限破静摩擦;
- Task6启动后等待用户手动摆球稳定,捕获当前位置作为任意目标,再整圈保持;
- Task6停车保持窗为约±0.65 cm且速度小于0.5 cm/s,停车恢复最大角度5°;
- YOLO用于首次定位与重捕,局部高速跟踪用于连续控制;
- DCC机械回中使用真实编码器相位15241,不依赖旧绝对0°。
六项任务分别使用RTSP端口5001~5006。Maix应用仍采用设备屏幕手动启动,不设置上电自启动,这是最终稳定性取舍,不是未完成功能。
4. 上位机/RDK X5最终代码
正式展开目录:06_RDKX5上位机。原始ZIP已移动到05_项目交接/交付压缩包/RDKX5存储回放功能_完赛归档.zip。
SHA-256 905FC6DA8745A1546850B8EB59EC577C6D5872FF55574E4B9D82A52ADE5AE7C9
正式控制台部署目标为:
/home/sunrise/rdk_evaluation
关键组成:
evaluation_console/evaluation_gui.py:1024×600触摸GUI;evaluation_console/rdk_evaluation.sh:六任务显示、录像、状态和回放控制;evaluation_console/config/tasks.conf:Task1~6与5001~5006端口映射;rdk_media.sh:录像索引、容量保护、断流重连和历史回放;desktop/:桌面入口;tests/:静态检查、GUI、录像监督、自动巡检和触摸退出测试。
控制台最终能力:
- 用户点击“开始显示并录像”后,持续巡检5001~5006;
- 自动发现有效H.264 RTSP任务并全屏显示;
- 按任务和全局场次号保存录像;
- 每60秒分段,断流后安全保存并尝试重连;
- 剩余空间低于10 GB时阻止继续录像;
- 支持停止并保存、播放本题最新录像、打开录像目录;
- 退出控制台时先停止录像和画面,再安全退出;
- 多路同时在线时按固定端口优先级选择并提示。
上位机任务说明中Task6已经标为“循线一圈并任意位置稳定”,与最终Maix Task6捕获逻辑一致。
5. 完赛结果应如何表述
代码层面已经形成完整三端系统:
MSPM0 OLED与车辆状态机
↓ UART任务、车辆阶段、陀螺仪
MaixCAM视觉与步进滚球闭环
↓ 分题H.264 RTSP
RDK X5显示、录像、索引与回放控制台
调试期间保存的7.036 s、GYROFIX3 RMS 1.61 cm等数据是某些已记录测试轮次,不应自动冒充最终比赛成绩;最终赛场得分、用时和裁判结果若没有单独记录,就保持“未在本地资料中找到”,不再写成待完成事项。
6. 赛后结论
工程已完赛并封存。后续阅读这些资料的目的不是继续赶比赛版本,而是复盘:
- 如何在高静摩擦、长执行延迟和不可靠GUI资源下完成可工作的闭环系统;
- 为什么真实编码器相位和可重复初始条件比继续堆PID更重要;
- 为什么Task5的FIX3能够靠量化对比收束,而第三题早期连续15版会越调越差;
- 为什么本地源码、烧录固件、设备端应用和上位机必须分别建立版本身份;
- 如何在比赛结束后用哈希和唯一目录保存可复现的最终成果。
2 技术方案与接口
1. 视觉坐标标定
设水管在图像中的两个端点为:
检测到的钢球中心为 \(P=(u,v)\),水管方向向量为:
将球心投影到水管轴线上:
再换算为以中心 O 为零点的实际位移:
其中 \(L=0.25\,\mathrm{m}\),\(s=0\) 为中心,\(s=+0.05\,\mathrm{m}\) 和 \(s=-0.05\,\mathrm{m}\) 分别对应 +5 cm 与 -5 cm。

2. 视觉检测方案
| 方案 | 算法耗时 | 结论 |
|---|---|---|
| YOLO | 41.2 ms |
适合首次定位或低频纠正 |
| 局部模板匹配 | 67.8 ms |
过慢,淘汰 |
| 80×60 自适应 LAB 色块 | 7.4 ms |
当前实时控制主方案 |
LAB 方案包含取帧后的总周期约 18.9 ms,约 53 fps;静止中心抖动约 0.13 px。
3. 位置与速度控制
- MaixCAM 输出球的位置 \(x\),连续帧差分并滤波得到速度 \(v\)。
- 位置环根据剩余距离生成目标速度:
- 速度环根据 \(v_{actual}-v_{target}\) 计算摆杆目标角度。
- DCC 驱动器执行并保持步进电机角度。
第三题状态机
CENTER:确认球在 O 点附近且速度足够低。TO_POSITIVE:使用一次受控强起动克服静摩擦,向+5 cm运动。TO_NEGATIVE:提前反向制动,向-5 cm运动;禁止负端二次强起动。HOLD_NEGATIVE:首次进入-5 ± 0.8 cm且|v|≤2 cm/s时立即调平。DONE:水平保持180 ms且仍在-5 ± 1 cm后完成;漂出则恢复普通控制。
第五题融合控制
- 输入:视觉位置/速度 + MPU6050 角速度。
- 启动车辆前,MaixCAM 先确认球在中心稳定,再回复
BALL:STARTED。 - 保留约
1500 ms缓启动。 - 陀螺仪前馈不能固定方向硬叠加:与视觉纠偏同向时全量使用,反向时衰减或关闭。
- 直线静摩擦短脉冲只允许在直线、低速且
|误差| > 0.8 cm时触发;建议从5.5°/260 ms开始复测。
4. 电机、编码器与接口
- 编码器相关寄存器范围:
0x40~0x47;记录中重点读取地址0x42,最终以拨码表确认。 0x11:相对整角控制,当前可靠方案。- 首次修正最多
5° ≈ 228 脉冲,避免拆成无效微步。 - 当前水平目标相位:
15241;闭环实测15244。 - 回中流程:读取真实编码器相位 →
0x11相对修正 → 再读取相位验收。 - 不再使用存在问题的
0x13或软重启探测。
5. 软件与启动安全
/etc/init.d/S06maixapp 曾在 comm method=none 时仍初始化 UART0,并向 /dev/serial0 写入 serial ready。UART0_TX 与 TB6612 的 PWMA 共用 A16,导致重启时可能出现电机脉冲。
已实施的保护:
comm method=none时不再初始化 UART0,也不再写入serial ready。- 原脚本备份:
/etc/init.d/S06maixapp.pre-codex-20260730。 - 相机使用单实例锁,生产模式关闭 RTSP 和屏幕显示。
- YOLO 单缓冲;相机通道
buff_num=1。 - 获取下一帧前显式释放当前
frame。 - 控制器、模型和相机通道纳入统一清理。
- 父进程异常时,电机子进程检测 EOF 并拉低输出。

3 系统交接与各任务结论
- 比赛已经结束,唯一最终归档是
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2026-8-1。 - 参赛者确认最终MSPM0代码已在比赛阶段手动烧录;Base4最终为187.5编码器厘米/28 cm/s,不再沿用“板上仍为150/25”的调试期判断。
- 最终Maix正式目录为应用1.5.0,控制身份
TASK6-CAPTURE10-SAFE-PARK-20260801,已经包含Task6任意位置捕获与停车保持逻辑。 - 上位机代码已展开到最终目录中的
06_RDKX5上位机;交付ZIP保存在05_项目交接/交付压缩包,包含六任务RTSP显示、自动录像、断流保存、索引和回放控制台。 - 本文后续“未烧录、待验证、下一步”等句子是调试当时的历史状态,用于解释决策过程;最终版本以完赛最终代码与成果为准。
1. 记录范围与可信度
本笔记不是只保存“最后参数”,而是保存整个协作过程中影响判断的关键事实:用户现场现象、Codex读取到的XDS内存、Maix轨迹、代码变更、烧录结果、失败版本和回滚理由。
可信度顺序:
- 当前源码、构建日志、XDS内存和保存的JSON轨迹;
- 现场明确口述(例如“打到底”“停在3 cm”“只转左轮”);
- 根据运动现象作出的推断;
- 未完成实车复测的预计值。
所有“预计”“推断”均不得冒充比赛验收结果。
2. 硬件、接线与控制职责
2.1 设备
- 主控:MSPM0G3507,Keil工程,XDS110下载/内存诊断。
- 小车:左右两轮差速,8路灰度循迹,MPU6050/姿态数据用于弯道前馈和终点门控。
- 视觉:MaixCAM Pro,摄像头侧装,识别钢球并计算沿25 cm管槽的一维位置。
- 执行器:DCC-101步进驱动器、步进电机、摇臂连杆和PPR开槽摆杆。
- 显示/操作:MSP OLED菜单;MaixCAM本机屏幕只负责手动启动应用与画面显示。
- 网络:绿联网卡,历史设备IP
10.5.5.29;MaixVision曾正常连接。不要把电脑屏幕画面当摄像头数据源。 - 调试:XDS110 Application/User UART曾枚举为COM7,Aux为COM8。
2.2 当前接线口径
接线文件:03_机械结构/步进电机和maixcam接线.txt。
Maix A18 -> 步进电机/DCC PWM
Maix A28 -> DCC RX
Maix A29 -> DCC TX
Maix A16 TX -> MSP RX
Maix A17 RX -> MSP TX
MSP与Maix是UART1/LwPKT字符串链路。旧MaixCamPro代码和旧接线曾被明确判定不可信,不能反向覆盖当前接线。
2.3 职责边界
- MSP:OLED任务选择、小车循迹、里程、车辆启停、30秒/8秒计时、IMU、向Maix发送任务和车体状态。
- Maix:球检测、位置/速度估计、滚球控制、DCC角度与保持、RTSP。
- 摆杆由Maix控制,不由MSP直接输出步进角度。
3. OLED任务与题目映射
| OLED | 串口命令 | 代码任务 | 含义 |
|---|---|---|---|
| Base 2 | TASK:2 |
Requirement 2 | 整圈循迹并停A点 |
| Base 3 | TASK:3 |
Requirement 3 | O→+5→-5并保持 |
| Base 4 | TASK:4 |
Requirement 4 | A→B 150 cm并稳球 |
| Play 1 | TASK:5 |
Requirement 5 | 整圈并把球保持O点 |
| Play 2 | TASK:6 |
Requirement 6 | 用户先摆任意刻度,捕获该位置后整圈保持 |
重要纠正:不存在OLED“Base5”;第五题实际叫Play 1,第六题叫Play 2。XDS中枚举从Requirement 2=0开始,因此h_id=3是Task5,h_id=4才是Task6。
4. 总体时间线
4.1 工程接管、目录和版本辨认
- 最初工程来自多个目录:
备份-lora-before、队友交接包、ti-contest-2026-H、ti-contest-2026-8-1等。 - 用户要求清理与当前目录无关的大量Git删除状态,随后要求按“MSP主控、Maix视觉、机械、设计/调参、项目交接”整理。
- 曾对队友D版/Keil工程做差异检查,判断不能整包直接覆盖;主要迁移通信与任务功能到用户自己的MSP工程,保留用户循迹基线。
- 最终整理后的正式目录为
ti-contest-2026-8-1,顶层分为01_MSP主控、02_MaixCAM视觉、03_机械结构、04_设计文档与调参记录、05_项目交接。 - 历史脚本和失败版本只用于追溯,正式入口是
01_MSP主控和02_MaixCAM视觉/当前部署。
4.2 机械中位、堵转和编码器
- 机械结构是步进电机摇臂带动摆杆。用户强调机械摆放本来就在中位,小球触底/落中能直接反映杆姿态。
- 初期绝对零点错误导致电机上电打到最底并堵转。根因不是用户没摆中,而是软件绝对0°与真实机械中位不一致。
- 旧记录中位先后出现
15624、15337,均被后续标定淘汰。 - 最终验证的水平目标相位为
15241,读回15244,相差3脉冲,约0.066°。 - DCC可靠命令是
0x11相对整角;细分微步在该机构上多次实测“完全不动”,不能继续依赖微步。 - 首次修正最多5°(约228脉冲),必须保留机械硬限,禁止直接下发未经反馈校验的绝对大角度。
- 用户曾质疑电机未使能,因为轻推连杆即可移动;后续“始终使能”测试确认有明显保持力。因此应用启动后应使能保持,但不应盲目执行旧绝对回中。
- 自动回中正确做法:读取真实编码器相位→
0x11相对修正→再次读相位验收。不要用旧0x13或软重启探测。
4.3 MaixCAM启动、黑屏、死机与网络
- MaixCAM经历多次黑屏、应用崩溃、设置界面卡死、网络不可达和重装系统。
- 主要稳定性根因不是简单“内存不够”,而是相机MMF/VI/VPSS缓冲未释放、RTSP/显示/识别多实例争用以及底部刻度硬件叠加层在客户端重连时触发
SIGSEGV(11)。 - 做过的稳定性处理:单实例锁、相机
buff_num=1、每帧显式释放、统一清理、生产模式减少显示/RTSP争用、父进程异常时电机子进程EOF安全处理。 - 左上角退出触摸曾被怀疑误触,后来用户明确要求触摸改回;最终采用长按1.5秒以减少虚报,但不能把所有黑屏都归因于误触。
- 开机自启动曾把系统和网络搞死。最终纪律:GUI只从Maix屏幕手动点开,禁止上电自启动,禁止用SSH启动GUI,禁止崩溃后循环强杀/重启。
/etc/init.d/S06maixapp曾在comm method=none时仍初始化UART0并发送serial ready。A16又与TB6612/PWMA链路冲突,造成重启瞬间电机抽动。修复方向是method=none时不初始化/不写UART0。- 用户后来明确选择手动点应用,宁可多一步,也不要自启风险。
- 历史账号
hwy / 4399ssjj在系统重装/恢复后不再被10.5.5.29 SSH接受;MaixVision仍可能连接,但不能据此假定SSH可用。
4.4 视觉方案从YOLO到混合跟踪
- 用户重装系统后要求仍以YOLO为基础,但指出持续YOLO延迟大。
- 讨论过香橙派3B+OV9281+OpenCV高帧率方案,但比赛时间不足,最终保留MaixCAM。
- 最终视觉策略:YOLO用于首次定位/丢失重捕;局部LAB色块/轮廓用于连续控制。
- 实测:YOLO约41.2 ms;模板匹配67.8 ms淘汰;80×60自适应LAB约7.4 ms;含取帧总周期约18.9 ms,约53 fps;静止抖动约0.13 px。
- 曾期望60~80 fps,实际基线约53 fps。不能在报告里写成稳定300 fps。
- 摄像头移动后必须重新标定。历史出现画面蓝线/中心与真实小球相差约2 cm,12次球心像素中位数240 px但物理约+2 cm。
- 256×192 RTSP底部刻度仅为辅助:
-12.5→31、-5→85、0→121、+5→157、+12.5→211。相机位置变化后该静态刻度立即失效。
5. 第三题(Base3)完整调参结论
5.1 目标与控制结构
- 从O点出发,先到+5 cm,再到-5 cm,最终必须稳定在-5±1 cm;不能任务完成后自动回正,只有OLED返回/STOP才回中。
- 视觉提供位置和滤波速度;位置环生成目标速度,速度环/PD生成杆角;DCC执行并保持。
- 静摩擦是核心难题:小角度/微步完全带不动,过大脉冲又会造成二次越界。
5.2 大量实测现象
- 早期出现:电机动但球原地不动;微步没有任何效果;改用绝对/整角才有明显动作。
- 多轮中出现停在3 cm、幅度越来越小、到点继续输出打到底、负方向根本没走、重复打两次浪费时间等问题。
- 用户多次指出“没动就应该持续加”“需要安全限幅”“小角度打不动”,这些都被实测证实。
- 多次连续启动/回中/按键用于建立轨迹;用户要求每轮记录时间点,后期因记录中断导致参数偏离此前较好方向。
- 曾经第十轮看似最好,后来连续复测发现可能有运气成分,说明单轮成功不能作为模型。
- 一轮理想捕获:2.96 s到-4.96 cm,速度-0.10 cm/s。失败是控制器没有在这一刻调平,继续PID并误触发反向强起动。
5.3 已确认规则
- +5阶段允许一次受控强起动;-5阶段禁止二次强起动。
- 首次进入-5±0.8 cm且速度≤2 cm/s立即调平。
- 水平保持180 ms且仍在-5±1 cm后才DONE;漂出才恢复普通控制。
- “到位置继续追”比“略慢一点”更危险,曾直接把球打到端点。
- 最好完整结果:正向峰值+5.46 cm,最终约-4.9 cm,长期保持稳定,但用时7.036 s,未达到5 s。
- 第一次刹车停在-1.87 cm导致第二次追赶,浪费约3 s;下一步应优化一次捕获,不应继续增加强起动幅度。
6. Base2整圈循迹
- Base2是Requirement 2,Maix只提供图传,车辆循迹由MSP完成。
- 用户多次指出“线还在中间却提前停止”,否定了“宽黑误识别”的草率判断。
- 起终点宽黑阈值最终坚持5路,用户明确拒绝降到4路,因为弯道可能误识别。当前
H_STOP_MARK_MIN_CHANNELS=5,确认样本数1。 - Base2与Task5/6速度不同,同样的物理赛道不能盲目共用同一个编码器里程常数;速度、打滑和负载会改变里程比例。
- 最后一次对话中Base2出现“只转左轮”。此前Base4新固件所有烧录均在DAP连接阶段失败,没有写入,因此不能认为是新距离参数破坏Base2。
- 排查优先级:右电机驱动/供电/使能/接线;右PWM和方向脚;灰度是否持续给出极限偏差;电机映射;板上固件状态。不要先改循迹PID掩盖硬件问题。
7. 第四题(Base4)
7.1 题意与调试期原实现
- A→B直线循迹,物理距离150 cm,同时保持小球在O点,时间≤8 s。
- Codex远程调试阶段板上最后可读版本曾是:
H_TASK4_TRACK_DISTANCE_CM=150、巡航25 cm/s、前20 cm降速、终点10 cm/s。 - 代码给
car_move_cm下发150+1 cm阈值补偿,理论在编码器150 cm处完成。
7.2 实测偏短、远程烧录失败与赛后最终状态
- 用户实测只跑约120 cm赛道距离。
- 按比例
150/120=1.25,本地源码加入Task4独立里程校正:编码器目标187.5 cm;不修改公共轮径,避免影响已收束的整圈任务。 - 若仍用25 cm/s,按速度曲线估算约8.23 s,可能违反8秒。故本地源码把Base4巡航改为28 cm/s,预计约7.45 s。
- 该版Keil全量编译0错误0警告,日志
task4_distance1875_build.log。 - UniFlash和Keil CMSIS-DAP都在连接阶段失败:
DAP Connection Error/E310 Debug access failed。XDS110固件切DFU并恢复Standard只恢复了探针本体,目标仍拒绝连接。 - 因此187.5/28在该次远程操作中没有烧入。比赛阶段参赛者随后手动烧录了最终固件;完赛目录中的最终AXF/HEX和源码均采用187.5/28。
8. 第五题(Play1 / Task5)
8.1 视觉+速度位置环+陀螺仪前馈
- 不是单纯视觉位置环:Maix根据球位置和速度输出角度;MSP持续发送车体Z轴角速度
CAR:YAW:n,Maix做前馈门控。 - 起步前回中握手+1500 ms缓启动有效,起步峰值约从+2.98降至+1.56 cm。
- 固定方向前馈不可用:第一弯可能抵消视觉,第二弯却可能有帮助。最终前馈只有与视觉纠偏方向一致时才全量使用,冲突时关闭/衰减。
8.2 版本结果
| 版本 | 位置范围 | RMS | 超±1 cm | 结论 |
|---|---|---|---|---|
| 初始前馈 | -2.54~+4.60 | 1.83 | 70.6% | 极端振荡减小,第一弯不足 |
| 符号翻转 | -6.02~+2.20 | 3.02 | 78.1% | 明显变差,翻转错误 |
| GYROFIX2 | -3.11~+3.69 | 1.97 | 62.5% | 恢复方向+受限脉冲 |
| GYROFIX3 | -3.14~+2.59 | 1.61 | 59.0% | 综合最好,正式回退点 |
GYROFIX3保留:前馈门控、KD=0.9、直线5.5°/260 ms短脉冲、700 ms冷却、回中握手、缓启动。弯道脉冲FIX4综合变差,已删除并回退。
8.3 停车和整圈终点
- Task5/6实际物理一圈约614.16 cm,但不同速度/负载下编码器里程不等价。
- 早期619 cm左右兜底导致第二弯未完成就停车。XDS读到
h_result=2、elapsed=24690、stop_mark=0,证明是里程误停,不是A点识别。 - 去掉兜底后有一轮30.003 s超时且
stop_mark=0,说明真实A点也可能漏检。 - 最终加入第二弯门控:18 s后看到|yaw rate|≥18°/s标记入第二弯;回落≤14开始终点接近;≤8视为出弯完成。只有完成第二弯才允许A点和里程兜底。
- A点仍优先使用5路宽黑+低转向率;兜底从614提高到660 cm。
- Task5实测28.717 s完成、车辆停车位置合适、
stop_mark=0,由660兜底;停车小震荡使球漂到-6 cm以上。 - 为降低硬刹,在640~660 cm将车速从12线性降到7.5 cm/s。该版编译并成功烧录。
9. 第六题(Play2 / Task6)
9.1 需求理解的演变
- 早期误把Task6设计成OLED选择Sign±与Position 1/2/3,担心动作队列上限。
- 重新读题后确认不需要复杂菜单:用户先自动回中,再手动把球摆到任意实体刻度;启动Play2时Maix捕获当前球位置作为目标;车辆整圈过程中保持这个目标。
- 因此删除Sign/Position菜单思路。Task6目标不是固定0点,也不能照搬Task5。
APP_TASK_CAPACITY=13并不是这一方案的瓶颈;最终任务表只有5个正式任务项。
9.2 关键故障
- 一开始Task6直接报
Prepare Ball First、摄像头卡死、自动回中偶发只使能不动作;分别涉及READY门控、相机资源、UART/DCC状态,不能混成一个问题。 - Task6曾表现为手动摆到+2后开始有动作,随后一直向0点平衡,证明错误继承Task5固定O目标。
- 修正为捕获启动时当前位置后,转弯偏差改善;但停车仍会打端点,A点还会多走接近半段直线。
- 直接把宽黑阈值5路降到4路被用户否决并回退。
- 只靠614/619里程可能少半圈;只靠真实宽黑又可能30秒超时。最终采用第二弯确认+A点优先+660兜底。
9.3 停车后必须继续回目标
- Task6一轮XDS:
h_id=4、h_result=2、elapsed=28166、stop_mark=0,车辆已由660兜底完成。 - 用户指出“小球没有停回设定刻度”,并明确要求即使30秒超时也不能把球丢着不管。
- 根因:旧Maix在
CAR:HOLD后把停车视为终态,做一次350 ms制动后冻结,视觉环不再追目标。 - 本地Maix正式源码已改:取消HOLD冻结;停车恢复角限制5°;进入目标±0.65 cm且速度<0.5 cm/s时调平。该本地修改因SSH认证失败未确认部署。
- 为兼容设备旧程序,MSP结束逻辑已从
CAR:HOLD改为冗余发送两次CAR:CRUISE。车辆已经由car_stop_and_reset()停止,CRUISE只让Maix继续纯视觉闭环,不会让车继续行驶,也不会像STOP一样清除Task6任意目标。 - 该MSP兼容修正构建0错误0警告并成功烧录,是板上最后确认成功烧录的功能版本。
10. 通信与命令语义
| 命令 | 方向 | 语义/注意事项 |
|---|---|---|
CENTER |
MSP→Maix | 机械回正+球回O,完成后BALL:CENTERED |
TASK:2..6 |
MSP→Maix | 同时选择对应视觉/RTSP任务 |
CAR:ACCEL |
MSP→Maix | 起步前馈状态 |
CAR:CRUISE |
MSP→Maix | 无纵向制动前馈;现在也用于停车后继续追目标 |
CAR:BRAKE |
MSP→Maix | 固定负向制动前馈,不能过早持续发送,否则会把任意目标向负端推 |
CAR:HOLD |
MSP→Maix | 旧设备版本会冻结Task6,不再作为Task5/6结束命令 |
STOP |
MSP→Maix | 操作员退出任务,允许回中/清理;Task3/6任务内不能误发 |
CAR:YAW:n |
MSP→Maix | 0.1 deg/s单位的角速度 |
11. XDS110诊断、地址与烧录
11.1 已验证工具链
- Keil:
C:\Users\12706\AppData\Local\Keil_v5\UV4\UV4.exe。 - 工程:
01_MSP主控/project/Keil/EmbedBolt316.uvprojx。 - UniFlash:
C:\ti\uniflash_9.5.0\dslite.bat。 - XDS配置:
C:\ti\codex_tools\xds110_mspm0g3507.ccxml。 - 烧录脚本:
C:\ti\codex_tools\flash_mspm0g3507.bat。 - Task5/6诊断:
01_MSP主控/tools/read_task6_post_xds110.js。
11.2 诊断脚本注意
脚本曾使用固定RAM地址。每次全量链接后地址可能变化,必须先从最新EmbedBolt316.map核对dbg_h_task_id、dbg_h_task_result、历史数组等符号,不能直接相信旧脚本。
11.3 探针与目标故障
- XDS110曾出现UniFlash Error -260。
xdsdfu -e显示3.0.0.41、NOserial、Runtime、Standard。 - 通过
xdsdfu -m进入DFU,再-c 1 -r恢复Standard,探针可恢复。 - 2026-08-01后期目标出现
CS_DAP_0 DAP Connection Error。重置XDS本体无效,Keil也报E310 Debug access failed。 - 这说明问题在目标MCU DAP/低功耗/复位状态,不是AXF编译失败。需要按住板上RESET做connect-under-reset,或电源/BSL/安全恢复后再烧。
- 失败发生在“Connecting”阶段,故不会半写入Base4 187.5版本。
- 上述结论只对应当时那次连接。比赛阶段参赛者后来手动烧录最终固件,DAP故障不再是完赛状态。
12. 完赛参数快照
MSP
Task4 physical target 150.0 cm
Task4 final odo target 187.5 cm (1.25校正,已手动烧录)
Task4 final speed 28.0 cm/s(已手动烧录)
Task4 start/end 8.0 / 10.0 cm/s
Task4 ramp/brake 900 ms / 20 cm
Task5/6 cruise 27.0 cm/s
Task5/6 start ramp 1500 ms
Finish approach 12.0 cm/s
Fallback soft brake 640~660 cm, 12→7.5 cm/s
Fallback stop 660.0 cm
Second curve arm 18000 ms
Curve seen/approach/done 18 / 14 / 8 deg/s
A wide-black channels 5
Maix本地正式源码
Task5 dynamic KP/KD 0.7 / 0.9
Task5 yaw gain/max/deadband 0.035 / 2.5° / 4°/s
Task5 breakaway 5.5° / 260 ms / 700 ms
Task6 dynamic KP/KD 1.05 / 0.85
Task6 yaw gain/max/deadband 0.08 / 3.0° / 3°/s
Task6 moving max angle 10°
Task6 stopped recovery max 5°
Task6 settle window ±0.65 cm, |v|<0.5 cm/s
Task6 hold breakaway 5° / 220 ms / 600 ms
13. 失败方案与禁止重复事项
- 禁止用旧绝对0°命令找平,曾导致直接触底堵转。
- 禁止把微步当主要执行方式;实测多次完全无动作。
- 禁止应用/GUI上电自启动和崩溃循环重启;曾导致网络和相机资源一起失效。
- 禁止多实例占用相机、RTSP、UART和显示。
- 禁止把A点宽黑阈值从5降到4,弯道误识别风险已由用户明确否决。
- 禁止只看单轮好运结果;第三题第十轮和多个“最好版”后来复测均暴露偶然性。
- 禁止同时改视觉、强起动、刹车、保持环和赛道里程,否则无法归因。
- 禁止用
CAR:HOLD结束当前设备上的Task6;旧版本会冻结视觉环。 - 禁止任务超时后放弃球控制;超时只停小车,Maix必须继续追保存目标。
- 禁止把本地编译成功直接写成已烧录。Base4 187.5/28在远程调试时就是典型反例;赛后之所以改记为已烧录,是因为参赛者明确确认后来完成了手动烧录。
14. 若未来复现该系统的建议顺序
- 若再遇到“只转左轮”,应先分别验证左右电机、驱动与灰度输入,不要先改循迹PID。
- 若DAP再次拒绝连接,应优先使用connect-under-reset,并把“连接成功”和“烧录Verify成功”分别记录。
- Base4的1.25校正来自约120→150 cm实测比例;若重做车辆或更换轮胎,应重新做多轮直线标定。
- Task5/6的660兜底、640~660平滑降速和结束后
CAR:CRUISE继续收敛是完赛代码的重要经验,不应随意删除。 - Maix重新部署时应先从设备屏幕退出应用、备份、语法检查、上传和哈希核对;仍不应通过SSH拉起GUI。
- 若重新测试Task6,应记录捕获目标、两弯峰值、停车位置/速度和重新进入±1 cm所需时间。
- 每次全量构建后应更新XDS诊断脚本地址,并保存map、构建日志、烧录输出和轨迹。
15. 对话中反复强调的现场原则
- 用户能快速手摆球并立即开始,不要每轮都强制走完整软件重启流程。
- 自动回中应由系统可靠完成,但任务运行后未经返回命令不能擅自回中。
- 小角度不等于平滑;静摩擦区需要受控破静摩擦,运动后必须立即撤力。
- 停车平滑要结合车辆速度曲线,而不是永远固定一个杆角。
- 视觉问题的主因曾被纠正为延迟而非静态误差;因此需要高帧率局部跟踪和速度估计。
- 用户要求持续读取和逐轮记录,不能在调参后半程停止看历史记录;每次改动都应回看已保存轨迹和失败经验。
4 实验复盘:从 7 月 30 日到完赛
本章按时间顺序记录架构确定、通信打通、机械回中、视觉切换、控制调参和最终对账。每个时间段都遵循“现象 → 判断 → 修改 → 结果”的叙事,便于复盘而不是重复阅读日志。
- 起点按现场指定,取 2026-07-30(星期四)21:44,中国标准时间。本机 Codex 主会话创建于 21:40:22,21:44:24 正式给出第三题架构方案。
- 时间来自本机原始 JSONL 会话,不是凭记忆补写。
- 正文不是逐句聊天记录,而是按“现象 → 操作 → 结果 → 判断 → 教训”整理。重复的“启动了/按了/读取”合并为测试轮次,改变技术判断的反馈保留准确时间。
- “编译成功”“已部署”“已烧录”“实车验证”是四种不同状态,本文严格区分。
比赛现已结束。参赛者确认最终MSPM0固件后来由本人手动烧录,MaixCAM最终应用和RDK X5上位机代码也都保存在ti-contest-2026-8-1。因此正文中“当时尚未烧入/仍需下一轮”的描述只表示对应时间点的历史事实,不代表工程现在未完赛。最终版本见完赛最终代码与成果。
0. 一页看懂整个过程
这几天最核心的矛盾不是某一个 PID 参数,而是五类问题交织:
- 机械基准不确定:软件角度 0° 一度不等于真实水平,导致上电打到底、轮间继承残余角、同一参数每轮初始条件不同。
- 执行器有强静摩擦与协议歧义:微步常常完全不动;
0x13绝对角在该 DCC 固件上会选择跨圈逼近,造成直接触底;真正可靠的是读真实相位后用0x11相对整角修正。 - 视觉不是只有“准不准”,更关键是延迟:持续 YOLO 约 25 fps,不足以处理高速滚球;换成“YOLO 首次定位 + 局部 LAB 跟踪”后达到约 53 fps,静态抖动 0.13 px。
- 状态机比单个增益更重要:到点后继续输出、换向仍受普通限步、停车进入 HOLD 后冻结或继续追打,都会让看似正确的局部控制变成全局失败。
- 实验管理失控会吞噬有效进展:7 月 31 日凌晨连续约 15 版叠加修改,后半程没有持续回看调参记录,导致偏离第 9~10 轮较好基线。之后以轨迹、版本标签、单变量修改和明确回退点收束,Task5 才稳定得到 GYROFIX3。
最终形成的可靠工程原则:
- 每轮任务开始前都以编码器真实相位重建机械水平,不继承软件累计角。
- 破静摩擦使用受控整角短脉冲;一旦检测到球运动,立即撤力或转入速度制动。
- 到点时先处理执行器残余角和球速,再判定位置;“位置到了”不等于“可以 DONE”。
- 车辆停车与滚球闭环分开:车可因完成或超时停止,球仍应继续回保存目标。
- 一次只改一个机制;每轮必须保存配置哈希、轨迹、板上固件状态和现场观察。
1. 2026-07-30(星期四):架构确定、通信打通、相机与应用稳定性
21:44—21:52:第三题架构和 MSP 入口
21:44:24,方案正式定稿。 第三题要求被明确为 O → +5 cm → -5 cm并稳定、总时长不超过 5 s、两端误差不超过 1 cm。控制职责划分为:
- MaixCAM Pro:视觉测位、位置/速度闭环、直接控制 DCC 步进机构;
- MSPM0:OLED、按键、任务计时、发送
TASK:3、接收完成/失败; - MSP 不进入高速滚球内环,避免 20 ms 调度和串口延迟干扰视觉控制。
21:46:18,现场给出最高权限并纠正硬件事实。 XDS110 已接入;新接线文件是唯一可信依据,原 MaixCAM Pro 代码不可直接相信。这一条非常重要:后续代码必须从真实引脚和实测链路反推,不能从旧工程反推接线。
21:47:28,确认 UART1 接线。 MSP 侧 PB3/RX ← Maix A16/TX,PB2/TX → Maix A17/RX,115200 8N1,共地。A16/A17 在 Maix 侧实际是 UART0,系统启动日志和系统通信服务可能抢占。
21:50:43—21:52:37,MSP 第三题入口完成并烧录。 加入 Base3/Task3、完成/失败回包、5 s 超时与停车保护;Keil 全量构建 0 错误 0 警告,XDS110 烧录校验成功。此时只完成任务框架,没有允许电机自动动作。
经验: 先把“谁负责什么、命令从哪来、失败谁收口”定清楚,再调控制器。否则 Maix、MSP、底盘三个状态机会互相覆盖。
21:53—22:21:网络恢复、双向 UART 实测、摄像头底层故障
21:53:46—21:54:53,绿联网卡恢复。 Windows 中 UGREEN 网卡此前只是 Disconnected,不是设备消失;重新连接 hwy 后定位 MaixCAM IP 为 10.5.5.29。
21:57—22:02,第一次部署即遇到 SIGSEGV。 新程序按 A16/A17/A18 接线重写,关闭系统自带 UART 协议,并先保持 PWM 禁用。相机/模型连续崩溃,最初怀疑 INT8 模型兼容和 VPSS 残留;继续分段测试后发现连官方相机程序也崩溃,因此不能把问题归罪于新算法。
22:06:50,职责再次由现场确认:杆子由 MaixCAM Pro 控制。 这排除了“让 MSP 直接输出步进角度”的岔路。
22:10—22:15,通信链路用无动作方法验收。 先只发 PONG 和 M0:BOOT:
- Maix A16 → MSP PB3 收包成功;
- MSP PB2 → Maix A17 收包成功;
- A18 未使能,测试不涉及机械风险。
22:21:19,当时的结论是相机 MIPI 0 FPS。 GC4653 能枚举但无图,最高概率是排线/运行环境。这个判断后来由重装系统使相机恢复,说明“工程代码不是唯一变量”是正确的。
经验: 串口、PWM、模型、相机必须拆开测。若一上来运行整套应用,SIGSEGV 会把四条链路混成一个“code 1”。
22:26—23:35:解释 code 1、重装恢复 YOLO、正确处理显示
22:26:28,澄清 code 1。 它只是进程异常退出,不是 Maix 相机硬件错误码。当时已见的直接原因包括路径错误和 CPython 不支持 time.sleep_ms();真正的相机问题另行诊断。
23:17:41,现场要求重装后仍用 YOLO。 重装后相机恢复 30 FPS;23:21:47 模型加载成功;23:22:17 完成 20 帧实拍,20/20 检到球,平均推理 39.5 ms,约 25 fps。
23:22:56,首次画面标定发现旧中心 240 px 明显偏右。 当时按画面有效杆长估算先改为 0 / 212.5 / 425 px,但这个只是初始视觉标定,摄像头后来移动后必须重新做。
23:23—23:28,完整程序卡在显示和内存。 YOLO 单测能跑,整套程序却 OOM/卡在 display.Display()。根因不是“Maix 一定不能显示”,而是后台脚本和 Launcher 同时抢显示与多媒体资源。
23:28:13,现场追问“一定不能显示吗”;23:28:21 给出正确答案:可以显示,但要按正式应用方式独占。 随后打包为 Launcher 应用,而不是 nohup 后台抢屏。
23:34:33—23:35:31,正式应用成功。 应用由 Launcher 启动,相机持续 60 FPS,屏幕显示 YOLO 框、O 点、±5 cm、位置与角度;只有收到 Task3 才允许 A18 动作。
经验: 嵌入式 Linux 上“算法可运行”和“完整 GUI 应用可稳定运行”是两件事。资源所有权必须唯一:相机、显示、RTSP、UART 都不能多实例争用。
23:42—23:59:首轮机构测试暴露死区与使能问题
23:44:40,应用驻留 60 s 通过。 帧计数从 667 增至 5319,无自行退出。
23:45:15,小幅 A18 测试: 中心 → +0.5° → -0.5° → 中心,程序正常退出,但肉眼动作不明显。
23:50—23:52,XDS 恢复后加入 SRAM 调试邮箱。 因 XDS 虚拟串口不是当前工程控制台通道,改为 XDS 写 RAM 值 3,仍走正式 Task3 路径。该固件编译并烧录成功。
23:53—23:58,机构与 DCC 通信逐项验证。 图纸估算表明 ±5° 属安全区;+2°、+5°短测球几乎不动。A28/A29 与 DCC 115200 UART 回包正常,因此接线、供电和通信在线。怀疑驱动器处于休眠/释放力矩,准备唤醒时又遇到相机内存资源未释放。
经验: “驱动器回 ACK”只证明命令被接收,不证明机械产生了足够角度和力;必须同时记录编码器相位、连杆动作和球位移。
2. 2026-07-31 凌晨:从触底堵转到可靠机械中位
00:06—01:27:第一次严重机械事故与系统恢复
00:06:07,现场报告步进电机堵转并直接打到最底。 这是整个调试最重要的安全事件。随后现场反复强调:轨道原本就在机械中位,小球能在中间本身就是证据,不能把错误归为“用户没摆中”。
问题链如下:
- 软件把当时保存的绝对原点当成真实机械水平;
- DCC 绝对位置/逼近方向的语义未经该固件实测;
- 任务失败或进程退出时,休眠命令可能只发一次且未校验;
- 电机仍保持上一次底部目标,人工轻推与软件状态不一致。
00:16:28,现场质疑是否真的使能。 轻轻发力能带动连杆说明保持力不足或电机处于 Sleep。后来“始终使能”试验出现明显保持力,证明使能状态必须由 DCC ACK 和实际保持力共同确认。
00:21:25,MaixVision 对 10.5.5.29 连接成功。 网络恢复不代表相机应用、SSH和GUI状态都正常;它只证明这一条连接链路可用。
00:37—01:27,系统进入资源占用/卡死循环。 出现黑屏、设置卡死、Type-C、断电重启、桌面能起但进入设置卡死、恢复备份、插拔相机等。01:26:43 现场判断“是不是上电自启动”,随后决定手动点应用。
最终纪律:
- 禁止 GUI 应用开机自启动;
- 禁止崩溃后循环拉起;
- 禁止用 SSH 后台启动需要显示的 GUI;
- 比赛时由 Launcher 手动启动,宁可多一步,不把系统拖死。
01:32—01:59:释放力矩、重设原点、绝对角模式暴露歧义
01:36:28,电机仍自动回到底且人工无法回正。 01:37:53 通过 DCC 0x19 收到 Motor Sleep 后才允许手动回中;正式代码随即改成最多重试三次并必须收到 Sleep ACK。
01:46—01:58,Base3 入口和方向测试。 Base3 确认对应 Task3。+0.5°/-0.5°测试却都可能让球走向画面左端,暴露 0x13 绝对角的“逼近方向/跨圈”语义不可信。
01:55:12,早期保存原点 15624。 这是阶段性值,后续已被 15337 和最终 15241 淘汰,不能再使用。
01:57:29,决定放弃 0x13 双向闭环。 改用 0x11 相对控制,避免绝对角绕行。
教训: 对闭环步进驱动器,命令名“绝对角”并不保证机械会走最短路径。未验证跨 0/环形编码器行为前,绝对目标可能比相对控制更危险。
3. 2026-07-31 02:00—05:54:第三题高强度迭代与失控复盘
02:00—02:30:微步完全无效,转向整角和静摩擦建模
02:01—02:30 连续多轮“启动—按键—观察”得到一致现场证据:
- 02:14:13:没动时闭环应该继续加,但必须有安全限幅;
- 02:16:21、02:18:50、02:20:31:微步完全没反应,明显不如整角;
- 02:24:42:要求始终使能;02:25:41 实测出现明显保持力;
- 02:29 左右仍无动作,说明“已使能”不等于“已克服静摩擦”。
02:16:39,识别出微步失败机制。 将 3°拆成六次 0.5°/23 脉冲时,每次命令都落在机构死区内,物理位置没有累积,软件却以为目标在累积。改为一次下发完整整角,同时保留累计硬限。
02:29:29,编码器证明位置环在动。 电机从 15272 走到 15135,正好 -137 脉冲约 -3°,但球仍未动;说明主要矛盾是机械静摩擦,而非视觉或串口。
02:30—03:18:方向、角度阈值和起动脉冲
02:30:54,首次观察到球明显运动但方向相反。 球从 +0.47 cm 到 -1.20 cm,方向看门狗及时触发 Sleep。
02:44:54,绝对角直接跨圈打到底。 DCC 目标跳到 31963,确认 0x13 不可安全用于该机构的双向闭环;02:45:31 立即锁定应用、禁止校准状态下使能。
02:46:29,切到 0x11 相对整角。 当时重设中位 15555,首次最多 5°≈228 脉冲,累计硬限 ±5°。
02:47—02:56,逐级识别静摩擦阈值。 +5°、+8°仍不足;总偏角约 +20°开始快速向左;负向约 -22°可让球快速向右。由此得到:有效破静摩擦阈值约在 10°~22°之间,并且正负方向不对称。
02:56:25,形成“起动脉冲”思想。 不让 PID 长时间顶在 -22°,而是短时打破静摩擦,检测到位移/速度后立即回到正常控制角。
02:58—03:18,连续调持续时间、检测阈值和再起动。 180 ms 太短;600 ms可起动但有冲端风险;随后加入位移 0.25 cm 或速度 1 cm/s 立即释放、再起动冷却、反向制动门控。03:16 仍出现当前机构位置下 550 ms不足。
经验: 小角度不等于平滑。对有静摩擦的机构,正确的“平滑”是有上限的破静摩擦脉冲 + 运动检测释放 + 速度制动,而不是永远只发 1°~3°。
03:18—03:44:恢复正式第三题,第一次接近成功
03:18:48,现场明确拒绝延长时间。 不能通过把控制超时改成 15 s 绕开题目。03:19:30 要求直接做完整 +5/-5。
03:22:00,正式双阶段版本部署。 正反向均加入破静摩擦起动和对称制动,Maix 控制超时回到 4.9 s。
03:33:43,现场再次指出“电机动了但没克服静摩擦”。 这证明控制必须记录球是否真正动,而不能只看电机 ACK。
03:34:25,首次明确要求建立调参记录。 后续每轮本应记录时间、参数和结果。
03:42:09,摄像头被移动,必须重新标定。 这是后面物理刻度与画面中心偏差的重要来源。
03:44:08,一轮已经在 2.96 s 到达 -4.96 cm,速度 -0.10 cm/s。 这是理想捕获时刻;失败原因不是到不了,而是控制器没切到水平保持,继续 PID 并误触发反向强起动。随后确立:
- -5 阶段禁止二次强起动;
- 首次进入 -5±0.8 cm 且速度≤2 cm/s立即调平;
- 水平保持 180 ms 且仍在 -5±1 cm才 DONE。
03:45—05:05:到点、残余角、启动抽动与记录中断
03:48:20,退出键退不出去;03:50:23,应用启动时电机会抽一下。 后来追到系统启动脚本在 comm method=none 时仍初始化 UART0/A16 并输出 serial ready,与其他电机链路复用产生瞬时扰动。结论是应用启动应保持使能,但不能盲目执行旧原点;系统 UART 服务也必须真正关闭。
04:25—04:29,应用启动使能要求被再次确认。 不使能时机构容易受外界扰动;使能只负责保持,不应自动往旧角度抽动。
04:33:39,一轮正向峰值降到 +6.60 cm,但负向过冲到约 -9.39 cm。 说明正向起动改善,负向阻尼不足。
04:44:58,发现 HOLD 进入时执行器仍残留 -10°。 位置已到 -4.99 cm、速度也不大,但杆未归平,随后继续加速。由此引入 UNWIND:先卸掉实际残余角,再进入 HOLD。
04:58:30,现场询问当前是不是视觉闭环和位置/速度环。 答案是肯定的:视觉位置和估计速度决定杆角;问题不在“有没有闭环”,而在执行延迟、静摩擦和状态切换。
05:05:01—05:05:08,流程性失败被现场直接指出:4 点以后没有继续记录,也没有回看《调参记录.md》。 这是随后越调越差的主要管理原因。
05:05—05:54:连续叠加修改导致退化,明确回退
05:10:11,回退后主轨迹恢复。 球到 +8.18 cm,负向最低 -6.26 cm,并在 2.78 s 到 -5.46 cm、+0.90 cm/s、实际角 0°。剩余问题是机械延迟导致 HOLD 后速度继续增长。
之后继续叠加入口脉冲、自适应 UNWIND、扩大窗口等机制。局部都有理由,但组合后不可预测。
现场连续反馈:
- 05:14:17、05:16:42:最终都卡在 3 cm;
- 05:19:19:越来越差,偏离原来较好方向;
- 05:29:13:无法继续接受这种退化;
- 05:29:48:已改约 15 版但没有实质进展。
05:19:40,正式承认偏离并回到第 10 轮简单基线。 删除叠加的 UNWIND、自适应释放、宽捕获和入口脉冲,只保留主轨迹、硬保护和日志。
05:37—05:45,尝试用多轮轨迹辨识运动模型。 五轮完整任务拟合得到总等效延迟约 260~400 ms,正向峰值速度 12.2~15.2 cm/s、负向 21.5~29.9 cm/s;但因输入本身来自闭环,二阶拟合出现非物理“负阻尼”,残差约 9.5 cm/s² RMS。结论:闭环轨迹不能直接当开环模型,需要固定角度短脉冲数据。
05:48:44,现场先判断视觉误差大;05:49:26 随即纠正为视觉延迟大。 这个纠正改变了方案方向:不是继续做静态标定微调,而是提高控制帧率。
教训: 连续改很多版并不等于信息增益。若没有版本标签、单变量和回退点,更多试验只会让控制器更复杂、现场更疲惫。
4. 2026-07-31 05:50—10:52:视觉换轨、物理相位回中与第三题收束
05:50—06:03:从持续 YOLO 切到混合视觉
05:50—05:54,讨论传统视觉高帧率。 香橙派3B+OV9281 可作为 150~200 fps 路线,但比赛时间不足,最终保留 MaixCAM。
Maix 实测基准:
- 480×480 纯取帧:60 fps;
- 全局霍夫圆:1.78 fps,淘汰;
- 100×70 局部霍夫:33.5 fps,且误抓车轮边缘;
- 模板匹配:67.8 ms,淘汰;
- YOLO 首次定位:41.2 ms;
- 80×60 自适应 LAB:算法 7.4 ms;
- 含取帧总周期 18.9 ms,约 53 fps;
- 静止抖动 0.13 px,120 帧成功率 100%。
06:02:27—06:03:26,混合视觉接入正式 Task3。 YOLO 只负责首次定位/丢失重捕;局部 LAB 跟踪进入每帧控制;显示降到约 18 fps,与控制解耦;电机参数保持第 10 轮基线不动。
06:03—06:55:发现真正的机械基准问题
06:05:05,现场发现响应快但根本没往负方向控制。 说明换视觉只降低延迟,不能自动修复方向和状态机。
06:11:49—06:14:32,现场提出关键改进:不应每轮人工摆轨道,步进电机有编码器,应固定到约 15000 多的中位。 这是整个系统稳定性的转折点。
随后通过 DCC 真实编码器相位确认:
- 早期软件累计角与物理相位不同步;
- 任务结束可能还残留 7°;
- 主程序声称 -28°,实际并没有稳定保持对应物理倾角。
06:43:35—06:44:57,最终机械中位确定。 用 0x12 读真实单圈相位,以 15241 为水平目标,按最短差值用 0x11 相对修正,再次读取验收;最终 15244,误差 3 脉冲,约 0.066°,并保持使能。
这套流程取代:
- 旧原点 15624/15337;
- 软件累计角回中;
0x13绝对角;- 软重启探测。
06:50:02,独立硬件验证。 实际相对到至少 -21°后,球从中部滚到 +13.76 cm端点,证明电机、连杆和方向正常;第三题此前失败主要是软件状态与真实相位不同步。
06:55—07:45:换向、提前制动与轮间继承
06:54:55,启动校正从环形相位 1124 自动回到 15238,误差 3 脉冲。 环形编码器跨零场景得到验证。
07:10—07:25,多轮现场观察指出三个错误:
- 本可进入负向,却又多顶一次;
- 距离只剩约 3 cm 时反而往错误方向打;
- 到位置后仍继续输出,最终打到底。
07:16:40,确认问题不是积分继承。 阶段切换时积分已清零;真正错误是普通 8°渐变限幅让当前 -15.44°只能先走到 -7.44°,换向后第一拍仍在错误方向。任务中换向必须允许在安全范围内直接跨零,而启动/停止回中仍分段进行。
07:31:33,一轮首次进入 -4.96 cm,但速度仍 -13.91 cm/s。 负向制动晚一个 DCC 周期:等到过零后才 BRAKE,第二档制动建立时已经冲到 -6.95 cm,惯性最低到 -9.06 cm。
07:31—07:38,制动点在 +4.5、+1.5、-0.5 cm间来回试。 +4.5 太早,只到约 -1.2;后续幅度越来越小。07:38:23 现场要求回到前三轮中“除了刹不住,其余明显更强”的版本,随后精确回退。
07:41:17,发现轮间继承的铁证。 一轮 PRECHECK 起始软件角为 +8°,不是 0°。上一轮故障后物理轨道没有回中,下一次 Task3 只重新使能,导致起点不一致。由此确定:每次 Task3 开始必须重新读取真实相位 15241,验收后清零软件角。
07:41:58,现场进一步要求连小球也自动回中心。 于是状态机扩展为:机械相位回中 → 视觉低速把球收敛到 0 → 居中稳定后才接受/执行 Task3。成功后必须保持 -5;只有显式 STOP/返回才回中。
09:18—10:52:自动回中、Base3 响应和最终可用结果
上午恢复测试后,自动回中仍出现半天不停止、停在 3 cm、任务完成后擅自回正、Base3偶发无响应等问题。现场在 10:07:12 明确:没有按返回就不要回正;第三题最终必须停在 -5。
10:13:02,一轮视觉轨迹突然从约 +4 跳到 -3.53 cm,球心 Y=223.5,偏离正常轨道 Y≈191。 这说明局部跟踪可能抓到轨道外目标;必须约束 ROI/Y 带并在异常跳变时重触发 YOLO,不能让错误坐标直接驱动大角。
10:20:13,得到完整可用但超时结果:
- 正向峰值 +5.46 cm;
- 最终稳定约 -4.9 cm;
- 第一次合格 DONE 时间 7.036 s;
- 首次制动停在 -1.87 cm,随后二次追赶,浪费约 3 s;
- UNWIND 有效,没有撞端。
这一轮说明“能完成运动并保持”已经实现,但题目 5 s 指标未达成。随后只把负向制动起点从 +0.5 cm 改到 -1.5 cm,试图取消二次追赶,并保留原始轨迹。
10:52:23,现场要求写交接并只打包当前最稳定版本。 第三题由持续调参转入交接收束。
5. 2026-07-31 下午:版本辨认、第四题和第五题
15:38—16:04:队友版本不能整包覆盖
读取队友交接包后,最终第三题基线被认定为 TUNE-3PT-20260731-A;D 为明确失败版,C 只有局部改善。现场要求把当前在用版单独剥离,并清理历史脚本、只保留调参记录。
对 MSP 工程的结论:队友 D 版不能整包直接替换用户 Keil 工程;应迁移通信和任务功能,保留用户已经验证的循迹基线。版本迁移应按模块和差异进行,不能按文件时间“新就覆盖旧”。
16:04—18:12:Base4 同时支持循迹与滚球
现场要求 MSP 按键命令发出后 Maix 所有任务都能响应,而不是只能运行单一第三题。Base4要求直线 150 cm,同时把球稳定在 O 点。
问题序列:
- Base2一度线还在中间却不循迹,否定了简单“宽黑误停”解释;
- 尝试让 Base4 自动拉起 Maix 应用,但造成软件死机;16:43现场决定取消,比赛时手动点应用,降低风险;
- 相机移动后标定出现约 +2 cm偏差;回中一度落在 -2/+1物理刻度;
- 车辆起步直接误停、滚球振荡到 6~7 cm;
- 小角度打不动,停车和起步冲击尤其明显。
17:12:01,现场给出正确控制原则:应做平滑,而不是永远固定死一个参数。 后续起步/停车采用随车辆阶段变化的目标和限幅,而不是固定摆杆角。
17:49—18:10,Base4主要问题收束到启动与停车。 停车时球曾到 -4 cm;18:12现场决定先固定这一版,进入下一题。
18:12—20:23:Play1/Task5、陀螺仪前馈与 GYROFIX3
18:43:38,任务名纠正:第五题是 OLED Play 1,不是 Base5。
首轮发现第二弯只走一半,循迹距离过短;同时弯道滚球不稳。19:05现场要求把 MSP 陀螺仪数据用起来。
19:17:19,第一轮同步数据: 29.68 s、500帧、201个 UART 包;位置 -2.54~+4.60 cm,RMS 1.83 cm,70.6%帧超±1 cm。极端振荡已减少,但第一弯正偏明显。
19:31:09,错误判断:认为陀螺仪前馈符号应翻转。 同时保留了正确的两个观察:起步未稳定、直线 8°脉冲过大。
19:37:53,实测立刻否定符号翻转。 范围恶化到 -6.02~+2.20 cm,RMS 3.02 cm,超±1 cm 78.1%。但回中握手和 1500 ms缓启动将起步峰值从 +2.98 降到 +1.56 cm,应保留。
GYROFIX2: 恢复原前馈方向,加入受限直线脉冲。结果 -3.11~+3.69 cm,RMS 1.97 cm,超±1 cm 62.5%。
20:09—20:15,GYROFIX3:
- 前馈若与视觉纠偏方向冲突则关闭;
- KD 0.45→0.9;
- 直线破静摩擦 5.5°/260 ms;
- 触发阈值 0.8→0.65 cm;
- 弯道禁止脉冲。
结果:29.69 s,范围 -3.14~+2.59 cm,RMS 1.61 cm,超±1 cm 59.0%,无超过±4 cm,停车后约 -0.19 cm。第一弯正峰从 +3.69 降到 +2.59 cm。
GYROFIX4 试加 5°/160 ms弯道脉冲后,峰值虽小但 RMS 1.68、超±1 cm 62.2%,综合变差。20:23:45完整回退到 GYROFIX3。 这是一次规范的“有指标对比、有明确回退”的成功调参流程。
6. 2026-08-01:Task6、终点门控、停车后继续回目标
04:21—05:04:读取队友 8-1 工程,纠正第六题需求
ti-contest-2026-8-1 被确认为队友承接后的最新基线:Maix应用1.4.1、Prepare Ball、任务RTSP端口、Task5 GYROFIX3、机械中位15241。正式后续只在该目录继续。
04:37:13,开始第六题并要求删除两条灰度分支。 GRAY_SENSOR_GANV_NO_MCU 和 GRAY_SENSOR_GANV_MCU 不再保留,避免并行分支让现场不知道实际编译哪条逻辑。
04:41—05:04,需求理解先复杂后简化。 最初设想 OLED 选择 Sign± 和 Position 1/2/3;重新读题和现场讨论后确认:用户自动回中,再手动把球摆到任意实体刻度,Play2启动时直接捕获当前位置为目标即可。无需复杂菜单,也不存在动作队列容量问题。
05:13—05:53:自动回中失败、Prepare Ball First 和 RTSP 崩溃
自动回中时常只使能不动作。读取证明两条 UART 均正常,编码器能回 15242;真正失败是视觉稳定判据过严:最后 -0.49 cm、0.55 cm/s,但要求±0.35 cm连续1000 ms,20 s后超时并主动 Sleep。
05:38:16,Task6直接报 Prepare Ball First,同时相机似乎卡死。 后续拆出两个独立原因:
- MSP READY锁存与Maix状态不同步,任务在 MSP 侧被提前拦截,甚至没发送
TASK:6; - Maix 应用后来确实退出/崩溃,不能把一切归为误触或网络。
05:41:03,现场否定“误触退出”的轻率结论,并要求触摸恢复。 后续日志最终找到真正根因:
mmf_region_update_canvas failed → camera read timeout → SIGSEGV(11)
RTSP客户端重连时,底部刻度使用的 MMF 硬件 Region叠加层崩溃。解决方案是禁用硬件刻度叠加,保留视觉检测、控制和刻度数据,不再用该不稳定显示路径。
05:51—06:14:Task6不能照搬Task5,停车控制从一端走到另一端
05:51:35,现场发现手摆 +2 后程序像在往0点平衡。 数据表明目标没有真的被改为0,而是捕获为 +1.364 cm;但 Task6直接复用了Task5增益和静摩擦参数,小偏差时仅输出约 -1.2°,长期卡在0附近,造成“像照搬Task5”的现象。于是 Task6控制参数独立。
05:58—06:01,一轮任意目标数据: 捕获 +5.326 cm;第一弯偏差 -3.81 cm,第二弯 -4.01 cm;停车瞬间球在 +4.326 cm、速度 +2.57 cm/s,CAR:HOLD 立即回0撤掉制动角,丢球帧还残留 -2.25°,把球推向正端。改为加强Task6弯道前馈、停车保留速度制动、丢球立即回平。
06:08,停车后误差0.8 cm但PD只有0.87°,静摩擦不动。 随后加入 HOLD阶段 5°/220 ms恢复脉冲。
06:14:43,轨迹证明该方案过度:HOLD后闭环跑了97 s,球在 -9.59~+9.32 cm反复追打,角度多次饱和±10°。 于是立即撤销持续恢复脉冲,改为有限制速度制动后回平。这是典型的“两端错误”:完全冻结会漂,永久追目标会打端点;最后应是有安全限幅的持续视觉收敛。
06:13—06:48:A点漏检、错误614兜底、第二弯门控与660兜底
现场同时报告车辆没有在A点停,多走接近半段直线。题面和代码确认 Base2、Task5、Task6物理路线相同,约614.16 cm;区别是速度、负载和打滑,不是路线长度。
06:27:34,XDS铁证: Task6 h_result=3、30003 ms超时、stop_mark=0。第一次回A完全漏检,30秒后强停。
曾把宽黑从5路降到4路,06:28:54现场明确否决:弯道可能误识别,阈值不能降。最终保持5路。
错误尝试:614 cm左右里程兜底。 06:33现场发现第二个半圆没完成就停车;XDS显示24.69 s正常完成、stop_mark=0,100%由里程兜底提前触发。原因是速度/负载/打滑让编码器“614 cm”不等于物理一圈。
最终方案:
- 用陀螺仪确认第二弯已经进入并完成;
- 完成第二弯后才允许5路A点识别与里程兜底;
- A点宽黑优先;
- 兜底提高到660 cm。
06:36:51,该版本编译、烧录、校验成功。
06:41:21,一轮28.717 s正常完成,stop_mark=0,由660兜底。 车辆位置合适,但硬刹令球漂到 -6 cm以上。随后只改停车过渡:640~660 cm由12线性降到7.5 cm/s,不提前发送固定 CAR:BRAKE。06:48:07 编译烧录成功。
06:50—06:56:任务结束后不能把球丢下
06:50:43,一轮 Task6 28.166 s完成,但球未回设定刻度。 旧 Maix 对 CAR:HOLD 的处理是终态冻结,视觉不再追目标。
06:53:32—06:53:50,现场给出最终业务要求:即使30秒超时,也不能把球丢在那里,必须继续打回设定刻度。
因 Maix重装后 SSH认证暂时不可用,先在 MSP 做兼容:车辆已由 car_stop_and_reset()停止,任务完成/超时后不发冻结视觉的 CAR:HOLD,改为重复发 CAR:CRUISE,让旧Maix继续纯视觉闭环;不发 STOP,避免清除Task6任意目标。
06:56:07,该 MSP 修复0错误0警告并烧录成功。 这是板上最后确认成功写入的核心功能版本之一。
7. 2026-08-01 下午至 2026-08-05:Base4里程、DAP故障和当前状态对账
08-01 16:38—17:11:第四题实际只走120 cm
16:38:13,检查第四问循迹距离。 源码目标为150 cm;现场实测物理只有约120 cm。
按 150/120=1.25,本地源码将 Task4独立编码器目标改为187.5 cm,并把巡航25提高到28 cm/s,预计约7.45 s,满足8 s。全量编译0错误0警告。
当时XDS110和Keil均在连接阶段报DAP错误,所以在该次远程调试中没有烧入。比赛阶段参赛者后来手动烧录了最终固件;赛后归档中的Base4最终值为187.5编码器厘米/28 cm/s。此后出现的Base2只转左轮属于当时的阶段性故障,不能用来否定最终固件。
08-05:把“本地源码、板上固件、Maix设备”三层分开
调试会话结束时的对账曾区分本地源码、板上固件和Maix设备;赛后根据最终文件夹和参赛者确认,更新为:
- 最终MSP: Base4为187.5/28;Task5/6包含第二弯门控、5路A点、660兜底、640~660平滑降速和结束后继续视觉收敛,已由参赛者手动烧录。
- 最终Maix: 应用1.5.0,控制身份
TASK6-CAPTURE10-SAFE-PARK-20260801,Task6任意位置捕获、停车恢复角限5°、稳定窗±0.65 cm且速度<0.5 cm/s均已进入正式源代码。 - 最终上位机: RDK X5控制台支持Task1~6端口巡检、显示、录像、断流保存、索引与回放。
这也是后续交接最容易犯错的地方:文件最新不等于板上最新;板上MSP最新不等于Maix应用也同步。
8. 失败模式—根因—以后怎么做
| 失败现象 | 当时容易误判 | 最终根因/证据 | 以后固定做法 |
|---|---|---|---|
| 上电打到底、堵转 | 用户没摆中 | 软件绝对零点不是真实水平;0x13跨圈;Sleep未验收 |
读真实相位→0x11最短相对修正→复读验收;机械限位与故障Sleep |
| 电机ACK但球不动 | 视觉/PID坏了 | 3°编码器确实到位,球仍不动;静摩擦阈值高 | 受控整角短脉冲,检测运动立即撤力 |
| 微步连续发仍不动 | 多发几次会累计 | 每个23脉冲都落在死区,物理不累计 | 禁用微步作为主控制手段 |
| 到-5后仍冲端点 | 制动力度不够 | 到点时杆仍残留角、球速未降;状态机继续PID | 先UNWIND/速度制动,再HOLD;位置、速度、实际角三条件 |
| 同参数每轮结果不同 | 环境随机 | 上一轮残余+8°/-16°被下一轮继承 | 每轮以编码器15241重建初始条件 |
| YOLO框稳定但控制差 | 静态坐标误差大 | 主要是约40 ms推理和总延迟 | YOLO种子+局部LAB,控制与显示解耦 |
| Maix黑屏/卡死 | 网络掉了/误触 | 多实例资源争用;RTSP硬件Region重连触发SIGSEGV | Launcher单实例;禁自启;禁硬件刻度叠加;统一释放 |
| Base3按了没反应 | OLED坏了 | READY门控、Maix进程退出、状态不同步 | 命令阶段和ACK分层记录;Maix真实状态决定是否启动 |
| A点漏检后跑第二圈 | 路程设置长 | stop_mark=0、30 s超时;5路线采样没命中 |
第二弯门控+A点优先+660兜底 |
| 614兜底少半圈 | 题面长度错 | 24.69 s、stop_mark=0,编码器提前到614 |
不用理论路程直接等同物理路线;结合IMU阶段 |
| 停车后球漂走 | 应立即回平 | HOLD冻结视觉,静摩擦和余速仍存在 | 车停与球控分离;视觉继续追保存目标并带安全限幅 |
| 连改15版越来越差 | 还需继续微调 | 机制叠加、记录中断、初始条件不一致 | 单变量、版本标签、三轮复测、无改善立即回退 |
9. 最值得吸取的调试方法
9.1 每轮实验前必须冻结五件事
- 代码版本标签与文件哈希;
- MSP板上固件版本,不只看本地源码;
- Maix实际运行的应用版本与进程PID;
- 机械编码器相位和球初始位置;
- 本轮只允许改变的一个参数/一个机制。
9.2 每轮统一记录
时间:
任务与版本:
机械初相位/终相位:
球初始位置:
唯一改动:
正向峰值、负向峰值:
首次进入目标时间与当时速度:
最终位置与稳定时间:
是否触发强起动/几次:
结束原因:DONE / FAIL / TIMEOUT / STOP
车辆停止原因:A点 / 里程兜底 / 超时
现场异常:碰撞、风、手摆误差、摄像头移动、网络/进程异常
结论:保留 / 回退 / 还需同版本复测
9.3 决策纪律
- 单轮好结果只算“候选”,至少连续三轮同初始条件才算改善。
- 若结果恶化,先回退,不在恶化版本上继续补丁叠补丁。
- 参数变化和状态机变化不能同轮进行。
- 任何“没有反应”先分层:命令是否发出、ACK是否收到、编码器是否动、机构是否动、球是否动、视觉是否正确。
- 任何“提前停止”必须读
h_result / elapsed / stop_mark / mileage,不能只凭画面猜宽黑。 - 任何相机黑屏先看进程、MMF、RTSP、显示所有权和退出来源,不能先重启循环。
- 编译成功后必须保存烧录结果;连接阶段失败等于没有改动板上程序。
10. 对这次协作本身的复盘
做得好的部分:
- 通过 XDS 内存、DCC编码器相位和Maix轨迹,把多次“看起来像”转成了证据;
- 发现持续YOLO延迟后,用基准测试选择局部LAB,而非继续凭感觉调PID;
- Task5使用统一指标对比FIX2/FIX3/FIX4,并明确回退到FIX3;
- 最终把设备、源码、板上固件三种版本状态分开。
需要避免重演的部分:
- 早期对机械中位和DCC绝对角语义验证不足,造成一次严重触底;
- 过早把相机退出归因于误触、把网络可用等同于应用可用,结论下得太快;
- 7月31日4点以后没有持续维护调参记录,多项改动叠加,浪费大量现场轮次;
- 让现场反复执行启动、回中、摆球,自动化和初始条件固定做得太晚;
- 有时先改参数再读取完整轨迹,正确顺序应是先保存证据、再确定唯一改动;
- 自动拉起Maix GUI、自启、后台运行等方案在资源脆弱的设备上风险过高,最终仍回到手动Launcher。
真正有效的进展通常不是“再调一个增益”,而是消除一个不可控变量:真实机械零点、统一初始条件、视觉延迟、状态机边界、版本口径、停止原因。先让实验可重复,再谈参数最优。
5 问题结论与实验记录模板
比赛已经结束,参赛者确认最终MSPM0固件已手动烧录。完赛版包含Base4的187.5 cm/28 cm/s、Task5/6的660 cm兜底、640~660 cm平滑降速和完成/超时后继续追目标;Maix正式代码为1.5.0,并已包含Task6任意位置捕获。本文的故障条目是赛前复盘,不是当前待办。
已解决或已定位
编码器计数不符
- 实际单位时间计数约为 300 多,并非按 MG310 的 1066 计算。
- 寄存器范围为
0x40~0x47,需结合拨码表确认读取含义。

MPU6050、U8g2 与 CPU 阻塞
- MPU6050 FIFO 冲击曾造成阻塞和反复异常。
- 相机 MMF/VI 缓冲未释放是反复崩溃的主要原因,不是普通内存不足。
- 已通过显式释放帧、单实例锁、单缓冲和完整清理链路修复。

上电异常脉冲
- 根因:
S06maixapp无条件初始化 UART0 并向 A16/UART0_TX 写入数据。 - 结果:重启时可能触发 TB6612 PWMA,导致电机突然动作。
- 当前策略:
method=none时跳过 UART0;相机异常只安全退出,禁止循环强制重启。
机械原点与回中
- 旧原点先后记录为
15624、15337,均已过时。 - 最新水平目标相位为
15241,实测15244,误差约0.066°。 - 回中状态机曾因成功门限和 4° 脉冲门限都设为
±0.2 cm而抖动,出现READY → CENTER → READY循环。 - 正式方案改为真实编码器相位闭环,不依赖旧绝对零点。

第三题:定点往返
最接近成功的一轮
- 球在
2.96 s到达-4.96 cm,速度仅-0.10 cm/s。 - 失败原因:未及时切换水平保持,PID 继续大幅修正,引发二次振荡和错误的反向强起动。
由此确定:
- 只允许
+5 cm阶段自动再次强起动。 -5 cm阶段禁止二次强起动。- 首次进入
-5 ± 0.8 cm且速度≤2 cm/s时立即调平。 - 水平保持
180 ms且仍在-5 ± 1 cm才发送DONE。
当前最好完整结果
| 指标 | 结果 |
|---|---|
| 正向峰值 | +5.46 cm |
| 最终位置 | 约 -4.9 cm |
| 长期保持 | 稳定 |
| 完成时间 | 7.036 s |
当前瓶颈:第一次制动停在 -1.87 cm,随后发生第二次追赶,浪费约 3 秒。下一步应优化提前制动和负端一次捕获,不应继续增强强起动。
第五题:行驶稳球
实验对比
| 版本 | 位置范围 | RMS | 超出 ±1 cm |
结论 |
|---|---|---|---|---|
| 初始陀螺仪前馈 | -2.54~+4.60 cm |
1.83 cm |
70.6% |
极端振荡减少,但第一弯补偿不足 |
| 前馈符号翻转 | -6.02~+2.20 cm |
3.02 cm |
78.1% |
明显变差,翻转方向错误 |
| GYROFIX2 | -3.11~+3.69 cm |
1.97 cm |
62.5% |
消除超过 ±4 cm 的情况 |
| GYROFIX3 | -3.14~+2.59 cm |
1.61 cm |
59.0% |
完赛代码保留的综合最佳基线 |
已确认的控制结论
- 回中握手和
1500 ms缓启动有效:起步峰值由约+2.98 cm降至+1.56 cm。 - 完全取消静摩擦脉冲不可行;约
+1°的持续小角度不足以让球脱离静摩擦。 - 原 8° 脉冲过强,会在行驶振动中造成反冲。
4.5°短脉冲方向正确但偏弱,通常只移动约0.1~0.3 cm。- 固定方向的纯前馈不可靠:第一弯可能抵消视觉纠偏,第二弯却可能有效。
- 速度阻尼
KD=0.45偏小,过中心后撤力较迟。
后续实际采用的方案
- 恢复原前馈符号;
- 前馈与视觉纠偏同向时全量启用,反向时关闭;
- Task5的
KD最终取0.9; - 直线短脉冲最终取
5.5°/260 ms,只在直线、低速和明显偏差时触发; - GYROFIX4弯道固定脉冲综合指标变差,因此回退并保留GYROFIX3。
完赛时保留的局限与历史故障
- 已保存的第三题完整轨迹中有一轮用时7.036 s;这是赛前测试数据,不等同于最终赛场成绩。
- 自动回正、约3 cm位置静摩擦卡滞和机械滞回曾显著影响重复性。
- 早期240 px中心与实体刻度偏约2 cm;完赛标定已更新为
3PT-20260731-E / 230 px。 - XDS110 COM7枚举和DAP拒绝连接曾中断远程烧录;最终固件后来由参赛者手动烧录。
- Task5两段弯道对固定方向前馈的需求不同,最终通过“与视觉纠偏冲突时关闭前馈”收束。
- Task6最终源代码包含任意目标捕获、停车恢复角5°和结束后继续回目标逻辑。
- Base4最终采用1.25校正,即187.5编码器厘米和28 cm/s。
- Base2只转左轮是最后阶段出现过的故障现象,作为硬件/输入排查经验保留,不再列为赛后待处理任务。
如果今后重做类似系统:实验记录模板
#### YYYY-MM-DD HH:mm|版本名
- 代码版本/提交:
- 机械零点与编码器相位:
- 参数改动:
- 总时长:
- 位置范围:
- RMS:
- 超出 ±1 cm:
- 第一弯峰值:
- 第二弯峰值:
- 最终位置/速度:
- 异常与安全事件:
- 结论:
- 下一步只改:
6 原始调试记录归档
本章保留现场原文和失败尝试,不与第 1~5 章的最终结论混用。需要复现时先查主线;只有当主线无法解释某个现象时,再回到这里追溯上下文。
以下内容按当时现场状态原样保留,其中“当前”“下一版”“未烧入”等词只代表记录生成时刻,不覆盖本文第1章的完赛最终状态。
maxicampro装侧面,直接获取二维坐标(x,y) 假设水管在图像里的两个端点为:
P0=(u0,v0),P1=(u1,v1)P_0=(u_0,v_0),\qquad P_1=(u_1,v_1)P0=(u0,v0),P1=(u1,v1)
YOLO 检测框中心为:
P=(u,v)P=(u,v)P=(u,v)
水管方向向量:
d=P1−P0\mathbf d=P_1-P_0d=P1−P0
把钢球坐标投影到水管轴线上:
λ=(P−P0)⋅dd⋅d\lambda= \frac{(P-P_0)\cdot\mathbf d} {\mathbf d\cdot\mathbf d}λ=d⋅d(P−P0)⋅d
再转换成实际位置:
s=(λ−λO)Ls=(\lambda-\lambda_O)Ls=(λ−λO)L
其中:
- L=0.25 mL=0.25\text{ m}L=0.25 m
- λO\lambda_OλO 是中心点 O 对应的位置
- s=0s=0s=0 为中心
- s=+0.05 ms=+0.05\text{ m}s=+0.05 m 为 +5 cm
- s=−0.05 ms=-0.05\text{ m}s=−0.05 m 为 −5 cm

- 计数错误,我去,不是mg310的1066啊,这个电机的编码器单位时间计数实际300多
寄存器地址0x42,嵌套计算0x40到0x47,拨码表确定。


O→+5→-5。
/etc/init.d/S06maixapp 无条件把 UART0 映射并向 /dev/serial0 写入“serial ready”,而 UART0_TX 正是 A16,也就是 TB6612 的 PWMA。method=none 只关闭 Maix Comm,并没有阻止这段开机 UART 写入,所以每次重启仍可能给电机一个脉冲。
之前反复崩溃不是普通内存不足,而是相机 MMF/VI 缓冲未释放,我又错误地用强制重启恢复,导致 A16 启动脉冲带动电机。
已经修复:
- 新增单实例相机锁,禁止 Launcher、探针和任务程序重叠占用摄像头。
- 关闭生产模式的 RTSP 和屏幕显示。
- YOLO 改为单缓冲,摄像头通道
buff_num=1。 - 每次读取下一帧前显式释放当前
frame。 - 从控制器、模型到相机通道全部纳入完整清理流程。
- 电机子进程会在相机父进程崩溃时检测 EOF,并自行拉低输出。
- 修正开机脚本:当
comm method=none时,不再初始化 UART0,也不会向 A16/UART0_TX 发送serial ready。 - 原启动脚本已备份为
/etc/init.d/S06maixapp.pre-codex-20260730。 - 今后相机异常只安全退出并报错,禁止自动强杀、重复初始化和强制重启。
当前 PID 732 正持续保持:
A16=LOW
A22=LOW
A23=LOW
新版稳定运行时是 hybrid_visual_runtime_stable.py,已同步到 MaixCAM,但我没有再次启动。
下一次应先断开电机电源或保持从齿轮脱开,只验证相机能够稳定启动、运行、退出并完全释放;通过后再接回机构。不会再用重启解决相机问题。

新原点,机械中位已保存为 15624步进电机初始化中点位置

0x11 相对整角控制:首次最多 5°≈228脉冲 一次下发,不再拆成无效微步;软件累计硬限 ±5°
3点的时候有点改善了
- 新原点:
15337 - 运动触发释放起动脉冲
- 位移阈值:
0.25 cm - 速度阈值:
1 cm/s - 单次角度变化限制:
8° - 反向制动上限:
+3° - 最终状态:
Motor Sleep
自动再起动现在按预期反复在 -22° ↔ 约-5.6° 之间工作,但每次 -22° 的最长保持只有 550 ms;在当前机构位置仍不足以破静摩擦。由于已经有“检测到运动立即释放”,可以安全地把最长等待延长到 1200 ms:没动就继续保持,一旦球开始动仍会立即撤销,不会固定推满 1.2 秒。
按第三题完整版做:从 O 点先到 +5 cm,再反向到 -5 cm,并在 -5 cm 附近稳定;整段仍限制 5 秒、最大偏差按 1 cm 判定,不延时。
我会把现有“单点 +5 cm”状态机改成双阶段轨迹,重点用一次强起动克服静摩擦、提前制动,并给正反向各自独立的安全角度限制。先让当前已启动程序安全停机,再改代码部署。
目前还差一部分
本轮轨迹其实已经非常接近成功:球在 2.96 s 到达 -4.96 cm,速度仅 -0.10 cm/s,这就是理想的捕获时刻。失败是因为控制器没有切换到“水平保持”,继续做大幅 PID 修正,造成二次振荡;最后又误触发了反向强起动,球滚到右端。电机已安全回到 0° 并休眠。
我现在按轨迹做确定性修改:
-
只允许 +5 阶段自动再次强起动,-5 阶段禁止二次强起动。
-
首次进入
-5±0.8 cm且速度 ≤2 cm/s 时立即把杆调平。 -
在水平状态连续保持 180 ms 且仍在
-5±1 cm才发送 DONE。 -
若漂出范围再恢复普通控制,不会打
-28°强脉冲。 -
MaixCAM YOLO 检测球的像素坐标,标定成位置
x(cm)。 -
连续帧的位置差经过滤波,估算球速
v(cm/s)。 -
位置环根据球到
-5 cm的剩余距离生成目标速度:
v_target = sign(error) × sqrt(2a|error|)。 -
速度环根据
v_actual - v_target计算摆杆角度。 -
DCC 驱动器内部执行并保持步进电机角度。
重启后基准成功:自适应LAB色块明显胜出。
- YOLO首次定位:
41.2 ms,只需偶尔调用 - 局部模板匹配:算法
67.8 ms,太慢,淘汰 - 80×60自适应LAB色块:算法
7.4 ms - 加取帧后总周期约
18.9 ms,约53 fps - 静止中心抖动仅
0.13像素,比当前YOLO控制环快约3倍
已经恢复到刚才手工找平的位置,并完成真实编码器闭环验证:
- 水平目标相位:
15241 - 最终实测相位:
15244 - 误差:3脉冲,约
0.066° - 电机当前持续使能保持
- 正式启动代码已部署
开机回中现在使用:读取真实编码器相位 → 0x11相对修正 → 再读相位验收,不再使用有问题的 0x13 或软重启探测。
- ED→MSP→UART→Maix 的链路正常,确实执行了第三题;
- 正向最高
+4.10 cm; - 负向最低
-4.03 cm; - 4.9秒末停在
-3.90 cm / 0.18 cm/s,差约0.3cm进入完成容差; - MSP随后正确发送STOP并自动回中。
原因是负端低速时保持角只有约1.5°,克服不了静摩擦。
自动回正还有明显问题。
核心不是零点标错,而是回中状态机缺少滞回:
- 成功门限和4°脉冲触发门限都是
±0.2 cm。 - 球刚在
-0.14 cm进入READY 0,视觉抖动到约-0.20 cm就会立刻重新触发4°脉冲。 - 结果是已经回中的球又被主动推走,出现
READY → CENTER → READY反复切换。 - 从远端回中时还可能因静摩擦突然释放,产生较大速度,恢复时间过长。
改为8°、最长700ms,并保留速度≥1cm/s立即反打;从-8°回到0°正好是一条安全步长。 3cm左右严重卡死
读取完成:
- 正向峰值:
+5.46 cm - 最终位置:约
−4.9 cm - 长期保持:稳定
- 完成时间:
7.036 s,超时
问题是第一次制动停在 −1.87 cm,随后发生第二次追赶,浪费约3秒
Status : OK Class : Ports FriendlyName : XDS110 Class Application/User UART (COM7) InstanceId : USB\VID_0451&PID_BEF3&MI_00\7&B69B450&0&0000 xds枚举问题
12 次球心在 239–241 px,中位数正好 240.0 px
这个位置在+2cm,还是不合适。
- 时长:29.68 秒
- 轨迹:500 帧
- UART 接收:201 包,说明陀螺仪报文已送达
- 小球范围:
-2.54~+4.60 cm - 最大正偏发生在约 10.41 秒,应该是弯道阶段
- RMS 误差:1.83 cm
- 超出 ±1 cm:353/500 帧(70.6%)
- 没再出现之前的
-8~+6 cm极端摆动 - 停车前约
-0.75 cm,随后保持在+0.28 cm
结论:陀螺仪前馈确实起作用了,极端震荡明显减小,但弯道仍偏向 +4.6 cm,补偿量或方向还没调准。轨迹已保存到 task5_gyro_latest_trace.json。
19:17
本轮结果:
- 位置范围:
-3.25~+4.87 cm - RMS 误差:
2.11 cm - 超过 ±1 cm:
72.3% - 第一弯:角速度约
-23~-28°/s,球冲到+4.87 cm - 第二弯:角速度同样约
-23~-28°/s,球主要停在-2~-3 cm
同步数据已经明确暴露三个问题:
-
陀螺仪前馈符号反了
第一弯视觉 PD 正在输出+2.8~+3.9°拉球回中,但陀螺仪前馈却叠加-0.65~-0.85°,削弱了纠偏。应把增益从+0.035改为-0.035。 -
起步前没有真正稳定
进入弯道前小球已经到过+2.98 cm。Task5 目前收到命令后车辆直接起步,应改成 MaixCAM 确认球稳定在中心后,再回复BALL:STARTED让 MSP 起步。 -
直线仍触发 8° 静摩擦脉冲
车辆行驶时本身已有振动,不需要这种大脉冲。它造成第一弯后从+4.8反冲到-2.35 cm。Task5 应禁止静态脉冲,始终使用平滑的小角度视觉 PD 加陀螺仪前馈。 19;39 这版整体变差,但原因已经很清楚:
- 完成时间:
29.69 s - 位置范围:
-6.02~+2.20 cm - RMS:
3.02 cm - 超过 ±1 cm:
78.1% - 第一弯结束冲到约
-4.42 cm - 第二弯最低达到
-6.02 cm
同步数据说明:
-
前馈翻转错了
弯道角速度约-27°/s时,前馈变成+0.8°,随后球持续向负方向移动。应恢复原来的负前馈方向。 -
起步改善了
起步峰值从上一版约+2.98 cm降到+1.56 cm,回中握手和 1500 ms 缓启动有效,应保留。 -
完全取消静摩擦脉冲也不行
直线上持续输出约+1°,但球卡在+1.5 cm,说明小角度无法克服静摩擦。不能恢复原来 8° 大脉冲,应改成约4~5°、150~250 ms的短脉冲,只在直线、低速且误差超过约 0.8 cm 时触发。
下一版应:恢复原前馈符号、保留回中握手和缓启动,并加入受限的小幅静摩擦脉冲。
GYROFIX2 确实比上一版好:
- 完成时间:
29.70 s - 位置范围:
-3.11~+3.69 cm - RMS:
1.97 cm - 超过 ±1 cm:
62.5% - 已完全消除超过 ±4 cm 的情况
- 第一弯:
-2.12~+3.69 cm - 第二弯:
-3.11~-1.36 cm
直线小脉冲共触发 9 次。4.5° 能产生正确方向的运动,但幅度偏弱,正侧通常只移动约 0.1~0.3 cm。
现在主要问题是:
- 第一弯球在正侧时,负向陀螺仪前馈会抵消视觉纠偏。
- 第二弯球在负侧时,同一个负向前馈又是正确的。
- 说明不能使用固定方向的纯前馈,需要根据球当前位置限制:前馈若与视觉纠偏方向相反就衰减或关闭。
- 当前速度阻尼
KD=0.45也偏小,过中心后电机撤力较迟。
下一版建议:
- 前馈只在与当前位置纠偏方向一致时全量生效。
- 相反时降为 0,避免第一弯继续推偏。
- Task5 的 KD 从
0.45提到约0.8~0.9。 - 直线脉冲提高到约
5.5°/260 ms,仍远低于原来的 8° 大脉冲。
19:51
2026-08-01之后的完整记录入口
本文件保留早期逐段原始记录。Task4、Task5、Task6、660 cm兜底、停车恢复、XDS内存诊断、目标DAP锁死、Base4在当次远程操作中未烧入等过程细节,统一整理在:
赛后状态:比赛已经结束,参赛者后来手动烧录了最终MSPM0固件;最终MSP、MaixCAM和RDK X5上位机代码见完赛最终代码与成果。本页中的“当前”只代表原始记录当时的现场状态。 +
7 跨项目通用电赛技术与调试经验
本章把本题中可迁移的电源、编码器、循迹、IMU、工程迁移和烧录工具经验单独收束。它们不是本题最终代码的额外步骤;使用时必须根据新硬件重新验证。
本章把跨项目可复用的传感器接线、循迹与姿态控制、工程迁移、烧录工具和故障索引并入同一篇主帖。前六章记录 2026 年 TI 杯 H 题的最终方案与现场复盘;两部分事实不互相覆盖,复现 H 题时以前六章的最终口径为准。
以下内容保留原始实验数据与代码路径,仅调整标题层级,使通用经验与 H 题主线在同一篇帖子中可检索。
7.1 硬件、电源与编码器
电赛物料清单
冯老师强烈建议三月底完成物料清单,根据以往题目整理所需物料。
物料分为两类:
- 根据今年题目方向推测可能需要的物料。
- 练习往年赛题时用到的物料。
ICM-42688二车调试
纠正记录:模块针脚与底板丝印反向适配
以下连接关系是对前面“按底板丝印直接解释”的纠正,以本节为准。
代码已经按修正后的配置重新烧录,但仍然没有收到 ACK,下一步需要检查实际 42688 模块本身。
问题原因是:这个 42688 模块的 8 针顺序与底板原来的 GY-521 接口是反向适配的,不能直接按照底板丝印解释模块针脚。
实际连接关系
在电源和地对齐后,实际连接为:
| 模块针脚 | 底板标注 | MCU 引脚 | 作用 |
|---|---|---|---|
CS |
AD0 |
PA30 |
片选;拉高进入 I²C 模式 |
AD0 |
INT |
PB1 |
地址选择;拉低后地址为 0x68 |
INT1 |
XCL |
PA31 |
普通 GPIO 输入 |
INT2 |
XDA |
PA28 |
普通 GPIO 输入 |
SCL |
SCL2 |
原软件 I²C SCL | 时钟线 |
SDA |
SDA2 |
原软件 I²C SDA | 数据线 |
软件配置纠正
之前代码把 PA30 拉低,相当于把模块 CS 拉低,强制进入 SPI 模式,因此 I²C 永远不会响应。
现在应改为:
PA30:普通 GPIO 输出并拉高,作为模块CS,使 42688 进入 I²C 模式。PB1:普通 GPIO 输出并拉低,作为模块AD0,固定 I²C 地址为0x68。PA31:普通 GPIO 输入,接模块INT1。PA28:普通 GPIO 输入,接模块INT2。- 软件 I²C 继续使用原来的两根 GPIO 作为 SCL/SDA。
配置排查命令
rg -n -S "GPIOA\.31|DL_GPIO_PIN_31|PA31|GPIOA\.28|DL_GPIO_PIN_28" \
C:\Users\12706\Desktop\embedded
补充说明
底板丝印标注本身不影响软件控制,关键是按照模块的实际针脚顺序配置 GPIO。PA30、PB1、PA31 和 PA28 都按普通 GPIO 使用,不应仅根据底板上的同名丝印判断功能。
纠正记录:初始化时序
问题定位
官方寄存器值 0x0F 本身是正确的,真正的问题是初始化顺序。
根据 TDK ICM-42688-P 数据手册,陀螺仪从 OFF 切换到低噪声工作模式后,至少需要保持开启约 45 ms。旧代码只等待了约 20 ms,并且先配置其他寄存器,最后才给传感器上电,时序不满足要求。
当前修正后的顺序
-
复位并完成 I²C 通信确认。
-
先写入:
PWR_MGMT0 = 0x0F使加速度计和陀螺仪进入工作状态。
-
等待
50 ms,给陀螺仪足够的启动时间。 -
再配置:
GYRO_CONFIG0 = 0x06 ACCEL_CONFIG0 = 0x26 -
再等待
10 ms,然后读取陀螺仪样本。 -
将
0x8000作为无效样本哨兵值,不能把它当作真实零漂参与校准。 -
只有读取到有效样本后,才将姿态模块标记为 ready。
代码位置
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-42688二车\ti-contest-2025-flash\custom_src\drivers\sensors\icm42688\attitude_algorithm.c
本次修改涉及初始化时序、启动等待和无效陀螺样本过滤。
保护效果
即使 42688 硬件异常或没有产生有效样本,姿态模块也不会被误标记为已就绪,Base1 不会因此被放行后无限原地打转。
最终测试结果
已确认的电气状态
VCC = 3.3 V
CS = 3.3 V
WHO_AM_I = 0x47
这一步进一步排除了基础接线问题:
VCC = 3.3 V:供电输入正常。CS = 3.3 V:模块已正确进入 I²C 模式。SCL/SDA为 3.3 V,WHO_AM_I = 0x47:I²C 数字通信正常。
当前只剩两项检查
-
测量模块稳压器输出端,也就是芯片侧
VDD。不能只测排针上的
VCC;芯片侧电压应稳定在约1.71~3.6 V,开启陀螺仪时不能出现明显跌落。 -
确认
AD0实测为0 V。
最终判断
如果上述两项都正常,结合已经验证的以下条件:
- 大端连续读取正常
- 初始化时序正确
- 未使用 PLL
- 温度、加速度和陀螺数据同时冻结
基本可以判定问题位于 ICM42688 模块的模拟/MEMS 部分,而不是软件通信或基础接线。
最有效的确认方法是直接更换一块 ICM42688 模块。当前软件已经能够正确报告 IMU 初始化失败,不会再在初始化失败后继续运行基础路线。
初始配置(已被上方纠正覆盖)
原始记录:按底板丝印的初始理解
INT→PB1AD0→PB0,由 MCU 固定输出低电平,I²C 地址保持为0x68XCL/SCL→PA30XDA/SDA→PA28
配置要点
- 上电初始化时,将
PB0配置为输出并固定拉低。 - 使用 I²C 通信时,SCL 连接
PA30,SDA 连接PA28。 - 中断信号接入
PB1。 - 由于
AD0为低电平,设备地址使用0x68。
编码器计数问题
初步判断
上拉已经把原来 ENCODER_3/4 的假中断压掉了,说明之前确实有浮空噪声。
先确认是否转动轮子,再进行 GPIO 轮询读取。
新结论
RESISTOR_NONE不要上拉,但是悬空脚必须关闭。现在只使用左边两个轮子。- 这个期间还更换了端子线。
配置调整
-
编码器输入恢复成范本配置。
ENCODER_1~8都从内部上拉改回DL_GPIO_RESISTOR_NONE,因为已经证明加上拉后motor2/3读不到有效脉冲。 -
正式驱动轮切到
motor2/motor3。配置目录:
Desktop/embedded/ti-contest-2026版本/ti-contest-2025-flash/ti-contest-2025-flash/custom_src/application/control/drive_mapping.h现在是:
更换电池与加重后的调参
第一次调参
Base1 完成状态
sm current=4/4
completed=1
直行
target_mileage=50.000
current_mileage=49.108
转后清零的直行航向
target_angle=0.000
current_yaw=0.566
straight_error=-0.566
straight_correction=0.918
直行目标速度
target_speed[2]=7.694
所以现在直行阶段是正向、航向也稳,0.566° 很小。
转角问题
转角没转好的原因在转向末端:
turn[31] yaw=79.117 err=10.883 out=5.000
turn[32] yaw=83.460 err=6.540 out=4.377
turn[33] yaw=87.749 err=2.251 out=0.522
它最后只到 87.75° 左右就进入后续流程了,差约 2.25°。之前为了防止过冲,把近目标速度压得太狠;换重电池后惯性小、负载大,末端推不够。
下一步建议只小调近目标,不动直行:
TURN_NEAR_MAX_SPEED: 5 -> 6.5
ANGLE_THRESHOLD_DEG: 1.5 -> 1.2
这样末端会再多推一点,目标从 87.7° 拉近到 89~90°,又不会回到之前冲过头的问题。
第二次调参
偶发多转 20°
多转 20° 更像是转向完成判定太薄,或者过目标后还没有立刻切断输出。
代码里已经没有主动给转向混平移速度,trans 是左右轮实际速度不完全对称造成的测量值。真正会导致“偶发多转 20°”的点是:过冲判定只接受 8° 内过零,过了 8° 反而不认完成,会继续纠正,实车就表现成多拧一截。
修改为:接近目标后发生过零,25° 内都立即完成并停车,同时保留防 IMU 大跳变。
第三次调参
- 直线目标:
50.000 cm - 实际里程:
49.129 cm - 直线结束 yaw:
-0.304° - 直线纠偏:
-0.341,很小
下一步建议做很小的目标角补偿:将 Base1 的 90.0f 改成 91.5f,不要再动 PID。这样不影响直线纠偏,也不放大偶发过冲。
7.2 循迹、转向与运动控制
灰度(光电)循迹
第一次调试:排除通信与接线问题
读取结果
- 总读取:
933 - 非
0xFF:933,说明通信没有断 - 无效图案:
730次,约占78% - 当前图案:
0x01,被判有效 - 当前纠偏方向已正确:左轮
0、右轮40
结论
“动一下、停一下”不是接线问题,而是查表规则太死:只接受连续的 1~4 个黑线位;出现 0x09 这类非连续图案就立即停车。推车后碰巧变成 0x01,它又开始运动。
第二次调试:改用八路加权平均
循迹位置改成八路加权平均:
- 只在
gray_byte == 0x00(完全没检测到黑线)时,报错停车。 - 其他非零组合都计算位置。
新问题
巡线卡在直线转角,保护过大。
思路:三路或四路识别到黑线时,执行对应方向的转向角度;这个过程也可以封装成动作队列。
第三次调试:90° 角点过冲
现象
90° 转角有点过冲。本来应该到 90° 转角的地方,灰度传感器直接越过,车辆停在那里卡住。
最初认为是循迹惯性受小车重量影响。进一步纠正后,原因是进入角点前的纵向制动不足:当前仍以 20 cm/s 接近,四路识别还要求连续 5 帧;重车已经跨过角点,才进入全白保护。
修改
- 单侧边缘 3 路:只触发预减速,速度降到
10 cm/s。 - 完整四路:连续确认由 5 帧降到 3 帧,避免跨过角点。
- 确认角点后:先停车制动约
120 ms。 - 制动结束后:再以当时的 yaw 计算
±90°目标。 - 短白区前探降为
6 cm/s、最多160 ms。 - 循迹 PID 修正量受当前基础速度限制,减速时不会突然反转车轮。
第四次调试:修正转角方向
0x0F/0x1F:现在对应正角,执行左转。0xF0/0xF8:对应负角,执行右转。- 转后重新捕获线带的原地旋转方向也同步修正。
- 不会再出现“转角方向改了,但找线仍沿旧方向旋转”的问题。
第五次调试:加入传感器前置距离
发现车辆旋转中心和灰度传感器之间存在安装距离,必须将其作为变量,否则车辆会提前停下。
已将 10 cm 前置距离做成动作参数:
car_add_track_with_corners(
255.0f, // 总循迹距离
90.0f, // 角点转角
10.0f // 灰度板到车辆旋转中心的距离
);
执行顺序
-
灰度确认角点:连续 3 帧识别到四路角点图案。
-
立即锁存角点方向,后续不会因灰度变化而改方向:
0x0F/0x1F:左转,方向+10xF0/0xF8:右转,方向-1
-
保持捕获瞬间的航向,直线闭环前进
sensor_offset_cm;Base3 当前为10 cm。 -
停车制动约
120 ms。 -
根据锁存方向计算目标:
target_yaw = current_yaw + direction * 90.0f; -
完成转角后重新捕获线带,继续循迹。
第六次调试:放宽过冲完成判定
越过目标后,允许最多 25° 的过冲仍判定完成。
第七次调试:取消转后原地找线
原先 90° 转完后,程序还会沿原方向原地旋转找线,这会额外产生几度左偏。现在改为:
- 完成 90° 转向后不再追加原地旋转。
- 以
8 cm/s低速向前循迹。 - 根据实时灰度误差逐步回到线带中心。
0x00仍立即停车。
圆弧逻辑
第一轮调试
问题
圆弧控制速度太猛。半径 30 cm、轮距 24 cm 时,代码用 CIRCLE_SPEED=70 算出:
- 外轮:
98 cm/s - 内轮:
42 cm/s
外轮几乎是直行上限的两倍。
修改
将圆弧速度按外轮不超过 50 cm/s 收束,同时增加圆弧读数变量,便于下一次读取累计角度和内外轮目标。
结果
圆弧动作完成:sm current=1/1 completed=1
- 半径:
30.000 cm - 目标角:
360.000° - 累计角:
360.746° - 过冲:约
0.746° - 顺时针:
clockwise=1 - 外轮目标:
49.000 cm/s - 内轮目标:
21.000 cm/s - 左右目标:左
49.000,右21.000
转向方向与Yaw符号不一致
调试结论
编码器读取和速度 PID 目前正常,问题已经从“速度闭环”转移到:
转向方向与 yaw 符号不一致。
实测数据
速度闭环
目标速度:M2 -24 cm/s,M3 +24 cm/s
实际速度:M2 -22.634 cm/s,M3 +22.634 cm/s
PWM:M2 -525,M3 +553
平移分量:0.000
编码器更新:M2 76,525 次,M3 76,514 次
左右轮速度闭环非常对称,没有出现饱和或方向反转。因此编码器和速度 PID 暂时不需要修改。
姿态与转向
目标角:+90°
当前 yaw:-10.432°
误差:+100.432°
转向输出:持续 +24 cm/s
历史 yaw:-10.407°,并且持续变得更负
问题分析
小车执行正 90° 转向动作时,实际 yaw 朝负方向变化:
- 控制器目标是
+90°。 - 当前 yaw 从
-10.432°继续向负方向变化。 - 误差越来越大,当前误差已经达到
+100.432°。 - 控制器因此持续输出
+24 cm/s,转向动作无法正常结束。
这说明左右轮的速度差方向已经产生了旋转,但该旋转方向与 yaw 的正负号定义相反。
里程现象
当前累计左右轮里程约为:
左轮:-1082 cm
右轮:+1082 cm
这进一步说明车辆确实在原地转向,而不是速度闭环失效;问题集中在转向轮速分配方向或 yaw 符号约定。
下一步修改
优先检查并修正以下其中一项:
- 转向时左右轮目标速度的分配方向。
- yaw 的正负号定义,或 yaw 误差的计算符号。
建议先确认“左轮负、右轮正”对应的实际旋转方向,再统一以下三者的约定:
- 左右轮速度差的正方向。
- yaw 增大的实际旋转方向。
- 转向动作中
direction或目标角度的正负号。
当前不需要重新调整编码器方向、速度 PID 参数或速度闭环,只需修正转向方向与 yaw 符号之间的映射关系。
根因确认与修复
根因
后续确认问题来自右后轮的电机极性与编码器方向配置:
- 后右轮正 PWM 实际让车辆后退。
- 后右编码器又把这个后退速度当成正速度反馈。
- 因此 Base1 两轮一起向后,Base2 则接近原地旋转,但 PID 读数看起来仍然“正常”。
已同步修改
-
翻转右后电机极性:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\drivers\actuators\motor\motor_user.c:45 -
修正后右编码器方向:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\config\car_params.c:22后右编码器方向:-1 → 1
编译与烧录结果
编译:0 Error / 0 Warning
烧录:已通过 XDS110 成功完成
下一步验证顺序
- 先测试直行,确认两轮都向前。
- 再测试 Base1。
- 最后重新验证 Base2 的原地转向和 yaw 方向。
PID调参:角度
Base1 初始参数
目标角度:90.0°
角度完成阈值:±1.2°
稳定样本数:10 次
转向最大速度:±40 cm/s
大误差最低转向速度:10 cm/s
最低速度启用误差:> 8°
角度 PID:Kp=1.1, Ki=0.0, Kd=0.15
现象与处理
yaw 转向到 90° 后,先慢速震荡,再逐渐减小震荡并停止。
进入 ±1.2° 角度窗口后,转向控制不再继续给小 PID 输出,而是直接把左右目标速度设为 0,只等待稳定计数完成。这样末端不会再靠小 PWM 来回蹭。
第二次调参
停车或复位时,将调试 PWM 一起清零,避免再读到上一拍残留值。
在 CAR_STATE_STOP 分支和 car_reset() 中都清零:
dbg_pwm_output_0..3 = 0;
结果
反而出现震荡:
yaw=106.307 err=-16.307
...
yaw=91.828 err=-1.828
yaw=89.327 err=0.673 out=0
yaw=87.003 err=2.997
yaw=84.925 err=5.075
...
yaw=79.554 err=10.446
这说明它冲过 90° 到 106°,又反打穿过 90° 到 79°,再回到目标。根因是转向速度和近目标输出太硬,惯性过冲大。
参数修改
TURN_MAX_SPEED: 40 -> 28
角度 PID Kp: 1.1 -> 0.9
角度 PID Kd: 0.15 -> 0.35
稳定样本: 10 -> 4
完成阈值: 1.2° -> 1.5°
20° 内输出限幅: ±14
8° 内输出限幅: ±7
最低转向速度: 10 -> 8
最低速度仅在误差 > 15° 时启用
第三次调参
现在不是震荡问题,而是“速度分段限幅 + 进入死区后断输出”带来的一点顿挫,尤其是:
err=2.122 out=1.169
err=1.373 out=0.000
可能是死区内斜率归零造成的:进入 ±1.5° 后,它还按斜率残留一点输出,等于在目标附近继续轻推。
应保留斜率限制,但死区内必须硬停车。
第四次调参
现象
超过 90° 一点后又回正。
原因
过冲后,程序主动反向纠偏了十多个周期。
完成判定
- 只要误差符号跨过
0,并且过冲≤ 4°,就直接接受完成并立即停车。 - 不再反向纠偏。
- 需要根据车的具体情况判断这个策略是否过于保守。
PID调参:直行距离
第二次调参
现象
转向停止点太激进。它在 85.3° 时输出还有 17.5,后面靠惯性继续旋转;延时 250 ms 后清零时车还没稳,直行时 yaw 已经跑到 147°,所以走成 U 形。
做法
- 扩大近目标限速区。
- 增大降速斜率,让输出能从
20附近快速降到5,而不是慢慢下降。 - Base1 的转后静止时间从
250 ms增加到500 ms。
第三次调参
直行时逻辑速度是正的,但实车后退,而且里程还能正向累计。
这说明 motor2/3 的“电机正方向”和“编码器正方向”都与物理前进方向相反。
7.3 IMU、Pitch与坡道控制
Pitch倾角调节
第一次调试:发现坐标轴偏差
实测数据
当前 pitch:-30.889°
最低 pitch:-35.029°
最高 pitch: 11.115°
当前 roll: -26.513°
采样数:3480
40° 坡道没有完全落在 pitch 轴上,而是分摊到了 pitch 和 roll。合成倾角约为:
acos(cos(pitch) × cos(roll)) ≈ 39.8°
初步判断
IMU 倾角基本正确,异常在于 IMU 坐标轴相对车身前进方向旋转了约 37°~45°。不能只用原始 pitch 判断坡道,需要把 pitch 和 roll 转换到车身前向坐标系,再做水平零点校准。
初步方案
把 IMU 的俯仰从传感器坐标转换到车身前向坐标:根据实测将车头前向轴设为传感器平面内约 -37°,用重力向量投影计算,随后再减去路线开始时的水平零点。这样 40° 坡道不会再被拆成 pitch=-31°、roll=-27°。
这是第一轮根据 DMP pitch/roll 得出的判断。后续实测证明 DMP 欧拉俯仰不稳定,最终方案已改为 FIFO 加速度和陀螺仪互补滤波。
第二次调试:最终架构
MPU6050 DMP yaw → 平地直行、转向、转圈
加速度 + X 轴陀螺 pitch → 上坡、下坡检测
两者共用一个 IMU 周期任务,但算法、零点和控制用途分开。
本轮完成的工作
-
确认 MPU6050 地址与身份:
- 实际
WHO_AM_I = 0x70 - 同时兼容
0x68/0x70
- 实际
-
最初直接使用 DMP pitch/roll:
- 水平静止时出现约
-37°~+21°波动 - 确认 DMP 俯仰不适合坡度判断
- DMP 只保留给 yaw
- 水平静止时出现约
-
改为读取 DMP FIFO 中已有的原始加速度:
-
不增加额外 I²C 读取
-
同时保留 FIFO 校准陀螺数据
-
接口位于:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\drivers\sensors\mpu6050\inv_mpu.c:3099
-
-
标定车身坐标轴:
-
车头接近竖直时读到
accel=[194, 2045, -226] -
确认车头前向对应传感器
+Y -
俯仰旋转轴对应传感器
X -
配置位于:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\app_template\app_template_config.h:57
-
-
加入互补滤波:
98%:X 轴陀螺积分 2%:加速度倾角校正 周期:10 ms实现文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\app_template\app_template_imu.c
静态结果
当前 pitch:+0.099°
最小值:-0.159°
最大值:+0.186°
因此静态误差约为 ±0.2°。
试错记录
1. 直接使用 DMP pitch
最初认为 DMP 已经输出欧拉角,可以直接用于坡道:
mpu_dmp_get_data(&pitch, &roll, &yaw);
实测 40° 坡道时:
pitch = -30.889°
roll = -26.513°
将两者合成后倾角约 39.8°,因此最初误判为“IMU 斜装,坡度被分摊到 pitch 和 roll”。
2. 尝试将 DMP pitch/roll 转换到车身坐标
根据当时数据推算,车头轴相对 IMU 约为 -37°:
#define IMU_CHASSIS_FORWARD_AXIS_DEG (-37.0f)
使用重力向量投影计算车身 pitch。数学计算本身成立,但输入的 DMP pitch/roll 并不稳定,因此这个安装角推断也不可靠。
3. 第一次加入相对 pitch 零点
增加:
app_template_get_pitch();
app_template_zero_pitch();
路线开始时清零,并记录:
- 当前 pitch
- 最小 pitch
- 最大 pitch
- 采样次数
但采样最初放在 car_task() 中。手推小车时车控任务没有运行,读取结果是:
samples = 0
min = 0
max = 0
所以无法记录手推坡道。
4. 把 pitch 采样移到 IMU 周期任务
改为每次 mpu6050_dmp_update() 后持续采样,周期 10 ms。
这样即使没有启动路线,手推小车也能记录倾角极值。
5. 尝试启动自动清零
第一版启动标定:
丢弃:0.5 s
平均:1 s
但标定过早:
标定零点 = -4.798°
稍后车身原始角约 = -17.46°
相对 pitch = -12.659°
说明当前工程中的 DMP pitch/roll 仍在启动后继续变化。
6. 尝试稳定窗口标定
改成只有连续 1 s 波动小于 0.75° 才接受零点。
结果是 DMP 持续变化,或用户在测试时动车,稳定条件一直不满足,OLED 长时间停在 0°。
随后增加最长等待时间:
等待:0.3 s
每窗:0.5 s
最多:两窗
最长:约 1.3 s
这解决了无限等待,但没有解决 DMP 姿态本身的异常。
7. 发现 OLED 仍显示原始 DMP pitch
内部已经有相对车身 pitch,但 OLED 菜单仍绑定:
&pitch
后来改成:
&dbg_current_pitch
OLED 才真正显示转换和清零后的车身 pitch。
8. 确认 DMP pitch/roll 不适合当前坡度检测
小车全程水平静止时读取到:
DMP pitch 当前值:-14.478°
相对 pitch:-15.456°
运行极值:-37.391° ~ +20.933°
静止跨度接近 58°。因此确认问题不只是零点,而是当前驱动中的 DMP 欧拉俯仰输出不稳定。
9. 从 DMP 欧拉角切换到 FIFO 原始加速度
dmp_read_fifo() 本来已经返回:
short gyro[3];
short accel[3];
long quat[4];
旧代码只用四元数计算 yaw/pitch/roll,把 accel 和 gyro 丢掉。
增加:
mpu_dmp_get_latest_accel();
mpu_dmp_get_latest_gyro();
直接复用 FIFO 数据,不额外增加 I²C 读取。
10. 第一次 FIFO 加速度仍沿用错误的 -37° 轴
虽然数据源换成了稳定的加速度计,但车头轴仍配置为 -37°。
当车头接近竖直时:
accel = [194, 2045, -226]
显示 pitch 约 43°
数据明确说明重力集中在 +Y 轴,车头前向实际是传感器 +Y,不是 -37°。
11. 将车头轴修正为传感器 +Y
最终改为:
#define IMU_CHASSIS_FORWARD_AXIS_DEG 90.0f
此后水平静止实测:
当前 pitch:+0.099°
最小值:-0.159°
最大值:+0.186°
静态误差降到约 ±0.2°。
12. 发现纯加速度 pitch 受车辆加减速影响
用 Base1 爬坡时:
最小 pitch:-19.771°
最大 pitch:+33.975°
加速度计会把电机起步、刹车和重力混在一起,所以静态很准,运动中会出现假倾角。
13. 最终改成 FIFO 加速度 + FIFO 陀螺互补滤波
当前最终方案:
98%:X 轴陀螺积分
2%:+Y 轴加速度倾角
周期:10 ms
数据用途:
DMP quaternion → yaw
DMP FIFO accel/gyro → pitch
DMP Euler pitch/roll → 不再用于坡道控制
所以不是完全删除 DMP,而是保留 DMP 四元数用于 yaw,并使用 DMP FIFO 中的 accel/gyro 计算 pitch。
这就是从“直接使用 DMP pitch”,经过坐标投影、零点标定、稳定窗口,到最终改用 FIFO 加速度和陀螺互补滤波的完整过程。
当前符号约定
上坡、车头抬起:负角
下坡、车头朝下:正角
坡道动作
模块与接口
新增独立坡道模块:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\control\car_ramp.c:1
路线接口:
car_add_up_ramp(max_distance_cm, speed_cmps);
car_add_down_ramp(max_distance_cm, speed_cmps);
兼容旧接口:
car_add_ramp(...) == car_add_up_ramp(...)
判定参数
| 项目 | 参数 |
|---|---|
| 上坡进入 | pitch <= -8° |
| 上坡退出 | pitch >= -3° |
| 下坡进入 | pitch >= +8° |
| 下坡退出 | pitch <= +3° |
| 进入确认 | 5 个周期 |
| 退出确认 | 10 个周期 |
| 最短坡面时间 | 500 ms |
| 动作超时 | 15 s |
| 下坡最大速度 | 25 cm/s |
状态机接入位置:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\control\car_state_machine.c:568
当前任务
原 Play 任务已替换为:
// Ramp Up
car_add_up_ramp(80.0f, 20.0f);
// Ramp Down
car_add_down_ramp(80.0f, 12.0f);
配置位置:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\app_template\app_template_actions.c:161
旧 Play 1 长路线和 Play 2 摄像头四路径已删除,路线文件缩减到约 221 行,固件减少约 892 bytes。最终工程编译结果为 0 Error / 0 Warning。
7.4 工程架构与快速迁移
架构问题
5. 堆栈问题
启动文件还是:
Stack_Size EQU 0x00001200 ; 4.5 KB
Heap_Size EQU 0x00003000 ; 12 KB
工程没有实际使用动态分配;encoder.c 里的 malloc 只是注释。
当前链接器显示 RAM 30.19 KB,其中:
Heap 12 KB
Stack 4.5 KB
实际静态数据约只有 13.7 KB。建议把 Heap 改为:
Heap_Size EQU 0x00000400
保留 1 KB 足够保守。修改后 RAM 余量会从约 1.8 KB 增加到约 13 KB。
Stack 4.5 KB先保留,因为工程里存在 snprintf、浮点运算以及 DMP 局部数组。
小车工程快速迁移改进
当前结论
当前工程还没有达到“换车时只修改一个配置文件”的程度,快速迁移能力约为 6.5/10。
如果新车仍然采用以下配置,上层路线基本不需要修改:
- 双驱差速结构
- 编码器电机
- 相同主控
- MPU6050
可以直接复用的部分
以下上层功能基本不绑定具体小车:
- 路线状态机
- 直线、转弯、圆弧和循迹动作
- 上坡、下坡动作
- OLED 和串口任务入口
- 超时与失败停车
- 调试读取框架
换车时必须调整的部分
1. 底盘尺寸与编码器参数
配置文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\control\car_config.h:1
需要调整:
WHEEL_RADIUS_CM
PULSE_NUM_PER_CIRCLE
WHEEL_BASE_CM
ENCODER_PERIOD_MS
ENCODER_DIR_*
2. 实际驱动电机映射
配置文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\control\drive_mapping.h:8
当前配置:
DRIVE_LEFT_MOTOR = MOTOR_BACK_LEFT
DRIVE_RIGHT_MOTOR = MOTOR_BACK_RIGHT
3. 电机 PWM 方向与底层引脚
需要检查:
motor_hardware.hmotor_user.c- SysConfig 引脚配置
4. IMU 安装方向
配置文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\app_template\app_template_config.h:57
当前配置:
IMU_CHASSIS_FORWARD_AXIS_DEG 90.0f
更换 IMU 安装方向后,必须重新标定:
- 车头轴
- 俯仰轴
- 角度符号
5. 灰度板位置
需要调整:
sensor_offset_cm
TRACK_SENSOR_COUNT
同时需要重新确认角点左右掩码。
6. PID 参数
配置文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\app_template\app_template_pid_params.c:11
新车重量、轮胎、电机或电池发生变化后,至少需要重新调整:
- 左右轮速度 PID
- 里程 PID
- 直行航向 PID
- 转角 PID
- 循迹 PID
7. 坡道阈值
配置文件:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\custom_src\application\control\car_ramp.c:8
需要调整:
RAMP_ENTER_PITCH_DEG
RAMP_EXIT_PITCH_DEG
RAMP_TIMEOUT_MS
迁移耗时判断
| 新车变化范围 | 预计迁移时间 | 主要工作 |
|---|---|---|
| 同主控、同传感器、同双驱结构 | 约 30~60 分钟 | 完成硬件映射,之后进行实车 PID 调试 |
| 同主控,但更换电机、轮径、轮距或 IMU 安装方式 | 约半天 | 完成基础迁移、参数修改和标定 |
| 更换主控、驱动板、编码器或循迹传感器 | 无法快速迁移 | 需要修改驱动层 |
当前最大不足
车辆参数目前分散在多个位置:
car_config.hdrive_mapping.happ_template_config.h- PID 参数文件
- 坡道模块
下一步改进
将分散的车辆参数收束到统一的车辆配置文件:
vehicle_profile.h
vehicle_profile.c
目标是更换小车时只需切换或修改一份车辆配置。
7.5 烧录与调试工具
自动切换烧录器
功能概述
工程已经实现 XDS110 与 J-Link 两种调试/烧录器之间的自动切换。入口位于:
C:\Users\12706\Desktop\embedded\ti-contest-2026版本\ti-contest-2025-flash\ti-contest-2025-flash\project\Keil\
切换流程为:
- 选择烧录器:
XDS110或J-Link。 - 修改 Keil 的
.uvprojx和.uvoptx配置。 - 可选:调用 Keil 编译当前工程。
- 调用对应烧录工具写入固件。
- 检查烧录结果并保留日志。
- 如果流程失败,自动恢复切换前的 Keil 配置。
文件组成
| 文件 | 作用 |
|---|---|
调试器切换.vbs |
隐藏 PowerShell 窗口,启动图形选择器 |
debug_probe_selector.ps1 |
提供 XDS110/J-Link 选择界面,并决定是否编译、烧录和校验 |
switch_debug_probe.ps1 |
执行实际的 Keil 配置切换、编译和烧录 |
EmbedBolt316.uvprojx |
Keil 工程文件,脚本会修改其中的烧录 DLL |
EmbedBolt316.uvoptx |
Keil 调试选项,脚本会修改调试器和目标选择 |
JLinkSettings.ini |
J-Link 的 Keil 配置文件 |
JLinkLog.txt |
J-Link 最近一次连接日志 |
图形界面用法
入口
双击:
project\Keil\调试器切换.vbs
界面中可以选择:
XDS110J-Link- 是否在切换后自动执行“编译、烧录和校验”
默认勾选编译、烧录和校验。
运行前必须关闭所有 Keil/uVision 窗口,否则脚本会拒绝执行,避免 Keil 使用缓存配置覆盖脚本修改。
命令行用法
在 project\Keil 目录执行:
切换到 XDS110
.\switch_debug_probe.ps1 -Probe xds110
切换并编译、烧录、校验:
.\switch_debug_probe.ps1 -Probe xds110 -Flash
切换到 J-Link
.\switch_debug_probe.ps1 -Probe jlink
切换并编译、烧录、校验:
.\switch_debug_probe.ps1 -Probe jlink -Flash
如果 PowerShell 的执行策略阻止脚本,可以使用:
powershell.exe -NoProfile -ExecutionPolicy Bypass -File .\switch_debug_probe.ps1 -Probe xds110 -Flash
XDS110 烧录流程
使用 XDS110 时,脚本会:
-
将 Keil 的
Flash2设置为BIN\UL2CM3.DLL。 -
将目标调试器选择为 XDS110 CMSIS-DAP。
-
使用 Keil 编译生成:
project\Keil\Objects\EmbedBolt316.axf -
在
C:\ti\uniflash_*中寻找最新的dslite.bat。 -
复制目标配置和 AXF 到临时目录。
-
将 XDS110 配置中的序列号替换为
NOserial,避免序列号绑定。 -
调用 TI UniFlash DSLite 烧录。
-
检查日志中的
IFlashDevice::HandleVerification(...) = true。
日志位置:
debug_flash_artifacts\build_logs\dslite_xds110_flash.log
成功后会将日志压缩为审计记录,包含:探针、接口、芯片型号、固件路径、固件大小、固件时间戳和完成时间。
J-Link 烧录流程
使用 J-Link 时,脚本会:
-
将 Keil 的监视器 DLL 切换为
Segger\JL2CM3.dll。 -
将目标选择切换为 J-Link。
-
使用 Keil 编译生成:
project\Keil\Objects\EmbedBolt316.hex -
在以下位置寻找 J-Link Commander:
C:\Program Files\SEGGER\JLink\JLink.exe C:\Program Files\SEGGER\JLink_V940\JLink.exe C:\Program Files\SEGGER\JLink_V796\JLink.exe -
生成临时 J-Link 命令文件:
device MSPM0G3507 si SWD speed 1000 connect r h loadfile EmbedBolt316.hex r g exit -
检查退出码、错误信息和
O.K.。
日志位置:
debug_flash_artifacts\build_logs\jlink_flash.log
Keil 配置切换内容
脚本会修改两个 Keil 文件:
.uvprojx
修改 <Flash2>:
XDS110:BIN\UL2CM3.DLL
J-Link:BIN\UL2CM3.DLL
两者使用同一个 Keil Flash DLL,但实际调试器由 .uvoptx 中的配置决定。
.uvoptx
主要修改:
| 项目 | XDS110 | J-Link |
|---|---|---|
nTsel |
3 |
4 |
pMon |
BIN\CMSIS_AGDI.dll |
Segger\JL2CM3.dll |
| 调试协议 | SWD | SWD |
| 调试时钟 | 1000000 |
1000000 |
| Keil Flash Sequence | 启用 | 禁用,改由脚本调用 J-Link Commander |
XDS110 和 J-Link 的目标芯片均为 MSPM0G3507。
编译与失败恢复
使用 -Flash 时,脚本会先调用:
C:\Users\12706\AppData\Local\Keil_v5\UV4\UV4.exe
并要求编译日志包含:
0 Error(s)
如果编译、烧录或校验失败:
- 脚本抛出错误。
- 自动写回切换前保存的
.uvprojx和.uvoptx。 - 临时烧录目录只允许在系统临时目录下删除。
- 失败日志保留在
debug_flash_artifacts\build_logs中。
当前注意事项
- 运行前关闭 Keil,避免配置缓存覆盖切换结果。
- XDS110 需要安装 TI UniFlash,并且
C:\ti\uniflash_*下存在dslite.bat。 - J-Link 需要安装 SEGGER J-Link Commander。
- 两种方式都要求先生成对应的 AXF 或 HEX 文件。
- 烧录接口为 SWD,目标芯片为 MSPM0G3507。
- 切换脚本只负责当前工程的调试器配置,不会修改源代码。
最近一次 J-Link 日志
JLinkLog.txt 中记录的最近一次 Keil 连接出现:
Failed to initialized DAP.
No PWR-AP detected.
这表示当时 J-Link 没有成功识别目标板的调试访问端口。优先检查:
- 目标板是否上电。
- SWDIO、SWCLK、GND 和复位线是否接好。
- J-Link 与目标板电平是否匹配。
- 是否有其他程序占用调试器。
- 是否需要在目标板复位时连接。
这属于硬件连接或目标供电问题,不等同于自动切换脚本本身失败。
7.6 问题现象—根因—解决索引
这一章不是新的调参记录,而是把前五章中分散的问题压缩成可检索的故障表。遇到相似现象时先按“优先检查”排查,再进入链接章节查看原始数据和修改过程。
| 现象 | 已确认或高概率根因 | 处理结论 | 详细记录 |
|---|---|---|---|
| ICM-42688 无有效数据,基础任务可能被错误放行并持续打转 | 模块8针顺序与底板原GY-521接口的理解相反;初始化状态又曾过早标记为就绪 | 按实物重新核对针脚映射;只有取得有效样本后才置姿态就绪,失败时禁止任务启动 | 42688针脚修正;初始化时序 |
| 编码器出现假计数、假中断,或加上拉后反而读不到脉冲 | 未使用输入悬空产生噪声;有效编码器输入不适合统一开启内部上拉 | 关闭悬空通道;有效输入恢复范本的DL_GPIO_RESISTOR_NONE;换线后重新逐轮确认 |
编码器计数问题 |
| 换重电池后90°转向末端差约2°,推不到目标 | 负载增大后近目标速度压得过低,末端输出不足 | 只微调近目标输出或目标角补偿,避免同时重调直行和整套PID | 更换电池后的调参 |
| 转向偶发多转约20° | 过零后的完成判定窗口过窄;超过窗口后控制器继续反向纠偏 | 用误差过零结合合理过冲范围结束动作,立即停车,不再连续反打 | 偶发多转记录;过零完成判定 |
| 灰度循迹“动一下、停一下”,但串口/传感器读取一直在线 | 查表只接受少量连续黑线组合,把0x09等非连续图案误判为失线 |
除0x00外均用八路加权平均求位置,避免对每种位图硬编码 |
灰度读取诊断;八路加权平均 |
| 90°角点处冲过黑线并卡死 | 车辆仍以较高速度接近,四路角点又要求连续5帧,重车跨过后才触发保护 | 边缘3路先减速;完整4路改3帧确认;锁存方向后制动约120 ms再转向 | 角点过冲 |
| 90°转完后仍多偏几度 | 转向完成后又沿原方向原地找线,额外累积角度 | 取消原地找线;改为低速前进并由实时灰度误差重新收线 | 取消转后找线 |
| 车辆在转,但yaw沿目标反方向变化,误差越来越大 | 转向轮速方向、yaw符号与目标角正负没有统一;实测还发现右后电机和编码器极性同时反了 | 先独立验证每个轮子的正PWM与编码器正负,再统一轮速差、yaw和目标角的符号约定 | Yaw符号问题;电机极性修复 |
| 速度PID数据看起来对称,但整车后退或原地转圈 | 电机极性和编码器方向同时配置错误,闭环会在错误物理方向上表现为“正常” | 判断闭环前必须观察车轮真实方向;本例翻转右后电机极性并修正右后编码器方向 | 根因与修复 |
| 角度控制冲过目标后左右反打、来回振荡 | 近目标输出过硬,且过冲后控制器继续反向纠偏多个周期 | 降低近目标强度;误差跨零且过冲可接受时直接完成并停车 | 角度 PID 记录 |
| 灰度检测到角点后车辆提前停车或转弯几何位置不对 | 灰度板位于车辆旋转中心之前,传感器触发点不等于车体应转弯的位置 | 将前置距离作为动作参数;触发后保持航向继续走该距离,再制动转向 | 传感器前置距离 |
| 坡道检测角度异常,自动清零等待或静止显示仍不可信 | IMU安装轴与车身轴不一致;DMP欧拉角不适合当前安装与坡道判定 | 明确车身前向轴,最终使用FIFO原始加速度与陀螺仪互补滤波 | Pitch 完整试错记录 |
| 只用加速度计算坡度时,加减速会被误认为上坡或下坡 | 车辆纵向加速度与重力分量混在一起 | 用陀螺仪短期动态配合加速度长期校正,并设置状态、阈值和持续时间判定 | 互补滤波方案 |
| MSPM0 RAM几乎耗尽,但工程没有实际动态分配 | 启动文件预留了12 KB Heap,静态占用不高却挤压可用RAM | Heap可缩到约1 KB;Stack暂保留4.5 KB以容纳snprintf、浮点和DMP局部数组 |
RAM 与堆栈 |
切换烧录器后编译/烧录失败,或J-Link提示No PWR-AP detected |
可能是工程配置切换失败,也可能只是目标未上电、SWD接线或调试器占用 | 脚本失败时恢复.uvprojx/.uvoptx并保留日志;DAP类错误优先检查供电、SWD和占用 |
失败恢复;J-Link 日志判断 |
推荐排查顺序
- 先看物理现象:供电、接线、轮子真实方向、机构是否卡住,不能只相信闭环数值。
- 再看原始输入:编码器计数、灰度位图、IMU FIFO和串口帧是否持续更新。
- 统一坐标与符号:电机正方向、编码器正方向、yaw正方向和任务目标必须一致。
- 检查状态机结束条件:超时、过零、连续帧、失线和停车逻辑往往比PID参数更先决定成败。
- 最后才调参数:每轮只改变一类参数,记录起点、目标、峰值、终点、耗时和现场扰动。
“数值闭环正常”不等于“物理方向正确”;“动作能到目标”也不等于“结束条件正确”。调车时应把传感器可信度、符号映射、状态机和控制参数分层验证。