Skip to content

refactor: identifier and visualization pipeline#56

Merged
creeper5820 merged 5 commits into
mainfrom
refactor/identifier-and-visualization
Jun 6, 2026
Merged

refactor: identifier and visualization pipeline#56
creeper5820 merged 5 commits into
mainfrom
refactor/identifier-and-visualization

Conversation

@creeper5820
Copy link
Copy Markdown
Collaborator

No description provided.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

Walkthrough

本PR统一Armor/Lightbar类型命名(大写→小写 d),重构绿灯与邻接光条检测接口与实现,新增 CameraFeature.from 与 PoseEstimator::configure_camera,推出 drawable/Canvas 与可视化 Armors 发布器,并将运行时调用流水线迁移为 draw_later/publish 模式。

Changes

统一类型与系统管道重构

Layer / File(s) Summary
核心数据契约与数学接口
src/utility/robot/armor.hpp, src/utility/math/camera.{hpp,cpp}, src/utility/math/outpost.{hpp,cpp}, src/utility/math/reprojection.{hpp,cpp}
重命名 Armor2D/Armor3DArmor2d/Armor3d,新增 Lightbar2d/Lightbar3dCameraFeature::fromcv_orientation()/cv_translation(),新增 ReprojectionSolution 与 project_points 实现。
识别子系统重构
src/module/identifier/{green_light,adjacency_lightbar,armor_detection}.*, src/kernel/identifier.*
替换 GreenLightLocator→GreenLightFinder,AdjacencyLightbarFinder::find 返回 Result(包含 found/predicted/areas/center),ArmorDetection::sync_detect 改为返回 std::vector<Armor2d>(不再 optional),Identifier 聚合与过滤路径更新并移除旧绘制转发。
位姿估计与 PnP 优化
src/kernel/pose_estimator.{hpp,cpp}, src/utility/math/solve_pnp/*
新增 Addition 结构与 configure_camera(std::array, std::array),新增 RobustPnpSolution 与 Reprojection 优化流程,estimate_armor 返回类型为 Armor3ds 并移除旧 debug/publish 包装。
可视化绘制与发布链路重构
src/kernel/visualization.{hpp,cpp}, config/config.yaml, src/runtime.cpp
新增 publishable/drawable/enable_stream 配置,Visualization 初始化签名与 update_image 参数变更,新增 draw_later/publish 与按 name Armors 发布器;图像流推送在 drawable 开启时使用 Canvas 渲染后通过 session 推送。
Canvas 与可绘制类型实现
src/utility/image/drawable.{hpp,cpp}
新增 Canvas、Text/Area、IDrawable/Drawable 模板与多个 draw 重载,用于绘制 Armor2d/Lightbar2d/Rect/Text。
ROS 可视化 Armors 管理
src/utility/rclcpp/visual/armor.{hpp,cpp}
新增 util::visual::Armors,实现按 name 复用发布器、生成 CUBE/ARROW/DELETE marker 并发布 MarkerArray。
跟踪/预测/火控类型同步
src/kernel/tracker.*, src/module/predictor/**, src/module/fire_control/aim_point_chooser.*
将 Tracker/Decider/RobotState/Snapshot/Backends/FireControl 接口统一为 Armor2d/Armor3d,对应实现同步调整。
测试与工具适配
test/*, tool/cxx/*
测试断言从 optional→容器 empty 语义切换,测试和工具代码改为使用 Armor3d,see_outpost 等工具改用 Lightbar3d.upper/lower
旧实现移除/清理
多处 green_light_detection/green_light_locator/armor_visualizer/utility/image/armor.* 被移除或替换
删除旧绘制与绿灯检测实现,移除 Capturer::get_prefix 声明与若干过时头文件引用。

Estimated code review effort:
🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs:

🐰 小白兔忙又俏,
字母小写换新装,
绿灯寻踪换新桥,
画布挥笔发光芒,
发布器把标记送上航。

✨ 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 refactor/identifier-and-visualization

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/utility/robot/id.hpp (1)

58-76: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

to_string 对非法 DeviceId 的处理没有 fail-fast。

Line 75 当前返回 "UNREACHABLE",会把非法参数静默传递到后续逻辑。建议改为显式错误路径(如断言/终止并附带错误信息),避免继续使用伪值。

As per coding guidelines "Use fail-fast strategy by default: perform comprehensive verification during construction/initialization phase, report explicit errors for illegal parameters instead of using default values".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/robot/id.hpp` around lines 58 - 76, The to_string(DeviceId)
function currently returns the silent sentinel "UNREACHABLE" for an invalid
DeviceId; change this to a fail-fast behavior: replace the final return with an
explicit abort/assertion that reports the illegal DeviceId (include the enum
value cast to its underlying integer) so callers cannot continue with a bogus
string. Update to_string to call an assertion or std::terminate with a clear
message (and add the needed include for <cassert> or <cstdlib>), keeping the
failure path in the function handling of DeviceId.
🧹 Nitpick comments (11)
src/module/predictor/outpost/robot_state.hpp (2)

13-29: ⚡ Quick win

RMCS_PIMPL_DEFINITION 建议放到类定义顶部。

这里宏位于类体尾部,和项目约定不一致,建议与其他模块保持同一布局风格。

♻️ 建议修改
 class OutpostRobotState {
+    RMCS_PIMPL_DEFINITION(OutpostRobotState)
+
 public:
     using EKF = OutpostEKFParameters::EKF;
@@
-    RMCS_PIMPL_DEFINITION(OutpostRobotState)
 };

As per coding guidelines, RMCS_PIMPL_DEFINITION macro should be placed at the top of class/struct definitions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/predictor/outpost/robot_state.hpp` around lines 13 - 29, Move the
RMCS_PIMPL_DEFINITION macro to the top of the OutpostRobotState class definition
to match project convention; specifically, place
RMCS_PIMPL_DEFINITION(OutpostRobotState) immediately after the opening of class
OutpostRobotState { and before the public: section so the PIMPL macro appears at
the top of the class alongside other classes that follow the same layout.

3-10: ⚡ Quick win

请统一为“本地头文件优先”的 include 顺序。

当前顺序是标准库在前、本地头文件在后,和仓库约定不一致。

♻️ 建议修改
-#include <chrono>
-#include <span>
-
 `#include` "module/predictor/outpost/ekf_parameter.hpp"
 `#include` "module/predictor/snapshot.hpp"
 `#include` "utility/clock.hpp"
 `#include` "utility/pimpl.hpp"
+
+#include <chrono>
+#include <span>

As per coding guidelines, Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/predictor/outpost/robot_state.hpp` around lines 3 - 10, The
include order in robot_state.hpp currently places standard headers (<chrono>,
<span>) before project headers; reorder them to follow the repo convention: list
local/project headers first ("module/predictor/outpost/ekf_parameter.hpp",
"module/predictor/snapshot.hpp", "utility/clock.hpp", "utility/pimpl.hpp"), then
a blank line, then standard library headers (<chrono>, <span>), ensuring the
groups are separated by a blank line and preserving existing includes.
src/kernel/tracker.hpp (1)

3-10: ⚡ Quick win

头文件分组顺序与项目规范不一致。

建议将本地头文件放在最前,再放标准库、最后第三方库,以保持全仓一致性。

♻️ 建议修改
-#include <expected>
-#include <span>
-#include <yaml-cpp/yaml.h>
-
 `#include` "module/tracker/decider.hpp"
 `#include` "utility/clock.hpp"
 `#include` "utility/pimpl.hpp"
 `#include` "utility/robot/armor.hpp"
+
+#include <expected>
+#include <span>
+
+#include <yaml-cpp/yaml.h>

As per coding guidelines, Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/tracker.hpp` around lines 3 - 10, The include order in the file is
not following project guidelines: put local project headers first (e.g.,
"module/tracker/decider.hpp", "utility/clock.hpp", "utility/pimpl.hpp",
"utility/robot/armor.hpp"), then standard library headers (<expected>, <span>),
and finally third‑party headers (<yaml-cpp/yaml.h>), with a blank line between
each group; reorder the includes accordingly so the header groups and spacing
match the coding standard.
test/aim_point_chooser.cpp (1)

1-16: ⚡ Quick win

测试文件 include 分组顺序建议按仓库规范调整。

建议先放本地头文件,再标准库,最后第三方库,减少风格不一致。

♻️ 建议修改
+#include "module/fire_control/aim_point_chooser.hpp"
+#include "utility/math/angle.hpp"
+
 `#include` <array>
 `#include` <cmath>
 `#include` <initializer_list>
 `#include` <memory>
 `#include` <optional>
 `#include` <random>
 `#include` <span>
 `#include` <string>
 `#include` <vector>
 
 `#include` <eigen3/Eigen/Geometry>
 `#include` <gtest/gtest.h>
-
-#include "module/fire_control/aim_point_chooser.hpp"
-#include "utility/math/angle.hpp"

As per coding guidelines, Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/aim_point_chooser.cpp` around lines 1 - 16, Reorder the include block in
test/aim_point_chooser.cpp to follow the project guideline: place local headers
first (e.g., "module/fire_control/aim_point_chooser.hpp" and
"utility/math/angle.hpp"), then standard library headers (array, cmath,
initializer_list, memory, optional, random, span, string, vector), and finally
third‑party headers (Eigen and gtest). Ensure blank lines separate these groups
and keep the same header names so functions/classes referenced by the test (like
symbols from aim_point_chooser.hpp and angle.hpp) remain resolvable.
src/module/fire_control/aim_point_chooser.cpp (1)

1-8: ⚡ Quick win

请按仓库约定重排 include 分组顺序。

当前把本地头文件拆成了两段(标准库前后各一段),建议合并为“本地头文件 -> 标准库 -> 第三方库”的顺序,减少后续维护时的风格漂移。

♻️ 建议修改
 `#include` "aim_point_chooser.hpp"
+#include "utility/math/conversion.hpp"
+#include "utility/serializable.hpp"
 
 `#include` <cmath>
 `#include` <tuple>
 `#include` <vector>
-
-#include "utility/math/conversion.hpp"
-#include "utility/serializable.hpp"

As per coding guidelines, Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/fire_control/aim_point_chooser.cpp` around lines 1 - 8, 把 include
分组并按仓库约定重排:将所有本地/项目头(例如
"aim_point_chooser.hpp"、"utility/math/conversion.hpp"、"utility/serializable.hpp")合并到一个连续块(首组),然后空一行,接着放标准库头(例如
<cmath>, <tuple>, <vector>)作为第二组;确保没有将本地头分散到标准库前后,保持三组(本地 -> 标准 ->
第三方)或合并为两组时本地在前。
src/module/tracker/armor_filter.hpp (1)

3-4: ⚡ Quick win

为公开接口补齐直接依赖头文件。

当前头文件在公开签名中使用 std::span / std::vector,但未直接包含 <span><vector>;这会使该头文件依赖传递包含,后续上游头文件调整时容易触发编译回归。

♻️ 建议修改
 `#pragma` once
 
 `#include` "utility/pimpl.hpp"
 `#include` "utility/robot/armor.hpp"
+#include <span>
+#include <vector>
 namespace rmcs::tracker {

As per coding guidelines **/*.{h,hpp,cpp,cc,cxx}: Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups.

