Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
73 commits
Select commit Hold shift + click to select a range
f164b87
add new fs stats layer
sauravbanna Jan 25, 2026
c2d9240
formatting
sauravbanna Jan 25, 2026
293eecd
revert
sauravbanna Jan 25, 2026
0fbc05b
added new vis proto for goalie stats
sauravbanna Jan 25, 2026
7a098a4
added posession tracking + enemy shots taken count
sauravbanna Jan 25, 2026
ff64061
added workaround fallback to calculate enemy shots blocked
sauravbanna Jan 25, 2026
54c5484
fix bugs
sauravbanna Jan 25, 2026
bd4847e
fixed bugs + goal shot detection logic + reduced noise
Thunderbots Jan 26, 2026
1b27029
revert
Thunderbots Jan 26, 2026
031621a
docs
Thunderbots Jan 26, 2026
f652fa5
Merge branch 'master' of https://github.com/UBC-Thunderbots/Software …
Thunderbots Feb 1, 2026
0ebe986
format
Thunderbots Feb 1, 2026
c554d8d
Merge remote-tracking branch 'origin' into sauravbanna/add_fullsystem…
Thunderbots Feb 9, 2026
64cad40
denoise stats a bit more
Thunderbots Feb 9, 2026
caa9719
format
Thunderbots Feb 9, 2026
5dc69e5
added docs for funny numbers + moved stats to own module
Thunderbots Feb 12, 2026
e2883e9
added pass tracker , refactored kick tracker
Thunderbots Feb 12, 2026
d9aa911
added trackers module and refactored existing trackers
sauravbanna Feb 14, 2026
1274048
rename stats class
sauravbanna Feb 14, 2026
515f8ba
Merge branch 'sauravbanna/add_fullsystem_stats' into sauravbanna/trac…
sauravbanna Feb 14, 2026
18ca3cf
added referee stat tracker
sauravbanna Feb 14, 2026
f17451f
added referee tracker
sauravbanna Feb 14, 2026
73e183d
fix BUILD file name
sauravbanna Feb 14, 2026
7853995
added goalie tracker
sauravbanna Feb 14, 2026
c8eba37
added trackers to track pass results
sauravbanna Feb 14, 2026
67cc238
removed unecessary imports + fields
sauravbanna Feb 14, 2026
d8c7fbf
format
sauravbanna Feb 14, 2026
b86bef4
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
sauravbanna Feb 14, 2026
50a9787
made stats module a managed resource to avoid repeated file opens
sauravbanna Feb 14, 2026
e133699
Merge branch 'sauravbanna/add_fullsystem_stats' into sauravbanna/add_…
sauravbanna Feb 14, 2026
f4eacb5
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
sauravbanna Feb 14, 2026
1e6ba11
finshed pass results logger for intervals
sauravbanna Feb 15, 2026
e8f2514
fixed enter method
sauravbanna Feb 15, 2026
6292c6e
Merge branch 'sauravbanna/add_fullsystem_stats' into sauravbanna/add_…
sauravbanna Feb 15, 2026
6add7f7
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
sauravbanna Feb 15, 2026
a26e580
added BUILD file + dependencies
Thunderbots Feb 16, 2026
e12911a
format
Thunderbots Feb 16, 2026
f830aae
fixed file append error
Thunderbots Feb 16, 2026
023cb5e
Merge branch 'sauravbanna/add_fullsystem_stats' into sauravbanna/add_…
Thunderbots Feb 16, 2026
db66ad4
fixed noise in shots on goal for friendly
Thunderbots Feb 16, 2026
d692749
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
Thunderbots Feb 16, 2026
4cdabe8
added buffer size arg
Thunderbots Feb 16, 2026
8cf5da3
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
Thunderbots Feb 16, 2026
a65e99d
format
Thunderbots Feb 16, 2026
522db07
add pass results to stata refresh
Thunderbots Feb 16, 2026
068e1d6
fix bug in kick trackers
Thunderbots Feb 16, 2026
350acd0
removed unecessary shot double count
Thunderbots Feb 16, 2026
9f653a3
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
Thunderbots Feb 16, 2026
bddb409
added headers for files
Thunderbots Feb 16, 2026
4b92f31
removed headers for features
Thunderbots Feb 16, 2026
9f8bbcc
fixed file format + csv logging works now
Thunderbots Feb 16, 2026
b52a8a7
fixed pretty print + default args in python bindings
Thunderbots Feb 18, 2026
29f2b6a
Merge branch 'sauravbanna/add_fullsystem_stats' into sauravbanna/add_…
Thunderbots Feb 18, 2026
48f1aa1
Merge branch 'sauravbanna/add_stat_trackers' into sauravbanna/track_p…
Thunderbots Feb 18, 2026
decac94
removed world buffer
Thunderbots Feb 21, 2026
019d0bb
Merge branch 'master' of https://github.com/UBC-Thunderbots/Software …
Thunderbots Mar 30, 2026
b47b544
Merge branch 'sauravbanna/test_pass_data_collection' into sauravbanna…
Thunderbots Mar 30, 2026
2ce1a1b
Merge branch 'sauravbanna/verbose_log_schema' into sauravbanna/track_…
Thunderbots Mar 30, 2026
6ce0a3b
Merge branch 'sauravbanna/refactor_trackers_to_log' into sauravbanna/…
Thunderbots Mar 30, 2026
e5893ba
added eventtype extension
Thunderbots Mar 30, 2026
1056162
added pass results tracking
Thunderbots Mar 31, 2026
5075e70
Merge branch 'sauravbanna/refactor_trackers_to_log' into sauravbanna/…
Thunderbots Mar 31, 2026
2fd44f2
moved pass result logging code to pass rresults tracker
Thunderbots Mar 31, 2026
2af2347
fix bugs
sauravbanna Mar 31, 2026
87d8ab1
rename
sauravbanna Mar 31, 2026
39814f1
Merge branch 'sauravbanna/track_pass_features' into sauravbanna/track…
sauravbanna Mar 31, 2026
2ac0245
Merge branch 'sauravbanna/track_pass_features' into sauravbanna/track…
sauravbanna Mar 31, 2026
f334f3b
added build target
sauravbanna Mar 31, 2026
6ec26e9
fix
Thunderbots Mar 31, 2026
c012f9c
Merge branch 'sauravbanna/track_pass_features' into sauravbanna/track…
Thunderbots Mar 31, 2026
c24fe2c
fix
Thunderbots Mar 31, 2026
f9a1e51
Merge branch 'sauravbanna/track_pass_features' into sauravbanna/track…
Thunderbots Mar 31, 2026
cd572c9
format
Thunderbots Mar 31, 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
4 changes: 0 additions & 4 deletions src/software/thunderscope/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,3 @@ class PassResultsConstants:
FRIENDLY_POSSESSION_SCORE = 2
ENEMY_POSSESSION_SCORE = -FRIENDLY_POSSESSION_SCORE
NEUTRAL_SCORE = 0

