Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
25b932f
Added extracted vision data with varying degrees of vanishing and noise
szeyoong-low Nov 12, 2025
acda222
Merge remote-tracking branch 'origin' into position_filtering_2, pull…
szeyoong-low Nov 16, 2025
35147f1
Attempt to store past raw game frames; starting work on test cases
szeyoong-low Nov 16, 2025
25875d3
added Andrew's filter
szeyoong-low Nov 18, 2025
058cda2
Integrated filters into position refiner
szeyoong-low Nov 18, 2025
750c925
bad example test
fred-huang122 Nov 18, 2025
361117c
Refined filter weights, added vision data for testing
szeyoong-low Nov 19, 2025
ea88864
Updated test data
szeyoong-low Nov 19, 2025
e7c8170
Noise now added manually, updated test data
szeyoong-low Nov 19, 2025
f5561e5
Amended test cases to address CI failure due to changes to PositionRe…
szeyoong-low Nov 19, 2025
5428838
Refinements to filters based on empirical data
szeyoong-low Nov 25, 2025
756809b
Added some references for building tests
szeyoong-low Nov 29, 2025
b0650d0
First pass unit tests
szeyoong-low Nov 30, 2025
62a633d
Some issues with unit tests. Working on fix
szeyoong-low Nov 30, 2025
e6ee520
Added live testing utilities, conducted analytics for filters, refact…
szeyoong-low Dec 4, 2025
27ee5c1
Finalised analysis of filters, unit tests are working, added more liv…
szeyoong-low Dec 4, 2025
39e1c68
Deleted redundant files
szeyoong-low Dec 4, 2025
6416895
Minor refinements to the live testing utilities
szeyoong-low Dec 4, 2025
81c0c57
fixed formatting issues
szeyoong-low Dec 4, 2025
870f59e
Commented out utilities for testing and exporting data
szeyoong-low Dec 8, 2025
e84df4a
Merge branch 'main' into position_filtering_2 in preparation for pull…
szeyoong-low Dec 8, 2025
8d80265
Completed merge with main
szeyoong-low Dec 8, 2025
429c257
Analysed vanishing problem, created sample datasets
szeyoong-low Dec 13, 2025
e8cde76
Position refiner now has access to the last game frame and command ma…
szeyoong-low Dec 13, 2025
0edd594
Fixed issues, now imputes correctly based on last gameframe
szeyoong-low Dec 25, 2025
a49ffe0
Completed work on vanishing
szeyoong-low Dec 26, 2025
c2666d2
Incorporated some suggestions from copilot regardign style
szeyoong-low Dec 26, 2025
3ab1afe
Addressed comments on PR
szeyoong-low Jan 7, 2026
9df7bcd
Removed redundant utility function
szeyoong-low Jan 8, 2026
2356d37
Factored out static method into global utility
szeyoong-low Jan 8, 2026
6be9f1e
cleanup
energy-in-joles Jan 8, 2026
aaf6579
Added back error handling for imports when run from Jupyter
szeyoong-low Jan 8, 2026
a5e6857
Merge branch 'position_filtering_2' into feature/vanishing
szeyoong-low Jan 10, 2026
2ec0df8
Renamed datasets to include the control mode, filtering only turned o…
szeyoong-low Jan 11, 2026
8b86bf3
Fixed bug in tests due to renaming of files
szeyoong-low Jan 11, 2026
a574c9e
Created working Kalman filter. Working on analytics
szeyoong-low Jan 11, 2026
3442897
Working on analytics
szeyoong-low Jan 14, 2026
4ca306d
Merged changes in main
szeyoong-low Jan 14, 2026
85bb58a
Implemented a flag to add Gaussian noise in rsim. Added another more …
szeyoong-low Jan 16, 2026
9b50a54
Analysing Kalman filter performance; need to merge new rsim utilities…
szeyoong-low Jan 16, 2026
432d880
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 16, 2026
f02ab75
Cleaned up implementation, removed hackish alternative
szeyoong-low Jan 18, 2026
2ad4607
Working on adding noise to each component independently
szeyoong-low Jan 18, 2026
1263afe
Completed implementation of noise addition
szeyoong-low Jan 18, 2026
06df77e
Addressed comments on PR, got orientation to work
szeyoong-low Jan 18, 2026
92c4d01
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 18, 2026
6f12f5a
Performed benchmarking on kalman filters
szeyoong-low Jan 18, 2026
525c374
Performed benchmarking on kalman filters
szeyoong-low Jan 18, 2026
ed6f9d6
More benchmarking
szeyoong-low Jan 18, 2026
05f47b0
Kalman filter performance validated
szeyoong-low Jan 18, 2026
a0fbf63
Kalman filters now handle vanishing
szeyoong-low Jan 21, 2026
4f1f0b8
Removed non-performing implementations
szeyoong-low Jan 24, 2026
4582cb3
Rejigged analytics for Kalman filter
szeyoong-low Jan 25, 2026
ae22d1c
Addressed comments in PR, added vanishing, added support for ball
szeyoong-low Jan 30, 2026
3ce3bec
Merge branch 'main' into feature/rsim_noise
szeyoong-low Jan 30, 2026
a09ddbf
Minor linting
szeyoong-low Jan 30, 2026
9af7771
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 30, 2026
e65a9aa
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 30, 2026
7cf76a4
Added filter for ball, added support for orientation
szeyoong-low Jan 31, 2026
6b6c985
Now able to run analytics for orientation
szeyoong-low Jan 31, 2026
187cc3a
Moved utility functions for adding Gaussian noise from classes repres…
szeyoong-low Jan 31, 2026
1faf53b
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 31, 2026
0218374
Turned off a flag used for testing
szeyoong-low Jan 31, 2026
3dfa31d
Minor bug fix
szeyoong-low Jan 31, 2026
275b043
Analysing data for orientation, plus some minor fixes
szeyoong-low Jan 31, 2026
284efc5
Completed work with Kalman filters, will now work on PR
szeyoong-low Jan 31, 2026
cd9c4a3
Removed some redundant files
szeyoong-low Jan 31, 2026
bb4197c
Renamed folder to ease merging with testing
szeyoong-low Jan 31, 2026
0b4115e
Renamed folder to ease merging with testing
szeyoong-low Jan 31, 2026
39ecef5
Cleanup, getting ready for PR
szeyoong-low Jan 31, 2026
15d0255
Merge branch 'feature/rsim_noise' into feature/kalman
szeyoong-low Jan 31, 2026
80ccdf5
Small fix to satisfy linter
szeyoong-low Jan 31, 2026
92fb56c
Final cleanup after reviewing PR diff
szeyoong-low Jan 31, 2026
0cc6c8a
Improved filter docs
szeyoong-low Jan 31, 2026
806d407
Merge branch 'main' into feature/kalman
energy-in-joles Feb 21, 2026
475d048
add docstring to math_utils.py
energy-in-joles Feb 21, 2026
63ead0b
remove unused get_displacement_vector
energy-in-joles Feb 21, 2026
a0749ec
remove unused import
energy-in-joles Feb 21, 2026
f2867dd
[chore] formatting
energy-in-joles Feb 21, 2026
ab8f062
chore: formatting
energy-in-joles Feb 21, 2026
35bbc12
fix matrix inversion numerical instability and formatting of class name
energy-in-joles Feb 21, 2026
5c2cafa
remove improper static method use
energy-in-joles Feb 21, 2026
b653b54
improper use of tuple[float] type hint and mix bug referencing self.c…
energy-in-joles Feb 21, 2026
c4a384c
removed references of .cmd_map not used position.py
energy-in-joles Feb 21, 2026
623de32
fix test failure
energy-in-joles Feb 21, 2026
3879da7
Made non-global constant variable lower-cased
szeyoong-low Feb 21, 2026
3c57fa8
Using matrix transpose attribute instead of function call
szeyoong-low Feb 21, 2026
e52fb42
update test cases
energy-in-joles Feb 21, 2026
627e0f0
Merge branch 'feature/kalman' of https://github.com/First-Order-RoboC…
energy-in-joles Feb 21, 2026
7b6121a
Removed redundant last_game_frame attribute
szeyoong-low Feb 21, 2026
55780aa
separate my and opp refiners
energy-in-joles Feb 21, 2026
00cc4d1
Merge branch 'feature/kalman' of https://github.com/First-Order-RoboC…
energy-in-joles Feb 21, 2026
2a58afb
update running attribute for opposite refiner too
energy-in-joles Feb 21, 2026
4ed1f05
Minor formatting and naming changes to Kalman filter
szeyoong-low Feb 21, 2026
9968582
fix incorrect assumption about robot id numbering in position refiner…
energy-in-joles Feb 21, 2026
47768e9
corrected direct imputation of None values into vision data. Fix bug …
energy-in-joles Feb 21, 2026
48ef0ef
improve reset functionaity of position refiner
energy-in-joles Feb 21, 2026
4e845c5
Fixed bugs introduced when removing assumption about numbering
szeyoong-low Feb 21, 2026
868cccd
fix dictionary logic in position refiner
energy-in-joles Feb 21, 2026
e4526ad
update optional typing for KalmanFilterBall filter
energy-in-joles Feb 21, 2026
a74e011
fix typing in KalmanFilterBall
energy-in-joles Feb 21, 2026
f39fa93
fix point cycle strat
energy-in-joles Feb 21, 2026
5fd5bb1
Merged changes
szeyoong-low Feb 21, 2026
02120cb
Merge branch 'feature/kalman' of github.com:First-Order-RoboCup-SSL/U…
szeyoong-low Feb 21, 2026
359107b
Fixed issues in test due to filters no longer having ids, and now tak…
szeyoong-low Feb 21, 2026
da01683
Kalman filter now has id attribute
szeyoong-low Feb 21, 2026
330e13a
label vision data using kalman id instead of last frame id
energy-in-joles Feb 21, 2026
2b7976a
add comment about treating substitution as vanishing
energy-in-joles Feb 21, 2026
bd6171b
remove unncessary imports
energy-in-joles Feb 21, 2026
ec0af89
add authors
energy-in-joles Feb 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ target/