Also applies to: 14-14

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/tracker/armor_filter.hpp` around lines 3 - 4, 头文件中公开签名使用了
std::span 与 std::vector,但 armor_filter.hpp 只包含本地头 "utility/pimpl.hpp" 和
"utility/robot/armor.hpp";请在该头文件直接添加缺失的标准库包含(#include <span> 和 `#include`
<vector>),并按项目约定把本地头、标准库、第三方库分别分组且用空行分隔(即保留 "utility/pimpl.hpp" 和
"utility/robot/armor.hpp" 为本地组,并将 <span> 和 <vector>
放入标准库组),以消除对传递包含的依赖并避免将来编译回归。
src/module/predictor/snapshot.hpp (1)

3-11: ⚡ Quick win

调整头文件分组顺序以符合仓库约定。

Line 3-11 当前是“第三方/标准库在前,本地头在后”,与仓库规定不一致;建议改为“本地头 → 标准库 → 第三方库”,并保留分组空行。

建议修改
-#include <eigen3/Eigen/Core>
-#include <memory>
-#include <vector>
-
 `#include` "utility/clock.hpp"
 `#include` "utility/math/kalman_filter/ekf.hpp"
 `#include` "utility/robot/armor.hpp"
 `#include` "utility/robot/id.hpp"
+
+#include <memory>
+#include <vector>
+
+#include <eigen3/Eigen/Core>

