"""
Implementation of RoboInterface extending the PFonRail to the specific uppsala working cell.
"""
from .pf_on_rail import PFonRail
import time
import logging
#some custom naming of the positions
ECHO_SOURCE = 0
ECHO_DESTINATION = 1
# robot drives there to have barcode scanned
bc_reader_position = "bc_reader"
lid_pick_offset = 7
lid_place_offset = 10
lid_off = 14
lid_alone_offset = - 3
[docs]
def approach_position(device: str) -> str:
approach_pos = f"{device}_approach"
logging.debug(f"Approach position to device {device} is {approach_pos}.")
return approach_pos
[docs]
def device_from_identifier(identifier: str) -> str:
device_name = identifier.split('_')[0]
logging.debug(f"{identifier} belongs to device {device_name}.")
return device_name
[docs]
class UppsalaPFonRail(PFonRail):
@property
def name(self) -> str:
# overwrite it because its nicer as server name
return "PFonRail"
[docs]
@classmethod
def get_name(cls) -> str:
return "UppsalaPFonRail"
[docs]
def site_to_position_identifier(self, device: str, slot: int) -> str:
# handle special case of echo
if device == "Echo":
if slot == ECHO_SOURCE:
return "Echo_source"
elif slot == ECHO_DESTINATION:
return "Echo_destination"
# devices with just one handover position are tagged like this
pos_identifier = f"{device}_nest"
# devices with multiple handover positions have their number attached (starting at 0)
if not self.graph_manager.position_known(pos_identifier):
pos_identifier += str(slot)
if not self.graph_manager.position_known(pos_identifier):
logging.error(f"neither {device}_nest nor {pos_identifier} are known positions")
return pos_identifier
[docs]
def move_to_safe_pos(self, identifier: str, offset: dict[str, float] | None = None):
"""
Moves to the approach position belonging to the specified position
:param offset:
:param identifier:
:return:
"""
device_name = device_from_identifier(identifier)
safe_pos = approach_position(device_name)
self.move_to_position(safe_pos, offset=offset)
[docs]
def pick_at_position(self, identifier: str, offset: dict[str, float] | None=None):
super().pick_at_position(identifier, offset = offset)
self.move_to_safe_pos(identifier, offset=offset)
[docs]
def place_at_position(self, identifier: str, offset: dict[str, float] | None = None):
super().place_at_position(identifier, offset=offset)
self.move_to_safe_pos(identifier, offset=offset)
[docs]
def prepare_for_output(self, internal_pos: int, device: str, position: int) -> bool:
safe_pos = approach_position(device)
self.move_to_position(safe_pos)
return True
# InteractiveTransferInterface
@property
def available_intermediate_actions(self) -> list[str]:
return ["read_barcode", "unlid", "lid"]
[docs]
def remove_lid(self, plate_position: str, lid_deposit_position: str):
logging.info(f"removing lid at {plate_position} and putting it to {lid_deposit_position}")
self.move_to_position(plate_position, offset={"z": lid_pick_offset})
self.grip_close()
self.move_to_position(plate_position, offset={"z": lid_off})
self.move_to_safe_pos(plate_position, offset={"z": lid_off})
self.place_at_position(lid_deposit_position, offset={"z": lid_alone_offset})
[docs]
def put_lid_on(self, plate_position: str, lid_position: str):
logging.info(f"putting lid from {lid_position} on plate at {plate_position}")
self.pick_at_position(lid_position, offset={"z":lid_alone_offset})
self.move_to_position(plate_position, offset={"z":lid_off})
self.move_to_position(plate_position, offset={"z":lid_place_offset})
self.grip_open()
self.move_to_safe_pos(plate_position, offset={"z":lid_place_offset})
[docs]
def get_barcode_scanned(self):
if self.graph_manager.position_known(bc_reader_position):
self.move_to_position(bc_reader_position)
time.sleep(.5)
[docs]
def put_labware(self, intermediate_actions: list[str], device: str, position: int):
position_identifier = self.site_to_position_identifier(device, position)
self.place_at_position(position_identifier)
# there should be no or one unlidding command
unlid_cmd = next((cmd for cmd in intermediate_actions if cmd.startswith("unlid_")), None)
# unlid command is encoded 'unlid_[DEVICE]_[POSITION]'
if unlid_cmd:
_, lid_device, lid_position = unlid_cmd.split("_")
lid_pos_identifier = self.site_to_position_identifier(lid_device, int(lid_position))
self.remove_lid(position_identifier, lid_pos_identifier)
[docs]
def get_labware(self, intermediate_actions: list[str], device: str, position: int):
position_identifier = self.site_to_position_identifier(device, position)
# there should be no or one unlidding command
lid_cmd = next((cmd for cmd in intermediate_actions if cmd.startswith("lid_")), None)
# unlid command is encoded 'unlid_[DEVICE]_[POSITION]'
if lid_cmd:
_, lid_device, lid_position = lid_cmd.split("_")
lid_pos_identifier = self.site_to_position_identifier(lid_device, int(lid_position))
self.put_lid_on(position_identifier, lid_pos_identifier)
self.pick_at_position(position_identifier)
if "read_barcode" in intermediate_actions:
self.get_barcode_scanned()