Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
b77d8be
add prototype dataflow of whistle detection
val-ba Feb 28, 2026
d349153
add whistle detector package
val-ba Feb 28, 2026
25cabdb
put project whistle detection code into whistle detector node
val-ba Mar 5, 2026
8b3c0ee
add model to share in setup py
val-ba Mar 5, 2026
b476e5a
fix wrong package structure
val-ba Mar 10, 2026
eff33a9
fix package naming
val-ba Mar 10, 2026
ec74f94
add whistle detection based on frequency bands
val-ba Mar 10, 2026
51acc88
add launch files
val-ba Mar 10, 2026
b8ef1be
add plugin dir for pipewire
val-ba Mar 10, 2026
ac237f2
update dsd for whistle detection and decision
val-ba Mar 10, 2026
a2bddc8
fix wrong anming of capsule in whistle decision
val-ba Mar 10, 2026
c3ec16f
fix wrong placement of launch file
val-ba Mar 10, 2026
1142976
git subrepo clone git@github.com:mgonzs13/audio_common.git src/lib/au…
texhnolyze Mar 12, 2026
d5ef600
update the audio launch
val-ba Mar 10, 2026
b1b292e
fix audio launch script
val-ba Mar 11, 2026
5fcdb01
simplify audio.launch
val-ba Mar 11, 2026
d8a19a4
add dependencies
val-ba Mar 11, 2026
edb0fb1
remove unnecessary launch of whistle detection in head mover test
val-ba Mar 11, 2026
9bb6b8a
remove command in setup.py
val-ba Mar 11, 2026
1416fab
move whistle detector to misc and add extra launch param
val-ba Mar 11, 2026
57077d7
be more conservative with whistle threshold
val-ba Mar 11, 2026
101fcf8
remove comments
val-ba Mar 12, 2026
faf8cca
chore(bitbots_whistle_detector): add `resource` marker
texhnolyze Mar 12, 2026
84ebddd
fix(whistle_detection): correctly localize during `STATE_SET` + whistle
cleWu03 Mar 12, 2026
689da17
Adjust rosbag record to new audio topic
jaagut Mar 13, 2026
32cab42
refactor(whistle_detection): publish `Time` when detected
texhnolyze Mar 13, 2026
69488fa
fix(audio): disable audio capture in sim by default
texhnolyze Mar 13, 2026
d2800f8
style(pixi): reorder dependencies
texhnolyze Mar 13, 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,730 changes: 764 additions & 966 deletions pixi.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ readline = ">=8.2.999" # This is needed because we want to install an empty rea

[feature.ros.dependencies]
# Misc dependencies for our ROS 2 packages
alsa-plugins = ">=1.2.12,<2"
beartype = ">=0.22.6,<0.23"
breathe = ">=4.36.0,<5"
cmake = "<3.30" # Constraint to avoid issues with deprecated features in newer cmake versions
Expand All @@ -51,6 +52,7 @@ ipython = ">=9.7.0,<10"
jaxtyping = ">=0.3.2,<0.4"
jinja2 = ">=3.1.6,<4"
libboost-devel = ">=1.86.0,<2"
libflac = "==1.4.3"
libnuma = ">=2.0.18,<3"
libopencv = ">=4.11.0,<5"
libprotobuf = ">=6.31.1,<7"
Expand All @@ -62,6 +64,7 @@ opencv = ">=4.11.0,<5"
paramiko = ">=4.0.0,<5"
pkg-config = ">=0.29.2,<0.30"
playsound = ">=1.3.0,<2"
portaudio = ">=19.7.0,<20"
protobuf = ">=6.31.1,<7"
psutil = ">=7.1.3,<8"
pthread-stubs = ">=0.4,<0.5"
Expand All @@ -84,6 +87,7 @@ colcon-common-extensions = ">=0.3.0,<0.4"
colcon-notification = ">=0.3.0,<0.4"
ros-jazzy-action-msgs = ">=2.0.3,<3"
ros-jazzy-ament-cmake = ">=2.5.4,<3"
ros-jazzy-ament-cmake-clang-format = ">=0.17.3,<0.18"
ros-jazzy-ament-cmake-mypy = ">=0.17.3,<0.18"
ros-jazzy-ament-copyright = ">=0.17.3,<0.18"
ros-jazzy-ament-flake8 = ">=0.17.3,<0.18"
Expand Down Expand Up @@ -131,6 +135,7 @@ ros-jazzy-rosbridge-suite = ">=2.3.0,<3"
ros-jazzy-rosgraph-msgs = ">=2.0.3,<3"
ros-jazzy-rosidl-default-generators = ">=1.6.0,<2"
ros-jazzy-rosidl-default-runtime = ">=1.6.0,<2"
ros-jazzy-rosidl-runtime-c = ">=4.6.7,<5"
ros-jazzy-rqt-gui = ">=1.6.0,<2"
ros-jazzy-rqt-gui-py = ">=1.6.0,<2"
ros-jazzy-sensor-msgs = ">=5.3.6,<6"
Expand Down Expand Up @@ -165,7 +170,6 @@ ros-jazzy-bio-ik-msgs = ">=0.0.0,<0.0.1"
ros-jazzy-biped-interfaces = ">=0.0.0,<0.0.1"
ros-jazzy-bitbots-tf-buffer = ">=1.0.0,<2"
ros-jazzy-ros2-python-extension = ">=1.0.0,<2"
ros-jazzy-audio-common = ">=0.3.15,<0.4"
ros-jazzy-dynamic-stack-decider = ">=0.5.3,<0.6"
ros-jazzy-dynamic-stack-decider-visualization = ">=0.2.1,<0.3"
ros-jazzy-game-controller-hl = ">=1.1.0,<2"
Expand Down Expand Up @@ -238,6 +242,7 @@ RMW_IMPLEMENTATION = "rmw_cyclonedds_cpp"
COLCON_LOG_LEVEL = "30"
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"
WEBOTS_HOME = "$CONDA_PREFIX/share/webots"
ALSA_PLUGIN_DIR = "/usr/lib/x86_64-linux-gnu/alsa-lib"

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

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from typing import Optional

from bitbots_utils.utils import get_parameters_from_other_node
from builtin_interfaces.msg import Time as TimeMsg
from game_controller_hsl_interfaces.msg import GameState
from rclpy.time import Time
from std_msgs.msg import Bool

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

Expand Down Expand Up @@ -127,3 +128,6 @@ def gamestate_callback(self, gamestate_msg: GameState) -> None:
"""
self.last_update = self._node.get_clock().now().nanoseconds / 1e9
self.gamestate = gamestate_msg

def whistle_detection_callback(self, msg: TimeMsg) -> None:
self.last_timestep_whistle_detected = Time.from_msg(msg)
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from bitbots_blackboard.body_blackboard import BodyBlackboard
from dynamic_stack_decider.abstract_decision_element import AbstractDecisionElement


class WhistleDetected(AbstractDecisionElement):
blackboard: BodyBlackboard

def __init__(self, blackboard, dsd, parameters):
super().__init__(blackboard, dsd, parameters)
self.previous_timestep_whistle_detected = self.blackboard.gamestate.last_timestep_whistle_detected

def perform(self, reevaluate=False):
"""
Returns "DETECTED" if a whistle was detected while the decision element was active, as part of the
DSD stack. If we have detected a whistle previously, but not during this decision element being on
the decision stack it counts as "NOT_DETECTED".
"""
if self.previous_timestep_whistle_detected == self.blackboard.gamestate.last_timestep_whistle_detected:
return "NOT_DETECTED"

return "DETECTED"

def get_reevaluate(self):
return True
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ $BallSeen
SECOND --> #SupporterRole
THIRD --> #DefensePositioning

#PlayingBehavior
$SecondaryStateDecider
PENALTYSHOOT --> #PenaltyShootoutBehavior
TIMEOUT --> #StandAndLook
ELSE --> $SecondaryStateTeamDecider
OUR --> #NormalBehavior
OTHER --> #Placing
NORMAL --> #NormalBehavior
OVERTIME --> #NormalBehavior

-->BodyBehavior
$IsPenalized
YES --> #DoNothing
Expand All @@ -143,23 +153,18 @@ $IsPenalized
NO --> $DoOnce
NOT_DONE --> @ChangeAction + action:waiting + r:false, @LookAtFieldFeatures + r:false, @Stand + duration:2
DONE --> #PositioningReady
SET --> $SecondaryStateDecider
PENALTYSHOOT --> $SecondaryStateTeamDecider
OUR --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @Stand
OTHER --> $BallSeen
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
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
ELSE --> #StandAndLook
SET --> $WhistleDetected
DETECTED --> #PlayingBehavior
NOT_DETECTED --> $SecondaryStateDecider
PENALTYSHOOT --> $SecondaryStateTeamDecider
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
OTHER --> $BallSeen
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
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
ELSE --> #StandAndLook
FINISHED --> $CurrentScore
AHEAD --> @Stand + duration:0.5 + r:false, @PlaySound + file:fanfare.wav, @PlayAnimationCheering + r:false, @GetWalkready + r:false, @LookForward, @Stand
ELSE --> #Init
PLAYING --> $SecondaryStateDecider
PENALTYSHOOT --> #PenaltyShootoutBehavior
TIMEOUT --> #StandAndLook
ELSE --> $SecondaryStateTeamDecider
OUR --> #NormalBehavior
OTHER --> #Placing
NORMAL --> #NormalBehavior
OVERTIME --> #NormalBehavior
PLAYING --> #PlayingBehavior
STANDBY --> #StandAndLook
STOPPED --> #DoNothing
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import rclpy
from bitbots_blackboard.body_blackboard import BodyBlackboard
from bitbots_tf_buffer import Buffer
from builtin_interfaces.msg import Time as TimeMsg
from dynamic_stack_decider.dsd import DSD
from game_controller_hsl_interfaces.msg import GameState
from geometry_msgs.msg import PoseWithCovarianceStamped, Twist
Expand Down Expand Up @@ -75,6 +76,13 @@ def __init__(self, node: Node):
qos_profile=1,
callback_group=MutuallyExclusiveCallbackGroup(),
)
node.create_subscription(
TimeMsg,
"whistle_detected",
blackboard.gamestate.whistle_detection_callback,
qos_profile=1,
callback_group=MutuallyExclusiveCallbackGroup(),
)

def loop(self):
try:
Expand Down
23 changes: 12 additions & 11 deletions src/bitbots_behavior/bitbots_body_behavior/package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,17 @@
<depend>soccer_vision_3d_msgs</depend>
<depend>tf_transformations</depend>
<depend>tf2</depend>
<test_depend>ament_mypy</test_depend>
<depend>std_msgs</depend>
<test_depend>ament_mypy</test_depend>

<test_depend>python3-pytest</test_depend>
<test_depend>python3-pytest</test_depend>

<export>
<rosdoc config="rosdoc.yaml"/>
<bitbots_documentation>
<status>starts</status>
<language>python3</language>
</bitbots_documentation>
<build_type>ament_python</build_type>
</export>
</package>
<export>
Comment thread
jaagut marked this conversation as resolved.
<rosdoc config="rosdoc.yaml"/>
<bitbots_documentation>
<status>starts</status>
<language>python3</language>
</bitbots_documentation>
<build_type>ament_python</build_type>
</export>
</package>
17 changes: 0 additions & 17 deletions src/bitbots_misc/bitbots_bringup/launch/README.md

This file was deleted.

35 changes: 10 additions & 25 deletions src/bitbots_misc/bitbots_bringup/launch/audio.launch
Original file line number Diff line number Diff line change
@@ -1,29 +1,14 @@
<?xml version="1.0"?>
<launch>
<arg name="sim" default="false" description="If true, we don't capture audio" />
<arg name="dst" default="appsink"/>
<arg name="device" default=""/>
<arg name="format" default="wave"/>
<arg name="bitrate" default="128"/>
<arg name="channels" default="1"/>
<arg name="depth" default="16"/>
<arg name="sample_rate" default="10000"/>
<arg name="sample_format" default="S16LE"/>
<arg name="ns" default="audio"/>
<arg name="audio_topic" default="audio" />
<!-- Our code currently is not sample_rate agnostic, but this must be overwritable to start the audio_capturer_node
on some audio drivers/devices if they do not support the default sample_rate of 16000. -->
<arg name="sample_rate" default="16000" description="The sample_rate with which the audio should be captured"/>

<group unless="$(var sim)">
<include file="$(find-pkg-share audio_capture)/launch/capture.launch.xml">
<arg name="dst" value="$(var dst)"/>
<arg name="device" value="$(var device)"/>
<arg name="format" value="$(var format)"/>
<arg name="bitrate" value="$(var bitrate)"/>
<arg name="channels" value="$(var channels)"/>
<arg name="depth" value="$(var depth)"/>
<arg name="sample_rate" value="$(var sample_rate)"/>
<arg name="sample_format" value="$(var sample_format)"/>
<arg name="ns" value="$(var ns)"/>
<arg name="audio_topic" value="$(var audio_topic)"/>
</include>
</group>
<node
pkg="audio_common"
exec="audio_capturer_node"
name="audio_capturer_node"
output="screen">
<param name="rate" value="$(var sample_rate)"/>
</node>
</launch>
6 changes: 4 additions & 2 deletions src/bitbots_misc/bitbots_bringup/launch/highlevel.launch
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
<arg name="vision" default="true" description="Whether the vision system should be started" />
<arg name="workspace_status" default="true" description="Whether to publish the current workspace status"/>
<arg name="world_model" default="true" description="Whether the world model should be started"/>
<arg name="whistle_detector" default="true" description="Whether whistle detector should be started"/>


<!-- launch game controller -->
Expand Down Expand Up @@ -55,7 +56,9 @@
<arg name="sim" value="$(var sim)"/>
</include>
</group>

<group if="$(var whistle_detector)">
<include file="$(find-pkg-share bitbots_whistle_detector)/launch/whistle_detector.launch"/>
</group>
<!-- launch localization or fake localization -->
<group if="$(var localization)">
<include file="$(find-pkg-share bitbots_localization)/launch/localization.launch">
Expand Down Expand Up @@ -87,7 +90,6 @@
<!-- launch audio processing -->
<group if="$(var audio)">
<include file="$(find-pkg-share bitbots_bringup)/launch/audio.launch">
<arg name="sim" value="$(var sim)" />
</include>
</group>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@

TOPICS_TO_RECORD: list[str] = [
"/animation",
"/audio/audio_info",
"/audio/audio",
"/audio",
"/ball_obstacle_active",
"/ball_position_relative_filtered",
"/balls_relative",
Expand Down Expand Up @@ -62,6 +61,7 @@
"/tf",
"/time_to_ball",
"/workspace_status",
"/whistle_detected",
]


Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0"?>
<launch>
<arg name="audio" default="true" description="Whether the audio system should be started" />
<arg name="behavior" default="true" description="Whether the behavior control system should be started" />
<arg name="behavior_dsd_file" default="main.dsd" description="The behavior dsd file that should be used" />
<arg name="game_controller" default="true" description="Whether the Gamecontroller module should be started" />
Expand All @@ -16,6 +17,7 @@

<!-- load teamplayer software stack -->
<include file="$(find-pkg-share bitbots_bringup)/launch/teamplayer.launch">
<arg name="audio" value="$(var audio)" />
<arg name="behavior" value="$(var behavior)" />
<arg name="behavior_dsd_file" value="$(var behavior_dsd_file)" />
<arg name="game_controller" value="$(var game_controller)"/>
Expand Down
2 changes: 2 additions & 0 deletions src/bitbots_misc/bitbots_bringup/launch/teamplayer.launch
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
<arg name="monitoring" default="true" description="Whether the system monitor and udp bridge should be started" />
<arg name="record" default="false" description="Whether the ros bag recording should be started" />
<arg name="tts" default="true" description="Whether to speak" />
<arg name="whistle_detector" default="true" description="Whether to detect whistles"/>
<arg unless="$(var sim)" name="fieldname" default="german_open_2026" description="Loads field settings (labor, webots, ...)." />
<arg if="$(var sim)" name="fieldname" default="webots" description="Loads field settings (labor, webots, ...)." />

Expand Down Expand Up @@ -54,6 +55,7 @@
<arg name="teamcom" value="$(var teamcom)" />
<arg name="vision" value="$(var vision)" />
<arg name="world_model" value="$(var world_model)" />
<arg name="whistle_detector" value="$(var whistle_detector)" />
</include>

<!-- load monitoring -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Setting up runtime type checking for this package
from beartype.claw import beartype_this_package

beartype_this_package()
Loading
Loading