Files
ASER/Doc/HANDOFF_v2.md
2026-04-04 23:24:36 +08:00

37 KiB
Raw Blame History

ARES 项目交接文档 v2

版本: v2.1 — 连接段三信号联合判定
基于: v2.0 + 赛道几何理解修正 + 连接段判定算法升级
更新内容: 修正地图几何理解、修复入场/连接段传感器误用 bug、升级连接段为三信号联合判定
本文目标: 完整描述当前代码库状态,让任何人能在 30 分钟内理解并继续工作


目录

  1. 一句话概述
  2. 与 v1.0 的核心差异
  3. 代码目录结构(当前)
  4. 软件架构总览
  5. 数据流水线(当前)
  6. 赛道级导航状态机详解
  7. 安全层改造详解
  8. 地图模块详解
  9. EKF 重置机制
  10. 编译开关与模式切换
  11. 全部可调参数
  12. FreeRTOS 任务一览
  13. 文件快速索引
  14. 已知问题与待办
  15. 实车调试建议

1. 一句话概述

在 v1.0 的单垄沟闭环基础上,新增了赛道级混合导航系统:用固定地图描述 S 型遍历拓扑,用 11 状态的 GlobalNav 状态机管理 6 条垄沟的完整遍历,用改造后的安全层支持"动作语义感知",最终实现从启动区入场 → 遍历全部 6 条垄沟 → 出场回停的完整比赛流程。


2. 与 v1.0 的核心差异

2.1 新增能力

能力 v1.0 v2.0
单垄沟往返
到端检测
6 条垄沟 S 型遍历
90° 转向(入/出沟)
连接段三信号联合判定
入沟重捕获确认
赛道级状态机
安全层动作语义感知
每次入沟 EKF 重置
出场与回停启动区

2.2 已解决的已知问题

编号 问题 解决方式
RISK-1 转向阶段安全层卡死 (v=0, w≠0 被前向防撞清零) 新增 SAFETY_MODE_TURN,转向时直接放行

2.3 没有动的部分

以下模块完全未修改,行为与 v1.0 一致:

  • corridor_ekf.c/.h — EKF 数学核心
  • corridor_preproc.c/.h — 传感器预处理
  • corridor_ctrl.c/.h — 沟内 PD 控制器
  • nav_script.c/.h — 保留,通过编译开关可切换回单沟测试
  • snc_can_app.c/.h — CAN 协议层(已冻结)
  • 所有传感器驱动VL53、激光、IMU
  • 黑板、里程计、指令槽

3. 代码目录结构(当前)

