Vision Anti-Pinch — use-can

相机默认每 2000 ms 无有效帧记一次失败,连续 6 次才停止流水线(纯超时约 12 秒);成功取得有效帧后重新计数。每个等待周期内仍以 100 ms 间隔检查停止请求,CAN 接收不受重试影响。取流错误或坏帧也计入重试期限;设备失效时尝试重开相机,恢复后继续推理。单次等待时间由 config/camera.json 的 camera.timeout_ms 配置。

编译与运行

目标环境:Jetson AGX Orin、JetPack 5.1.2 / L4T R35.4.1、CUDA 11.4、TensorRT 8.5.x、OpenCV 4.5.4。 源码编译另需 CMake 3.24+ 和相应开发库。

./scripts/build.sh                  # 或 make
./scripts/initialize_camera.sh      # 开机后摄像头尚未初始化时执行
./run_camera.sh                     # 执行 build/camera_risk
./run_camera.sh --visualize         # 可选 OpenCV 本地窗口

预编译 Orin 包:

cd orin
./scripts/initialize_camera.sh
./run.sh                           # 脚本直接 exec C++ ELF 程序
# 也可以直接执行:
./build/camera_risk --config config/camera.json

默认无窗口、不保存文件;Ctrl+C / SIGTERM 停止。--visualize 使用 Orin 的图形桌面,关闭窗口仅停止显示、推理继续。没有桌面环境时保持无窗口推理。

流水线与结果变量

V4L2 MMAP 采集 / NPP UYVY 转换(线程 1)
 → YOLO TensorRT 检测(线程 2)
 → RTMW TensorRT / 隔离推理 / C++ 时序融合(线程 3)
 → 前后门多特征归属 / 因果中值 / mask 风险 / CAN 过滤
 → shared_ptr<const FrameResult> 最新结果变量

摄像头使用有界队列并丢弃积压旧帧;可视化独立读取最新结果。 下游直接链接 camera_risk_core,在自己的线程中读取:

#include "camera_pipeline.hpp"
#include "config.hpp"

cms::CameraPipeline pipeline(cms::loadConfig("config/camera.json"));
pipeline.start();
// 下游自己的循环中读取;首帧前 result 为空。
auto result = pipeline.latest();
if (result) {
    const auto& risk = result->risk;
    const auto& front = result->door_risks.at("front");
    const auto& rear = result->door_risks.at("rear");
    const auto& people = result->persons;  // 每人 selected/smoothed/temporal 各 133 点
    const auto& assignments = result->door_assignments;
    const auto& can = result->can;
    // risk.risk_type / risk.risk_level / risk.risk_score(std::optional<double>)
}
// 退出时:
pipeline.requestStop();
pipeline.join();

latest() 返回拥有数据的只读快照,读者互不消费结果,旧引用不会被新帧修改。慢读者可以跳过中间帧;异常通过 join() 传播。停止后的快照只代表最后结果,持续控制应检查运行状态和时间戳。 公共结构定义见 include/frame_result.hpp,接口见 include/camera_pipeline.hpp。

CAN 与风险

  • 0x391 的 data[0..3]:左前、右前、左后、右后。
  • 默认左侧,--can-side right 切到右侧;值为 0 时对应门活跃。
  • 缺失或过期(默认 1000 ms)报文输出 CAN_UNKNOWN,分数为空,不能解释为 clear。
  • --no-can --active-door both 显式模拟门状态;也可选择 front/rear/none。
  • 优先使用有效手部凸包,无有效手部时用人体框兜底;transition 保留 unknown 语义。
  • 最终使用 risk 或 door_risks;ungated_risk 仅用于诊断。当前只接收门状态,不发送执行器指令。
  • mask 和前后门参数来自研发机位,默认 calibration_verified=false;装车后需要重新标定。

配置位于 config/camera.json,模型位于 orin/models/engines/。详细参数:

./run_camera.sh --help
./run_camera.sh --duration 30
./run_camera.sh --save-results /path/results.jsonl

显式保存时每帧写一行 JSON,核心字段保留 frame_index、track_ids、boxes、skeletons、door_assignments、door_risks、risk、ungated_risk、can;文件由用户指定路径管理。--video 可使用同一 C++ 流程处理视频文件,尺寸需匹配配置。

目录与打包

  • src/:C++ / CUDA 源文件及 main.cpp。
  • include/:头文件及下游数据结构。
  • third_party/nlohmann/:C++ JSON 依赖及许可证。
  • config/、annotations/:运行配置与标定。
  • scripts/:编译、摄像头初始化、打包。
  • orin/:可单独复制的 ELF 程序、模型、驱动、CAN 库和配置。

修改源码后,在 Orin 重新编译并执行 ./scripts/package_orin.sh,或执行 make package。运行、打包均不使用 Python。打包后可在 orin 目录运行 sha256sum -c SHA256SUMS。

可选保存(默认全部关闭)

三个独立参数可以单独使用,也可以组合:

./run_camera.sh --save-original --save-annotated --save-results
# 独立包:./orin/run.sh --save-original --save-annotated --save-results

开启任一项时,程序自动创建可执行文件所属工程的 output/ 及三个子目录:

  • original/:--save-original 保存未叠加的原图,JPEG 质量 95。
  • annotated/:--save-annotated 保存带框、关键点及风险文字的 JPEG,无需开启可视化窗口。
  • results/:--save-results 每个完成推理的帧保存一个 JSON,包含帧号、检测框、跟踪 ID、关键点及置信度、风险和耗时;有 CAN 的分支还包含相应状态。

同一帧三类文件同名(扩展名不同),文件名包含运行标识和帧号,多次运行不覆盖。JSON 的 images 提供相对于 output/ 的图片路径,未选择保存的图片为 null。源码入口写入工程 output/;独立包入口写入 orin/output/。默认不创建目录、不保存文件。

保存对象是完成推理的帧;惰性分支暂停时不新增文件。开启保存会增加编码和磁盘 I/O 开销。写入失败时报告错误并停止,不静默丢失文件。

相机超时回归测试:./tests/run_camera_timeout.sh;加 --wall-clock 验证默认 6 次超时约 12 秒。测试直接编译实际相机代码,使用模拟采集和转换器,无需摄像头、GPU 或 OpenCV;不覆盖视频回放路径。

板端真实摄像头 / TensorRT 恢复与停止测试记录见 Orin 测试报告。

S
Description
No description provided
Readme 366 MiB
Languages
Python 100%