Skip to content

Commit 170f7c5

Browse files
committed
Merge branch 'main' into feature/supertone_tts
2 parents 3c48e27 + e50eebe commit 170f7c5

108 files changed

Lines changed: 13497 additions & 902 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.pre-commit-config.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
exclude: |
2+
(?x)(
3+
^src/lib/|
4+
^src/bitbots_team_communication/bitbots_team_communication/bitbots_team_communication/RobocupProtocol/
5+
)
6+
17
repos:
28
- repo: https://github.com/astral-sh/ruff-pre-commit
39
rev: v0.9.6
@@ -14,7 +20,6 @@ repos:
1420
args:
1521
- "-i"
1622
- id: cppcheck
17-
exclude: &exclude_robocup_protocol ^src/bitbots_team_communication/bitbots_team_communication/bitbots_team_communication/RobocupProtocol/
1823
args:
1924
- "--inline-suppr"
2025
- "--suppress=missingIncludeSystem"
@@ -28,13 +33,11 @@ repos:
2833
hooks:
2934
- id: cmake-format
3035
- id: cmake-lint
31-
exclude: *exclude_robocup_protocol
3236
- repo: https://github.com/pre-commit/pre-commit-hooks
3337
rev: v5.0.0
3438
hooks:
3539
- id: check-merge-conflict
3640
- id: check-toml
3741
- id: check-xml
3842
- id: check-yaml
39-
exclude: *exclude_robocup_protocol
4043
- id: detect-private-key

pixi.lock

Lines changed: 782 additions & 668 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pixi.toml

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ authors = ["Florian Vahl <7vahl@informatik.uni-hamburg.de>"]
33
channels = [
44
"https://data.bit-bots.de/conda/", # For self hosted ROS / robostack packages
55
"https://data.bit-bots.de/conda-misc/output/", # For self hosted misc (non-ROS, neural network weights, ...) packages
6-
"robostack-jazzy", # Robostack jazzy channel for ROS packages
6+
"robostack-jazzy", # Robostack jazzy channel for ROS packages
77
"conda-forge" # General conda-forge channel
88
]
99
name = "bitbots_main"
@@ -162,7 +162,7 @@ ros-jazzy-soccer-vision-3d-rviz-markers = ">=1.0.0,<2"
162162
ros-jazzy-soccer-vision-3d-msgs = ">=1.0.0,<2"
163163
ros-jazzy-soccer-vision-attribute-msgs = ">=1.0.0,<2"
164164
ros-jazzy-rot-conv = ">=1.1.0,<2"
165-
ros-jazzy-bio-ik = ">=2.0.0,<3"
165+
# ros-jazzy-bio-ik = ">=2.0.0,<3"
166166
ros-jazzy-bio-ik-msgs = ">=0.0.0,<0.0.1"
167167
ros-jazzy-biped-interfaces = ">=0.0.0,<0.0.1"
168168
ros-jazzy-bitbots-tf-buffer = ">=1.0.0,<2"
@@ -206,12 +206,17 @@ make = ">=4.4.1,<5" # To avoid issues in the CI
206206
webots = ">=2022b,<2023a"
207207

208208
[feature.format.dependencies]
209+
# Add git-subrepo to format dependencies as currently there are
210+
# sqlite conflicts in the default/ros environment preventing execution
211+
# of pre-commit hooks running after commits from the git-subrepo cli
212+
git-subrepo = ">=0.4.9,<0.5"
209213
clang-format = ">=21.1.0,<22"
210-
cppcheck = ">=2.18.3,<3"
214+
cppcheck = ">=2.18.3,<2.20"
211215
pre-commit = ">=4.4.0,<5"
212216

213217
[feature.ros.pypi-dependencies]
214218
# These are are pypi dependencies needed for our ROS 2 packages
219+
construct = ">=2.10.56, <3"
215220
syrupy = ">=5.0.0, <6"
216221
exhale = ">=0.3.7, <0.4"
217222

scripts/deploy/tasks/build.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def _clean(self, connections: Group) -> GroupResult:
4242
:return: The results of the task.
4343
"""
4444
print_debug(f"Cleaning the following packages before building: {self._package}")
45-
cmd_clean = f"cd {self._remote_workspace} && pixi run clean {self._package}"
45+
cmd_clean = f"cd {self._remote_workspace} && pixi run --environment robot clean {self._package}"
4646

4747
print_debug(f"Calling '{cmd_clean}'")
4848
try:
@@ -62,7 +62,7 @@ def _build(self, connections: Group) -> GroupResult:
6262
:return: The results of the task.
6363
"""
6464
print_debug("Building packages")
65-
cmd = f"cd {self._remote_workspace} && pixi run build {self._package}"
65+
cmd = f"cd {self._remote_workspace} && pixi run --environment robot build {self._package}"
6666

6767
print_debug(f"Calling '{cmd}'")
6868
try:

scripts/deploy/tasks/launch.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def _check_nodes_already_running(self, connections: Group) -> GroupResult:
5555
:return: Results, with success if ROS 2 nodes are not already running
5656
"""
5757
print_debug("Checking if ROS 2 nodes are already running")
58-
cmd = f"cd {self._remote_workspace} && pixi run ros2 node list -c"
58+
cmd = f"cd {self._remote_workspace} && pixi run --environment robot ros2 node list -c"
5959

6060
print_debug(f"Calling '{cmd}'")
6161
try:
@@ -152,7 +152,7 @@ def _check_tmux_session_already_running(self, connections: Group) -> GroupResult
152152
def _launch_teamplayer(self, connections: Group) -> GroupResult:
153153
print_debug("Launching teamplayer")
154154
# Create tmux session
155-
cmd = f"tmux new-session -d -s {self._tmux_session_name} && tmux send-keys -t {self._tmux_session_name} 'cd {self._remote_workspace} && pixi run ros2 launch bitbots_bringup teamplayer.launch record:=true tts:=false' Enter"
155+
cmd = f"tmux new-session -d -s {self._tmux_session_name} && tmux send-keys -t {self._tmux_session_name} 'cd {self._remote_workspace} && pixi run --environment robot ros2 launch bitbots_bringup teamplayer.launch record:=true tts:=false' Enter"
156156

157157
print_debug(f"Calling '{cmd}'")
158158
try:

scripts/deploy/tasks/sync.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ def _sync_single(connection: Connection) -> Result | None:
6767
print_error(f"Rsync command failed to execute on host {connection.host}")
6868
return
6969

70-
# Verify syncing succeeded and system architectures matches by running "pixi install"
71-
cmd = f"cd {self._remote_workspace} && pixi install"
70+
# Verify syncing succeeded and system architectures matches by running "pixi install --environment robot"
71+
cmd = f"cd {self._remote_workspace} && pixi install --environment robot"
7272
print_debug("Installing dependencies on remote host to verify synchronization and architecture match.")
7373
print_debug(f"Calling '{cmd}' on: {connection.host}")
7474
verify_result = connection.run(cmd, hide=hide_output())
Lines changed: 40 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from typing import Optional
22

33
from bitbots_utils.utils import get_parameters_from_other_node
4-
from game_controller_hl_interfaces.msg import GameState
4+
from game_controller_hsl_interfaces.msg import GameState
5+
from std_msgs.msg import Bool
56

67
from bitbots_blackboard.capsules import AbstractBlackboardCapsule
78

@@ -12,33 +13,44 @@ class GameStatusCapsule(AbstractBlackboardCapsule):
1213
def __init__(self, node, blackboard=None):
1314
super().__init__(node, blackboard)
1415
self.team_id: int = get_parameters_from_other_node(self._node, "parameter_blackboard", ["team_id"])["team_id"]
16+
self.own_id: int = get_parameters_from_other_node(self._node, "parameter_blackboard", ["bot_id"])["bot_id"]
1517
self.gamestate = GameState()
1618
self.last_update: float = 0.0
1719
self.unpenalized_time: float = 0.0
1820
self.last_goal_from_us_time = -86400.0
1921
self.last_goal_time = -86400.0
2022
self.free_kick_kickoff_team: Optional[bool] = None
23+
self.game_controller_stop: bool = False
24+
# publish stopped msg for hcm
25+
self.stop_pub = node.create_publisher(Bool, "game_controller/stop_msg", 1)
2126

22-
def get_gamestate(self) -> int:
23-
return self.gamestate.game_state
27+
def get_game_state(self) -> int:
28+
# Init, ready, set, playing, finished
29+
return self.gamestate.main_state
2430

25-
def get_secondary_state(self) -> int:
26-
return self.gamestate.secondary_state
31+
def get_game_phase(self) -> int:
32+
# Timeout, Normal, Extratime, Penaltyshoot
33+
return self.gamestate.game_phase
2734

28-
def get_secondary_state_mode(self) -> int:
29-
return self.gamestate.secondary_state_mode
35+
def get_set_play(self) -> int:
36+
# None, Direct Freekick, Indirect Freekick, Penalty, Throw in, Goalkick, Cornerkick,
37+
return self.gamestate.set_play
3038

3139
def get_secondary_team(self) -> int:
32-
return self.gamestate.secondary_state_team
40+
# Team ID, wer in set Play den Ball hat
41+
return self.gamestate.kicking_team
3342

3443
def has_kickoff(self) -> bool:
35-
return self.gamestate.has_kick_off
44+
# vegelcih mit eigener Teamnummer
45+
return self.gamestate.kicking_team == self.team_id
46+
47+
def is_stopped(self) -> bool:
48+
return self.gamestate.stopped
3649

3750
def has_penalty_kick(self) -> bool:
3851
return (
39-
self.gamestate.secondary_state == GameState.STATE_PENALTYKICK
40-
or self.gamestate.secondary_state == GameState.STATE_PENALTYSHOOT
41-
) and self.gamestate._secondary_state_team == self.team_id
52+
self.gamestate.set_play == GameState.SET_PLAY_PENALTY_KICK and self.gamestate.kicking_team == self.team_id
53+
)
4254

4355
def get_our_goals(self) -> int:
4456
return self.gamestate.own_score
@@ -55,26 +67,17 @@ def get_seconds_since_any_goal(self) -> float:
5567
def get_seconds_remaining(self) -> float:
5668
# Time from the message minus time passed since receiving it
5769
return max(
58-
self.gamestate.seconds_remaining - (self._node.get_clock().now().nanoseconds / 1e9 - self.last_update), 0.0
70+
self.gamestate.secs_remaining - (self._node.get_clock().now().nanoseconds / 1e9 - self.last_update), 0.0
5971
)
6072

6173
def get_secondary_seconds_remaining(self) -> float:
6274
"""Seconds remaining for things like kickoff"""
6375
# Time from the message minus time passed since receiving it
6476
return max(
65-
self.gamestate.secondary_seconds_remaining
66-
- (self._node.get_clock().now().nanoseconds / 1e9 - self.last_update),
77+
self.gamestate.secondary_time - (self._node.get_clock().now().nanoseconds / 1e9 - self.last_update),
6778
0.0,
6879
)
6980

70-
def get_seconds_since_last_drop_ball(self) -> Optional[float]:
71-
"""Returns the seconds since the last drop in"""
72-
if self.gamestate.drop_in_time == -1:
73-
return None
74-
else:
75-
# Time from the message plus seconds passed since receiving it
76-
return self.gamestate.drop_in_time + (self._node.get_clock().now().nanoseconds / 1e9 - self.last_update)
77-
7881
def get_seconds_since_unpenalized(self) -> float:
7982
return self._node.get_clock().now().nanoseconds / 1e9 - self.unpenalized_time
8083

@@ -87,9 +90,6 @@ def received_gamestate(self) -> bool:
8790
def get_team_id(self) -> int:
8891
return self.team_id
8992

90-
def get_red_cards(self) -> int:
91-
return self.gamestate.team_mates_with_red_card
92-
9393
def gamestate_callback(self, gamestate_msg: GameState) -> None:
9494
if self.gamestate.penalized and not gamestate_msg.penalized:
9595
self.unpenalized_time = self._node.get_clock().now().nanoseconds / 1e9
@@ -101,21 +101,29 @@ def gamestate_callback(self, gamestate_msg: GameState) -> None:
101101
if gamestate_msg.rival_score > self.gamestate.rival_score:
102102
self.last_goal_time = self._node.get_clock().now().nanoseconds / 1e9
103103

104+
self.game_controller_stop = gamestate_msg.stopped
105+
106+
self.stop_pub.publish(Bool(data=self.game_controller_stop))
107+
108+
"""Anstoß im Falle von Overtime jetzt erstmal nicht genauer geregelt
104109
if (
105-
gamestate_msg.secondary_state_mode == 2
106-
and self.gamestate.secondary_state_mode != 2
107-
and gamestate_msg.game_state == GameState.GAMESTATE_PLAYING
110+
gamestate_msg.main_state == GameState.STATE_SET
111+
and self.gamestate.setPlay != 2
112+
and gamestate_msg.state == GameState.STATE_PLAYING
108113
):
109114
# secondary action is now executed but we will not see this in the new messages.
110115
# it will look like a normal kick off, but we need to remember that this is some sort of free kick
111116
# we set the kickoff value accordingly, then we will not be allowed to move if it is a kick for the others
112-
self.free_kick_kickoff_team = gamestate_msg.secondary_state_team
117+
self.free_kick_kickoff_team = gamestate_msg.kicking_team
113118
114-
if gamestate_msg.secondary_state_mode != 2 and gamestate_msg.secondary_seconds_remaining == 0:
119+
if gamestate_msg.set_play != 2 and gamestate_msg.secondary_time == 0:
120+
self.free_kick_kickoff_team = gamestate_msg.kicking_team
121+
122+
if gamestate_msg.set_play != 2 and gamestate_msg.secondary_time == 0:
115123
self.free_kick_kickoff_team = None
116124
117125
if self.free_kick_kickoff_team is not None:
118126
gamestate_msg.has_kick_off = self.free_kick_kickoff_team == self.team_id
119-
127+
"""
120128
self.last_update = self._node.get_clock().now().nanoseconds / 1e9
121129
self.gamestate = gamestate_msg

src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/world_model_capsule.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,10 @@ def __init__(self, node, blackboard):
5858
self.map_margin: float = self._node.get_parameter("map_margin").value
5959

6060
# Ball state
61+
# The ball in the map frame (default to the center of the field if ball is not seen yet)
6162
self._ball: PointStamped = PointStamped(
62-
header=Header(stamp=Time(clock_type=ClockType.ROS_TIME), frame_id=self.map_frame)
63-
) # The ball in the map frame (default to the center of the field if ball is not seen yet)
63+
header=Header(stamp=Time(clock_type=ClockType.ROS_TIME).to_msg(), frame_id=self.map_frame)
64+
)
6465
self._ball_covariance: np.ndarray = np.zeros((2, 2)) # Covariance of the ball
6566

6667
# Publisher for visualization in RViZ

src/bitbots_behavior/bitbots_blackboard/package.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
<build_depend>bitbots_docs</build_depend>
2424
<depend>bitbots_tf_buffer</depend>
2525
<depend>bitbots_utils</depend>
26-
<depend>game_controller_hl_interfaces</depend>
26+
<depend>game_controller_hsl_interfaces</depend>
2727
<depend>python3-numpy</depend>
2828
<depend>rclpy</depend>
2929
<depend>ros2_numpy</depend>

src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/game_state_decider.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from bitbots_blackboard.body_blackboard import BodyBlackboard
22
from dynamic_stack_decider.abstract_decision_element import AbstractDecisionElement
3-
from game_controller_hl_interfaces.msg import GameState
3+
from game_controller_hsl_interfaces.msg import GameState
44

55

66
class GameStateDecider(AbstractDecisionElement):
@@ -16,18 +16,28 @@ def perform(self, reevaluate=False):
1616
:return:
1717
"""
1818

