Skip to content

Commit bc3f75c

Browse files
committed
rework movement sequences.
1 parent a141e4b commit bc3f75c

1 file changed

Lines changed: 91 additions & 29 deletions

File tree

src/percussion_task_manager/percussion_task_manager/task_manager_node.py

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ class TaskState(str, Enum):
1818
CAPTURING = 'CAPTURING'
1919
POSE_ACQUIRED = 'POSE_ACQUIRED'
2020
MOVING_TO_WEDGELOCK = 'MOVING_TO_WEDGELOCK'
21+
AT_MARKER = 'AT_MARKER'
2122
HAMMERING = 'HAMMERING'
2223
DONE = 'DONE'
2324
RETURNING = 'RETURNING'
@@ -45,9 +46,11 @@ def __init__(self) -> None:
4546
# Services/Topics
4647
self._start_srv = self.create_service(Trigger, '/start_task', self.start_task_callback)
4748
self._state_pub = self.create_publisher(String, '/task_manager/state', 10)
49+
self._state_sub = self.create_subscription(String, '/task_manager/state', self._on_state_changed, 10)
4850
self._capture_client: Client = self.create_client(TriggerCapture, capture_service_name)
4951
self._motion_client = ActionClient(self, ExecuteMotion, '/execute_motion')
5052

53+
self._selected_marker: Optional[Pose6D] = None
5154
self._current_state = TaskState.IDLE
5255
self._pending_capture_call = None
5356
self._returning = False
@@ -70,7 +73,7 @@ def _build_sequence(self, marker_pose: Pose6D) -> List[dict]:
7073
{
7174
'motion_type': 'MOVE_TO_MARKER', # 10 cm standoff in base X
7275
'marker_pose': marker_pose,
73-
'approach_offset': [-0.07, 0.0, 0.0, 0.0, 0.0, 0.0], # Base Frame
76+
'approach_offset': [-0.020, 0.0, 0.0, 0.0, 0.0, 0.0], # Base Frame
7477
},
7578
{
7679
'motion_type': 'MOVE_TO_CONTACT', # Touch Ledger facing marker
@@ -105,7 +108,7 @@ def _build_sequence(self, marker_pose: Pose6D) -> List[dict]:
105108
{
106109
'motion_type': 'RELATIVE_MOVE', # MOVE closer to pole
107110
'marker_pose': _make_pose6d(),
108-
'approach_offset': [0.025, 0.0, 0.10, 0.0, 0.0, 0.0], # TCP frame
111+
'approach_offset': [0.030, 0.0, 0.10, 0.0, 0.0, 0.0], # TCP frame
109112
},
110113
{
111114
'motion_type': 'MOVE_TO_CONTACT', # Touch bar sideways
@@ -115,7 +118,7 @@ def _build_sequence(self, marker_pose: Pose6D) -> List[dict]:
115118
{
116119
'motion_type': 'RELATIVE_MOVE', # Move into striking position
117120
'marker_pose': _make_pose6d(),
118-
'approach_offset': [0.0, 0.0, -0.00300, 0.0, 0.0, 0.0], # TCP frame
121+
'approach_offset': [0.0, 0.0, -0.00200, 0.0, 0.0, 0.0], # TCP frame
119122
},
120123
]
121124

@@ -131,21 +134,66 @@ def _build_return_sequence(self) -> List[dict]:
131134
'approach_offset': [0.0, 0.05, -0.10, 0.0, 0.0, 0.0], # TCP frame
132135
},
133136
{
134-
'motion_type': 'RELATIVE_MOVE', # Rotate Tool to unface wedgelock
135-
'marker_pose': _make_pose6d(),
136-
'approach_offset': [0.0, 0.0, 0.0, 0.0, 1.5701, 0.0], # TCP frame
137-
},
138-
{
139-
'motion_type': 'RETURN_HOME',
137+
'motion_type': 'RELATIVE_MOVE', # Retract from wedgelock
140138
'marker_pose': _make_pose6d(),
141-
'approach_offset': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
139+
'approach_offset': [0.0, 0.0, 0.0, 0.0, 1.57, 0.0], # TCP frame
142140
},
141+
#{
142+
# 'motion_type': 'RETURN_HOME',
143+
# 'marker_pose': _make_pose6d(),
144+
# 'approach_offset': [0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
145+
#},
143146
]
144147

145148
# ------------------------------------------------------------------
146149
# State
147150
# ------------------------------------------------------------------
148151

