From 3eaf72621cbf1b2ed1f2e85cc67fac72d0c5f1f1 Mon Sep 17 00:00:00 2001 From: Ubuntu Date: Wed, 6 May 2026 20:51:34 +0800 Subject: [PATCH 1/8] fix: fix armor selection logic --- config/config.yaml | 6 +++--- src/component.cpp | 4 ++-- src/module/fire_control/aim_point_chooser.cpp | 19 +++++++++++++------ .../solver/aim_point_sampling.cpp | 10 +++++----- .../solver/aim_point_sampling.hpp | 2 +- test/aim_point_chooser.cpp | 18 ++++++++++++++++++ 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/config/config.yaml b/config/config.yaml index 1ab56fc..4dabc4f 100644 --- a/config/config.yaml +++ b/config/config.yaml @@ -76,14 +76,14 @@ pose_estimator: [-0.064232403853946, -0.087667493884102, 0, 0, 0.792381808294582] fire_control: - initial_bullet_speed: 24.2 # m/s - shoot_delay: 0.1 # s + initial_bullet_speed: 21.4 # m/s + shoot_delay: 0.07 # s mpc_enable: true yaw_offset: 0.0 # degree pitch_offset: 0.0 # degree aim_point_chooser: - coming_angle: 60.0 # degree + coming_angle: 70.0 # degree leaving_angle: 20.0 # degree outpost_coming_angle: 70.0 # degree outpost_leaving_angle: 30.0 # degree diff --git a/src/component.cpp b/src/component.cpp index 4a8fd68..4481a56 100644 --- a/src/component.cpp +++ b/src/component.cpp @@ -4,7 +4,7 @@ #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif -#include "adapter/sentry.hpp" +#include "adapter/adapter.hpp" #include "kernel/feishu.hpp" #include "utility/rclcpp/node.hpp" #include "utility/shared/context.hpp" @@ -41,7 +41,7 @@ class AutoAimComponent final : public rmcs_executor::Component { InputInterface robot_id; auto make_context() const { - auto context = SystemContext { }; + auto context = SystemContext {}; context.timestamp = Clock::now(); diff --git a/src/module/fire_control/aim_point_chooser.cpp b/src/module/fire_control/aim_point_chooser.cpp index beea8d0..237ca71 100644 --- a/src/module/fire_control/aim_point_chooser.cpp +++ b/src/module/fire_control/aim_point_chooser.cpp @@ -57,7 +57,8 @@ struct AimPointChooser::Impl { if (!(config.coming_angle > 0.0) || !(config.leaving_angle > 0.0) || !(config.outpost_coming_angle > 0.0) || !(config.outpost_leaving_angle > 0.0)) { return std::unexpected { - "coming_angle, leaving_angle, outpost_coming_angle and outpost_leaving_angle must be > 0", + "coming_angle, leaving_angle, outpost_coming_angle and outpost_leaving_angle must " + "be > 0", }; } @@ -95,7 +96,7 @@ struct AimPointChooser::Impl { }; for (size_t index = 0; index < armors.size(); ++index) { - const auto delta_yaw = util::normalize_angle(yaw(index) - center_yaw); + const auto delta_yaw = util::normalize_angle(yaw(index) - center_yaw); candidate_evals[index] = { .delta_yaw = delta_yaw, .in_window = in_window(delta_yaw), @@ -103,11 +104,17 @@ struct AimPointChooser::Impl { } const auto priority_key = [&](size_t index) { - const auto abs_delta = std::abs(candidate_evals[index].delta_yaw); - const auto id = armors[index].id; - const auto is_last = last_chosen_armor_id.has_value() && (id == *last_chosen_armor_id); + const auto preferred_incoming = [&] { + const auto delta = candidate_evals[index].delta_yaw; + if (angular_velocity > 0.0) return (delta > 0.0) ? 1 : 0; + if (angular_velocity < 0.0) return (delta < 0.0) ? 1 : 0; + return 0; + }(); + const auto abs_delta = std::abs(candidate_evals[index].delta_yaw); + const auto id = armors[index].id; + const auto is_last = last_chosen_armor_id.has_value() && (id == *last_chosen_armor_id); const auto last_penalty = is_last ? 0 : 1; - return std::tuple { abs_delta, last_penalty, id, index }; + return std::tuple { preferred_incoming, abs_delta, last_penalty, id, index }; }; auto best_idx = std::optional {}; diff --git a/src/module/fire_control/solver/aim_point_sampling.cpp b/src/module/fire_control/solver/aim_point_sampling.cpp index d1ed612..7bca483 100644 --- a/src/module/fire_control/solver/aim_point_sampling.cpp +++ b/src/module/fire_control/solver/aim_point_sampling.cpp @@ -12,27 +12,27 @@ auto rmcs::fire_control::AimPointSampler::sample_at( -> std::expected { auto aim_point = sample_aim_point_at(snapshot, chooser, t); if (!aim_point.has_value()) { - return std::unexpected { "aim point sample failed" }; + return std::unexpected { aim_point.error() }; } - auto attitude = solve_aim_attitude(*aim_point, bullet_speed); + auto attitude = solve_aim_attitude(aim_point.value(), bullet_speed); if (!attitude.has_value()) { return std::unexpected { attitude.error() }; } return AimSample { .attitude = *attitude, - .aim_point = *aim_point, + .aim_point = aim_point.value(), }; } auto rmcs::fire_control::AimPointSampler::sample_aim_point_at(predictor::Snapshot const& snapshot, - AimPointChooser& chooser, TimePoint t) -> std::optional { + AimPointChooser& chooser, TimePoint t) -> std::expected { auto predicted_armors = snapshot.predicted_armors(t); auto predicted_kinematics = snapshot.kinematics_at(t); auto chosen_armor = chooser.choose_armor(predicted_armors, predicted_kinematics.center_position, predicted_kinematics.angular_velocity); - if (!chosen_armor.has_value()) return std::nullopt; + if (!chosen_armor.has_value()) return std::unexpected { "choose_armor returned nullopt" }; auto aim_point = Eigen::Vector3d {}; chosen_armor->translation.copy_to(aim_point); diff --git a/src/module/fire_control/solver/aim_point_sampling.hpp b/src/module/fire_control/solver/aim_point_sampling.hpp index fdaa8a6..c2cec11 100644 --- a/src/module/fire_control/solver/aim_point_sampling.hpp +++ b/src/module/fire_control/solver/aim_point_sampling.hpp @@ -29,7 +29,7 @@ class AimPointSampler { private: static auto sample_aim_point_at(predictor::Snapshot const& snapshot, AimPointChooser& chooser, - TimePoint t) -> std::optional; + TimePoint t) -> std::expected; static auto solve_aim_attitude(Eigen::Vector3d const& aim_point, double bullet_speed) -> std::expected; diff --git a/test/aim_point_chooser.cpp b/test/aim_point_chooser.cpp index 3f321e1..0501e88 100644 --- a/test/aim_point_chooser.cpp +++ b/test/aim_point_chooser.cpp @@ -106,3 +106,21 @@ TEST(AimPointChooser, SingleArmorHighSpeedScanBySpinDirection) { } } } + +TEST(AimPointChooser, PreferIncomingArmorWhenSpinPositive) { + auto const armors = make_armors({ -30.0, 5.0 }); + auto const chosen = choose_once(armors, 0.0, kFastPositive); + EXPECT_EQ(chosen, std::optional { 0 }); +} + +TEST(AimPointChooser, PreferIncomingArmorWhenSpinNegative) { + auto const armors = make_armors({ -5.0, 30.0 }); + auto const chosen = choose_once(armors, 0.0, kFastNegative); + EXPECT_EQ(chosen, std::optional { 1 }); +} + +TEST(AimPointChooser, KeepAbsoluteDeltaPriorityWhenSpinZero) { + auto const armors = make_armors({ -15.0, 5.0 }); + auto const chosen = choose_once(armors, 0.0, 0.0); + EXPECT_EQ(chosen, std::optional { 1 }); +} From 0b8ec8e2c63e47b3b3eaaeb98ce13de1ba9f045d Mon Sep 17 00:00:00 2001 From: heyeuu <2829004293@qq.com> Date: Wed, 6 May 2026 21:05:48 +0800 Subject: [PATCH 2/8] chore: remove feshu test --- test/CMakeLists.txt | 6 ---- test/feishu_test.cpp | 72 -------------------------------------------- 2 files changed, 78 deletions(-) delete mode 100644 test/feishu_test.cpp diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 0385080..d8d7a77 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -143,12 +143,6 @@ ament_add_gtest( ${TEST_DIR}/transform_communication.cpp ) -# Feishu IPC -ament_add_gtest( - test_feishu - ${TEST_DIR}/feishu_test.cpp -) - # Aim point chooser ament_add_gtest( test_aim_point_chooser diff --git a/test/feishu_test.cpp b/test/feishu_test.cpp deleted file mode 100644 index beb300a..0000000 --- a/test/feishu_test.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -#include -#include -#include -#include - -#include "kernel/feishu.hpp" -#include "utility/shared/context.hpp" - -using namespace std::chrono_literals; -using namespace rmcs; -using namespace rmcs::kernel; - -TEST(FeishuIntegration, BidirectionalCommunication) { - const auto pid = ::fork(); - ASSERT_NE(pid, -1); - - if (pid == 0) { - auto feishu_child = Feishu { }; - std::this_thread::sleep_for(50ms); - - auto deadline = Clock::now() + 500ms; - auto ctrl = std::optional { }; - while (!ctrl && Clock::now() < deadline) { - if (feishu_child.heartbeat()) { - ctrl = feishu_child.latest(); - } else { - std::this_thread::sleep_for(10ms); - } - } - ASSERT_TRUE(ctrl.has_value()); - - auto auto_state = AutoAimState { }; - auto_state.should_control = true; - auto_state.should_shoot = true; - auto_state.yaw = 1.23; - - feishu_child.send(auto_state); - exit(0); - } - - auto feishu_parent = Feishu { }; - std::this_thread::sleep_for(50ms); - - feishu_parent.heartbeat(); - - auto ctrl = SystemContext { }; - ctrl.timestamp = Clock::now(); - - feishu_parent.send(ctrl); - - auto deadline = Clock::now() + 500ms; - auto auto_state = std::optional { }; - while (!auto_state && Clock::now() < deadline) { - if (feishu_parent.heartbeat()) { - auto_state = feishu_parent.latest(); - } else { - std::this_thread::sleep_for(10ms); - } - } - - ASSERT_TRUE(auto_state.has_value()); - EXPECT_TRUE(auto_state->should_control); - EXPECT_TRUE(auto_state->should_shoot); - EXPECT_DOUBLE_EQ(auto_state->yaw, 1.23); - - int status = 0; - ASSERT_EQ(::waitpid(pid, &status, 0), pid); - ASSERT_TRUE(WIFEXITED(status)); - EXPECT_EQ(WEXITSTATUS(status), 0); -} From b187b35525a4ecbfdc409dc75a4f87b123f7c5a1 Mon Sep 17 00:00:00 2001 From: heyeuu <2829004293@qq.com> Date: Wed, 6 May 2026 22:14:21 +0800 Subject: [PATCH 3/8] feat: introduce non-MPC direct tracking mode for Outpost targets --- src/kernel/fire_control.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/kernel/fire_control.cpp b/src/kernel/fire_control.cpp index b091aac..cad394a 100644 --- a/src/kernel/fire_control.cpp +++ b/src/kernel/fire_control.cpp @@ -29,11 +29,16 @@ struct FireControl::Impl { double pitch_offset; constexpr static std::tuple metas { - &Config::initial_bullet_speed, "initial_bullet_speed", - &Config::shoot_delay, "shoot_delay", - &Config::mpc_enable, "mpc_enable", - &Config::yaw_offset, "yaw_offset", - &Config::pitch_offset, "pitch_offset", + &Config::initial_bullet_speed, + "initial_bullet_speed", + &Config::shoot_delay, + "shoot_delay", + &Config::mpc_enable, + "mpc_enable", + &Config::yaw_offset, + "yaw_offset", + &Config::pitch_offset, + "pitch_offset", }; } config; @@ -89,9 +94,8 @@ struct FireControl::Impl { auto yaw_acc = std::numeric_limits::quiet_NaN(); auto feedforward_valid = false; - if (config.mpc_enable) { - auto sample_attitude = - [&](TimePoint t) -> std::expected { + if (config.mpc_enable && snapshot.device_id() != DeviceId::OUTPOST) { + auto sample_attitude = [&](TimePoint t) -> std::expected { auto sample = AimPointSampler::sample_at( snapshot, aim_point_chooser, t, config.initial_bullet_speed); if (!sample.has_value()) return std::unexpected { sample.error() }; @@ -111,11 +115,11 @@ struct FireControl::Impl { yaw_acc = planned->yaw_acc; feedforward_valid = true; } else { - constexpr int kYawRow = 0; - constexpr int kPitchRow = 2; + constexpr int kYawRow = 0; + constexpr int kPitchRow = 2; constexpr int kCenterCol = kMpcAxisHorizon / 2; - pitch = (*reference)(kPitchRow, kCenterCol); - yaw = util::normalize_angle((*reference)(kYawRow, kCenterCol)); + pitch = (*reference)(kPitchRow, kCenterCol); + yaw = util::normalize_angle((*reference)(kYawRow, kCenterCol)); } } } From 902c422672262c149b0e7fd9bf55fa7f26875253 Mon Sep 17 00:00:00 2001 From: creeper5820 Date: Wed, 6 May 2026 22:12:36 +0800 Subject: [PATCH 4/8] ci: build RMCS before running tests to resolve rmcs_msgs dependency --- .github/workflows/gtest.yml | 56 ++++++++++++++++++++++++++++++------- test/CMakeLists.txt | 2 ++ 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/.github/workflows/gtest.yml b/.github/workflows/gtest.yml index 85289b6..1798335 100644 --- a/.github/workflows/gtest.yml +++ b/.github/workflows/gtest.yml @@ -2,10 +2,13 @@ name: Run Test on: push: - branches: [ main ] pull_request: workflow_dispatch: +env: + RMCS_REPO: https://github.com/Alliance-Algorithm/RMCS.git + RMCS_REF: main + jobs: test: runs-on: ubuntu-latest @@ -14,45 +17,78 @@ jobs: options: --user 0 env: - WS_DIR: ${{ github.workspace }}/ws - SRC_DIR: ${{ github.workspace }}/ws/src TEST_ASSETS_ROOT: /tmp/auto_aim steps: - - name: Checkout repository into ROS2 workspace + - name: Checkout rmcs_auto_aim_v2 uses: actions/checkout@v4 with: - repository: Alliance-Algorithm/rmcs_auto_aim_v2 - path: ws/src/rmcs_auto_aim_v2 + path: rmcs_auto_aim_v2 + + - name: Clone RMCS workspace + shell: bash + run: | + set -euo pipefail + git clone --depth 1 --branch "${RMCS_REF}" "${RMCS_REPO}" /tmp/RMCS + mkdir -p /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2 + tar -C "${GITHUB_WORKSPACE}/rmcs_auto_aim_v2" --exclude=".git" -cf - . \ + | tar -C /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2 -xf - - name: Install yq dependency run: | apt-get update apt-get install -y yq + - name: Build RMCS workspace + shell: bash + working-directory: /tmp/RMCS/rmcs_ws + run: | + set -euo pipefail + set +u + source /opt/ros/jazzy/setup.bash + set -u + colcon build --packages-up-to rmcs_auto_aim_v2 + - name: Download test assets shell: bash run: | - cd "$SRC_DIR/rmcs_auto_aim_v2/test" + set -euo pipefail + set +u + source /opt/ros/jazzy/setup.bash + source /tmp/RMCS/rmcs_ws/install/setup.bash + set -u + cd /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2/test TEST_ASSETS_ROOT="$TEST_ASSETS_ROOT" ./download_assets.sh - name: Configure test project shell: bash run: | + set -euo pipefail + set +u source /opt/ros/jazzy/setup.bash - cd "$SRC_DIR/rmcs_auto_aim_v2/test" + source /tmp/RMCS/rmcs_ws/install/setup.bash + set -u + cd /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2/test cmake -S . -B build -DCMAKE_BUILD_TYPE=Release - name: Build test project shell: bash run: | + set -euo pipefail + set +u source /opt/ros/jazzy/setup.bash - cd "$SRC_DIR/rmcs_auto_aim_v2/test" + source /tmp/RMCS/rmcs_ws/install/setup.bash + set -u + cd /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2/test cmake --build build --parallel - name: Run gtests shell: bash run: | + set -euo pipefail + set +u source /opt/ros/jazzy/setup.bash - cd "$SRC_DIR/rmcs_auto_aim_v2/test" + source /tmp/RMCS/rmcs_ws/install/setup.bash + set -u + cd /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2/test ctest --test-dir build --output-on-failure diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index d8d7a77..5574edd 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -27,6 +27,7 @@ find_package(ament_cmake_gtest REQUIRED) find_package(rclcpp REQUIRED) find_package(visualization_msgs REQUIRED) find_package(geometry_msgs REQUIRED) +find_package(rmcs_msgs REQUIRED) find_package(yaml-cpp REQUIRED) find_package(OpenVINO REQUIRED) @@ -38,6 +39,7 @@ include_directories( ${rclcpp_INCLUDE_DIRS} ${visualization_msgs_INCLUDE_DIRS} ${geometry_msgs_INCLUDE_DIRS} + ${rmcs_msgs_INCLUDE_DIRS} ${OpenCV_INCLUDE_DIRS} ) From 78900bf1898ec3ec77f95c5bc3743584392d78fc Mon Sep 17 00:00:00 2001 From: creeper5820 Date: Wed, 6 May 2026 22:21:08 +0800 Subject: [PATCH 5/8] ci: add concurrency group to avoid duplicate test runs on PR --- .github/workflows/gtest.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/gtest.yml b/.github/workflows/gtest.yml index 1798335..346061a 100644 --- a/.github/workflows/gtest.yml +++ b/.github/workflows/gtest.yml @@ -5,6 +5,10 @@ on: pull_request: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + env: RMCS_REPO: https://github.com/Alliance-Algorithm/RMCS.git RMCS_REF: main From 506b43c0818ae2f18393dd6dd6ff9724d7d60eb6 Mon Sep 17 00:00:00 2001 From: creeper5820 Date: Wed, 6 May 2026 22:25:43 +0800 Subject: [PATCH 6/8] fix: add missing rmcs_description and fast_tf dependencies to package.xml --- package.xml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/package.xml b/package.xml index 5534fd1..e46cda1 100644 --- a/package.xml +++ b/package.xml @@ -15,6 +15,8 @@ rmcs_executor + rmcs_description + fast_tf hikcamera From 9ad2e6ecfea20913d23dd52a70b3ecba3fd923fb Mon Sep 17 00:00:00 2001 From: creeper5820 Date: Wed, 6 May 2026 22:27:37 +0800 Subject: [PATCH 7/8] ci: clone hikcamera and init submodules for fast_tf --- .github/workflows/gtest.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/gtest.yml b/.github/workflows/gtest.yml index 346061a..5e143f7 100644 --- a/.github/workflows/gtest.yml +++ b/.github/workflows/gtest.yml @@ -12,6 +12,7 @@ concurrency: env: RMCS_REPO: https://github.com/Alliance-Algorithm/RMCS.git RMCS_REF: main + HIKCAMERA_REPO: https://github.com/Alliance-Algorithm/ros2-hikcamera.git jobs: test: @@ -33,7 +34,8 @@ jobs: shell: bash run: | set -euo pipefail - git clone --depth 1 --branch "${RMCS_REF}" "${RMCS_REPO}" /tmp/RMCS + git clone --depth 1 --recurse-submodules --branch "${RMCS_REF}" "${RMCS_REPO}" /tmp/RMCS + git clone --depth 1 "${HIKCAMERA_REPO}" /tmp/RMCS/rmcs_ws/src/hikcamera mkdir -p /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2 tar -C "${GITHUB_WORKSPACE}/rmcs_auto_aim_v2" --exclude=".git" -cf - . \ | tar -C /tmp/RMCS/rmcs_ws/src/rmcs_auto_aim_v2 -xf - From e24dbd11169163e82325a1685f3b1cfa77c57580 Mon Sep 17 00:00:00 2001 From: creeper5820 Date: Wed, 6 May 2026 22:44:26 +0800 Subject: [PATCH 8/8] fix: add missing rmcs_msgs and hikcamera include paths to CMakeLists.txt --- CMakeLists.txt | 3 +++ package.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7630051..26598de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ find_package(ament_index_cpp REQUIRED) find_package(rclcpp REQUIRED) find_package(visualization_msgs REQUIRED) find_package(geometry_msgs REQUIRED) +find_package(rmcs_msgs REQUIRED) find_package(rmcs_executor REQUIRED) find_package(rmcs_description REQUIRED) @@ -47,10 +48,12 @@ include_directories( ${ament_index_cpp_INCLUDE_DIRS} ${visualization_msgs_INCLUDE_DIRS} ${geometry_msgs_INCLUDE_DIRS} + ${rmcs_msgs_INCLUDE_DIRS} ${rmcs_executor_INCLUDE_DIRS} ${rmcs_description_INCLUDE_DIRS} ${fast_tf_INCLUDE_DIRS} + ${hikcamera_INCLUDE_DIRS} ) ## 代码资源搜索 diff --git a/package.xml b/package.xml index e46cda1..c986fdd 100644 --- a/package.xml +++ b/package.xml @@ -17,6 +17,7 @@ rmcs_executor rmcs_description fast_tf + rmcs_msgs hikcamera