From 851eec4efd29ccc05f24a5b6325a1b1f4d4ff78c Mon Sep 17 00:00:00 2001 From: zlq04222 <1542498005@qq.com> Date: Mon, 27 Jul 2026 22:30:26 +0800 Subject: [PATCH 1/4] feat: bind sentry event api and enemy outpost/base hp to lua --- src/cxx/component.cc | 33 +++++++++++++++++++++++++++++++++ src/cxx/context.cc | 2 ++ src/cxx/context.hh | 2 ++ src/lua/api.lua | 1 + src/lua/blackboard.lua | 16 ++++++++++++++++ 5 files changed, 54 insertions(+) diff --git a/src/cxx/component.cc b/src/cxx/component.cc index 38b8bdb..c36023f 100644 --- a/src/cxx/component.cc +++ b/src/cxx/component.cc @@ -10,6 +10,9 @@ #include #include +#include +#include + namespace rmcs::navigation { class Navigation final @@ -31,6 +34,7 @@ class Navigation final struct Command { using ChassisMode = rmcs_msgs::ChassisMode; + using SentryEventCounts = std::unordered_map; OutputInterface enable_control; OutputInterface enable_autoaim; @@ -39,6 +43,7 @@ class Navigation final OutputInterface gimbal_toward; OutputInterface climb_cross_direction; OutputInterface climb_is_climb; + OutputInterface sentry_events; explicit Command(Navigation& component) { component.register_output("/rmcs_navigation/enable_control", enable_control, true); @@ -50,6 +55,8 @@ class Navigation final component.register_output( "/rmcs_navigation/request/cross_direction", climb_cross_direction, kNan); component.register_output("/rmcs_navigation/request/is_climb", climb_is_climb, false); + component.register_output( + "/rmcs_navigation/sentry_events", sentry_events, SentryEventCounts{}); } } command{*this}; @@ -77,6 +84,8 @@ class Navigation final auto game = blackboard["game"].get(); game["stage"] = rmcs_msgs::to_string(*rmcs.game_stage); + game["enemy_outpost_hp"] = *rmcs.enemy_outpost_hp; + game["enemy_base_hp"] = *rmcs.enemy_base_hp; auto play = blackboard["play"].get(); play["rswitch"] = rmcs_msgs::to_string(*rmcs.switch_right); @@ -116,6 +125,30 @@ class Navigation final lua.inject("relocalize", [this] { nav.relocalize(rmcs.robot_id->color()); }); + lua.inject("sentry_event", [this](const std::string& name) { + using SentryEvent = rmcs_msgs::SentryEvent; + static const auto table = std::unordered_map{ + {"SWITCH_POSE_ATTACK", SentryEvent::SWITCH_POSE_ATTACK}, + {"SWITCH_POSE_DEFENSE", SentryEvent::SWITCH_POSE_DEFENSE}, + {"SWITCH_POSE_MOVE", SentryEvent::SWITCH_POSE_MOVE}, + {"SWITCH_POSE_POWERED_ATTACK", SentryEvent::SWITCH_POSE_POWERED_ATTACK}, + {"SWITCH_POSE_POWERED_DEFENSE", SentryEvent::SWITCH_POSE_POWERED_DEFENSE}, + {"SWITCH_POSE_POWERED_MOVE", SentryEvent::SWITCH_POSE_POWERED_MOVE}, + {"CONFIRM_REBIRTH", SentryEvent::CONFIRM_REBIRTH}, + {"CONFIRM_INSTANT_REBIRTH", SentryEvent::CONFIRM_INSTANT_REBIRTH}, + {"EXCHANGE_AMMO_SUPPLY_POINT", SentryEvent::EXCHANGE_AMMO_SUPPLY_POINT}, + {"EXCHANGE_AMMO_REMOTE", SentryEvent::EXCHANGE_AMMO_REMOTE}, + {"EXCHANGE_HP_REMOTE", SentryEvent::EXCHANGE_HP_REMOTE}, + {"ACTIVATE_ENERGY_CORE", SentryEvent::ACTIVATE_ENERGY_CORE}, + }; + + if (const auto it = table.find(name); it != table.end()) { + ++(*command.sentry_events)[it->second]; + } else { + node::warn("Unknown sentry event: {}", name); + } + }); + node::info("Navigation is initialized"); } diff --git a/src/cxx/context.cc b/src/cxx/context.cc index 02f32c2..c4e3556 100644 --- a/src/cxx/context.cc +++ b/src/cxx/context.cc @@ -68,6 +68,8 @@ struct RmcsContext::Impl { make_input("/referee/current_hp", context.robot_health, std::uint16_t{400}); make_input("/referee/shooter/bullet_allowance", context.robot_bullet, std::uint16_t{300}); make_input("/referee/id", context.robot_id, rmcs_msgs::RobotId{}); + make_input("/referee/enemy/outpost/hp", context.enemy_outpost_hp, std::uint16_t{0}); + make_input("/referee/enemy/base/hp", context.enemy_base_hp, std::uint16_t{0}); make_input("/remote/switch/right", context.switch_right, rmcs_msgs::Switch::UNKNOWN); make_input("/remote/switch/left", context.switch_left, rmcs_msgs::Switch::UNKNOWN); diff --git a/src/cxx/context.hh b/src/cxx/context.hh index f570b1f..f8f2e3f 100644 --- a/src/cxx/context.hh +++ b/src/cxx/context.hh @@ -21,6 +21,8 @@ public: InputInterface robot_id; InputInterface robot_health; InputInterface robot_bullet; + InputInterface enemy_outpost_hp; + InputInterface enemy_base_hp; InputInterface switch_right; InputInterface switch_left; diff --git a/src/lua/api.lua b/src/lua/api.lua index 689da4b..4e3c8d8 100644 --- a/src/lua/api.lua +++ b/src/lua/api.lua @@ -21,6 +21,7 @@ local util = require("util.native") --- @field switch_motion_mode fun(mode: "normal" | "attack" | "slope") --- @field update_under_attack fun(yes: boolean) --- @field relocalize fun() 触发重定位,红/蓝方由 referee robot_id 自动派生 +--- @field sentry_event fun(event: string) 触发一次哨兵裁判系统指令,计数递增后由 SentryDecision 检测变化并发送 --- local api = setmetatable({}, { __index = function(_, name) diff --git a/src/lua/blackboard.lua b/src/lua/blackboard.lua index e72be8f..49b41b4 100644 --- a/src/lua/blackboard.lua +++ b/src/lua/blackboard.lua @@ -12,6 +12,20 @@ Intent = { spikes = "spikes", supply = "supply", } +SentryEvent = { + SWITCH_POSE_ATTACK = "SWITCH_POSE_ATTACK", + SWITCH_POSE_DEFENSE = "SWITCH_POSE_DEFENSE", + SWITCH_POSE_MOVE = "SWITCH_POSE_MOVE", + SWITCH_POSE_POWERED_ATTACK = "SWITCH_POSE_POWERED_ATTACK", + SWITCH_POSE_POWERED_DEFENSE = "SWITCH_POSE_POWERED_DEFENSE", + SWITCH_POSE_POWERED_MOVE = "SWITCH_POSE_POWERED_MOVE", + CONFIRM_REBIRTH = "CONFIRM_REBIRTH", + CONFIRM_INSTANT_REBIRTH = "CONFIRM_INSTANT_REBIRTH", + EXCHANGE_AMMO_SUPPLY_POINT = "EXCHANGE_AMMO_SUPPLY_POINT", + EXCHANGE_AMMO_REMOTE = "EXCHANGE_AMMO_REMOTE", + EXCHANGE_HP_REMOTE = "EXCHANGE_HP_REMOTE", + ACTIVATE_ENERGY_CORE = "ACTIVATE_ENERGY_CORE", +} local function create_default_blackboard() local result = { @@ -26,6 +40,8 @@ local function create_default_blackboard() }, game = { stage = GameStage.UNKNOWN, + enemy_outpost_hp = 0, + enemy_base_hp = 0, }, play = { rswitch = "UNKNOWN", From da549b50d6ff2b4524a3d9439deeafa32d5451ea Mon Sep 17 00:00:00 2001 From: zlq04222 <1542498005@qq.com> Date: Tue, 28 Jul 2026 15:13:18 +0800 Subject: [PATCH 2/4] feat: gimbal-frame yaw tracking, deferred climb direction and supercap boost output --- src/cxx/component.cc | 33 ++++++++++++++++------ src/cxx/controller/motion.cc | 53 ++++++++++++++++++++++-------------- src/cxx/controller/motion.hh | 6 ++-- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/src/cxx/component.cc b/src/cxx/component.cc index c36023f..b0035d4 100644 --- a/src/cxx/component.cc +++ b/src/cxx/component.cc @@ -25,6 +25,7 @@ class Navigation final static inline auto kVecNaN = Eigen::Vector2d{kNan, kNan}; std::atomic lua_tick_count = 0; + double pending_climb_world_yaw = kNan; details::LuaContext lua{*this}; details::Navigation nav{*this}; @@ -38,6 +39,7 @@ class Navigation final OutputInterface enable_control; OutputInterface enable_autoaim; + OutputInterface enable_supercap_; OutputInterface chassis_behavior; OutputInterface chassis_speed; OutputInterface gimbal_toward; @@ -48,6 +50,7 @@ class Navigation final explicit Command(Navigation& component) { component.register_output("/rmcs_navigation/enable_control", enable_control, true); component.register_output("/rmcs_navigation/enable_autoaim", enable_autoaim, true); + component.register_output("/rmcs_navigation/enable_supercap", enable_supercap_, false); component.register_output( "/rmcs_navigation/chassis_behavior", chassis_behavior, ChassisMode::AUTO); component.register_output("/rmcs_navigation/chassis_velocity", chassis_speed, kVecNaN); @@ -64,11 +67,8 @@ class Navigation final auto [x, y, yaw] = nav.check_position(); // 高频查询 TF 是不对的,所以应该先缓存一份 - // context 保留 NaN 作为 world 不可用的真实信号,blackboard 单独 fallback motion.context.current_world_yaw = yaw; - if (std::isnan(yaw)) { - yaw = motion.context.current_local_yaw; - } + ++motion.context.yaw_sample; motion.context.x = x; motion.context.y = y; @@ -115,9 +115,16 @@ class Navigation final lua.inject( "switch_motion_mode", [this](const std::string& mode) { motion.switch_mode(mode); }); lua.inject("update_under_attack", [this](bool yes) { motion.context.under_attack = yes; }); + lua.inject( + "update_supercap_boost", [this](bool enable) { *command.enable_supercap_ = enable; }); lua.inject("set_climb_direction", [this](double world_yaw) { - *command.climb_cross_direction = motion.world2odom(world_yaw); + if (std::isfinite(world_yaw)) { + pending_climb_world_yaw = world_yaw; + } else { + pending_climb_world_yaw = kNan; + *command.climb_cross_direction = kNan; + } }); lua.inject( "set_climb_switch", [this](bool is_climb) { *command.climb_is_climb = is_climb; }); @@ -155,6 +162,11 @@ class Navigation final auto before_updating() -> void override { rmcs.ensure_defaults(); } auto update() -> void override { + const auto gimbal_direction = fast_tf::cast( + rmcs_description::BottomYawLink::DirectionVector{Eigen::Vector3d::UnitX()}, *rmcs.tf); + motion.context.current_gimbal_yaw = + std::atan2(gimbal_direction->y(), gimbal_direction->x()); + if (lua_tick_count++ == 10) [[unlikely]] { lua_tick_count = 0; sync_blackboard(); @@ -172,11 +184,14 @@ class Navigation final motion.context.target_chassis_speed = (elapsed > kCmdVelTimeout) ? Eigen::Vector2d::Zero() : nav_cmd.speed; - const auto direction = fast_tf::cast( - rmcs_description::BaseLink::DirectionVector{Eigen::Vector3d::UnitX()}, *rmcs.tf); - motion.context.current_local_yaw = std::atan2(direction->y(), direction->x()); - const auto cmd = motion.spin_once(); + if (std::isfinite(pending_climb_world_yaw)) { + const auto target = motion.world2gimbal_odom(pending_climb_world_yaw); + if (std::isfinite(target)) { + *command.climb_cross_direction = target; + pending_climb_world_yaw = kNan; + } + } if (*command.enable_control) { *command.chassis_speed = cmd.chassis_speed; *command.gimbal_toward = cmd.gimbal_toward; diff --git a/src/cxx/controller/motion.cc b/src/cxx/controller/motion.cc index 749649d..c169cc0 100644 --- a/src/cxx/controller/motion.cc +++ b/src/cxx/controller/motion.cc @@ -23,28 +23,44 @@ struct MotionFsm::Impl { LowPassFilter slope_filter{Tau<3.0>{}, Eigen::Vector2d::Zero()}; - double yaw_bias = 0; - double last_world_yaw = kNan; + bool gimbal_yaw_bias_initialized = false; + double gimbal_yaw_bias = kNan; + std::uint64_t last_yaw_sample = 0; - static constexpr auto normalize_yaw(double yaw) noexcept { + static auto normalize_yaw(double yaw) -> double { return std::atan2(std::sin(yaw), std::cos(yaw)); } - auto update_yaw_bias() { + auto update_yaw_bias(double local_yaw, bool& initialized, double& bias) -> bool { const auto world_yaw = context.current_world_yaw; - if (!std::isfinite(world_yaw) || world_yaw == last_world_yaw) + if (!std::isfinite(world_yaw) || !std::isfinite(local_yaw)) + return false; + + constexpr auto kYawBiasCorrectionGain = 0.002; + const auto measured_bias = normalize_yaw(world_yaw - local_yaw); + if (!initialized) { + bias = measured_bias; + initialized = true; + } else { + const auto bias_error = normalize_yaw(measured_bias - bias); + bias = normalize_yaw(bias + kYawBiasCorrectionGain * bias_error); + } + return true; + } + + auto update_yaw_biases() -> void { + if (last_yaw_sample == context.yaw_sample) return; - last_world_yaw = world_yaw; - constexpr auto kGain = 0.002; - const auto error = normalize_yaw(world_yaw - context.current_local_yaw - yaw_bias); - yaw_bias = normalize_yaw(yaw_bias + kGain * error); + last_yaw_sample = context.yaw_sample; + update_yaw_bias( + context.current_gimbal_yaw, gimbal_yaw_bias_initialized, gimbal_yaw_bias); } - auto world2odom(double world_yaw) const { - if (!std::isfinite(world_yaw)) + auto world2gimbal_odom(double world_yaw) const -> double { + if (!std::isfinite(world_yaw) || !gimbal_yaw_bias_initialized) return kNan; - return normalize_yaw(world_yaw - yaw_bias); + return normalize_yaw(world_yaw - gimbal_yaw_bias); } auto update_gimbal_target() -> Eigen::Vector2d { @@ -58,15 +74,12 @@ struct MotionFsm::Impl { const auto pitch = context.target_gimbal_toward.y(); const auto wy = context.current_world_yaw; - // world 不可用:目标按 OdomGimbalImu 绝对角直通(与 current_local_yaw 同源) + // world 不可用时保持上一帧云台目标,避免切换坐标参考。 if (!std::isfinite(wy)) { - if (!std::isfinite(target_yaw)) { - return {command.gimbal_toward.x(), command.gimbal_toward.y()}; - } - return {normalize_yaw(target_yaw), pitch}; + return {command.gimbal_toward.x(), command.gimbal_toward.y()}; } - const auto target_local_yaw = world2odom(target_yaw); + const auto target_local_yaw = world2gimbal_odom(target_yaw); return {target_local_yaw, pitch}; } @@ -124,7 +137,7 @@ struct MotionFsm::Impl { } auto spin_once() noexcept -> Command { - update_yaw_bias(); + update_yaw_biases(); fsm.spin_once(); return command; } @@ -137,7 +150,7 @@ MotionFsm::~MotionFsm() noexcept = default; auto MotionFsm::switch_mode(const std::string& mode) -> void { pimpl->switch_mode(mode); } -auto MotionFsm::world2odom(double yaw) -> double { return pimpl->world2odom(yaw); } +auto MotionFsm::world2gimbal_odom(double yaw) -> double { return pimpl->world2gimbal_odom(yaw); } auto MotionFsm::spin_once() noexcept -> Command { return pimpl->spin_once(); } diff --git a/src/cxx/controller/motion.hh b/src/cxx/controller/motion.hh index 72de324..da108f0 100644 --- a/src/cxx/controller/motion.hh +++ b/src/cxx/controller/motion.hh @@ -1,6 +1,7 @@ #pragma once #include "cxx/util/pimpl.hh" +#include #include #include #include @@ -23,8 +24,9 @@ public: Eigen::Vector2d target_chassis_speed = kVecNan; Eigen::Vector2d target_gimbal_toward = kVecNan; - double current_local_yaw = kNan; + double current_gimbal_yaw = kNan; double current_world_yaw = kNan; + std::uint64_t yaw_sample = 0; double x = kNan, y = kNan; @@ -39,7 +41,7 @@ public: explicit MotionFsm(rclcpp::Node& node) noexcept; auto switch_mode(const std::string& mode) -> void; - auto world2odom(double yaw) -> double; + auto world2gimbal_odom(double yaw) -> double; auto spin_once() noexcept -> Command; }; From ec2d6b90a049749786892ad2e488734ac7c8defd Mon Sep 17 00:00:00 2001 From: zlq04222 <1542498005@qq.com> Date: Tue, 28 Jul 2026 15:13:24 +0800 Subject: [PATCH 3/4] feat: supercap boost on step crossing, sentry posture switching and train map tuning --- src/lua/action.lua | 15 +++++++++++++++ src/lua/api.lua | 1 + src/lua/blackboard.lua | 3 +++ src/lua/endpoint/train.lua | 2 ++ src/lua/map/train.lua | 18 ++++++++++++------ src/lua/task/robot_status.lua | 36 +++++++++++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/src/lua/action.lua b/src/lua/action.lua index 200e255..bb30002 100644 --- a/src/lua/action.lua +++ b/src/lua/action.lua @@ -33,6 +33,9 @@ local action = { full_scan_start = 0, full_scan_stamp = 0, }, + climb = { + up = false, + }, } --- 绑定 action 的后台任务。 @@ -167,6 +170,7 @@ function action:gimbal_scan(y1, y2) self.gimbal.p1 = 0 + 0.2 self.gimbal.p2 = 0 - 0.2 end + function action:gimbal_toward(yaw, pitch) action:info("Set gimbal to toward mode") self.gimbal.mode = "toward" @@ -175,14 +179,17 @@ function action:gimbal_toward(yaw, pitch) self.gimbal.p1 = pitch self.gimbal.p2 = pitch end + function action:gimbal_free() action:info("Set gimbal to free mode") self.gimbal.mode = "free" end + function action:gimbal_suspend() action:info("Set gimbal to suspended mode") self.gimbal.mode = "suspended" end + -- @param interval number function action:gimbal_suspend_during(interval) self.gimbal.suspend_timeline = clock:now() + interval @@ -198,10 +205,12 @@ end function action:set_gimbal_pt(t) self.gimbal.pt_per_rad = t end + --- @param t number function action:set_gimbal_yt(t) self.gimbal.yt_per_rad = t end + function action:reset_gimbal_speed() self.gimbal.pt_per_rad = kPtPerRad self.gimbal.yt_per_rad = kYtPerRad @@ -217,6 +226,11 @@ function action:update_under_attack(yes) api.update_under_attack(yes) end +--- @param enable boolean +function action:update_supercap_boost(enable) + api.update_supercap_boost(enable) +end + --- 触发一次重定位,红/蓝方由 referee robot_id 自动派生; --- 服务未就绪或 robot_id 未知时本次调用被丢弃并打 WARN,不抛错。 function action:relocalize() @@ -240,6 +254,7 @@ end --- @param is_climb boolean true 上台阶,false 下台阶。 --- @return boolean success function action:blocking_cross_step(world_yaw, is_climb) + self.climb.up = is_climb api.set_climb_switch(is_climb) api.set_climb_direction(world_yaw) request:yield() diff --git a/src/lua/api.lua b/src/lua/api.lua index 4e3c8d8..ad652bd 100644 --- a/src/lua/api.lua +++ b/src/lua/api.lua @@ -13,6 +13,7 @@ local util = require("util.native") --- @field fuck fun(message: string) --- --- @field update_enable_control fun(enable: boolean) +--- @field update_supercap_boost fun(enable: boolean) --- @field send_target fun(x: number, y: number) --- @field update_gimbal_direction fun(yaw: number, pitch: number) --- @field set_climb_direction fun(angle: number) diff --git a/src/lua/blackboard.lua b/src/lua/blackboard.lua index 49b41b4..a88d6c2 100644 --- a/src/lua/blackboard.lua +++ b/src/lua/blackboard.lua @@ -58,6 +58,7 @@ local function create_default_blackboard() rule = { -- 状态类规则 health_limit = 200, + health_critical = 50, bullet_limit = 20, health_ready = 350, bullet_ready = 95, @@ -72,6 +73,8 @@ local function create_default_blackboard() intent_to_return = Intent.nothing, current = nil, -- 当前地图节点,由 Map 边 Task 成功后推进 + + power_move = false, }, } diff --git a/src/lua/endpoint/train.lua b/src/lua/endpoint/train.lua index 4cc5fb1..f32ca64 100644 --- a/src/lua/endpoint/train.lua +++ b/src/lua/endpoint/train.lua @@ -70,6 +70,7 @@ on_init = function() action:update_enable_control(false) action:switch_topic_forward(false) + action:update_supercap_boost(false) action:stop_navigation() if intent_handler ~= nil then @@ -92,6 +93,7 @@ on_init = function() request:sleep(2) action:relocalize() + request:sleep(5) action:switch_topic_forward(true) action:switch_motion_mode("attack") diff --git a/src/lua/map/train.lua b/src/lua/map/train.lua index 759f1bd..a2ad58e 100644 --- a/src/lua/map/train.lua +++ b/src/lua/map/train.lua @@ -5,13 +5,13 @@ local bb = require("blackboard").singleton() local Points = { kOrigin = Map:point("kBegin", { x = 0.0, y = 0.0 }), - kAttackInLeft = Map:point("kAttackInLeft", { x = 2.0, y = 3.5 }), + kAttackInLeft = Map:point("kAttackInLeft", { x = 1.0, y = 0.2 }), kAttackInRight = Map:point("kAttackInRight", { x = 2.4, y = 0.2 }), kStepBegin = Map:point("kStepBegin", { x = 2.4, y = -0.7 }), kStepFinal = Map:point("kStepFinal", { x = 2.4, y = -2.0 }), - kUnderSlope = Map:point("kUnderSlope", { x = 4.7, y = -2.6 }), - kUnderRune = Map:point("kUnderRune", { x = 4.6, y = 1.1 }), - kAttackAtHole = Map:point("kAttackAtHole", { x = 5.3, y = 3.8 }), + kUnderSlope = Map:point("kUnderSlope", { x = 4.7, y = -2.1 }), + kUnderRune = Map:point("kUnderRune", { x = 4.7, y = -2.1 }), + kAttackAtHole = Map:point("kAttackAtHole", { x = 4.7, y = -2.1 }), } local function navigate(_, to) @@ -31,10 +31,16 @@ Map:connect(Points.kOrigin, Points.kAttackInRight) { navigate, navigate } Map:connect(Points.kAttackInRight, Points.kStepBegin) { navigate, navigate } Map:connect(Points.kStepBegin, Points.kStepFinal) { function(from, to) - return action:blocking_cross_step(math.atan(to.y - from.y, to.x - from.x), true) + action:update_supercap_boost(true) + local success = action:blocking_cross_step(math.atan(to.y - from.y, to.x - from.x), true) + action:update_supercap_boost(false) + return success end, function(from, to) - return action:blocking_cross_step(math.atan(to.y - from.y, to.x - from.x), false) + action:update_supercap_boost(true) + local success = action:blocking_cross_step(math.atan(to.y - from.y, to.x - from.x), false) + action:update_supercap_boost(false) + return success end, } Map:connect(Points.kStepFinal, Points.kUnderSlope) { navigate, navigate } diff --git a/src/lua/task/robot_status.lua b/src/lua/task/robot_status.lua index 374a888..d02e373 100644 --- a/src/lua/task/robot_status.lua +++ b/src/lua/task/robot_status.lua @@ -1,4 +1,5 @@ local action = require("action") +local api = require("api") local clock = require("util.clock") local request = require("util.scheduler").request @@ -6,6 +7,14 @@ return function() local last_attack_timestamp = clock:now() local last_hp = 0 + local last_posture = nil + local kPoseEvent = { + POWERED_DEFENSE = SentryEvent.SWITCH_POSE_POWERED_DEFENSE, + DEFENSE = SentryEvent.SWITCH_POSE_DEFENSE, + POWERED_MOVE = SentryEvent.SWITCH_POSE_POWERED_MOVE, + ATTACK = SentryEvent.SWITCH_POSE_ATTACK, + } + while true do local hp = blackboard.user.health if last_hp > hp then @@ -21,6 +30,33 @@ return function() action:gimbal_suspend_during(1) end + local s = api.get_climb_status() + local climbing = s > 0 and s < 1 + + local power_defense = hp < blackboard.rule.health_critical or (climbing and action.climb.up) + local defense = hp < blackboard.rule.health_limit or (climbing and not action.climb.up) + local power_move = blackboard.context.power_move + local attack = blackboard.autoaim.should_control + + local desired + if power_defense then + desired = "POWERED_DEFENSE" + elseif defense then + desired = "DEFENSE" + elseif power_move then + desired = "POWERED_MOVE" + elseif attack then + desired = "ATTACK" + else + desired = "DEFENSE" + end + + if desired ~= last_posture then + last_posture = desired + action:info("Sentry pose -> " .. desired) + api.sentry_event(kPoseEvent[desired]) + end + request:yield() end end From 2a1d6776751d24ad6403ba73c8310bc839a0e99a Mon Sep 17 00:00:00 2001 From: zlq04222 <1542498005@qq.com> Date: Tue, 28 Jul 2026 15:13:34 +0800 Subject: [PATCH 4/4] feat: defer test endpoint navigation restart to switch trigger and log hp --- src/lua/endpoint/test.lua | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/lua/endpoint/test.lua b/src/lua/endpoint/test.lua index 3c1e1f4..40d1a46 100644 --- a/src/lua/endpoint/test.lua +++ b/src/lua/endpoint/test.lua @@ -26,6 +26,8 @@ local restart_navigation = function() } end +local navigation_restarted = false + --- --- Export Context --- @@ -40,8 +42,6 @@ on_init = function() clock:reset(blackboard.meta.timestamp) action:update_enable_control(true) - restart_navigation() - action:set_gimbal_yt(10) action:set_gimbal_pt(5) action:gimbal_scan(-0.4, 0) @@ -50,7 +50,8 @@ on_init = function() scheduler:append_task(function() local switch_order = order.new(blackboard.getter.rswitch, 1) switch_order:on({ "MIDDLE", "UP", "MIDDLE" }, function() - action:info("Nod event appended") + restart_navigation() + navigation_restarted = true action:gimbal_nod(1) end) @@ -62,6 +63,21 @@ on_init = function() end end) + scheduler:append_task(function() + while not navigation_restarted do + request:yield() + end + while true do + action:info(string.format( + "己方血量: %d, 敌方前哨血量: %d, 敌方基地血量: %d", + blackboard.user.health, + blackboard.game.enemy_outpost_hp, + blackboard.game.enemy_base_hp + )) + request:sleep(1) + end + end) + scheduler:append_task(function() while true do request:sleep(0.1)