D:\ARES\
├── App/
│   ├── robot_params.h                ← ★ 全局参数配置(含新增 P6 赛道级参数)
│   ├── app_tasks.c/.h                ← 导航流水线(已改造,#if USE_GLOBAL_NAV 切换)
│   │
│   ├── nav/                          ← 导航与控制
│   │   ├── global_nav.c/.h           ← ★★ 新增赛道级总控11状态机
│   │   ├── track_map.c/.h            ← ★★ 新增S型遍历地图
│   │   ├── corridor_ctrl.c/.h        ← 沟内 PD 控制器(未改)
│   │   ├── segment_fsm.c/.h          ← 安全状态机已改造SafetyMode
│   │   └── nav_script.c/.h           ← 单沟测试脚本(保留,未改)
│   │
│   ├── est/
│   │   ├── corridor_filter.c/.h      ← 已改造:新增 CorridorFilter_Reset()
│   │   └── corridor_ekf.c/.h         ← EKF 核心(未改)
│   │
│   ├── preproc/
│   │   ├── corridor_msgs.h           ← 已改造:新增 SafetyMode_t 枚举
│   │   └── corridor_preproc.c/.h     ← 传感器预处理(未改)
│   │
│   ├── Contract/                     ← 数据契约(未改)
│   ├── Can/                          ← CAN 协议(已冻结,未改)
│   ├── IMU/                          ← IMU 驱动(未改)
│   ├── laser/                        ← 激光驱动(未改)
│   └── VL53L0X_API/                  ← ToF 驱动(未改)
│
├── Doc/
│   ├── HANDOFF.md                    ← v1.0 交接文档
│   ├── 混合导航方案.md                ← 方案设计文档
│   ├── 实施方案.md                    ← 详细实施文档
│   ├── HANDOFF_v2.md                 ← ★ 本文档v2.0
│   └── map.md                        ← 赛道地图
│
├── build/Debug/ARES.elf              ← 当前可用固件(编译通过)
└── CMakeLists.txt

4. 软件架构总览

┌───────────────────────────────────────────────────────────────────────────┐
│                           FreeRTOS 任务层                                  │
│   canTxTask  monitorTask  navTask  laserTestTask  vl53Task  imuTask        │
│    (20ms)     (100ms)     (20ms)    (50ms)        (100ms)   (10ms)         │
└──────────────────────────┬────────────────────────────────────────────────┘
                           │
              navTask 内每 20ms 执行一次导航流水线
                           │
┌──────────────────────────▼────────────────────────────────────────────────┐
│                    Blackboard (全局传感器数据黑板)                           │
└──────────────────────────┬────────────────────────────────────────────────┘
                           │ GetSnapshot()
┌──────────────────────────▼────────────────────────────────────────────────┐
│              CorridorPreproc  (传感器清洗 → CorridorObs_t)                  │
└──────────────────────────┬────────────────────────────────────────────────┘
                           │
┌──────────────────────────▼────────────────────────────────────────────────┐
│          CorridorFilter / EKF  (状态估计 → CorridorState_t {e_y,e_th,s})   │
└──────────────────────────┬────────────────────────────────────────────────┘
                           │
         ┌─────────────────┴──────────────────────┐
         │  USE_GLOBAL_NAV=1 (赛道模式)             │  USE_GLOBAL_NAV=0 (测试模式)
         ▼                                         ▼
┌─────────────────────┐                  ┌──────────────────────┐
│    GlobalNav        │                  │     NavScript        │
│  (赛道级状态机)      │                  │   (单沟往返脚本)      │
│  11 个阶段          │                  │   IDLE→CORRIDOR→EXIT │
│  ↕ TrackMap         │                  └──────────────────────┘
└────────┬────────────┘
         │ nav_out.safety_mode
         │ nav_out.request_corridor / use_override
         ▼
┌─────────────────────┐         ┌────────────────────┐
│   CorridorCtrl      │◄────────│ (request_corridor) │
│  (沟内 PD 控制)      │         └────────────────────┘
└────────┬────────────┘
         │ RawCmd_t
         ▼
┌─────────────────────────────────────────────────────────┐
│                   SegFsm (安全仲裁)                       │
│        感知 SafetyMode → 动作语义相关安全策略              │
│  CORRIDOR: 前向减速/停车/E-STOP 全开                      │
│  TURN:     直接放行 (允许 v=0, w≠0)                      │
│  STRAIGHT: 仅前向防撞,不检查 conf                        │
│  IDLE:     全部清零                                      │
└────────┬────────────────────────────────────────────────┘
         │ SegFsmOutput_t {safe_v, safe_w}
         ▼
    CmdSlot_Push → canTxTask → CAN 0x100 → STM32F407 底盘

5. 数据流水线(当前)

navTask 每 20ms 执行,共 7 步:

Step 1: Blackboard_GetSnapshot(&board)
          │  原子快照,无撕裂
          │
Step 2: CorridorPreproc_ExtractObs(&board, now_ms, &obs)
          │  VL53: mm→m范围校验
          │  STP+ATK: 互补融合
          │  → CorridorObs_t {d_lf/d_lr/d_rf/d_rr, d_front, d_back, valid_mask}
          │
Step 3: CorridorFilter_Update(&obs, imu_wz, odom_vx, dt, yaw_rad, yaw_ok, &state)
          │  EKF 预测 + 侧墙观测更新 + IMU 航向约束
          │  → CorridorState_t {e_y, e_th, s, conf}
          │
Step 4: GlobalNav_Update(&obs, &state, &board, &nav_out)   【赛道模式】
          │  赛道级状态机推进
          │  → GlobalNavOutput_t {stage, safety_mode, request_corridor, override_v/w}
          │
Step 5: if (nav_out.request_corridor)
          │    CorridorCtrl_Compute(&state, &obs, imu_wz, &raw_cmd)  ← 沟内 PD
          │  else
          │    raw_cmd = {override_v, override_w}                    ← 上层覆盖
          │
Step 6: SegFsm_Update(&raw_cmd, &obs, &state, nav_out.safety_mode, &fsm_out)
          │  感知 SafetyMode 的安全仲裁
          │  → SegFsmOutput_t {safe_v, safe_w}
          │
Step 7: CmdSlot_Push(fsm_out.safe_v, fsm_out.safe_w, 0)
          → canTxTask 取走 → CAN 0x100

6. 赛道级导航状态机详解

6.1 文件

文件 内容
App/nav/global_nav.h 枚举、配置结构、输出结构、API 声明
App/nav/global_nav.c 完整状态机实现596 行)

6.2 状态枚举