# the time intervals to log results for after each pass
# so after a pass, wait X seconds and then log game state
INTERVALS_S = [1, 5, 10]
12 changes: 12 additions & 0 deletions src/software/thunderscope/log/pass_results/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,15 @@ py_library(
"//software/thunderscope/log/trackers:tracker",
],
)

py_library(
name = "pass_results",
srcs = [
"pass_event.py",
"pass_result_tracker.py",
"pass_results.py",
],
deps = [
"//software/thunderscope/log/trackers:tracker",
],
)
11 changes: 8 additions & 3 deletions src/software/thunderscope/log/pass_results/pass_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,19 @@
Team,
)
from dataclasses import dataclass
from enum import auto, StrEnum
from enum import IntEnum
from proto.import_all_protos import *


class PassResultType(StrEnum):
class PassResultType(IntEnum):
"""Enum for the different types of pass results we want to log"""

RESULT_PRE = auto()
RESULT_1S = 1
RESULT_5S = 5
RESULT_10S = 10
RESULT_20S = 20
RESULT_30S = 30
RESULT_PRE = 0


@dataclass
Expand Down
167 changes: 167 additions & 0 deletions src/software/thunderscope/log/pass_results/pass_result_tracker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
from software.thunderscope.log.trackers.kick_tracker import PassTracker
from software.thunderscope.log.pass_results.pass_event import (
PassResultType,
TrackedPassResult,
)
from software.thunderscope.log.trackers.tracked_event import (
EventType,
Team,
get_event_from_world,
)
from typing import override
from dataclasses import dataclass
from software.thunderscope.constants import PassResultsConstants
from proto.import_all_protos import *
from software.thunderscope.proto_unix_io import ProtoUnixIO
import queue