As per coding guidelines **/*.{h,hpp,cpp,cc,cxx}: Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/module/predictor/snapshot.hpp` around lines 3 - 11, Reorder the includes
in snapshot.hpp so local headers come first, then standard library headers, then
third-party headers: group and place "utility/clock.hpp",
"utility/math/kalman_filter/ekf.hpp", "utility/robot/armor.hpp",
"utility/robot/id.hpp" before <memory> and <vector>, and put <eigen3/Eigen/Core>
last; keep a single blank line between each group to match the repository header
ordering convention.
src/kernel/identifier.hpp (1)

20-22: ⚡ Quick win

补齐 <vector> 直接依赖,避免头文件对传递包含的耦合

Result::areas 在 Line 22 直接使用了 std::vector,建议在头文件显式 #include <vector>,避免未来上游头文件变动导致编译脆弱性。

建议修改
 `#include` <expected>
 `#include` <optional>
+#include <vector>
 
 `#include` <opencv2/core/types.hpp>
 `#include` <yaml-cpp/node/node.h>

As per coding guidelines "Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/identifier.hpp` around lines 20 - 22, The header is using
std::vector for Result::areas but doesn't directly include <vector>, making
compilation fragile; add an explicit `#include` <vector> at the top of this header
and ensure includes follow the project's ordering (local headers, blank line,
standard library like <vector>, then third-party headers) so Result::areas
resolves without relying on transitive includes.
src/utility/image/drawable.hpp (1)

1-4: ⚡ Quick win

为头文件补齐标准库依赖,避免隐式传递包含

当前声明直接依赖了 std::string / std::uint8_t / std::declval / std::move,建议显式包含对应标准头,减少编译脆弱性。

建议修改
 `#pragma` once
 `#include` "utility/image/image.hpp"
 `#include` "utility/robot/armor.hpp"
+
+#include <concepts>
+#include <cstdint>
+#include <string>
+#include <utility>

As per coding guidelines "Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups (can be merged into one block if few headers)".

Also applies to: 7-29

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/image/drawable.hpp` around lines 1 - 4, The header currently
relies on standard types/functions (std::string, std::uint8_t, std::move,
std::declval) without explicitly including their headers; update drawable.hpp to
explicitly include the needed standard headers (<string>, <cstdint>, <utility>)
and reorder headers to follow the guideline (local headers first, then a blank
line, then standard library headers), ensuring includes for
"utility/image/image.hpp" and "utility/robot/armor.hpp" remain present and the
new standard headers are added immediately after with a separating blank line.
src/kernel/pose_estimator.hpp (1)

35-35: 💤 Low value

考虑将 addition() 声明为 const 成员函数

该方法仅返回内部数据的 const 引用,不修改对象状态,声明为 const 更符合语义且允许在 const 上下文中调用。

♻️ 建议修改
-    auto addition() -> const Addition&;
+    auto addition() const -> const Addition&;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.hpp` at line 35, 将成员函数 addition() 从非 const 声明改为
const 成员函数:在声明 auto addition() -> const Addition&; 后加上 const(即 auto addition()
const -> const Addition&;),并同步更新对应的定义/实现(pose_estimator::addition)以在签名中包含尾随
const,以便方法可在 const 对象上调用且语义正确。
src/kernel/visualization.hpp (1)

3-11: ⚡ Quick win

头文件包含顺序与编码规范不符

根据编码规范,头文件应按以下顺序排列:本地头文件、标准库、第三方库,并用空行分隔。当前顺序为标准库 → 第三方 → 本地,建议调整。

♻️ 建议修改
 `#pragma` once

+#include "utility/image/drawable.hpp"
+#include "utility/image/image.hpp"
+#include "utility/robot/armor.hpp"
+
 `#include` <expected>
 `#include` <span>
 `#include` <string>

 `#include` <yaml-cpp/yaml.h>
-
-#include "utility/image/drawable.hpp"
-#include "utility/image/image.hpp"
-#include "utility/robot/armor.hpp"

As per coding guidelines: "Header files should follow the order: local headers, standard library, third-party libraries, with blank lines separating these groups"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/visualization.hpp` around lines 3 - 11, Reorder the `#include` block
in visualization.hpp to follow the project's header ordering: first local
headers ("utility/image/drawable.hpp", "utility/image/image.hpp",
"utility/robot/armor.hpp"), then standard library headers (<expected>, <span>,
<string>), then third-party headers (<yaml-cpp/yaml.h>), and insert a blank line
between each group; update the include sequence in the file accordingly so the
file matches the coding guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/kernel/identifier.cpp`:
- Around line 69-78: 当前逻辑只用 result.green_light->y 作为阈值并且仅过滤
ArmorGenre::OUTPOST/BASE,导致低于绿灯矩形下边缘的误检和其它类型装甲未被过滤;请在检测到 result.green_light
时把阈值改为 result.green_light->y + result.green_light->height,并修改用于
std::erase_if(detected, pred) 的 pred(或替换该谓词)为针对所有 Armor 项比较 armor.bl.y <
(green_light->y + green_light->height) 的条件,移除对 ArmorGenre::OUTPOST/BASE
的专门判断以对所有装甲生效。

In `@src/module/identifier/armor_detection.hpp`:
- Line 19: The current sync_detect(const Image&) noexcept ->
std::vector<Armor2d> signature swallows all error cases (empty image, ROI
failure from generate_openvino_request(), explain_infer_result() returning
nullopt) into an indistinguishable empty vector; change the API to preserve an
explicit failure channel (e.g. return std::expected<std::vector<Armor2d>,
std::string> or similar) so callers can tell “no armor” from “detection failed”,
update sync_detect's implementation in armor_detection.cpp to propagate and
return errors from generate_openvino_request() and explain_infer_result() rather
than returning a default empty vector, and adjust callers to handle the error
variant accordingly.

In `@src/utility/rclcpp/visual/armor.cpp`:
- Line 59: 当前 ARROW 的 lifetime 在 marker.lifetime 处被设为 1s,导致与 CUBE(之前在文件中以 0.1s
设置)不一致并在短暂停更时出现残留箭头;将 ARROW 的 lifetime 与 CUBE 统一即可。修复方法:在更新 marker.lifetime(标识
ARROW 的赋值处)改为与 CUBE 相同的值(0.1s),或更好地:提取一个共享常量(例如 kMarkerLifetime 或
marker_lifetime)并在设置 ARROW 和 CUBE 时都使用该常量,从而确保两者保持一致且便于将来调整。

---

Outside diff comments:
In `@src/utility/robot/id.hpp`:
- Around line 58-76: The to_string(DeviceId) function currently returns the
silent sentinel "UNREACHABLE" for an invalid DeviceId; change this to a
fail-fast behavior: replace the final return with an explicit abort/assertion
that reports the illegal DeviceId (include the enum value cast to its underlying
integer) so callers cannot continue with a bogus string. Update to_string to
call an assertion or std::terminate with a clear message (and add the needed
include for <cassert> or <cstdlib>), keeping the failure path in the function
handling of DeviceId.

---

Nitpick comments:
In `@src/kernel/identifier.hpp`:
- Around line 20-22: The header is using std::vector for Result::areas but
doesn't directly include <vector>, making compilation fragile; add an explicit
`#include` <vector> at the top of this header and ensure includes follow the
project's ordering (local headers, blank line, standard library like <vector>,
then third-party headers) so Result::areas resolves without relying on
transitive includes.

In `@src/kernel/pose_estimator.hpp`:
- Line 35: 将成员函数 addition() 从非 const 声明改为 const 成员函数:在声明 auto addition() ->
const Addition&; 后加上 const(即 auto addition() const -> const
Addition&;),并同步更新对应的定义/实现(pose_estimator::addition)以在签名中包含尾随 const,以便方法可在 const
对象上调用且语义正确。

In `@src/kernel/tracker.hpp`:
- Around line 3-10: The include order in the file is not following project
guidelines: put local project headers first (e.g., "module/tracker/decider.hpp",
"utility/clock.hpp", "utility/pimpl.hpp", "utility/robot/armor.hpp"), then
standard library headers (<expected>, <span>), and finally third‑party headers
(<yaml-cpp/yaml.h>), with a blank line between each group; reorder the includes
accordingly so the header groups and spacing match the coding standard.

In `@src/kernel/visualization.hpp`:
- Around line 3-11: Reorder the `#include` block in visualization.hpp to follow
the project's header ordering: first local headers
("utility/image/drawable.hpp", "utility/image/image.hpp",
"utility/robot/armor.hpp"), then standard library headers (<expected>, <span>,
<string>), then third-party headers (<yaml-cpp/yaml.h>), and insert a blank line
between each group; update the include sequence in the file accordingly so the
file matches the coding guideline.

In `@src/module/fire_control/aim_point_chooser.cpp`:
- Around line 1-8: 把 include 分组并按仓库约定重排:将所有本地/项目头(例如
"aim_point_chooser.hpp"、"utility/math/conversion.hpp"、"utility/serializable.hpp")合并到一个连续块(首组),然后空一行,接着放标准库头(例如
<cmath>, <tuple>, <vector>)作为第二组;确保没有将本地头分散到标准库前后,保持三组(本地 -> 标准 ->
第三方)或合并为两组时本地在前。

In `@src/module/predictor/outpost/robot_state.hpp`:
- Around line 13-29: Move the RMCS_PIMPL_DEFINITION macro to the top of the
OutpostRobotState class definition to match project convention; specifically,
place RMCS_PIMPL_DEFINITION(OutpostRobotState) immediately after the opening of
class OutpostRobotState { and before the public: section so the PIMPL macro
appears at the top of the class alongside other classes that follow the same
layout.
- Around line 3-10: The include order in robot_state.hpp currently places
standard headers (<chrono>, <span>) before project headers; reorder them to
follow the repo convention: list local/project headers first
("module/predictor/outpost/ekf_parameter.hpp", "module/predictor/snapshot.hpp",
"utility/clock.hpp", "utility/pimpl.hpp"), then a blank line, then standard
library headers (<chrono>, <span>), ensuring the groups are separated by a blank
line and preserving existing includes.

In `@src/module/predictor/snapshot.hpp`:
- Around line 3-11: Reorder the includes in snapshot.hpp so local headers come
first, then standard library headers, then third-party headers: group and place
"utility/clock.hpp", "utility/math/kalman_filter/ekf.hpp",
"utility/robot/armor.hpp", "utility/robot/id.hpp" before <memory> and <vector>,
and put <eigen3/Eigen/Core> last; keep a single blank line between each group to
match the repository header ordering convention.

In `@src/module/tracker/armor_filter.hpp`:
- Around line 3-4: 头文件中公开签名使用了 std::span 与 std::vector,但 armor_filter.hpp 只包含本地头
"utility/pimpl.hpp" 和 "utility/robot/armor.hpp";请在该头文件直接添加缺失的标准库包含(#include
<span> 和 `#include` <vector>),并按项目约定把本地头、标准库、第三方库分别分组且用空行分隔(即保留
"utility/pimpl.hpp" 和 "utility/robot/armor.hpp" 为本地组,并将 <span> 和 <vector>
放入标准库组),以消除对传递包含的依赖并避免将来编译回归。

In `@src/utility/image/drawable.hpp`:
- Around line 1-4: The header currently relies on standard types/functions
(std::string, std::uint8_t, std::move, std::declval) without explicitly
including their headers; update drawable.hpp to explicitly include the needed
standard headers (<string>, <cstdint>, <utility>) and reorder headers to follow
the guideline (local headers first, then a blank line, then standard library
headers), ensuring includes for "utility/image/image.hpp" and
"utility/robot/armor.hpp" remain present and the new standard headers are added
immediately after with a separating blank line.

In `@test/aim_point_chooser.cpp`:
- Around line 1-16: Reorder the include block in test/aim_point_chooser.cpp to
follow the project guideline: place local headers first (e.g.,
"module/fire_control/aim_point_chooser.hpp" and "utility/math/angle.hpp"), then
standard library headers (array, cmath, initializer_list, memory, optional,
random, span, string, vector), and finally third‑party headers (Eigen and
gtest). Ensure blank lines separate these groups and keep the same header names
so functions/classes referenced by the test (like symbols from
aim_point_chooser.hpp and angle.hpp) remain resolvable.
🪄 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: e867de64-fad2-450e-90b3-865e035d4d28

📥 Commits

Reviewing files that changed from the base of the PR and between 3829ccd and e2aad11.

📒 Files selected for processing (64)
  • config/config.yaml
  • src/kernel/capturer.hpp
  • src/kernel/identifier.cpp
  • src/kernel/identifier.hpp
  • src/kernel/pose_estimator.cpp
  • src/kernel/pose_estimator.hpp
  • src/kernel/tracker.cpp
  • src/kernel/tracker.hpp
  • src/kernel/visualization.cpp
  • src/kernel/visualization.hpp
  • src/module/debug/visualization/armor_visualizer.cpp
  • src/module/debug/visualization/armor_visualizer.hpp
  • src/module/fire_control/aim_point_chooser.cpp
  • src/module/fire_control/aim_point_chooser.hpp
  • src/module/identifier/adjacency_lightbar.cpp
  • src/module/identifier/adjacency_lightbar.hpp
  • src/module/identifier/armor_detection.cpp
  • src/module/identifier/armor_detection.hpp
  • src/module/identifier/green_light.cpp
  • src/module/identifier/green_light.hpp
  • src/module/identifier/green_light_detection.cpp
  • src/module/identifier/green_light_detection.hpp
  • src/module/identifier/green_light_locator.cpp
  • src/module/predictor/backend/robot_state_backend.cpp
  • src/module/predictor/backend/robot_state_backend.hpp
  • src/module/predictor/backend/snapshot_backend.hpp
  • src/module/predictor/outpost/ekf_parameter.hpp
  • src/module/predictor/outpost/robot_state.cpp
  • src/module/predictor/outpost/robot_state.hpp
  • src/module/predictor/outpost/snapshot.cpp
  • src/module/predictor/regular/ekf_parameter.hpp
  • src/module/predictor/regular/robot_state.cpp
  • src/module/predictor/regular/robot_state.hpp
  • src/module/predictor/regular/snapshot.cpp
  • src/module/predictor/robot_state.cpp
  • src/module/predictor/robot_state.hpp
  • src/module/predictor/snapshot.cpp
  • src/module/predictor/snapshot.hpp
  • src/module/tracker/armor_filter.cpp
  • src/module/tracker/armor_filter.hpp
  • src/module/tracker/decider.cpp
  • src/module/tracker/decider.hpp
  • src/runtime.cpp
  • src/utility/image/armor.cpp
  • src/utility/image/armor.hpp
  • src/utility/image/drawable.cpp
  • src/utility/image/drawable.hpp
  • src/utility/image/green_light.cpp
  • src/utility/image/green_light.hpp
  • src/utility/math/camera.cpp
  • src/utility/math/camera.hpp
  • src/utility/math/outpost.cpp
  • src/utility/math/outpost.hpp
  • src/utility/math/solve_pnp/outpost_distance_optimizer.cpp
  • src/utility/math/solve_pnp/outpost_distance_optimizer.hpp
  • src/utility/math/solve_pnp/yaw_optimizer.cpp
  • src/utility/rclcpp/visual/armor.cpp
  • src/utility/rclcpp/visual/armor.hpp
  • src/utility/robot/armor.hpp
  • src/utility/robot/id.hpp
  • test/aim_point_chooser.cpp
  • test/model_infer.cpp
  • test/solve_pnp.cpp
  • tool/cxx/see_outpost.cpp
💤 Files with no reviewable changes (10)
  • src/utility/image/green_light.hpp
  • src/module/debug/visualization/armor_visualizer.cpp
  • src/utility/image/armor.hpp
  • src/module/identifier/green_light_detection.hpp
  • src/utility/image/green_light.cpp
  • src/kernel/capturer.hpp
  • src/module/identifier/green_light_locator.cpp
  • src/module/debug/visualization/armor_visualizer.hpp
  • src/module/identifier/green_light_detection.cpp
  • src/utility/image/armor.cpp

Comment thread src/kernel/identifier.cpp
Comment thread src/module/identifier/armor_detection.hpp
Comment thread src/utility/rclcpp/visual/armor.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
src/kernel/pose_estimator.cpp (1)

149-180: 💤 Low value

建议清理注释掉的代码

这段被注释的 yaw_optimizer 相关代码已经不再使用,且有 TODO 标记表明需要清理。建议在本次 PR 或后续 PR 中移除,以保持代码整洁。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.cpp` around lines 149 - 180, Remove the
dead/commented yaw-optimizer block to clean up the codebase: delete the
commented lines referencing config.yaw_optimizer, the block that sets
input.armor_shape / input.xyz_in_world / input.center_yaw / input.genre and the
std::ranges::copy into input.detected_corners, plus the assignment
armor_3d.orientation = yaw_optimizer.solve().orientation; keep the surrounding
PNP logic (pnp_solution, armor_3d population) intact so only the unused
yaw_optimizer-related comments and TODO are removed.
src/utility/math/solve_pnp/pnp_solution.cpp (1)

4-18: 💤 Low value

头文件顺序不符合规范

根据编码规范,头文件顺序应为:本地头文件、标准库、第三方库,各组之间用空行分隔。当前顺序将标准库头文件放在了第三方库之后。

建议的头文件顺序调整
 `#include` "pnp_solution.hpp"
 `#include` "utility/math/angle.hpp"
 `#include` "utility/math/conversion.hpp"
 `#include` "utility/math/reprojection.hpp"

+#include <array>
+#include <cmath>
+#include <limits>
+#include <optional>
+#include <ranges>
+#include <stdexcept>
+#include <vector>
+
 `#include` <eigen3/Eigen/Geometry>
 `#include` <opencv2/calib3d.hpp>
 `#include` <opencv2/core/eigen.hpp>
-
-#include <array>
-#include <cmath>
-#include <limits>
-#include <optional>
-#include <ranges>
-#include <stdexcept>
-#include <vector>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/math/solve_pnp/pnp_solution.cpp` around lines 4 - 18, Reorder the
include blocks in pnp_solution.cpp so local project headers
("utility/math/angle.hpp", "utility/math/conversion.hpp",
"utility/math/reprojection.hpp") come first, followed by standard library
headers (<array>, <cmath>, <limits>, <optional>, <ranges>, <stdexcept>,
<vector>), and finally third‑party headers (<eigen3/Eigen/Geometry>,
<opencv2/calib3d.hpp>, <opencv2/core/eigen.hpp>), with a blank line between each
group to comply with the header ordering convention.

Source: Coding guidelines

src/utility/math/solve_pnp/yaw_optimizer.cpp (1)

103-106: 💤 Low value

ReprojectionOptimizer::solve() 是空实现

该方法目前始终返回 false,如果有调用方依赖此功能,将无法正常工作。请确认这是有意为之的占位实现,还是遗漏了实现逻辑。

需要我协助实现此优化器的逻辑吗?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/math/solve_pnp/yaw_optimizer.cpp` around lines 103 - 106,
ReprojectionOptimizer::solve() is a stub that always returns false which breaks
callers expecting actual optimization; replace the empty implementation in
ReprojectionOptimizer::solve with the real optimizer logic (run the yaw/pose
optimization steps, update internal state and return true on success/false on
failure) using existing optimizer helpers in this class, or if the algorithm
isn't ready, make the unimplemented state explicit by throwing a descriptive
exception (e.g., std::logic_error("ReprojectionOptimizer::solve not
implemented")) or logging a clear TODO and returning a failure code, so callers
can detect the intentional absence; locate and modify the
ReprojectionOptimizer::solve method to implement one of these fixes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utility/math/solve_pnp/pnp_solution.cpp`:
- Around line 228-232: The loop uses std::views::iota(0, steps + 1) but steps is
computed as a double from std::round, causing a type mismatch and possible wrong
iteration count; fix by making the loop bounds an integer: convert or store
steps as an integer (e.g., int steps_int = static_cast<int>(std::round(...)))
and use std::views::iota(0, steps_int + 1) when iterating over the yaw search
that updates optimized_yaw/optimized_error so the iteration count is
well-defined.

---

Nitpick comments:
In `@src/kernel/pose_estimator.cpp`:
- Around line 149-180: Remove the dead/commented yaw-optimizer block to clean up
the codebase: delete the commented lines referencing config.yaw_optimizer, the
block that sets input.armor_shape / input.xyz_in_world / input.center_yaw /
input.genre and the std::ranges::copy into input.detected_corners, plus the
assignment armor_3d.orientation = yaw_optimizer.solve().orientation; keep the
surrounding PNP logic (pnp_solution, armor_3d population) intact so only the
unused yaw_optimizer-related comments and TODO are removed.

In `@src/utility/math/solve_pnp/pnp_solution.cpp`:
- Around line 4-18: Reorder the include blocks in pnp_solution.cpp so local
project headers ("utility/math/angle.hpp", "utility/math/conversion.hpp",
"utility/math/reprojection.hpp") come first, followed by standard library
headers (<array>, <cmath>, <limits>, <optional>, <ranges>, <stdexcept>,
<vector>), and finally third‑party headers (<eigen3/Eigen/Geometry>,
<opencv2/calib3d.hpp>, <opencv2/core/eigen.hpp>), with a blank line between each
group to comply with the header ordering convention.

In `@src/utility/math/solve_pnp/yaw_optimizer.cpp`:
- Around line 103-106: ReprojectionOptimizer::solve() is a stub that always
returns false which breaks callers expecting actual optimization; replace the
empty implementation in ReprojectionOptimizer::solve with the real optimizer
logic (run the yaw/pose optimization steps, update internal state and return
true on success/false on failure) using existing optimizer helpers in this
class, or if the algorithm isn't ready, make the unimplemented state explicit by
throwing a descriptive exception (e.g.,
std::logic_error("ReprojectionOptimizer::solve not implemented")) or logging a
clear TODO and returning a failure code, so callers can detect the intentional
absence; locate and modify the ReprojectionOptimizer::solve method to implement
one of these fixes.
🪄 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: 40ef6233-ff7d-4538-be7d-870f4cf8f702

📥 Commits

Reviewing files that changed from the base of the PR and between de8d0b1 and 284f4ab.

📒 Files selected for processing (7)
  • src/kernel/pose_estimator.cpp
  • src/kernel/pose_estimator.hpp
  • src/utility/math/reprojection.hpp
  • src/utility/math/solve_pnp/pnp_solution.cpp
  • src/utility/math/solve_pnp/pnp_solution.hpp
  • src/utility/math/solve_pnp/yaw_optimizer.cpp
  • src/utility/math/solve_pnp/yaw_optimizer.hpp
💤 Files with no reviewable changes (1)
  • src/kernel/pose_estimator.hpp

Comment thread src/utility/math/solve_pnp/pnp_solution.cpp Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (7)
src/utility/math/outpost.cpp (1)

18-20: ⚡ Quick win

vertical_axis 计算的归一化是冗余的。

Line 19 已经对 armor.orientation * UnitZ 的结果调用了 .normalized(),因为四元数旋转向量保持长度,UnitZ 长度为1,所以旋转后的向量长度仍为1,归一化是多余的操作。

♻️ 建议的优化
-    const auto vertical_axis  = Eigen::Vector3d {
-        (armor.orientation.make<Eigen::Quaterniond>() * Eigen::Vector3d::UnitZ()).normalized()
-    };
+    const auto vertical_axis = Eigen::Vector3d {
+        armor.orientation.make<Eigen::Quaterniond>() * Eigen::Vector3d::UnitZ()
+    };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/math/outpost.cpp` around lines 18 - 20, The expression computing
vertical_axis redundantly calls .normalized() on the rotated UnitZ vector;
remove the unnecessary normalization so vertical_axis is assigned directly from
(armor.orientation.make<Eigen::Quaterniond>() * Eigen::Vector3d::UnitZ()),
keeping the existing use of Eigen::Vector3d and preserving the vertical_axis
identifier and the armor.orientation.make<Eigen::Quaterniond>() *
Eigen::Vector3d::UnitZ() operation.
src/kernel/pose_estimator.cpp (4)

211-212: ⚡ Quick win

移除或说明注释代码的保留意图。

Lines 211-212 的注释代码 result.armor.orientation = outpost_in_camera.orientation; 如果是临时调试代码应删除;如果是为后续优化保留的备选方案,应添加明确的说明注释(如 // TODO: 考虑是否需要同时优化旋转// 当前仅优化距离,旋转保持不变)。

🗑️ 建议的改动

如果确定不需要,直接删除:

                 if (outpost_optimizer.solve()) {
                     addition.origin.push_back(*outpost3d);
 
                     auto& result = outpost_optimizer.result;
 
-                    // 只优化距离,旋转保持原来的
-                    // result.armor.orientation = outpost_in_camera.orientation;
-
                     outpost_in_camera = result.armor;

如果需要保留作为参考,改为:

-                    // 只优化距离,旋转保持原来的
-                    // result.armor.orientation = outpost_in_camera.orientation;
+                    // NOTE: 当前仅优化距离,不修改 orientation。
+                    //       如需同时优化旋转,取消下行注释:
+                    // result.armor.orientation = outpost_in_camera.orientation;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.cpp` around lines 211 - 212, The commented-out
assignment result.armor.orientation = outpost_in_camera.orientation is left
ambiguous—either remove it if it was temporary, or keep it but replace the bare
comment with an explicit note; update the surrounding code in the pose
estimation routine (where result and outpost_in_camera are used) to either
delete that line entirely or change the comment to a clear intent like "// TODO:
consider optimizing rotation as well" or "// Currently only optimizing distance;
orientation intentionally unchanged" so future readers know why orientation is
not modified.

238-269: ⚖️ Poor tradeoff

重投影循环较长,建议提取为辅助方法。

Lines 238-269 的 for 循环包含坐标转换、ReprojectionSolution 配置、投影求解和 Lightbar2d 构造等多个步骤,认知复杂度较高。建议将此循环体提取为 Impl 的私有辅助方法(如 project_lightbar_to_2d),参数化 bar/color,返回 std::optional<Lightbar2d>,失败时返回 std::nullopt

♻️ 可选的重构示例
// 在 Impl 中添加私有方法:
auto project_lightbar_to_2d(const Lightbar3d& bar, const cv::Scalar& color) const
    -> std::optional<Lightbar2d> {
    const auto upper_opencv = ros2opencv_position(bar.upper.make<Eigen::Vector3d>());
    const auto lower_opencv = ros2opencv_position(bar.lower.make<Eigen::Vector3d>());

    auto projection = ReprojectionSolution<2> { };
    projection.input.camera = camera_feature;
    projection.input.object_points = {
        cv::Point3f { static_cast<float>(upper_opencv[0]), 
                      static_cast<float>(upper_opencv[1]), 
                      static_cast<float>(upper_opencv[2]) },
        cv::Point3f { static_cast<float>(lower_opencv[0]), 
                      static_cast<float>(lower_opencv[1]), 
                      static_cast<float>(lower_opencv[2]) },
    };
    projection.input.image_points = { cv::Point2f { }, cv::Point2f { } };

    if (!projection.solve()) return std::nullopt;

    return Lightbar2d {
        .color = bar.color,
        .upper = Point2d { projection.result.projected_points[0] },
        .lower = Point2d { projection.result.projected_points[1] },
        .draw_color = color,
    };
}

// 在原处简化为:
for (const auto& [bar, color] : std::views::zip(bars, draw_color)) {
    if (auto lightbar_2d = project_lightbar_to_2d(bar, color)) {
        addition.detected_2d.push_back(*lightbar_2d);
    }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.cpp` around lines 238 - 269, The for-loop
performing ros2opencv_position, ReprojectionSolution setup/solve, and Lightbar2d
construction is too long—extract it into a private Impl helper named
project_lightbar_to_2d that takes (const Lightbar3d& bar, const cv::Scalar&
color) and returns std::optional<Lightbar2d>; inside the helper call
ros2opencv_position for upper/lower, populate projection.input.camera =
camera_feature and projection.input.object_points, call projection.solve() and
return std::nullopt on failure, otherwise construct and return the Lightbar2d;
then replace the loop body with: if (auto lb = project_lightbar_to_2d(bar,
color)) addition.detected_2d.push_back(*lb).

234-236: 💤 Low value

颜色计算表达式不够清晰。

Lines 234-235 使用 cv::Scalar {...} * 1.0cv::Scalar {...} * 0.5 生成不同亮度的颜色。虽然功能正确,但 * 1.0 是冗余操作,且意图不够明确。建议用更具语义的变量名或注释说明 1.0 表示 "full brightness",0.5 表示 "half brightness"。

♻️ 可选的改进方案
                     const auto color      = ArmorVisualColor { lightbar.color };
+                    constexpr auto kFullBrightness = 1.0;
+                    constexpr auto kHalfBrightness = 0.5;
                     const auto draw_color = std::array {
-                        cv::Scalar { color.b() * 255, color.g() * 255, color.r() * 255 } * 1.0,
-                        cv::Scalar { color.b() * 255, color.g() * 255, color.r() * 255 } * 0.5,
+                        cv::Scalar { color.b() * 255, color.g() * 255, color.r() * 255 } * kFullBrightness,
+                        cv::Scalar { color.b() * 255, color.g() * 255, color.r() * 255 } * kHalfBrightness,
                     };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.cpp` around lines 234 - 236, The color brightness
arithmetic is unclear and uses a redundant "* 1.0"; replace the inline
multiplications with clearly named variables or a short comment: compute a base
cv::Scalar from color (e.g., baseColor), then derive full brightness and half
brightness as fullColor (baseColor) and halfColor (baseColor * 0.5) and use
those instead of cv::Scalar{...} * 1.0 / * 0.5; reference the existing color
variable and the cv::Scalar constructions in the pose estimation code to locate
where to introduce baseColor/fullColor/halfColor and add a one-line comment
indicating that fullColor is "full brightness" and halfColor is "half
brightness".

179-181: 🏗️ Heavy lift

FIXME 注释指出关键缺陷,建议开启 Issue 跟踪。

注释中提到两个严重问题:

  1. 坐标系变换导致 Pitch 随观测角度变化
  2. 前哨站 Yaw 在大角度时出现二义性翻转

这些是稳定性和准确性方面的潜在 Critical 问题。建议创建 Issue 进行跟踪,并考虑在当前 PR 中至少添加日志或警告,当检测到异常 Pitch/Yaw 变化时提示开发者。

您是否需要我为此创建 Issue 模板或生成异常检测代码?

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/kernel/pose_estimator.cpp` around lines 179 - 181, Create an Issue
tracking the two FIXME items and add runtime anomaly detection and logging
around the coordinate transform and yaw-disambiguation code: in the
PoseEstimator::estimatePose (or the code block performing the coordinate frame
transform, e.g., transformCoordinateFrame) add a check comparing current Pitch
and Yaw to the previous values (or to a smooth/expected trajectory) and if
deltaPitch > configurable_threshold_deg or deltaYaw > configurable_threshold_deg
emit a warning log with the raw and transformed vectors and the camera/observer
angle; additionally, in the outpost/front-station yaw handling (e.g.,
resolveYawAmbiguity or the branch that picks between flipped yaw solutions) add
detection for large-angle ambiguity flips and log the candidate yaw pair and
chosen solution, and optionally reject/flag the frame for further
inspection—make thresholds configurable and ensure logs include enough context
(frame id, timestamp, input angles) so the Issue can be debugged.
src/utility/math/reprojection.cpp (1)

12-13: ⚡ Quick win

补充文档说明 object_points 的坐标系假设。

cv::projectPoints 使用零旋转向量和零平移向量,这意味着 object_points 必须已经位于相机坐标系中。建议在函数或结构体的文档注释中明确说明此前置条件,避免调用方误用。

📝 建议添加的注释

reprojection.hpp 的 Line 16 之前添加:

/// `@brief` Projects 3D points (already in camera frame) to 2D image plane.
/// `@note` object_points must be in camera coordinate system (rvec=0, tvec=0 is used).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/math/reprojection.cpp` around lines 12 - 13, 说明当前调用
cv::projectPoints 时传入了 rvec=0 和 tvec=0,从而要求 object_points
已经位于相机坐标系;请在相关接口的文档注释中明确这一前置条件(例如在 reprojection.hpp 的注释区域/函数注释中),用类似 “Projects
3D points (already in camera frame) to 2D image plane. `@note` object_points must
be in camera coordinate system (rvec=0, tvec=0 is used).” 的说明标注
cv::projectPoints、object_points 和零旋转/零平移的假设,以避免调用方误用。
src/utility/math/reprojection.hpp (1)

16-27: 💤 Low value

project_points 结构可简化为函数。

project_points 结构只是为了在构造时调用 impl 并存储结果,这种模式可以直接用一个返回 bool 的静态函数替代,减少不必要的状态存储。

♻️ 可选的简化方案
 namespace details {
-    struct project_points {
-        bool success = false;
-        explicit project_points(std::span<const cv::Point3f> object_points,
-            const cv::Mat& intrinsic, const cv::Mat& distortion,
-            std::span<cv::Point2f> projected_points)
-            : success { impl(object_points, intrinsic, distortion, projected_points) } { };
-        explicit operator bool() const { return success; }
-
-    private:
-        static auto impl(std::span<const cv::Point3f> object_points, const cv::Mat& intrinsic,
-            const cv::Mat& distortion, std::span<cv::Point2f> projected_points) -> bool;
-    };
+    auto project_points(std::span<const cv::Point3f> object_points,
+        const cv::Mat& intrinsic, const cv::Mat& distortion,
+        std::span<cv::Point2f> projected_points) -> bool;
 }

并在 Line 51-53 处改为:

-        if (!details::project_points { input.object_points, input.camera.intrinsic(),
-                input.camera.distortion(), result.projected_points })
+        if (!details::project_points(input.object_points, input.camera.intrinsic(),
+                input.camera.distortion(), result.projected_points))
             return false;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/utility/math/reprojection.hpp` around lines 16 - 27, The project_points
struct is unnecessary boilerplate — replace it with a simple free/static
function that directly calls impl and returns its bool result: remove the
project_points struct, keep or convert impl (static auto impl(...) -> bool) into
a single function signature like bool project_points(std::span<const
cv::Point3f> object_points, const cv::Mat& intrinsic, const cv::Mat& distortion,
std::span<cv::Point2f> projected_points) that forwards to the existing impl
logic (or inline impl body), and update any call sites that constructed
project_points(...) or used its bool conversion to call the new
project_points(...) function and use its bool return value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/utility/math/reprojection.cpp`:
- Around line 1-5: Reorder the include directives so they follow the project
convention (local headers, then standard library, then third-party): keep
`#include` "reprojection.hpp" first, then move `#include` <vector> next, and finally
`#include` <opencv2/calib3d.hpp>; update the top of reprojection.cpp accordingly
(references: "reprojection.hpp", <vector>, and <opencv2/calib3d.hpp>).

---

Nitpick comments:
In `@src/kernel/pose_estimator.cpp`:
- Around line 211-212: The commented-out assignment result.armor.orientation =
outpost_in_camera.orientation is left ambiguous—either remove it if it was
temporary, or keep it but replace the bare comment with an explicit note; update
the surrounding code in the pose estimation routine (where result and
outpost_in_camera are used) to either delete that line entirely or change the
comment to a clear intent like "// TODO: consider optimizing rotation as well"
or "// Currently only optimizing distance; orientation intentionally unchanged"
so future readers know why orientation is not modified.
- Around line 238-269: The for-loop performing ros2opencv_position,
ReprojectionSolution setup/solve, and Lightbar2d construction is too
long—extract it into a private Impl helper named project_lightbar_to_2d that
takes (const Lightbar3d& bar, const cv::Scalar& color) and returns
std::optional<Lightbar2d>; inside the helper call ros2opencv_position for
upper/lower, populate projection.input.camera = camera_feature and
projection.input.object_points, call projection.solve() and return std::nullopt
on failure, otherwise construct and return the Lightbar2d; then replace the loop
body with: if (auto lb = project_lightbar_to_2d(bar, color))
addition.detected_2d.push_back(*lb).
- Around line 234-236: The color brightness arithmetic is unclear and uses a
redundant "* 1.0"; replace the inline multiplications with clearly named
variables or a short comment: compute a base cv::Scalar from color (e.g.,
baseColor), then derive full brightness and half brightness as fullColor
(baseColor) and halfColor (baseColor * 0.5) and use those instead of
cv::Scalar{...} * 1.0 / * 0.5; reference the existing color variable and the
cv::Scalar constructions in the pose estimation code to locate where to
introduce baseColor/fullColor/halfColor and add a one-line comment indicating
that fullColor is "full brightness" and halfColor is "half brightness".
- Around line 179-181: Create an Issue tracking the two FIXME items and add
runtime anomaly detection and logging around the coordinate transform and
yaw-disambiguation code: in the PoseEstimator::estimatePose (or the code block
performing the coordinate frame transform, e.g., transformCoordinateFrame) add a
check comparing current Pitch and Yaw to the previous values (or to a
smooth/expected trajectory) and if deltaPitch > configurable_threshold_deg or
deltaYaw > configurable_threshold_deg emit a warning log with the raw and
transformed vectors and the camera/observer angle; additionally, in the
outpost/front-station yaw handling (e.g., resolveYawAmbiguity or the branch that
picks between flipped yaw solutions) add detection for large-angle ambiguity
flips and log the candidate yaw pair and chosen solution, and optionally
reject/flag the frame for further inspection—make thresholds configurable and
ensure logs include enough context (frame id, timestamp, input angles) so the
Issue can be debugged.

In `@src/utility/math/outpost.cpp`:
- Around line 18-20: The expression computing vertical_axis redundantly calls
.normalized() on the rotated UnitZ vector; remove the unnecessary normalization
so vertical_axis is assigned directly from
(armor.orientation.make<Eigen::Quaterniond>() * Eigen::Vector3d::UnitZ()),
keeping the existing use of Eigen::Vector3d and preserving the vertical_axis
identifier and the armor.orientation.make<Eigen::Quaterniond>() *
Eigen::Vector3d::UnitZ() operation.

In `@src/utility/math/reprojection.cpp`:
- Around line 12-13: 说明当前调用 cv::projectPoints 时传入了 rvec=0 和 tvec=0,从而要求
object_points 已经位于相机坐标系;请在相关接口的文档注释中明确这一前置条件(例如在 reprojection.hpp
的注释区域/函数注释中),用类似 “Projects 3D points (already in camera frame) to 2D image
plane. `@note` object_points must be in camera coordinate system (rvec=0, tvec=0
is used).” 的说明标注 cv::projectPoints、object_points 和零旋转/零平移的假设,以避免调用方误用。

In `@src/utility/math/reprojection.hpp`:
- Around line 16-27: The project_points struct is unnecessary boilerplate —
replace it with a simple free/static function that directly calls impl and
returns its bool result: remove the project_points struct, keep or convert impl
(static auto impl(...) -> bool) into a single function signature like bool
project_points(std::span<const cv::Point3f> object_points, const cv::Mat&
intrinsic, const cv::Mat& distortion, std::span<cv::Point2f> projected_points)
that forwards to the existing impl logic (or inline impl body), and update any
call sites that constructed project_points(...) or used its bool conversion to
call the new project_points(...) function and use its bool return value.
🪄 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: 34061cf9-cff5-4757-9357-8c29f1909380

📥 Commits

Reviewing files that changed from the base of the PR and between 284f4ab and 63d4070.

📒 Files selected for processing (9)
  • config/config.yaml
  • src/kernel/pose_estimator.cpp
  • src/utility/math/outpost.cpp
  • src/utility/math/reprojection.cpp
  • src/utility/math/reprojection.hpp
  • src/utility/math/solve_pnp/pnp_solution.cpp
  • src/utility/math/solve_pnp/pnp_solution.hpp
  • src/utility/robot/constant.hpp
  • test/CMakeLists.txt
✅ Files skipped from review due to trivial changes (2)
  • test/CMakeLists.txt
  • src/utility/robot/constant.hpp
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/utility/math/solve_pnp/pnp_solution.hpp
  • src/utility/math/solve_pnp/pnp_solution.cpp

Comment thread src/utility/math/reprojection.cpp
@creeper5820 creeper5820 merged commit 4b9e936 into main Jun 6, 2026
3 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in RMCS Auto Aim V2 Jun 6, 2026
@creeper5820 creeper5820 deleted the refactor/identifier-and-visualization branch June 6, 2026 20:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant