Skip to content

Commit 887e904

Browse files
authored
Whistle detection (#775)
2 parents e50eebe + d2800f8 commit 887e904

75 files changed

Lines changed: 6419 additions & 1046 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.

pixi.lock

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

pixi.toml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ readline = ">=8.2.999" # This is needed because we want to install an empty rea
3737

3838
[feature.ros.dependencies]
3939
# Misc dependencies for our ROS 2 packages
40+
alsa-plugins = ">=1.2.12,<2"
4041
beartype = ">=0.22.6,<0.23"
4142
breathe = ">=4.36.0,<5"
4243
cmake = "<3.30" # Constraint to avoid issues with deprecated features in newer cmake versions
@@ -51,6 +52,7 @@ ipython = ">=9.7.0,<10"
5152
jaxtyping = ">=0.3.2,<0.4"
5253
jinja2 = ">=3.1.6,<4"
5354
libboost-devel = ">=1.86.0,<2"
55+
libflac = "==1.4.3"
5456
libnuma = ">=2.0.18,<3"
5557
libopencv = ">=4.11.0,<5"
5658
libprotobuf = ">=6.31.1,<7"
@@ -62,6 +64,7 @@ opencv = ">=4.11.0,<5"
6264
paramiko = ">=4.0.0,<5"
6365
pkg-config = ">=0.29.2,<0.30"
6466
playsound = ">=1.3.0,<2"
67+
portaudio = ">=19.7.0,<20"
6568
protobuf = ">=6.31.1,<7"
6669
psutil = ">=7.1.3,<8"
6770
pthread-stubs = ">=0.4,<0.5"
@@ -84,6 +87,7 @@ colcon-common-extensions = ">=0.3.0,<0.4"
8487
colcon-notification = ">=0.3.0,<0.4"
8588
ros-jazzy-action-msgs = ">=2.0.3,<3"
8689
ros-jazzy-ament-cmake = ">=2.5.4,<3"
90+
ros-jazzy-ament-cmake-clang-format = ">=0.17.3,<0.18"
8791
ros-jazzy-ament-cmake-mypy = ">=0.17.3,<0.18"
8892
ros-jazzy-ament-copyright = ">=0.17.3,<0.18"
8993
ros-jazzy-ament-flake8 = ">=0.17.3,<0.18"
@@ -131,6 +135,7 @@ ros-jazzy-rosbridge-suite = ">=2.3.0,<3"
131135
ros-jazzy-rosgraph-msgs = ">=2.0.3,<3"
132136
ros-jazzy-rosidl-default-generators = ">=1.6.0,<2"
133137
ros-jazzy-rosidl-default-runtime = ">=1.6.0,<2"
138+
ros-jazzy-rosidl-runtime-c = ">=4.6.7,<5"
134139
ros-jazzy-rqt-gui = ">=1.6.0,<2"
135140
ros-jazzy-rqt-gui-py = ">=1.6.0,<2"
136141
ros-jazzy-sensor-msgs = ">=5.3.6,<6"
@@ -165,7 +170,6 @@ ros-jazzy-bio-ik-msgs = ">=0.0.0,<0.0.1"
165170
ros-jazzy-biped-interfaces = ">=0.0.0,<0.0.1"
166171
ros-jazzy-bitbots-tf-buffer = ">=1.0.0,<2"
167172
ros-jazzy-ros2-python-extension = ">=1.0.0,<2"
168-
ros-jazzy-audio-common = ">=0.3.15,<0.4"
169173
ros-jazzy-dynamic-stack-decider = ">=0.5.3,<0.6"
170174
ros-jazzy-dynamic-stack-decider-visualization = ">=0.2.1,<0.3"
171175
ros-jazzy-game-controller-hl = ">=1.1.0,<2"
@@ -238,6 +242,7 @@ RMW_IMPLEMENTATION = "rmw_cyclonedds_cpp"
238242
COLCON_LOG_LEVEL = "30"
239243
PYTHONWARNINGS="ignore:::setuptools.command.install,ignore:::setuptools.command.easy_install,ignore:::pkg_resources,ignore:easy_install command is deprecated,ignore:setup.py install is deprecated"
240244
WEBOTS_HOME = "$CONDA_PREFIX/share/webots"
245+
ALSA_PLUGIN_DIR = "/usr/lib/x86_64-linux-gnu/alsa-lib"
241246

242247
[feature.ros.activation]
243248
scripts = [
@@ -249,3 +254,4 @@ scripts = [
249254
default = ["ros", "format"] # Full development environment (excluding robot-only deps)
250255
format = ["format"] # Format only environment
251256
robot = ["ros", "format", "robot"] # Robot environment with additional robot-only dependencies
257+

src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/game_status_capsule.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
from typing import Optional
2-
31
from bitbots_utils.utils import get_parameters_from_other_node
2+
from builtin_interfaces.msg import Time as TimeMsg
43
from game_controller_hsl_interfaces.msg import GameState
4+
from rclpy.time import Time
55
from std_msgs.msg import Bool
66

77
from bitbots_blackboard.capsules import AbstractBlackboardCapsule
@@ -19,8 +19,9 @@ def __init__(self, node, blackboard=None):
1919
self.unpenalized_time: float = 0.0
2020
self.last_goal_from_us_time = -86400.0
2121
self.last_goal_time = -86400.0
22-
self.free_kick_kickoff_team: Optional[bool] = None
22+
self.free_kick_kickoff_team: bool | None = None
2323
self.game_controller_stop: bool = False
24+
self.last_timestep_whistle_detected: Time | None = None
2425
# publish stopped msg for hcm
2526
self.stop_pub = node.create_publisher(Bool, "game_controller/stop_msg", 1)
2627

@@ -127,3 +128,6 @@ def gamestate_callback(self, gamestate_msg: GameState) -> None:
127128
"""
128129
self.last_update = self._node.get_clock().now().nanoseconds / 1e9
129130
self.gamestate = gamestate_msg
131+
132+
def whistle_detection_callback(self, msg: TimeMsg) -> None:
133+
self.last_timestep_whistle_detected = Time.from_msg(msg)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
from bitbots_blackboard.body_blackboard import BodyBlackboard
2+
from dynamic_stack_decider.abstract_decision_element import AbstractDecisionElement
3+
4+
5+
class WhistleDetected(AbstractDecisionElement):
6+
blackboard: BodyBlackboard
7+
8+
def __init__(self, blackboard, dsd, parameters):
9+
super().__init__(blackboard, dsd, parameters)
10+
self.previous_timestep_whistle_detected = self.blackboard.gamestate.last_timestep_whistle_detected
11+
12+
def perform(self, reevaluate=False):
13+
"""
14+
Returns "DETECTED" if a whistle was detected while the decision element was active, as part of the
15+
DSD stack. If we have detected a whistle previously, but not during this decision element being on
16+
the decision stack it counts as "NOT_DETECTED".
17+
"""
18+
if self.previous_timestep_whistle_detected == self.blackboard.gamestate.last_timestep_whistle_detected:
19+
return "NOT_DETECTED"
20+
21+
return "DETECTED"
22+
23+
def get_reevaluate(self):
24+
return True

src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,16 @@ $BallSeen
130130
SECOND --> #SupporterRole
131131
THIRD --> #DefensePositioning
132132

133+
#PlayingBehavior
134+
$SecondaryStateDecider
135+
PENALTYSHOOT --> #PenaltyShootoutBehavior
136+
TIMEOUT --> #StandAndLook
137+
ELSE --> $SecondaryStateTeamDecider
138+
OUR --> #NormalBehavior
139+
OTHER --> #Placing
140+
NORMAL --> #NormalBehavior
141+
OVERTIME --> #NormalBehavior
142+
133143
-->BodyBehavior
134144
$IsPenalized
135145
YES --> #DoNothing
@@ -143,23 +153,18 @@ $IsPenalized
143153
NO --> $DoOnce
144154
NOT_DONE --> @ChangeAction + action:waiting + r:false, @LookAtFieldFeatures + r:false, @Stand + duration:2
145155
DONE --> #PositioningReady
146-
SET --> $SecondaryStateDecider
147-
PENALTYSHOOT --> $SecondaryStateTeamDecider
148-
OUR --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @Stand
149-
OTHER --> $BallSeen
150-
YES --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @TrackBall + r:false, @PlayAnimationGoalieArms + r:false, @Stand // goalie only needs to care about the ball
151-
NO --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @LookAtFieldFeatures + r:false, @PlayAnimationGoalieArms + r:false, @Stand
152-
ELSE --> #StandAndLook
156+
SET --> $WhistleDetected
157+
DETECTED --> #PlayingBehavior
158+
NOT_DETECTED --> $SecondaryStateDecider
159+
PENALTYSHOOT --> $SecondaryStateTeamDecider
160+
OUR --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @Stand // we need to also see the goalie
161+
OTHER --> $BallSeen
162+
YES --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @TrackBall + r:false, @PlayAnimationGoalieArms + r:false, @Stand // goalie only needs to care about the ball
163+
NO --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @LookAtFieldFeatures + r:false, @PlayAnimationGoalieArms + r:false, @Stand
164+
ELSE --> #StandAndLook
153165
FINISHED --> $CurrentScore
154166
AHEAD --> @Stand + duration:0.5 + r:false, @PlaySound + file:fanfare.wav, @PlayAnimationCheering + r:false, @GetWalkready + r:false, @LookForward, @Stand
155167
ELSE --> #Init
156-
PLAYING --> $SecondaryStateDecider
157-
PENALTYSHOOT --> #PenaltyShootoutBehavior
158-
TIMEOUT --> #StandAndLook
159-
ELSE --> $SecondaryStateTeamDecider
160-
OUR --> #NormalBehavior
161-
OTHER --> #Placing
162-
NORMAL --> #NormalBehavior
163-
OVERTIME --> #NormalBehavior
168+
PLAYING --> #PlayingBehavior
164169
STANDBY --> #StandAndLook
165170
STOPPED --> #DoNothing

src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/body_behavior.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import rclpy
44
from bitbots_blackboard.body_blackboard import BodyBlackboard
55
from bitbots_tf_buffer import Buffer
6+
from builtin_interfaces.msg import Time as TimeMsg
67
from dynamic_stack_decider.dsd import DSD
78
from game_controller_hsl_interfaces.msg import GameState
89
from geometry_msgs.msg import PoseWithCovarianceStamped, Twist
@@ -75,6 +76,13 @@ def __init__(self, node: Node):
7576
qos_profile=1,
7677
callback_group=MutuallyExclusiveCallbackGroup(),
7778
)
79+
node.create_subscription(
80+
TimeMsg,
81+
"whistle_detected",
82+
blackboard.gamestate.whistle_detection_callback,
83+
qos_profile=1,
84+
callback_group=MutuallyExclusiveCallbackGroup(),
85+
)
7886

7987
def loop(self):
8088
try:

src/bitbots_behavior/bitbots_body_behavior/package.xml

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,16 +30,17 @@
3030
<depend>soccer_vision_3d_msgs</depend>
3131
<depend>tf_transformations</depend>
3232
<depend>tf2</depend>
33-
<test_depend>ament_mypy</test_depend>
33+
<depend>std_msgs</depend>
34+
<test_depend>ament_mypy</test_depend>
3435

35-
<test_depend>python3-pytest</test_depend>
36+
<test_depend>python3-pytest</test_depend>
3637

37-
<export>
38-
<rosdoc config="rosdoc.yaml"/>
39-
<bitbots_documentation>
40-
<status>starts</status>
41-
<language>python3</language>
42-
</bitbots_documentation>
43-
<build_type>ament_python</build_type>
44-
</export>
45-
</package>
38+
<export>
39+
<rosdoc config="rosdoc.yaml"/>
40+
<bitbots_documentation>
41+
<status>starts</status>
42+
<language>python3</language>
43+
</bitbots_documentation>
44+
<build_type>ament_python</build_type>
45+
</export>
46+
</package>

src/bitbots_misc/bitbots_bringup/launch/README.md

Lines changed: 0 additions & 17 deletions
This file was deleted.
Lines changed: 10 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,14 @@
11
<?xml version="1.0"?>
22
<launch>
3-
<arg name="sim" default="false" description="If true, we don't capture audio" />
4-
<arg name="dst" default="appsink"/>
5-
<arg name="device" default=""/>
6-
<arg name="format" default="wave"/>
7-
<arg name="bitrate" default="128"/>
8-
<arg name="channels" default="1"/>
9-
<arg name="depth" default="16"/>
10-
<arg name="sample_rate" default="10000"/>
11-
<arg name="sample_format" default="S16LE"/>
12-
<arg name="ns" default="audio"/>
13-
<arg name="audio_topic" default="audio" />
3+
<!-- Our code currently is not sample_rate agnostic, but this must be overwritable to start the audio_capturer_node
4+
on some audio drivers/devices if they do not support the default sample_rate of 16000. -->
5+
<arg name="sample_rate" default="16000" description="The sample_rate with which the audio should be captured"/>
146

15-
<group unless="$(var sim)">
16-
<include file="$(find-pkg-share audio_capture)/launch/capture.launch.xml">
17-
<arg name="dst" value="$(var dst)"/>
18-
<arg name="device" value="$(var device)"/>
19-
<arg name="format" value="$(var format)"/>
20-
<arg name="bitrate" value="$(var bitrate)"/>
21-
<arg name="channels" value="$(var channels)"/>
22-
<arg name="depth" value="$(var depth)"/>
23-
<arg name="sample_rate" value="$(var sample_rate)"/>
24-
<arg name="sample_format" value="$(var sample_format)"/>
25-
<arg name="ns" value="$(var ns)"/>
26-
<arg name="audio_topic" value="$(var audio_topic)"/>
27-
</include>
28-
</group>
7+
<node
8+
pkg="audio_common"
9+
exec="audio_capturer_node"
10+
name="audio_capturer_node"
11+
output="screen">
12+
<param name="rate" value="$(var sample_rate)"/>
13+
</node>
2914
</launch>

src/bitbots_misc/bitbots_bringup/launch/highlevel.launch

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
<arg name="vision" default="true" description="Whether the vision system should be started" />
1313
<arg name="workspace_status" default="true" description="Whether to publish the current workspace status"/>
1414
<arg name="world_model" default="true" description="Whether the world model should be started"/>
15+
<arg name="whistle_detector" default="true" description="Whether whistle detector should be started"/>
1516

1617

1718
<!-- launch game controller -->
@@ -55,7 +56,9 @@
5556
<arg name="sim" value="$(var sim)"/>
5657
</include>
5758
</group>
58-
59+
<group if="$(var whistle_detector)">
60+
<include file="$(find-pkg-share bitbots_whistle_detector)/launch/whistle_detector.launch"/>
61+
</group>
5962
<!-- launch localization or fake localization -->
6063
<group if="$(var localization)">
6164
<include file="$(find-pkg-share bitbots_localization)/launch/localization.launch">
@@ -87,7 +90,6 @@
8790
<!-- launch audio processing -->
8891
<group if="$(var audio)">
8992
<include file="$(find-pkg-share bitbots_bringup)/launch/audio.launch">
90-
<arg name="sim" value="$(var sim)" />
9193
</include>
9294
</group>
9395

0 commit comments

Comments
 (0)