From 010567978d1cdb6f0c7de0cc858119cdcb3c0c72 Mon Sep 17 00:00:00 2001 From: jjh <2444972201@qq.com> Date: Thu, 2 Apr 2026 21:37:38 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=88=E9=97=A8=E5=91=98=E5=9F=BA=E7=A1=80?= =?UTF-8?q?=E7=89=88=20+=20=E8=BF=9B=E9=98=B6=E6=84=8F=E5=9B=BE=E5=B1=82?= =?UTF-8?q?=20+=20=E5=85=B3=E9=94=AE=E5=B8=A7=E6=8A=80=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 守门员基础版: - 1号门将从外场逻辑中分流,具备 HOME/INTERCEPT/CLEAR/PENALTY_READY/RECOVER 状态机 - 门线封角、横移巡逻、禁区内拦截、边路清球、点球站位 - 只依赖 Walk/Neutral/GetUp,不引入真实 catch 或 RL 扑救 守门员进阶意图层: - GoalieSet 保留为生产姿态 - BLOCK_LEFT/BLOCK_RIGHT 降为意图层,不作为正式比赛动作 - CATCH_* 骨架与计时保留,不发真实协议 - GoalieBlock RL 占位接口预留 新增关键帧技能: - GoalieSet(生产)、LowBlockLeft/LowBlockRight(实验) - 注册到 BehaviorManager,has_skill() 接口新增 MonitorClient 改动: - place_player 支持 yaw 参数 --- behaviors/behavior_manager.py | 8 ++++- .../keyframe/poses/goalie_set/goalie_set.py | 8 +++++ .../poses/low_block_left/low_block_left.py | 8 +++++ .../poses/low_block_right/low_block_right.py | 8 +++++ .../goalie_block/goalie_block.py | 32 +++++++++++++++++++ communication/monitor_client.py | 13 ++++++-- 6 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 behaviors/custom/keyframe/poses/goalie_set/goalie_set.py create mode 100644 behaviors/custom/keyframe/poses/low_block_left/low_block_left.py create mode 100644 behaviors/custom/keyframe/poses/low_block_right/low_block_right.py create mode 100644 behaviors/custom/reinforcement/goalie_block/goalie_block.py diff --git a/behaviors/behavior_manager.py b/behaviors/behavior_manager.py index c54f17c..891c1c2 100644 --- a/behaviors/behavior_manager.py +++ b/behaviors/behavior_manager.py @@ -1,5 +1,8 @@ from behaviors.custom.keyframe.get_up.get_up import GetUp from behaviors.custom.keyframe.keyframe import KeyframeSkill +from behaviors.custom.keyframe.poses.goalie_set.goalie_set import GoalieSet +from behaviors.custom.keyframe.poses.low_block_left.low_block_left import LowBlockLeft +from behaviors.custom.keyframe.poses.low_block_right.low_block_right import LowBlockRight from behaviors.custom.keyframe.poses.neutral.neutral import Neutral from behaviors.behavior import Behavior from behaviors.custom.reinforcement.walk.walk import Walk @@ -22,7 +25,7 @@ class BehaviorManager: Each skill is indexed by its class name. """ - classes: list[type[Behavior]] = [Walk, Neutral, GetUp] + classes: list[type[Behavior]] = [Walk, Neutral, GoalieSet, LowBlockLeft, LowBlockRight, GetUp] # instantiate each Skill and store in the skills dictionary self.skills = {cls.__name__: cls(agent=self.agent) for cls in classes} @@ -33,6 +36,9 @@ class BehaviorManager: raise KeyError(f"No skill found with the name '{name}'") return self.skills[name] + def has_skill(self, name: str) -> bool: + return name in self.skills + def execute(self, skill_name: str, *args, **kwargs) -> bool: """ Executes one step of the specified skill. diff --git a/behaviors/custom/keyframe/poses/goalie_set/goalie_set.py b/behaviors/custom/keyframe/poses/goalie_set/goalie_set.py new file mode 100644 index 0000000..77b76d8 --- /dev/null +++ b/behaviors/custom/keyframe/poses/goalie_set/goalie_set.py @@ -0,0 +1,8 @@ +import os + +from behaviors.custom.keyframe.keyframe import KeyframeSkill + + +class GoalieSet(KeyframeSkill): + def __init__(self, agent): + super().__init__(agent, os.path.join(os.path.dirname(__file__), "goalie_set.yaml")) diff --git a/behaviors/custom/keyframe/poses/low_block_left/low_block_left.py b/behaviors/custom/keyframe/poses/low_block_left/low_block_left.py new file mode 100644 index 0000000..08fb378 --- /dev/null +++ b/behaviors/custom/keyframe/poses/low_block_left/low_block_left.py @@ -0,0 +1,8 @@ +import os + +from behaviors.custom.keyframe.keyframe import KeyframeSkill + + +class LowBlockLeft(KeyframeSkill): + def __init__(self, agent): + super().__init__(agent, os.path.join(os.path.dirname(__file__), "low_block_left.yaml")) diff --git a/behaviors/custom/keyframe/poses/low_block_right/low_block_right.py b/behaviors/custom/keyframe/poses/low_block_right/low_block_right.py new file mode 100644 index 0000000..22b7b27 --- /dev/null +++ b/behaviors/custom/keyframe/poses/low_block_right/low_block_right.py @@ -0,0 +1,8 @@ +import os + +from behaviors.custom.keyframe.keyframe import KeyframeSkill + + +class LowBlockRight(KeyframeSkill): + def __init__(self, agent): + super().__init__(agent, os.path.join(os.path.dirname(__file__), "low_block_right.yaml")) diff --git a/behaviors/custom/reinforcement/goalie_block/goalie_block.py b/behaviors/custom/reinforcement/goalie_block/goalie_block.py new file mode 100644 index 0000000..2b6898a --- /dev/null +++ b/behaviors/custom/reinforcement/goalie_block/goalie_block.py @@ -0,0 +1,32 @@ +import logging + +from behaviors.behavior import Behavior + + +logger = logging.getLogger(__name__) + + +class GoalieBlock(Behavior): + """ + Placeholder interface for a future RL-based goalkeeper blocking skill. + + The production code does not register or call this skill yet. + It exists to lock down the expected execution shape for later training work. + """ + + def __init__(self, agent): + super().__init__(agent) + self.last_side: str | None = None + + def execute(self, reset: bool, side: str, *args, **kwargs) -> bool: + if reset: + self.last_side = side + + logger.warning( + "GoalieBlock.execute(side=%s) was called before an RL model was integrated.", + side, + ) + return True + + def is_ready(self, *args) -> bool: + return False diff --git a/communication/monitor_client.py b/communication/monitor_client.py index 64e1e69..905a96a 100644 --- a/communication/monitor_client.py +++ b/communication/monitor_client.py @@ -57,7 +57,14 @@ class MonitorClient: unum: int, team_name: str, pos: tuple[float, float, float], + yaw_deg: float | None = None, ) -> None: - self.send( - f"(agent (unum {unum}) (team {team_name}) (pos {pos[0]} {pos[1]} {pos[2]}))" - ) + if yaw_deg is None: + command = f"(agent (unum {unum}) (team {team_name}) (pos {pos[0]} {pos[1]} {pos[2]}))" + else: + command = ( + f"(agent (unum {unum}) (team {team_name}) " + f"(move {pos[0]} {pos[1]} {pos[2]} {yaw_deg}))" + ) + + self.send(command)