集成式人机交互与底层驱动环境设计说明书

模块名称:stm32_keyboard_control
核心节点:keyboard_control_node
固件对应:USER/main.c (STM32 Firmware)
适用阶段: 硬件调试 / SLAM 建图预备

1. 设计概述 (Design Overview)

在早期架构中,控制逻辑(Controller)与硬件接口(Driver)被物理分离。考虑到 STM32 固件采用了高效的字符流控制协议,我们将架构精简为集成式驱动模式。本模块 keyboard_control_node 充当 ROS 2 上位机与底层硬件的唯一交互网关,通过多线程并发机制,同时实现毫秒级的人机交互控制与高频传感器数据采集。

1.1 系统上下文架构 (System Context Architecture)

在这里插入图片描述

2. 软件详细设计 (Software Detailed Design)

2.1 并发模型 (Concurrency Model)

为了保证控制的实时性与数据的完整性,节点内部采用异步多线程模型

  1. 输入监听线程 (Daemon Thread)

    • pynput.keyboard
    • 职责:以非阻塞方式监听键盘中断事件(Press/Release)。
    • 同步机制:通过原子变量或线程锁(Lock)更新全局控制状态 self.target_cmd
    • 逻辑
      • on_press: 映射 WASD 为对应字符,置位 active_flag
      • on_release: 触发死人开关 (Deadman Switch) 逻辑,立即发送停止指令或置位停止标志。
  2. IO 主线程 (Main Loop)

    • pyserial, rclpy.timer
    • 周期:20Hz (50ms)
    • 职责 (下行):检查 self.target_cmd,向串口写入对应的 ASCII 字符(如 b'W')。
    • 职责 (上行):读取串口缓冲区,以 \n 为定界符提取传感器数据帧。

2.2 通信协议规范 (Protocol Specification)

本系统采用非对称混合协议:下行控制追求极简低延迟,上行数据追求可读性与解析便利。

2.2.1 下行控制协议 (Host -> MCU)

类型: 单字节字符指令 (Single-Byte Character Command)
波特率: 115200 bps

动作键位发送载荷 (Hex)固件响应函数 (main.c)运动学描述
前进W0x57SmoothControlSpeed(v, v, v, v)vx>0,ωz=0v_x > 0, \omega_z = 0vx>0,ωz=0
后退S0x53SmoothControlSpeed(-v, -v, -v, -v)vx<0,ωz=0v_x < 0, \omega_z = 0vx<0,ωz=0
左转A0x41SmoothControlSpeed(-v, -v, v, v)vx=0,ωz>0v_x = 0, \omega_z > 0vx=0,ωz>0 (原地左旋)
右转D0x44SmoothControlSpeed(v, v, -v, -v)vx=0,ωz<0v_x = 0, \omega_z < 0vx=0,ωz<0 (原地右旋)
急停Space0x20SmoothControlSpeed(0, 0, 0, 0)强制阻尼制动
  • 心跳保活:STM32 端的 CheckCommandTimeout 设定了 500ms 超时。上位机必须以至少 2Hz 的频率发送指令,否则机器人将自动停车。
2.2.2 上行反馈协议 (MCU -> Host)

类型: ASCII CSV 文本流
帧结束符:\n (0x0A)

  1. 里程计数据帧

    • 格式/four_wheel_encoder,<enc1>,<enc2>,<enc3>,<enc4>,<timestamp>
    • 解析示例
      # 原始数据: b'/four_wheel_encoder,102,-98,105,-100,12054\n'
      parts = line.decode().strip().split(',')
      if parts[0] == '/four_wheel_encoder':
      fl, fr, rl, rr = map(int, parts[1:5])
      ts = int(parts[5])
    • 物理意义encX 代表自上一次采样以来(约 20ms)各个轮子的脉冲增量 (Delta Pulse)
  2. IMU 数据帧

    • 格式/imu_data,<ax>,<ay>,<az>,<gx>,<gy>,<gz>,<temp>,<timestamp>
    • 物理意义:MPU6050 的原始 16 位寄存器值 (LSB)。需在上位机根据量程(如 ±2g, ±2000°/s)转换为标准单位 (m/s2m/s^2m/s2, rad/srad/srad/s)。

3. 关键算法实现 (Critical Implementation)

3.1 里程计解算 (Odometry Calculation)

为了支持 SLAM,keyboard_control_node 必须实现运动学正解,将编码器脉冲转换为机器人的位姿 (x,y,θ)(x, y, \theta)(x,y,θ)

  • 参数定义
    • PULSE_PER_METER: ≈1571.0\approx 1571.01571.0 (基于轮径 0.067m, 11线霍尔, 30:1 减速比)
    • WHEEL_TRACK: 0.17m0.17m0.17m (轮距)
  • 计算逻辑 (差速模型):
    1. 计算左右轮平均位移:
      ΔdL=enc1+enc32⋅Kscale,ΔdR=enc2+enc42⋅Kscale\Delta d_L = \frac{enc_1 + enc_3}{2} \cdot K_{scale}, \quad \Delta d_R = \frac{enc_2 + enc_4}{2} \cdot K_{scale}ΔdL=2enc1+enc3Kscale,ΔdR=2enc2+enc4Kscale
    2. 计算中心位移与旋转:
      Δs=ΔdR+ΔdL2,Δθ=ΔdR−ΔdLWtrack\Delta s = \frac{\Delta d_R + \Delta d_L}{2}, \quad \Delta \theta = \frac{\Delta d_R - \Delta d_L}{W_{track}}Δs=2ΔdR+ΔdL,Δθ=WtrackΔdRΔdL
    3. 更新全局位姿:
      xt=xt−1+Δs⋅cos⁡(θt−1+Δθ2)x_t = x_{t-1} + \Delta s \cdot \cos(\theta_{t-1} + \frac{\Delta \theta}{2})xt=xt1+Δscos(θt1+2Δθ)
      yt=yt−1+Δs⋅sin⁡(θt−1+Δθ2)y_t = y_{t-1} + \Delta s \cdot \sin(\theta_{t-1} + \frac{\Delta \theta}{2})yt=yt1+Δssin(θt1+2Δθ)
      θt=θt−1+Δθ\theta_t = \theta_{t-1} + \Delta \thetaθt=θt1+Δθ

3.2 数据发布规范 (ROS 2 Interface)

解析后的数据需封装为以下标准消息:

  1. 里程计 (/odom)

    • 类型:nav_msgs/msg/Odometry
    • 坐标系:frame_id="odom", child_frame_id="base_link"
    • 内容:包含位姿 pose 和 速度 twist
  2. TF 变换 (tf2_ros)

    • 必须广播 odom -> base_link 的动态变换。这是 SLAM 算法(如 Cartographer 或 Slam Toolbox)定位机器人的基础。
    • 实现:使用 tf2_ros.TransformBroadcaster

4. 调试与集成指南 (Integration Guide)

4.1 启动步骤

  1. 授予串口权限
    sudo chmod 777 /dev/ttyUSB0
  2. 运行节点
    ros2 run stm32_keyboard_control keyboard_control_node
  3. 验证数据
    • 新开终端,检查是否收到 TF 数据:
      ros2 run tf2_ros tf2_echo odom base_link
    • 如果只能控制但没有 TF 输出,说明上行数据解析逻辑缺失,需立即补全,否则 SLAM 无法运行。

4.2 常见问题排查

  • 现象:机器人移动断断续续。
    • 原因:心跳发送频率低于 2Hz,触发了 STM32 的超时保护。
    • 对策:检查 timer 回调频率,建议设为 10Hz 或 20Hz。
  • 现象:TF 树断裂。
    • 原因:未正确发布 /odom 话题或 TransformBroadcaster 未实例化。
    • 对策:确保 keyboard_control_node 中包含里程计解算代码。
posted @ 2026-01-09 15:20  gccbuaa  阅读(2)  评论(0)    收藏  举报