diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000..26d33521af --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000000..930c017364 --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,14 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000..105ce2da2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000..addea05e43 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/.idea/pylabrobot.iml b/.idea/pylabrobot.iml new file mode 100644 index 0000000000..ec63674cd7 --- /dev/null +++ b/.idea/pylabrobot.iml @@ -0,0 +1,7 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000..35eb1ddfbb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pylabrobot/liquid_handling/backends/tecan/EVO_backend.py b/pylabrobot/liquid_handling/backends/tecan/EVO_backend.py index ecc8d29c84..03859bb9ac 100644 --- a/pylabrobot/liquid_handling/backends/tecan/EVO_backend.py +++ b/pylabrobot/liquid_handling/backends/tecan/EVO_backend.py @@ -10,6 +10,7 @@ Union, ) +from pylabrobot.liquid_handling.utils import get_tight_single_resource_liquid_op_offsets from pylabrobot.io.usb import USB from pylabrobot.liquid_handling.backends.backend import ( LiquidHandlerBackend, @@ -288,14 +289,20 @@ async def setup(self): # Initialize plungers. Assumes wash station assigned at rail 1. await self.liha.set_z_travel_height([self._z_range] * self.num_channels) - await self.liha.position_absolute_all_axis(45, 1031, 90, [1200] * self.num_channels) + wash = self.deck.get_resource("wash_waste") + wash_offsets = get_tight_single_resource_liquid_op_offsets(wash, self.num_channels) + location = wash.get_absolute_location() + wash.center() + wash_offsets[0] + location.x = int(location.x * 10) + location.y = int((352 - location.y) * 10) + location.z = int(wash.get_size_z() * 10) + await self.liha.position_absolute_all_axis(location.x, location.y,90, [location.z] * self.num_channels) await self.liha.initialize_plunger(self._bin_use_channels(list(range(self.num_channels)))) await self.liha.position_valve_logical([1] * self.num_channels) await self.liha.move_plunger_relative([100] * self.num_channels) await self.liha.position_valve_logical([0] * self.num_channels) await self.liha.set_end_speed_plunger([1800] * self.num_channels) await self.liha.move_plunger_relative([-100] * self.num_channels) - await self.liha.position_absolute_all_axis(45, 1031, 90, [self._z_range] * self.num_channels) + await self.liha.position_absolute_all_axis(location.x, location.y, 90, [self._z_range] * self.num_channels) async def setup_arm(self, module): try: @@ -459,7 +466,7 @@ async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[in x, _ = self._first_valid(x_positions) y, yi = self._first_valid(y_positions) assert x is not None and y is not None - await self.liha.set_z_travel_height(z if z else self._z_range for z in z_positions["travel"]) + await self.liha.set_z_travel_height([z if z else self._z_range for z in z_positions["travel"]]) await self.liha.position_absolute_all_axis( x, y - yi * ys, @@ -487,6 +494,7 @@ async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int]): # Get positions including offsets x_positions, y_positions, z_positions = self._liha_positions(ops, use_channels) + z_positions["start"] = [int(op.resource.parent.z_start) for op in ops if op.resource.parent.z_start] # directly get z_position from z_start to avoid tip length issue? # move channels ys = int(ops[0].resource.get_absolute_size_y() * 10) @@ -678,8 +686,8 @@ def get_z_position(z, z_off, tip_length): for i, (op, channel) in enumerate(zip(ops, use_channels)): location = ops[i].resource.get_absolute_location() + op.resource.center() - x_positions[channel] = int((location.x - 100 + op.offset.x) * 10) - y_positions[channel] = int((346.5 - location.y + op.offset.y) * 10) # TODO: verify + x_positions[channel] = int((location.x + op.offset.x) * 10) + y_positions[channel] = int((352 - (location.y + op.offset.y)) * 10) # TODO: verify par = ops[i].resource.parent if not isinstance(par, (TecanPlate, TecanTipRack)): @@ -692,12 +700,15 @@ def get_z_position(z, z_off, tip_length): z_positions["start"][channel] = get_z_position( par.z_start, par.get_absolute_location().z + op.offset.z, tip_length ) + # container.get_absolute_position(z="cavity_bottom") + lld_search_height z_positions["dispense"][channel] = get_z_position( par.z_dispense, par.get_absolute_location().z + op.offset.z, tip_length ) + # container.get_absolute_position(z="cavity_bottom") + liquid_height z_positions["max"][channel] = get_z_position( par.z_max, par.get_absolute_location().z + op.offset.z, tip_length ) + # container.get_absolute_position(z="cavity_bottom") return x_positions, y_positions, z_positions diff --git a/pylabrobot/resources/tecan/plate_carriers.py b/pylabrobot/resources/tecan/plate_carriers.py index 4b7c1266ad..9db28d478a 100644 --- a/pylabrobot/resources/tecan/plate_carriers.py +++ b/pylabrobot/resources/tecan/plate_carriers.py @@ -554,7 +554,7 @@ def MP_4Pos_flat(name: str) -> TecanPlateCarrier: size_y=380.0, size_z=6.9, off_x=11.0, - off_y=51.0, + off_y=23.0, roma_x=1835, roma_y=388, roma_z_safe=946, diff --git a/pylabrobot/resources/tecan/tecan_decks.py b/pylabrobot/resources/tecan/tecan_decks.py index 656314bba8..114555ecaa 100644 --- a/pylabrobot/resources/tecan/tecan_decks.py +++ b/pylabrobot/resources/tecan/tecan_decks.py @@ -135,15 +135,15 @@ def _coordinate_for_rails(self, rails: int, resource: Resource): raise ValueError(f"Resource {resource} is not a Tecan resource.") return Coordinate( - (rails - 1) * _RAILS_WIDTH - resource.off_x + 100, - resource.off_y + 345 - resource.get_absolute_size_y(), + 130 + (rails - 1) * _RAILS_WIDTH - resource.off_x, + resource.off_y, 0, ) # TODO: verify def _rails_for_x_coordinate(self, x: float): """Convert an x coordinate to a rail identifier.""" - return round((x + _RAILS_WIDTH - 101) / _RAILS_WIDTH) + 1 + return round((x + _RAILS_WIDTH - 130) / _RAILS_WIDTH) + 1 def summary(self) -> str: """Return a summary of the deck.""" diff --git a/pylabrobot/resources/tecan/tip_carriers.py b/pylabrobot/resources/tecan/tip_carriers.py index 3c3a1c1fe4..971b9df20c 100644 --- a/pylabrobot/resources/tecan/tip_carriers.py +++ b/pylabrobot/resources/tecan/tip_carriers.py @@ -146,15 +146,15 @@ def DiTi_3Pos(name: str) -> TecanTipCarrier: name=name, size_x=149.0, size_y=374.0, - size_z=4.5, - off_x=12.0, - off_y=24.7, + size_z=123.2, + off_x=12, + off_y=60, sites=create_homogeneous_resources( klass=ResourceHolder, locations=[ - Coordinate(13.3, 70.0, 4.5), - Coordinate(13.3, 170.0, 4.5), - Coordinate(13.3, 270.0, 4.5), + Coordinate(13.3, 13.4, 4.5), + Coordinate(13.3, 113.4, 4.5), + Coordinate(13.3, 213.4, 4.5), ], resource_size_x=127.0, resource_size_y=88.5, diff --git a/pylabrobot/resources/tecan/tip_racks.py b/pylabrobot/resources/tecan/tip_racks.py index e32b332dbc..bdb6ba1d19 100644 --- a/pylabrobot/resources/tecan/tip_racks.py +++ b/pylabrobot/resources/tecan/tip_racks.py @@ -1235,7 +1235,7 @@ def DiTi_1000ul_LiHa(name: str) -> TecanTipRack: num_items_x=12, num_items_y=8, dx=7.7, - dy=8.7, + dy=7.7, dz=32.6, item_dx=9.0, item_dy=9.0, diff --git a/pylabrobot/resources/tecan/wash.py b/pylabrobot/resources/tecan/wash.py index 29af808690..1f0ded9854 100644 --- a/pylabrobot/resources/tecan/wash.py +++ b/pylabrobot/resources/tecan/wash.py @@ -46,14 +46,14 @@ def Wash_Station(name: str) -> TecanWashStation: size_x=25.0, size_y=390.0, size_z=0.0, + off_y= -13, off_x=12.5, - off_y=24.7, sites=create_resources( klass=ResourceHolder, locations=[ - Coordinate(12.2, 106.7, 0.0), - Coordinate(11.0, 180.7, 0.0), - Coordinate(12.2, 281.7, 0.0), + Coordinate(12.2, 107, 0.0), + Coordinate(11.0, 181, 0.0), + Coordinate(12.2, 282, 0.0), ], resource_size_x=[ 12.0,