这是一个独立 C++ 程序,用来连接球体检测后端的 WebSocket,读取推理检测框坐标,完成视觉闭环控制,并向一个通用 RC HTTP 控制端发送底盘指令。
autoControl 不依赖 TeaFamily 或遥控插件源码。rpi5-stm32-tank-remote 只作为 RC HTTP 协议参考实现:
/Users/gonc/study/gonc_proj/TeaFamily/plugins/rpi5-stm32-tank-remote
默认捡球策略:
- 读取
ball_server /ws/stream的frame和detections。 - 选出
ball检测框,计算框中心线与摄像头画面中心线的水平误差。 - 检测线程只覆盖最新目标快照,控制线程以固定频率闭环运行,不积压旧帧。
- 对球中心和转向输出做低通滤波,并限制油门、转向的单位时间变化量。
- 连续多帧进入中心死区后才前进;偏离更大的退出阈值时回到原地对准。
- 连续对准后平滑加速到最大油门,不根据球框远近减速。
- 球连续消失达到
lost_target_timeout_ms(默认 250 ms)后调用/stop。
cmake -S . -B build
cmake --build build
ctest --test-dir build依赖:
- CMake
- Boost.Asio / Boost.Beast
- nlohmann_json
先启动识别后端和底盘控制插件,然后复制配置:
cp config.example.json config.json
./build/auto_control --config config.json可以先用 dry-run 验证控制计算,不实际发送底盘指令:
./build/auto_control --config config.json --dry-rundetection_ws_url 连接识别端 WebSocket。识别后端接口格式来自:
/Users/gonc/study/gonc_proj/ballDect/ball_detection/backend_cpp
示例:
{
"detection_ws_url": "ws://127.0.0.1:8000/ws/stream?target=http://192.168.8.100:8889/rpi-camera/whep",
"rc_base_url": "http://192.168.8.100:19750",
"target_class_name": "ball",
"target_class_id": -1,
"min_confidence": 0.25,
"fallback_frame_width": 1920,
"command_interval_ms": 50,
"lost_target_timeout_ms": 250,
"reconnect_delay_ms": 1000,
"control": {
"center_deadband_px": 24.0,
"turn_gain": 650.0,
"min_turn": 80,
"max_turn": 650,
"throttle": 0,
"invert_throttle": false,
"invert_turn": false,
"pickup_enabled": true,
"approach_throttle": 1000,
"approach_max_turn": 320,
"turn_filter_alpha": 0.4,
"kalman_process_noise": 0.5,
"kalman_center_measurement_noise": 0.000025,
"kalman_height_measurement_noise": 0.0001,
"kalman_prediction_lead_ms": 40,
"kalman_max_prediction_ms": 150,
"aligned_exit_px": 60.0,
"aligned_frames": 3,
"throttle_ramp_per_second": 1200,
"turn_ramp_per_second": 3000
}
}center_deadband_px: 中心死区,误差小于该像素值时不转向。turn_gain: 归一化误差到turn的比例。误差为半个画面宽度时,输出约等于该值。min_turn: 目标已偏离死区但输出太小时,给一个最小转向量克服静摩擦。max_turn: 转向上限,最终仍会被限制在底盘插件支持的-1000..1000。throttle: 对准阶段的基础油门,默认0。invert_throttle: 实车前后方向与协议相反时设为true。invert_turn: 如果实车方向相反,改成true。pickup_enabled: 是否启用自动靠近捡球;设为false时只做中心线对准。command_interval_ms: 闭环控制周期,默认50 ms(目标 20 Hz;实际频率仍受 RC HTTP 响应时间限制)。approach_throttle: 对准后的固定目标油门,默认最大值1000,不随球框远近变化。approach_max_turn: 前进跟踪时的转向修正上限。turn_filter_alpha: 转向命令低通系数。kalman_process_noise: 球运动模型噪声;越大越容易跟随快速变向,越小越平滑。kalman_center_measurement_noise: 球中心测量噪声方差;越大越不信任检测框中心。kalman_height_measurement_noise: 球框高度测量噪声方差。kalman_prediction_lead_ms: 在最新视频帧位置基础上向前预测的补偿时间。kalman_max_prediction_ms: 丢帧或延迟时允许的最大预测时间,避免无限外推。aligned_frames: 连续对准多少个新检测帧后允许前进。aligned_exit_px: 前进过程中偏差超过该值时退出前进,形成迟滞,避免状态抖动。throttle_ramp_per_second/turn_ramp_per_second: 每秒最大输出变化量。
ball_server /ws/stream
-> WebSocket 线程覆盖最新检测快照(不建立历史队列)
-> 固定周期控制线程读取最新快照
-> 位置滤波 + 连续多帧对准确认
-> 未对准: 平滑原地转向
-> 已对准: 渐进加速并持续跟踪中心
-> 保持跟踪: 平滑加速到最大油门并持续保持
-> 偏离退出阈值: 退回原地对准
-> 球连续消失 250 ms: 单一控制线程 POST /stop
RC 命令和停车命令只允许由同一个控制线程发送,因此不会发生旧 /stop 与新 /rc 并发乱序。单个检测消息最多保留 64 个检测框,运行时只保存一个最新快照,内存占用有固定上限。