Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
51 changes: 51 additions & 0 deletions entities/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,60 @@ This folder contains `namedtuple` declarations that are used across the reposito
- `vision.py` declares the namedtuples output from our vision systems (grSim or SSLVision)
- TODO: `instruction.py` declares the namedtuples compiled and sent to the physical robots

## game

- `game.py` contains all records of the various frames in this game
- `field.py` contains the pre-defined positions of critical field objects, stored as `Shapely` objects for easy spatial analysis
- `ball.py`, `robot.py` are not currently in use, but can be implemented to create persistent objects to store relevant info about the ball or each robot
- `team_info.py`
- `referee_command.py`
- `stage.py`

# entities

Contains the entity objects used to store game state and game data.

## data

This folder contains `namedtuple` declarations that are used across the repository.

- `vision.py` declares the namedtuples output from our vision systems (grSim or SSLVision)
- TODO: `instruction.py` declares the namedtuples compiled and sent to the physical robots

## game

- `game.py` contains all records of the various frames in this game
- `field.py` contains the pre-defined positions of critical field objects, stored as `Shapely` objects for easy spatial analysis
- `ball.py`, `robot.py` are not currently in use, but can be implemented to create persistent objects to store relevant info about the ball or each robot
- `team_info.py`: **TeamInfo Class** represents the information about a team, including the team's name, score, red and yellow cards, timeouts, and goalie.
- **Attributes**:
- `name`: The team's name.
- `score`: The number of goals scored by the team.
- `red_cards`: The number of red cards issued to the team.
- `yellow_cards`: The total number of yellow cards ever issued to the team.
- `timeouts`: The number of timeouts this team can still call.
- `timeout_time`: The number of microseconds of timeout this team can use.
- **Methods**:
- `parse_referee_packet(packet)`: Parses the referee packet and updates the team information.

## referee

This folder contains classes related to the referee system and game state management.

### referee_command.py

- **RefereeCommand Class**: Represents a referee command with an ID and name.
- **Attributes**:
- `command_id`: The ID of the command.
- `name`: The name of the command.
- **Methods**:
- `from_id(command_id: int)`: Creates a `Command` instance from the given command ID.

### stage.py

- **Stage Class**: Represents a game stage with an ID and name.
- **Attributes**:
- `stage_id`: The ID of the stage.
- `name`: The name of the stage.
- **Methods**:
- `from_id(stage_id: int)`: Creates a `Stage` instance from the given stage ID.
68 changes: 68 additions & 0 deletions entities/game/team_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
class TeamInfo:
"""
Class containing information about a team.
"""

def __init__(
self,
name: str,
score: int = 0,
red_cards: int = 0,
yellow_cards: int = 0,
timeouts: int = 0,
timeout_time: int = 0,
):
# The team's name (empty string if operator has not typed anything).
self.name = name
# The number of goals scored by the team during normal play and overtime.
self.score = score
# The number of red cards issued to the team since the beginning of the
# game.
self.red_cards = red_cards
# The total number of yellow cards ever issued to the team.
self.yellow_cards = yellow_cards
# The number of timeouts this team can still call.
# If in a timeout right now, that timeout is excluded.
self.timeouts = timeouts
# The number of microseconds of timeout this team can use.
self.timeout_time = timeout_time

def __repr__(self):
return (
f"Team Name : {self.name}\n"
f"Score : {self.score}\n"
f"Red Cards : {self.red_cards}\n"
f"Yellow Cards : {self.yellow_cards}\n"
f"Timeouts Left : {self.timeouts}\n"
f"Timeout Time : {self.timeout_time} usn"
)

def parse_referee_packet(self, packet):
"""
Parses the SSL_Referee_TeamInfo packet and updates the team information.

Args:
packet (SSL_Referee_TeamInfo): The packet containing team information.
"""
self.name = packet.name
self.score = packet.score
self.red_cards = packet.red_cards
self.yellow_cards = packet.yellow_cards
self.timeouts_left = packet.timeouts
self.timeout_time = packet.timeout_time

def increment_score(self):
self.score += 1

def increment_red_cards(self):
self.red_cards += 1

def increment_yellow_cards(self):
self.yellow_cards += 1

def decrement_timeouts(self):
if self.timeouts > 0:
self.timeouts -= 1

def add_timeout_time(self, time: int):
self.timeout_time += time
36 changes: 36 additions & 0 deletions entities/referee/referee_command.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class RefereeCommand:
"""
Class representing a referee command.
"""

