@@ -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