diff --git a/unilabos/devices/liquid_handling/prcxi/prcxi.py b/unilabos/devices/liquid_handling/prcxi/prcxi.py index 3d99941..4625055 100644 --- a/unilabos/devices/liquid_handling/prcxi/prcxi.py +++ b/unilabos/devices/liquid_handling/prcxi/prcxi.py @@ -433,6 +433,12 @@ class PRCXI9300Handler(LiquidHandlerAbstract): async def move_to(self, well: Well, dis_to_top: float = 0, channel: int = 0): return await super().move_to(well, dis_to_top, channel) + async def shaker_action(self, time: int, frequency: float): + return await self._unilabos_backend.shaker_action(time, frequency) + + async def heater_action(self, temperature: float, time: int): + return await self._unilabos_backend.heater_action(temperature, time) + class PRCXI9300Backend(LiquidHandlerBackend): """PRCXI 9300 的后端实现,继承自 LiquidHandlerBackend。 @@ -474,6 +480,15 @@ class PRCXI9300Backend(LiquidHandlerBackend): self._num_channels = channel_num self._execute_setup = setup self.debug = debug + self.axis = "Left" + + async def shaker_action(self, time: int, frequency: float): + print(f"\n\nShaker action: time={time}, frequency={frequency}\n\n") + # return await self.api_client.shaker_action(time, frequency) + + async def heater_action(self, temperature: float, time: int): + print(f"\n\nHeater action: temperature={temperature}, time={time}\n\n") + # return await self.api_client.heater_action(temperature, time) def post_init(self, ros_node: BaseROS2DeviceNode): self._ros_node = ros_node @@ -555,7 +570,18 @@ class PRCXI9300Backend(LiquidHandlerBackend): async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int] = None): """Pick up tips from the specified resource.""" - + # INSERT_YOUR_CODE + # Ensure use_channels is converted to a list of ints if it's an array + if hasattr(use_channels, 'tolist'): + _use_channels = use_channels.tolist() + else: + _use_channels = list(use_channels) if use_channels is not None else None + if _use_channels == [0]: + axis = "Left" + elif _use_channels == [1]: + axis = "Right" + else: + raise ValueError("Invalid use channels: " + str(_use_channels)) plate_indexes = [] for op in ops: plate = op.resource.parent @@ -585,6 +611,7 @@ class PRCXI9300Backend(LiquidHandlerBackend): hole_row = tipspot_index % 8 + 1 step = self.api_client.Load( + axis=axis, dosage=0, plate_no=PlateNo, is_whole_plate=False, @@ -599,13 +626,23 @@ class PRCXI9300Backend(LiquidHandlerBackend): async def drop_tips(self, ops: List[Drop], use_channels: List[int] = None): """Pick up tips from the specified resource.""" - + if hasattr(use_channels, 'tolist'): + _use_channels = use_channels.tolist() + else: + _use_channels = list(use_channels) if use_channels is not None else None + if _use_channels == [0]: + axis = "Left" + elif _use_channels == [1]: + axis = "Right" + else: + raise ValueError("Invalid use channels: " + str(_use_channels)) # 检查trash # if ops[0].resource.name == "trash": PlateNo = ops[0].resource.parent.children.index(ops[0].resource) + 1 step = self.api_client.UnLoad( + axis=axis, dosage=0, plate_no=PlateNo, is_whole_plate=False, @@ -648,6 +685,7 @@ class PRCXI9300Backend(LiquidHandlerBackend): hole_row = tipspot_index % 8 + 1 step = self.api_client.UnLoad( + axis=axis, dosage=0, plate_no=PlateNo, is_whole_plate=False, @@ -671,7 +709,7 @@ class PRCXI9300Backend(LiquidHandlerBackend): none_keys: List[str] = [], ): """Mix liquid in the specified resources.""" - + plate_indexes = [] for op in targets: deck = op.parent.parent @@ -714,7 +752,16 @@ class PRCXI9300Backend(LiquidHandlerBackend): async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None): """Aspirate liquid from the specified resources.""" - + if hasattr(use_channels, 'tolist'): + _use_channels = use_channels.tolist() + else: + _use_channels = list(use_channels) if use_channels is not None else None + if _use_channels == [0]: + axis = "Left" + elif _use_channels == [1]: + axis = "Right" + else: + raise ValueError("Invalid use channels: " + str(_use_channels)) plate_indexes = [] for op in ops: plate = op.resource.parent @@ -747,6 +794,7 @@ class PRCXI9300Backend(LiquidHandlerBackend): hole_row = tipspot_index % 8 + 1 step = self.api_client.Imbibing( + axis=axis, dosage=int(volumes[0]), plate_no=PlateNo, is_whole_plate=False, @@ -761,7 +809,16 @@ class PRCXI9300Backend(LiquidHandlerBackend): async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None): """Dispense liquid into the specified resources.""" - + if hasattr(use_channels, 'tolist'): + _use_channels = use_channels.tolist() + else: + _use_channels = list(use_channels) if use_channels is not None else None + if _use_channels == [0]: + axis = "Left" + elif _use_channels == [1]: + axis = "Right" + else: + raise ValueError("Invalid use channels: " + str(_use_channels)) plate_indexes = [] for op in ops: plate = op.resource.parent @@ -795,6 +852,7 @@ class PRCXI9300Backend(LiquidHandlerBackend): hole_row = tipspot_index % 8 + 1 step = self.api_client.Tapping( + axis=axis, dosage=int(volumes[0]), plate_no=PlateNo, is_whole_plate=False, @@ -1000,9 +1058,10 @@ class PRCXI9300Api: assist_fun4: str = "", assist_fun5: str = "", liquid_method: str = "NormalDispense", + axis: str = "Left", ) -> Dict[str, Any]: return { - "StepAxis": self.axis, + "StepAxis": axis, "Function": "Load", "DosageNum": dosage, "PlateNo": plate_no, @@ -1038,9 +1097,10 @@ class PRCXI9300Api: assist_fun4: str = "", assist_fun5: str = "", liquid_method: str = "NormalDispense", - ) -> Dict[str, Any]: + axis: str = "Left", + ) -> Dict[str, Any]: return { - "StepAxis": self.axis, + "StepAxis": axis, "Function": "Imbibing", "DosageNum": dosage, "PlateNo": plate_no, @@ -1076,9 +1136,10 @@ class PRCXI9300Api: assist_fun4: str = "", assist_fun5: str = "", liquid_method: str = "NormalDispense", + axis: str = "Left", ) -> Dict[str, Any]: return { - "StepAxis": self.axis, + "StepAxis": axis, "Function": "Tapping", "DosageNum": dosage, "PlateNo": plate_no, @@ -1114,9 +1175,10 @@ class PRCXI9300Api: assist_fun4: str = "", assist_fun5: str = "", liquid_method: str = "NormalDispense", - ) -> Dict[str, Any]: + axis: str = "Left", + ) -> Dict[str, Any]: return { - "StepAxis": self.axis, + "StepAxis": axis, "Function": "Blending", "DosageNum": dosage, "PlateNo": plate_no, @@ -1152,9 +1214,10 @@ class PRCXI9300Api: assist_fun4: str = "", assist_fun5: str = "", liquid_method: str = "NormalDispense", + axis: str = "Left", ) -> Dict[str, Any]: return { - "StepAxis": self.axis, + "StepAxis": axis, "Function": "UnLoad", "DosageNum": dosage, "PlateNo": plate_no, diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml index a7dbc1d..33c30a7 100644 --- a/unilabos/registry/devices/liquid_handler.yaml +++ b/unilabos/registry/devices/liquid_handler.yaml @@ -4500,6 +4500,9 @@ liquid_handler: simulator: default: false type: boolean + total_height: + default: 310 + type: number required: - backend - deck @@ -7553,6 +7556,35 @@ liquid_handler.prcxi: title: custom_delay参数 type: object type: UniLabJsonCommandAsync + auto-heater_action: + feedback: {} + goal: {} + goal_default: + temperature: null + time: null + handles: {} + placeholder_keys: {} + result: {} + schema: + description: '' + properties: + feedback: {} + goal: + properties: + temperature: + type: number + time: + type: integer + required: + - temperature + - time + type: object + result: {} + required: + - goal + title: heater_action参数 + type: object + type: UniLabJsonCommandAsync auto-iter_tips: feedback: {} goal: {} @@ -7694,6 +7726,35 @@ liquid_handler.prcxi: title: set_group参数 type: object type: UniLabJsonCommand + auto-shaker_action: + feedback: {} + goal: {} + goal_default: + frequency: null + time: null + handles: {} + placeholder_keys: {} + result: {} + schema: + description: '' + properties: + feedback: {} + goal: + properties: + frequency: + type: number + time: + type: integer + required: + - time + - frequency + type: object + result: {} + required: + - goal + title: shaker_action参数 + type: object + type: UniLabJsonCommandAsync auto-touch_tip: feedback: {} goal: {} diff --git a/unilabos/test/experiments/prcxi_9320_with_res.json b/unilabos/test/experiments/prcxi_9320_with_res.json index a925f60..4804da2 100644 --- a/unilabos/test/experiments/prcxi_9320_with_res.json +++ b/unilabos/test/experiments/prcxi_9320_with_res.json @@ -21,7 +21,7 @@ "_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck", "_resource_child_name": "PRCXI_Deck" }, - "host": "192.168.1.201", + "host": "10.20.30.184", "port": 9999, "debug": false, "setup": true, @@ -29,7 +29,7 @@ "timeout": 10, "matrix_id": "5de524d0-3f95-406c-86dd-f83626ebc7cb", "simulator": false, - "channel_num": 1 + "channel_num": 2 }, "data": { "reset_ok": true @@ -9964,8 +9964,8 @@ }, { - "id": "container_for_nothing3", - "name": "container_for_nothing3", + "id": "emptyT3", + "name": "emptyT3", "children": [], "parent": "PRCXI_Deck", @@ -9996,8 +9996,8 @@ }, { - "id": "container_for_nothing4", - "name": "container_for_nothing4", + "id": "emptyT4", + "name": "emptyT4", "children": [], "parent": "PRCXI_Deck", @@ -19806,8 +19806,8 @@ }, { - "id": "container_for_nothing7", - "name": "container_for_nothing7", + "id": "emptyT7", + "name": "emptyT7", "children": [], "parent": "PRCXI_Deck", @@ -19837,8 +19837,8 @@ "data": {} }, { - "id": "container_for_nothing8", - "name": "container_for_nothing8", + "id": "emptyT8", + "name": "emptyT8", "children": [], "parent": "PRCXI_Deck", @@ -28015,8 +28015,8 @@ }, { - "id": "container_for_nothing11", - "name": "container_for_nothing11", + "id": "emptyT11", + "name": "emptyT11", "children": [], "parent": "PRCXI_Deck", @@ -28046,8 +28046,8 @@ "data": {} }, { - "id": "container_for_nothing12", - "name": "container_for_nothing12", + "id": "emptyT12", + "name": "emptyT12", "children": [], "parent": "PRCXI_Deck",