typedef enum {
    GNAV_IDLE = 0,             // 启动区等待
    GNAV_ENTRY_STRAIGHT,       // 入场直线
    GNAV_TURN_INTO_CORRIDOR,   // 第一次入沟转向 (90°)
    GNAV_REACQUIRE,            // 重捕获走廊
    GNAV_CORRIDOR_TRACK,       // 沟内闭环跟踪
    GNAV_TURN_OUT_OF_CORRIDOR, // 出沟转向 (90°)
    GNAV_LINK_STRAIGHT,        // 连接段直行
    GNAV_TURN_INTO_NEXT,       // 入下一条沟转向 (90°)
    GNAV_EXIT_STRAIGHT,        // 出场直行
    GNAV_DOCK,                 // 回停启动区
    GNAV_FINISHED,             // 终态
    GNAV_ERROR                 // 异常态 (超时兜底)
} GlobalNavStage_t;

6.3 完整状态转移图

                    GlobalNav_Start()
                          │
                          ▼
                      GNAV_IDLE启动区等待
                          │ 第一个 Update 周期自动
                          ▼
                  GNAV_ENTRY_STRAIGHT入场直线 ──── [里程≥0.30m 或 超时10s]
                          │                (不用VL53左侧围栏始终有效会误触发)
                          ▼
               GNAV_TURN_INTO_CORRIDOR第一次入沟转向 ── [IMU 转角 ≥ 85°]
                          │
                          ▼
                    GNAV_REACQUIRE重捕获走廊 ─────── [3+传感器有效 + 宽度匹配 + conf≥0.6 持续5拍]
                          │                [超时5s → ERROR]
                          ▼
                 GNAV_CORRIDOR_TRACK沟内闭环跟踪 ───── [d_front≤0.10m + 里程>1.0m]
                      │                   [里程>2.5m 超长保护]
                      │
           ┌──────────┘
           ▼
  GNAV_TURN_OUT_OF_CORRIDOR出沟转向 ────────────── [IMU 转角 ≥ 85°]
           │
           ├── [非最后一条沟]
           │         │
           │         ▼
           │   GNAV_LINK_STRAIGHT连接段直行 ──────── [B: 前激光变化≥0.595m]
           │         │                     [或 (A: 里程≥0.595m) AND (C: VL53沟口检测连续2拍)]
           │         │                     [超时8s → ERROR]
           │         ▼
           │  GNAV_TURN_INTO_NEXT入下一条沟转向 ──────── [IMU 转角 ≥ 85°]
           │         │
           │         └─────────────────── → GNAV_REACQUIRE (循环)
           │
           └── [最后一条沟 (C6)]
                     │
                     ▼
            GNAV_EXIT_STRAIGHT出场直行 ─────────── [侧向VL53全丢 + 冲刺≥1.5m]
                     │                     [里程>4.5m 或 超时30s → DOCK]
                     ▼
                GNAV_DOCK回停启动区 ──────────────── [里程≥0.5m 或 超时5s]
                     │
                     ▼
               GNAV_FINISHED终态 ──────────── 终态,停车

任意阶段超时 → GNAV_ERROR异常态 → 2s 后 → GNAV_FINISHED终态

6.4 各状态行为速查表

状态 v (m/s) w (rad/s) 安全模式 传感器依赖 退出条件
IDLE启动区等待 0 0 IDLE Start() 触发
ENTRY_STRAIGHT入场直线 0.08 P保直 STRAIGHT IMU航向+前激光 里程≥0.30m 或 超时
TURN_INTO_CORRIDOR第一次入沟转向 0 ±1.0 TURN IMU yaw 转角≥85°
REACQUIRE重捕获走廊 0.05 P保直 STRAIGHT VL53+EKF 双侧锁定持续5拍
CORRIDOR_TRACK沟内闭环跟踪 0.15 (PD) PD CORRIDOR VL53+IMU+前激光 d_front≤0.10m+里程>1m
TURN_OUT出沟转向 0 ±1.0 TURN IMU yaw 转角≥85°
LINK_STRAIGHT连接段直行 0.10 P保直 STRAIGHT 前激光+里程+非围栏侧VL53 三信号联合判定(见6.8)
TURN_INTO_NEXT入下一条沟转向 0 ±1.0 TURN IMU yaw 转角≥85°
EXIT_STRAIGHT出场直行 0.15 P保直 STRAIGHT IMU+里程+VL53全丢 VL53全丢+冲刺1.5m
DOCK回停启动区 0.05 0 STRAIGHT 里程计 里程到
FINISHED终态 0 0 IDLE 终态
ERROR异常态 0 0 IDLE 2s后→FINISHED

6.5 S 型遍历中的转向方向