@dataclass
class LoggedPass:
pass_: Pass
timestamp: float
score: float


class PassResultTracker(PassTracker):
def __init__(
self,
proto_unix_io: ProtoUnixIO,
from_team: Team,
event_queue: queue.Queue,
for_team: Team | None = None,
**kwargs,
):
"""Initializes the PassResultTracker

:param proto_unix_io: the proto unix io to get the game state from
:param from_team: the team that this tracker is tracking from (events are from this team)
:param for_team: the team that this tracker is tracking for (events are for this team)
default is same as the from_team, but can be different
:param event_queue: the queue to write events to
"""
super().__init__(
proto_unix_io=proto_unix_io,
from_team=from_team,
for_team=for_team if for_team is not None else from_team,
event_queue=event_queue,
**kwargs,
)

self.score = 0

self.intervals = [item.value for item in PassResultType]
self.interval_labels = [item.name for item in PassResultType]

self.logged_passes_map: dict[int, list[LoggedPass]] = {
interval: [] for interval in self.intervals
}

@override
def refresh(self) -> None:
super().refresh()

self._update_pass_timestamps()

@override
def write_event(self, event_type: EventType) -> None:
"""This method is called by the super-class when there is a new pass
Adds the pass to the first list of logged passes, at the smallest interval

:param event_type: (unused)
"""
if not self.curr_pass:
return

if not self.cached_world:
return

self.logged_passes_map[PassResultsConstants.INTERVALS_S[0]].append(
LoggedPass(
pass_=self.curr_pass,
timestamp=self.cached_world.getMostRecentTimestamp().toSeconds(),
score=self.score,
)
)

def set_score(self, score: float) -> None:
"""Sets the current game score to the given value

:param score: the new score
"""
self.score = score

def _log_pass_result(
self, pass_result_type: PassResultType, pass_: Pass, score: float = 0.0
) -> None:
"""Logs a single pass result, with the given pass, score, and event type

:param pass_result_type: the result type corresponding to the interval after which
we are logging the result
:param pass_: the pass whose results are being logged
:param score: the score for this pass's results compared to when the pass started
"""
if not self.cached_world:
return

pass_event = get_event_from_world(
world_msg=self.cached_world_msg,
event_type=EventType.PASS,
from_team=self.from_team,
for_team=self.for_team,
)

event = TrackedPassResult(
pass_event=pass_event,
pass_result_type=pass_result_type,
pass_=pass_,
score=score,
)

self.event_queue.put(event)

def _log_if_over_interval(
self, logged_pass: LoggedPass, interval: float, pass_result_type: PassResultType
) -> bool:
"""Checks if the given pass we logged is older than the given interval
If so, logs a result with the given type with the correct score

:param logged_pass: the pass we previously logged, with the timestamp and score at the time
:param interval: the interval that the pass may be older than
:param pass_result_type: the result type corresponding to this interval
:return: True if the pass is older than interval (and therefore result has been logged)
False if not
"""
if (
self.cached_world_msg.time_sent.epoch_timestamp_seconds
- logged_pass.timestamp
> interval
):
self._log_pass_result(
pass_result_type=pass_result_type,
pass_=logged_pass.pass_,
score=(self.score - logged_pass.score),
)

return True

return False

def _update_pass_timestamps(self):
"""For all currently logged passes, check if the interval they belong to has passed
If so, log that pass result
And move them to the next interval if exists
"""
for idx, interval in enumerate(self.intervals):
logged_passes = self.logged_passes_map[interval]

pass_result_type = self.interval_labels[idx]

# passes are in the list in chronological order
while self._log_if_over_interval(
logged_passes[0], interval, pass_result_type
):
logged_pass = logged_passes.pop(0)

if idx < len(self.intervals) - 1:
self.logged_passes_map[self.intervals[idx + 1]].append(logged_pass)
Loading