152+
def _on_state_changed(self, _msg: String) -> None:
153+
state = _msg.data
154+
155+
match state:
156+
case TaskState.TASK_REQUESTED:
157+
self.run_capture_service()
158+
159+
case TaskState.CAPTURING:
160+
161+
pass
162+
case TaskState.POSE_ACQUIRED:
163+
# marker_pose = self._selected_marker
164+
if self._selected_marker is None:
165+
self.get_logger().error('POSE_ACQUIRED but no marker available')
166+
self.publish_state(TaskState.ERROR)
167+
return
168+
169+
self._sequence = self._build_sequence(self._selected_marker)
170+
self.get_logger().info(f'sequence: {self._sequence}')
171+
self._returning = False
172+
self._execute_next_step()
173+
self.publish_state(TaskState.MOVING_TO_WEDGELOCK)
174+
case TaskState.AT_MARKER:
175+
# Check low level readiness
176+
# Request hammering action
177+
self.publish_state(TaskState.HAMMERING)
178+
pass
179+
case TaskState.HAMMERING:
180+
# wait for result from arduino
181+
self.get_logger().info(f'sequence: {self._sequence}')
182+
self.publish_state(TaskState.DONE)
183+
case TaskState.DONE:
184+
self._sequence = self._build_return_sequence()
185+
self._returning = True
186+
self.get_logger().info(f'sequence: {self._sequence}')
187+
self._execute_next_step()
188+
self.publish_state(TaskState.RETURNING)
189+
pass
190+
case _:
191+
pass
192+
193+
194+
195+
196+
149197
def publish_state(self, state: TaskState) -> None:
150198
self._current_state = state
151199
msg = String()
@@ -159,22 +207,25 @@ def publish_state(self, state: TaskState) -> None:
159207

160208
def start_task_callback(self, request: Trigger.Request, response: Trigger.Response) -> Trigger.Response:
161209
del request
210+
self.publish_state(TaskState.TASK_REQUESTED)
211+
response.success = True
212+
response.message = 'Task requested.'
213+
return response
214+
215+
# ------------------------------------------------------------------
216+
# Start capture service
217+
# ------------------------------------------------------------------
162218

163-
if self._current_state not in [TaskState.IDLE, TaskState.DONE, TaskState.ERROR]:
164-
response.success = False
165-
response.message = f'Task manager busy, current state: {self._current_state.value}'
166-
return response
167-
219+
def run_capture_service(self):
168220
if not self._capture_client.service_is_ready():
169221
self.get_logger().warn('Capture service not reported ready yet; sending request anyway.')
170222

171-
self.publish_state(TaskState.CAPTURING)
223+
self._selected_marker = None
172224
self._pending_capture_call = self._capture_client.call_async(TriggerCapture.Request())
173225
self._pending_capture_call.add_done_callback(self._on_capture_done)
226+
self.publish_state(TaskState.CAPTURING)
227+
174228

175-
response.success = True
176-
response.message = 'Task accepted; capture request sent.'
177-
return response
178229

179230
# ------------------------------------------------------------------
180231
# Capture callback
@@ -216,14 +267,18 @@ def _on_capture_done(self, future) -> None:
216267
)
217268

218269

270+
self._selected_marker = selected.pose
271+
272+
219273
self.publish_state(TaskState.POSE_ACQUIRED)
220274

275+
221276
# Rework to be more general motion.
222277

223278

224-
self._sequence = self._build_sequence(selected.pose)
225-
self._returning = False
226-
self._execute_next_step()
279+
#self._sequence = self._build_sequence(selected.pose)
280+
#self._returning = False
281+
#self._execute_next_step()
227282

228283
# ------------------------------------------------------------------
229284
# Sequence execution
@@ -233,12 +288,14 @@ def _execute_next_step(self) -> None:
233288
if not self._sequence:
234289
self.get_logger().info(f'if not self.sequence')
235290
if not self._returning:
291+
self.publish_state(TaskState.AT_MARKER)
236292
# Main sequence done — start return sequence
237-
self._returning = True
238-
self._sequence = self._build_return_sequence()
239-
self.publish_state(TaskState.HAMMERING)
240-
self.get_logger().info(f'Hammer sequence . . . ')
241-
self.publish_state(TaskState.DONE)
293+
# self._returning = True
294+
# self._sequence = self._build_return_sequence()
295+
# self.publish_state(TaskState.HAMMERING)
296+
# self.get_logger().info(f'Hammer sequence . . . ')
297+
# self.publish_state(TaskState.DONE)
298+
pass
242299
else:
243300
# Return sequence done — back to idle
244301
self.publish_state(TaskState.IDLE)
@@ -253,6 +310,11 @@ def _execute_next_step(self) -> None:
253310
self._send_motion_goal(step)
254311

255312
def _send_motion_goal(self, step: dict) -> None:
313+
if step['marker_pose'] is None:
314+
self.get_logger().error('Attempting to send goal with None marker_pose')
315+
self.publish_state(TaskState.ERROR)
316+
return
317+
256318
if not self._motion_client.server_is_ready():
257319
self.get_logger().error('Motion action server not available.')
258320
self.publish_state(TaskState.ERROR)
@@ -263,8 +325,8 @@ def _send_motion_goal(self, step: dict) -> None:
263325
goal.marker_pose = step['marker_pose']
264326
goal.approach_offset = step['approach_offset']
265327

266-
state = TaskState.RETURNING if self._returning else TaskState.MOVING_TO_WEDGELOCK
267-
self.publish_state(state)
328+
#state = TaskState.RETURNING if self._returning else TaskState.MOVING_TO_WEDGELOCK
329+
#self.publish_state(state)
268330
send_future = self._motion_client.send_goal_async(goal)
269331
send_future.add_done_callback(self._on_motion_goal_accepted)
270332

0 commit comments

Comments
 (0)