cmvr-es/cmvr-es/common/README.md

5.5 KiB
Raw Blame History

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 源文件列表。

新增共享类型

  1. 选择 types/<domain>/ 或已有领域文件;
  2. 类型使用明确单位,例如米、弧度、秒、纳秒;
  3. 为容器长度、自由度和数值范围提供校验函数;
  4. 保持控制器无关,将厂商字段转换为通用枚举或结果;
  5. 确认不会迫使所有调用方引入设备 SDK
  6. 增加边界值和错误输入测试。

AGV 通用类型应参考 types/agv/agv_types.h,机械臂通用类型应参考 types/arm/arm_types.h。不要为了一个具体控制器把协议结构塞回 abstract_*.h

媒体模型

media/media_frame.h 中的 TrackDescriptorMediaFrame 及 payload 在构造后不可变,可被多个协议消费者共享。

扩展媒体字段时需要保持:

  • TrackDescriptor::generation 非零,编码参数变化时创建新 descriptor
  • PTS、DTS 和 duration 使用 descriptor 的 time_base
  • capture_time_ns 使用单调时钟,供节奏控制和延迟统计;
  • capture_utc_ns 只作为可选墙上时间,不能用于计算持续时间;
  • H.264/H.265 明确 ANNEX_BAVCC
  • 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 再无锁读取槽位,应使用队列提供的原子读取接口。

配置和文件路径

config/config_files.h 提供:

  • resolveConfigFile():相对根配置目录解析业务配置;
  • resolveResourceFile():在配置根及其父目录中查找模型等资源;
  • loadConfigFile() / saveConfigFile():读写 Proto Text 配置。

进程启动后配置根由 main.cpp 设置。公共组件不应自行使用当前工作目录拼接配置路径。

io/proto_file_io.h 写出的 TextFormat 文件权限为 0600。保存运行时配置前,应确认目标目录存在,并避免把生产密钥写入仓库。

新增公共组件

  1. 确认能力确实会被两个及以上模块复用;
  2. 定义最小 API 和所有权、线程安全、错误语义;
  3. 将头文件放入合适子目录,将实现放入相邻 .cpp
  4. 更新 CMake target 和 target_link_libraries
  5. 不使用未声明的传递依赖;
  6. 增加无设备单元测试;
  7. 对并发组件增加关闭、超时、覆盖、取消和析构测试;
  8. 使用 ASan/TSan 时检查生命周期和数据竞争。

推荐测试目标放在组件相邻的 tests/,并在 BUILD_TESTING 下通过 add_test() 登记。仅创建 _test 可执行文件不会自动进入 CTest。

提交检查

  • API 不依赖具体设备或传输协议
  • 公共类型有明确单位和有效性规则
  • 所有权及线程安全写入注释
  • 新增 .cpp 和依赖已经加入 CMake
  • 缓冲区关闭能够唤醒等待线程
  • 不记录密码、私钥或大块媒体 payload
  • 无设备测试可以在开发主机运行