架构改进:头部追踪 + 球过时检测 + 球员独占 + 定位球处理

头部追踪:
- 球可见时 he1/he2 追踪球方位,球不可见时左右扫描
- 在技能执行后、commit_motor_targets_pd 前覆盖头部电机目标

球位置过时检测:
- world.py 新增 ball_age property 和阈值常量
- 球消失 ≥3s 时外场球员原地旋转搜索,门将不再基于过期信息拦截

最近球员独占:
- 每个 agent 自行判断是否离球最近(视觉队友位置 + 0.5m 死区防抖)
- 最近球员执行 carry_ball,其他球员走到编号对应的支援站位

定位球基础处理:
- THEIR_KICK 时外场球员退到中圈半径外防守位,面朝球
- OUR_KICK 时最近球员上前踢球,其他人进攻支援位

决策层重构:
- update_current_behavior 外场分支拆分为 playmode_group 判断
- 新增 _outfield_decide / _am_i_nearest_to_ball / support_position / _defensive_set_piece
This commit is contained in:
jjh
2026-04-02 21:38:28 +08:00
parent a70557d2cc
commit 34f74c3005
2 changed files with 672 additions and 9 deletions

View File

@@ -1,4 +1,4 @@
from dataclasses import Field
from world.commons.field import Field
import numpy as np
from world.commons.other_robot import OtherRobot
from world.commons.field import FIFAField, HLAdultField, Soccer7vs7Field
@@ -38,10 +38,14 @@ class World:
self.score_left: int = None
self.score_right: int = None
self.their_team_name: str = None
self.last_server_time: str = None
self.last_server_time: float = None
self._global_cheat_position: np.ndarray = np.zeros(3)
self.global_position: np.ndarray = np.zeros(3)
self.ball_pos: np.ndarray = np.zeros(3)
self.ball_last_pos: np.ndarray = np.zeros(3)
self.ball_last_update_time: float = None
self.ball_velocity_2d: np.ndarray = np.zeros(2)
self.ball_speed: float = 0.0
self.is_ball_pos_updated: bool = False
self.our_team_players: list[OtherRobot] = [OtherRobot() for _ in range(self.MAX_PLAYERS_PER_TEAM)]
self.their_team_players: list[OtherRobot] = [OtherRobot(is_teammate=False) for _ in
@@ -56,6 +60,19 @@ class World:
playmode=self.playmode, is_left_team=self.is_left_team
)
# ------------------------------------------------------------------
# Ball freshness
# ------------------------------------------------------------------
BALL_FRESH_THRESHOLD: float = 0.6 # < 0.6s: reliable
BALL_STALE_THRESHOLD: float = 3.0 # > 3.0s: completely lost
@property
def ball_age(self) -> float:
"""Seconds since the ball position was last updated by vision."""
if self.ball_last_update_time is None or self.server_time is None:
return float("inf")
return self.server_time - self.ball_last_update_time
def is_fallen(self) -> bool:
return self.global_position[2] < 0.3
@@ -65,4 +82,4 @@ class World:
elif field_name in ('sim3d_7vs7'):
return Soccer7vs7Field(world=self)
else:
return FIFAField(world=self)
return FIFAField(world=self)