EXP-03 · 8 学时(2 理论 + 6 实践)

车道保持与路口信号通行

让小车"像人一样开车":视觉巡线用 PID 把车道中心线偏差压进 ±2cm 发 /cmd_vel,路口停止线前按 /traffic/light 红灯停绿灯行,斑马线检测到行人模型必让,IDLE/CROSSING/WAITING 三级优先级状态机统管决策——验收标准:直道偏差 ≤2cm、红灯 10/10 次停稳、斑马线礼让 10/10 次触发。

理论2+实践6PID 巡线停止线检测斑马线礼让优先级状态机

01本节目标

  • 讲清巡线控制闭环:视觉算偏差 e(t) → PID 出角速度 → /cmd_vel → 底盘执行 → 相机再观测,理解"反馈环画成圈"。
  • 完成车道中心线检测节点(ROI 内高对比识别线质心提取),并用 PID 把直道偏差收敛到 ±2cm。
  • 完成停止线检测:路口前 20cm 触发减速,结合 EXP-02 的 /traffic/light 实现红灯停、绿灯行、黄灯按距决策。
  • 完成斑马线礼让:检测到行人模型(EXP-02 标志/颜色通道复用)30cm 内必停,行人离开 2s 后恢复。
  • 实现 IDLE / CROSSING / WAITING 优先级状态机,讲清优先级排序:行人 > 红灯 > 巡线。
  • 牢记:低速起步、提前减速——巡线速度超过 0.25m/s,40cm 窄道必出轨。
素材说明:本实验无实拍素材,示意图与交互动画为准(沿用 EXP-01/02 的沙盘规格假设,以现场沙盘实际元素为准)。

02核心原理:偏差进、角速度出——PID 与优先级状态机的双人舞

把小车想像成蒙眼走钢丝的人(只不过"眼"是下视 ROI):它看不见整个世界,只盯着脚下一小段车道线。相机在图像下方取一条 ROI 横带,对高对比识别线做质心提取——车道中心在画面 x = W/2 时偏差 e=0;偏左 e<0、偏右 e>0。接下来是老朋友 PID:P 项按偏差成比例打方向(纠得急),I 项积分消除"轮子左右不对称"造成的恒定跑偏,D 项对偏差变化率提前刹车、抑制过冲震荡。三者相乘相加,得到角速度 ω,连同限速后的线速度 v 一起塞进 /cmd_vel——差速/麦克纳姆轮据此两侧差速,车头回正,完成一圈闭环。

光会沿线还不够,路口要"懂规矩"。优先级状态机把三种约束排出座次:行人 > 红灯 > 巡线。IDLE(默认巡线)、WAITING(红灯/行人导致的等待)、CROSSING(绿灯通行中)。任何时刻多个条件同时成立,高优先级赢——斑马线上有人,哪怕绿灯也得让;红灯变绿的瞬间,还得确认停止线前没有行人残余,才从 WAITING 迁移到 CROSSING。状态迁移要带滞回:判定条件持续 200ms 才迁,避免灯缘抖动让车在路口"点头"。

IDLE / WAITING / CROSSING 优先级状态机 IDLE 巡线中 · PID 出力 WAITING 红灯 / 行人 · v=0 CROSSING 绿灯通行 · 加速通过 红灯 / 行人↓ 绿灯 & 无行人 过路口 → 巡线 行人离开 2s 最高优先级抢占:CROSSING 中突现行人 → 直落 WAITING(行人 > 红灯 > 巡线) 迁移条件需持续 200ms(滞回),/cmd_vel 平滑斜坡限变化率,防止车头"点头"抖动
图 3-1|自制示意图:路口优先级状态机——红实线为最高优先级抢占路径;每个迁移都带 200ms 滞回与速度斜坡,对应 s4 操作步骤的调参环节。
偏差 e 从哪来
ROI 横带内高对比识别线的质心 x 与画面中心 W/2 之差,归一化到 [-1,1];丢线时保持上帧方向 + 降速。
停止线怎么认
垂直于车道的白色亮横条:ROI 内满宽白色行 + 与车道线 T 形相交;检测到即进入"预见减速"。
行人判据
EXP-02 /traffic/sign 的"注意行人"仅是提示,真正停车判据是行人模型色块在斑马线区 ROI 内出现。
速度怎么限
巡线 v=0.18m/s,停止线前 20cm 斜坡降到 0.08,横向 ω 上限 1.2rad/s——宁慢勿甩。

03硬件与场景