19-
game_state_number = self.blackboard.gamestate.get_gamestate()
19+
game_state_number = self.blackboard.gamestate.get_game_state()
20+
is_stopped = self.blackboard.gamestate.is_stopped()
2021
# todo this is a temporary hack to make GUI work
21-
if game_state_number == GameState.GAMESTATE_INITIAL:
22+
if is_stopped:
23+
return "STOPPED"
24+
elif game_state_number == GameState.STATE_INITIAL:
2225
return "INITIAL"
23-
elif game_state_number == GameState.GAMESTATE_READY:
26+
elif game_state_number == GameState.STATE_READY:
2427
return "READY"
25-
elif game_state_number == GameState.GAMESTATE_SET:
28+
elif game_state_number == GameState.STATE_SET:
2629
return "SET"
27-
elif game_state_number == GameState.GAMESTATE_PLAYING:
30+
elif game_state_number == GameState.STATE_PLAYING:
2831
return "PLAYING"
29-
elif game_state_number == GameState.GAMESTATE_FINISHED:
32+
elif game_state_number == GameState.STATE_FINISHED:
3033
return "FINISHED"
34+
elif game_state_number == GameState.STATE_STANDBY:
35+
return "STANDBY"
36+
else:
37+
# This should never happen, but all cases required string response
38+
# as we do not get any stack trace otherwise
39+
self.blackboard.node.get_logger().error(f"Received unknown game state number: {game_state_number}")
40+
return "UNKNOWN"
3141

3242
def get_reevaluate(self):
3343
"""

0 commit comments

Comments
 (0)