Skip to content
Open
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
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 3 additions & 2 deletions .rsyncignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ __pycache__
# Don't sync the simulation environments
src/bitbots_simulation/bitbots_mujoco_sim/

# Don't sync the build bitbots_rust_nav target directory
src/bitbots_navigation/bitbots_rust_nav/target
# Don't sync the rust build target directory
target/
src/bitbots_navigation/bitbots_rust_nav/target/
4 changes: 4 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@
"install/bitbots_msgs/lib/python3.12/site-packages",
"build/bitbots_ball_filter",
"install/bitbots_ball_filter/lib/python3.12/site-packages",
"build/better_launch",
"install/better_launch/lib/python3.12/site-packages",
".pixi/envs/default/lib/python/site-packages",
".pixi/envs/default/lib/python3.12/site-packages",
],
Expand Down Expand Up @@ -302,6 +304,8 @@
"install/bitbots_msgs/lib/python3.12/site-packages",
"build/bitbots_ball_filter",
"install/bitbots_ball_filter/lib/python3.12/site-packages",
"build/better_launch",
"install/better_launch/lib/python3.12/site-packages",
".pixi/envs/default/lib/python/site-packages",
".pixi/envs/default/lib/python3.12/site-packages",
],
Expand Down
257 changes: 169 additions & 88 deletions pixi.lock

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,12 @@ alsa-plugins = ">=1.2.12,<2"
beartype = ">=0.22.6,<0.23"
breathe = ">=4.36.0,<5"
cbor2 = ">=5.9.0,<6"
click = ">=8.4.2,<9" # Required by better_launch (src/lib/better_launch)
cmake = "<3.30" # Constraint to avoid issues with deprecated features in newer cmake versions
colorama = ">=0.4.6,<0.5"
compilers = ">=1.11.0,<2"
construct = ">=2.10.70,<3"
docstring_parser = ">=0.18.0,<0.19" # Required by better_launch (src/lib/better_launch)
eigen = ">=3.4.0,<4"
fabric = ">=3.2.2,<4"
flask = ">=3.1.2,<4"
Expand All @@ -74,10 +76,12 @@ ninja = ">=1.13.2,<2"
numpy = ">=1.26.4,<2"
nvidia-ml-py = ">=13.595.45,<14"
opencv = ">=4.11.0,<5"
osrf_pycommon = ">=0.2.1,<0.3" # Required by better_launch (src/lib/better_launch)
paramiko = ">=4.0.0,<5"
pkg-config = ">=0.29.2,<0.30"
playsound = ">=1.3.0,<2"
portaudio = ">=19.7.0,<20"
prompt_toolkit = ">=3.0.52,<4" # Required by better_launch (src/lib/better_launch)
protobuf = ">=6.31.1,<7"
psutil = ">=7.1.3,<8"
pthread-stubs = ">=0.4,<0.5"
Expand All @@ -92,6 +96,7 @@ rospkg = ">=1.6.0,<2"
rsync = ">=3.4.3,<4"
ruff = ">=0.14.6,<0.15"
scipy = ">=1.17.1,<2"
setproctitle = ">=1.3.7,<2" # Required by better_launch (src/lib/better_launch)
simpleeval = ">=1.0.3,<2"
sphinx-rtd-theme = ">=3.0.2,<4"
sysroot_linux-64 = ">=2.28,<3"
Expand Down
2 changes: 1 addition & 1 deletion scripts/deploy/tasks/launch.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def _check_tmux_session_already_running(self, connections: Group) -> GroupResult
def _launch_teamplayer(self, connections: Group) -> GroupResult:
print_debug("Launching teamplayer")
# Create tmux session
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"
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 bl bitbots_bringup teamplayer.launch.py --record true --tts false' Enter"

print_debug(f"Calling '{cmd}'")
try:
Expand Down
6 changes: 4 additions & 2 deletions scripts/ros.plugin.sh
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,9 @@ setup_alises() {

# ros aliases
alias ros2='cdc && pixi run ros2'
alias bl='cdc && pixi run bl'
alias rr='ros2 run'
alias rl='ros2 launch'
alias rl='bl'

alias rte='ros2 topic echo'
alias rtl='ros2 topic list'
Expand Down Expand Up @@ -81,8 +82,9 @@ setup_alises() {

# ros aliases
unalias ros2
unalias bl
alias rr='ros2 run'
alias rl='ros2 launch'
alias rl='bl'

alias rte='ros2 topic echo'
alias rtl='ros2 topic list'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import os
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, cast

import matplotlib.image as mpimg
import matplotlib.pyplot as plt
Expand All @@ -42,6 +43,9 @@
from ros2_numpy import numpify
from tf_transformations import euler_from_quaternion

if TYPE_CHECKING:
from bitbots_blackboard.body_blackboard import BodyBlackboard

# --------------------------------------------------------------------------- #
# Field / behavior parameters (mirrors config, so no ROS param server needed). #
# --------------------------------------------------------------------------- #
Expand Down Expand Up @@ -171,7 +175,7 @@ def __init__(self, robot: Pose, ball: Pose):
def make_capsule(robot: Pose, ball: Pose) -> PathfindingCapsule:
"""Build the real capsule without running __init__ (which needs a ROS node)."""
capsule = PathfindingCapsule.__new__(PathfindingCapsule)
capsule._blackboard = FakeBlackboard(robot, ball)
capsule._blackboard = cast("BodyBlackboard", FakeBlackboard(robot, ball))
return capsule


Expand Down Expand Up @@ -211,7 +215,7 @@ def __init__(self):
self.ax.set_ylabel("y (down)")

# Radio buttons to pick the target type.
rax = self.fig.add_axes([0.01, 0.5, 0.15, 0.18])
rax = self.fig.add_axes((0.01, 0.5, 0.15, 0.18))
self._targets = list(BallGoalType)
self.radio = RadioButtons(rax, [t.value for t in self._targets], active=self._targets.index(self.target))
self.radio.on_clicked(self._on_target)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,20 @@ def perform(self, reevaluate=False):

if not self.blackboard.kick.is_currently_kicking:
self.pop()


class RLKickAngleRobot(AbstractKickAction):
def __init__(self, blackboard, dsd, parameters):
super().__init__(blackboard, dsd, parameters)
self._strength = parameters.get("strength", 2.0)
self._angle_deg_in_map = parameters.get("angle_deg_in_map", 0.0)
self._start_time = None

def perform(self, reevaluate=False):
# transform map to robot relative
if self._start_time is None:
self._start_time = self.blackboard.node.get_clock().now()
self.blackboard.kick.start_rl_kick(self._angle_deg_in_map, self._strength)

if not self.blackboard.kick.is_currently_kicking:
self.pop()
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,11 @@ $DoOnce
$KickOrDribble + map_goal_distance:%ball_approach_dist // should be same as below $GoToBall + target:map action
KICK --> $DoOnce
NOT_DONE --> @ChangeAction + action:going_to_ball, @LookAtFieldFeatures, @GoToBall + target:rl_kick + blocking:false
DONE --> $ReachedAndAlignedToPathPlanningGoalPosition + threshold:%rl_kick_approach_tolerance_pos + orientation_threshold:%rl_kick_approach_tolerance_rad + latch:true
DONE --> $ReachedAndAlignedToPathPlanningGoalPosition + threshold:%rl_kick_approach_tolerance_pos + orientation_threshold:%rl_kick_approach_tolerance_deg + latch:true
NO --> @ChangeAction + action:going_to_ball, @LookAtFieldFeatures, @GoToBall + target:rl_kick
YES --> $DoOnce
NOT_DONE --> @StoreBallMovementDetectionStartPosition
DONE --> @ChangeAction + action:kicking, @Stand + duration:0.1 + r:false, @LookAtBallPenalty + r:false, @RLKickTowardsGoal + strength:3.5 + r:false, @ForgetBall
DONE --> @ChangeAction + action:kicking, @Stand + duration:0.1 + r:false, @LookAtBallPenalty + r:false, @RLKickTowardsGoal + strength:3.0 + r:false, @ForgetBall
DRIBBLE --> $AvoidBall // old behavior before kick when we want to kick the ball in
NO --> $BallClose + distance:%ball_reapproach_dist + angle:%ball_reapproach_angle
YES --> $BallKickArea
Expand Down Expand Up @@ -88,7 +88,7 @@ $GoalieActive

#PenaltyShootoutBehavior
$SecondaryStateTeamDecider
OUR --> @StandAndWaitRandom + min:10 + max:25, @ChangeAction + action:kicking, @LookAtFieldFeatures, @WalkInPlace + duration:2, @RLKick + duration:3 + r:false, @WalkInPlace + duration:1 + r:false, @Stand
OUR --> @StandAndWaitRandom + min:10 + max:25, @ChangeAction + action:kicking, @LookAtFieldFeatures, @WalkInPlace + duration:2, @RLKickAngleRobot + angle_deg_in_map:30.0 + strength:3.0 + r:false, @WalkInPlace + duration:1 + r:false, @Stand
ELSE --> $BallDangerous + radius:1.3
LEFT --> @PlayAnimationGoalieFallLeft, @Stand
RIGHT --> @PlayAnimationGoalieFallRight, @Stand
Expand Down Expand Up @@ -180,7 +180,7 @@ $IsPenalized
ELSE --> #PlayingBehavior
NOT_DETECTED --> $SecondaryStateDecider
PENALTYSHOOT --> $SecondaryStateTeamDecider
OUR --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @Stand // we need to also see the goalie
OUR --> @Stand + duration:5.0 + r:false, @LookForward + r:false, @RLKickAngleRobot + angle_deg_in_map:30.0 + strength:3.0 + r:false, @Stand
OTHER --> $BallSeen
YES --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + 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, @LookAtFieldFeatures + r:false, @PlayAnimationGoalieArms + r:false, @Stand
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,18 +153,16 @@ body_behavior:

kick_decision_smoothing: 10.0


rl_kick_approach_tolerance_pos: 0.25
rl_kick_approach_tolerance_rad: 0.4
rl_kick_approach_tolerance_pos: 0.12
rl_kick_approach_tolerance_deg: 20.0

rl_kick:
timeout: 2.0 # how long the kick policy is active
approach_dist: 0.5 # distance from the ball to the approach point on the arc
approach_arc_half_degree: 100.0 # half opening angle (in degrees) of the arc around the point opposite the kick direction
goal_line_offset: 0.25 # distance beyond the goal line used for the left/right kick target points
kick_target_y_offset: 0.5 # inset (in y) from the goal posts used for the left/right kick target points
timeout: 2.0 # how long the kick policy is active
approach_dist: 0.6 # distance from the ball to the approach point on the arc
approach_arc_half_degree: 60.0 # half opening angle (in degrees) of the arc around the point opposite the kick direction
goal_line_offset: 0.25 # distance beyond the goal line used for the left/right kick target points
goal_kick_dir_inset: 0.5
max_approach_angle_deg: 60
max_approach_angle_deg: 90

##################
# costmap params #
Expand Down
17 changes: 0 additions & 17 deletions src/bitbots_behavior/bitbots_body_behavior/launch/behavior.launch

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env python3
from better_launch import BetterLaunch, launch_this


@launch_this
def behavior(dsd_file: str = "main.dsd", tf_prefix: str = "", sim: bool = False):
bl = BetterLaunch()

bl.node(
"bitbots_body_behavior",
"body_behavior",
"body_behavior",
params={
"dsd_file": dsd_file,
"actionlib_server_sub_queue_size": -1,
"odom_frame": f"{tf_prefix}odom",
"map_frame": f"{tf_prefix}map",
"base_footprint_frame": f"{tf_prefix}base_footprint",
},
param_files=[
bl.find("bitbots_body_behavior", "body_behavior.yaml", "config"),
bl.find("bitbots_body_behavior", "animations.yaml", "config"),
],
use_sim_time=sim,
max_respawns=-1,
)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#!/usr/bin/env python3
from better_launch import BetterLaunch, launch_this


@launch_this
def behavior_standalone(sim: bool = False, dsd_file: str = "main.dsd"):
"""
Parameters
----------
dsd_file : str
The behavior dsd file that should be used
"""
bl = BetterLaunch()

fieldname = "small_division_2026" if sim else "labor"

bl.include(
"bitbots_parameter_blackboard",
"parameter_blackboard.launch.py",
sim=sim,
fieldname=fieldname,
)

bl.include(
"bitbots_body_behavior",
"behavior.launch.py",
dsd_file=dsd_file,
sim=sim,
)
2 changes: 1 addition & 1 deletion src/bitbots_behavior/bitbots_body_behavior/setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
("share/" + package_name, ["package.xml"]),
("share/ament_index/resource_index/packages", ["resource/" + package_name]),
("share/" + package_name + "/config", glob.glob("config/*")),
("share/" + package_name + "/launch", glob.glob("launch/*.launch")),
("share/" + package_name + "/launch", glob.glob("launch/*.launch.py")),
],
scripts=[],
install_requires=[
Expand Down
14 changes: 0 additions & 14 deletions src/bitbots_misc/bitbots_bringup/launch/audio.launch

This file was deleted.

21 changes: 21 additions & 0 deletions src/bitbots_misc/bitbots_bringup/launch/audio.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env python3
from better_launch import BetterLaunch, launch_this


@launch_this
def audio(sample_rate: int = 48000):
"""
Parameters
----------
sample_rate : int
The sample_rate with which the audio should be captured. 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.
"""
bl = BetterLaunch()
bl.node(
"audio_common",
"audio_capturer_node",
"audio_capturer_node",
params={"rate": sample_rate},
)
16 changes: 0 additions & 16 deletions src/bitbots_misc/bitbots_bringup/launch/demo.launch

This file was deleted.

28 changes: 28 additions & 0 deletions src/bitbots_misc/bitbots_bringup/launch/demo.launch.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
from better_launch import BetterLaunch, launch_this


@launch_this
def demo(sim: bool = False, behavior_dsd_file: str = "demo.dsd"):
"""
Parameters
----------
sim : bool
Whether the robot is running in simulation or on real hardware
behavior_dsd_file : str
The behavior dsd file that should be used
"""
bl = BetterLaunch()

# load teamplayer software stack without some unnecessary stuff, that is not needed in the demo
bl.include(
"bitbots_bringup",
"teamplayer.launch.py",
behavior_dsd_file=behavior_dsd_file,
fieldname="demo",
game_controller=False,
localization=False,
sim=sim,
teamcom=False,
path_planning=True,
)
Loading
Loading