HP60C 下视 ROI
取画面下 1/3 为巡线 ROI;近盲区 0.5m 反而帮了忙——下视距离刚好在 0.25~0.45m,车道线清晰不畸变。
麦克纳姆轮底盘
执行 /cmd_vel;全向能力使"边巡线边平移避让"成为可能,但本实验只用 v+ω 差速模式,行为更可预测。
沙盘路口与斑马线
停止线、斑马线均为白色标线;灯口复用 EXP-01 语义点位,行人模型摆斑马线东侧端头。
2D 激光雷达兜底
视觉失锁(反光/阴影)时,雷达前方 0.4m 扇区出现障碍仍硬停——视觉与雷达双保险。
练习科目通过标准常见失败
直道巡线 5m偏差 ≤±2cm,不压线不出线Kp 过大蛇形;Ki 残留积分饱和
直角弯 4 处入弯前减速至 0.08m/s,一次过弯Kd=0 过冲甩尾;速度没降
路口红灯停停在停止线后 2~5cm,10/10刹车太晚越线;提前减速区设太近
斑马线礼让行人模型出现 30cm 内必停,10/10只检测"注意行人"标志而漏了真行人
生活化类比:状态机像路口交警、PID 像方向盘上的手——交警说"停",手再稳也不能动;交警说"走",手才接管。谁说了算是优先级,不是谁先到。

04操作步骤

S1下视标定
取 ROI → 采集三光照车道帧 → 学习质心算法
→
S2PID 手动整定
先 Kp 起振回退半 → 加 Kd 阻尼 → Ki 消稳态偏差
→
S3停止线 + 灯态联动
0.2m 预见减速 → 读 /traffic/light → 红停绿行
→
S4斑马线礼让
行人 ROI 检测 → 30cm 触发刹停 → 2s 滞后恢复
→
S5状态机集成联调
三状态贯穿全圈 → 录 rosbag 回放核对迁移日志
  1. PID 整定顺序(经典 Z-N 简化法):Ki=Kd=0,Kp 从 0.4 起加倍到小车开始蛇形振荡,回退取 2/3 作为 Kp;加 Kd=0.15 起步压振荡;最后 Ki=0.02 消掉轮差导致的恒偏——一次只动一个参数,每轮跑 5m 直道记偏差曲线。
  2. 预见减速:停止线检测到时距 0.2m 开始斜坡降速,而不是到线急刹——"提前减速"写进代码而不是靠反应。
  3. 灯态联动:红灯或黄灯且距线 <0.15m 时 v 斜坡归零进入 WAITING;/traffic/light 消失超过 1s 视为故障,按红灯处理(fail-safe 停车而非抢行)。
  4. 礼让逻辑:行人模型色块进入斑马线 ROI 即触发(与灯态无关,优先级最高);离开后连续 2s 无目标才恢复巡线,防止行人模型晃动反复触发。
  5. 状态机联调:打印每次迁移的时间戳与理由(trigger),录 ros2 bag record -a,回放核对:全圈 4 路口 + 1 斑马线迁移序列与预期一致。
  6. 留痕:直道偏差曲线截图、红灯/礼让 10/10 计数表、状态迁移日志,构成验收三件套。
写入 s4 的验收速查:直道 ≤±2cm · 红灯停 10/10 · 礼让 10/10 · 状态迁移无振荡(同一迁移 1s 内 ≤1 次)。易错点:Kp 一把梭振荡、忘记积分清零(WAITING 结束后 I 项带着旧积分冲出去)、速度没斜坡、灯态话题断了还继续走。

05关键命令

/cmd_vel、teleop、rosbag 用法沿用《培训方案》xlsx 风格;灯态话题来自 EXP-02。

# ① 起相机(EXP-02 驱动复用)+ 灯态识别节点
ros2 launch ascamera hp60c.launch.py
python3 src/light_node.py --config config/hsv_config.yaml

# ② 启动巡线 + 路口状态机节点(参数包 lane_follow.yaml)
ros2 run car1_control lane_follow_node.py --ros-args \
  --params-file src/car1_control/config/lane_follow.yaml
ros2 topic echo /cmd_vel                       # 看 v/ω 是否平滑
ros2 topic echo /traffic/light                 # R/Y/G 联动输入

# ③ 手动微调 PID(运行中热改,改完立刻跑 5m 直道)
ros2 param set /lane_follow_node kp 0.60
ros2 param set /lane_follow_node kd 0.15
ros2 param set /lane_follow_node ki 0.02

# ④ 无灯时手动注入灯态,联调状态机
ros2 topic pub -r 1 /traffic/light std_msgs/String "{data: 'R'}"

# ⑤ 联调录包回放:迁移日志 + TF + 偏差话题全录
ros2 bag record -a -o lane_interface_bag
ros2 bag play lane_interface_bag
ros2 run tf2_tools view_frames                 # out/frames.pdf 查 TF 完整性
验收判据 ①
直道 5m 偏差曲线带宽 ≤±2cm(rosbag 提取 e(t) 画图)。
验收判据 ②
红灯 10 次全停线后;绿灯 10 次全通行;灯态断流按 fail-safe 停车。
验收判据 ③
行人模型 10 次出现全部刹停、离开 2s 恢复;优先级抢占在日志中可溯。
验收判据 ④
全圈状态迁移序列与预期一致、无 1s 内重复振荡迁移。

06原理动画:巡线 PID 反馈环与信号灯时序通行

