认识机器人的身体:控制板、电机和传感器
🔄 上一章回顾
上一章我们跟着一条 START_MOTION 命令出发,认识了上位机(电脑,负责发号施令)和下位机(控制板,负责现场执行)。我们知道了命令会通过串口这条"对讲机线"从电脑传给控制板,最终变成电机转动。现在,我们要走到控制板旁边,看看它的"身体"究竟由哪些零件组成。
🎯 本章你会学到
- STM32 控制芯片是什么,为什么它能当机器人的"大脑"
- 串口通信(UART)的工作原理——电脑和控制板如何"对话"
- 电机是怎样被控制方向和力道的(H 桥和 PWM)
- 编码器如何让机器人"知道"轮子转了多少
- IMU 如何让机器人"感受"自己的姿态
- 原厂小车怎样被改造成比赛机器人
命令来到控制板门口
上一章里,电脑已经准备好一条 START_MOTION。在它变成四个轮子的动作之前,我们先沿着串口线走到控制板旁边,看看这块板子上都有些什么。
一块控制板看上去布满芯片、插座和走线,初学者很容易感到不知所措——这里一根线,那里一个电容,到底该从哪里看起?不用担心,换个角度想,它其实更像机器人的身体:
- STM32 芯片 是大脑,负责组织所有工作
- 串口 是耳朵,负责听取电脑发来的消息
- 电机输出 是肌肉,负责让轮子转动
- 编码器和 IMU 是感觉器官,告诉大脑"轮子转了多少""身体有没有歪"
- 蜂鸣器和 OLED 屏 帮助人了解机器人当前的状态
每个部件只负责一小段任务,组合起来才完成一次运动。理解这个身体,不是为了记住每一块芯片的名字,而是为了知道:当电脑发来一条命令时,这条命令会经过哪些"器官",最后怎样变成轮子转动。
STM32F407:机器人的大脑
普通电脑和嵌入式芯片有什么不同?
在认识 STM32 之前,我们先想一个问题:你的笔记本电脑和机器人里的芯片,有什么不同?
你的电脑有 CPU、硬盘、内存、USB 接口、Wi-Fi 模块……这些东西分散在主板上,体积大、功耗高,需要风扇散热。但机器人不需要这么多功能——它不用打开浏览器、不用播放视频,它只需要做一件事:接收命令,控制电机,读取传感器。
想象一下你的手机芯片:它把处理器、内存、通信模块全部集成在一块指甲盖大小的芯片里。机器人的控制芯片也是类似的思路,只不过它更专注于控制硬件,而不是运行 App。这种"把电脑缩小、专门用来控制设备"的芯片,就叫微控制器(microcontroller,简称 MCU)。
认识 STM32F407
STM32F407 就是我们这个项目使用的 MCU。它里面包含了一台小型电脑需要的一切:
💡 零基础小课堂:芯片里的"硬盘"和"草稿纸"
- Flash(闪存)——芯片的"硬盘"。你写好的程序会被存储在这里,断电也不会丢失。每次芯片通电,它就从 Flash 里读出程序开始执行。
- RAM(随机存取存储器)——芯片的"草稿纸"。程序运行时产生的临时数据(比如当前电机速度、传感器读数)放在这里。断电后这些数据就清空了,就像擦掉草稿纸上的字。
除了 Flash 和 RAM,STM32 还有很多外设——串口、定时器、GPIO 等等。这些外设让芯片能和外界打交道:通过串口和电脑通信,通过定时器产生精确的控制信号,通过 GPIO 读取传感器。
💡 零基础小课堂:GPIO——万能接口
GPIO 的全称是 General-Purpose Input/Output(通用输入输出口)。你可以把它想象成一排可以自由分配工作的万能接口:有的接口被安排去读取开关状态,有的被安排去控制电机方向,有的被切换成串口功能。同一个接口在不同配置下可以做完全不同的事情——这种灵活性是 STM32 强大的地方。好在工程里已经把每个接口的用途写进了初始化代码,我们只需要知道"这个接口现在被配成了什么功能"就好。
MCU 和普通电脑 CPU 的关键区别在于:它把"计算"和"控制"打包在了一起,而且非常重视实时性——外界事件来了(比如串口收到一个字节),它需要在可预测的时间内做出反应,不能像电脑那样"等一会儿再说"。
💡 零基础小课堂:寄存器——芯片内部的"控制开关"
你可能会在代码里看到"寄存器"这个词。寄存器(register) 是芯片内部的一些小格子,每个格子里存着一个数字。往格子里写入不同的数字,就能控制硬件的不同行为——比如设置串口的通信速度、改变电机的输出大小。你可以把它想象成一排拨动开关:拨到不同位置,机器就做不同的事。我们暂时不需要直接操作寄存器,驱动代码已经帮我们封装好了。
中断:随时接听的"来电"
微控制器很适合守在机器人现场。电脑发送消息的时刻无法精确预测,轮子反馈的脉冲也会不断到来。STM32 可以用中断(interrupt) 及时处理这些事件。
中断就像手机来电铃声:不管你正在做什么——吃饭、看书、聊天——铃声一响,你就会去看手机。平时芯片做自己手里的事,一旦有紧急事件(比如串口收到新数据),它就先放下手里的活,处理完紧急事件再回来继续。没有中断的话,程序就只能一直反复询问"有没有新数据",既浪费时间,又可能错过关键时机。
systemInit():开馆前逐间亮灯
项目启动时,systemInit() 这个函数会把所有硬件外设逐一唤醒。它就像剧院开演前逐间亮灯、检查设备——先确定谁有优先权(中断分组),再按顺序启动每个外设。
这段代码位于 USER/system.c,下面是它初始化的主要内容:
| 顺序 | 初始化内容 | 作用 |
|---|---|---|
| 1 | 中断优先级分组 | 确定各个中断的优先权 |
| 2 | 延时函数 | 为后续初始化提供精确等待 |
| 3 | I²C 总线 | 准备芯片间的通信线路 |
| 4 | 系统参数 | 加载基本配置 |
| 5 | UART1 串口 | 打开与电脑的通信通道 |
| 6 | UART3 串口 | 原厂保留的备用通道 |
| 7 | 电机 PWM(TIM8) | 准备电机控制信号 |
| 8 | ICM20948(IMU) | 初始化姿态传感器 |
| 9 | 蜂鸣器 | 准备声音提示 |
| 10 | 使能按键 / 用户按键 | 准备按键输入 |
| 11 | OLED 屏幕 | 准备状态显示 |
| 12 | 四路编码器 | 准备轮速测量 |
这个顺序不是随便写的。比如 I²C 要在 ICM20948 之前准备好(因为 IMU 通过 I²C 通信),串口要在命令进来之前打开,电机 PWM 要在运动指令下发之前配置好。
下面是其中最关键的几行代码:
UART1_Init(115200); // 打开串口1,设置通信速度为 115200
MiniBalance_PWM_Init(16799, 0); // 初始化电机 PWM 控制,频率 10kHz
ICM20948_Init(); // 初始化姿态传感器(IMU)
EncoderA_Init(); // 初始化 A 号轮子的脉冲计数器(编码器)
EncoderB_Init(); // 初始化 B 号轮子的脉冲计数器
EncoderC_Init(); // 初始化 C 号轮子的脉冲计数器
EncoderD_Init(); // 初始化 D 号轮子的脉冲计数器
初始化完成代表设备已经具备工作条件,但"具备条件"不等于"正在参与控制"。就像把乐器都调好了音,但乐曲什么时候开始演奏,还要看指挥的手势。
💡 零基础小课堂:原理图和 Keil
仓库根目录有一份 C50C 原理图。原理图就是硬件的"地图",标明了每个零件怎么连接——比如哪个引脚接到电机,哪个引脚接到串口。图中主控芯片标记为 F407VET6,这就是我们的 STM32F407。看原理图时不用一开始就看懂每一页,先找到主控芯片、电机接口、串口接口就够了。
Keil 是写嵌入式程序的专用编辑器(IDE),类似于你可能用过的 VS Code,但专门针对 STM32 这类芯片做了优化。工程里的 Keil 项目文件定义了目标设备为 STM32F407VE,它会据此选择正确的启动文件和编译设置。
初学者常见疑问:为什么初始化函数的名字有的叫
Init,有的叫_Init?这主要是代码风格问题,不同文件的作者习惯不同。阅读时重点是看它初始化了哪个外设、用了哪个定时器、哪个引脚,不用纠结命名风格。
UART1:命令进入机器人的门
什么是串口通信?
到目前为止,我们知道电脑需要把 START_MOTION 命令发给控制板。但电脑和控制板是两个独立的设备——它们之间需要一种方式来交流。这就像两个人站在不同的房间里,需要一种方法来传递消息。
这种交流方式就是串口通信。我们用的具体方式叫 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发器)。
💡 零基础小课堂:串口通信——两个人用对讲机通话
想象两个人各拿一部对讲机通话。要成功通话,他们需要先约好:
- 用同一个频道——否则根本听不到对方
- 说话的语速要一致——一个人说得飞快,另一个人听得慢吞吞,就会听错
串口通信和这完全一样。"频道"就是连接的引脚(电脑的哪个口对控制板的哪个口),"语速"就是波特率(baud rate)——双方每秒传输多少个信号。波特率必须两端一致,否则收到的就是乱码,就像两个人语速不同导致听不清一样。
"串行"表示数据沿一条线路按时间顺序逐位通过,像一列单行行驶的小车,一个接一个地通过收费站。发送端和接收端提前约好速度与格式,就能把字节还原出来。
UART1 的具体配置
当前新协议选择 USART1。LOWER_CONTROLLER/BOARD/board_uart_config.h 负责选择通信端口,实际引脚定义位于 HARDWARE/Inc/uartx.h。当前启用的配置把发送脚设为 PA9,接收脚设为 PA10;备用的 PB6、PB7 没有参与当前编译。
换句话说,仓库里可能同时存在几条"路线",但编译器只会把当前选中的那一条接进程序。这种设计方便以后换接口时不用大改代码。
115200,8N1——通信的"约定"
UART1_Init(115200) 这行代码做了什么?它设置了串口的通信参数。让我们慢慢来看:
- 115200 是波特率,意思是每秒传输大约 115200 个信号。这是一个非常常用的速度。
- 8 表示每次传输 8 位数据(刚好是一个字节)
- N 表示 No parity,不做奇偶校验(一种简单的错误检测,这里不需要)
- 1 表示用 1 个停止位来标记一次传输的结束
合在一起写成 "115200,8N1",这就是双方的"通话约定"。
⚠️ 串口通信最重要的原则
两端的参数必须一致!如果上位机发的是 115200,下位机也必须配成 115200;如果一边用 8N1,另一边也要用 8N1。参数不一致,收到的就是乱码——就像对讲机频道不同,只能听到噪音。
UART3:原厂保留的备用通道
systemInit() 还初始化了 UART3,这是原厂工程保留下来的硬件准备。新的比赛通信路径由 LOWER_CONTROLLER/BOARD/board_uart_config.h 选择,当前明确指向 UART1。
这样阅读代码时就有一条清楚路线:寻找新命令,应当沿 UART1 进入 TRANSPORT。UART3 目前更像一条备用通道,暂时不参与新的协议流程。
初学者看到这种"旧代码还在、新代码另起炉灶"的情况不必慌张,大型仓库里很常见:保留旧功能是为了调试和参考,新功能走自己的路径。
电机输出:方向和力道分开表达
机器人想让直流电机转动,需要回答两个问题:往哪边转?给多大输出? 这两个问题在代码里是分开处理的——先决定"这个轮子要向前还是向后",再决定"用多大力气"。
方向控制:H 桥
方向由成对的控制脚表达。以电机 A 为例,代码会设置 AIN1 和 AIN2 两个引脚。
💡 零基础小课堂:H 桥——四个开关控制电流方向
H 桥(H-bridge) 是直流电机最常见的方向控制方式。想象四个开关摆成字母 H 的形状,电机在 H 的横杠上:
- 打开左上和右下两个开关→电流从左往右流→电机正转
- 打开右上和左下两个开关→电流从右往左流→电机反转
- 同一侧的两个开关都打开→电机被短接→快速刹车
在代码里,AIN1 和 AIN2 就对应 H 桥的两个控制端。一个给高电平、一个给低电平,电机朝一个方向转;把电平交换,电机就反向。B、C、D 三路各有自己的方向脚,原理完全一样。
力道控制:PWM——快速开关的水龙头
知道了方向,接下来就是力道。力道使用 PWM(Pulse Width Modulation,脉宽调制) 来表达。
可以把 PWM 想象成快速开关水龙头:在一个很短的周期里,打开的时间越长,平均送出的水就越多。如果一秒之内,水龙头打开 80% 的时间、关闭 20% 的时间,水量就接近满开的 80%。PWM 做的事情完全一样——只不过开关的是电流,而不是水。
电机看到的是连续而快速的开关,但由于机械惯性,电机不会一下转一下停,而是表现得比较平滑。就像你快速开关水龙头时,水流虽然有波动,但水管里持续有水在流。
PWM 的频率也很重要:频率太低,电机会明显"一顿一顿",甚至发出嗡嗡声;频率太高,驱动电路的开关损耗会增加。工程里把 PWM 频率定在 10 kHz(每秒开关一万次),是一个在平滑性和效率之间比较常见的折中。
当前的开环控制
MiniBalance_PWM_Init(16799, 0) 让定时器 TIM8 以 10 kHz 产生 PWM。计数范围从 0 到 16799,代码把满量程记为 16800。新运动层使用的固定值是 3000。
💡 零基础小课堂:开环控制——闭着眼睛开车
当前的运动控制方式叫开环控制(open-loop control)。它像闭着眼睛开车,把油门固定在一个位置:程序给出一个固定的电机输出值,但完全不看轮子实际转了多快。
好处是:简单、直接,方便先验证电机接线和方向是否正确。 坏处是:遇到地面阻力变化或电池电压下降时,速度会跟着波动——因为没有人在"看路"做调整。
后面的章节会介绍闭环控制,那才是"睁开眼睛开车"——根据实际轮速自动调整输出。
gear 参数:功能正在"分期实现"
START_MOTION 帧会带上一个 gear(档位)参数,但 motion_start_motion() 里暂时用了一行特殊的写法:
(void)gear; // 告诉编译器:我知道这个参数存在,但暂时不使用它
💡 零基础小课堂:(void) 写法是什么意思?
在 C 语言中,如果一个函数接收了参数但没有使用它,编译器会发出警告:"你传了一个参数进来,但没用到,是不是写漏了?" (void)gear 就是告诉编译器:"我是故意不用的,别提醒我了。" 这是一种常见的写法,意味着这个功能正在分期实现——协议先把位置占好,业务逻辑后面再填。
命令中的"微速、慢速、快速"已经有编码,但实际输出仍统一使用固定 PWM 3000。后续加入档位表或闭环控制时,这个参数才会真正影响速度。
思考一下:为什么先固定 PWM 3000,而不是直接根据 gear 算出不同速度?因为在大型电控代码里,通常要先确认"电机能转、方向正确、轮位映射没问题",再逐步加入速度闭环和档位映射。一步做太多,出了问题反而不好定位。
从寄存器到真实转矩
STM32 的引脚负责表达控制信号,电机驱动电路负责把信号变成能够带动电机的电流。这个关系像水龙头把手与水管:把手给出开关和大小,真正输送水的是后面的管路。
固件写入 PWMA 时,实际是在修改 TIM8 的比较寄存器;定时器随后在 PC9 引脚产生 PWM。A 路的方向脚 AIN1、AIN2 位于 PB13 和 PB12。
把这个过程理清楚:
- 上层代码说"电机 A 输出 3000"
motion_set_pwm()根据正负号设置 PB13、PB12 的高低电平,决定方向- 把数值的绝对值写入 TIM8 的比较寄存器
- TIM8 在 PC9 引脚上输出对应占空比的 PWM 波形
- 电机驱动板根据方向脚和 PWM 波形,向电机供电
- 电机转动,带动轮子
B、C、D 通道沿用同样结构,各自连接 TIM8 的另一个比较通道和一对方向脚。motion_set_pwm() 先依据数值正负设置方向,再把绝对值写入 PWM。于是 +3000 与 -3000 拥有相同输出幅度但旋转方向相反,0 会把 PWM 清零。
这个简单约定让上层算法可以用带符号的数字描述轮子——正数表示正转,负数表示反转——而不需要关心每一根方向脚到底要怎么设。
实机调试时,软件数值、驱动供电、电机接线和轮子安装共同决定最终动作。板级映射与方向系数把这些现场差异收拢起来,运动层便能继续使用"左前轮向前"这样清楚的语言。
四个通道与四个轮位
电机驱动板把输出口叫作 A、B、C、D,但运动算法更关心左前、左后、右前、右后。通道名描述电线接在哪里,轮位名描述电机位于车身哪里。板级配置负责在两套名称之间搭桥。
这个桥非常重要:如果接线和算法各说各话,车子很可能原地打转甚至朝反方向跑。
当前 board_motion_config.h 给出的映射如下:
| 车身轮位 | 电机通道 | 方向校正系数 |
|---|---|---|
| 左前 | A | +1 |
| 左后 | D | -1 |
| 右前 | B | -1 |
| 右后 | C | +1 |
方向校正系数来自真实安装关系。同样写入正值时,镜像安装的电机可能让轮子朝相反方向转。配置层用 +1 或 -1 统一"车身向前"的含义。运动算法只需表达四个逻辑轮位应该怎样转,接线变化可以集中在板级文件中处理。
初学者常见疑问:如果电机线接反了或方向系数写错了,会发生什么?最直观的现象是:程序让车往前跑,它却往后退;或者让车旋转,它却平移。调试时先让单个轮子以固定 PWM 正转,观察实际方向,再回头修正系数。通常不需要改运动算法,只需要改
board_motion_config.h。
仓库中的 MOTION/README.md 曾保留过一份较早的默认映射说明,当前可执行配置以 board_motion_config.h 为准。文档可能会滞后,但编译进去的配置不会撒谎。当你发现车子行为和预期不符时,优先看代码里的宏定义,而不是只看 README。
这张图表达了一个分层思想:最上层是运动算法关心的逻辑轮位,中间是板级配置做的翻译,最下面是实际接线的电机通道。以后如果换一块驱动板,或者某根线需要重新插,只要改中间这层翻译,运动算法本身可以不动。
编码器:让机器人知道轮子转了多少
为什么需要知道轮子转了多少?
前面我们讲了开环控制的问题——程序给出一个固定的 PWM 值,但不知道轮子到底转了多快。如果地面变滑了、电池电压降低了,轮子会悄悄变慢,而程序对此一无所知。
要解决这个问题,我们需要一种方法来测量轮子的实际转速。这就是编码器的工作。
编码器是什么?
编码器(encoder) 会随着电机或轮轴转动产生脉冲。它像安装在轮子旁边的计步器——每走一步,它就"咔嗒"记录一下。程序统计这些"咔嗒"的数量和方向,就能算出轮子转了多少、转得多快。
没有编码器的话,机器人就像一个闭着眼睛跑步的人:它知道自己在蹬腿,但不知道到底跑了多远、有没有跑偏。
编码器怎么工作?
编码器和定时器的配合方式是这样的:
- 编码器安装在电机旁边,轮子每转一小段,编码器就发出一个脉冲信号
- 这个脉冲被送到定时器的外部输入脚
- 定时器内部有一个计数器,每收到一个脉冲就加 1(或减 1,取决于转动方向)
- 程序定期读取这个计数器,就能知道这段时间里轮子转过了多少
工程为 A、B、C、D 四路编码器分别使用定时器 TIM2、TIM3、TIM4 和 TIM5。systemInit() 已经调用了四个初始化函数,底层读取接口是 Read_Encoder()。
有了编码器提供的实际速度数据,就可以做闭环控制(closed-loop control)——把目标速度和实际速度反复比较,自动调整输出。这就像骑车时不断看路况并调整脚上的力。闭环控制会在第 5 章详细展开,这里只需要知道:编码器是实现闭环的硬件基础。
当前新的 MOTION 仍使用固定 PWM,SENSORS 目录也把 encoder_feedback.c 列为后续文件。硬件驱动已经在场,新业务层还需要把反馈接进运动控制。看到 EncoderA_Init() 被调用,只能说明编码器已经可以计数;真正用它去修正 PWM,还需要另一段闭环代码。
🔧 调试小技巧
调试编码器时,可以先用手转动轮子,同时读取 Read_Encoder() 的返回值,确认:正方向转动时数值增加,反方向转动时数值减少,停转时数值稳定。这一步验证通过,后续闭环才能可靠。
ICM20948:感受姿态变化
控制板还连接了 ICM20948。它是一颗 IMU(Inertial Measurement Unit,惯性测量单元)。可以把它想象成机器人的内耳——人靠内耳保持平衡、感知自己是站着还是歪了,机器人则靠 IMU 感知自己的姿态。
ICM20948 内部集成了三种传感器:
- 加速度计:测量三个轴上的加速度。静止时,它会感受到重力,因此可以大致判断哪边是"下"。
- 陀螺仪:测量三个轴上的角速度(旋转的快慢)。积分一段时间,可以估算出转过了多少角度。
- 磁力计:测量地磁场方向,像一个电子指南针。
为什么需要三种传感器?因为每种都有自己的弱点:陀螺仪会慢慢"漂移"(静止不动也会输出一个小小的非零值),磁力计容易受电机和金属干扰,加速度计在剧烈运动时不准。实际工程中通常要把三者的数据结合起来,取长补短,才能得到稳定的姿态信息。这种方法叫传感器融合,后面的章节会更详细地介绍。
仓库的 ICM20948 驱动能够初始化器件与磁力计,也提供读取数据的接口。读取结果存放在全局 imu 变量中。驱动还保留了零漂校准接口——因为传感器静止时也可能出现微小偏移,像一只没有完全归零的秤。
新协议定义了 GET_HEADING,其中 heading 表示航向角。当前命令分发器会检查这条命令,然后返回 NOT_IMPLEMENTED(尚未实现)。SENSORS 规划中的 heading.c 将来会把底层 IMU 数据整理成稳定的航向接口,再交给应用层回传。这里又是一次"硬件已就绪,业务待补齐"的分期实现。
从原厂小车到新的比赛业务
这个项目的控制板并不是我们从零设计的,而是基于原厂 WHEELTEC 的通用小车工程进行改造。你可以把它想象成改装一辆二手车:车的发动机、轮子、传感器都是现成的好零件,但我们需要重新安排驾驶逻辑,让它适应比赛场地的需求。
原厂工程覆盖多种车型和交互方式。旧入口会创建运动控制、数据显示、LED、数据上报、IMU、手柄和自检等多项任务——功能齐全但边界模糊,像一辆什么都能做但不够专精的样车。
当前 USER/main.c 已经换成一条更集中的入口:启动阶段只创建新的 app_task,旧 BALANCE 业务继续留在仓库中提供参考。
💡 零基础小课堂:麦轮——能横着走的轮子
编译宏 MEC_CAR 说明这是一台麦轮车。麦克纳姆轮(Mecanum wheel,简称麦轮) 是一种特殊的轮子——它的轮面上装了一圈斜着的小滚轮。普通轮子只能前后滚,但麦轮通过四个轮子的速度组合,可以实现横向平移和原地旋转,非常适合比赛场上快速变向。保留 MEC_CAR 宏,意味着底层运动学仍然按麦轮来组织。
这次改造保留了硬件能力,也让比赛逻辑拥有清晰边界。Keil 工程已经把 app_main.c、command_dispatcher.c、response_sender.c、协议生成代码、UART transport 和运动控制文件加入编译目标,新的命令链开始承担实际业务入口。
小提示:大型仓库重构时,常见策略是"先立新后破旧"——新的业务逻辑走新的入口和新的任务,旧代码先不删除,作为参考资料。这样即使新逻辑还有 bug,也可以快速切回旧代码验证硬件是否正常。
小结
现在,机器人身体的主要部件已经认清:
- STM32F407 是控制板的大脑——一颗集成了处理器、存储和外设的微控制器
- UART1(PA9/PA10) 是电脑与控制板之间的通信门,
START_MOTION将从这里进入 - TIM8 和四路方向脚 负责把带符号的电机输出变成真实的转矩
- 板级配置 把逻辑轮位映射到电机通道,并用
+1/-1统一方向 - 编码器(TIM2~TIM5) 已经准备好测量轮子转速,为后续闭环打好基础
- ICM20948 已经初始化,等待上层把航向接口实现出来
- 新的
app_task成为程序入口,旧业务作为参考保留
START_MOTION 将从 PA10 进入 UART1,STM32 会在收到一个字节时立即响应。它怎样在繁忙的程序中接住每个字节,又怎样等到整封"信"收齐后再打开,下一章会从上电和任务调度开始回答。
本章新词
| 术语 | 英文 | 一句话解释 |
|---|---|---|
| 微控制器 | MCU / Microcontroller | 一台指甲盖大小的完整电脑,专门用来控制硬件设备 |
| Flash | Flash Memory | 芯片的"硬盘",存储程序代码,断电不丢失 |
| RAM | Random Access Memory | 芯片的"草稿纸",存放运行时的临时数据,断电就清空 |
| GPIO | General-Purpose I/O | 可以自由分配工作的万能接口 |
| 寄存器 | Register | 芯片内部的小格子,写入数字就能控制硬件行为 |
| 中断 | Interrupt | 像手机来电——不管在干什么,紧急事件一到就去处理 |
| 原理图 | Schematic | 硬件的"地图",标明每个零件怎么连接 |
| Keil | Keil MDK | 写嵌入式程序的专用编辑器(IDE) |
| UART | Universal Asynchronous Receiver/Transmitter | 一种串口通信方式,让两个设备互相传输数据 |
| 波特率 | Baud Rate | 通信的"语速",双方每秒传输多少个信号,必须一致 |
| PWM | Pulse Width Modulation | 脉宽调制——通过快速开关来控制平均输出的大小 |
| H 桥 | H-Bridge | 四个开关组成的电路,用来控制电流方向,从而控制电机正反转 |
| 编码器 | Encoder | 安装在轮子旁边的"计步器",记录轮子转了多少 |
| 开环控制 | Open-loop Control | 只管输出、不看结果的控制方式,像闭着眼睛开车 |
| 闭环控制 | Closed-loop Control | 根据实际反馈自动调整输出,像看着路况开车 |
| IMU | Inertial Measurement Unit | 惯性测量单元——机器人的"内耳",感知姿态和旋转 |
| 传感器融合 | Sensor Fusion | 把多个传感器的数据结合起来,取长补短得到更准确的结果 |
| 麦轮 | Mecanum Wheel | 轮面上装了斜向小滚轮的特殊轮子,能实现横移和原地旋转 |