Skip to content

Commit

Permalink
fix(api): separate home and backoff steps into separate move groups (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
ahiuchingau authored Jul 13, 2023
1 parent 2376f87 commit eed0bef
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 158 deletions.
121 changes: 47 additions & 74 deletions api/src/opentrons/hardware_control/backends/ot3controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
create_move_group,
axis_to_node,
get_current_settings,
create_home_group,
create_home_groups,
node_to_axis,
sensor_node_for_mount,
sensor_node_for_pipette,
Expand Down Expand Up @@ -106,6 +106,7 @@
AionotifyEvent,
OT3Mount,
OT3AxisMap,
OT3AxisKind,
CurrentConfig,
MotorStatus,
InstrumentProbeType,
Expand Down Expand Up @@ -453,85 +454,69 @@ def _get_axis_home_distance(self, axis: OT3Axis) -> float:
else:
return -1 * self.axis_bounds[axis][1] - self.axis_bounds[axis][0]

def _build_axes_home_groups(
self, axes: Sequence[OT3Axis], speed_settings: Dict[OT3AxisKind, float]
) -> List[MoveGroup]:
present_axes = [ax for ax in axes if self.axis_is_present(ax)]
if not present_axes:
return []
else:
distances = {ax: self._get_axis_home_distance(ax) for ax in present_axes}
velocities = {
ax: -1 * speed_settings[OT3Axis.to_kind(ax)] for ax in present_axes
}
return create_home_groups(distances, velocities)

def _build_home_pipettes_runner(
self,
axes: Sequence[OT3Axis],
gantry_load: GantryLoad,
) -> Optional[MoveGroupRunner]:
pipette_axes = [ax for ax in axes if ax in OT3Axis.pipette_axes()]
if not pipette_axes:
return None

speed_settings = self._configuration.motion_settings.max_speed_discontinuity[
gantry_load
]

distances_pipette = {
ax: self._get_axis_home_distance(ax)
for ax in axes
if ax in OT3Axis.pipette_axes()
}
velocities_pipette = {
ax: -1 * speed_settings[OT3Axis.to_kind(ax)]
for ax in axes
if ax in OT3Axis.pipette_axes()
}

move_group_pipette = []
if distances_pipette and velocities_pipette:
pipette_move = self._filter_move_group(
create_home_group(distances_pipette, velocities_pipette)
)
move_group_pipette.append(pipette_move)

if move_group_pipette:
return MoveGroupRunner(move_groups=move_group_pipette, start_at_index=2)
return None
move_groups: List[MoveGroup] = self._build_axes_home_groups(
pipette_axes, speed_settings
)
return MoveGroupRunner(move_groups=move_groups)

def _build_home_gantry_z_runner(
self,
axes: Sequence[OT3Axis],
gantry_load: GantryLoad,
) -> Optional[MoveGroupRunner]:
gantry_axes = [ax for ax in axes if ax in OT3Axis.gantry_axes()]
if not gantry_axes:
return None

speed_settings = self._configuration.motion_settings.max_speed_discontinuity[
gantry_load
]

distances_gantry = {
ax: self._get_axis_home_distance(ax)
for ax in axes
if ax in OT3Axis.gantry_axes() and ax not in OT3Axis.mount_axes()
}
velocities_gantry = {
ax: -1 * speed_settings[OT3Axis.to_kind(ax)]
for ax in axes
if ax in OT3Axis.gantry_axes() and ax not in OT3Axis.mount_axes()
}
distances_z = {
ax: self._get_axis_home_distance(ax)
for ax in axes
if ax in OT3Axis.mount_axes()
}
velocities_z = {
ax: -1 * speed_settings[OT3Axis.to_kind(ax)]
for ax in axes
if ax in OT3Axis.mount_axes()
}
move_group_gantry_z = []
if distances_z and velocities_z:
z_move = self._filter_move_group(
create_home_group(distances_z, velocities_z)
)
move_group_gantry_z.append(z_move)
if distances_gantry and velocities_gantry:
# home X axis before Y axis, to avoid collision with thermo-cycler lid
# that could be in the back-left corner
for ax in [OT3Axis.X, OT3Axis.Y]:
if ax in axes:
gantry_move = self._filter_move_group(
create_home_group(
{ax: distances_gantry[ax]}, {ax: velocities_gantry[ax]}
)
)
move_group_gantry_z.append(gantry_move)
if move_group_gantry_z:
return MoveGroupRunner(move_groups=move_group_gantry_z)
# first home all the present mount axes
z_axes = list(filter(lambda ax: ax in OT3Axis.mount_axes(), gantry_axes))
z_groups = self._build_axes_home_groups(z_axes, speed_settings)

# home X axis before Y axis, to avoid collision with thermo-cycler lid
# that could be in the back-left corner
x_groups = (
self._build_axes_home_groups([OT3Axis.X], speed_settings)
if OT3Axis.X in gantry_axes
else []
)
y_groups = (
self._build_axes_home_groups([OT3Axis.Y], speed_settings)
if OT3Axis.Y in gantry_axes
else []
)

move_groups = [*z_groups, *x_groups, *y_groups]
if move_groups:
return MoveGroupRunner(move_groups=move_groups)
return None

@requires_update
Expand Down Expand Up @@ -575,18 +560,6 @@ async def home(
self._handle_motor_status_response(position)
return axis_convert(self._position, 0.0)

def _filter_move_group(self, move_group: MoveGroup) -> MoveGroup:
new_group: MoveGroup = []
for step in move_group:
new_group.append(
{
node: axis_step
for node, axis_step in step.items()
if node in self._motor_nodes()
}
)
return new_group

async def tip_action(
self,
axes: Sequence[OT3Axis],
Expand Down
17 changes: 7 additions & 10 deletions api/src/opentrons/hardware_control/backends/ot3utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -348,21 +348,18 @@ def create_move_group(
return move_group, {k: float(v) for k, v in pos.items()}


def create_home_group(
def create_home_groups(
distance: Dict[OT3Axis, float], velocity: Dict[OT3Axis, float]
) -> MoveGroup:
) -> List[MoveGroup]:
node_id_distances = _convert_to_node_id_dict(distance)
node_id_velocities = _convert_to_node_id_dict(velocity)
home = create_home_step(
distance=node_id_distances,
velocity=node_id_velocities,
)
home_group = [
create_home_step(distance=node_id_distances, velocity=node_id_velocities)
]
# halve the homing speed for backoff
backoff_velocities = {k: v / 2 for k, v in node_id_velocities.items()}
backoff = create_backoff_step(backoff_velocities)

move_group: MoveGroup = [home, backoff]
return move_group
backoff_group = [create_backoff_step(backoff_velocities)]
return [home_group, backoff_group]


def create_tip_action_group(
Expand Down
Loading

0 comments on commit eed0bef

Please sign in to comment.