Skip to content

Commit dc7035b

Browse files
authored
Fix / Clean up look at handling (#723)
2 parents 1a85bf9 + 6fc2110 commit dc7035b

File tree

9 files changed

+110
-161
lines changed

9 files changed

+110
-161
lines changed

bitbots_behavior/bitbots_blackboard/bitbots_blackboard/capsules/misc_capsule.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from bitbots_msgs.msg import Audio, HeadMode, RobotControlState
99

1010
THeadMode: TypeAlias = Literal[ # type: ignore[valid-type]
11-
HeadMode.SEARCH_BALL,
11+
HeadMode.TRACK_BALL,
1212
HeadMode.SEARCH_FIELD_FEATURES,
1313
HeadMode.LOOK_FORWARD,
1414
HeadMode.DONT_MOVE,

bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/actions/head_modes.py

Lines changed: 47 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import rclpy
21
from bitbots_blackboard.body_blackboard import BodyBlackboard
32
from dynamic_stack_decider.abstract_action_element import AbstractActionElement
3+
from rclpy.task import Future
44

5-
from bitbots_msgs.action import LookAt
5+
from bitbots_msgs.action import LookAt as LookAtROSAction
66
from bitbots_msgs.msg import HeadMode
77

88

@@ -12,40 +12,60 @@ class AbstractHeadModeElement(AbstractActionElement):
1212
blackboard: BodyBlackboard
1313

1414

15-
class LookAtBall(AbstractHeadModeElement):
16-
"""Search for Ball and track it if found"""
15+
class LookAt(AbstractHeadModeElement):
16+
"""Looks at a given point in a given frame. Pass x, y, z and frame as parameters."""
1717

1818
def __init__(self, blackboard, dsd, parameters):
1919
super().__init__(blackboard, dsd, parameters)
20+
self.blocking = parameters.get("blocking", True)
21+
self.finished = not self.blocking
2022

21-
def perform(self):
22-
ball_position = self.blackboard.world_model.get_best_ball_point_stamped()
23-
server_running = self.blackboard.animation.lookat_action_client.wait_for_server(timeout_sec=1.0)
23+
# Check if action server is running
24+
server_running = self.blackboard.animation.lookat_action_client.wait_for_server(timeout_sec=0.1)
2425
if not server_running:
25-
while not server_running and rclpy.ok():
26-
self.blackboard.node.get_logger().warn(
27-
"Lookat Action Server not running! Lookat cannot work without lookat server!"
28-
"Will now wait until server is accessible!",
29-
throttle_duration_sec=10.0,
30-
)
31-
server_running = self.blackboard.animation.lookat_action_client.wait_for_server(timeout_sec=1)
32-
if server_running:
33-
self.blackboard.node.get_logger().warn("Lookat server now running, 'look_at_ball' action will go on.")
34-
else:
35-
self.blackboard.node.get_logger().warn("Lookat server did not start. Did not send action.")
36-
return self.pop()
37-
38-
goal = LookAt.Goal()
39-
goal.look_at_position = ball_position
40-
self.blackboard.animation.lookat_action_client.send_goal_async(goal)
41-
return self.pop()
26+
self.blackboard.node.get_logger().error("LookAt action server not running! Failed to look at ball.")
27+
self.finished = True
28+
return
29+
30+
# Validate parameter
31+
assert "frame" in parameters, "LookAt action missing frame parameter"
32+
33+
# Create look at goal
34+
goal = LookAtROSAction.Goal()
35+
goal.look_at_position.point.x = parameters.get("x", 0.0)
36+
goal.look_at_position.point.y = parameters.get("y", 0.0)
37+
goal.look_at_position.point.z = parameters.get("z", 0.0)
38+
goal.look_at_position.header.frame_id = parameters["frame"]
39+
40+
# Handle action server responses
41+
def goal_response_callback(future: Future):
42+
goal_handle = future.result()
43+
if not goal_handle.accepted:
44+
self.blackboard.node.get_logger().warn("Can not perform look at, goal rejected")
45+
self.finished = True
46+
return
47+
48+
def done_callback(future: Future):
49+
result = future.result().result
50+
if not result.success:
51+
self.blackboard.node.get_logger().warn("Looking at failed")
52+
self.finished = True
53+
54+
goal_handle.get_result_async().add_done_callback(done_callback)
55+
56+
# Call the action server
57+
self.blackboard.animation.lookat_action_client.send_goal_async(goal).add_done_callback(goal_response_callback)
58+
59+
def perform(self):
60+
if self.finished:
61+
return self.pop()
4262

4363

44-
class SearchBall(AbstractHeadModeElement):
45-
"""Look for ball"""
64+
class TrackBall(AbstractHeadModeElement):
65+
"""Tracks the last known ball position"""
4666

4767
def perform(self):
48-
self.blackboard.misc.set_head_duty(HeadMode.SEARCH_BALL)
68+
self.blackboard.misc.set_head_duty(HeadMode.TRACK_BALL)
4969
return self.pop()
5070

5171

bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/demo.dsd

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ $AvoidBall
1414
NEAR --> $FootSelection
1515
LEFT --> #PerformKickLeft
1616
RIGHT --> #PerformKickRight
17-
FAR --> @ChangeAction + action:going_to_ball, @LookAtFront, @GoToBall + target:close
18-
NO --> @ChangeAction + action:going_to_ball + r:false, @LookAtFieldFeatures + r:false, @AvoidBallActive + r:false, @GoToBall + target:close + blocking:false + distance:%ball_far_approach_dist
17+
FAR --> @ChangeAction + action:going_to_ball, @TrackBall, @GoToBall + target:close
18+
NO --> @ChangeAction + action:going_to_ball + r:false, @TrackBall, @AvoidBallActive + r:false, @GoToBall + target:close + blocking:false + distance:%ball_far_approach_dist
1919
YES --> $ReachedPathPlanningGoalPosition + threshold:%ball_far_approach_position_thresh
2020
YES --> @AvoidBallInactive
21-
NO --> @ChangeAction + action:going_to_ball, @LookAtFieldFeatures, @GoToBall + target:close + distance:%ball_far_approach_dist
21+
NO --> @ChangeAction + action:going_to_ball, @TrackBall, @GoToBall + target:close + distance:%ball_far_approach_dist
2222

2323
-->BodyBehavior
2424
$DoOnce

bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/main.dsd

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ $DoOnce
2727
@ChangeAction + action:kicking, @LookAtFront, @WalkKick + foot:right + r:false, @WalkInPlace + duration:1 + r:false, @ForgetBall + r:false, @WalkInPlace + duration:1 + r:false, @LookAtFieldFeatures + r:false
2828

2929
#Dribble
30-
@ChangeAction + action:going_to_ball, @CancelPathplanning, @LookAtBall, @LookAtFront, @DribbleForward
30+
@ChangeAction + action:going_to_ball, @CancelPathplanning, @LookAtFront, @DribbleForward
3131

3232
#RolePositionWithPause
3333
$DoOnce
@@ -78,8 +78,8 @@ $GoalieActive
7878
#SupporterRole
7979
$PassStarted
8080
YES --> $BallSeen
81-
YES --> @LookAtBall, @ChangeAction + action:positioning, @AvoidBallActive, @GoToPassAcceptPosition
82-
NO --> @SearchBall, @ChangeAction + action:positioning, @AvoidBallActive, @GoToPassAcceptPosition
81+
YES --> @TrackBall, @ChangeAction + action:positioning, @AvoidBallActive, @GoToPassAcceptPosition
82+
NO --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @AvoidBallActive, @GoToPassAcceptPosition
8383
NO --> @LookAtFieldFeatures, @ChangeAction + action:positioning, @AvoidBallActive, @GoToPassPreparePosition
8484

8585
#GoalieRole
@@ -97,8 +97,8 @@ $SecondaryStateTeamDecider
9797
RIGHT --> @PlayAnimationGoalieFallRight, @Stand
9898
CENTER --> @PlayAnimationGoalieFallCenter, @Stand
9999
ELSE --> $BallSeen
100-
YES --> @LookAtBall, @Stand
101-
NO --> @SearchBall, @Stand
100+
YES --> @TrackBall, @Stand
101+
NO --> @LookAtFieldFeatures, @Stand
102102

103103

104104
#Placing
@@ -179,8 +179,8 @@ $IsPenalized
179179
PENALTYSHOOT --> $SecondaryStateTeamDecider
180180
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
181181
OTHER --> $BallSeen
182-
YES --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @LookAtBall + r:false, @PlayAnimationGoalieArms + r:false, @Stand // goalie only needs to care about the ball
183-
NO --> @Stand + duration:0.1 + r:false, @DeactivateHCM + r:false, @LookForward + r:false, @PlayAnimationInitInSim + r:false, @GetWalkready + r:false, @SearchBall + r:false, @PlayAnimationGoalieArms + r:false, @Stand
182+
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
183+
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
184184
ELSE --> #StandAndLook
185185
FINISHED --> $CurrentScore
186186
AHEAD --> @Stand + duration:0.5 + r:false, @PlaySound + file:fanfare.wav, @PlayAnimationCheering + r:false, @GetWalkready + r:false, @LookForward, @Stand

bitbots_behavior/bitbots_body_behavior/bitbots_body_behavior/behavior_dsd/minimal.dsd

Lines changed: 0 additions & 46 deletions
This file was deleted.

bitbots_misc/bitbots_teleop/scripts/teleop_keyboard.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
R: reset ball in simulation
5252
5353
Head Modes:
54-
0: Search for Ball and track it if found
54+
0: Track the last known ball position
5555
1: Look generally for all features on the field (ball, goals, corners, center point)
5656
2: Simply look directly forward
5757
3: Don't move the head
@@ -147,7 +147,7 @@ def __init__(self):
147147
self.head_msg.joint_names = ["HeadPan", "HeadTilt"]
148148
self.head_msg.positions = [0.0] * 2
149149

150-
self.head_mode_msg = HeadMode()
150+
self.head_mode_msg = HeadMode(head_mode=HeadMode.DONT_MOVE)
151151

152152
self.head_pan_step = 0.05
153153
self.head_tilt_step = 0.05
@@ -221,9 +221,9 @@ def loop(self):
221221
self.head_msg.positions[1] = 0
222222
self.head_pub.publish(self.head_msg)
223223
elif key == "0":
224-
# Search for Ball and track it if found
225-
self.head_mode_msg.head_mode = HeadMode.SEARCH_BALL
226-
assert int(key) == HeadMode.SEARCH_BALL
224+
# Track the last known ball position
225+
self.head_mode_msg.head_mode = HeadMode.TRACK_BALL
226+
assert int(key) == HeadMode.TRACK_BALL
227227
elif key == "1":
228228
# Look generally for all features on the field (ball, goals, corners, center point)
229229
self.head_mode_msg.head_mode = HeadMode.SEARCH_FIELD_FEATURES

bitbots_motion/bitbots_head_mover/config/head_config.yml

Lines changed: 0 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -45,49 +45,6 @@ move_head:
4545

4646
# Search pattern for ball
4747
search_patterns:
48-
search_ball:
49-
# search pattern speed
50-
tilt_speed:
51-
type: double
52-
description: "Tilt speed for the search pattern"
53-
default_value: 3.0
54-
55-
pan_speed:
56-
type: double
57-
description: "Pan speed for the search pattern"
58-
default_value: 3.0
59-
60-
# Max values for the search pattern
61-
pan_max:
62-
type: double_array
63-
default_value: [90.0, -90.0]
64-
description: "Maximum pan values for the search pattern (in degrees)"
65-
validation:
66-
fixed_size<>: 2
67-
68-
tilt_max:
69-
type: double_array
70-
default_value: [-10.0, -60.0]
71-
description: "Maximum tilt values for the search pattern (in degrees)"
72-
validation:
73-
fixed_size<>: 2
74-
75-
# Number of scan lines for the search pattern
76-
scan_lines:
77-
type: int
78-
default_value: 2
79-
description: "Number of scan lines for the search pattern"
80-
validation:
81-
gt_eq<>: [1]
82-
83-
# Reduces last scanline by that factor so that robot does not collide
84-
reduce_last_scanline:
85-
type: double
86-
default_value: 0.2
87-
description: "Reduces last scanline by that factor so that robot does not collide"
88-
validation:
89-
bounds<>: [0.0, 1.0]
90-
9148
search_ball_penalty:
9249
tilt_speed:
9350
type: double

0 commit comments

Comments
 (0)