模型推理移至管道末尾降舵机延迟60→16ms + 视觉Mat复用 + 端到端延迟计时 + OpenCV 4.13 + WASD遥控

This commit is contained in:
spdis
2026-06-29 16:43:41 +08:00
parent 40d5cb1604
commit 017a827b18
16 changed files with 1201 additions and 709 deletions
+54 -32
View File
@@ -34,13 +34,12 @@
```
main()
├── cfg_load_all() # 从工作目录文件读取全部配置
├── 补读 cone_avoid_gain/range/hold_frames
├── CameraInit(0) # 打开摄像头, LCD, 模型, I2C, 计算巡线尺寸
├── CameraInit(0) # 打开摄像头, LCD, 模型, I2C, VL53L0X, 计算巡线尺寸
├── ControlInit() # 初始化双电机 GPIO + PWM + 启动编码器线程
└── while(running):
├── CameraHandler() # ★ 逐帧执行
└── target_speed = g_cfg.speed # (debug 模式下每 7 帧重载)
└── target_speed = g_cfg.speed # (debug 模式下每 30 帧重载)
```
`CameraInit` 现在只接受 `camera_id` 一个参数(之前有 dest_fps, width, height 三个遗留参数已移除)。
@@ -48,12 +47,12 @@ main()
---
## CameraHandler 11 步流水线
## CameraHandler 10 步流水线 (`src/camera.cpp:755`)
```
Step 1 capture_frame() 640×480 MJPEG → IMREAD_REDUCED_COLOR_4
取帧+解码 → raw_frame = 160×120 BGR
(回退: raw_mat 三通道 → 直用 640×480)
Step 1 capture_frame() 640×480 MJPEG → IMREAD_REDUCED_COLOR_4
取帧+解码 → raw_frame = 160×120 BGR
(回退: raw_mat 三通道 → 直用 640×480)
Step 2 save_image_if_requested() debug=1 && saveImg 文件=1 → 存 ./image/XXXXX.jpg
保存图像 (条件)
@@ -62,36 +61,43 @@ Step 3 image_main() raw_frame → resize(lt_w×lt_h) → HSV 双
视觉巡线 → floodFill(种子 (lt_w/2, lt_h-10), 半径5)
→ 逐行最长连续段搜索 → 丢线补全(row 10~59)
输出: left_line[], right_line[], mid_line[]
随后: mid_line_raw = mid_line (原始中线快照)
Step 4 run_model_inference() 每 2 帧推理一次
Step 4 lidar_avoid_process() 每 2 帧读距 → 距离→行映射 → 去抖确认
激光避障 确认后中线变形 (固定朝右) + 消失后保持衰减
方向判断基于 mid_line_raw, 变形修改 mid_line
Step 5 run_model_inference() 每 2 帧推理一次
模型推理 raw_frame (160×120) → model_v10_detect()
4 类: 0=锥桶 1=红灯 2=绿灯 3=斑马线
g_thresh = {0.90, 0.75, 0.80, 0.90}
g_thresh = {0.65, 0.75, 0.80, 0.82}
→ g_boxes[16], g_box_count
Step 5a zebra_process() 去抖计数 + ZNORMAL→ZSTOP(4s)→ZCOOLDOWN(5s)
Step 6a zebra_process() 去抖计数 + ZNORMAL→ZSTOP(4s)→ZCOOLDOWN(5s)
斑马线状态机 触发: 连续5帧 + 起源于远(cy≤50) + 当前近(cy>zebrasee)
刹停时 I2C 语音播报
Step 5b traffic_light_process() TLNORMAL→TLSTOP→TLWAIT_GREEN
Step 6b traffic_light_process() TLNORMAL→TLSTOP→TLWAIT_GREEN
红绿灯状态机 红灯≥3帧 → 停车; 红灯消失 → 等绿灯; 绿灯≥3帧 → 通行
Step 5c cone_detect_and_deform() 去抖确认 + 中线变形 + 消失后保持衰减
锥桶检测 & 中线变形 cone_speed 减速 + cone_hold_frames 保持
Step 6c cone_detect_and_deform() 去抖确认 + 中线变形 + 消失后保持衰减 + 回弹
锥桶检测 & 中线变形 cone_hold_frames 保持 → cone_return_frames 回弹
Step 6 steering_update() foresee/2 → check_row → mid_line[row]×2 - newWidth/2
Step 7 steering_update() foresee/2 → check_row → mid_line[row]×2 - newWidth/2
舵机控制 deadband 过滤 → servo duty: 1500000 ± offset ns
Step 7 motor_update() 开环PWM + 编码器比例刹车 + 弯道减速 + 锥桶减速
电机控制
Step 8 motor_update() 开环PWM + 编码器比例刹车 + 弯道减速
电机控制 (锥桶/挡板减速代码存在但已注释)
Step 8 lcd_render() track→BGR→ROI + 边界线(红/绿/蓝) + 检测框 + 状态指示
Step 9 lcd_render() track→BGR→ROI + 边界线(红/绿/蓝) + 检测框 + 状态指示
LCD 渲染 RGB565 → /dev/fb0 mmap
Step 9 fps_log() 每 15 帧输出总帧率 + 分步耗时 ms
Step 10 fps_log() 分步耗时日志
FPS 统计
```
另:每 150 帧调用 `malloc_trim(0)` 回收空闲内存(嵌入式优化)。
---
## 视觉巡线深度展开 (`image_main`)
@@ -183,9 +189,10 @@ ControlUpdate(speed, zebra_or_tl_block):
motor[i]->updateduty(0) ← 已静止,不刹车
return
curve = 1.0 - |g_steer_deviation| × 0.4 ← 弯道减速
curve = max(curve, 0.6) ← 最低 ≥ 60%
curve = 1.0 - |g_steer_deviation| × g_cfg.curve_slope ← 弯道减速 (默认 0.4)
curve = max(curve, g_cfg.curve_min) ← 最低倍率 (默认 0.8)
spd = speed × curve
// 锥桶减速 (cone_speed) / 挡板减速 (lidar_speed) 代码存在但已注释
motor[0].updateduty(spd) → 左电机 (pwmchip8/pwm2, gpio12 方向)
motor[1].updateduty(spd) → 右电机 (pwmchip8/pwm1, gpio13 方向)
@@ -196,8 +203,8 @@ ControlUpdate(speed, zebra_or_tl_block):
刹车力度与当前车速成正比(`brake_scale`),有上限(`brake_max` ns)。
速度低于 0.5 pps 时不再施加刹车。
**motor_update 额外逻辑:** `motor_update()` 在调用 `ControlUpdate` 之前,若锥桶已触发(`cone_is_slow()`
会将 speed 乘以 `g_cfg.cone_speed`(默认 0.5),实现锥桶路段减速
**motor_update 额外逻辑:** `motor_update()` 中包含锥桶和挡板减速代码(`cone_is_slow()``× cone_speed`
`lidar_is_active()``× lidar_speed`),但当前**已注释**,仅弯道减速生效
**motor[0] vs motor[1]** 左/右区别仅在于 gpioNum12 vs 13)和 pwm通道(2 vs 1),函数调用完全相同。
@@ -347,28 +354,43 @@ lcd_render():
|---|---|---|---|---|
| `./speed` | double | 60 | 11 | 目标速度 (% 占空比) |
| `./start` | int(0/1) | 0 | 0 | 使能开关,1=电机运行 |
| `./debug` | int(0/1) | 0 | (不写入) | 每7帧重载配置+允许存图 |
| `./debug` | int(0/1) | 0 | (不写入) | 每30帧重载配置+允许存图 |
| `./showImg` | int(0/1) | 0 | (不写入) | LCD 显示(每10帧轮询→g_lcd_on |
| `./foresee` | double | 80 | 40 | 舵机前瞻行 (显示空间像素) |
| `./deadband` | double | 5 | 8 | 舵机死区 (显示空间像素) |
| `./steer_gain` | double | 1.0 | 1.5 | 舵机增益 |
| `./center_bias` | double | 0 | (不写入) | 中线偏置修正 |
| `./kp`,`./ki`,`./kd` | double | - | 3.5/0.3/2.0 | PID 参数 (当前未使用) |
| `./mortor_kp/ki/kd` | double | - | 0.6/0.2/0 | 电机编码器 PID (当前未使用) |
| `./zebrasee` | double | 60 | (不写入) | 斑马线近界阈值 (模型空间cy) |
| `./destfps` | double | 30* | (不写入) | 目标帧率 (*代码兜底值) |
| `./saveImg` | int(0/1) | - | (不写入) | 保存帧图像 (需 debug=1) |
| `./cone_avoid_gain` | double | 0.3 | 0.3 | 锥桶中线变形推离量 (归一化) |
| `./cone_avoid_range` | int | 30 | 30 | 变形斜坡陡峭度 |
| `./cone_speed` | double | 0.5 | 0.5 | 锥桶触发时速度倍率 |
| `./cone_min_frames` | int | 3 | 3 | 锥桶连续确认帧数 |
| `./cone_speed` | double | 0.5 | 0.5 | 锥桶触发时速度倍率 (当前未生效) |
| `./cone_min_frames` | int | 1 | 1 | 锥桶确认帧数 (单帧即确认) |
| `./cone_margin` | int | 0 | 0 | 0=中心点, 1=框边缘检查 |
| `./cone_thresh` | double | 0.80 | 0.80 | 锥桶置信度阈值 |
| `./cone_hold_frames` | int | 30 | 30 | 锥桶消失后保持变形帧数 |
| `./cone_hold_frames` | int | 15 | 30 | 锥桶消失后保持变形帧数 |
| `./cone_return_gain` | double | 1.0 | (不写入) | 回弹力度 (1.0=等同避让) |
| `./cone_return_frames` | int | 30 | (不写入) | 回弹持续帧数 |
| `./curve_slope` | double | 0.4 | (不写入) | 弯道减速斜率 |
| `./curve_min` | double | 0.8 | (不写入) | 弯道最低速度倍率 |
| `./brake_scale` | double | 10 | 10 | 刹车速度→占空比系数 |
| `./brake_max` | int | 10000 | 10000 | 最大刹车占空比 (ns) |
| `./lidar_enable` | int(0/1) | 1 | 1 | 激光避障总开关 |
| `./lidar_thresh` | int | 300 | 300 | 障碍判定距离阈值 (mm) |
| `./lidar_pre` | int | 800 | (不写入) | 预触发去抖窗口 (mm) |
| `./lidar_near` | int | 50 | 50 | row=lt_h-1 对应距离 (mm) |
| `./lidar_far` | int | 1200 | 1200 | row=10 对应距离 (mm) |
| `./lidar_near_start` | int | 1 | 1 | near_valid 起始偏移 |
| `./lidar_near_end` | int | 4 | 4 | near_valid 终止偏移 |
| `./lidar_far_span` | int | 6 | 6 | far_lost 检测跨度 |
| `./lidar_min_frames` | int | 3 | 3 | 连续确认帧数 |
| `./lidar_avoid_gain` | double | 0.4 | 0.4 | 绕行推离力度 (归一化) |
| `./lidar_avoid_range` | int | 30 | 30 | 绕行斜坡陡峭度 |
| `./lidar_speed` | double | 0.4 | 0.4 | 绕行速度倍率 (当前未生效) |
| `./lidar_hold_frames` | int | 30 | 30 | 消失后保持帧数 |
**debug 模式:** `./debug` = 1 时,主循环每7帧调用一次 `cfg_load_all()` 重读全部配置,支持热更新调参。同时允许 `saveImg` 保存图像。
**debug 模式:** `./debug` = 1 时,主循环每 30 帧调用一次 `cfg_load_all()` 重读全部配置,支持热更新调参。同时允许 `saveImg` 保存图像。
**注意:** `global.h` 中的 `CfgCache` 默认值和 `ctl.sh` 写入的值不一致(如 speed: 60 vs 11)。`ctl.sh` 写入的值覆盖代码默认值,是实际运行参数。
@@ -380,12 +402,12 @@ lcd_render():
| 文件 | 功能 | 排除原因 |
|---|---|---|
| `vl53l0x.cpp` | 激光测距模块 | 硬件未连接 |
| `zebra_detect.cpp` | 经典斑马线检测 | 已被 Mild 模型替代 |
| `PIDController.cpp` | 位置式/增量式 PID | 电机开环直驱,无调用点 |
| `serial.cpp` | VOFA 串口可视化 | 未使用 |
**注意:** `PIDController.h` 仍在 `lib/` 中,`MotorController` 仅提供 `updateduty()`(开环占空比),
**注意:** `vl53l0x.cpp` 已恢复编译(激光测距已集成至 `lidar_avoid_process()`)。
`PIDController.h` 仍在 `lib/` 中,`MotorController` 仅提供 `updateduty()`(开环占空比),
不提供 `updateSpeed()` 方法。
---
@@ -396,7 +418,7 @@ lcd_render():
- **输入**160×120 BGR
- **输出**:4 类 + 背景 → 9 通道:0=锥桶, 1=红灯, 2=绿灯, 3=斑马线
- **架构**3→9→9→13→13→19→19→19→44→44→64→64 → head(64→64,dw) → out(64→9)
- **阈值**`{0.90, 0.75, 0.80, 0.90}`(锥桶/红灯/绿灯/斑马线)
- **阈值**`{0.65, 0.75, 0.80, 0.82}`(锥桶/红灯/绿灯/斑马线)
- **权重文件**`mild_v12.bin`105KB 自定义二进制格式)
- **推理频率**:每 2 帧一次(跳帧节省 CPU)