5.5 KiB
5.5 KiB
Common 模块开发指南
common/ 保存可被设备、算法、管理器和协议层复用的基础能力。这里适合放稳定、协议无关、厂商无关的类型与工具,不适合放设备连接、业务服务或任务调度逻辑。
返回项目总览。
目录职责
| 目录 | 职责 |
|---|---|
base/ |
日志、基础常量、gRPC 辅助函数和线程安全缓冲区 |
config/ |
配置根目录解析和 Proto Text 配置加载 |
io/ |
Protobuf 二进制与 TextFormat 文件读写 |
math/ |
坐标变换、关节限制、QP 和运动数学 |
media/ |
协议无关媒体模型以及 FFmpeg 采集、编码、写文件能力 |
types/ |
跨后端共享的领域类型,例如 AGV、机械臂和几何类型 |
vision/ |
图像显示、投影等视觉辅助代码 |
依赖边界
新增公共组件时应遵守:
- 不依赖
service/、task/或具体厂商设备实现; - 不保存 gRPC/QUIC 连接、session 或客户端状态;
- 通用类型不包含厂商报文字段、端口号和私有错误码;
- 需要调用设备的逻辑应放在 manager adapter、service 或 task;
- 需要第三方库的
.cpp组件应通过明确的 CMake target 暴露依赖; - 避免在公共头文件中使用全局
using namespace或引入大体量实现头。
当前 common 共享库目标是 cmvr_es::common,日志是独立目标 cmvr_es::logging。新增 .cpp 文件时,需要更新 CMakeLists.txt 或对应子目录 CMake;纯头文件不需要加入 add_library 源文件列表。
新增共享类型
- 选择
types/<domain>/或已有领域文件; - 类型使用明确单位,例如米、弧度、秒、纳秒;
- 为容器长度、自由度和数值范围提供校验函数;
- 保持控制器无关,将厂商字段转换为通用枚举或结果;
- 确认不会迫使所有调用方引入设备 SDK;
- 增加边界值和错误输入测试。
AGV 通用类型应参考 types/agv/agv_types.h,机械臂通用类型应参考 types/arm/arm_types.h。不要为了一个具体控制器把协议结构塞回 abstract_*.h。
媒体模型
media/media_frame.h 中的 TrackDescriptor、MediaFrame 及 payload 在构造后不可变,可被多个协议消费者共享。
扩展媒体字段时需要保持:
TrackDescriptor::generation非零,编码参数变化时创建新 descriptor;- PTS、DTS 和 duration 使用 descriptor 的
time_base; capture_time_ns使用单调时钟,供节奏控制和延迟统计;capture_utc_ns只作为可选墙上时间,不能用于计算持续时间;- H.264/H.265 明确
ANNEX_B或AVCC; - AAC、Opus、PCM 明确 payload format、采样率和声道数;
- 不把 QUIC、gRPC 或浏览器专有字段加入通用帧。
设备媒体接入流程见 ../manager/README.md 的 MediaSourceHub 章节。
环形队列选择
base/ring_buffer.h 当前包含三类缓冲区:
| 类型 | 使用场景 | 重要约束 |
|---|---|---|
RingBuffer<T> |
只需要保存最近 N 项并批量读取 | 覆盖最旧项,没有阻塞读取 |
SPMCRingBuffer<T> |
历史单生产者场景 | 独立 reader_tail 只能由一个线程拥有 |
BroadcastFrameRing<T> |
新的媒体或广播式多消费者场景 | 每个消费者使用独立 Cursor,保存不可变共享对象 |
新的实时多消费者模块优先使用 BroadcastFrameRing<T>:
- capacity 必须大于零;
- 同一 Cursor 不得被多个线程同时读取或移动;
- 慢消费者落后时会跳到最旧保留项,并得到精确 dropped count;
reset()开启新 generation,旧 Cursor 在下一次成功读取时看到变化;close()唤醒等待者,关闭后不能继续发布;- 不要先读取 head 再无锁读取槽位,应使用队列提供的原子读取接口。
配置和文件路径
resolveConfigFile():相对根配置目录解析业务配置;resolveResourceFile():在配置根及其父目录中查找模型等资源;loadConfigFile()/saveConfigFile():读写 Proto Text 配置。
进程启动后配置根由 main.cpp 设置。公共组件不应自行使用当前工作目录拼接配置路径。
io/proto_file_io.h 写出的 TextFormat 文件权限为 0600。保存运行时配置前,应确认目标目录存在,并避免把生产密钥写入仓库。
新增公共组件
- 确认能力确实会被两个及以上模块复用;
- 定义最小 API 和所有权、线程安全、错误语义;
- 将头文件放入合适子目录,将实现放入相邻
.cpp; - 更新 CMake target 和
target_link_libraries; - 不使用未声明的传递依赖;
- 增加无设备单元测试;
- 对并发组件增加关闭、超时、覆盖、取消和析构测试;
- 使用 ASan/TSan 时检查生命周期和数据竞争。
推荐测试目标放在组件相邻的 tests/,并在 BUILD_TESTING 下通过 add_test() 登记。仅创建 _test 可执行文件不会自动进入 CTest。
提交检查
- API 不依赖具体设备或传输协议
- 公共类型有明确单位和有效性规则
- 所有权及线程安全写入注释
- 新增
.cpp和依赖已经加入 CMake - 缓冲区关闭能够唤醒等待线程
- 不记录密码、私钥或大块媒体 payload
- 无设备测试可以在开发主机运行