Files
ASER/Doc/GLOBAL_NAV_REQUIREMENT.md
2026-04-03 07:57:57 +08:00

668 lines
21 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 固定场地条件下的赛道级导航需求说明
## 1. 问题背景
当前项目已经具备较完整的“单条垄沟内局部导航”能力,包括:
- 侧向测距支撑的走廊横向定位
- IMU / EKF 支撑的航向估计
- 前向距离触发的到端检测
- 原地转向
- 走廊内闭环控制
但正式比赛要求并不是“在一条走廊里走稳”这么简单,而是:
- 遍历全部 `6` 条垄沟
- 在端部完成换沟
- 最终从唯一出入口驶离场地
- 再停回启动区
因此,真正的问题已经从“局部走廊控制”升级成了“赛道级导航”。
本文件针对一个新的核心顾虑做说明:
- 左右 `VL53L0X` 是近场侧向传感器,实际有效距离有限
- 当小车走完第一条通道、完成转向、准备去第二条通道口时,下一条通道口可能仍在数米之外
- 此时无法指望左右侧向 VL53 直接识别远处的下一条通道入口
由此引出新的设计问题:
- 是否需要把当前导航从“局部走廊式”升级为“固定地图下的全局式导航”
本文件只做需求分析与方案建议,不修改现有代码。
## 2. 比赛场地与问题是否成立
根据比赛规则文件 `附件6B类“马铃薯捡拾机器人竞技”比赛及评审规则.md`
- 场地尺寸:`390cm x 300cm`
- 共有 `5` 条田垄
- 每条田垄:长 `220cm`、宽 `30cm`
- 围栏与田垄之间、相邻田垄之间均为 `40cm` 垄沟
- 实际需要遍历的是 `6` 条垄沟
- 场地尺寸允许误差:`+-5%`
结合 `HANDOFF.md` 的赛道理解:
- 当前赛道本质上是 `6` 段平行窄走廊
- 其间通过端部动作完成换沟
- 最终还要完成出场和停回启动区
因此,你的顾虑是成立的:
- 左右侧向 VL53 的作用域主要是在“贴着垄沟/墙体附近”时建立局部几何约束
- 一旦小车离开当前垄沟、进入端部开阔区或横向换沟区,下一条垄沟入口往往不在 VL53 的可靠观测范围内
- 所以不能把“下一条通道入口识别”这个任务建立在左右 VL53 的远距离探测能力上
这里需要特别澄清一个容易说错的点:
- 赛道级运动并不一定是“在端部开阔区横移很长一段,再去远距离搜索下一条垄沟入口”
- 更符合当前场地理解的运动方式,是一种 **S 型串行入沟**
1. 从出发区直行到第 1 条垄沟入口附近
2. 第 1 条垄沟在车体一侧(例如右侧)
3. 原地右转 `90°` 对准垄沟后入沟
4. 沿垄沟通过
5. 到端后原地左转 `90°`,进入端部直线连接段
6. 再前进一小段到下一条垄沟入口附近
7. 再原地左转 `90°` 入下一条垄沟
8. 之后重复形成 S 型遍历
也就是说:
- 下一条垄沟并不是完全未知目标
- 它通常位于“端部连接直线段之后的固定相邻位置”
- 问题核心不是远距离搜索,而是 **按固定几何完成 90° 转向 + 短直线推进 + 再次 90° 入沟**
换句话说:
- `VL53` 适合做局部跟墙/居中
- 不适合独立承担赛道级换沟导航
## 3. 当前项目的能力边界
`HANDOFF.md` 已经明确指出:
- 当前项目更像“单垄沟闭环验证系统”
- 还不是完整的 `6` 垄沟遍历赛道导航系统
当前已经具备的能力主要是:
1. 垄沟内定位与控制
2. 到端检测
3. 原地转向
4. 安全停车
当前还缺失的关键能力是:
1. 多垄沟拓扑状态管理
2. 端部换沟策略
3. 下一目标垄沟的判定逻辑
4. 出场与停回启动区的赛道级动作编排
所以,这不是某一个传感器量程的小补丁问题,而是系统层次已经需要从“局部控制”提升到“地图引导下的赛道导航”。
## 4. 为什么仅靠局部传感器闭环不够
### 4.1 局部闭环擅长的任务
局部闭环擅长的是:
-`40cm` 垄沟里保持居中
- 在局部几何约束下控制横向误差和航向误差
- 在接近端部时停车或转向
这些任务的共同特征是:
- 机器人周围可观测到明确的近场结构
- 当前目标由附近环境直接决定
### 4.2 换沟问题的本质不同
从第一条垄沟换到第二条垄沟,不只是“继续沿墙走”,而是要回答以下更高层的问题:
1. 我当前已经完成了第几条垄沟
2. 下一条目标垄沟是哪一条
3. 这次应该左移还是右移
4. 端部 `90°` 转向后需要前进多少连接距离
5. 下一次 `90°` 转向应朝哪一侧入沟
6. 什么时候说明我已经对准并进入了下一条垄沟,可以重新切回局部走廊跟踪模式
这些问题都不是单次近场测距能直接回答的。
它们需要:
- 赛道拓扑信息
- 段落状态
- 距离累计
- 转向后姿态保持
- 已完成进度记忆
所以,换沟本质上是“任务级导航问题”,不是“单纯传感器观测问题”。
## 5. 是否需要全局导航
### 5.1 需要,但不一定是 SLAM 式全局导航
你提出“地图是固定的,是否要改成全局式导航”,我的判断是:
- 需要“全局导航思想”
- 但不需要上“通用移动机器人 SLAM”那种全局导航系统
原因是这个比赛场地有几个重要特征:
1. 地图是固定结构
- 场地拓扑不变
- 垄沟数量固定
- 宽度和相对排列固定
2. 尺寸有误差但不是完全未知
- 规则允许 `+-5%`
- 说明不能死信纯几何标称值
- 但也不代表你需要从零建图
3. 导航目标是离散段落式的
- 进入第 1 条垄沟
- 沿垄沟前进
- 到端
- 换到相邻垄沟
- 重复
- 最后出场并停回启动区
这类问题更适合:
- 固定地图
- 拓扑状态机
- 局部感知闭环
- 少量里程/姿态积分
而不是:
- 实时全局建图
- 通用路径规划
- 自由空间导航
### 5.2 更准确的说法:需要“赛道级固定地图导航”
如果用更工程化的语言描述,真正需要的不是传统 SLAM而是
- 固定地图下的赛道级导航
- 或者:拓扑-度量混合导航
它的含义是:
1. 上层知道整张赛道的结构
2. 下层在当前局部段里做高频闭环
3. 段与段之间的切换靠预定义几何、里程推进和事件触发完成
这比“纯局部反应式导航”强很多,但比“完整 SLAM”简单得多也更符合比赛实际。
## 6. 为什么不建议直接走完整 SLAM / 全局自由导航
### 6.1 赛场结构太规则SLAM 的收益不高
比赛场地不是开放未知环境,而是高度规则的固定赛道。
如果直接上完整 SLAM会遇到两个问题
1. 复杂度远大于实际收益
2. 还要处理对称结构导致的重定位歧义
因为 `6` 条垄沟本身非常相似:
- 走廊宽度相同
- 垄长相同
- 多个局部观测在不同位置上可能长得很像
这对通用 SLAM 来说并不天然友好。
### 6.2 规则里存在地毯与尺寸误差,纯度量导航也不能硬信
比赛规则明确说明:
- 随机会在 `2` 条垄沟铺设地毯模拟松软路面
- 场地尺寸允许 `+-5%` 误差
这意味着:
- 纯里程计距离不能被绝对相信
- 纯固定距离脚本也不能完全相信
所以最合理的方案不是“只靠地图”,而是:
- 地图负责告诉你要去哪一段
- 传感器负责告诉你你是否已经贴近那一段并进入局部闭环条件
## 7. 推荐的导航架构
我建议把系统分成三层。
### 7.1 第 1 层:局部走廊控制层
职责:
- 在垄沟内保持稳定行驶
- 利用侧向 VL53 和 IMU 控制 `e_y``e_th`
- 处理贴墙、居中、偏置行走等局部任务
这层继续使用你现在已经有的能力即可。
### 7.2 第 2 层:端部与换沟动作层
职责:
- 识别到端
- 完成 `90°` 转向
- 保持连接段朝向直线推进
- 在下一条垄沟入口处再执行一次 `90°` 转向入沟
- 在接近下一条垄沟入口时重新捕获局部走廊结构
这一层的主要依赖不应再是“直接看到很远处的下一条通道口”,而应是:
- IMU 航向保持
- 编码器里程推进
- 前向/后向长距测距作安全与事件辅助
- 重新捕获两侧结构时切回走廊模式
### 7.3 第 3 层:赛道级拓扑/地图层
职责:
- 记录当前是第几条垄沟
- 决定下一条目标垄沟编号
- 决定换沟方向
- 决定当前所处阶段:入场、走廊、端部、换沟、再入沟、退出、回停
- 在最终阶段规划如何从最后一条垄沟回到唯一出口并停回启动区
这层就是“全局导航思想”的承载层。
## 8. 具体到你的顾虑:第二通道口怎么判定
这个问题不应该被设计成:
- “我在端部一转身,然后用 VL53 去远距离搜索第二通道口在哪里”
更合理的设计应该是:
### 8.1 已知目标法
系统在上层已经知道:
- 当前完成的是第 `i` 条垄沟
- 下一个目标是第 `i+1` 条或第 `i-1` 条垄沟
也就是说,目标不是“搜索未知入口”,而是“按已知地图去下一个入口”。
### 8.2 动作脚本法
在端部动作中执行一段有结构的换沟脚本,例如:
1. 到端停车
2. 原地转 `90°` 到端部连接段朝向
3. 用 IMU 保持该朝向直行一小段
4. 用里程计累计连接段推进距离
5. 到达下一条垄沟入口附近后再原地转 `90°`
6. 一旦两侧 VL53 重新形成新垄沟的局部几何特征,则确认入沟成功
7. 切回局部走廊跟踪
如果按你描述的实际拓扑,更准确的理解是:
- 换沟动作不是“横向平移到另一条沟”
- 而是“端部出沟后走一段连接直线,再 90° 入下一沟”
- 整体轨迹更接近规则的 S 型遍历
### 8.3 重新捕获法
下一条垄沟入口的确认,最可靠的时刻往往不是“远处看见”,而是“进入附近后重新捕获到局部走廊结构”。
也就是说:
- 上层负责把车带到“应该接近下一条垄沟入口”的区域
- 下层负责在近场把入口真正锁住
这比远距离直接识别入口更稳。
## 9. 哪些传感器在赛道级导航里应该扮演什么角色
### 9.1 左右 VL53L0X
适合:
- 垄沟内横向定位
- 局部几何重捕获
- 判断自己是否已经重新进入某条垄沟
不适合:
- 远距离寻找下一条通道口
- 独立承担赛道级换沟导航
### 9.2 IMU
适合:
- 转向控制
- 端部横移/换沟时的航向保持
- 跨局部无墙约束阶段的短时姿态维持
### 9.3 编码器 / 里程计
适合:
- 换沟距离推进
- 已走段长估计
- 作为脚本动作的度量输入
缺点:
- 地毯和打滑会导致累计误差
所以它应作为:
- 主推进量
- 但不是唯一最终确认依据
### 9.4 前后长距测距
当前硬件里前后测距量程远大于 VL53理论上更适合
- 到端检测
- 判断前方是否接近围栏
- 在开阔区提供安全保护
- 对某些段落提供事件辅助
它不一定直接告诉你“第二通道口在这”,但可以帮助判断:
- 是否还在端部开阔区
- 是否已经逼近另一侧围栏或终点边界
- 是否应减速/停止/切换动作阶段
## 10. 推荐的总体方案
### 10.1 推荐方向:固定地图 + 拓扑状态机 + 局部闭环
这是我最推荐的方向。
其核心思想是:
- 地图不是在线建出来的,而是事先已知
- 机器人不需要理解“任意世界坐标”
- 机器人只需要知道自己当前位于哪个赛道段、下一步要切到哪个段
可以把整张赛道抽象成若干固定段:
1. 启动区
2. 入口对准段
3. 垄沟 1
4. 端部连接段 1
5. 垄沟 2
6. 端部连接段 2
7. ...
8. 垄沟 6
9. 出场段
10. 启动区停车段
如果按运动学动作再细分,每一个“端部连接段”内部实际上可以拆成:
1. 到端停车
2. 第一次 `90°` 转向
3. 连接直线推进
4. 第二次 `90°` 转向
5. 入沟重捕获
每个段有自己的:
- 目标朝向
- 目标推进方向
- 退出条件
- 允许使用的观测
- 安全策略
### 10.2 这不是“纯全局”,而是“全局指导下的局部控制”
这种方案的优势在于:
- 不会把所有问题都压给近场传感器
- 不会过度依赖里程计的绝对精度
- 保留你当前局部走廊控制代码的大部分价值
- 更贴合固定场地赛事的工程实际
## 11. 不推荐的方案
### 11.1 不推荐:继续纯局部反应式地扩当前逻辑
如果只是继续把当前“单垄沟往返”逻辑往外补,仍然不引入上层赛道状态,那么很容易遇到:
- 转完向不知道该去第几条沟
- 明明应该换沟,却又回到原来那条沟附近
- 因地毯或打滑导致脚本距离错位
- 无法稳定完成最终出场与回停
### 11.2 不推荐:直接上完整 SLAM / 通用全局路径规划
这对当前赛题来说过重,收益不一定匹配复杂度。
## 12. 对当前项目的直接结论
结合当前代码与比赛规则,可以得出以下结论:
1. 你的顾虑成立
- 左右 VL53 无法独立解决“数米外下一条垄沟入口识别”问题
2. 当前项目确实缺少赛道级导航层
- 当前更偏向单垄沟局部验证系统
3. 后续必须补上固定地图下的全局段落管理
- 否则无法可靠完成正式比赛要求的 `6` 垄沟遍历
4. 但不建议走完整 SLAM 路线
- 更合适的是固定地图 + 拓扑状态机 + 局部感知闭环
## 13. 后续实施建议
如果后续开始真正改造导航系统,建议优先级如下:
1. 先定义完整赛道拓扑和段落状态机
2. 明确每一段的进入条件、退出条件、目标朝向和目标距离
3. 让局部走廊控制只负责“在某条已知垄沟里跑稳”
4. 让换沟段由 IMU + 里程计 + 长距测距辅助来完成
5. 用左右 VL53 做“重新捕获下一条垄沟”确认,而不是远距离搜寻入口
6. 最后再考虑是否需要引入更强的全局定位增强手段
### 13.1 建议分 5 步走
结合当前项目现状,建议不要一口气重写整套导航,而是按“先把单段动作语义补完整,再把赛道级层叠上去”的顺序推进。
推荐拆成 `5` 步。
### 第 1 步:先把现有局部导航链路补到“可复用”
这一步不是做全局导航,而是先把现有单垄沟能力整理成后续可调用的稳定基础模块。
优先要补或改的模块:
1. `App/nav/segment_fsm.c/.h`
- 增加“动作语义”或“模式感知”输入
- 区分:走廊前进、原地转向、横向换沟、退出直线
- 解决当前 `TURN_AT_END` 可能被安全层整段按死的问题
2. `App/nav/nav_script.c/.h`
- 不再把它视为最终比赛脚本
- 先把它收敛成“单段动作编排器”或“局部验证脚本”
- 明确哪些能力未来会上移到赛道级状态机
3. `App/preproc/corridor_msgs.h`
- 补充动作模式、段类型、重捕获结果等跨模块消息定义
- 避免后面继续把语义塞进零散布尔量里
4. `App/app_tasks.c`
- 补齐导航启动前的 ready 判定
- 明确 navTask 每周期里:局部控制输出、赛道级输出、安全层输出的优先级
这一阶段的目标不是“遍历 6 条垄沟”,而是:
- 让“走廊跟踪 / 到端 / 原地转向 / 安全仲裁”这几个局部动作变成可被上层稳定调用的基础能力
### 第 2 步:新增赛道级拓扑状态机模块
这一步开始真正引入“全局导航思想”,但仍然基于固定地图,不做 SLAM。
建议新增模块:
1. `App/nav/global_nav_fsm.c/.h`
- 负责赛道级阶段推进
- 记录当前是第几条垄沟
- 决定下一条目标垄沟编号
- 决定下一次是左转入沟还是右转入沟
- 决定当前处于:启动、入沟、走沟、到端、换沟、再入沟、出场、回停 的哪一阶段
2. `App/nav/track_map.c/.h`
- 保存固定赛道的拓扑和名义几何
- 例如:垄沟数量、编号顺序、相邻关系、换沟方向、出口所在侧、启动区相对位置
- 不追求通用地图系统,只做当前赛题所需的固定地图描述
3. `App/preproc/corridor_msgs.h`
- 增加赛道级状态输出结构
- 例如:当前 corridor_id、target_corridor_id、segment_type、progress_state
为什么这一步要单独拆出来:
- 当前项目最大缺口不是局部控制,而是“不知道自己在整张赛道里进行到哪一步”
- 这个职责不能继续堆在 `nav_script.c` 里,否则会越改越像一份超长 if-else 脚本
### 第 3 步:新增换沟动作层模块
这一层负责跨出当前垄沟、去相邻垄沟入口附近、再把局部控制权交还给走廊跟踪层。
建议新增模块:
1. `App/nav/lane_change_executor.c/.h`
- 输入:当前赛道级目标、目标换沟方向、目标段参数
- 输出:本周期期望动作 `v/w`
- 内部实现典型动作序列:
- 到端停车
- 第一次 `90°` 转向到连接段朝向
- 维持航向直线推进
- 按里程推进到预计下一沟入口区域
- 第二次 `90°` 转向入沟
- 减速搜索并等待局部结构重捕获
2. `App/nav/heading_hold.c/.h` 或并入 `lane_change_executor`
- 用 IMU 做连接直线阶段短时航向保持
- 与走廊控制器解耦,避免把“无侧墙阶段”继续硬塞进 `corridor_ctrl.c`
3. `App/nav/reacquire_detector.c/.h`
- 负责判断是否已重新进入一条有效垄沟
- 典型判据:左右 VL53 重新同时形成合理几何、置信度恢复、持续若干拍成立
这一阶段的核心目标是:
- 不依赖“远距离看到下一条垄沟入口”
- 而是“按固定地图推进到预计区域,再由局部传感器完成重捕获确认”
### 第 4 步:补出场与回停模块
前 3 步完成后,系统已经具备:
- 走一条垄沟
- 到端
- 换到相邻垄沟
但正式比赛还需要最后的:
- 从最后一条垄沟驶离
- 回到唯一出口
- 停回启动区
建议新增模块:
1. `App/nav/exit_planner.c/.h`
- 定义从最后有效垄沟切到出场段的固定动作逻辑
- 决定离场时的目标朝向、推进距离、退出条件
2. `App/nav/start_zone_dock.c/.h`
- 负责最终回停启动区
- 可以做成简化版固定脚本,不需要复杂路径规划
这一阶段不要追求炫技,重点是:
- 流程完整
- 可解释
- 可调参
- 能在赛场误差下稳定完成收尾动作
### 第 5 步:最后再做统一调参与验证支撑
当前项目已经有局部参数,但赛道级导航落地后,还需要把“段参数”和“地图参数”系统化管理。
建议补的模块或整理项:
1. `App/robot_params.h`
- 补充赛道级参数
- 例如:换沟名义距离、减速搜索距离、重捕获持续拍数、回停距离等
2. `App/nav/global_nav_debug.c/.h` 或临时调试结构
- 给 CubeMonitor / 日志暴露关键内部量
- 例如:当前 corridor_id、stage、target_heading、reacquire_flag、lane_change_progress
3. `HANDOFF.md` / `GLOBAL_NAV_REQUIREMENT.md`
- 随代码同步更新
- 保证后续调试时文档和实现一致
这一阶段的目标是:
- 把“能跑”变成“能调、能解释、能复现”
### 13.2 各步的交付标准
为了避免后续开发一直停留在“看起来写了很多模块”,建议每一步都设一个明确交付标准。
第 1 步交付标准:
- 原地转向不再被安全层错误清零
- 走廊前进 / 原地转向 / 退出直行三类动作有清晰安全语义
- 局部导航链路在架空测试中行为稳定可解释
第 2 步交付标准:
- 系统能够明确输出“当前第几条垄沟、下一条目标是哪条、当前赛道阶段是什么”
- 不再依赖单个脚本文件隐式记录全局进度
第 3 步交付标准:
- 能从一条垄沟末端稳定切换到相邻垄沟入口附近
- 能通过 VL53 重捕获确认重新入沟
第 4 步交付标准:
- 能在完成全部目标垄沟后可靠离场
- 能完成最终回停启动区
第 5 步交付标准:
- 参数、日志、状态可观测性完整
- 可以支持正式场地反复调参与问题定位
### 13.3 为什么是这个顺序
这个顺序的核心原则是:
1. 先补“动作语义一致性”,再补“赛道级状态记忆”
2. 先解决端部动作可用性,再扩展多垄沟遍历
3. 先做固定地图和拓扑状态机,再考虑任何更重的全局定位增强
如果顺序反过来,例如一开始就写完整 6 垄沟状态机,但底层转向和换沟动作还不稳定,那么上层状态再完整也只会变成“会卡在某一步的复杂脚本”。
因此,最合理的开发路径不是“先把全局状态机写满”,而是:
- 第 1 步:把局部动作做成稳固积木
- 第 2 步:加赛道级任务管理
- 第 3 步:补跨段动作
- 第 4 步:补最终出场与回停
- 第 5 步:统一调参与调试支撑
## 14. 一句话结论
你的问题本质上说明:当前系统已经不能只靠“局部走廊导航”来思考了。
真正需要补的是“固定地图下的赛道级导航层”,而不是盲目把 VL53 当成远距离入口探测器,也不是直接上复杂 SLAM。