def __init__(self, command_id: int, name: str):
self.command_id = command_id
self.name = name

def __repr__(self):
return f"RefereeCommand(id={self.command_id}, name={self.name})"

@staticmethod
def from_id(command_id: int):
command_map = {
0: "HALT",
1: "STOP",
2: "NORMAL_START",
3: "FORCE_START",
4: "PREPARE_KICKOFF_YELLOW",
5: "PREPARE_KICKOFF_BLUE",
6: "PREPARE_PENALTY_YELLOW",
7: "PREPARE_PENALTY_BLUE",
8: "DIRECT_FREE_YELLOW",
9: "DIRECT_FREE_BLUE",
10: "INDIRECT_FREE_YELLOW",
11: "INDIRECT_FREE_BLUE",
12: "TIMEOUT_YELLOW",
13: "TIMEOUT_BLUE",
14: "GOAL_YELLOW",
15: "GOAL_BLUE",
16: "BALL_PLACEMENT_YELLOW",
17: "BALL_PLACEMENT_BLUE",
}
name = command_map.get(command_id, "UNKNOWN")
return RefereeCommand(command_id, name)
32 changes: 32 additions & 0 deletions entities/referee/stage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
class Stage:
"""
Class representing a game stage.
"""

def __init__(self, stage_id: int, name: str):
self.stage_id = stage_id
self.name = name

def __repr__(self):
return f"Stage(id={self.stage_id}, name={self.name})"

@staticmethod
def from_id(stage_id: int):
stage_map = {
0: "NORMAL_FIRST_HALF_PRE",
1: "NORMAL_FIRST_HALF",
2: "NORMAL_HALF_TIME",
3: "NORMAL_SECOND_HALF_PRE",
4: "NORMAL_SECOND_HALF",
5: "EXTRA_TIME_BREAK",
6: "EXTRA_FIRST_HALF_PRE",
7: "EXTRA_FIRST_HALF",
8: "EXTRA_HALF_TIME",
9: "EXTRA_SECOND_HALF_PRE",
10: "EXTRA_SECOND_HALF",
11: "PENALTY_SHOOTOUT_BREAK",
12: "PENALTY_SHOOTOUT",
13: "POST_GAME",
}
name = stage_map.get(stage_id, "UNKNOWN")
return Stage(stage_id, name)
16 changes: 11 additions & 5 deletions main.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import threading
from entities.game import Game
from team_controller.src.data.referee_receiver import RefereeMessageReceiver
from team_controller.src.data.vision_receiver import VisionDataReceiver


Expand All @@ -12,12 +13,17 @@ def main():
game = Game()
# Initialize the VisionDataReceiver
receiver = VisionDataReceiver(debug=False)
referee_receiver = RefereeMessageReceiver(debug=True)

# Start the data receiving in a separate thread
data_thread = threading.Thread(target=data_update_listener, args=(receiver,))
data_thread.daemon = True # Allows the thread to close when the main program exits
data_thread.start()

referee_thread = threading.Thread(target=referee_receiver.pull_referee_data)
referee_thread.daemon = True
referee_thread.start()

try:
while True:
# Wait for the update event with a timeout (optional)
Expand All @@ -27,13 +33,13 @@ def main():
game.add_new_state(frame_data)

# access current state data
print(
game.current_state.yellow_robots[0].x,
game.current_state.yellow_robots[0].y,
)
# print(
# game.current_state.yellow_robots[0].x,
# game.current_state.yellow_robots[0].y,
# )

# access game records from -x number of frames ago
print(game.records[-1].ts, game.records[-1].ball[0].x)
# print(game.records[-1].ts, game.records[-1].ball[0].x)
else:
print("No data update received within the timeout period.")

Expand Down
4 changes: 3 additions & 1 deletion team_controller/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ This folder contains all the different controller classes for communication with
This folder contains all the files which perform the initial processing of data being received, this includes:

- **Referee Data**
> Note: Referee Message Parsing is not yet implemented.
- Receives and processes referee messages containing game state information.
- Updates internal data structures with the latest referee commands, stage, team information, and designated ball placement positions.
- Provides methods to retrieve the latest referee data, command, stage, and other relevant information.
- **Vision Data**
- The `VisionDataReceiver` class is responsible for receiving and managing vision data for robots and the ball in a multi-robot game environment. It interfaces with a network manager to receive packets containing positional data for the ball and robots on both teams. The class updates internal data structures accordingly. Here is an [example usage](src/tests/vision_receiver_test.py).
- **Data Types**:
Expand Down
Loading