From 8a390dde06cf991bd86ae29b42ae2a6a1ddce68c Mon Sep 17 00:00:00 2001 From: jjh <2444972201@qq.com> Date: Wed, 1 Apr 2026 19:10:12 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E5=86=99=20carry=5Fball=20=E4=B8=BA?= =?UTF-8?q?=E4=B8=89=E6=AE=B5=E5=BC=8F=20catch=5Fball=20=E6=8B=B1=E7=90=83?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- agent/agent.py | 75 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 51 insertions(+), 24 deletions(-) diff --git a/agent/agent.py b/agent/agent.py index 60ab684..6966aa4 100644 --- a/agent/agent.py +++ b/agent/agent.py @@ -95,7 +95,12 @@ class Agent: def carry_ball(self): """ - Basic example of a behavior: moves the robot toward the goal while handling the ball. + Minimal catch-ball behavior. + + All players share the same logic: + 1. approach a point behind the ball + 2. reposition with a lateral offset if they are close but not yet behind it + 3. push the ball forward once they are aligned """ their_goal_pos = self.agent.world.field.get_their_goal_position()[:2] ball_pos = self.agent.world.ball_pos[:2] @@ -103,12 +108,23 @@ class Agent: ball_to_goal = their_goal_pos - ball_pos bg_norm = np.linalg.norm(ball_to_goal) - if bg_norm == 0: - return - ball_to_goal_dir = ball_to_goal / bg_norm + if bg_norm <= 1e-6: + ball_to_goal_dir = np.array([1.0, 0.0]) + else: + ball_to_goal_dir = ball_to_goal / bg_norm - dist_from_ball_to_start_carrying = 0.30 - carry_ball_pos = ball_pos - ball_to_goal_dir * dist_from_ball_to_start_carrying + lateral_dir = np.array([-ball_to_goal_dir[1], ball_to_goal_dir[0]]) + + back_offset = 0.40 + side_offset = 0.35 + push_distance = 0.80 + approach_distance = 0.90 + push_start_distance = 0.55 + behind_margin = 0.08 + angle_tolerance = np.deg2rad(20.0) + + behind_point = ball_pos - ball_to_goal_dir * back_offset + push_target = ball_pos + ball_to_goal_dir * push_distance my_to_ball = ball_pos - my_pos my_to_ball_norm = np.linalg.norm(my_to_ball) @@ -120,25 +136,36 @@ class Agent: cosang = np.dot(my_to_ball_dir, ball_to_goal_dir) cosang = np.clip(cosang, -1.0, 1.0) angle_diff = np.arccos(cosang) + aligned = (my_to_ball_norm > 1e-6) and (angle_diff <= angle_tolerance) - ANGLE_TOL = np.deg2rad(7.5) - aligned = (my_to_ball_norm > 1e-6) and (angle_diff <= ANGLE_TOL) - - behind_ball = np.dot(my_pos - ball_pos, ball_to_goal_dir) < 0 + behind_ball = np.dot(my_pos - ball_pos, ball_to_goal_dir) < -behind_margin desired_orientation = MathOps.vector_angle(ball_to_goal) - if not aligned or not behind_ball: - self.agent.skills_manager.execute( - "Walk", - target_2d=carry_ball_pos, - is_target_absolute=True, - orientation=None if np.linalg.norm(my_pos - carry_ball_pos) > 2 else desired_orientation - ) - else: - self.agent.skills_manager.execute( - "Walk", - target_2d=their_goal_pos, - is_target_absolute=True, - orientation=desired_orientation - ) + lateral_sign = np.sign(np.cross(ball_to_goal_dir, my_to_ball_dir)) + if lateral_sign == 0: + lateral_sign = 1.0 if (my_pos[1] - ball_pos[1]) >= 0 else -1.0 + reposition_point = behind_point + lateral_dir * lateral_sign * side_offset + + if my_to_ball_norm > approach_distance: + target_2d = behind_point + orientation = None + elif not behind_ball: + target_2d = reposition_point + orientation = None if np.linalg.norm(my_pos - reposition_point) > 0.8 else desired_orientation + elif not aligned and my_to_ball_norm > push_start_distance: + target_2d = behind_point + orientation = desired_orientation + else: + target_2d = push_target + orientation = desired_orientation + + if np.linalg.norm(target_2d - my_pos) <= 1e-4: + target_2d = my_pos + ball_to_goal_dir * 0.30 + + self.agent.skills_manager.execute( + "Walk", + target_2d=target_2d, + is_target_absolute=True, + orientation=orientation, + )