场地结构关键理解:

  • 垄沟沿 X 轴(横向) 分布,长 220cm宽 40cm
  • 左右两端各有一条 纵向端部通道(宽 40cm长 390cm
  • 启动区在左下角,入口对齐左端通道
  • C1 在最南端离入口最近C6 在最北端
  • 机器人从启动区向北进入左端通道,入场距离仅约 10~30cm 即到 C1 入口

端部通道传感器特点:

  • 一侧贴围栏VL53 能测到(~20cm
  • 另一侧交替出现垄背端面和垄沟开口:垄背端面处能测到,垄沟开口处测不到(开口通向 220cm 远的对端,远超 VL53 的 1.2m 有效距离)
  • 因此端部通道内不能依赖 EKF,必须用 IMU 航向保持 + 前/后激光到端检测

从地图推导的 S 型转向规律(北 = Y 递减 = 地图上方):

垄沟 行驶方向 入沟转向(从纵向通道) 到端后出沟转向 连接段方向
C1 →东 右转(CW) 左转(CCW) 北行(右端通道)
C2 ←西 左转(CCW) 右转(CW) 北行(左端通道)
C3 →东 右转(CW) 左转(CCW) 北行(右端通道)
C4 ←西 左转(CCW) 右转(CW) 北行(左端通道)
C5 →东 右转(CW) 左转(CCW) 北行(右端通道)
C6 ←西 左转(CCW) 左转(CCW)→朝南 南行出场

C6 出沟左转说明: C6 向西走到左端通道,前激光测到左围栏。此时需要朝南回到入口出场,从朝西左转 90° 正好朝南。

6.6 转向执行细节

三种转向状态TURN_INTO_CORRIDOR、TURN_OUT、TURN_INTO_NEXT共用同一套 execute_turn() 逻辑:

// 已转过的角度 = (当前yaw - 起始yaw) × 方向符号(±1)
float delta = (imu_yaw - turn_start_yaw) * turn_sign;

// 减速区: 剩余角度 < 28.6° 时开始线性减速
float omega = turn_omega;  // 默认 1.0 rad/s
if (remaining_deg < decel_zone_deg) {
    omega = turn_min_omega + ratio * (turn_omega - turn_min_omega);
}
// 最低角速度 0.3 rad/s防止接近目标时停转

// 完成判定: 已转 ≥ 85° (容差 5°)
if (delta >= 90° - 5°)  转移到下一状态

6.7 重捕获判据

进入新垄沟后,GNAV_REACQUIRE 阶段低速前进,同时检查三个条件:

  1. 至少 3 个侧向传感器有效4 个 VL53 中至少 3 个返回合法距离)
  2. 几何宽度匹配:若左右两侧都有效,则 d_left + d_right + 车宽 与走廊标称宽度 40cm 的误差 ≤ 5cm
  3. EKF 置信度 ≥ 0.6

三个条件同时满足,连续 5 拍100ms才认为重捕获成功切换到 GNAV_CORRIDOR_TRACK

6.8 连接段三信号联合判定(核心新设计)

场景描述

走完垄沟后,机器人在端部纵向通道里面朝北行驶,目标是走 70cm 到达下一条垄沟的入口。这 70cm 等于一条垄沟宽40cm加一条垄背宽30cm

端部通道里的传感器情况:

            围栏侧VL53始终有效不参与判定
               │
       ┌───────┤        ┌── 垄背端面VL53有效 ~10cm
       │  车   │        │
       │       │ ─────► │  ← 非围栏侧
       │       │        │
       └───────┤        └── 垄沟开口VL53无效 / >1.2m
               │
            围栏侧
            
   前激光 ↑ 测到上围栏(距离随北行递减)
   后激光 ↓ 测到下围栏(距离随北行递增)

非围栏侧 VL53 的信号特征:

  • 经过垄背端面时:读数 ≈ (通道宽 - 车宽) / 2 - VL53内缩 = (40-20)/2 - 0 = 10cm有效
  • 进入垄沟开口时:射线穿入沟内(沟长 220cm + 对端通道 40cm ≈ 260cm超出 VL53 有效距离 1.2m → 返回无效或 0

当车身中心对准垄沟入口时,前后两颗 VL53间距 12cm都已进入开口区域沟口宽 40cm两颗均应丢失。

三个信号定义

信号 来源 触发条件 精度 权重
A 里程计 odom_distance_accum odom >= 0.70m × 0.85 = 0.595m 低(打滑)
B 前激光变化 d_front_start - d_front_now 变化量 >= 0.70m × 0.85 = 0.595m 高(绝对距离)
C VL53 沟口检测 非围栏侧前/后 VL53 读数 > 0.5m 或无效,连续 2 拍40ms 中(直接探沟口)

阈值 0.5m 的来源:正常贴垄背端面时 VL53 读数 ≈ 10cm进入沟口后 >120cm超出量程。0.5m 在两者正中间,充分区分。

0.85 容差系数:为里程计打滑和激光安装偏置留 15% 裕量。

触发逻辑

B  ||  (A && C)
  • B 单独成立 → 前激光变化量足够,直接触发(最可靠,不依赖其他)
  • A 且 C 同时成立 → 里程计粗定位 + VL53 精确探到沟口,联合校验后触发

哪一侧是"非围栏侧"

刚走完的那条沟的行驶方向决定,在 LINK_STRAIGHT 阶段 current_corridor_id 还未更新:

刚走完的沟 到达哪个通道 围栏侧 非围栏侧(检查这侧)
TRAVEL_DIR_EAST(向东) 右端通道 右侧 左侧 VL53
TRAVEL_DIR_WEST(向西) 左端通道 左侧 右侧 VL53

关键代码(global_nav.c

/* 信号 B: 前激光变化量 */
float d_front_delta = s_nav.link_d_front_start - obs->d_front;
bool laser_ok = (d_front_delta >= s_nav.cfg.link_distance * 0.85f);

/* 信号 A: 里程计 */
bool odom_ok = odom_since_entry() >= s_nav.cfg.link_distance * 0.85f;

/* 信号 C: 非围栏侧 VL53 沟口检测连续2拍*/
bool gap_now = gap_detected_on_open_side(obs, cd->travel_dir);  // cd = 当前沟
if (gap_now) s_nav.link_gap_count++;
else         s_nav.link_gap_count = 0;
bool gap_confirmed = (s_nav.link_gap_count >= 2);

/* 联合判定 */
if (laser_ok || (odom_ok && gap_confirmed))
    transition_to(GNAV_TURN_INTO_NEXT, board);

7. 安全层改造详解

7.1 改造动机

v1.0 的 segment_fsm 统一用前向距离判定安全策略,导致转向阶段被卡死RISK-1

  • 到端后 d_front 很近,SegFsm 进入 STOP 状态
  • 此时脚本输出 v=0, w≠0 期望原地转向
  • 但 STOP 状态将 safe_w 也清零 → 转不动

7.2 改造方案

新增 SafetyMode_t 枚举作为安全层的"动作语义输入"

// corridor_msgs.h
typedef enum {
    SAFETY_MODE_IDLE,       // 零速,不做任何裁剪
    SAFETY_MODE_CORRIDOR,   // 完整安全检查(前向减速/停车/E-STOP
    SAFETY_MODE_TURN,       // 转向:直接放行,不检查前距和置信度
    SAFETY_MODE_STRAIGHT    // 直行:仅前向防撞,不检查 conf
} SafetyMode_t;

7.3 各模式行为

SafetyMode 前向减速/停车 E-STOP (conf<0.1) w 保留
IDLE (全清零)
CORRIDOR APPROACH 时保留
TURN 完全放行
STRAIGHT APPROACH 时保留

7.4 函数签名变化

// v1.0 (旧)
void SegFsm_Update(const RawCmd_t *raw_cmd,
                   const CorridorObs_t *obs,
                   const CorridorState_t *state,
                   SegFsmOutput_t *out);

// v2.0 (新) — 增加 SafetyMode_t mode 参数
void SegFsm_Update(const RawCmd_t *raw_cmd,
                   const CorridorObs_t *obs,
                   const CorridorState_t *state,
                   SafetyMode_t mode,          // ← 新增
                   SegFsmOutput_t *out);

兼容性: 旧的 nav_script 调用路径(USE_GLOBAL_NAV=0 时)传入 SAFETY_MODE_CORRIDOR,行为与 v1.0 完全一致。


8. 地图模块详解

8.1 文件

文件 内容
App/nav/track_map.h 数据结构 + API 声明
App/nav/track_map.c 硬编码 S 型遍历表 + 查询实现

8.2 设计原则

地图不做全局坐标,只回答三个问题:

  1. 从第 N 条沟完成后,下一条是第几条?
  2. 这次该往哪转?(左/右)
  3. 当前是不是最后一条沟?

8.3 核心数据

// 单条垄沟描述
typedef struct {
    uint8_t           id;              // 0-5
    TravelDirection_t travel_dir;      // EAST(→) 或 WEST(←)
    TurnDirection_t   exit_turn_dir;   // 出沟转向方向
    TurnDirection_t   entry_turn_dir;  // 入沟转向方向(从纵向通道转入)
    bool              is_last;         // 是否为最后一条
} CorridorDescriptor_t;

硬编码的遍历表(track_map.c

C0(C1): →东  entry:右转  exit:左转  is_last:false
C1(C2): ←西  entry:左转  exit:右转  is_last:false
C2(C3): →东  entry:右转  exit:左转  is_last:false
C3(C4): ←西  entry:左转  exit:右转  is_last:false
C4(C5): →东  entry:右转  exit:左转  is_last:false
C5(C6): ←西  entry:左转  exit:左转  is_last:true   ← 最后一条,左转朝南出场

8.4 API

void                        TrackMap_Init(void);
const TrackMap_t*            TrackMap_Get(void);
const CorridorDescriptor_t* TrackMap_GetCorridor(uint8_t id);
uint8_t                     TrackMap_GetNextCorridorId(uint8_t current_id);
bool                        TrackMap_IsLastCorridor(uint8_t id);
TurnDirection_t             TrackMap_GetExitTurnDir(uint8_t id);
TurnDirection_t             TrackMap_GetEntryTurnDir(uint8_t id);

9. EKF 重置机制

9.1 为什么每次入沟都要重置

不同垄沟的 e_y 参考基准不同(每条沟的"居中"对应的 VL53 读数不同。如果不重置EKF 会用上一条沟的历史协方差和参考值去更新新沟的观测,导致:

  • 初始几拍置信度虚高P 矩阵太小)
  • 横向偏差 e_y 带着上条沟的偏置

9.2 实现

// corridor_filter.h — 新增接口
void CorridorFilter_Reset(void);

// corridor_filter.c — 实现
void CorridorFilter_Reset(void) {
    if (!s_initialized) return;
    CorridorEKF_Reset();        // EKF 状态归零P 恢复初始值
    s_imu_yaw_ref_rad = 0.0f;  // 解锁 yaw_ref
    s_imu_yaw_ref_set = false; // 等待在新沟中重新锁定
}

9.3 调用时机

GlobalNavtransition_to(GNAV_REACQUIRE, ...) 时调用,即每次转向完成后、开始寻找新走廊之前。


10. 编译开关与模式切换

10.1 控制宏

// App/robot_params.h
#define USE_GLOBAL_NAV   0    // 1=赛道模式  0=单沟测试模式 (当前为单沟测试)

10.2 两种模式的差异

USE_GLOBAL_NAV=1 USE_GLOBAL_NAV=0
导航模块 GlobalNav NavScript
启动调用 GlobalNav_Start() NavScript_Start()
遍历范围 6 条垄沟 S 型 单垄沟往返
安全模式 按阶段动态切换 固定 SAFETY_MODE_CORRIDOR
适用场景 正式比赛 单条走廊调试

10.3 切换方法

仅修改 robot_params.h 中的宏,重新编译烧录即可。所有逻辑通过 #if USE_GLOBAL_NAVapp_tasks.c 中编译时切换,不增加运行时开销。


11. 全部可调参数

P0 — 几何参数(实测填写)

参数 当前值 说明
PARAM_ROBOT_WIDTH 0.200 m 车体宽度
PARAM_ROBOT_LENGTH 0.200 m 车体长度
PARAM_WHEEL_DIAMETER 0.080 m 驱动轮直径
PARAM_WHEEL_TRACK 0.140 m 左右轮中心距
PARAM_SENSOR_BASE_LENGTH 0.120 m 同侧前后 VL53 间距
PARAM_CORRIDOR_WIDTH 0.40 m 走廊宽度
PARAM_FRONT_LASER_OFFSET 0.0 m 前激光到车头偏置
PARAM_REAR_LASER_OFFSET 0.0 m 后激光到车尾偏置
PARAM_VL53_SIDE_INSET 0.0 m 侧向 VL53 统一内缩距离 (兼容)
PARAM_VL53_LEFT_INSET 0.0 m 左侧 VL53 内缩距离 (实测后填入!)
PARAM_VL53_RIGHT_INSET 0.0 m 右侧 VL53 内缩距离 (实测后填入!)
PARAM_ENCODER_CPR 500 编码器每转脉冲数

P2 — EKF 滤波器(调优)

参数 当前值 说明
PARAM_EKF_Q_EY 0.01 横向过程噪声
PARAM_EKF_Q_ETH 0.001 航向过程噪声
PARAM_EKF_Q_S 0.1 里程过程噪声
PARAM_EKF_R_EY 0.015 横向观测噪声 (VL53 可信度低,已调大)
PARAM_EKF_R_ETH 0.001 航向观测噪声(侧墙,已取消使用)
PARAM_EKF_R_ETH_IMU 0.002 航向观测噪声IMU已调小以充分利用高精度 IMU
PARAM_EKF_P0_EY 0.1 e_y 初始不确定度
PARAM_EKF_P0_ETH 0.1 e_th 初始不确定度

P3 — 沟内控制器(调优)

参数 当前值 说明
PARAM_CTRL_KP_THETA 2.0 航向比例增益
PARAM_CTRL_KD_THETA 0.4 航向微分增益
PARAM_CTRL_KP_Y 4.0 横向比例增益
PARAM_CTRL_V_CRUISE 0.15 m/s 巡航速度
PARAM_CTRL_W_MAX 1.5 rad/s 最大角速度
PARAM_CTRL_V_MAX 0.3 m/s 最大线速度
PARAM_CTRL_SPEED_REDUCTION 0.4 弯道减速系数

P4 — 安全阈值(调优)

参数 当前值 说明
PARAM_SAFE_D_FRONT_STOP 0.10 m 前向停车距离
PARAM_SAFE_D_FRONT_APPROACH 0.25 m 前向减速预警距离
PARAM_SAFE_APPROACH_MIN_V 0.05 m/s 减速区最低速度
PARAM_SAFE_CONF_ESTOP 0.10 E-Stop 置信度阈值CORRIDOR模式

P6 — 赛道级导航参数新增v2.0

参数 当前值 说明
USE_GLOBAL_NAV 0 编译开关 (当前为单沟测试模式)
入场段
PARAM_GNAV_ENTRY_V 0.08 m/s 入场速度
PARAM_GNAV_ENTRY_DISTANCE 0.30 m 入场里程上限 (启动区到C1入口仅约10~30cm)
PARAM_GNAV_ENTRY_TIMEOUT 10000 ms 入场超时
转向
PARAM_GNAV_TURN_OMEGA 1.0 rad/s 转向角速度
PARAM_GNAV_TURN_TOLERANCE 0.087 rad (~5°) 转向完成容差
PARAM_GNAV_TURN_DECEL_ZONE 0.5 rad (~28°) 减速区起始角度
PARAM_GNAV_TURN_MIN_OMEGA 0.3 rad/s 减速区最低角速度
PARAM_GNAV_TURN_TIMEOUT 8000 ms 单次转向超时
重捕获
PARAM_GNAV_REACQUIRE_V 0.05 m/s 重捕获速度
PARAM_GNAV_REACQUIRE_CONF 0.6 置信度阈值
PARAM_GNAV_REACQUIRE_WIDTH_TOL 0.05 m 走廊宽度容差
PARAM_GNAV_REACQUIRE_TICKS 5 拍 连续确认次数
PARAM_GNAV_REACQUIRE_TIMEOUT 5000 ms 重捕获超时
沟内
PARAM_GNAV_CORRIDOR_END_DIST 0.10 m 到端检测距离
PARAM_GNAV_CORRIDOR_MAX_LEN 2.50 m 沟内里程保护上限
连接段
PARAM_GNAV_LINK_V 0.10 m/s 连接段速度
PARAM_GNAV_LINK_DISTANCE 0.70 m 连接段标称距离
PARAM_GNAV_LINK_TIMEOUT 8000 ms 连接段超时
出场
PARAM_GNAV_EXIT_V 0.15 m/s 出场速度
PARAM_GNAV_EXIT_RUNOUT 1.50 m 侧向丢失后冲刺距离
PARAM_GNAV_EXIT_MAX_DIST 4.50 m 出场里程保护 (纵向通道全长约3.9m)
PARAM_GNAV_EXIT_TIMEOUT 30000 ms 出场超时 (纵向通道距离长,给足时间)
回停
PARAM_GNAV_DOCK_V 0.05 m/s 回停速度
PARAM_GNAV_DOCK_DISTANCE 0.50 m 回停距离
其他
PARAM_GNAV_HEADING_KP 0.03 航向保持 P 增益°→rad/s

12. FreeRTOS 任务一览

与 v1.0 完全一致,无新增任务:

任务名 周期 优先级 职责
canTxTask 20ms AboveNormal CAN 0x100 发送100ms 看门狗
navTask 20ms AboveNormal 完整导航流水线(含新 GlobalNav
LaserTsk(内部) 10ms AboveNormal 4 路 UART DMA 激光解析
monitorTask 100ms Normal CAN 健康;里程计积分
laserTestTask 50ms Normal 激光推送黑板
vl53Task 100ms Normal VL53L0X 读取推送黑板
imuTask 10ms BelowNormal IMU 解析推送黑板
defaultTask Normal USB CDC 初始化;空闲循环

13. 文件快速索引

你想做什么 去看哪个文件
改调参数值 App/robot_params.h
切换赛道/单沟模式 App/robot_params.hUSE_GLOBAL_NAV
看赛道状态机逻辑 App/nav/global_nav.c
看 S 型遍历拓扑表 App/nav/track_map.c
看安全模式定义 App/preproc/corridor_msgs.hSafetyMode_t
看安全层实现 App/nav/segment_fsm.c
看沟内控制律 App/nav/corridor_ctrl.c
看 EKF 数学 App/est/corridor_ekf.c
看 EKF 重置 App/est/corridor_filter.cCorridorFilter_Reset()
看导航流水线入口 App/app_tasks.cAppTasks_RunNavTask_Impl()
看系统初始化 App/app_tasks.cAppTasks_Init()
看 CAN 协议 App/Can/snc_can_app.c
看全局数据结构 App/Contract/robot_blackboard.h
看传感器预处理 App/preproc/corridor_preproc.c
看赛道地图 Doc/map.md
看单沟测试脚本 App/nav/nav_script.c

14. 已知问题与待办

已在 v2.0 解决

# 问题 解决方式
RISK-1 转向阶段被安全层卡死 SAFETY_MODE_TURN 直接放行
缺少 6 沟遍历能力 global_nav.c 完整实现
缺少 EKF 入沟重置 CorridorFilter_Reset()

v1.0 遗留的已解决 BUG已全部修复

BUG-1 至 BUG-9 均在 v1.0 已修复v2.0 继承已修复状态。详见 HANDOFF.md

当前待办

# 问题 优先级 说明
CAL-1 PARAM_FRONT_LASER_OFFSET = 0.0 实测填写,影响到端检测精度
CAL-2 PARAM_REAR_LASER_OFFSET = 0.0 同上
CAL-3 PARAM_VL53_SIDE_INSET = 0.0 单侧退化时影响 EKF 精度
CAL-4 PARAM_IMU_YAW_OFFSET = 0.0 声明了但代码未使用
TODO-1 GlobalNav 里程计时间源 当前用 imu_wz.timestamp_ms 估算时间,可改为 HAL_GetTick() 从外部传入,更准确
TODO-2 连接段过短/过长自适应 当前固定 0.70m,实际可能因转向角度偏差需要微调
TODO-3 重捕获单侧有效策略 若入沟角度大导致某侧 VL53 暂时无效,当前判定较严格

设计风险(已知,待注意)

# 风险 影响 说明
RISK-2 连接段偏航 IMU 短时漂移 + 轮滑可能导致连接段走歪,靠里程计上限保护
RISK-3 转向精度 IMU 积分漂移90°实际转角可能有 2-5° 误差,重捕获阶段兜底
RISK-4 入场阶段判据 "侧向 VL53 有效"作为进入第一条沟的触发,若传感器偶发有效可能提前转向

15. 实车调试建议

建议调试顺序

第1步: 几何参数实测 (P0)
  → 卷尺量 PARAM_FRONT/REAR_LASER_OFFSET、PARAM_VL53_SIDE_INSET

第2步: USE_GLOBAL_NAV=0单沟测试
  → 验证走廊跟踪、到端检测、180°转向nav_script 旧路径)

第3步: 切换 USE_GLOBAL_NAV=1测试单次 90° 转向
  → 手动把机器人放在沟内,触发 TURN_OUT看 IMU 转角是否准确

第4步: 测试重捕获
  → 手动转向后进入 REACQUIRE看 5 拍锁定时间,调 CONF 阈值

第5步: 测试双沟 S 型 (C1 → C2)
  → 验证连接段长度、入沟对准

第6步: 全 6 沟测试
  → 观察每条沟的入沟质量、完成率

第7步: 调优参数
  → TURN_OMEGA, LINK_DISTANCE, REACQUIRE_TICKS 等

常见问题诊断(新增 v2.0 相关)

现象 可能原因 处置方法
转向后没进下一阶段 IMU 转角计算偏差 检查 imu_yaw_continuous 是否正常更新;调小 TURN_TOLERANCE
重捕获超时5s 入沟角度偏大VL53 看不到两侧 增大 REACQUIRE_TIMEOUT;或降低 REACQUIRE_TICKS
连接段走过头 里程计打滑 适当减小 LINK_DISTANCE;靠 VL53 探壁辅助触发
连接段走不够 里程计未积分odom=0 检查 monitorTask 里程计链路
安全层卡住转向 SAFETY_MODE_TURN 未传入 检查 GlobalNav_Update()nav_out.safety_mode 输出
出场后未停车 VL53 未丢失触发 调小 EXIT_RUNOUT;检查 all_side_lost() 判定
每次入沟偏向一侧 PARAM_VL53_SIDE_INSET 未校准 实测传感器内缩距离并填入

给接手者的提醒:

  1. 调参前先确认 USE_GLOBAL_NAV 的模式,不同模式下调的参数组不同
  2. v2.0 新增的 P6 参数全部有默认值,实车前必须根据实际场地微调 LINK_DISTANCEENTRY_DISTANCE
  3. CorridorFilter_Reset() 在每次入沟时自动调用,不需要手动干预
  4. 如果出现整体行为异常,先把 USE_GLOBAL_NAV=0 切回单沟模式定位问题
  5. CAN 协议层 (snc_can_app.c) 已冻结,不要修改