From 6ceca54a7ba0fcf8bc2c155fccb507e761712893 Mon Sep 17 00:00:00 2001 From: Clemens Wulff Date: Sat, 4 Jul 2026 22:35:34 +0900 Subject: [PATCH 1/4] decide for kicking depending on distance of seen robots --- .../capsules/costmap_capsule.py | 22 +++++++++++++++++++ .../behavior_dsd/decisions/dribble_or_kick.py | 9 +++++++- .../behavior_dsd/main.dsd | 2 +- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py index 35b0389950..416f0027de 100644 --- a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py +++ b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py @@ -41,6 +41,8 @@ def __init__(self, node, blackboard): self.map_margin: float = self.body_config["map_margin"] self.obstacle_costmap_smoothing_sigma: float = self.body_config["obstacle_costmap_smoothing_sigma"] self.obstacle_cost: float = self.body_config["obstacle_cost"] + self.closest_robot_infront_dist: float = 10000 + self.closest_robot_behind_dist: float = 10000 # Publisher for visualization in RViZ self.costmap_publisher = self._node.create_publisher(OccupancyGrid, "debug/costmap", 1) @@ -61,6 +63,8 @@ def robot_callback(self, msg: RobotArray) -> None: """ # Init a new obstacle costmap obstacle_map = np.zeros_like(self.costmap) + self.closest_robot_infront_dist = 10000 + self.closest_robot_behind_dist = 10000 # Iterate over all robots robot: Robot for robot in msg.robots: @@ -69,6 +73,16 @@ def robot_callback(self, msg: RobotArray) -> None: # TODO inflate # Draw obstacle with smoothing independent weight on obstacle costmap obstacle_map[idx_x, idx_y] = self.obstacle_cost * self.obstacle_costmap_smoothing_sigma + + dist_to_robot = np.linalg.norm(np.array[self._blackboard.world_model.get_current_position()[0], self._blackboard.world_model.get_current_position()[1]]) - np.array([robot.bb.center.position.x,robot.bb.center.position.y]) + if robot.bb.center.position.x > self._blackboard.world_model.get_current_position()[0]: + if dist_to_robot < self.closest_robot_infront_dist: + self.closest_robot_infront_dist = dist_to_robot + else: + if dist_to_robot < self.closest_robot_behind_dist: + self.closest_robot_behind_dist = dist_to_robot + + # Smooth obstacle map obstacle_map = gaussian_filter(obstacle_map, self.obstacle_costmap_smoothing_sigma) # Get pass offsets @@ -432,3 +446,11 @@ def get_best_kick_direction( ) ] return kick_direction + + def is_other_robot_close(self, threshold_front: float, threshold_behind: float) -> bool: + if threshold_front > self.closest_robot_infront_dist: + return True + elif threshold_behind > self.closest_robot_behind_dist: + return True + else: + return False diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/dribble_or_kick.py b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/dribble_or_kick.py index 45db9efe08..93013031d2 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/dribble_or_kick.py +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/dribble_or_kick.py @@ -17,6 +17,8 @@ def __init__(self, blackboard, dsd, parameters): self.num_kick_angles = self.blackboard.config["num_kick_angles"] self.dribble_kick_angle = self.blackboard.config["dribble_kick_angle"] + self.threshold_front = parameters.get("threshold_front", 10) + self.threshold_behind = parameters.get("threshold_behind", 10) def perform(self, reevaluate=False): """ @@ -50,7 +52,12 @@ def perform(self, reevaluate=False): ball_near = ball_distance < self.ball_distance_threshold self.publish_debug_data(f"Ball distance (needs <{self.ball_distance_threshold})", ball_distance) - if oriented_to_goal and front_free and goal_far and ball_near: + # no other robots to close + other_robots_close = self.blackboard.costmap.is_other_robot_close(self.threshold_front, self.threshold_behind) + # actual set play situation + set_play_state = self.blackboard.gamestate.get_set_play() + + if other_robots_close and set_play_state == 0: return "DRIBBLE" else: return "KICK" diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd index 7851fbf805..066ad49a6e 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd @@ -31,7 +31,7 @@ $DoOnce NO --> @LookAtFieldFeatures, @GoToRolePosition #KickWithAvoidance -$KickOrDribble + map_goal_distance:%ball_approach_dist // should be same as below $GoToBall + target:map action +$KickOrDribble + map_goal_distance:%ball_approach_dist + threshold_front:1.5 + threshold_behind:1 // 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_deg + latch:true From 2945ded7035df7f1cf347c141722e30fb96dd67b Mon Sep 17 00:00:00 2001 From: Clemens Wulff Date: Sun, 5 Jul 2026 01:59:41 +0900 Subject: [PATCH 2/4] small fixes --- .../bitbots_blackboard/capsules/costmap_capsule.py | 8 ++++---- .../bitbots_body_behavior/behavior_dsd/main.dsd | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py index 416f0027de..c869142abf 100644 --- a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py +++ b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py @@ -41,8 +41,8 @@ def __init__(self, node, blackboard): self.map_margin: float = self.body_config["map_margin"] self.obstacle_costmap_smoothing_sigma: float = self.body_config["obstacle_costmap_smoothing_sigma"] self.obstacle_cost: float = self.body_config["obstacle_cost"] - self.closest_robot_infront_dist: float = 10000 - self.closest_robot_behind_dist: float = 10000 + self.closest_robot_infront_dist: float = 10000.0 + self.closest_robot_behind_dist: float = 10000.0 # Publisher for visualization in RViZ self.costmap_publisher = self._node.create_publisher(OccupancyGrid, "debug/costmap", 1) @@ -63,8 +63,8 @@ def robot_callback(self, msg: RobotArray) -> None: """ # Init a new obstacle costmap obstacle_map = np.zeros_like(self.costmap) - self.closest_robot_infront_dist = 10000 - self.closest_robot_behind_dist = 10000 + self.closest_robot_infront_dist = 10000.0 + self.closest_robot_behind_dist = 10000.0 # Iterate over all robots robot: Robot for robot in msg.robots: diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd index 066ad49a6e..2f4097c377 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd @@ -31,7 +31,7 @@ $DoOnce NO --> @LookAtFieldFeatures, @GoToRolePosition #KickWithAvoidance -$KickOrDribble + map_goal_distance:%ball_approach_dist + threshold_front:1.5 + threshold_behind:1 // should be same as below $GoToBall + target:map action +$DribbleOrKick + map_goal_distance:%ball_approach_dist + threshold_front:2 + threshold_behind:0.5 // change back to KickorDribble to fix 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_deg + latch:true From 65338afa3aa8e79b5946d7e96be4dd3e74641d80 Mon Sep 17 00:00:00 2001 From: Clemens Wulff Date: Sun, 5 Jul 2026 02:13:27 +0900 Subject: [PATCH 3/4] change DribbleOrKick in KickOrDribble --- .../behavior_dsd/decisions/kick_or_dribble.py | 9 ++++++++- .../bitbots_body_behavior/behavior_dsd/main.dsd | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/kick_or_dribble.py b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/kick_or_dribble.py index d25c2ae1dc..1c3fa01073 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/kick_or_dribble.py +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/kick_or_dribble.py @@ -11,13 +11,20 @@ def __init__(self, blackboard, dsd, parameters): super().__init__(blackboard, dsd, parameters) self.target_distance = parameters.get("map_goal_target_distance", 0.5) self.side_offset = parameters.get("side_offset", 0.0) + self.threshold_front = parameters.get("threshold_front", 10) + self.threshold_behind = parameters.get("threshold_behind", 10) def perform(self, reevaluate=False): """ Determines whether to kick or dribble based on the angle of the map goal """ map_goal = self.blackboard.pathfinding.get_map_goal(self.target_distance, self.side_offset) - if abs(map_goal[2]) > math.pi / 2: # point away from opponent goal, so we should dribble + # no other robots to close + other_robots_close = self.blackboard.costmap.is_other_robot_close(self.threshold_front, self.threshold_behind) + # actual set play situation + set_play_state = self.blackboard.gamestate.get_set_play() + + if abs(map_goal[2]) > math.pi / 2 or (other_robots_close and set_play_state == 0): # point away from opponent goal, so we should dribble return "DRIBBLE" else: return "KICK" diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd index 2f4097c377..54cff55e71 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd @@ -31,7 +31,7 @@ $DoOnce NO --> @LookAtFieldFeatures, @GoToRolePosition #KickWithAvoidance -$DribbleOrKick + map_goal_distance:%ball_approach_dist + threshold_front:2 + threshold_behind:0.5 // change back to KickorDribble to fix +$KickorDribble + map_goal_distance:%ball_approach_dist + threshold_front:2 + threshold_behind:0.5 // change back to KickorDribble to fix 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_deg + latch:true From 4784479c8a215cd56b5e6d75f357623358061eb5 Mon Sep 17 00:00:00 2001 From: Cornelius Krupp Date: Sun, 5 Jul 2026 06:18:09 +0800 Subject: [PATCH 4/4] Fix typos --- .../bitbots_blackboard/capsules/costmap_capsule.py | 2 +- .../bitbots_body_behavior/behavior_dsd/main.dsd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py index c869142abf..86ed25b83f 100644 --- a/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py +++ b/src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/costmap_capsule.py @@ -74,7 +74,7 @@ def robot_callback(self, msg: RobotArray) -> None: # Draw obstacle with smoothing independent weight on obstacle costmap obstacle_map[idx_x, idx_y] = self.obstacle_cost * self.obstacle_costmap_smoothing_sigma - dist_to_robot = np.linalg.norm(np.array[self._blackboard.world_model.get_current_position()[0], self._blackboard.world_model.get_current_position()[1]]) - np.array([robot.bb.center.position.x,robot.bb.center.position.y]) + dist_to_robot = np.linalg.norm(np.array([self._blackboard.world_model.get_current_position()[0], self._blackboard.world_model.get_current_position()[1]]) - np.array([robot.bb.center.position.x,robot.bb.center.position.y])) if robot.bb.center.position.x > self._blackboard.world_model.get_current_position()[0]: if dist_to_robot < self.closest_robot_infront_dist: self.closest_robot_infront_dist = dist_to_robot diff --git a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd index 54cff55e71..010a193c2f 100644 --- a/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd +++ b/src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd @@ -31,7 +31,7 @@ $DoOnce NO --> @LookAtFieldFeatures, @GoToRolePosition #KickWithAvoidance -$KickorDribble + map_goal_distance:%ball_approach_dist + threshold_front:2 + threshold_behind:0.5 // change back to KickorDribble to fix +$KickOrDribble + map_goal_distance:%ball_approach_dist + threshold_front:2.0 + threshold_behind:0.5 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_deg + latch:true