def test_cp_blending(): from_pt = Point(10, 10, 10) to_pt = Point(0, 0, 10) arc = plan_arc(from_pt, to_pt, 50, None, CriticalPoint.XY_CENTER) check_arc_basic([a[0] for a in arc], from_pt, to_pt) assert arc[0][1] is None assert arc[1][1] is CriticalPoint.XY_CENTER assert arc[2][1] is CriticalPoint.XY_CENTER arc2 = plan_arc(from_pt, to_pt, 50, CriticalPoint.TIP, None) check_arc_basic([a[0] for a in arc], from_pt, to_pt) assert arc2[0][1] == CriticalPoint.TIP assert arc2[1][1] is None assert arc2[2][1] is None
def test_arc_with_waypoint(): from_pt = Point(20, 20, 40) to_pt = Point(0, 0, 10) arc = plan_arc(from_pt, to_pt, 50, extra_waypoints=[(5, 10), (20, 30)]) check_arc_basic([a[0] for a in arc], from_pt, to_pt) assert arc[1][0].x == 5 assert arc[1][0].y == 10 assert arc[1][0].z == 50 assert arc[2][0].x == 20 assert arc[2][0].y == 30 assert arc[2][0].z == 50
async def move(user_flow: CalibrationUserFlow, to_loc: Location): from_pt = await user_flow._get_current_point(None) from_loc = Location(from_pt, None) cp = user_flow._get_critical_point_override() max_height = user_flow._hardware.get_instrument_max_height( user_flow._mount) safe = planning.safe_height(from_loc, to_loc, user_flow._deck, max_height) moves = plan_arc(from_pt, to_loc.point, safe, origin_cp=None, dest_cp=cp) for move in moves: await user_flow._hardware.move_to(mount=user_flow._mount, abs_position=move[0], critical_point=move[1])
async def _move(self, to_loc: Location): from_pt = await self._get_current_point() from_loc = Location(from_pt, None) cp = self._get_critical_point() max_height = self._hardware.get_instrument_max_height(self._mount) safe = geometry.safe_height( from_loc, to_loc, self._deck, max_height) moves = plan_arc(from_pt, to_loc.point, safe, origin_cp=None, dest_cp=cp) for move in moves: await self._hardware.move_to(mount=self._mount, abs_position=move[0], critical_point=move[1])
async def _move(self, mount: Mount, to_loc: Location, cp_override: CriticalPoint = None): from_pt = await self.hardware.gantry_position(mount) from_loc = Location(from_pt, None) cp = cp_override or self._pip_info_by_mount[mount].critical_point max_height = self.hardware.get_instrument_max_height(mount) safe = geometry.safe_height( from_loc, to_loc, self._deck, max_height) moves = plan_arc(from_pt, to_loc.point, safe, origin_cp=None, dest_cp=cp) for move in moves: await self.hardware.move_to( mount, move[0], critical_point=move[1])
def plan_moves( from_loc: types.Location, to_loc: types.Location, deck: 'Deck', instr_max_height: float, well_z_margin: float = None, lw_z_margin: float = None, force_direct: bool = False, minimum_lw_z_margin: float = None, minimum_z_height: float = None,)\ -> List[Tuple[types.Point, Optional[CriticalPoint]]]: """ Plan moves between one :py:class:`.Location` and another. Each :py:class:`.Location` instance might or might not have a specific kind of geometry attached. This function is intended to return series of moves that contain the minimum safe retractions to avoid (known) labware on the specified :py:class:`Deck`. :param from_loc: The last location. :param to_loc: The location to move to. :param deck: The :py:class:`Deck` instance describing the robot. :param force_direct: If True, ignore any Z margins force a direct move The other parameters are as :py:meth:`safe_height`. :returns: A list of tuples of :py:class:`.Point` and critical point overrides to move through. """ constraints = MoveConstraints.build( instr_max_height=instr_max_height, well_z_margin=well_z_margin, lw_z_margin=lw_z_margin, minimum_lw_z_margin=minimum_lw_z_margin, minimum_z_height=minimum_z_height) assert constraints.minimum_z_height >= 0.0 to_point = to_loc.point to_lw, to_well = split_loc_labware(to_loc) from_point = from_loc.point from_lw, from_well = split_loc_labware(from_loc) dest_quirks = quirks_from_any_parent(to_lw) from_quirks = quirks_from_any_parent(from_lw) from_center = 'centerMultichannelOnWells' in from_quirks to_center = 'centerMultichannelOnWells' in dest_quirks dest_cp_override = CriticalPoint.XY_CENTER if to_center else None origin_cp_override = CriticalPoint.XY_CENTER if from_center else None is_same_location = ((to_lw and to_lw == from_lw) and (to_well and to_well == from_well)) if (force_direct or (is_same_location and not (minimum_z_height or 0) > 0)): # If we’re going direct, we can assume we’re already in the correct # cp so we can use the override without prep return [(to_point, dest_cp_override)] # Generate arc moves # Find the safe z heights based on the destination and origin labware/well safe = _build_safe_height(from_loc, to_loc, deck, constraints) must_dodge = should_dodge_thermocycler(deck, from_loc, to_loc) if must_dodge: sc = deck.get_slot_center('5') wp = [(sc.x, sc.y)] else: wp = [] return plan_arc(from_point, to_point, safe, origin_cp_override, dest_cp_override, wp)
def test_basic_arcs(from_pt, to_pt, z_height): check_arc_basic([a[0] for a in plan_arc(from_pt, to_pt, z_height)], from_pt, to_pt)