# jetson-runtime **Repository Path**: taj5/jetson-runtime ## Basic Information - **Project Name**: jetson-runtime - **Description**: 面向 NVIDIA Jetson Orin NX 的多算法边缘视觉运行时。平台通过 REST 管理相机、算法与任务,运行时使用最新帧调度推理,并通过 MQTT 上报事件与报警。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-14 - **Last Updated**: 2026-09-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Jetson Algorithm Runtime 面向 NVIDIA Jetson Orin NX 的多算法边缘视觉运行时。平台通过 REST 管理相机、算法与任务,运行时使用最新帧调度推理,并通过 MQTT 上报事件与报警。 目标硬件环境:Jetson Orin NX 16GB Super,JetPack 6.2(L4T 36.4.3),CUDA 12.6,TensorRT 10.3,Python 3.10.12。 ## 当前能力 - YAML + Pydantic 配置校验和 JSON 结构化日志。 - SQLite 任务持久化与 MQTT 离线队列。 - file、image、synthetic Mock 视频源,引用计数帧池、最新帧缓存和 JPEG 取证缓存。 - 算法抽象、Mock 检测/分类、共享算法注册表、TensorRT context 生命周期抽象和 GPU worker pool。 - 任务状态机、优先级队列、调度器、资源预算与迟滞降频策略。 - Bearer Token REST API、事件去重/报警去抖、MQTT QoS 策略、健康探针和 systemd 单元模板。 ## 当前限制 RTSP 已使用 PyGObject `appsink` 取帧,`app.main` 会启动常驻 HTTP 服务。MQTT 支持 Paho Broker 连接、QoS 与离线队列;生产接入前仍需配置并验证 Broker。 ## Windows 开发 安装 [uv](https://docs.astral.sh/uv/),然后在 PowerShell 中执行: ```powershell cd D:\WorkBuddy-Workspace\jetson-runtime $env:UV_CACHE_DIR = ".uv-cache" uv run --extra dev pytest uv run python -m app.main ``` 预期测试结果: ```text 21 passed ``` ## Jetson 安装 在 Jetson 上复制或克隆本仓库后执行: ```bash sudo apt update sudo apt install -y python3-venv python3-pip \ python3-gi python3-gst-1.0 gir1.2-gstreamer-1.0 gir1.2-gst-plugins-base-1.0 \ gstreamer1.0-tools gstreamer1.0-plugins-base \ gstreamer1.0-plugins-good gstreamer1.0-plugins-bad cd ~/jetson-runtime python3 -m venv --system-site-packages .venv source .venv/bin/activate pip install --upgrade pip pip install -e ".[dev,jetson]" pytest -q ``` `--system-site-packages` 使虚拟环境能访问 JetPack 提供的 TensorRT 和 PyGObject 软件包。 验证 NVIDIA 与 GStreamer 环境: ```bash python3 -c "import tensorrt as trt; print(trt.__version__)" gst-inspect-1.0 nvv4l2decoder gst-launch-1.0 --version jtop ``` 验证一条 RTSP 硬解链路,将地址替换为实际摄像头地址: ```bash gst-launch-1.0 -v \ rtspsrc location="rtsp://user:password@camera.example/stream" latency=200 ! \ rtph264depay ! h264parse ! nvv4l2decoder ! \ nvvidconv ! fakesink sync=false ``` 运行时观察 `jtop` 中的 CPU、GPU、显存和温度;先验证单路,再逐步增加到八路。 ## 配置 `configs/device.yaml`: ```yaml device_id: jetson-local data_dir: data database_path: data/runtime.db log_level: INFO api_token: development-token-change-before-deployment ``` 部署前必须将 `api_token` 改为随机的设备级密钥,不要提交真实密钥。算法定义在 `configs/algorithms.yaml`。 ## REST API 完整的鉴权、字段约束、状态码与调用示例见 [REST API 接口参考](docs/api-reference.md)。 控制面接口使用 `Authorization: Bearer `: | 方法 | 路径 | 用途 | | --- | --- | --- | | GET | `/api/v1/device` | 设备信息 | | GET | `/api/v1/cameras` | 相机 ID、连接状态和重连次数 | | GET | `/api/v1/algorithms` | 算法状态 | | POST | `/api/v1/algorithms/{id}/load` | 加载算法 | | POST | `/api/v1/algorithms/{id}/unload` | 卸载算法 | | POST | `/api/v1/tasks` | 创建任务 | | GET | `/api/v1/tasks` | 查询任务 | | PATCH | `/api/v1/tasks/{id}` | 修改任务 | | DELETE | `/api/v1/tasks/{id}` | 删除任务 | | GET | `/api/v1/system/resources` | 资源快照 | | GET | `/api/v1/system/health` | Scheduler/Worker 健康状态 | | GET | `/api/v1/metrics` | 性能指标 | | GET | `/api/v1/images/{image_id}` | 报警取证图片 | 创建任务请求示例: ```json { "camera_id": "camera-001", "algorithm_id": "mock-detector", "fps": 2, "priority": 10 } ``` 平台下发任务前,先使用同一个 Bearer Token 发现设备能力: ```bash curl -H 'Authorization: Bearer ' http://:8000/api/v1/device curl -H 'Authorization: Bearer ' http://:8000/api/v1/cameras curl -H 'Authorization: Bearer ' http://:8000/api/v1/algorithms ``` `/api/v1/cameras` 返回可用于 `camera_id` 的相机及其连接状态;`/api/v1/algorithms` 返回可用于 `algorithm_id` 的已注册算法。随后平台将这两个 ID 放入 `POST /api/v1/tasks` 请求。RTSP 地址和模型文件路径不会通过此流程下发。 ## 报警后处理 每帧推理结果会按任务 `config` 的 `confidence`、`classes` 和 `roi` 过滤。过滤后的目标从无到有、从有到无时,Runtime 发布 MQTT `result` 事件;连续命中达到 `alarm.debounce_frames`、持续时间达到 `alarm.min_duration_ms`,并且距上一条报警超过 `alarm.cooldown_ms` 时,发布 MQTT `alarm` 事件。`result` 和 `alarm` 使用 QoS 1;Broker 不可用时会写入 SQLite 离线队列。 在 `configs/device.yaml` 设置 `mqtt.host` 后,Runtime 使用 Paho MQTT 自动连接 Broker;用户名和密码通过 `username_env`、`password_env` 指定的环境变量读取。连接恢复时自动补发 SQLite 离线队列。未配置 `mqtt.host` 时,报警消息会留在离线队列,不会发送到平台。 启用 Broker 的设备配置示例: ```yaml mqtt: host: mqtt.example.internal port: 1883 username_env: JETSON_MQTT_USERNAME password_env: JETSON_MQTT_PASSWORD keepalive_seconds: 30 ``` 在 Jetson shell 或 `/etc/jetson-runtime/runtime.env` 中设置凭据: ```bash JETSON_MQTT_USERNAME=runtime-device JETSON_MQTT_PASSWORD=change-me ``` 平台创建任务时可通过 `config` 控制报警规则: ```json { "camera_id": "ppe-camera-001", "algorithm_id": "ppe-yolo26m", "fps": 8, "config": { "confidence": 0.25, "classes": ["Hard_hat", "Person", "Vest"], "roi": [[0, 0], [1920, 0], [1920, 1080], [0, 1080]], "alarm": { "debounce_frames": 3, "min_duration_ms": 1000, "cooldown_ms": 30000 } } } ``` `roi` 使用原始画面像素坐标,只有检测框中心点在多边形内的对象才参与事件和报警判断。空 `classes` 表示不过滤类别。`confidence` 是任务级二次过滤阈值;将其设为低于模型在 `configs/algorithms.yaml` 中配置的阈值不会恢复已被模型过滤的检测框。 ## 启动 PPE RTSP Runtime RTSP 硬件解码、帧缓冲、调度与断线重连的完整原理见 [RTSP 取流原理](docs/rtsp-streaming.md)。 `configs/algorithms.yaml` 已注册 `models/ppe-yolo26m.engine` 的 `ppe-yolo26m` 算法;`configs/device.yaml` 已定义 `ppe-camera-001` 和自启动任务 `ppe-camera-001-yolo26m`。RTSP URL 只从环境变量读取,避免凭据进入 Git。设置 `JETSON_RTSP_URL` 后启动: ```bash source .venv/bin/activate export JETSON_RTSP_URL='rtsp://admin:password@camera-host:554' python -m app.main ``` 服务默认监听 `0.0.0.0:8000`,并会自动创建和启用 PPE 任务。检查任务状态: ```bash curl -H 'Authorization: Bearer development-token-change-before-deployment' http://127.0.0.1:8000/api/v1/tasks ``` 检查相机、推理 worker 与调度器健康状态: ```bash curl http://127.0.0.1:8000/api/v1/system/health curl -H 'Authorization: Bearer development-token-change-before-deployment' http://127.0.0.1:8000/api/v1/tasks ``` 使用 systemd 时,将 `deploy/runtime.env.example` 复制为 `/etc/jetson-runtime/runtime.env` 并写入实际 `JETSON_RTSP_URL`,然后安装 `deploy/runtime.service`: ```bash sudo install -d -m 700 /etc/jetson-runtime sudo cp deploy/runtime.env.example /etc/jetson-runtime/runtime.env sudo chmod 600 /etc/jetson-runtime/runtime.env sudoedit /etc/jetson-runtime/runtime.env sudo cp deploy/runtime.service /etc/systemd/system/runtime.service sudo systemctl daemon-reload sudo systemctl enable --now runtime journalctl -u runtime -f ``` ## MQTT 主题 ```text device/{device_id}/status QoS 0 device/{device_id}/heartbeat QoS 0 device/{device_id}/result QoS 1 device/{device_id}/alarm QoS 1 ``` 离线期间的 result/alarm 会落入 SQLite;连接恢复后按顺序补发,并附加 `offline: true`。 `result` 事件的 `event` 为 `object_appear` 或 `object_disappear`;报警消息的 `event` 为 `alarm`。两类消息均包含 `task_id`、`camera_id`、`algorithm_id`、`capture_ts`、`latency_ms` 与过滤后的检测结果。使用下列命令可在 Broker 上验证: ```bash mosquitto_sub -h mqtt.example.internal -p 1883 -u "$JETSON_MQTT_USERNAME" -P "$JETSON_MQTT_PASSWORD" \ -t 'device/jetson-local/result' -t 'device/jetson-local/alarm' -v ``` ## YOLO TensorRT 算法 通用 YOLO 适配器位于 `app/algorithm/yolo.py`,支持 YOLOv5 的 `[N, 5+C]` 和 YOLOv8 的 `[4+C, N]` 输出。它负责 RGB letterbox、NCHW float32 归一化、置信度过滤、NMS 和将检测框映射回原图坐标。 Jetson 端执行器在 `app/inference/yolo_tensorrt.py`,使用 TensorRT 10 named I/O API、独立 CUDA stream 与 context session pool。安装 CUDA Python 绑定: ```bash source .venv/bin/activate pip install -e ".[jetson]" ``` 安全帽模型的注册方式: ```python from app.algorithm import YoloDetectionAlgorithm from app.inference import TensorRTYOLOExecutor executor = TensorRTYOLOExecutor( "models/helmet/1.0.0/model.engine", input_shape=(1, 3, 640, 640), worker_count=3, ) algorithm = YoloDetectionAlgorithm( "helmet", "1.0.0", ["helmet", "no_helmet"], executor, ) ``` 将此 `algorithm` 作为 `AlgorithmRegistry` 中 `helmet` 的 factory 返回即可被多个 Task 共享。engine 必须在当前 Jetson 上通过 `trtexec` 生成,不能从 Windows 直接复制。 YOLO26 若导出为包含 TensorRT NMS 的 end-to-end engine,使用: ```python algorithm = YoloDetectionAlgorithm( "helmet", "1.0.0", ["helmet", "no_helmet"], executor, output_format="end_to_end", ) ``` 该模式预期输出为 `[batch, detections, 6]`,每一行为 `x1, y1, x2, y2, score, class_id`,不再重复 NMS。若 engine 输出为原始 `[4 + classes, candidates]`,保持默认 `output_format="raw"`。 ### PPE YOLO26 示例 仓库中的 `models/ppe-yolo26m.pt` 包含以下类别,顺序必须保持一致:`Gloves`、`Hard_hat`、`Mask`、`Person`、`Safety_boots`、`Vest`。 在 Jetson 上先确认 PyTorch 已能使用 CUDA,然后安装导出工具: ```bash source .venv/bin/activate python -c "import torch; print(torch.__version__, torch.cuda.is_available())" pip install ultralytics ``` JetPack 6.2 使用 CUDA 12.6,因此必须固定 `cuda-python>=12.6,<12.7`。不要安装 13.x 或更高的 CUDA 12 minor 版本,运行时兼容 `cuda.cudart` 与 `cuda.bindings.runtime` 两种导入路径。 导出静态 ONNX 并在 **当前 Jetson** 上生成带 NMS 的 engine: ```bash python -c "from ultralytics import YOLO; YOLO('models/ppe-yolo26m.pt').export(format='onnx', imgsz=640, dynamic=False, nms=True, opset=13)" /usr/src/tensorrt/bin/trtexec \ --onnx=models/ppe-yolo26m.onnx \ --saveEngine=models/ppe-yolo26m.engine \ --fp16 --memPoolSize=workspace:1024 ``` 使用一张 JPEG/PNG 图片验证 engine: ```bash python scripts/run_yolo.py \ --engine models/ppe-yolo26m.engine \ --image testdata/ppe.jpg \ --input-size 640 \ --output-format end_to_end \ --classes Gloves Hard_hat Mask Person Safety_boots Vest ``` 命令会输出统一 `DetectionPayload` JSON。若 `trtexec` 显示 engine 输出是原始 `[1, 10, N]`(4 个框参数 + 6 个类别),将最后一项改为 `--output-format raw`。 ## 目标机验收 在 RTSP、真实 TensorRT engine 和 MQTT broker 接入后,在 Orin NX 上完成: 1. 八路混合 FPS 场景连续运行 24 小时,确认无内存增长和任务饿死。 2. 测量 `capture_ts` 到推理结果的 P95 延迟,目标小于 500ms。 3. 断开 MQTT 30 分钟后恢复,确认报警按序补发。 4. 重启设备,确认启用的任务从 SQLite 恢复。 5. 单路 1080p NVDEC 解码 CPU 占用低于 15%,三 worker 压力下 GPU 利用率高于 80%。 部署与运维细节见 [docs/operations.md](docs/operations.md)。