Skip to content

Feat/feishu history - #39

Closed
heyeuu wants to merge 5 commits into
mainfrom
feat/feishu-history
Closed

Feat/feishu history#39
heyeuu wants to merge 5 commits into
mainfrom
feat/feishu-history

Conversation

@heyeuu

@heyeuu heyeuu commented Apr 22, 2026

Copy link
Copy Markdown
Member

PR总结:飞书历史时间戳对齐功能

概述

本PR引入基于摄像机触发事件与控制状态历史的时间戳对齐机制,旨在提高图像帧与控制命令之间的时间同步精度,包含共享内存历史客户端、飞书通信层重构、摄像机触发同步、AutoAim 组件与运行时的若干适配以及对应单元测试。

主要改动

  1. 共享内存历史客户端与映射封装(src/utility/shared/interprocess.hpp)
  • 新增 MappedContext RAII 封装,统一 shm_open/ftruncate/mmap 与清理逻辑。
  • 新增模板 HistoryClient<T, N>,实现固定大小环形缓冲的历史记录:
    • Send/Recv 接口:open/push/is_updated/latest/find_latest/pop_next 等。
    • 每条 Entry 含原子 version/sequence,采用奇偶 version 协议保证读写一致性。
  • 重构现有 Client::Send/Recv,改用 MappedContext 并封装读写访问,移除拷贝操作。
  1. 飞书通信层重构(src/kernel/feishu.hpp)
  • 引入 Channel 抽象与 ChannelTraits 映射,统一通信/历史语义接口。
  • 对 util::ControlState 与新增 util::CameraTriggerEvent 使用 HistoryClient,添加历史容量常量:
    • ControlState 历史容量:4096
    • CameraTriggerEvent 历史容量:512
  • 新增 fetch_latest_matching(...) 与 AutoAim 专用的 fetch_latest_before(timestamp) 等历史查询接口;commit/fetch/updated 维持向后兼容但委托给 Channel。
  1. 新增 CameraTriggerEvent 数据结构(src/utility/shared/context.hpp)
  • 新增 rmcs::util::CameraTriggerEvent { std::uint64_t seq; Clock::time_point timestamp; } 。
  1. 摄像机触发同步(src/kernel/capturer.cpp + 配置)
  • 新增配置项 capturer.enable_trigger_sync(在 config/config.yaml 中设置为 true);仅对 hikcamera 源生效(且 config 中将 hikcamera.fixed_framerate 由 false 改为 true)。
  • 在成功捕获回调中可选进行触发绑定:从 camera_trigger 的历史中查找最符合条件的最近触发(序列单调、触发时间 <= 图像时间、与图像时间差 <= 最大同步年龄),匹配成功则用触发时间覆盖图像时间戳并更新绑定序列与状态;匹配失败则通过限速器(rate limiter)控制告警频率。
  1. AutoAim 组件增强(src/component.cpp)
  • 使用来自预定义输入(/predefined/timestamp)的时间戳替代 Clock::now() 生成 control_state.timestamp。
  • 引入 camera_trigger_channel 与 camera trigger 提交逻辑(提交 util::CameraTriggerEvent):
    • 跳过 seq==0 或重复 seq。
    • 若序列跳跃超过 1,则触发节流的 camera_trigger_gap_detected 警告。
    • 提交失败触发节流的 commit_camera_trigger_failed 并提前返回。
    • 仅在触发输入准备且检查通过时发布 CameraTriggerEvent。
  1. 运行时与控制状态检索(src/runtime.cpp)
  • 用 rclcpp::on_shutdown 替代直接的 SIGINT 处理,调用 util::set_running(false)。
  • fetch_control_state 接口改为接收 image_timestamp,优先调用 feishu.fetch_latest_before(image_timestamp);若历史不可用则降级回 feishu.fetch() 并记录不同警告。
  • 主循环退出条件增加 !rclcpp::ok() 检查。
  1. 测试(test/timestamp_alignment.cpp、test/CMakeLists.txt)
  • 新增 gtest 目标 test_timestamp_alignment,并添加 timestamp_alignment.cpp:
    • 验证 HistoryClient<CameraTriggerEvent, 8> 的 FIFO 消费与时间戳保持。
    • 验证 HistoryClient<ControlState, 8>::find_latest 的按时间/谓词筛选语义。
    • 验证“晚到触发”绑定语义(只有满足单调 seq、时间约束与最大龄限后才能绑定)。
    • 验证 FeishuRuntimeRole::AutoAim::fetch_latest_before 的历史查询行为。
    • 测试使用独立 SHM 名和清理作用域保证测试隔离。

设计亮点

  • 通过 HistoryClient 提供的历史查询能力,实现对过去控制态与触发事件的回溯匹配,从而精确对齐图像时间戳。
  • 使用原子 version 奇偶协议与环形缓冲保证并发读写一致性与有界历史窗口。
  • 告警限速与序列跳跃检测降低日志噪音并提示潜在硬件问题。
  • 在历史不可用时具备平滑降级路径以维持功能可用性。

配置变更

  • config/config.yaml 中新增并启用:capturer.enable_trigger_sync: true
  • capturer.hikcamera.fixed_framerate 从 false 改为 true

影响与注意事项

  • 共享内存层及其 ABI 有较大改动(新增 HistoryClient、MappedContext、Channel 抽象),需要重点审查内存布局、对齐以及多进程并发边界条件。
  • 新增历史容量常量需评估内存占用与 mmap/resize 行为的影响。
  • 触发时间对齐目前仅在配置开启且仅对 Hikcamera 生效。
  • 建议在 CI 中运行新增测试并在多次运行间确保 SHM 名清理以避免残留干扰。

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

添加摄像头触发器与图像时间戳对齐逻辑;引入历史感知的共享内存通道(HistoryClient/Channel/ChannelTraits)与 CameraTriggerEvent;在 Feishu IPC、AutoAim 组件和运行时中加入基于时间戳的对齐查询;新增单元测试与配置项变更。

Changes

Cohort / File(s) Summary
配置
config/config.yaml
新增 capturer.enable_trigger_sync: true,并将 capturer.hikcamera.fixed_frameratefalse 改为 true
捕获器时间对齐
src/kernel/capturer.cpp
在捕获成功路径中(仅对 hikcamera 且启用时)查询 CameraTriggerEvent 历史并在匹配时用触发 timestamp 覆盖图像时间戳;维护 last_bound_trigger_seq_,并对缺失触发做速率限制告警。
Feishu IPC 与通道抽象
src/kernel/feishu.hpp
重构为基于 Channel<T>/ChannelTraits<T> 的实现,Feishu 委托 Channel 并新增 fetch_latest_before();切换 ControlState/CameraTriggerEvent 到 HistoryClient 后端。
共享内存与历史缓冲实现
src/utility/shared/interprocess.hpp
新增 MappedContext 封装共享内存映射;新增 HistoryClient<T,N> 实现固定环形历史缓冲(Send/Recv/查找/弹出等);Client 读写改用映射辅助。
共享类型
src/utility/shared/context.hpp
新增 rmcs::util::CameraTriggerEvent { std::uint64_t seq; Clock::time_point timestamp; } 与相关 shm 名称/容量常量。
AutoAim 与触发发布
src/component.cpp
注册相机触发输入并维护触发序列,提交 control_state 后条件发布 CameraTriggerEvent(跳序检测、节流告警、提交失败处理)。
运行时与控制态检索
src/runtime.cpp
用 rclcpp 关闭钩子替代 SIGINT;fetch_control_state 改为接收 image_timestamp 并优先调用 feishu.fetch_latest_before(image_timestamp),主循环终止条件包含 !rclcpp::ok()
预测器稳健性修正
src/module/predictor/.../robot_state.cpp
在两个 predictor 的 predict(t) 中加入 if (t <= time_stamp) return; 以防非递增时间导致负或零 dt。
测试与构建
test/CMakeLists.txt, test/timestamp_alignment.cpp
新增 test_timestamp_alignment 单元测试,覆盖 HistoryClient 顺序/查找、触发对齐语义及 Feishu::fetch_latest_before

Sequence Diagram(s)

sequenceDiagram
    participant Cap as Capturer
    participant Hist as HistoryClient<br/>CameraTriggerEvent
    participant Q as CaptureQueue
    participant Img as Image

    Cap->>Cap: capture_success(img)
    activate Cap
    Cap->>Hist: fetch_latest_matching(predicate: seq>last_bound && ts<=img.ts && age<=max_age)
    activate Hist
    alt 匹配到触发事件
        Hist-->>Cap: CameraTriggerEvent(seq, timestamp)
        Cap->>Img: 覆盖 image.timestamp = trigger.timestamp
        Cap->>Cap: 更新 last_bound_trigger_seq_, reset rate limiter
    else 未匹配
        Hist-->>Cap: 无匹配
        Cap->>Cap: 增加速率限制计数并可能记录警告
    end
    deactivate Hist
    Cap->>Q: push(image)  // 入队(可能已对齐)
    deactivate Cap
Loading
sequenceDiagram
    participant RT as Runtime
    participant Auto as AutoAimComponent
    participant Fei as Feishu<AutoAim>
    participant HistS as HistoryClient<br/>ControlState

    RT->>Auto: 传入 image_timestamp
    activate Auto
    Auto->>Fei: fetch_latest_before(image_timestamp)
    activate Fei
    Fei->>HistS: find_latest(state.timestamp <= image_timestamp)
    activate HistS
    alt 找到匹配 ControlState
        HistS-->>Fei: 返回 ControlState
        Fei-->>Auto: 返回对齐 ControlState
    else 未找到或历史不可用
        HistS-->>Fei: 返回空
        Fei-->>Auto: std::nullopt
    end
    deactivate HistS
    deactivate Fei
    Auto->>Auto: 处理或提交 control_state(或警告/回退)
    deactivate Auto
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • creeper5820

兔子诗

🐰 触发声轻轻敲,
时钟与画面共跳,
共享历史织新篇,
兔耳欣喜跳三跳,
对齐成功乐逍遥。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题描述了主要变化的实质内容——引入 Feishu 历史记录功能,与包括配置更新、CameraTriggerEvent、HistoryClient 和时间戳同步等核心改动相符。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/feishu-history

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/component.cpp`:
- Around line 146-151: publish_camera_trigger_event() is currently called before
feishu.commit(control_state), causing the trigger to be visible to AutoAim
before the ControlState with the same timestamp; move the commit so
feishu.commit(control_state) is executed before publish_camera_trigger_event()
inside publish_control_state(), and apply the same reorder to the other
occurrence around lines 176-179 (i.e., ensure update_gimbal_direction(),
update_control_state(), then feishu.commit(control_state), then
publish_camera_trigger_event()) so the trigger always follows the committed
ControlState.
- Around line 160-179: In publish_camera_trigger_event, avoid unguarded
dereferences of camera_trigger_seq_ and camera_trigger_timestamp_; first check
that the InputInterface/read handles are ready (e.g.,
camera_trigger_seq_.has_value() or an isReady() method) and only read
*camera_trigger_seq_ and *camera_trigger_timestamp_ when confirmed, otherwise
use a safe fallback (skip commit/return early or provide a default timestamp)
and ensure action_throttler logic still behaves correctly; update references to
camera_trigger_seq_, camera_trigger_timestamp_,
last_committed_camera_trigger_seq_, camera_trigger_channel.commit(...) and
action_throttler.dispatch/reset to operate only after readiness is verified.

In `@src/kernel/capturer.cpp`:
- Around line 115-123: 在 camera_trigger_channel.fetch_latest_matching
的匹配条件中加入对“上一帧原始图像时间戳”的下限检查,防止迟到触发被绑定到下一帧:新增并维护一个如 last_frame_raw_timestamp(初始为 0
或最小时间)并在每帧开始或绑定后更新它,然后在 lambda 中除了现有条件(candidate.seq > last_bound_trigger_seq_
&& candidate.timestamp <= capture_timestamp && capture_timestamp -
candidate.timestamp <= trigger_sync_max_age)再加上 candidate.timestamp >
last_frame_raw_timestamp;最后在成功绑定(在设置
image->set_timestamp/last_bound_trigger_seq_ 之前或之后按逻辑)更新
last_frame_raw_timestamp = previous capture_timestamp(即把当前帧的原始 capture_timestamp
保存为下一帧的下限)。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 07515262-70fb-496a-befb-918c3c5e18b1

📥 Commits

Reviewing files that changed from the base of the PR and between f2b16f1 and eb1fcb0.

📒 Files selected for processing (9)
  • config/config.yaml
  • src/component.cpp
  • src/kernel/capturer.cpp
  • src/kernel/feishu.hpp
  • src/runtime.cpp
  • src/utility/shared/context.hpp
  • src/utility/shared/interprocess.hpp
  • test/CMakeLists.txt
  • test/timestamp_alignment.cpp

Comment thread src/component.cpp
Comment thread src/component.cpp Outdated
Comment thread src/kernel/capturer.cpp
@heyeuu heyeuu added the enhancement New feature or request label Apr 23, 2026
@heyeuu heyeuu moved this from Todo to In progress in RMCS Auto Aim V2 Apr 23, 2026
@heyeuu heyeuu added this to the 火控及控制模块 milestone Apr 23, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/kernel/capturer.cpp`:
- Around line 70-71: The code unconditionally calls
yaml["enable_trigger_sync"].as<bool>() which throws if the key is missing;
change logic in the initialization that sets enable_trigger_sync so you only
access yaml["enable_trigger_sync"] when source == "hikcamera" (e.g., evaluate
trigger_sync_config only inside the branch) or use yaml["enable_trigger_sync"]
with a safe default (check for existence with yaml[...].IsDefined() or use a
fallback) before calling .as<bool>(); update the assignment that uses
trigger_sync_config and ensure enable_trigger_sync remains false (or a safe
default) for non-"hikcamera" sources.

In `@test/timestamp_alignment.cpp`:
- Around line 27-35: The file uses std::move inside the ShmScope constructor
initializer (ShmScope::ShmScope and name_) but does not directly include
<utility>; add a direct include for <utility> at the top of the file so
std::move is properly declared and the dependency is explicit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 96cae677-93bc-4e0a-9401-93f50c36d9de

📥 Commits

Reviewing files that changed from the base of the PR and between eb1fcb0 and e75b44b.

📒 Files selected for processing (5)
  • src/component.cpp
  • src/kernel/capturer.cpp
  • src/module/predictor/outpost/robot_state.cpp
  • src/module/predictor/regular/robot_state.cpp
  • test/timestamp_alignment.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/component.cpp

Comment thread src/kernel/capturer.cpp Outdated
Comment thread test/timestamp_alignment.cpp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/kernel/capturer.cpp (1)

70-70: ⚠️ Potential issue | 🟠 Major

enable_trigger_sync 保留默认值,避免旧版 hikcamera 配置启动失败。

Line 70 已经避免了非 hikcamera 配置读取该字段,但 hikcamera 配置缺少新增键时仍会直接 .as<bool>() 并导致初始化失败;这个开关建议默认关闭以保持配置向后兼容。

建议修改
-        enable_trigger_sync = source == "hikcamera" && yaml["enable_trigger_sync"].as<bool>();
+        enable_trigger_sync =
+            source == "hikcamera" && yaml["enable_trigger_sync"].as<bool>(false);

可用下面的只读脚本检查仓库内是否还有 hikcamera 配置未声明该新增键;预期结果是不输出缺失文件:

#!/bin/bash
set -euo pipefail

fd -e yaml -e yml | while IFS= read -r file; do
  if rg -q -P 'source:\s*["'\''"]?hikcamera["'\''"]?\s*$' "$file" \
     && ! rg -q -P 'enable_trigger_sync\s*:' "$file"; then
    printf 'hikcamera config missing enable_trigger_sync: %s\n' "$file"
  fi
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/kernel/capturer.cpp` at line 70, 当前代码直接对 hikcamera 配置做
yaml["enable_trigger_sync"].as<bool>(),如果该键缺失会抛异常,需保留默认关闭并只在键存在时读取; change the
initialization of enable_trigger_sync to a safe default (false) and then, inside
the existing source == "hikcamera" branch, check the YAML node existence before
calling as<bool>() — e.g. use yaml["enable_trigger_sync"] &&
yaml["enable_trigger_sync"].IsDefined() (or
yaml["enable_trigger_sync"].as<bool>(false) if yaml-cpp overload is preferred)
to set enable_trigger_sync, referring to the symbol enable_trigger_sync in
src/kernel/capturer.cpp.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/kernel/capturer.cpp`:
- Line 70: 当前代码直接对 hikcamera 配置做
yaml["enable_trigger_sync"].as<bool>(),如果该键缺失会抛异常,需保留默认关闭并只在键存在时读取; change the
initialization of enable_trigger_sync to a safe default (false) and then, inside
the existing source == "hikcamera" branch, check the YAML node existence before
calling as<bool>() — e.g. use yaml["enable_trigger_sync"] &&
yaml["enable_trigger_sync"].IsDefined() (or
yaml["enable_trigger_sync"].as<bool>(false) if yaml-cpp overload is preferred)
to set enable_trigger_sync, referring to the symbol enable_trigger_sync in
src/kernel/capturer.cpp.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 241ee6a0-a603-4bce-be58-cdd955d45420

📥 Commits

Reviewing files that changed from the base of the PR and between e75b44b and b32a554.

📒 Files selected for processing (2)
  • src/kernel/capturer.cpp
  • test/timestamp_alignment.cpp

@github-project-automation github-project-automation Bot moved this from In progress to Done in RMCS Auto Aim V2 Apr 24, 2026
@heyeuu
heyeuu deleted the feat/feishu-history branch April 29, 2026 03:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants