Better defence, goalie and supporter positions#925
Conversation
|
How did you get this image? |
|
I vibe coded a simple GUI to interactively test the function that generates the placement. This is the script I added in this pr. It is not ready yet. |
…ngle robot that plays as striker)
| width=parameters["field.size.y"], | ||
| goal_width=parameters["field.goal.width"], | ||
| ) | ||
| self._params = Params() |
There was a problem hiding this comment.
Ideally we want to load theses parameters from the behavior config file (or a separate one, as the current one is pretty large as it is).
|
|
||
| @cached_capsule_function | ||
| def get_formation_assignment(self) -> dict: | ||
| ballPose = self._blackboard.world_model.get_best_ball_point_stamped() |
There was a problem hiding this comment.
Maybe we should have separate functions for the team ball and "own ball" detection. Because we definitely want to use the team ball here.
| poses.append(data.robot_position.pose) | ||
| return poses | ||
|
|
||
| def quaternion_to_yaw(self, q) -> float: |
There was a problem hiding this comment.
Specify the quaternion notation xyzw vs wxyz and maybe move/check but it's utils for these functions.
| FIRST --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition + mode:freekick_first | ||
| SECOND --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition + mode:freekick_second | ||
| THIRD --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition | ||
| YES --> $RankToBallWithGoalie |
There was a problem hiding this comment.
I don't think this selection is necessary anymore. Everyone should just go to their placement position and stand there if it was reached.
There was a problem hiding this comment.
i will take a closer look there once we have discussed how to handle set play situations with the new positioning capsule, got a view ideas there
| @@ -110,16 +107,12 @@ $BallSeen | |||
There was a problem hiding this comment.
Only the striker should search the ball. The others should go to the role position.
| FIRST --> #StrikerRole | ||
| SECOND --> #SupporterRole | ||
| THIRD --> #DefensePositioning | ||
| YES --> $RankToBallWithGoalie |
There was a problem hiding this comment.
I think the only really useful destinction here is striker, supporter, defender, goalie (maybe). We can probably do the same placement strategy for the goalie and and defenders and we are not limited in the number of defenders that way.
There was a problem hiding this comment.
The striker needs special handling because it wants to kick if it reached its goal position. The supporter wants to track the ball if the striker is kicking and needs special handling for that and the others just go to their positions to stand in the way.
| SECOND --> #SupporterRole | ||
| THIRD --> #DefensePositioning | ||
| YES --> $RankToBallWithGoalie | ||
| STRIKER --> #StrikerRole |
There was a problem hiding this comment.
The striker role needs to be reworked to position itself using the new striker placement.
|
Also adapt the capsule/ gui so we can do headless tests of the placement function without the software stack. Currently the function is duplicated. Also probably some denouncing/hysteresis is needed. I would add it to the capsule as this needs to be global state. Just store if we have changed our role in the last x seconds and if did we want to stick with it. This prevents flickering behavior. The x can be randomly selected from a configurable range (0-1 sec for example). |
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
…logic Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
…ts_main into feature/better_assignment
Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
…better_assignment Signed-off-by: Florian Vahl <florian@flova.de>
Signed-off-by: Florian Vahl <florian@flova.de>
|
@copilot, behebe bitte die Mergekonflikte in diesem Pull Request. |
73dae1f to
53874db
Compare
There was a problem hiding this comment.
Pull request overview
This PR introduces a new formation-based positioning approach for field players (goalie/defenders/supporter/striker) and rewires parts of the body behavior to use those assignments, with accompanying tooling/UI changes for simulation/debugging.
Changes:
- Add a new formation computation + assignment capsule (
PositioningCapsule) and a standalone matplotlib debug GUI for tuning/visualizing it. - Update body behavior DSD flow to use formation positions/roles (and remove several older position actions/branches).
- Remove the “init” animation path and adjust some supporting tools/config (RViz marker executor, team-data sim UI, Pixi lock updates).
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/lib/soccer_vision_3d_rviz_markers/soccer_vision_3d_rviz_markers/visualizer.py | Switches to EventsExecutor for spinning the marker node. |
| src/bitbots_team_communication/bitbots_team_data_sim_rqt/bitbots_team_data_sim_rqt/team_data_ui.py | Extends the RQT UI with sliders for robot/ball pose inputs and covariance. |
| src/bitbots_robot/piplus_animations/animations/misc/init.json | Removes the init animation definition. |
| src/bitbots_motion/bitbots_hcm/bitbots_hcm/hcm_dsd/actions/play_animation.py | Removes the PlayAnimationInit action class in HCM. |
| src/bitbots_behavior/bitbots_body_behavior/config/body_behavior.yaml | Adjusts role positions and adds formation/supporter + threshold parameters; tweaks ready wait time. |
| src/bitbots_behavior/bitbots_body_behavior/config/animations.yaml | Removes the Misc.init animation mapping. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd | Reworks behavior tree to use formation positioning and new role decision; removes older goalie/supporter/placing flows. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/config_role.py | Spelling tweak in docstring (“behavior”). |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/decisions/closest_to_ball.py | Replaces rank-to-ball decision with role-from-positioning decision (AssignedRole). |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/play_animation.py | Removes init animation actions from body behavior. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_pass_position.py | Removes pass-position action implementation. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_formation.py | Adds an action to publish the formation-assigned target pose (with optional “stand when on target” hysteresis). |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_defense_position.py | Removes legacy defense positioning action. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_corner_kick_position.py | Removes legacy corner-kick positioning action. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_block_position.py | Removes legacy block-position action. |
| src/bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/go_to_ball.py | Changes how ball-approach goals are computed/published (currently problematic). |
| src/bitbots_behavior/bitbots_blackboard/scripts/debug_positioning.py | Adds a matplotlib GUI to visualize/tune formation computation and assignments. |
| src/bitbots_behavior/bitbots_blackboard/CMakeLists.txt | Installs scripts directory into the package’s lib install path. |
| src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/team_data_capsule.py | Adds helpers for passive-player IDs and robot pose extraction (x,y,theta). |
| src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/positioning_capsule.py | Adds new formation computation + assignment capsule and supporting geometry/params/types. |
| src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/game_status_capsule.py | Adds get_own_id() accessor. |
| src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/animation_capsule.py | Removes init animation parameter usage. |
| src/bitbots_behavior/bitbots_blackboard/bitbots_blackboard/body_blackboard.py | Wires the new PositioningCapsule into the blackboard. |
| pixi.lock | Dependency lockfile updates (e.g., libtiff, absl-py, click). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| try: | ||
| rclpy.spin(node) | ||
| executor.spin() | ||
| except KeyboardInterrupt: | ||
| pass |
| # Create spin box | ||
| self.ball_covariance_box = QSpinBox() | ||
| self.ball_covariance_box.setRange(-400, 400) | ||
| self.main_layout.addWidget(self.ball_covariance_box) | ||
| # Create slider | ||
| self.ball_covariance_slider = QSlider(Qt.Horizontal) # type: ignore[attr-defined] | ||
| self.ball_covariance_slider.setRange(-400, 400) | ||
| self.main_layout.addWidget(self.ball_covariance_slider) |
| pose_with_cov = PoseWithCovariance() | ||
| pose_with_cov.pose.position.x = robot_widget.position_sliders_x.get_x_position() | ||
| pose_with_cov.pose.position.y = robot_widget.position_sliders_y.get_y_position() |
| team_data.robot_position = pose_with_cov | ||
| team_data.state = robot_widget.state_box.get_state() |
| if self.is_valid(data) and (data.strategy.action is Strategy.ACTION_PASSIVE): | ||
| passive_robot_ids.append(data.robot_id) | ||
| if self.strategy.action is Strategy.ACTION_PASSIVE: | ||
| passive_robot_ids.append(self._blackboard.gamestate.get_own_id()) |
| ball = np.array([ball_pose.point.x, ball_pose.point.y]) | ||
| robot_poses = self._blackboard.team_data.get_robot_poses() | ||
| passive_robot_ids = self._blackboard.team_data.get_id_of_passive_player() | ||
| self._node.get_logger().info(f"Length of robot_poses: {len(robot_poses)}") |
| def perform(self, reevaluate=False): | ||
| pose_msg = self.blackboard.pathfinding.get_ball_goal(self.target, self.distance, self.side_offset) | ||
| pose_msg = PoseStamped() | ||
| pose_msg.header.stamp = self.blackboard.node.get_clock().now().to_msg() | ||
| pose_msg.header.frame_id = self.blackboard.map_frame | ||
| optimal_positioning = self.blackboard.positioning.get_formation_assignment() |
TBD, small proof of concept:
Checklist
pixi run build