-
Notifications
You must be signed in to change notification settings - Fork 24
Better defence, goalie and supporter positions #925
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
e74145f
5c21291
6cd3000
1ced7f6
61bf6e7
4fa2aed
eca2b97
775da12
842adfd
43c6e31
49ed7aa
6d616d6
251a18d
9002998
49d519a
eaaf36d
bfbf3c7
3fc4e2c
28dbf2e
ae03c94
d058eeb
b884405
656f27f
e2c3c4a
ab88f08
2ef42fe
b9bfea2
104cea8
b6b222d
ee12f90
c09ac88
1b03218
5190a13
09a1641
d86cc96
e10883c
fa5e0ce
9ddf72d
bedf8e9
5551f44
94408f2
85c0aaa
93cd9c4
7c664c7
5cf3bab
eeed157
a3f9344
8b63646
9a3099b
bcfdbb2
426c857
a093312
33a0ff2
0e885e3
5904a09
1b38e33
a99dc2c
6d3d637
6acf08a
d35ad73
888ea17
1ece6ee
3e11e17
ad9f591
6e49a6c
6818fa5
aaed253
463144b
53874db
bd8cb9c
4867dce
bdae2ba
7d52bbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import math | ||
| from typing import Literal, Optional | ||
|
|
||
| import numpy as np | ||
|
|
@@ -183,6 +184,26 @@ def get_active_teammate_poses(self, count_goalies: bool = False) -> list[Pose]: | |
| poses.append(data.robot_position.pose) | ||
| return poses | ||
|
|
||
| def quaternion_to_yaw(self, q) -> float: | ||
| """Extract yaw (theta) from a quaternion.""" | ||
| return math.atan2(2.0 * (q.w * q.z + q.x * q.y), 1.0 - 2.0 * (q.y * q.y + q.z * q.z)) | ||
|
|
||
| def get_robot_poses(self) -> dict[int, list[float]]: | ||
| """Returns a mapping of jersey_number -> [x, y, theta] for all active robots.""" | ||
| robot_poses = {} | ||
| data: TeamData | ||
| for data in self.team_data.values(): | ||
| if self.is_valid(data): | ||
| pose = data.robot_position.pose | ||
| robot_poses[data.robot_id] = [ | ||
| pose.position.x, | ||
| pose.position.y, | ||
| self.quaternion_to_yaw(pose.orientation), | ||
| ] | ||
| # include own data | ||
| robot_poses[self._blackboard.gamestate.get_own_id()] = list(self._blackboard.world_model.get_current_position()) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a flag for that |
||
| return robot_poses | ||
|
|
||
| def get_number_of_active_field_players(self, count_goalie: bool = False) -> int: | ||
| def is_not_goalie(team_data: TeamData) -> bool: | ||
| return team_data.strategy.role != Strategy.ROLE_GOALIE | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,26 @@ | |
| from dynamic_stack_decider.abstract_action_element import AbstractActionElement | ||
| from tf2_geometry_msgs import PoseStamped | ||
|
|
||
| class GoToGoaliePosition(AbstractActionElement): | ||
| blackboard: BodyBlackboard | ||
|
|
||
| def __init__(self, blackboard, dsd, parameters): | ||
| super().__init__(blackboard, dsd, parameters) | ||
|
|
||
| def perform(self, reevaluate=False): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now it treads go to goalie, defense, etc all the same. That might be confusing, because somebody calls go to defense position to go explicitly there and he ends up at the goalie position.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer an explicit go to placement position. We can keep the old supporter position for the forced two robot ball touch, but that works outside of this placement. The PR is still pending, but it essentially removes the robot from the assignment after the ball was touched and goes to an explicit position to wait. While the others play with essentially one robot less. This can be done in the new concept, but we need the explicit support position for this. Other than that all other go to defense, block etc can be removed. Go to role needs to stay.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We also need to think about what to do if we don't see a ball. The position assignment should still work based on the lastest ball. I think the striker should perform our normal ball discovery behavior (turn around, go to opponent goal, go to middle line on the side). The rest of the robots should go to their role positions to not interfere with the striker during this procedure.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the whole part with coding the positioning goals in the old GoTo decisions was only for testing :) I use GoToFormationPosition now in the most cases, we still need to discuss how to handle the supporter during no double touch, I would prefer a direct integration in the formation capsule |
||
|
|
||
| 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() | ||
| own_position = optimal_positioning[self.blackboard.gamestate.get_own_id()] | ||
| pose = own_position["goal_pose"] | ||
| pose_msg.pose.position.x = pose[0] | ||
| pose_msg.pose.position.y = pose[1] | ||
| pose_msg.pose.orientation.w = pose[2] | ||
|
|
||
| self.blackboard.pathfinding.publish(pose_msg) | ||
|
|
||
| class GoToBlockPosition(AbstractActionElement): | ||
| blackboard: BodyBlackboard | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,34 +33,42 @@ def perform(self, reevaluate=False): | |
| self.publish_debug_data("time to ball", my_time_to_ball) | ||
| self.publish_debug_data("Rank to ball", rank) | ||
| if rank == 1: | ||
| return "YES" | ||
| return "NO" # only for testing remeber to REMOVE! | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove :P |
||
| return "NO" | ||
|
|
||
| def get_reevaluate(self): | ||
| return True | ||
|
|
||
|
|
||
| class RankToBallNoGoalie(AbstractDecisionElement): | ||
| class RankToBallWithGoalie(AbstractDecisionElement): | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't call it rank to ball. Maybe something like assigned role. |
||
| blackboard: BodyBlackboard | ||
|
|
||
| def __init__(self, blackboard, dsd, parameters): | ||
| super().__init__(blackboard, dsd, parameters) | ||
|
|
||
| def perform(self, reevaluate=False): | ||
| my_time_to_ball = self.blackboard.team_data.get_own_time_to_ball() | ||
| rank = self.blackboard.team_data.team_rank_to_ball(my_time_to_ball, count_goalies=False, use_time_to_ball=True) | ||
| self.publish_debug_data("time to ball", my_time_to_ball) | ||
| self.publish_debug_data("Rank to ball", rank) | ||
| if rank == 1: | ||
| return "FIRST" | ||
| elif rank == 2: | ||
| return "SECOND" | ||
| elif rank == 3: | ||
| return "THIRD" | ||
| optimal_positioning = self.blackboard.positioning.get_formation_assignment() | ||
| own_position = optimal_positioning[self.blackboard.gamestate.get_own_id()] | ||
| role = own_position["role"] | ||
| self.publish_debug_data("Role from positioning", role) | ||
| if role == "striker": | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again we might want to use an enum here
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would use 1 = striker, 2 = goalie, 3, 5...x = defender 4 = supporter wich is the logical order for adding the roles depending on the number of robots. must be synchronised with capsule functions
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can use a string enum. |
||
| return "STRIKER" | ||
| elif role == "goalie": | ||
| return "GOALIE" | ||
| elif role == "defender_0": | ||
| return "DEFENDER_ZERO" | ||
| elif role == "defender_1": | ||
| return "DEFENDER1" | ||
| elif role == "defender_2": | ||
| return "DEFENDER2" | ||
| elif role == "defender_3": | ||
| return "DEFENDER3" | ||
| elif role == "supporter": | ||
| return "SUPPORTER" | ||
| else: | ||
| # emergency fall back if something goes wrong | ||
| self.blackboard.node.get_logger().warning("Rank to ball had some issues") | ||
| return "FIRST" | ||
| self.blackboard.node.get_logger().warning("Rank to ball had some issues. Role" + role) | ||
| return "STRIKER" | ||
|
|
||
| def get_reevaluate(self): | ||
| return True | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -62,11 +62,6 @@ $GoalieHandlingBall | |
| YES --> @ChangeAction + action:positioning, @AvoidBallActive, @LookAtFieldFeatures, @GoToDefensePosition //quick fix for playing with two robots during GO | ||
| NO --> #KickWithAvoidance | ||
|
|
||
| #DefensePositioning | ||
| $GoalieActive | ||
| YES --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @GoToDefensePosition | ||
| NO --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @GoToBlockPosition | ||
|
|
||
| #SupporterRole | ||
| $PassStarted | ||
| YES --> $BallSeen | ||
|
|
@@ -94,10 +89,12 @@ $DoOnce | |
| NO --> $SecondaryStateTeamDecider | ||
| OUR --> #SearchBall | ||
| ELSE --> @AvoidBallActive, @LookAtFieldFeatures, @WalkInPlace + duration:2, @GoToRelativePosition + x:1 + y:0 + t:0, @Stand | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can do the search ball behavior in both cases here as our robots are way faster now and we had the issue in the past that we didn't leave the keep out area in time |
||
| YES --> $RankToBallNoGoalie | ||
| 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 | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think this selection is necessary anymore. Everyone should just go to their placement position and stand there if it was reached.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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 |
||
| STRIKER --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition + mode:freekick_first | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't go to defense position. Go to placement position or whatever we want to call it.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also we have an issue here. We need an explicit placement for situations where the other team has e.g. a free kick. In this situation the striker role should be deactivated, the striker should be reassigned to a defensive role and we should enforce a keep out area around the ball. This should be pretty easily implemtable in the placement function if we add a flag for this.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would use the positioning capsule with specialised formation functions for each set play situation, we should also integrate the "no double touch allowed" situation directly to the formation logic |
||
| DEFENDER0 --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition + mode:freekick_second | ||
| SUPPORTER --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition | ||
| GOALIE --> @GoToGoaliePosition | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this different? |
||
| ELSE --> @ChangeAction + action:positioning, @LookAtFieldFeatures, @AvoidBallActive, @GoToDefensePosition + mode:freekick_second | ||
|
|
||
| #Init | ||
| @Stand + duration:0.1 + r:false, @ChangeAction + action:waiting, @LookForward, @Stand | ||
|
|
@@ -110,16 +107,12 @@ $BallSeen | |
| YES --> $KickOffTimeUp | ||
| NO_NORMAL --> #StandAndLook | ||
| NO_FREEKICK --> #Placing | ||
| YES --> $ConfigRole | ||
| GOALIE --> #GoalieBehavior | ||
| ELSE --> $CountActiveRobotsWithoutGoalie | ||
| ONE --> $RankToBallNoGoalie | ||
| FIRST --> #StrikerRole | ||
| SECOND --> #DefensePositioning | ||
| ELSE --> $RankToBallNoGoalie | ||
| FIRST --> #StrikerRole | ||
| SECOND --> #SupporterRole | ||
| THIRD --> #DefensePositioning | ||
| YES --> $RankToBallWithGoalie | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 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. |
||
| STRIKER --> #StrikerRole | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The striker role needs to be reworked to position itself using the new striker placement. |
||
| GOALIE --> @GoToGoaliePosition | ||
| DEFENDER_ZERO --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @GoToDefensePosition | ||
| SUPPORTER --> #SupporterRole | ||
| ELSE --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @GoToDefensePosition //defender 1 bis 4 integrieren? | ||
|
|
||
| #PlayingBehavior | ||
| $SecondaryStateDecider | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Specify the quaternion notation xyzw vs wxyz and maybe move/check but it's utils for these functions.