Open
Conversation
…st bugs - Convert RefereeData from NamedTuple to @DataClass(eq=False) so the custom __eq__ is respected (NamedTuple.__eq__ cannot be overridden — tuple equality always wins) - Use TYPE_CHECKING guard for TeamInfo import to avoid circular import (game/__init__ → Game → GameFrame → RefereeData → TeamInfo → game/__init__) - __eq__ compares TeamInfo by .score and .goalkeeper (the mutable game-state fields) since TeamInfo has no structural __eq__ of its own - Add __hash__ consistent with the subset of fields used in __eq__ - RefereeRefiner.add_new_referee_data: replace tuple slicing [1:] with == (now correctly uses the custom __eq__) - test_referee_unit.py: fix GameHistory() → GameHistory(10) (max_history is a required positional argument) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adopted main's SideRuntime refactor (my/opp sides) in strategy_runner.py while preserving referee integration. Fixed imports to new data_processing module paths. Resolved standard_ssl.py conflicts keeping RefereeData usage from our branch with main's improved assertion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 20 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py:231
_frame_to_observations()docstring says it returns a 4-tuple includingreferee_data, and StrategyRunner now branches onlen(obs) == 4, but the function still returns only a 3-tuple. This means embedded referee data is never provided to StrategyRunner and RSIM mode will always seereferee_data=Noneunless externally injected. Update the return value (and type annotation) to actually include the currentRefereeDatafrom the embedded referee state machine, or revert the docstring/StrategyRunner logic if referee data is not available here.
def _frame_to_observations(
self,
) -> Tuple[RawVisionData, RobotResponse, RobotResponse]:
"""Return observation data that aligns with grSim. There may be Gaussian noise and vanishing added.
Returns (vision_observation, yellow_robot_feedback, blue_robot_feedback, referee_data)
vision_observation: closely aligned to SSLVision that returns a FramData object
yellow_robots_info: feedback from individual yellow robots that returns a List[RobotInfo]
blue_robots_info: feedback from individual blue robots that returns a List[RobotInfo]
referee_data: current referee state from embedded referee state machine
"""
if self.latest_observation[0] == self.steps:
return self.latest_observation[1]
# Ball observation shared by all robots
if self._vanishing():
ball_obs = []
else:
SSLStandardEnv._add_gaussian_noise_ball(self.frame.ball, self.gaussian_noise)
ball_obs = [RawBallData(self.frame.ball.x, -self.frame.ball.y, self.frame.ball.z, 1.0)]
# Robots observation (Blue + Yellow)
blue_obs = []
blue_robots_info = []
for i in range(len(self.frame.robots_blue)):
if self._vanishing():
continue
robot = self.frame.robots_blue[i]
robot_pos, robot_info = self._get_robot_observation(robot)
blue_obs.append(robot_pos)
blue_robots_info.append(robot_info)
yellow_obs = []
yellow_robots_info = []
for i in range(len(self.frame.robots_yellow)):
if self._vanishing():
continue
robot = self.frame.robots_yellow[i]
robot_pos, robot_info = self._get_robot_observation(robot)
yellow_obs.append(robot_pos)
yellow_robots_info.append(robot_info)
# Return the complete shared observation
# note that ball_obs stored in list to standardise with SSLVision
# As there is sometimes multiple possible positions for the ball
# Get referee data
# current_time = self.time_step * self.steps
# Camera id as 0, only one camera for RSim
result = (
RawVisionData(self.time_step * self.steps, yellow_obs, blue_obs, ball_obs, 0),
yellow_robots_info,
blue_robots_info,
)
self.latest_observation = (self.steps, result)
return result
Contributor
Author
|
Referee integration
Custom referee
Referee override behavior
Operator UX
Geometry / configurability
Tests
|
- Add rsim integration tests for ball placement, direct free kick (ours and theirs), and kickoff positioning in test_referee_rsim.py - Add 15 unit tests covering PrepareKickoffTheirsStep, DirectFreeOursStep, and DirectFreeTheirsStep action nodes in test_referee_unit.py - Switch demo script control_scheme from dwa to pid Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace Field._UNDERSCORE_CONSTANTS with their public ClassProperty equivalents in math_utils.py and geometry.py. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ument future work - conftest.py: default --headless to True so tests don't open rsim window - strategy_runner.py: skip ball teleport on STOP when next_command is BALL_PLACEMENT so the robot must physically carry the ball - test_referee_rsim.py: replace broken full-sequence test with a comment documenting why it is deferred (ball placement carry mechanics not yet reliable in rsim) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Penalty and ball placement buttons are not in use; removing them keeps the operator panel focused on the commands we actually use. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Ball placement phase before free kick per SSL rulebook - BallPlacementOursStep carry mechanics investigation (two-robot kissing) - GUI suggested next action to reduce operator cognitive load Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Delete dead RefereeStateMachine (never wired up, duplicated GameStateMachine with a broken _replace() call on a mutable class) - Remove dead len(obs)==4 branch in _run_step; RSim always reads from ref_buffer - Snapshot TeamInfo via copy.copy() in _generate_referee_data() to prevent score mutations retroactively corrupting stored RefereeRefiner records - Update docs and stale docstrings accordingly - Document TeamInfo frozen dataclass refactor as deferred follow-up work Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace from_field_bounds with from_field_dims in RefereeGeometry so goal/defense dimensions scale with the actual field, not hardcoded to STANDARD_FIELD_DIMS - Fix Vector3D→Vector2D conversions in actions.py for fpp controller compatibility (DirectFreeOursStep, BallPlacementOursStep) - Rename get_min_bounding_zone→get_min_bounding_req in point_cycle_strategy and wandering_strategy to match abstract base class - Update test fixtures to use new Field(field_dims=...) constructor and correct BALL_KEEP_OUT_DISTANCE (0.8 m) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
_project_outside_circle was using a hardcoded (1, 0) fallback when a robot sits exactly on the obstruction center (dist == 0), pushing it to positive-x regardless of which half the team defends. Now _clear_to_legal_ positions passes an own-half-aware fallback so coincident robots are always cleared toward their correct side. Also fix test_all_robots_placed_on_own_half_* to track final target per robot (dict keyed by robot_id) rather than a flat list, so the count assertion is robust against the clearing pass re-issuing a move command. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…etry Add CustomReferee.override_geometry() to replace geometry on both the referee and its internal state machine. StrategyRunner now calls this immediately after resolving field_bounds, so the custom referee always uses the actual full_field_dims + field_bounds rather than the standard- field values baked into the YAML profile. The YAML geometry block is preserved as a fallback for standalone CustomReferee use outside of StrategyRunner. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
from_field_dims(STANDARD_FIELD_DIMS) is the direct equivalent and makes the standard-field case no more special than any other. Update the test fixture accordingly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…eometry Aligns with FieldDimensions.half_defense_area_depth. Updated geometry.py, profile_loader.py, gui.py, and both YAML profiles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…_positions Three issues addressed: 1. Remove CLEARANCE_FALLBACK_DIRECTION from referee_constants — it was the default parameter of _project_outside_circle but no caller used the default; the fallback is now always passed explicitly. 2. _clear_to_legal_positions now accepts an optional intended_targets dict. When provided, clearance starts from the intended formation target rather than robot.p, so the clearing pass refines rather than discards the formation intent. PrepareKickoffTheirsStep now passes intended_targets instead of pre-issuing move commands and relying on overwrite. 3. Use own-half direction as the coincidence fallback for both ball and designated-position clearance — consistent with the invariant that friendly robots belong on their own half during all restart states. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…quence resets During PREPARE_KICKOFF_* and PREPARE_PENALTY_*, robots are actively moving to their formation positions. The keep-out rule was firing after 30 frames of encroachment and resetting the sequence to STOP → DIRECT_FREE, causing a violation loop. These states are now excluded from _STOPPAGE_COMMANDS — the state machine already gates progression via _kicker_in_centre_circle and _penalty_kicker_ready, so keep-out violations here are spurious. The rule remains active for DIRECT_FREE_* where defending robots must genuinely stay clear while the free kick is set up. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…event sequence resets" This reverts commit d6f4f11.
…rget If a robot is currently inside a keep-out zone, sending it toward a distant formation target makes it traverse the exclusion zone for multiple frames, triggering the keep-out violation counter. Instead, when a robot is encroaching, project it out from its current position immediately. Only use the intended formation target when the robot is already clear of all exclusion zones. This prevents keep-out rule violations during PREPARE_KICKOFF without modifying the referee state machine. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The function previously used a hardcoded 0.5 m (centre-circle radius), meaning formation positions could be placed at exactly 0.5 m from the ball. _clear_to_legal_positions would then push them out to 0.8 m, but the robot still had to travel through the keep-out zone to reach its target, accumulating violation frames. Using BALL_KEEP_OUT_DISTANCE (0.8 m) ensures formation positions are always placed at or beyond our enforced clearance distance, so robots never need to traverse the keep-out zone to reach their assigned position. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Update docs/custom_referee.md: replace stale from_standard_div_b() / from_field_bounds() references with the actual from_field_dims() API; fix half_defense_length → half_defense_depth in the dataclass snippet - Fix misleading __eq__ comment in RefereeData: clarify that time_sent and time_received are excluded, not all timestamps - Fix GameFrame.is_ball_in_goal: accept a Field parameter (self.field does not exist on GameFrame); add ball None guard; simplify with abs() - Fix demo_custom_referee.py: replace non-existent from_standard_div_b() with from_field_dims(STANDARD_FIELD_DIMS); fix half_defense_length → half_defense_depth crash Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix PreparePenaltyTheirsStep: behind_line_x used +sign which placed non-keeper robots toward our goal instead of toward the centre line; change to -sign so robots are correctly positioned behind the penalty mark facing midfield (mirrors the existing PreparePenaltyOursStep logic) - Rename misleading test: test_resolve_referee_system_defaults_to_none_even_when_custom_referee_is_provided → test_resolve_referee_system_rejects_custom_referee_without_explicit_system - Fix demo_referee_gui_rsim.py docstring: run command pointed to utama_core/tests/referee/ path instead of the actual root-level file Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…a record Properties like last_command, blue_team, status_message, etc. were all reading from _referee_records[-1], which is not updated when the new RefereeData compares equal (e.g. only status_message or time_sent changes). This could leave live properties stale between meaningful state changes. Add _latest_referee_data, updated unconditionally on every refine() call (alongside the existing _latest_stage_time_left), and point all live properties at it. _referee_records still grows only on meaningful state changes, preserving its role as a deduplicated history. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The field was renamed in code (RefereeGeometry, YAML profiles) but three doc files still used the old name in YAML examples and the field table. Updated docs/custom_referee.md, docs/referee_integration.md, and docs/custom_referee_gui.md to match the actual API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Only simulation.yaml and human.yaml exist under profiles/. exhibition.yaml was listed in the directory tree but was never created. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Referee data pipeline
@dataclassto support a custom eq that ignores timestamps and game events (preventing spurious re-records)Custom referee & state machine
Compliant action nodes (actions.py)
Operator GUI (gui.py)
Profiles