STM32 底层固件架构与驱动设计说明书
适用硬件: STM32F103 系列 (基于野火 F103-MINI 开发板修改)
模块功能: 运动控制、传感器数据采集、底层通信
1. 系统概述 (System Overview)
本固件运行于机器人底盘控制器的 STM32 MCU 上,作为底层驱动核心,承担以下职责:
- 运动执行:通过 I2C 总线控制四轮差速电机驱动板,实现全向移动与平滑调速。
- 数据感知:采集 IMU (MPU6050) 的姿态数据与电机编码器的里程计数据。
- 数据交互:通过 UART 串口与上位机 (ROS 2 节点) 进行高频数据通讯。
2. 硬件资源配置 (Hardware Configuration)
根据 USER/main.c 及相关 BSP 文件,系统硬件资源分配如下:
| 外设 (Peripheral) | 引脚/总线 (Pin/Bus) | 功能描述 (Description) | 备注 |
|---|---|---|---|
| USART1 | PA9 (TX), PA10 (RX) | 上位机通讯接口 | 波特率 115200, 开启接收中断 |
| I2C (Hard/Soft) | PB10 (SCL), PB11 (SDA) | 电机驱动板通信 | 用于下发速度与读取编码器 |
| I2C (Sensor) | I2C1 (配置依赖) | MPU6050 通信 | 读取六轴传感器数据 |
| TIM3 | 内部定时器 | 系统时基/定时任务 | 提供精确延时或中断源 |
3. 核心驱动模块详细设计
3.1 电机控制与里程计 (Motor & Odometry)
代码文件: USER/main.c, BSP/motor_model/bsp_motor_iic.c
3.1.1 物理参数模型
系统采用运动学模型解算里程计,关键物理参数定义如下:
- 减速比与线数:
1:30减速比,11线霍尔编码器。 - 脉冲系数 (PULSE_PER_REVOLUTION): 11.0×30.0=330.011.0 \times 30.0 = 330.011.0×30.0=330.0 (每圈脉冲数)。
- 轮胎参数: 直径 0.067m,周长约 0.21m。
3.1.2 编码器读取与死区过滤
为了解决静态时的信号抖动问题,代码中实现了智能死区过滤策略 (CalculateOdometry 函数):
-
机制:系统检测当前是否接收到运动指令 ('W', 'A', 'S', 'D')。
-
逻辑 :
- 运动中:不做过滤,保留微小的脉冲变化,确保 SLAM 建图精度。
- 静止中 :若脉冲变化量 Δ∈[−2,2]\Delta \in [-2, 2]Δ∈[−2,2],强制置零。
-
实现代码片段 :
cbool is_moving = (current_cmd == 'W' || current_cmd == 'A' || ...); if (!is_moving) { if(delta_pulse[i] >= -2 && delta_pulse[i] <= 2) delta_pulse[i] = 0; }
3.1.3 平滑速度控制
为保护电机齿轮箱并减少机器人急停急启带来的冲击,实现了加速度限制逻辑 (SmoothControlSpeed 函数):
- 最大加速度 :
max_acceleration = 100。 - 每次循环仅允许速度值在当前值基础上增加或减少最大加速度值,实现梯形速度规划的简易版本。
3.2 惯性测量单元 (IMU)
代码文件: USER/mpu6050.c
- 初始化流程 :
- 硬件复位等待电源稳定。
- ID 校验 :循环 5 次读取
WHO_AM_I寄存器 (期望值0x68或0x69),确保硬件连接正常。若失败则通过串口打印错误诊断。 - 配置电源管理、采样率分频、低通滤波及量程。
- 数据采集:提供原始加速度 (Accel)、角速度 (Gyro) 和温度 (Temp) 的读取接口。
4. 主程序架构与调度 (Main Loop Logic)
系统采用 "前后台系统" (Foreground-Background System) 架构:
4.1 中断层 (后台)
- USART1_IRQHandler :
- 负责接收上位机指令。
- 解析单字符控制指令 ('W', 'A', 'S', 'D', 'T')。
- 时间同步 :收到 'T' 指令后解析随后的时间戳字符串,计算 STM32 与 ROS 系统的时间偏移量
system_time_offset。
4.2 主循环层 (前台)
main() 函数中的 while(1) 循环通过轮询系统时间 (GetSystemTime) 实现非阻塞的多任务调度:
-
指令执行任务:
- 调用
ExecuteCommand(current_cmd)执行当前速度控制。 - 超时保护 :调用
CheckCommandTimeout(),若超过 500ms 未收到新指令,自动停车,防止失控。
- 调用
-
里程计发布任务 (20ms 周期):
- 调用
CalculateOdometry()计算脉冲增量。 - 通过串口发送格式化数据:
/four_wheel_encoder,e1,e2,e3,e4,timestamp\n。
- 调用
-
IMU 发布任务 (10ms 周期):
- 读取 MPU6050 数据。
- 通过串口发送格式化数据:
/imu_data,ax,ay,az,gx,gy,gz,temp,timestamp\n。
-
状态监控任务 (约 2-4秒):
- 每 200 次循环打印一次系统摘要,用于调试。
5. 关键算法与原子操作
5.1 时间戳获取
为了保证多任务环境下时间的单调递增性,GetSystemTime 函数使用了原子保护:
c
__disable_irq(); // 关中断
current_time = monotonic_time_ms;
__enable_irq(); // 开中断
这防止了在读取时间变量时被定时器中断打断从而导致的数据竞争。
6. 接口协议摘要 (Interface Summary)
为了配合后续 ROS 驱动开发,底层固定的数据格式如下:
- 上行 (STM32 -> ROS):纯文本 CSV 格式,以换行符结尾。
- 下行 (ROS -> STM32) :
- 单字节指令:
W/A/S/D(前后左右)。 - 时间同步指令:
T+ 时间戳文本。
- 单字节指令: