# 编码器刹车 — 设计与实现 ## 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 ```