fix(experement): leave the dock even when the axial retreat is rejected

The tool is already docked before the retreat, so a rejected axial move can fall through to a graded +Y exit at a lower height instead of aborting the route.
This commit is contained in:
Даниил Грабарь
2026-11-09 03:40:43 +10:00
parent 41144ecd2a
commit e4d2e48158
@@ -451,29 +451,44 @@ class ReferenceOperations:
rack_pose, rack_pose,
) )
self._require_synchronized() self._require_synchronized()
try:
self._retreat(goal, f'dock_tool({tool_name})') self._retreat(goal, f'dock_tool({tool_name})')
except OperationError as error:
# The axial retreat can be rejected from the socket branch.
# The tool is already docked, so stepping out is still safe.
if 'Планирование' not in str(error):
raise
self.motion.reset_stop()
# Step out of the rack along +Y before any joint-space move; the # Step out of the rack along +Y before any joint-space move; the
# axial retreat alone can leave the wrist against its limit. # axial retreat alone can leave the wrist against its limit. Use a
transfer = self._above(goal, self.geometry.transfer_gap) # lower height if the full retreat was rejected.
for gap in (
self.geometry.transfer_gap, 0.05, 0.02,
):
base = self._above(goal, gap)
reached = False
for offset in (0.10, 0.06, 0.03): for offset in (0.10, 0.06, 0.03):
exit_pose = Transform.from_xyz_rpy( exit_pose = Transform.from_xyz_rpy(
[0.0, offset, 0.0], [0.0, 0.0, 0.0], [0.0, offset, 0.0], [0.0, 0.0, 0.0],
parent='world', child='rack_exit_offset', parent='world', child='rack_exit_offset',
).compose_relaxed(transfer) ).compose_relaxed(base)
label = ( label = (
f'dock_tool({tool_name}):exit' if offset == 0.10 f'dock_tool({tool_name}):exit' if offset == 0.10
else f'dock_tool({tool_name}):exit:{offset:.2f}' else f'dock_tool({tool_name}):exit:{offset:.2f}'
) )
try: try:
self._move( self._move(
exit_pose, 'lin', self.geometry.speeds['transfer'], exit_pose, 'lin',
label, self.geometry.speeds['transfer'], label,
) )
reached = True
break break
except OperationError as error: except OperationError as error:
if 'Планирование' not in str(error): if 'Планирование' not in str(error):
raise raise
self.motion.reset_stop() self.motion.reset_stop()
if reached:
break
self._emit('dock_tool', object=tool_name, phase='done') self._emit('dock_tool', object=tool_name, phase='done')
return OperationResult(True, 'dock_tool', f'{tool_name} docked', tuple(self.events)) return OperationResult(True, 'dock_tool', f'{tool_name} docked', tuple(self.events))
except Exception as error: except Exception as error: