diff --git a/pylabrobot/liquid_handling/backends/hamilton/STAR.py b/pylabrobot/liquid_handling/backends/hamilton/STAR.py index 7d33ea5c82..4d1d0b768b 100644 --- a/pylabrobot/liquid_handling/backends/hamilton/STAR.py +++ b/pylabrobot/liquid_handling/backends/hamilton/STAR.py @@ -882,8 +882,7 @@ def trace_information_to_string(module_identifier: str, trace_information: int) 35: "Voltages outside permitted range", 36: "Stop during execution of command", 37: "Stop during execution of command", - 40: "No parallel processes permitted (Two or more commands sent for the same control" - "process)", + 40: "No parallel processes permitted (Two or more commands sent for the same controlprocess)", 50: "Dispensing drive init. position not found", 51: "Dispensing drive not initialized", 52: "Dispensing drive movement error", @@ -1216,7 +1215,7 @@ async def get_iswap_version(self) -> str: return self._iswap_version async def request_pip_channel_version(self, channel: int) -> str: - return cast(str, (await self.send_command(f"P{channel+1}", "RF", fmt="rf" + "&" * 17))["rf"]) + return cast(str, (await self.send_command(f"P{channel + 1}", "RF", fmt="rf" + "&" * 17))["rf"]) def get_id_from_fw_response(self, resp: str) -> Optional[int]: """Get the id from a firmware response.""" @@ -3116,7 +3115,7 @@ async def core_check_resource_exists_at_location_center( elif user_prompt == "abort": raise ValueError( f"Resource '{resource.name}' not found at center" - f" location {(center.x,center.y,center.z)}" + f" location {(center.x, center.y, center.z)}" " & error not resolved -> aborted resource movement." ) else: @@ -3517,44 +3516,44 @@ async def set_instrument_configuration( and 9999. Default 60. """ - assert ( - 1 <= instrument_size_in_slots_x_range <= 9 - ), "instrument_size_in_slots_x_range must be between 1 and 99" + assert 1 <= instrument_size_in_slots_x_range <= 9, ( + "instrument_size_in_slots_x_range must be between 1 and 99" + ) assert 1 <= auto_load_size_in_slots <= 54, "auto_load_size_in_slots must be between 1 and 54" assert 1000 <= tip_waste_x_position <= 25000, "tip_waste_x_position must be between 1 and 25000" - assert ( - 0 <= right_x_drive_configuration_byte_1 <= 1 - ), "right_x_drive_configuration_byte_1 must be between 0 and 1" - assert ( - 0 <= right_x_drive_configuration_byte_2 <= 1 - ), "right_x_drive_configuration_byte_2 must be between 0 and must1" - assert ( - 0 <= minimal_iswap_collision_free_position <= 30000 - ), "minimal_iswap_collision_free_position must be between 0 and 30000" - assert ( - 0 <= maximal_iswap_collision_free_position <= 30000 - ), "maximal_iswap_collision_free_position must be between 0 and 30000" + assert 0 <= right_x_drive_configuration_byte_1 <= 1, ( + "right_x_drive_configuration_byte_1 must be between 0 and 1" + ) + assert 0 <= right_x_drive_configuration_byte_2 <= 1, ( + "right_x_drive_configuration_byte_2 must be between 0 and must1" + ) + assert 0 <= minimal_iswap_collision_free_position <= 30000, ( + "minimal_iswap_collision_free_position must be between 0 and 30000" + ) + assert 0 <= maximal_iswap_collision_free_position <= 30000, ( + "maximal_iswap_collision_free_position must be between 0 and 30000" + ) assert 0 <= left_x_arm_width <= 9999, "left_x_arm_width must be between 0 and 9999" assert 0 <= right_x_arm_width <= 9999, "right_x_arm_width must be between 0 and 9999" assert 0 <= num_pip_channels <= 16, "num_pip_channels must be between 0 and 16" assert 0 <= num_xl_channels <= 8, "num_xl_channels must be between 0 and 8" assert 0 <= num_robotic_channels <= 8, "num_robotic_channels must be between 0 and 8" - assert ( - 0 <= minimal_raster_pitch_of_pip_channels <= 999 - ), "minimal_raster_pitch_of_pip_channels must be between 0 and 999" - assert ( - 0 <= minimal_raster_pitch_of_xl_channels <= 999 - ), "minimal_raster_pitch_of_xl_channels must be between 0 and 999" - assert ( - 0 <= minimal_raster_pitch_of_robotic_channels <= 999 - ), "minimal_raster_pitch_of_robotic_channels must be between 0 and 999" + assert 0 <= minimal_raster_pitch_of_pip_channels <= 999, ( + "minimal_raster_pitch_of_pip_channels must be between 0 and 999" + ) + assert 0 <= minimal_raster_pitch_of_xl_channels <= 999, ( + "minimal_raster_pitch_of_xl_channels must be between 0 and 999" + ) + assert 0 <= minimal_raster_pitch_of_robotic_channels <= 999, ( + "minimal_raster_pitch_of_robotic_channels must be between 0 and 999" + ) assert 0 <= pip_maximal_y_position <= 9999, "pip_maximal_y_position must be between 0 and 9999" - assert ( - 0 <= left_arm_minimal_y_position <= 9999 - ), "left_arm_minimal_y_position must be between 0 and 9999" - assert ( - 0 <= right_arm_minimal_y_position <= 9999 - ), "right_arm_minimal_y_position must be between 0 and 9999" + assert 0 <= left_arm_minimal_y_position <= 9999, ( + "left_arm_minimal_y_position must be between 0 and 9999" + ) + assert 0 <= right_arm_minimal_y_position <= 9999, ( + "right_arm_minimal_y_position must be between 0 and 9999" + ) return await self.send_command( module="C0", @@ -3805,17 +3804,17 @@ async def occupy_and_provide_area_for_external_access( 1) all arms left. 2) all arms right. """ - assert ( - 0 <= taken_area_identification_number <= 9999 - ), "taken_area_identification_number must be between 0 and 9999" + assert 0 <= taken_area_identification_number <= 9999, ( + "taken_area_identification_number must be between 0 and 9999" + ) assert 0 <= taken_area_left_margin <= 99, "taken_area_left_margin must be between 0 and 99" - assert ( - 0 <= taken_area_left_margin_direction <= 1 - ), "taken_area_left_margin_direction must be between 0 and 1" + assert 0 <= taken_area_left_margin_direction <= 1, ( + "taken_area_left_margin_direction must be between 0 and 1" + ) assert 0 <= taken_area_size <= 50000, "taken_area_size must be between 0 and 50000" - assert ( - 0 <= arm_preposition_mode_related_to_taken_areas <= 2 - ), "arm_preposition_mode_related_to_taken_areas must be between 0 and 2" + assert 0 <= arm_preposition_mode_related_to_taken_areas <= 2, ( + "arm_preposition_mode_related_to_taken_areas must be between 0 and 2" + ) return await self.send_command( module="C0", @@ -3835,9 +3834,9 @@ async def release_occupied_area(self, taken_area_identification_number: int = 0) Must be between 0 and 9999. Default 0. """ - assert ( - 0 <= taken_area_identification_number <= 999 - ), "taken_area_identification_number must be between 0 and 9999" + assert 0 <= taken_area_identification_number <= 999, ( + "taken_area_identification_number must be between 0 and 9999" + ) return await self.send_command( module="C0", @@ -3931,15 +3930,15 @@ async def initialize_pipetting_channels( assert all(0 <= xp <= 25000 for xp in x_positions), "x_positions must be between 0 and 25000" assert all(0 <= yp <= 6500 for yp in y_positions), "y_positions must be between 0 and 6500" - assert ( - 0 <= begin_of_tip_deposit_process <= 3600 - ), "begin_of_tip_deposit_process must be between 0 and 3600" - assert ( - 0 <= end_of_tip_deposit_process <= 3600 - ), "end_of_tip_deposit_process must be between 0 and 3600" - assert ( - 0 <= z_position_at_end_of_a_command <= 3600 - ), "z_position_at_end_of_a_command must be between 0 and 3600" + assert 0 <= begin_of_tip_deposit_process <= 3600, ( + "begin_of_tip_deposit_process must be between 0 and 3600" + ) + assert 0 <= end_of_tip_deposit_process <= 3600, ( + "end_of_tip_deposit_process must be between 0 and 3600" + ) + assert 0 <= z_position_at_end_of_a_command <= 3600, ( + "z_position_at_end_of_a_command must be between 0 and 3600" + ) assert 0 <= tip_type <= 99, "tip must be between 0 and 99" assert 0 <= discarding_method <= 1, "discarding_method must be between 0 and 1" @@ -3990,15 +3989,15 @@ async def pick_up_tip( assert all(0 <= xp <= 25000 for xp in x_positions), "x_positions must be between 0 and 25000" assert all(0 <= yp <= 6500 for yp in y_positions), "y_positions must be between 0 and 6500" - assert ( - 0 <= begin_tip_pick_up_process <= 3600 - ), "begin_tip_pick_up_process must be between 0 and 3600" - assert ( - 0 <= end_tip_pick_up_process <= 3600 - ), "end_tip_pick_up_process must be between 0 and 3600" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= begin_tip_pick_up_process <= 3600, ( + "begin_tip_pick_up_process must be between 0 and 3600" + ) + assert 0 <= end_tip_pick_up_process <= 3600, ( + "end_tip_pick_up_process must be between 0 and 3600" + ) + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) return await self.send_command( module="C0", @@ -4052,18 +4051,18 @@ async def discard_tip( assert all(0 <= xp <= 25000 for xp in x_positions), "x_positions must be between 0 and 25000" assert all(0 <= yp <= 6500 for yp in y_positions), "y_positions must be between 0 and 6500" - assert ( - 0 <= begin_tip_deposit_process <= 3600 - ), "begin_tip_deposit_process must be between 0 and 3600" - assert ( - 0 <= end_tip_deposit_process <= 3600 - ), "end_tip_deposit_process must be between 0 and 3600" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" - assert ( - 0 <= z_position_at_end_of_a_command <= 3600 - ), "z_position_at_end_of_a_command must be between 0 and 3600" + assert 0 <= begin_tip_deposit_process <= 3600, ( + "begin_tip_deposit_process must be between 0 and 3600" + ) + assert 0 <= end_tip_deposit_process <= 3600, ( + "end_tip_deposit_process must be between 0 and 3600" + ) + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) + assert 0 <= z_position_at_end_of_a_command <= 3600, ( + "z_position_at_end_of_a_command must be between 0 and 3600" + ) return await self.send_command( module="C0", @@ -4225,100 +4224,100 @@ async def aspirate_pip( assert all(0 <= x <= 2 for x in aspiration_type), "aspiration_type must be between 0 and 2" assert all(0 <= xp <= 25000 for xp in x_positions), "x_positions must be between 0 and 25000" assert all(0 <= yp <= 6500 for yp in y_positions), "y_positions must be between 0 and 6500" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) assert 0 <= min_z_endpos <= 3600, "min_z_endpos must be between 0 and 3600" - assert all( - 0 <= x <= 3600 for x in lld_search_height - ), "lld_search_height must be between 0 and 3600" - assert all( - 0 <= x <= 500 for x in clot_detection_height - ), "clot_detection_height must be between 0 and 500" - assert all( - 0 <= x <= 3600 for x in liquid_surface_no_lld - ), "liquid_surface_no_lld must be between 0 and 3600" - assert all( - 0 <= x <= 3600 for x in pull_out_distance_transport_air - ), "pull_out_distance_transport_air must be between 0 and 3600" - assert all( - 0 <= x <= 3600 for x in second_section_height - ), "second_section_height must be between 0 and 3600" - assert all( - 0 <= x <= 10000 for x in second_section_ratio - ), "second_section_ratio must be between 0 and 10000" + assert all(0 <= x <= 3600 for x in lld_search_height), ( + "lld_search_height must be between 0 and 3600" + ) + assert all(0 <= x <= 500 for x in clot_detection_height), ( + "clot_detection_height must be between 0 and 500" + ) + assert all(0 <= x <= 3600 for x in liquid_surface_no_lld), ( + "liquid_surface_no_lld must be between 0 and 3600" + ) + assert all(0 <= x <= 3600 for x in pull_out_distance_transport_air), ( + "pull_out_distance_transport_air must be between 0 and 3600" + ) + assert all(0 <= x <= 3600 for x in second_section_height), ( + "second_section_height must be between 0 and 3600" + ) + assert all(0 <= x <= 10000 for x in second_section_ratio), ( + "second_section_ratio must be between 0 and 10000" + ) assert all(0 <= x <= 3600 for x in minimum_height), "minimum_height must be between 0 and 3600" - assert all( - 0 <= x <= 3600 for x in immersion_depth - ), "immersion_depth must be between 0 and 3600" - assert all( - 0 <= x <= 1 for x in immersion_depth_direction - ), "immersion_depth_direction must be between 0 and 1" - assert all( - 0 <= x <= 3600 for x in surface_following_distance - ), "surface_following_distance must be between 0 and 3600" - assert all( - 0 <= x <= 12500 for x in aspiration_volumes - ), "aspiration_volumes must be between 0 and 12500" - assert all( - 4 <= x <= 5000 for x in aspiration_speed - ), "aspiration_speed must be between 4 and 5000" - assert all( - 0 <= x <= 500 for x in transport_air_volume - ), "transport_air_volume must be between 0 and 500" - assert all( - 0 <= x <= 9999 for x in blow_out_air_volume - ), "blow_out_air_volume must be between 0 and 9999" - assert all( - 0 <= x <= 999 for x in pre_wetting_volume - ), "pre_wetting_volume must be between 0 and 999" + assert all(0 <= x <= 3600 for x in immersion_depth), ( + "immersion_depth must be between 0 and 3600" + ) + assert all(0 <= x <= 1 for x in immersion_depth_direction), ( + "immersion_depth_direction must be between 0 and 1" + ) + assert all(0 <= x <= 3600 for x in surface_following_distance), ( + "surface_following_distance must be between 0 and 3600" + ) + assert all(0 <= x <= 12500 for x in aspiration_volumes), ( + "aspiration_volumes must be between 0 and 12500" + ) + assert all(4 <= x <= 5000 for x in aspiration_speed), ( + "aspiration_speed must be between 4 and 5000" + ) + assert all(0 <= x <= 500 for x in transport_air_volume), ( + "transport_air_volume must be between 0 and 500" + ) + assert all(0 <= x <= 9999 for x in blow_out_air_volume), ( + "blow_out_air_volume must be between 0 and 9999" + ) + assert all(0 <= x <= 999 for x in pre_wetting_volume), ( + "pre_wetting_volume must be between 0 and 999" + ) assert all(0 <= x <= 4 for x in lld_mode), "lld_mode must be between 0 and 4" - assert all( - 1 <= x <= 4 for x in gamma_lld_sensitivity - ), "gamma_lld_sensitivity must be between 1 and 4" - assert all( - 1 <= x <= 4 for x in dp_lld_sensitivity - ), "dp_lld_sensitivity must be between 1 and 4" - assert all( - 0 <= x <= 100 for x in aspirate_position_above_z_touch_off - ), "aspirate_position_above_z_touch_off must be between 0 and 100" - assert all( - 0 <= x <= 99 for x in detection_height_difference_for_dual_lld - ), "detection_height_difference_for_dual_lld must be between 0 and 99" + assert all(1 <= x <= 4 for x in gamma_lld_sensitivity), ( + "gamma_lld_sensitivity must be between 1 and 4" + ) + assert all(1 <= x <= 4 for x in dp_lld_sensitivity), ( + "dp_lld_sensitivity must be between 1 and 4" + ) + assert all(0 <= x <= 100 for x in aspirate_position_above_z_touch_off), ( + "aspirate_position_above_z_touch_off must be between 0 and 100" + ) + assert all(0 <= x <= 99 for x in detection_height_difference_for_dual_lld), ( + "detection_height_difference_for_dual_lld must be between 0 and 99" + ) assert all(3 <= x <= 1600 for x in swap_speed), "swap_speed must be between 3 and 1600" assert all(0 <= x <= 99 for x in settling_time), "settling_time must be between 0 and 99" assert all(0 <= x <= 12500 for x in mix_volume), "mix_volume must be between 0 and 12500" assert all(0 <= x <= 99 for x in mix_cycles), "mix_cycles must be between 0 and 99" - assert all( - 0 <= x <= 900 for x in mix_position_from_liquid_surface - ), "mix_position_from_liquid_surface must be between 0 and 900" + assert all(0 <= x <= 900 for x in mix_position_from_liquid_surface), ( + "mix_position_from_liquid_surface must be between 0 and 900" + ) assert all(4 <= x <= 5000 for x in mix_speed), "mix_speed must be between 4 and 5000" - assert all( - 0 <= x <= 3600 for x in mix_surface_following_distance - ), "mix_surface_following_distance must be between 0 and 3600" - assert all( - 0 <= x <= 999 for x in limit_curve_index - ), "limit_curve_index must be between 0 and 999" + assert all(0 <= x <= 3600 for x in mix_surface_following_distance), ( + "mix_surface_following_distance must be between 0 and 3600" + ) + assert all(0 <= x <= 999 for x in limit_curve_index), ( + "limit_curve_index must be between 0 and 999" + ) assert 0 <= recording_mode <= 2, "recording_mode must be between 0 and 2" - assert all( - 0 <= x <= 3600 for x in retract_height_over_2nd_section_to_empty_tip - ), "retract_height_over_2nd_section_to_empty_tip must be between 0 and 3600" - assert all( - 4 <= x <= 5000 for x in dispensation_speed_during_emptying_tip - ), "dispensation_speed_during_emptying_tip must be between 4 and 5000" - assert all( - 4 <= x <= 5000 for x in dosing_drive_speed_during_2nd_section_search - ), "dosing_drive_speed_during_2nd_section_search must be between 4 and 5000" - assert all( - 3 <= x <= 1600 for x in z_drive_speed_during_2nd_section_search - ), "z_drive_speed_during_2nd_section_search must be between 3 and 1600" + assert all(0 <= x <= 3600 for x in retract_height_over_2nd_section_to_empty_tip), ( + "retract_height_over_2nd_section_to_empty_tip must be between 0 and 3600" + ) + assert all(4 <= x <= 5000 for x in dispensation_speed_during_emptying_tip), ( + "dispensation_speed_during_emptying_tip must be between 4 and 5000" + ) + assert all(4 <= x <= 5000 for x in dosing_drive_speed_during_2nd_section_search), ( + "dosing_drive_speed_during_2nd_section_search must be between 4 and 5000" + ) + assert all(3 <= x <= 1600 for x in z_drive_speed_during_2nd_section_search), ( + "z_drive_speed_during_2nd_section_search must be between 3 and 1600" + ) assert all(0 <= x <= 3600 for x in cup_upper_edge), "cup_upper_edge must be between 0 and 3600" - assert all( - 0 <= x <= 5000 for x in ratio_liquid_rise_to_tip_deep_in - ), "ratio_liquid_rise_to_tip_deep_in must be between 0 and 50000" - assert all( - 0 <= x <= 3600 for x in immersion_depth_2nd_section - ), "immersion_depth_2nd_section must be between 0 and 3600" + assert all(0 <= x <= 5000 for x in ratio_liquid_rise_to_tip_deep_in), ( + "ratio_liquid_rise_to_tip_deep_in must be between 0 and 50000" + ) + assert all(0 <= x <= 3600 for x in immersion_depth_2nd_section), ( + "immersion_depth_2nd_section must be between 0 and 3600" + ) return await self.send_command( module="C0", @@ -4485,73 +4484,73 @@ async def dispense_pip( assert all(0 <= xp <= 25000 for xp in x_positions), "x_positions must be between 0 and 25000" assert all(0 <= yp <= 6500 for yp in y_positions), "y_positions must be between 0 and 6500" assert any(0 <= x <= 3600 for x in minimum_height), "minimum_height must be between 0 and 3600" - assert any( - 0 <= x <= 3600 for x in lld_search_height - ), "lld_search_height must be between 0 and 3600" - assert any( - 0 <= x <= 3600 for x in liquid_surface_no_lld - ), "liquid_surface_no_lld must be between 0 and 3600" - assert any( - 0 <= x <= 3600 for x in pull_out_distance_transport_air - ), "pull_out_distance_transport_air must be between 0 and 3600" - assert any( - 0 <= x <= 3600 for x in immersion_depth - ), "immersion_depth must be between 0 and 3600" - assert any( - 0 <= x <= 1 for x in immersion_depth_direction - ), "immersion_depth_direction must be between 0 and 1" - assert any( - 0 <= x <= 3600 for x in surface_following_distance - ), "surface_following_distance must be between 0 and 3600" - assert any( - 0 <= x <= 3600 for x in second_section_height - ), "second_section_height must be between 0 and 3600" - assert any( - 0 <= x <= 10000 for x in second_section_ratio - ), "second_section_ratio must be between 0 and 10000" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert any(0 <= x <= 3600 for x in lld_search_height), ( + "lld_search_height must be between 0 and 3600" + ) + assert any(0 <= x <= 3600 for x in liquid_surface_no_lld), ( + "liquid_surface_no_lld must be between 0 and 3600" + ) + assert any(0 <= x <= 3600 for x in pull_out_distance_transport_air), ( + "pull_out_distance_transport_air must be between 0 and 3600" + ) + assert any(0 <= x <= 3600 for x in immersion_depth), ( + "immersion_depth must be between 0 and 3600" + ) + assert any(0 <= x <= 1 for x in immersion_depth_direction), ( + "immersion_depth_direction must be between 0 and 1" + ) + assert any(0 <= x <= 3600 for x in surface_following_distance), ( + "surface_following_distance must be between 0 and 3600" + ) + assert any(0 <= x <= 3600 for x in second_section_height), ( + "second_section_height must be between 0 and 3600" + ) + assert any(0 <= x <= 10000 for x in second_section_ratio), ( + "second_section_ratio must be between 0 and 10000" + ) + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) assert 0 <= min_z_endpos <= 3600, "min_z_endpos must be between 0 and 3600" - assert any( - 0 <= x <= 12500 for x in dispense_volumes - ), "dispense_volume must be between 0 and 12500" + assert any(0 <= x <= 12500 for x in dispense_volumes), ( + "dispense_volume must be between 0 and 12500" + ) assert any(4 <= x <= 5000 for x in dispense_speed), "dispense_speed must be between 4 and 5000" assert any(4 <= x <= 5000 for x in cut_off_speed), "cut_off_speed must be between 4 and 5000" - assert any( - 0 <= x <= 180 for x in stop_back_volume - ), "stop_back_volume must be between 0 and 180" - assert any( - 0 <= x <= 500 for x in transport_air_volume - ), "transport_air_volume must be between 0 and 500" - assert any( - 0 <= x <= 9999 for x in blow_out_air_volume - ), "blow_out_air_volume must be between 0 and 9999" + assert any(0 <= x <= 180 for x in stop_back_volume), ( + "stop_back_volume must be between 0 and 180" + ) + assert any(0 <= x <= 500 for x in transport_air_volume), ( + "transport_air_volume must be between 0 and 500" + ) + assert any(0 <= x <= 9999 for x in blow_out_air_volume), ( + "blow_out_air_volume must be between 0 and 9999" + ) assert any(0 <= x <= 4 for x in lld_mode), "lld_mode must be between 0 and 4" assert 0 <= side_touch_off_distance <= 45, "side_touch_off_distance must be between 0 and 45" - assert any( - 0 <= x <= 100 for x in dispense_position_above_z_touch_off - ), "dispense_position_above_z_touch_off must be between 0 and 100" - assert any( - 1 <= x <= 4 for x in gamma_lld_sensitivity - ), "gamma_lld_sensitivity must be between 1 and 4" - assert any( - 1 <= x <= 4 for x in dp_lld_sensitivity - ), "dp_lld_sensitivity must be between 1 and 4" + assert any(0 <= x <= 100 for x in dispense_position_above_z_touch_off), ( + "dispense_position_above_z_touch_off must be between 0 and 100" + ) + assert any(1 <= x <= 4 for x in gamma_lld_sensitivity), ( + "gamma_lld_sensitivity must be between 1 and 4" + ) + assert any(1 <= x <= 4 for x in dp_lld_sensitivity), ( + "dp_lld_sensitivity must be between 1 and 4" + ) assert any(3 <= x <= 1600 for x in swap_speed), "swap_speed must be between 3 and 1600" assert any(0 <= x <= 99 for x in settling_time), "settling_time must be between 0 and 99" assert any(0 <= x <= 12500 for x in mix_volume), "mix_volume must be between 0 and 12500" assert any(0 <= x <= 99 for x in mix_cycles), "mix_cycles must be between 0 and 99" - assert any( - 0 <= x <= 900 for x in mix_position_from_liquid_surface - ), "mix_position_from_liquid_surface must be between 0 and 900" + assert any(0 <= x <= 900 for x in mix_position_from_liquid_surface), ( + "mix_position_from_liquid_surface must be between 0 and 900" + ) assert any(4 <= x <= 5000 for x in mix_speed), "mix_speed must be between 4 and 5000" - assert any( - 0 <= x <= 3600 for x in mix_surface_following_distance - ), "mix_surface_following_distance must be between 0 and 3600" - assert any( - 0 <= x <= 999 for x in limit_curve_index - ), "limit_curve_index must be between 0 and 999" + assert any(0 <= x <= 3600 for x in mix_surface_following_distance), ( + "mix_surface_following_distance must be between 0 and 3600" + ) + assert any(0 <= x <= 999 for x in limit_curve_index), ( + "limit_curve_index must be between 0 and 999" + ) assert 0 <= recording_mode <= 2, "recording_mode must be between 0 and 2" return await self.send_command( @@ -4697,12 +4696,12 @@ async def core_get_plate( assert 0 <= open_gripper_position <= 9999, "open_gripper_position must be between 0 and 9999" assert 0 <= plate_width <= 9999, "plate_width must be between 0 and 9999" assert 0 <= grip_strength <= 99, "grip_strength must be between 0 and 99" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" - assert ( - 0 <= minimum_z_position_at_the_command_end <= 3600 - ), "minimum_z_position_at_the_command_end must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) + assert 0 <= minimum_z_position_at_the_command_end <= 3600, ( + "minimum_z_position_at_the_command_end must be between 0 and 3600" + ) command_output = await self.send_command( module="C0", @@ -4745,12 +4744,12 @@ async def core_put_plate( assert 0 <= z_press_on_distance <= 50, "z_press_on_distance must be between 0 and 999" assert 0 <= z_speed <= 1600, "z_speed must be between 0 and 1600" assert 0 <= open_gripper_position <= 9999, "open_gripper_position must be between 0 and 9999" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" - assert ( - 0 <= z_position_at_the_command_end <= 3600 - ), "z_position_at_the_command_end must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) + assert 0 <= z_position_at_the_command_end <= 3600, ( + "z_position_at_the_command_end must be between 0 and 3600" + ) command_output = await self.send_command( module="C0", @@ -4812,9 +4811,9 @@ async def position_single_pipetting_channel_in_y_direction( y_position: y position [0.1mm]. Must be between 0 and 6500. """ - assert ( - 1 <= pipetting_channel_index <= self.num_channels - ), "pipetting_channel_index must be between 1 and self" + assert 1 <= pipetting_channel_index <= self.num_channels, ( + "pipetting_channel_index must be between 1 and self" + ) assert 0 <= y_position <= 6500, "y_position must be between 0 and 6500" return await self.send_command( @@ -4837,9 +4836,9 @@ async def position_single_pipetting_channel_in_z_direction( 3347 is the max. """ - assert ( - 1 <= pipetting_channel_index <= self.num_channels - ), "pipetting_channel_index must be between 1 and self.num_channels" + assert 1 <= pipetting_channel_index <= self.num_channels, ( + "pipetting_channel_index must be between 1 and self.num_channels" + ) # docs say 3600, but empirically 3347 is the max assert 0 <= z_position <= 3347, "z_position must be between 0 and 3347" @@ -4860,9 +4859,9 @@ async def search_for_teach_in_signal_using_pipetting_channel_n_in_x_direction( x_position: x position [0.1mm]. Must be between 0 and 30000. """ - assert ( - 1 <= pipetting_channel_index <= self.num_channels - ), "pipetting_channel_index must be between 1 and self.num_channels" + assert 1 <= pipetting_channel_index <= self.num_channels, ( + "pipetting_channel_index must be between 1 and self.num_channels" + ) assert 0 <= x_position <= 30000, "x_position must be between 0 and 30000" return await self.send_command( @@ -4900,9 +4899,9 @@ async def move_all_pipetting_channels_to_defined_position( assert 0 <= x_positions <= 25000, "x_positions must be between 0 and 25000" assert 0 <= y_positions <= 6500, "y_positions must be between 0 and 6500" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_command must be between 0 and 3600" + ) assert 0 <= z_endpos <= 3600, "z_endpos must be between 0 and 3600" return await self.send_command( @@ -4924,9 +4923,9 @@ async def position_max_free_y_for_n(self, pipetting_channel_index: int): pipetting_channel_index: Index of pipetting channel. Must be between 0 and self.num_channels. """ - assert ( - 0 <= pipetting_channel_index < self.num_channels - ), "pipetting_channel_index must be between 1 and self.num_channels" + assert 0 <= pipetting_channel_index < self.num_channels, ( + "pipetting_channel_index must be between 1 and self.num_channels" + ) # convert Python's 0-based indexing to Hamilton firmware's 1-based indexing pipetting_channel_index = pipetting_channel_index + 1 @@ -4953,9 +4952,9 @@ async def request_y_pos_channel_n(self, pipetting_channel_index: int) -> float: 0 is the backmost channel. """ - assert ( - 0 <= pipetting_channel_index < self.num_channels - ), "pipetting_channel_index must be between 0 and self.num_channels" + assert 0 <= pipetting_channel_index < self.num_channels, ( + "pipetting_channel_index must be between 0 and self.num_channels" + ) # convert Python's 0-based indexing to Hamilton firmware's 1-based indexing pipetting_channel_index = pipetting_channel_index + 1 @@ -5174,7 +5173,7 @@ async def initialize_core_96_head( xd=0 if loc.x >= 0 else 1, yh=f"{abs(round(loc.y * 10)):04}", za=f"{round(loc.z * 10):04}", - ze=f"{round(z_position_at_the_command_end*10):04}", + ze=f"{round(z_position_at_the_command_end * 10):04}", ) async def move_core_96_to_safe_position(self): @@ -5221,12 +5220,12 @@ async def pick_up_tips_core96( assert 0 <= x_direction <= 1, "x_direction must be between 0 and 1" assert 1080 <= y_position <= 5600, "y_position must be between 1080 and 5600" assert 0 <= z_deposit_position <= 3425, "z_deposit_position must be between 0 and 3425" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" - assert ( - 0 <= minimum_height_command_end <= 3425 - ), "minimum_height_command_end must be between 0 and 3425" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + ) + assert 0 <= minimum_height_command_end <= 3425, ( + "minimum_height_command_end must be between 0 and 3425" + ) return await self.send_command( module="C0", @@ -5271,12 +5270,12 @@ async def discard_tips_core96( assert 0 <= x_direction <= 1, "x_direction must be between 0 and 1" assert 1080 <= y_position <= 5600, "y_position must be between 1080 and 5600" assert 0 <= z_deposit_position <= 3425, "z_deposit_position must be between 0 and 3425" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" - assert ( - 0 <= minimum_height_command_end <= 3425 - ), "minimum_height_command_end must be between 0 and 3425" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + ) + assert 0 <= minimum_height_command_end <= 3425, ( + "minimum_height_command_end must be between 0 and 3425" + ) return await self.send_command( module="C0", @@ -5389,31 +5388,31 @@ async def aspirate_core_96( assert 0 <= x_position <= 30000, "x_position must be between 0 and 30000" assert 0 <= x_direction <= 1, "x_direction must be between 0 and 1" assert 1080 <= y_positions <= 5600, "y_positions must be between 1080 and 5600" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + ) assert 0 <= minimal_end_height <= 3425, "minimal_end_height must be between 0 and 3425" assert 0 <= lld_search_height <= 3425, "lld_search_height must be between 0 and 3425" - assert ( - 0 <= liquid_surface_at_function_without_lld <= 3425 - ), "liquid_surface_at_function_without_lld must be between 0 and 3425" - assert ( - 0 <= pull_out_distance_to_take_transport_air_in_function_without_lld <= 3425 - ), "pull_out_distance_to_take_transport_air_in_function_without_lld must be between 0 and 3425" - assert ( - 0 <= maximum_immersion_depth <= 3425 - ), "maximum_immersion_depth must be between 0 and 3425" - assert ( - 0 <= tube_2nd_section_height_measured_from_zm <= 3425 - ), "tube_2nd_section_height_measured_from_zm must be between 0 and 3425" - assert ( - 0 <= tube_2nd_section_ratio <= 10000 - ), "tube_2nd_section_ratio must be between 0 and 10000" + assert 0 <= liquid_surface_at_function_without_lld <= 3425, ( + "liquid_surface_at_function_without_lld must be between 0 and 3425" + ) + assert 0 <= pull_out_distance_to_take_transport_air_in_function_without_lld <= 3425, ( + "pull_out_distance_to_take_transport_air_in_function_without_lld must be between 0 and 3425" + ) + assert 0 <= maximum_immersion_depth <= 3425, ( + "maximum_immersion_depth must be between 0 and 3425" + ) + assert 0 <= tube_2nd_section_height_measured_from_zm <= 3425, ( + "tube_2nd_section_height_measured_from_zm must be between 0 and 3425" + ) + assert 0 <= tube_2nd_section_ratio <= 10000, ( + "tube_2nd_section_ratio must be between 0 and 10000" + ) assert 0 <= immersion_depth <= 3600, "immersion_depth must be between 0 and 3600" assert 0 <= immersion_depth_direction <= 1, "immersion_depth_direction must be between 0 and 1" - assert ( - 0 <= liquid_surface_sink_distance_at_the_end_of_aspiration <= 990 - ), "liquid_surface_sink_distance_at_the_end_of_aspiration must be between 0 and 990" + assert 0 <= liquid_surface_sink_distance_at_the_end_of_aspiration <= 990, ( + "liquid_surface_sink_distance_at_the_end_of_aspiration must be between 0 and 990" + ) assert 0 <= aspiration_volumes <= 11500, "aspiration_volumes must be between 0 and 11500" assert 3 <= aspiration_speed <= 5000, "aspiration_speed must be between 3 and 5000" assert 0 <= transport_air_volume <= 500, "transport_air_volume must be between 0 and 500" @@ -5425,12 +5424,12 @@ async def aspirate_core_96( assert 0 <= settling_time <= 99, "settling_time must be between 0 and 99" assert 0 <= mix_volume <= 11500, "mix_volume must be between 0 and 11500" assert 0 <= mix_cycles <= 99, "mix_cycles must be between 0 and 99" - assert ( - 0 <= mix_position_from_liquid_surface <= 990 - ), "mix_position_from_liquid_surface must be between 0 and 990" - assert ( - 0 <= surface_following_distance_during_mix <= 990 - ), "surface_following_distance_during_mix must be between 0 and 990" + assert 0 <= mix_position_from_liquid_surface <= 990, ( + "mix_position_from_liquid_surface must be between 0 and 990" + ) + assert 0 <= surface_following_distance_during_mix <= 990, ( + "surface_following_distance_during_mix must be between 0 and 990" + ) assert 3 <= speed_of_mix <= 5000, "speed_of_mix must be between 3 and 5000" assert 0 <= limit_curve_index <= 999, "limit_curve_index must be between 0 and 999" @@ -5581,30 +5580,30 @@ async def dispense_core_96( assert 0 <= x_position <= 30000, "x_position must be between 0 and 30000" assert 0 <= x_direction <= 1, "x_direction must be between 0 and 1" assert 1080 <= y_position <= 5600, "y_position must be between 1080 and 5600" - assert ( - 0 <= maximum_immersion_depth <= 3425 - ), "maximum_immersion_depth must be between 0 and 3425" - assert ( - 0 <= tube_2nd_section_height_measured_from_zm <= 3425 - ), "tube_2nd_section_height_measured_from_zm must be between 0 and 3425" - assert ( - 0 <= tube_2nd_section_ratio <= 10000 - ), "tube_2nd_section_ratio must be between 0 and 10000" + assert 0 <= maximum_immersion_depth <= 3425, ( + "maximum_immersion_depth must be between 0 and 3425" + ) + assert 0 <= tube_2nd_section_height_measured_from_zm <= 3425, ( + "tube_2nd_section_height_measured_from_zm must be between 0 and 3425" + ) + assert 0 <= tube_2nd_section_ratio <= 10000, ( + "tube_2nd_section_ratio must be between 0 and 10000" + ) assert 0 <= lld_search_height <= 3425, "lld_search_height must be between 0 and 3425" - assert ( - 0 <= liquid_surface_at_function_without_lld <= 3425 - ), "liquid_surface_at_function_without_lld must be between 0 and 3425" - assert ( - 0 <= pull_out_distance_to_take_transport_air_in_function_without_lld <= 3425 - ), "pull_out_distance_to_take_transport_air_in_function_without_lld must be between 0 and 3425" + assert 0 <= liquid_surface_at_function_without_lld <= 3425, ( + "liquid_surface_at_function_without_lld must be between 0 and 3425" + ) + assert 0 <= pull_out_distance_to_take_transport_air_in_function_without_lld <= 3425, ( + "pull_out_distance_to_take_transport_air_in_function_without_lld must be between 0 and 3425" + ) assert 0 <= immersion_depth <= 3600, "immersion_depth must be between 0 and 3600" assert 0 <= immersion_depth_direction <= 1, "immersion_depth_direction must be between 0 and 1" - assert ( - 0 <= liquid_surface_sink_distance_at_the_end_of_dispense <= 990 - ), "liquid_surface_sink_distance_at_the_end_of_dispense must be between 0 and 990" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + assert 0 <= liquid_surface_sink_distance_at_the_end_of_dispense <= 990, ( + "liquid_surface_sink_distance_at_the_end_of_dispense must be between 0 and 990" + ) + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3425, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3425" + ) assert 0 <= minimal_end_height <= 3425, "minimal_end_height must be between 0 and 3425" assert 0 <= dispense_volume <= 11500, "dispense_volume must be between 0 and 11500" assert 3 <= dispense_speed <= 5000, "dispense_speed must be between 3 and 5000" @@ -5619,12 +5618,12 @@ async def dispense_core_96( assert 0 <= settling_time <= 99, "settling_time must be between 0 and 99" assert 0 <= mixing_volume <= 11500, "mixing_volume must be between 0 and 11500" assert 0 <= mixing_cycles <= 99, "mixing_cycles must be between 0 and 99" - assert ( - 0 <= mixing_position_from_liquid_surface <= 990 - ), "mixing_position_from_liquid_surface must be between 0 and 990" - assert ( - 0 <= surface_following_distance_during_mixing <= 990 - ), "surface_following_distance_during_mixing must be between 0 and 990" + assert 0 <= mixing_position_from_liquid_surface <= 990, ( + "mixing_position_from_liquid_surface must be between 0 and 990" + ) + assert 0 <= surface_following_distance_during_mixing <= 990, ( + "surface_following_distance_during_mixing must be between 0 and 990" + ) assert 3 <= speed_of_mixing <= 5000, "speed_of_mixing must be between 3 and 5000" assert 0 <= limit_curve_index <= 999, "limit_curve_index must be between 0 and 999" assert 0 <= recording_mode <= 2, "recording_mode must be between 0 and 2" @@ -5705,9 +5704,9 @@ async def move_core_96_head_to_defined_position( assert 0 <= x_direction <= 1, "x_direction must be between 0 and 1" assert 1080 <= y_position <= 5600, "y_position must be between 1080 and 5600" assert 0 <= y_position <= 5600, "z_position must be between 0 and 5600" - assert ( - 0 <= minimum_height_at_beginning_of_a_command <= 3425 - ), "minimum_height_at_beginning_of_a_command must be between 0 and 3425" + assert 0 <= minimum_height_at_beginning_of_a_command <= 3425, ( + "minimum_height_at_beginning_of_a_command must be between 0 and 3425" + ) return await self.send_command( module="C0", @@ -6356,9 +6355,9 @@ async def park_iswap( of a command [0.1mm]. Must be between 0 and 3600. Default 3600. """ - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) command_output = await self.send_command( module="C0", @@ -6424,23 +6423,23 @@ async def iswap_get_plate( assert 0 <= z_position <= 3600, "z_position must be between 0 and 3600" assert 0 <= z_direction <= 1, "z_direction must be between 0 and 1" assert 1 <= grip_direction <= 4, "grip_direction must be between 1 and 4" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" - assert ( - 0 <= z_position_at_the_command_end <= 3600 - ), "z_position_at_the_command_end must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) + assert 0 <= z_position_at_the_command_end <= 3600, ( + "z_position_at_the_command_end must be between 0 and 3600" + ) assert 1 <= grip_strength <= 9, "grip_strength must be between 1 and 9" assert 0 <= open_gripper_position <= 9999, "open_gripper_position must be between 0 and 9999" assert 0 <= plate_width <= 9999, "plate_width must be between 0 and 9999" assert 0 <= plate_width_tolerance <= 99, "plate_width_tolerance must be between 0 and 99" assert 0 <= collision_control_level <= 1, "collision_control_level must be between 0 and 1" - assert ( - 0 <= acceleration_index_high_acc <= 4 - ), "acceleration_index_high_acc must be between 0 and 4" - assert ( - 0 <= acceleration_index_low_acc <= 4 - ), "acceleration_index_low_acc must be between 0 and 4" + assert 0 <= acceleration_index_high_acc <= 4, ( + "acceleration_index_high_acc must be between 0 and 4" + ) + assert 0 <= acceleration_index_low_acc <= 4, ( + "acceleration_index_low_acc must be between 0 and 4" + ) command_output = await self.send_command( module="C0", @@ -6515,20 +6514,20 @@ async def iswap_put_plate( assert 0 <= z_position <= 3600, "z_position must be between 0 and 3600" assert 0 <= z_direction <= 1, "z_direction must be between 0 and 1" assert 1 <= grip_direction <= 4, "grip_direction must be between 1 and 4" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" - assert ( - 0 <= z_position_at_the_command_end <= 3600 - ), "z_position_at_the_command_end must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) + assert 0 <= z_position_at_the_command_end <= 3600, ( + "z_position_at_the_command_end must be between 0 and 3600" + ) assert 0 <= open_gripper_position <= 9999, "open_gripper_position must be between 0 and 9999" assert 0 <= collision_control_level <= 1, "collision_control_level must be between 0 and 1" - assert ( - 0 <= acceleration_index_high_acc <= 4 - ), "acceleration_index_high_acc must be between 0 and 4" - assert ( - 0 <= acceleration_index_low_acc <= 4 - ), "acceleration_index_low_acc must be between 0 and 4" + assert 0 <= acceleration_index_high_acc <= 4, ( + "acceleration_index_high_acc must be between 0 and 4" + ) + assert 0 <= acceleration_index_low_acc <= 4, ( + "acceleration_index_low_acc must be between 0 and 4" + ) command_output = await self.send_command( module="C0", @@ -6624,16 +6623,16 @@ async def move_plate_to_position( assert 0 <= z_position <= 3600, "z_position must be between 0 and 3600" assert 0 <= z_direction <= 1, "z_direction must be between 0 and 1" assert 1 <= grip_direction <= 4, "grip_direction must be between 1 and 4" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) assert 0 <= collision_control_level <= 1, "collision_control_level must be between 0 and 1" - assert ( - 0 <= acceleration_index_high_acc <= 4 - ), "acceleration_index_high_acc must be between 0 and 4" - assert ( - 0 <= acceleration_index_low_acc <= 4 - ), "acceleration_index_low_acc must be between 0 and 4" + assert 0 <= acceleration_index_high_acc <= 4, ( + "acceleration_index_high_acc must be between 0 and 4" + ) + assert 0 <= acceleration_index_low_acc <= 4, ( + "acceleration_index_low_acc must be between 0 and 4" + ) command_output = await self.send_command( module="C0", @@ -6667,9 +6666,9 @@ async def collapse_gripper_arm( fold_up_sequence_at_the_end_of_process: fold up sequence at the end of process. Default True. """ - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) return await self.send_command( module="C0", @@ -6733,16 +6732,16 @@ async def prepare_iswap_teaching( assert 0 <= z_direction <= 1, "z_direction must be between 0 and 1" assert 0 <= location <= 1, "location must be between 0 and 1" assert 0 <= hotel_depth <= 3000, "hotel_depth must be between 0 and 3000" - assert ( - 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600 - ), "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + assert 0 <= minimum_traverse_height_at_beginning_of_a_command <= 3600, ( + "minimum_traverse_height_at_beginning_of_a_command must be between 0 and 3600" + ) assert 0 <= collision_control_level <= 1, "collision_control_level must be between 0 and 1" - assert ( - 0 <= acceleration_index_high_acc <= 4 - ), "acceleration_index_high_acc must be between 0 and 4" - assert ( - 0 <= acceleration_index_low_acc <= 4 - ), "acceleration_index_low_acc must be between 0 and 4" + assert 0 <= acceleration_index_high_acc <= 4, ( + "acceleration_index_high_acc must be between 0 and 4" + ) + assert 0 <= acceleration_index_low_acc <= 4, ( + "acceleration_index_low_acc must be between 0 and 4" + ) return await self.send_command( module="C0", @@ -7270,15 +7269,15 @@ async def clld_probe_z_height_using_channel( + f"and {STAR.z_drive_increment_to_mm(15_000)} mm/sec, is {channel_speed} mm/sec" ) assert 5 <= channel_acceleration_thousand_increments <= 150, ( - f"Channel acceleration must be between \n{STAR.z_drive_increment_to_mm(5*1_000)} " - + f" and {STAR.z_drive_increment_to_mm(150*1_000)} mm/sec**2, is {channel_acceleration} mm/sec**2" - ) - assert ( - 0 <= detection_edge <= 1_023 - ), "Edge steepness at capacitive LLD detection must be between 0 and 1023" - assert ( - 0 <= detection_drop <= 1_023 - ), "Offset after capacitive LLD edge detection must be between 0 and 1023" + f"Channel acceleration must be between \n{STAR.z_drive_increment_to_mm(5 * 1_000)} " + + f" and {STAR.z_drive_increment_to_mm(150 * 1_000)} mm/sec**2, is {channel_acceleration} mm/sec**2" + ) + assert 0 <= detection_edge <= 1_023, ( + "Edge steepness at capacitive LLD detection must be between 0 and 1023" + ) + assert 0 <= detection_drop <= 1_023, ( + "Offset after capacitive LLD edge detection must be between 0 and 1023" + ) assert 0 <= post_detection_dist_increments <= 9_999, ( "Post cLLD-detection movement distance must be between \n0" + f" and {STAR.z_drive_increment_to_mm(9_999)} mm, is {post_detection_dist} mm" @@ -7293,7 +7292,7 @@ async def clld_probe_z_height_using_channel( post_detection_dist_str = f"{post_detection_dist_increments:04}" await self.send_command( - module=f"P{channel_idx+1}", + module=f"P{channel_idx + 1}", command="ZL", zh=lowest_immers_pos_str, # Lowest immersion position [increment] zc=start_pos_search_str, # Start position of LLD search [increment] @@ -7449,20 +7448,20 @@ async def ztouch_probe_z_height_using_channel( + f" and {STAR.z_drive_increment_to_mm(15_000)} mm/sec, is {channel_speed} mm/sec" ) assert 5 <= channel_acceleration_thousand_increments <= 150, ( - f"Channel acceleration must be between \n{STAR.z_drive_increment_to_mm(5*1_000)}" - + f" and {STAR.z_drive_increment_to_mm(150*1_000)} mm/sec**2, is {channel_speed} mm/sec**2" + f"Channel acceleration must be between \n{STAR.z_drive_increment_to_mm(5 * 1_000)}" + + f" and {STAR.z_drive_increment_to_mm(150 * 1_000)} mm/sec**2, is {channel_speed} mm/sec**2" ) assert 20 <= channel_speed_upwards_increments <= 15_000, ( f"Channel retraction speed must be between \n{STAR.z_drive_increment_to_mm(20)}" + f" and {STAR.z_drive_increment_to_mm(15_000)} mm/sec, is {channel_speed_upwards} mm/sec" ) - assert ( - 0 <= detection_limiter_in_PWM <= 125 - ), "Detection limiter value must be between 0 and 125 PWM." + assert 0 <= detection_limiter_in_PWM <= 125, ( + "Detection limiter value must be between 0 and 125 PWM." + ) assert 0 <= push_down_force_in_PWM <= 125, "Push down force between 0 and 125 PWM values" - assert ( - 0 <= post_detection_dist <= 245 - ), f"Post detection distance must be between 0 and 245 mm, is {post_detection_dist}" + assert 0 <= post_detection_dist <= 245, ( + f"Post detection distance must be between 0 and 245 mm, is {post_detection_dist}" + ) lowest_immers_pos_str = f"{lowest_immers_pos_increments:05}" start_pos_search_str = f"{start_pos_search_increments:05}" @@ -7473,7 +7472,7 @@ async def ztouch_probe_z_height_using_channel( push_down_force_in_PWM_str = f"{push_down_force_in_PWM:03}" ztouch_probed_z_height = await self.send_command( - module=f"P{channel_idx+1}", + module=f"P{channel_idx + 1}", command="ZH", zb=start_pos_search_str, # begin of searching range [increment] za=lowest_immers_pos_str, # end of searching range [increment] @@ -7537,14 +7536,23 @@ async def get_channels_y_positions(self) -> Dict[int, float]: ) return {channel_idx: round(y / 10, 2) for channel_idx, y in enumerate(resp["ry"])} - async def position_channels_in_y_direction(self, ys: Dict[int, float]): + async def position_channels_in_y_direction_relative( + self, ys: Dict[int, float], yv: Optional[int] = 6000 + ): + positions = await self.get_channels_y_positions() + relative_positions = [positions[i] + ys.get(i, 0) for i in range(len(positions))] + await self.position_channels_in_y_direction(dict(enumerate(relative_positions)), yv=yv) + + async def position_channels_in_y_direction(self, ys: Dict[int, float], yv: Optional[int] = 6000): """position all channels simultaneously in the Y direction. There is a command for this (C0OY), but I couldn't get it to work, so this sends commands to the individual channels instead. Args: ys: A dictionary mapping channel index to the desired Y position in mm. The channel index is 0-indexed from the back. + yv: The maximum velocity of the movement in steps/second. The default is 6000. """ + print("yv", f"{yv:04}") # check that the locations of channels after the move will be at least 9mm apart, and in # descending order @@ -7569,6 +7577,7 @@ def _channel_y_to_steps(y: float) -> int: module=f"P{STAR.channel_id(channel_idx)}", command="YA", ya=f"{_channel_y_to_steps(y):05}", + yv=f"{yv:04}", ) for channel_idx, y in channel_locations.items() ) @@ -7590,7 +7599,7 @@ async def position_channels_in_z_direction(self, zs: Dict[int, float]): channel_locations[channel_idx] = z return await self.send_command( - module="C0", command="JZ", zp=[f"{round(z*10):04}" for z in channel_locations.values()] + module="C0", command="JZ", zp=[f"{round(z * 10):04}" for z in channel_locations.values()] ) diff --git a/pylabrobot/liquid_handling/liquid_handler.py b/pylabrobot/liquid_handling/liquid_handler.py index 6b79ce4555..a447d5357a 100644 --- a/pylabrobot/liquid_handling/liquid_handler.py +++ b/pylabrobot/liquid_handling/liquid_handler.py @@ -53,6 +53,7 @@ does_volume_tracking, ) from pylabrobot.resources.errors import CrossContaminationError, HasTipError +from pylabrobot.resources.filter import Filter from pylabrobot.resources.liquid import Liquid from pylabrobot.tilting.tilter import Tilter @@ -1044,7 +1045,7 @@ async def dispense( for resource in resources: if isinstance(resource.parent, Plate) and resource.parent.has_lid(): - raise ValueError("Dispensing to plate with lid") + raise ValueError("Aspirating from a well with a lid is not supported.") assert len(vols) == len(offsets) == len(flow_rates) == len(liquid_height) @@ -1915,6 +1916,13 @@ async def drop_resource( y=plate_location.y, z=plate_location.z + destination.get_absolute_size_z() - lid.nesting_z_height, ) + elif isinstance(destination, Plate) and isinstance(resource, Filter): + plate_location = destination.get_absolute_location() + to_location = Coordinate( + x=plate_location.x, + y=plate_location.y, + z=plate_location.z + destination.get_size_z() - resource.nesting_z_height, + ) else: to_location = destination.get_absolute_location() @@ -1954,6 +1962,11 @@ async def drop_resource( ) elif isinstance(destination, Plate) and isinstance(resource, Lid): destination.assign_child_resource(resource) + elif isinstance(destination, Plate) and isinstance(resource, Filter): + destination.assign_child_resource( + resource, + location=Coordinate(x=0, y=0, z=destination.get_size_z() - resource.nesting_z_height), + ) else: destination.assign_child_resource(resource, location=to_location) @@ -2243,5 +2256,6 @@ def assign_child_resource( class OperationCallback(Protocol): - def __call__(self, handler: "LiquidHandler", *args: Any, **kwargs: Any) -> None: - ... # pragma: no cover + def __call__( + self, handler: "LiquidHandler", *args: Any, **kwargs: Any + ) -> None: ... # pragma: no cover diff --git a/pylabrobot/resources/filter.py b/pylabrobot/resources/filter.py new file mode 100644 index 0000000000..aef497725c --- /dev/null +++ b/pylabrobot/resources/filter.py @@ -0,0 +1,19 @@ +from typing import Optional +from pylabrobot.resources.resource import Resource + + +class Filter(Resource): + """Filter for plates for use in filtering cells before flow cytometry.""" + + def __init__( + self, + name: str, + size_x: float, + size_y: float, + size_z: float, + category: str = "filter", + model: Optional[str] = None, + ): + super().__init__( + name=name, size_x=size_x, size_y=size_y, size_z=size_z, category=category, model=model + ) diff --git a/pylabrobot/resources/plate.py b/pylabrobot/resources/plate.py index 5cc4d62a26..d9401f33cb 100644 --- a/pylabrobot/resources/plate.py +++ b/pylabrobot/resources/plate.py @@ -12,6 +12,7 @@ cast, ) +from pylabrobot.resources.filter import Filter from pylabrobot.resources.resource_holder import get_child_location from .itemized_resource import ItemizedResource @@ -126,6 +127,10 @@ def assign_child_resource( location: Optional[Coordinate] = None, reassign: bool = True, ): + if isinstance(resource, Filter): + default_location = get_child_location(resource) + self._get_lid_location(resource) + location = location or default_location + return super().assign_child_resource(resource, location=location, reassign=reassign) if isinstance(resource, Lid): if self.has_lid(): raise ValueError(f"Plate '{self.name}' already has a lid.") diff --git a/pylabrobot/resources/retro_filter/__init__.py b/pylabrobot/resources/retro_filter/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/pylabrobot/resources/retro_filter/retro_filter.md b/pylabrobot/resources/retro_filter/retro_filter.md new file mode 100644 index 0000000000..b514d6cfaa --- /dev/null +++ b/pylabrobot/resources/retro_filter/retro_filter.md @@ -0,0 +1,23 @@ +# Retro Filter V4 + + + +Designed for flow cytometry prep. + +## Usage Instructions + +1. Lay **40–80 µm filter cloth** between the upper and lower portions. +2. Snap the filter assembly shut. +3. Lay scissors flush against the top-bottom interface. +4. **Cut the filter cloth close** to the printed parts to avoid any excess that could obstruct robotic handling. +5. The filter is ready for **single-use**. + +> **Tip**: For a reusable filtration assembly, purchase **80 µm steel mesh** from Component Supply. + + +### [OnShape doc](https://cad.onshape.com/documents/c9c3cf6b64034d54f966eda5/w/fed83636389b833df37c2dac/e/80426a2258abe186fc00e172?renderMode=0&uiState=6768d74c1ea3896154236237) + + +

+ RetroBio Logo +

diff --git a/pylabrobot/resources/retro_filter/retro_filter.png b/pylabrobot/resources/retro_filter/retro_filter.png new file mode 100644 index 0000000000..836974dbd6 Binary files /dev/null and b/pylabrobot/resources/retro_filter/retro_filter.png differ diff --git a/pylabrobot/resources/retro_filter/retro_filter.py b/pylabrobot/resources/retro_filter/retro_filter.py new file mode 100644 index 0000000000..ce9832447d --- /dev/null +++ b/pylabrobot/resources/retro_filter/retro_filter.py @@ -0,0 +1,116 @@ +from typing import List, Optional +from pylabrobot.liquid_handling.liquid_handler import LiquidHandler +from pylabrobot.resources.coordinate import Coordinate +from pylabrobot.resources.filter import Filter +from pylabrobot.resources.plate import Plate + + +class RetroFilter(Filter): + filter_dispense_offset = Coordinate( + 0, 0, 9 + ) # height above parent plate to dispense through filter + + def __init__( + self, + name: str, + size_x: float = 129, + size_y: float = 88, + size_z: float = 19.7, + category: str = "filter", + model: Optional[str] = None, + nesting_z_height: float = 2, + ): + self.nesting_z_height = nesting_z_height + super().__init__( + name=name, size_x=size_x, size_y=size_y, size_z=size_z, category=category, model=model + ) + + async def move_filter( + self, + lh: LiquidHandler, + to_dest: Plate, # lh drop_resource only supports filters on Plates (for now) + arm: str = "core", + channel_1=7, + channel_2=8, + **kwargs, + ): + """move filter from CarrierSite to a Plate using core grippers (faster) or iSWAP (slower)""" + + pickup_kwargs = kwargs.copy() + if arm == "core": + pickup_kwargs.update( + {"core_grip_strength": 15, "channel_1": channel_1, "channel_2": channel_2} + ) + await lh.pick_up_resource( + resource=self, use_arm=arm, pickup_distance_from_top=15, **pickup_kwargs + ) + + await lh.drop_resource(destination=to_dest, use_arm=arm, **kwargs) + + async def dispense_through_filter( + self, + indices: List[int], + volumes: List[float], + lh: LiquidHandler, + anticlog_loops: int = 4, + **dispense_kwargs, + ): + if not isinstance(self.parent, Plate): + raise RuntimeError("Filter must be on a Plate.") + + if len(volumes) != len(indices): + raise ValueError("Mismatch in volumes vs. indices.") + + offsets = dispense_kwargs.pop("offsets", Coordinate(0, 0, 0)) + if isinstance(offsets, Coordinate): + offsets = [offsets] * len(indices) + offsets = [offset + self.filter_dispense_offset for offset in offsets] + + wells = [self.parent[i][0] for i in indices] + travel_z = self.parent.get_absolute_location("c", "c", "t").z + 20 + pip_z_at_dsp = [ + well.get_absolute_location().z + offsets[i].z + well.material_z_thickness + for i, well in enumerate(wells) + ] + print("pip_z_at_dsp", pip_z_at_dsp) + overrides = { + "offsets": offsets, + "transport_air_volume": 0, + "settling_time": 5, + "swap_speed": 100, + "pull_out_distance_transport_air": 0, + "minimum_traverse_height_at_beginning_of_a_command": travel_z, + "min_z_endpos": min(pip_z_at_dsp), + } + merged_kwargs = {**dispense_kwargs, **overrides} + + await lh.dispense(resources=wells, vols=volumes, **merged_kwargs) + for i in range(anticlog_loops): + await lh.backend.position_channels_in_y_direction_relative( + ys={ + 7: +2, + 6: +2, + }, + yv=100, + ) + await lh.backend.position_channels_in_y_direction_relative( + ys={ + 7: -4, + 6: -4, + }, + yv=100, + ) + await lh.backend.position_channels_in_y_direction_relative( + ys={ + 7: +2, + 6: +2, + }, + yv=100, + ) + # this movement is choppy, ideally we use dispense on the fly X0 continuous drive movement + for i in range(5): + await lh.backend.move_iswap_x_relative(step_size=0.4, allow_splitting=False) + for i in range(5): + await lh.backend.move_iswap_x_relative(step_size=-0.8, allow_splitting=False) + for i in range(5): + await lh.backend.move_iswap_x_relative(step_size=0.4, allow_splitting=False) diff --git a/pylabrobot/resources/retro_filter/retro_filter_lower.stl b/pylabrobot/resources/retro_filter/retro_filter_lower.stl new file mode 100644 index 0000000000..1231bef333 Binary files /dev/null and b/pylabrobot/resources/retro_filter/retro_filter_lower.stl differ diff --git a/pylabrobot/resources/retro_filter/retro_filter_upper.stl b/pylabrobot/resources/retro_filter/retro_filter_upper.stl new file mode 100644 index 0000000000..72de058012 Binary files /dev/null and b/pylabrobot/resources/retro_filter/retro_filter_upper.stl differ