# Jupyter Notebook
.ipynb_checkpoints
.jupyter/

# IPython
profile_default/
Expand Down
5 changes: 3 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from utama_core.strategy.examples import (
DefenceStrategy,
GoToBallExampleStrategy,
PointCycleStrategy,
RobotPlacementStrategy,
StartupStrategy,
TwoRobotPlacementStrategy,
Expand All @@ -17,15 +18,15 @@ def main():
custom_bounds = FieldBounds(top_left=(2.25, 1.5), bottom_right=(4.5, -1.5))

runner = StrategyRunner(
strategy=TwoRobotPlacementStrategy(first_robot_id=0, second_robot_id=1, field_bounds=custom_bounds),
strategy=PointCycleStrategy(n_robots=2, field_bounds=custom_bounds, endpoint_tolerance=0.1, seed=42),
my_team_is_yellow=True,
my_team_is_right=True,
mode="rsim",
exp_friendly=2,
exp_enemy=0,
replay_writer_config=ReplayWriterConfig(replay_name="test_replay", overwrite_existing=True),
print_real_fps=True,
profiler_name=None
profiler_name=None,
)
runner.my_strategy.render()
runner.run()
Expand Down
2,062 changes: 980 additions & 1,082 deletions pixi.lock

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ authors = [
{ name = "Hamish Starling", email = "hamish.starling22@imperial.ac.uk" },
{ name = "Luke Moran", email = "luke.moran22@imperial.ac.uk" },
{ name = "Sadig Sadikhzada", email = "sadig.sadikhzada23@imperial.ac.uk" },
{ name = "Li Han", email = "han.li124@imperial.ac.uk" }
{ name = "Li Han", email = "han.li124@imperial.ac.uk" },
{ name = "Valentin Bruhl", email = "valentin.bruhl24@imperial.ac.uk" },
{ name = "Sarthak Agarwal", email = "sarthak.agarwal25@imperial.ac.uk" },
{ name = "Low Sze Yoong", email = "szeyoong.low25@imperial.ac.uk" },
{ name = "Jiaming Liu", email = "jiaming.liu25@imperial.ac.uk" },
]
requires-python = ">=3.11"

Expand Down
2 changes: 1 addition & 1 deletion utama_core/global_utils/math_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def normalise_heading_deg(angle):
The normalized angle in the range [-180, 180] degrees.
"""
half_rev = 180

return (angle + half_rev) % (2 * half_rev) - half_rev


Expand Down
55 changes: 29 additions & 26 deletions utama_core/rsoccer_simulator/src/ssl/envs/standard_ssl.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import logging
from numpy.random import normal
import random
from typing import List, Tuple

from numpy.random import normal

from utama_core.config.formations import LEFT_START_ONE, RIGHT_START_ONE
from utama_core.config.robot_params import RSIM_PARAMS
from utama_core.config.settings import (
Expand All @@ -13,11 +14,15 @@
)
from utama_core.entities.data.command import RobotResponse
from utama_core.entities.data.raw_vision import RawBallData, RawRobotData, RawVisionData
from utama_core.global_utils.math_utils import deg_to_rad, rad_to_deg, normalise_heading_deg
from utama_core.global_utils.math_utils import (
deg_to_rad,
normalise_heading_deg,
rad_to_deg,
)
from utama_core.rsoccer_simulator.src.Entities import Ball, Frame, Robot
from utama_core.rsoccer_simulator.src.ssl.ssl_gym_base import SSLBaseEnv
from utama_core.rsoccer_simulator.src.Utils.gaussian_noise import RsimGaussianNoise
from utama_core.rsoccer_simulator.src.Utils import KDTree
from utama_core.rsoccer_simulator.src.Utils.gaussian_noise import RsimGaussianNoise

logger = logging.getLogger(__name__)

Expand All @@ -38,19 +43,19 @@ class SSLStandardEnv(SSLBaseEnv):
Description:
list of (x, y, theta) coords for each robot to spawn in (in meters and radians).
See the default BLUE_START_ONE/YELLOW_START_ONE for reference.

gaussian_noise
Type: RsimGaussianNoise
Description:
When running in rsim, add Gaussian noise to ball and robots with the given standard deviations.
Mutates the Robot object in place. The 3 parameters are for x (in m), y (in m), and orientation (in degrees)
respectively. Defaults to 0 for each.

vanishing
Type: float
Description:
When running in rsim, cause robots and ball to vanish with the given probability. Defaults to 0.

Observation:
Type: Tuple[FrameData, List[RobotInfo], List[RobotInfo]]
Num Item
Expand Down Expand Up @@ -78,7 +83,7 @@ def __init__(
blue_starting_formation: list[tuple] = None,
yellow_starting_formation: list[tuple] = None,
gaussian_noise: RsimGaussianNoise = RsimGaussianNoise(),
vanishing: float = 0
vanishing: float = 0,
):
super().__init__(
field_type=field_type,
Expand Down Expand Up @@ -108,11 +113,11 @@ def __init__(
self.latest_observation = (-1, None)

logger.info(f"{n_robots_blue}v{n_robots_yellow} SSL Environment Initialized")

# Adding Gaussian noise and vanishing. Refer to StrategyRunner
self.gaussian_noise = gaussian_noise
assert vanishing >= 0

assert vanishing >= 0, "Negative vanishing probability not allowed"
self.vanishing = vanishing

def reset(self, *, seed=None, options=None):
Expand Down Expand Up @@ -172,7 +177,7 @@ def _frame_to_observations(
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]
"""

if self.latest_observation[0] == self.steps:
return self.latest_observation[1]

Expand All @@ -189,7 +194,7 @@ def _frame_to_observations(
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)
Expand All @@ -200,7 +205,7 @@ def _frame_to_observations(
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)
Expand All @@ -221,7 +226,7 @@ def _frame_to_observations(

def _get_robot_observation(self, robot):
SSLStandardEnv._add_gaussian_noise_robot(robot, self.gaussian_noise)

robot_pos = RawRobotData(robot.id, robot.x, -robot.y, -float(deg_to_rad(robot.theta)), 1)
robot_info = RobotResponse(robot.id, robot.infrared)
return robot_pos, robot_info
Expand Down Expand Up @@ -415,47 +420,45 @@ def in_gk_area(obj):

return pos_frame


def _vanishing(self) -> bool:
"""Determines whether a frame should vanish. Only runs after Game Gater is passed"""
return self.steps > 0 and self.vanishing and (random.random() < self.vanishing)


@staticmethod
def _add_gaussian_noise_ball(ball: Ball, noise: RsimGaussianNoise):
"""
When running in rsim, add Gaussian noise to ball with the given standard deviations.
Mutates the Robot object in place.

Args:
noise (RsimGaussianNoise): The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively.
Defaults to 0 for each.
"""

if noise.x_stddev:
ball.x += normal(scale=noise.x_stddev)

if noise.y_stddev:
ball.y += normal(scale=noise.y_stddev)

# No noise addition for z, since rSim is 2-D

@staticmethod
def _add_gaussian_noise_robot(robot: Robot, noise: RsimGaussianNoise):
"""
When running in rsim, add Gaussian noise to robot with the given standard deviations.
Mutates the Robot object in place.

Args:
noise (RsimGaussianNoise): The 3 parameters are for x (in m), y (in m), and orientation (in degrees) respectively.
Defaults to 0 for each.
"""

if noise.x_stddev:
robot.x += normal(scale=noise.x_stddev)

if noise.y_stddev:
robot.y += normal(scale=noise.y_stddev)

if noise.th_stddev_deg:
robot.theta = normalise_heading_deg(robot.theta + normal(scale=noise.th_stddev_deg))
robot.theta = normalise_heading_deg(robot.theta + normal(scale=noise.th_stddev_deg))
Loading
Loading