巡线 PID 闭环:偏差 e 进,角速度 ω 出,车头回正 Σ PID 控制器 Kp·e + Ki·∫e + Kd· ė /cmd_vel v 限速 · ω 限幅 小车 C1 麦克纳姆轮 相机 ROI 质心 反馈:新 e = 质心 − W/2 —— 每帧 30 次闭环,偏差不积累过夜 理想响应:阶跃给定下 e(t) 衰减不振荡 —— Kd 提供阻尼,Ki 消稳态差
动画 3-1:黄点=前向控制流(偏差→PID→速度→底盘),绿点=反馈流(相机重测质心)。环每转一圈 33ms,转得够快,车看起来才是"稳稳压着线"。
红→绿时序 × 小车接近停止线的走停决策 南北灯 RED 3s Y 5s GREEN 25s 小车 C1 停止线 状态机日志(8s 一个周期): WAITING:红灯,v 斜坡归零,停线后 3cm 黄灯:距线远→已停;距线近→抢过(go-on-thru) CROSSING:绿灯 0.18m/s 巡线过口 回 IDLE:过口 0.3m 迁移,积分清零
动画 3-2:8 秒压缩演示一个 48s 配时周期——小车在红灯段刹停于停止线,黄灯按距决策,绿灯恢复巡线过口;下方为状态机同步日志。
观察动画 3-1 中如果拔掉绿色反馈线会怎样?系统变成开环:ω 只按固定程序转,轮差、地面摩擦、光照突变全无法纠正——车走出 S 形直至出轨。控制的本质不是"发命令",是"看结果改命令"。

07互动实验:巡线 PID 参数滑杆实时仿真

拖 Kp/Ki/Kd 看偏差曲线:蛇形、过冲、稳态差一目了然
e=0 车道中心 ±2cm 带 e(t) 阶跃响应(初始偏 6cm)——目标:尽快进带且不振

快速实验:① Kp 拉到 3.0、Kd=0 → 曲线持续振荡(蛇形);② Kd 拉到 2.0 → 过冲被压平但响应变肉;③ Ki 拉大且 Kp 也大 → 积分饱和,超调久收不回。把三参数调到"两个周期内进带且不越界",就是实车直道 ≤±2cm 的前置条件。

08常见问题

Q 直道上蛇形摆动?
Kp 过大或 Kd=0:按 s4 顺序回退 Kp 取 2/3 振荡点,再补 0.15 级 Kd;同时确认 ω 限幅 1.2。
Q 车总往一侧偏?
轮差/轮胎气压不对称的恒偏:加 Ki=0.02 消之;或 WAITING 结束忘了清积分——积分挂着旧账冲出线。
Q 红灯抢行?
/traffic/light 断流且没做 fail-safe:断流 ≥1s 必须按红灯停;查灯态节点是否被相机重启动连坐。
Q 停车总是越线?
减速区太近(惯性冲过):预见距离 0.2m 起 + 刹停斜坡;确认"提前减速"在代码而非靠手速。
Q 行人模型认不出?
ROI 没盖到斑马线端头或换光照没重标色域:复用 EXP-02 标定流程,色块面积阈值降到 300px²。
Q 状态机 1 秒迁 3 次?
缺滞回:迁移条件持续 200ms 才迁;灯缘抖动/行人边缘闪烁都会被 200ms 窗口滤掉。
Q 弯道总切内压线?
入弯没降速 + Kd 过阻尼响应迟:弯前 0.3m 斜坡降到 0.08,弯中允许偏差放宽到 ±4cm 通过再收敛。
Q /cmd_vel 来回跳变?
检测帧率不稳或双节点抢发:ros2 node info 查唯一发布者;对 ω 加斜率限制(≤4 rad/s²)。

09拓展阅读

  • 《机器人学中的状态估计》第 9 章 PID:从误差动力学看 Kp/Ki/Kd——把互动面板的曲线与书中阶跃响应图对读。
  • Nav2 controller 参数对照:DWB 的评分权重与本课 PID 是同一思想在 2D 速度采样域的展开,EXP-04 泊车会回到这个对照。
  • 行为树 vs 有限状态机:本课用三级优先级 FSM 够用;当规则再涨一倍(让行+限速+改道+警报),业界会迁移到 BehaviorTree.CPP——留作课程后续。
  • rosbag 分析工作流:用 ros2 bag info + rqt_plot 画 e(t) 曲线交作业,比截图更有说服力。
  • 上下文:EXP-02 的 /traffic/* 话题是本实验状态机的感知输入,联调异常先回查话题频率。

10思考题 · 自测

✅ 完成成果
直道偏差 ≤±2cm、红灯 10/10、礼让 10/10、状态迁移无振荡,rosbag 留痕。
🧠 原理收获
能画出 PID 闭环框图并解释三项各治什么病,讲清优先级与滞回两道保险。
🛠 技能收获
独立完成 PID 手动整定、预见减速参数化、状态机日志审计三件套。
📐 评分速览
巡线质量 35% + 灯口通行 30% + 礼让 25% + 日志规范 10%。
思考 1为什么 WAITING 结束进入 CROSSING 前要清积分项?用"I 项累积"解释不清积分时绿灯起步冲线的现象。
思考 2行人 > 红灯 > 巡线的优先级是拍脑袋定的吗?若沙盘新增"救护车优先"规则,状态机要改哪里——迁移表还是优先级表?