3.4 KiB
3.4 KiB
编码器刹车 — 设计与实现
1. 硬件
编码器2,引脚:
| 信号 | 引脚 | 模式 |
|---|---|---|
| LSB 脉冲 | GPIO 67 | 输入 |
| DIR 方向 | GPIO 72 | 输入 |
两引脚均属 gpiochip64(GPA64,base=64,16 pins)。
2. 触发条件
ControlUpdate(speed, zebra_block) 中 zebra_block == true 时进入刹车流程。zebra_block 由 CameraHandler Step 5 斑马线状态机传入——当 g_zstate == Z_STOP 时为 true。
3. 刹车状态机
┌──────────┐
正常行驶 ───→ │ IDLE │
└────┬─────┘
│ zebra_block==true
▼
┌──────────┐
│ BRAKING │ ← 施加 -30% 占空比
│ │ 每帧读 GPIO 67
└────┬─────┘
┌───────────┴───────────┐
│ 脉冲变化 │ 脉冲不变
▼ ▼
轮子在转 → 继续刹车 g_brake_still++
重置计数器 │
连续 5 帧无变化?
或超时 60 帧?
│
▼
┌──────────┐
│ HOLDING │ ← duty=0,保持静止
└──────────┘
│
zebra_block==false
│
▼
┌──────────┐
│ IDLE │
└──────────┘
4. 参数
定义在 src/control.cpp:
| 常量 | 值 | 含义 |
|---|---|---|
BRAKE_STILL_THRESH |
5 | 连续无脉冲帧数阈值,超过即判停 |
BRAKE_TIMEOUT |
60 | 最长刹车帧数(~2s @30fps),强制释放 |
BRAKE_DUTY |
-30 | 刹车占空比(-100~100,负值=反转) |
5. 读取方式
GPIO 67 通过 sysfs 文件描述符轮询(GPIO::readValue()),每帧 lseek + read 一次。不依赖中断。
为什么轮询够用: 30fps 帧率 = 33ms 间隔。编码器假设 100+ 脉冲/转,即使 1 转/秒的极慢速度也有 3+ 脉冲/帧间隔,不会漏判。
6. 刹车强度
motor[i]->updateduty(-30)
MotorController::updateduty() 内:
- 占空比:
period * |duty| / 100 = 50000 * 30 / 100 = 15000 ns - 方向:
duty < 0→directionGPIO.setValue(false)→ 反转
即 30% 占空比的反向驱动,足够刹停但不会让车向后猛冲。
7. 编码器生效范围
- 仅在斑马线 STOP 时使用编码器
- 正常行驶时编码器处于"打开但未使用"状态(fd 保持 open,但不 read)
- 锥桶避障不使用编码器
g_cfg.start == 0时刹车状态机重置
8. 关键代码路径
main.cpp
└── while(running)
└── CameraHandler()
└── ControlUpdate(target_speed, g_zstate == Z_STOP)
└── if (zebra_block) → 刹车状态机
└── encoderLSB.readValue() ← GPIO 67