刚接手硬件组的那年,我干得最多的事不是画板子,也不是调电机,而是把同一套话重复讲给每一批新队员听:CAN 线为什么必须双绞、电调 ID 为什么要先拨再上电、电池那个通信口到底该怎么读。讲到第三批人的时候我才意识到,问题不在新人笨,而在这套东西本身没有一份"从零到能跑"的入口文档。于是有了这份《Robomaster 硬件基础讲义》,改到 V0.2.1 时,它已经从一叠零散的截图和笔记,变成了一份能直接丢给大一新生、两周后他就能自己点亮底盘的东西。这篇内容我就把这份讲义的骨架、每块内容的取舍理由、以及那些写在页边空白处的踩坑记录摊开讲一遍,适合刚进硬件组的新人、负责带队的电控老队员,或者想把自己的队伍文档体系重新梳理一遍的人参考。
1. 讲义为什么要从"接口"讲起而不是从模电数电讲起
1.1 新队员真正卡住的地方从来不是原理
带过几届人之后你会发现一个很反直觉的现象:新队员看《模拟电子技术基础》看得下去,画个分压电路也画得出来,但把它接到实车上就懵了。他不知道 M3508 那根四芯线里哪根是 CAN_H、哪根是 CAN_L,不知道电调要接 24V 还是 12V,不知道电池上那个多出来的通信口是干什么的。这些内容任何一本教材都不会写,因为它们不是"电子学知识",而是"这套特定系统的约定"。
V0.2.1 最大的改动就是把开篇从"电学基础回顾"换成了"接口速查"。第一节只讲三件事:供电接口、通信接口、机械安装接口。每件事配一张实物照片加一张标注图,标注内容是"这根线是什么信号、电压范围多少、接错了会怎样"。比如供电这一节会明确告诉你,底盘主回路是直接挂 6S 电池的,也就是满电 25.2V 往下掉到 19V 左右,任何标着"5V 输入"的模块直接往上接就是当场冒烟,中间必须经过 DC-DC。
这个顺序调整背后的逻辑很简单:新人第一周的目标不是"理解",而是"能复现一套已知能跑的接线"。先给他一条走得通的路,让他把车跑起来,兴趣和信心建立起来之后,再去追问为什么,接受度会高得多。反过来,先灌两周理论再让他接线,大概率第三周人就没了。
1.2 三张接口图撑起了半支队伍的排障能力
讲义里我坚持放了三张"全车接口总图",分别是电源拓扑图、CAN 总线拓扑图和信号地拓扑图。这三张图看着土,但在实战排障里的价值极高。车不动了,第一步永远是顺着电源图量电压;电机某个 ID 没响应,顺着 CAN 图看它挂在哪一段、终端电阻装在哪个节点;出现莫名其妙的重启或者传感器乱跳,就去查地拓扑图,看是不是某个模块的地没共上。
提示:接口图一定要画成"物理连接图"而不是"原理框图"。原理框图省掉了线长、接插件位置和转接板,而 90% 的现场故障恰恰发生在这三样东西里。
我印象最深的一次是分区赛前夜,云台一直随机丢 CAN 帧。按框图查了半天没结果,最后顺着物理连接图发现,从主控到云台的 CAN 线中间经过了一个自制转接板,那个板子上的 120Ω 终端电阻居然被贴了两颗,等效 60Ω,总线负载直接把信号吃掉了一半。这种事原理图上根本看不出来,只有物理连接图能救你。
1.3 讲义的版本号里藏着一套内容管理方法
V0.2.1 这个号不是随便编的。我们内部约定:主版本号变化代表结构重写,次版本号变化代表新增章节,末位版本号变化代表纠错和补充细节。V0.1 是十页的手写笔记扫描件,V0.2 是第一次系统化整理出的六个章节,V0.2.1 则修掉了 V0.2 里三处错误——比如把电调的控制值范围和实际电流的对应关系写错了,以及漏掉了 DBUS 信号需要反相这个关键点。
这套版本约定最大的好处是"责任可追溯"。讲义末尾有一张修订记录表,写着谁在什么时间、因为什么事改了哪一页。新人踩了一个新坑,改完讲义就在表上记一笔,下一届就不会再踩。几年下来,这份东西的实际价值已经远超任何一本买来的教材,因为它记录的是你们这支队伍真实遇到过的所有问题。
2. 主控与外设骨架:为什么新人仍然该从官方开发板起步
2.1 自制主控板的诱惑与代价
几乎每一届都有新人问:为什么不用我们自己画的板子,官方开发板又贵又大。这个问题我在 V0.2.1 里专门写了一节来回答,因为我见过太多队伍在自制主控上翻车。
自制主控板的问题不在于画不出来,而在于你同时要面对三件事:硬件设计(电源、时钟、接口保护)、底层驱动(时钟树、外设初始化、中断优先级)和系统集成(和电调、裁判系统、图传的联调)。三件事叠在一起,任何一件出问题,现象都是"车不动",你根本没有办法二分定位。官方开发板的意义就在于它把前两件事替你做了,让你在起步阶段只有一个变量:系统集成。
注意:这不是说自制板不好。等到你队伍里有人能独立调通一套 CAN 通信、独立跑通一套 FreeRTOS 任务调度之后,再上自制板,成功率会高出好几倍。顺序反了,就是拿比赛当学费。
2.2 引脚资源分配表该怎么写才不返工
讲义里有一张空白的"引脚分配表"模板,要求每个新人自己填。表头是:引脚号、外设功能、占用模块、冲突备注、确认人。看起来简单,但填这张表的过程本身就是一次系统设计训练。
填表时最容易忽略的是"复用冲突"。比如某两个串口共用了一个时钟源,或者某个定时器的四个通道你想同时用来做四路 PWM,但其中一路的引脚已经被 CAN 占用了。这些冲突在纸上查手册的时候能发现,在代码里编译能过、烧录能过、跑起来才发现某路输出没反应,那时候排障成本是十倍。
我一般要求新人在填表之前做两件事:第一,把主控的引脚复用表打印出来,用荧光笔把打算用的引脚全部标出;第二,把所有模块的接口需求列成清单,包括数量、类型、电压。然后两边对照着填。这个流程走一遍大概两小时,但能省掉后面两天的调试。
| 模块 | 接口类型 | 数量 | 电压需求 | 常见冲突点 |
|---|---|---|---|---|
| 底盘电调 | CAN | 1 路总线 | 24V 供电 | 与云台电调共用总线时的 ID 冲突 |
| 云台电机 | CAN | 1 路总线 | 24V 供电 | 终端电阻位置 |
| 遥控接收机 | UART(DBUS) | 1 路 | 5V | 波特率与校验位配置 |
| 裁判系统 | UART | 1 路 | 5V | 与图传共用时的收发方向 |
| 图传模块 | 以太网 | 1 路 | 12V/24V | 网口差分对走线 |
| 传感器 | I2C/SPI | 视方案 | 3.3V | 上拉电阻与总线电容 |
2.3 时钟与波特率:HAL 配置里最隐蔽的两个坑
用图形化工具配置底层驱动确实省事,但有两个地方我要求新人必须手工核对,不能全信图形界面。
第一个是时钟树。图形界面默认给的时钟配置有时候和你的实际需求不匹配,尤其是涉及到 USB、以太网这类对时钟精度敏感的模块时。时钟配错的表现往往不是"完全不能用",而是"偶尔丢包""跑一会儿就死",这种间歇性故障最难查。讲义里的做法是:配完时钟后,把实际算出来的各总线频率写进注释,和手册里的范围对一遍。
第二个就是 CAN 波特率。这套系统里电调用的总线速率是固定的 1 Mbps,而 1 Mbps 对时钟分频的要求比较苛刻,稍微偏一点就会导致误码率上升。新人最常犯的错是照着别的例程抄了一个波特率参数,表面看能通信,但一上高负载就丢帧。讲义里给了一小段自查代码思路:把 CAN 的位时序参数(分频、时间段 1、时间段 2、跳变宽度)都算出来,验证采样点落在 75% 到 87.5% 这个区间内。
/* 位时序自查示例:验证采样点位置是否合理 */ float tq = 1.0f / (can_clk / prescaler); float total = (1 + bs1 + bs2) * tq; float sample_point = (1 + bs1) * tq / total; /* 建议 sample_point 落在 0.75 ~ 0.875 之间 */3. 供电链条:从电池到分电板再到每一级稳压
3.1 智能电池那个多出来的通信口到底读什么
第一次拿到电池,新人最容易疑惑的就是除了两根粗线之外的那个多针接口。那是电池管理系统对外输出的通信口,能读到电池的总电压、每一节电芯的电压、放电电流、剩余电量和温度。为什么一定要读?因为主回路电压在负载突变时会明显跌落,你如果只看总电压来判断电量,会严重误判。
讲义里把这件事的价值写得很直白:知道剩余电量,你才能在比赛中决定是继续进攻还是保电;知道单节电压差异,你才能及早发现某节电芯衰减,避免它在大电流放电时先掉到保护阈值导致整车断电。
读取这块数据的实现方式,通常是主控通过一路串口按固定协议去要数据,然后解析成结构体。讲义的示例代码只给了框架,因为协议本身会随电池型号变化,但结构是通用的:
typedef struct { float total_voltage; /* 总电压 V */ float cell_voltage[6]; /* 单节电压 V */ float current; /* 放电电流 A,充电为负 */ uint8_t soc; /* 剩余电量 % */ uint8_t temperature; /* 温度 ℃ */ } battery_info_t;提示:读电池数据一定要做超时和校验处理。串口线在震动环境下偶尔会接触不良,没有超时保护的话,解析函数会拿着半帧数据算出一堆离谱数值,然后你的低电量保护逻辑就会误触发。
3.2 分电板与超级电容:瞬时大电流下的电压跌落
底盘四轮同时急加速的瞬间,电流可以轻松冲到几十安培。这时候如果电池和电调之间的线径不够、接头接触电阻偏大,主回路电压会瞬间跌好几个伏。电压一跌,电调可能直接报欠压保护,表现就是"一加速就断电,松开又恢复"。
解决办法有两个层面。线径和接头上,讲义要求主回路走线尽量短、尽量粗,接头优先选接触面积大的类型,并且定期检查有没有氧化发黑。另一个层面就是并联储能模块,也就是常说的超级电容。它的作用是在大电流冲击的瞬间补上这部分能量,把电压跌落压在一个可接受的范围内。
但这里有个新人常犯的错:装了储能模块就以为万事大吉,结果模块本身没做好预充和限流,上电瞬间浪涌电流直接把保险丝烧了。讲义里专门写了一节预充流程,要求上电前先经过限流电阻给电容充电,等电压接近电池电压后再切换到主回路。
3.3 防护三件套:防反接、瞬态抑制与保险
讲义的电源章节最后固定讲三个保护器件,我管它叫"防护三件套"。
防反接是最基础的,常见做法是用一颗 P 沟道场效应管做理想二极管,压降小、发热低。新人容易用错的地方是选型时只看电流不看导通电阻,结果正常工作时管子上压降零点几伏,几十安培下发热量惊人。
瞬态抑制器件用来对付感性负载断电瞬间的反向尖峰。底盘和拨弹机构里全是感性负载,没有抑制的话,这些尖峰会在整个电源网络上乱窜,表现为随机复位、传感器误动作。选型时要关注钳位电压和响应时间,别只盯着封装。
保险丝的作用不是防短路,而是防"短路之后把电池也带走"。选值我一般建议按峰值工作电流的 1.5 到 2 倍来定,太小了会在急加速时误断,太大了就失去意义。这一类参数没有绝对标准,讲义里给的是思考方法,不是固定数值,因为不同车重、不同轮径的电流曲线差别很大。
4. 执行机构与总线:CAN 网络上的那些约定
4.1 电机编号、报文与"先拨码后上电"的铁律
这套电驱系统的通信几乎全走 CAN 总线,电机和电调的身份靠各自内部的编号区分。翻车最多的地方就是两个电调编号撞了,或者编号和代码里写的不一致。现象是:明明只给一个电机发指令,两个电机一起转,或者某个电机怎么发都没反应。
讲义的规矩是:每次上车前,逐个确认编号,确认时只接一个电调。更重要的是,改编号必须在断电状态下进行,改完再上电。带电改码轻则无效,重则电调进保护状态需要重新上电复位。
CAN 报文的收发结构也要求在讲义里写清楚。控制报文是几路控制量打包成一帧,反馈报文是每个电调单独回一帧,数据段里依次是机械角度、转速、实际电流和温度。新人第一次看这些数据时会很困惑:为什么角度是 0 到 8191?因为那是编码器的原始计数值,对应一圈的机械角度,要做多圈累计得自己写溢出处理。
/* 反馈报文解析框架,角度为编码器原始值 */ typedef struct { uint16_t ecd; /* 机械角度原始值 0~8191 */ int16_t speed; /* 转速 rpm */ int16_t current; /* 实际转矩电流原始值 */ uint8_t temp; /* 温度 ℃ */ } motor_feedback_t; /* 多圈角度累计:处理每圈溢出 */ static void update_total_angle(motor_feedback_t *fb, int32_t *total) { static uint16_t last_ecd = 0; int16_t delta = (int16_t)(fb->ecd - last_ecd); if (delta < -4096) delta += 8192; if (delta > 4096) delta -= 8192; *total += delta; last_ecd = fb->ecd; }注意:角度溢出处理没做的话,你的位置环在跨圈瞬间会看到角度从最大值跳回 0,PID 会以为电机瞬移了半圈,输出一个巨大的修正量,表现就是云台突然抽搐一下。这个问题在慢速调试时很难发现,一上高速就暴露。
4.2 控制量、电流与力矩之间的关系
讲义里有一张换算表,讲的是下发的控制值、电调实际输出电流和电机输出力矩之间的对应关系。很多新人以为下发的是"速度",其实下发的是电流环的目标值,也就是力矩。速度能到多少,取决于负载。
这个认知差异导致一个典型问题:新人写位置环时,直接拿"控制值"当"速度"去调参数,结果参数怎么调都不对。正确的做法是把整条链路理清楚:位置误差经过位置环输出速度期望,速度期望经过速度环输出电流期望,电流期望再经过限幅转成下发的控制值。三层环各管各的,混在一起就永远调不好。
| 层级 | 输入 | 输出 | 主要作用 |
|---|---|---|---|
| 位置环 | 目标角度、实际角度 | 速度期望 | 决定响应快慢与超调 |
| 速度环 | 速度期望、实际转速 | 电流期望 | 抑制扰动、稳定转速 |
| 电流环 | 电流期望 | 电调控制值 | 电调内部闭环,响应最快 |
摩擦轮这类应用又不太一样。它不需要精确位置,反而需要两个轮子转速严格一致,否则弹道会偏。这时候位置环直接砍掉,速度环的两路反馈拿来互相做差,差的绝对值超过阈值就报警或降速。这套做法讲义里写得很细,因为它属于典型的"文档里不会写、实际必须这么做"的经验型内容。
4.3 拨弹机构为什么总卡
拨弹卡弹是几乎每支队伍都遇到过的问题,讲义里单独用一节来讲。原因大致分三类:机械装配间隙、控制参数不合理、检测逻辑缺失。
机械层面,拨盘和弹道之间的间隙如果偏大或偏心,弹丸会在入口处被夹住。控制层面,如果拨盘电机用的是纯电流控制,遇到阻力时它只会硬顶,越顶越紧。正确做法是加上堵转检测:监测实际转速和实际电流,当转速明显低于期望而电流明显高于阈值时,立刻反转一小段再尝试。
讲义给出的检测逻辑是"转速-电流双阈值",单独用转速会被误判,单独用电流会被负载波动干扰。两个条件同时满足才判定为堵转,这样误报率会低很多。这套逻辑在 V0.2.1 里加了一段伪代码说明,因为 V0.2 只有文字描述,新人照着实现经常把阈值定死,换一批弹丸就失效。
5. 遥控、裁判系统与接地:现场故障高发区
5.1 遥控信号解析里那几个必须记住的参数
遥控接收机输出的串口信号,是最容易配错的一环。它的参数和普通串口不一样:常规的 8 位数据、无校验、1 位停止位在这里不成立。讲义里把正确参数用加粗标出来,并要求新人第一次调试时打印原始字节流验证。
新人的典型错误是:串口参数配对了,但收到的数据全是乱的,或者遥控器不动的时候数据也在跳。前者多半是参数没配对,后者往往是信号极性或者解析偏移搞错了。正确的验证方法很简单:遥控器摇杆全部回中,打印出的一帧数据应该是稳定的一组中位值;推动某一个通道,只有对应位置的两个字节变化。用这个方法五分钟就能定位问题。
提示:调试遥控信号时,建议先完全不接电机,只把解析结果映射成几个点灯 LED。看到 LED 跟着摇杆动,再去接执行机构。这样能把"信号问题"和"执行问题"彻底分开。
5.2 裁判系统的供电与数据流
裁判系统是比赛里非常特殊的一环,它既提供判罚数据,也是很多功能的数据源。讲义里对它的描述集中在两点:供电和数据方向。
供电上,它有独立的电源输出接口,不要图省事直接接到主回路上,电压对不上。数据方向上,它和主控之间的串口是双向的,但要区分哪些数据是"它发给你"的,哪些是"你发给它"的。新人最容易犯的错是把两路串口的收发方向搞反,结果数据一条都读不到。
还有一点讲义里反复强调:裁判系统相关的线束在比赛前要单独固定,因为它的接口大多是插拔式的,震动环境下很容易松。我在一次区域赛上亲眼见过对手因为裁判系统线松了被判通信异常,那是非常可惜的失分。
5.3 共地、屏蔽和一次真实的排查全过程
接地问题是最玄学的一类故障,讲义里用一个完整的排查案例来教方法。
现象:整车在静止时一切正常,一旦底盘大电流启动,云台就开始随机抖动,同时图传画面出现横条纹。
第一步,排除电源。用示波器看主控的 5V 和 3.3V 轨,发现启动瞬间有约 0.3V 的跌落,但仍在器件工作范围内,暂时不认为是根因。
第二步,怀疑 CAN 干扰。把云台从总线上单独断开,用独立线缆直连主控,抖动依旧。说明不是总线竞争。
第三步,查信号地。用万用表量主控地和云台地被连接的那根线,发现两者之间居然有几十毫伏的电位差,而这根地线走的是细线,还和电机的相线捆在了一起。至此基本锁定:电机相线的高频开关噪声通过线束耦合进了信号地,因为地线阻抗高,噪声无法快速泄放。
解决办法有三步:把信号地和功率地分开走线,只在电源入口处单点汇合;给云台通信线换成带屏蔽的线,屏蔽层单端接地;在云台电源入口加共模电感。改完之后抖动消失,图传横条也没了。
这个案例在讲义里的价值不在于"给出答案",而在于展示"怎么一步步缩小范围"。所以我要求学生读完这一节后,自己复述一遍排查顺序,作为考核项。
| 现象 | 优先怀疑 | 快速验证方法 |
|---|---|---|
| 静止正常、启动异常 | 接地或耦合干扰 | 分开信号地与功率地后复测 |
| 单个电机无响应 | 编号或接线 | 断电重新确认编号 |
| 随机复位 | 电源跌落或瞬态干扰 | 示波器观测供电轨 |
| 角度跳变 | 编码器溢出未处理 | 检查多圈累计逻辑 |
| 遥控数据乱跳 | 串口参数或极性 | 回中位打印原始数据 |
6. 讲义 V0.2.1 的迭代方法与新人上手节奏
6.1 把"踩过的坑"变成讲义里的固定章节
这份讲义最大的特点是没有一节是"凭想象写的"。每一节后面都能追溯到某一次真实的故障。我的做法是:每次故障解决后,填一张"故障记录卡",内容包括现象、排查过程、最终原因、改进措施、是否写入讲义。填完归档,等到版本迭代时统一整理。
这样做的好处是讲义永远在生长,而且生长方向是正确的——它补的都是真实缺口,不是理论盲区。V0.2 到 V0.2.1 的几十处修订里,有三分之一是文字表述优化,三分之二是实打实的技术纠错。比如有一处把电调控制值与电流的对应关系写错了量程,导致新人按错的量程去算限幅,电机上电就猛冲一下,非常危险。
注意:技术文档里的数值错误比缺内容更危险。缺失会让人去查手册,错误会让人以为自己是错的,从而把正确的做法改掉。所以每次修订,数值部分我都要求至少两个人交叉核对。
6.2 两周上手路线怎么排
讲义的最后是一张"两周上手路线表",这不是给老师看的,是给新人自己勾的进度表。
| 时间 | 目标 | 验收标准 |
|---|---|---|
| 第 1–2 天 | 认接口、读三张总图 | 能口述全车电源和总线拓扑 |
| 第 3–4 天 | 点亮主控、跑通串口打印 | 串口能看到自定义输出 |
| 第 5–6 天 | 单电机 CAN 通信 | 独立控制一个电机的转速和方向 |
| 第 7–8 天 | 遥控信号解析 | 摇杆动作能映射到 LED 或变量 |
| 第 9–10 天 | 多电机联调 | 四个底盘电机同时受控 |
| 第 11–12 天 | 电池数据与保护逻辑 | 低电量时能触发行为变化 |
| 第 13–14 天 | 整车联调 | 手动遥控整车正常行走 |
这张表的关键设计是每天都有"看得见的验收标准"。新人最怕的是"学了一周不知道自己会了什么",有验收标准就不会。而且每天的验收都建立在昨天的成果上,中间断了会立刻暴露,不会拖到比赛前才发现。
我自己带人的时候,还会在验收环节故意制造两个小故障让他排查,比如把某个电调编号改掉、或者把一根 CAN 线拔松。他在没有提示的情况下能不能定位,才是真正判断"上手了没有"的标准。这个做法后来也写进了 V0.2.1,作为带训人的操作建议。
6.3 讲义的传播方式:别做成只读的 PDF
最后说一个容易被忽略的点:讲义的形式。V0.1 是 PDF,结果是没人愿意改,因为改一次要走一遍导出流程,麻烦。V0.2.1 换成了可协作编辑的在线文档,任何人发现问题当场就能改,改完在修订记录里留一笔。
这个改动看起来只是工具切换,实际上改变了团队的文档习惯。文档从"某个人的成果"变成了"所有人的公共资产",新人改起来没有心理负担,老人也不用每次亲自维护。为了让改动可控,我们在文档里加了一条约定:涉及数值和接口定义的修改,必须留修改理由,并且当天在群里说一声。
这份讲义到现在还没有"完成版",我觉得也不应该有。每年规则在变,器件在换,新问题层出不穷,它能保持更新本身就是它最大的价值。真正让我觉得这份东西值得做下去的,是有一次新人自己排查出一个从没遇过的电源问题,解决之后主动跑来跟我说"我能不能把这个加到讲义里"。那一刻我就知道,这东西已经不只是我一个人的讲义了。