-
Notifications
You must be signed in to change notification settings - Fork 0
Fix/goalkeeping #92
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix/goalkeeping #92
Changes from all commits
8733d80
306e651
f7aeeb1
c535696
960a66c
1443eb8
6992fff
c41dcb5
a3af538
702f2ed
6284cde
838fff7
582d27b
82850be
b011603
0c36171
e1f16ac
d0b8210
9b33ef8
dddafec
bbb4023
75bcf79
4ed3e4a
174dc74
d4678ab
30faaa8
a28a158
d5339ca
b547a90
368d9d7
0370dfc
7cf62de
60d37cd
232cce1
b7d6afa
8a5938a
c055a87
527a3ef
d4970ec
c024939
3a307b7
fbf65d6
481c57c
9356700
0dae44e
eb0a3d0
44e91ad
ac6d7ca
6ad963b
82d7be6
4930ce2
892ef5e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,58 +1,85 @@ | ||||||||||||||||||||||||||||||||||||
| import math | ||||||||||||||||||||||||||||||||||||
| from typing import Optional | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| from utama_core.entities.data.command import RobotCommand | ||||||||||||||||||||||||||||||||||||
| import numpy as np | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| from utama_core.entities.data.vector import Vector2D | ||||||||||||||||||||||||||||||||||||
| from utama_core.entities.game import Game | ||||||||||||||||||||||||||||||||||||
| from utama_core.motion_planning.src.common.motion_controller import MotionController | ||||||||||||||||||||||||||||||||||||
| from utama_core.rsoccer_simulator.src.ssl.envs.standard_ssl import SSLStandardEnv | ||||||||||||||||||||||||||||||||||||
| from utama_core.skills.src.go_to_point import go_to_point | ||||||||||||||||||||||||||||||||||||
| from utama_core.skills.src.utils.defense_utils import ( | ||||||||||||||||||||||||||||||||||||
| align_defenders, | ||||||||||||||||||||||||||||||||||||
| find_likely_enemy_shooter, | ||||||||||||||||||||||||||||||||||||
| to_defense_parametric, | ||||||||||||||||||||||||||||||||||||
| velocity_to_orientation, | ||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| def defend_parameter( | ||||||||||||||||||||||||||||||||||||
| game: Game, | ||||||||||||||||||||||||||||||||||||
| motion_controller: MotionController, | ||||||||||||||||||||||||||||||||||||
| defender_id: int, | ||||||||||||||||||||||||||||||||||||
| robot_id: int, | ||||||||||||||||||||||||||||||||||||
| env: Optional[SSLStandardEnv] = None, | ||||||||||||||||||||||||||||||||||||
| ) -> RobotCommand: | ||||||||||||||||||||||||||||||||||||
| _, enemy, ball = game.friendly_robots, game.enemy_robots, game.ball | ||||||||||||||||||||||||||||||||||||
| shooters_data = find_likely_enemy_shooter(enemy, ball) | ||||||||||||||||||||||||||||||||||||
| orientation = None | ||||||||||||||||||||||||||||||||||||
| tracking_ball = False | ||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||
| if not shooters_data: | ||||||||||||||||||||||||||||||||||||
| target_tracking_coord = ball.p.to_2d() | ||||||||||||||||||||||||||||||||||||
| if ball.v is not None and None not in ball.v: | ||||||||||||||||||||||||||||||||||||
| orientation = velocity_to_orientation(ball.v.to_2d()) | ||||||||||||||||||||||||||||||||||||
| tracking_ball = True | ||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||
| defenseing_friendly = game.friendly_robots[robot_id] | ||||||||||||||||||||||||||||||||||||
| vel = game.ball.v.to_2d() | ||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||
| vel = game.ball.v.to_2d() | |
| ball_v = game.ball.v | |
| if ball_v is None: | |
| vel = np.array([0.0, 0.0]) | |
| else: | |
| vel = ball_v.to_2d() |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The logic at lines 24 and 27 has asymmetric conditions. Line 24 uses '>= -0.5' while line 27 uses '< -0.5', meaning when game.ball.p.y equals -0.5, both conditions could execute if robot_id is 1 and len(game.friendly_robots) > 2. Additionally, when ball.p.y is between -0.5 and positive values and robot_id is 2, no early return occurs. The logic should ensure all cases are properly handled.
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The conditions at lines 24-29 only handle specific robot IDs (1 and 2) and don't account for other defender robot IDs that might exist. If robot_id is something other than 1 or 2 but len(game.friendly_robots) > 2, the function continues without the early return, which may not be the intended behavior. Consider using a more robust approach to identify which defenders should take which positions.
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Potential division by zero when (x2 - x1)^2 + (y2 - y1)^2 equals zero (i.e., when the ball position equals the goal target position). This should be checked before the division.
| t = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / ((x2 - x1) ** 2 + (y2 - y1) ** 2) | |
| denom = (x2 - x1) ** 2 + (y2 - y1) ** 2 | |
| if denom < 1e-12: | |
| t = 0.0 | |
| else: | |
| t = ((x3 - x1) * (x2 - x1) + (y3 - y1) * (y2 - y1)) / denom |
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function cal_xy5 has parameter names that suggest swapping x and y coordinates (xa, ya, xb, yb at line 56 vs ya=y2, xa=x2, yb=y1, xb=x1), which is confusing. However, the return value at line 60 swaps them back (ver_y, ver_x). This double-swapping makes the code difficult to understand and error-prone. Consider using clearer variable names or adding comments to explain the coordinate transformation.
| if abs(x2 - x4) < 1 and -1 < y4 < 1: | |
| hori_x, hori_y = cal_xy5(x2, y2, x1, y1, 1.0, x4, y4) | |
| ver_x, ver_y = cal_xy5(y2, x2, y1, x1, 2.0, x4, y4) | |
| if distance(x4, y4, hori_x, hori_y) < distance(x4, y4, ver_x, ver_y): | |
| x4, y4 = hori_x, hori_y | |
| else: | |
| if abs(x2 - x4) < 1 and -1 < y4 < 1: | |
| # Horizontal candidate: shift the projection point by `w` along the x-axis | |
| hori_x, hori_y = cal_xy5(x2, y2, x1, y1, 1.0, x4, y4) | |
| # Vertical candidate: reuse the same helper by transposing coordinates | |
| # (treat y as x and x as y). The result is therefore (y, x) in field | |
| # coordinates and must be swapped back below. | |
| ver_x, ver_y = cal_xy5(y2, x2, y1, x1, 2.0, x4, y4) | |
| if distance(x4, y4, hori_x, hori_y) < distance(x4, y4, ver_x, ver_y): | |
| x4, y4 = hori_x, hori_y | |
| else: | |
| # Swap back to (x, y) field coordinates obtained via the transposed call |
NingchuanIC marked this conversation as resolved.
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -17,25 +17,50 @@ def goalkeep( | |||||||||||||||||||||||||||||||||||||||||||||||||
| robot_id: int, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| env: Optional[SSLStandardEnv] = None, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| ): | |
| ): | |
| # Determine if the goalkeeper effectively has possession of the ball. | |
| # In the absence of an explicit possession flag, approximate it by proximity. | |
| keeper = game.friendly_robots[robot_id] | |
| ball = game.ball | |
| distance_to_ball = np.hypot(keeper.p.x - ball.p.x, keeper.p.y - ball.p.y) | |
| # If very close to the ball, clear it toward a safer area away from our own goal. | |
| if distance_to_ball < 0.1: | |
| if game.my_team_is_right: | |
| # Our goal is on the right; clear toward the left half. | |
| clear_target = Vector2D(-3.0, 0.0) | |
| else: | |
| # Our goal is on the left; clear toward the right half. | |
| clear_target = Vector2D(3.0, 0.0) | |
| return go_to_point( | |
| game, | |
| motion_controller, | |
| robot_id, | |
| clear_target, | |
| dribbling=False, | |
| ) |
NingchuanIC marked this conversation as resolved.
Show resolved
Hide resolved
Copilot
AI
Jan 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The intersection_with_vertical_line function doesn't consider the my_team_is_right parameter. The x_line default value of 4.5 is hardcoded and will be incorrect when defending the left goal.
Uh oh!
There was an error while loading. Please reload this page.