添加切换枪头方法,添加mock振荡与加热方法

This commit is contained in:
zhangshixiang
2025-12-16 11:19:13 +08:00
parent 8ba911bb55
commit 44fc80c70f
3 changed files with 150 additions and 26 deletions

View File

@@ -433,6 +433,12 @@ class PRCXI9300Handler(LiquidHandlerAbstract):
async def move_to(self, well: Well, dis_to_top: float = 0, channel: int = 0): 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) 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): class PRCXI9300Backend(LiquidHandlerBackend):
"""PRCXI 9300 的后端实现,继承自 LiquidHandlerBackend。 """PRCXI 9300 的后端实现,继承自 LiquidHandlerBackend。
@@ -474,6 +480,15 @@ class PRCXI9300Backend(LiquidHandlerBackend):
self._num_channels = channel_num self._num_channels = channel_num
self._execute_setup = setup self._execute_setup = setup
self.debug = debug 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): def post_init(self, ros_node: BaseROS2DeviceNode):
self._ros_node = ros_node 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): async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int] = None):
"""Pick up tips from the specified resource.""" """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 = [] plate_indexes = []
for op in ops: for op in ops:
plate = op.resource.parent plate = op.resource.parent
@@ -585,6 +611,7 @@ class PRCXI9300Backend(LiquidHandlerBackend):
hole_row = tipspot_index % 8 + 1 hole_row = tipspot_index % 8 + 1
step = self.api_client.Load( step = self.api_client.Load(
axis=axis,
dosage=0, dosage=0,
plate_no=PlateNo, plate_no=PlateNo,
is_whole_plate=False, is_whole_plate=False,
@@ -599,13 +626,23 @@ class PRCXI9300Backend(LiquidHandlerBackend):
async def drop_tips(self, ops: List[Drop], use_channels: List[int] = None): async def drop_tips(self, ops: List[Drop], use_channels: List[int] = None):
"""Pick up tips from the specified resource.""" """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 # # 检查trash #
if ops[0].resource.name == "trash": if ops[0].resource.name == "trash":
PlateNo = ops[0].resource.parent.children.index(ops[0].resource) + 1 PlateNo = ops[0].resource.parent.children.index(ops[0].resource) + 1
step = self.api_client.UnLoad( step = self.api_client.UnLoad(
axis=axis,
dosage=0, dosage=0,
plate_no=PlateNo, plate_no=PlateNo,
is_whole_plate=False, is_whole_plate=False,
@@ -648,6 +685,7 @@ class PRCXI9300Backend(LiquidHandlerBackend):
hole_row = tipspot_index % 8 + 1 hole_row = tipspot_index % 8 + 1
step = self.api_client.UnLoad( step = self.api_client.UnLoad(
axis=axis,
dosage=0, dosage=0,
plate_no=PlateNo, plate_no=PlateNo,
is_whole_plate=False, is_whole_plate=False,
@@ -714,7 +752,16 @@ class PRCXI9300Backend(LiquidHandlerBackend):
async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None): async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None):
"""Aspirate liquid from the specified resources.""" """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 = [] plate_indexes = []
for op in ops: for op in ops:
plate = op.resource.parent plate = op.resource.parent
@@ -747,6 +794,7 @@ class PRCXI9300Backend(LiquidHandlerBackend):
hole_row = tipspot_index % 8 + 1 hole_row = tipspot_index % 8 + 1
step = self.api_client.Imbibing( step = self.api_client.Imbibing(
axis=axis,
dosage=int(volumes[0]), dosage=int(volumes[0]),
plate_no=PlateNo, plate_no=PlateNo,
is_whole_plate=False, is_whole_plate=False,
@@ -761,7 +809,16 @@ class PRCXI9300Backend(LiquidHandlerBackend):
async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None): async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None):
"""Dispense liquid into the specified resources.""" """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 = [] plate_indexes = []
for op in ops: for op in ops:
plate = op.resource.parent plate = op.resource.parent
@@ -795,6 +852,7 @@ class PRCXI9300Backend(LiquidHandlerBackend):
hole_row = tipspot_index % 8 + 1 hole_row = tipspot_index % 8 + 1
step = self.api_client.Tapping( step = self.api_client.Tapping(
axis=axis,
dosage=int(volumes[0]), dosage=int(volumes[0]),
plate_no=PlateNo, plate_no=PlateNo,
is_whole_plate=False, is_whole_plate=False,
@@ -1000,9 +1058,10 @@ class PRCXI9300Api:
assist_fun4: str = "", assist_fun4: str = "",
assist_fun5: str = "", assist_fun5: str = "",
liquid_method: str = "NormalDispense", liquid_method: str = "NormalDispense",
axis: str = "Left",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
return { return {
"StepAxis": self.axis, "StepAxis": axis,
"Function": "Load", "Function": "Load",
"DosageNum": dosage, "DosageNum": dosage,
"PlateNo": plate_no, "PlateNo": plate_no,
@@ -1038,9 +1097,10 @@ class PRCXI9300Api:
assist_fun4: str = "", assist_fun4: str = "",
assist_fun5: str = "", assist_fun5: str = "",
liquid_method: str = "NormalDispense", liquid_method: str = "NormalDispense",
axis: str = "Left",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
return { return {
"StepAxis": self.axis, "StepAxis": axis,
"Function": "Imbibing", "Function": "Imbibing",
"DosageNum": dosage, "DosageNum": dosage,
"PlateNo": plate_no, "PlateNo": plate_no,
@@ -1076,9 +1136,10 @@ class PRCXI9300Api:
assist_fun4: str = "", assist_fun4: str = "",
assist_fun5: str = "", assist_fun5: str = "",
liquid_method: str = "NormalDispense", liquid_method: str = "NormalDispense",
axis: str = "Left",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
return { return {
"StepAxis": self.axis, "StepAxis": axis,
"Function": "Tapping", "Function": "Tapping",
"DosageNum": dosage, "DosageNum": dosage,
"PlateNo": plate_no, "PlateNo": plate_no,
@@ -1114,9 +1175,10 @@ class PRCXI9300Api:
assist_fun4: str = "", assist_fun4: str = "",
assist_fun5: str = "", assist_fun5: str = "",
liquid_method: str = "NormalDispense", liquid_method: str = "NormalDispense",
axis: str = "Left",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
return { return {
"StepAxis": self.axis, "StepAxis": axis,
"Function": "Blending", "Function": "Blending",
"DosageNum": dosage, "DosageNum": dosage,
"PlateNo": plate_no, "PlateNo": plate_no,
@@ -1152,9 +1214,10 @@ class PRCXI9300Api:
assist_fun4: str = "", assist_fun4: str = "",
assist_fun5: str = "", assist_fun5: str = "",
liquid_method: str = "NormalDispense", liquid_method: str = "NormalDispense",
axis: str = "Left",
) -> Dict[str, Any]: ) -> Dict[str, Any]:
return { return {
"StepAxis": self.axis, "StepAxis": axis,
"Function": "UnLoad", "Function": "UnLoad",
"DosageNum": dosage, "DosageNum": dosage,
"PlateNo": plate_no, "PlateNo": plate_no,

View File

@@ -4500,6 +4500,9 @@ liquid_handler:
simulator: simulator:
default: false default: false
type: boolean type: boolean
total_height:
default: 310
type: number
required: required:
- backend - backend
- deck - deck
@@ -7553,6 +7556,35 @@ liquid_handler.prcxi:
title: custom_delay参数 title: custom_delay参数
type: object type: object
type: UniLabJsonCommandAsync 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: auto-iter_tips:
feedback: {} feedback: {}
goal: {} goal: {}
@@ -7694,6 +7726,35 @@ liquid_handler.prcxi:
title: set_group参数 title: set_group参数
type: object type: object
type: UniLabJsonCommand 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: auto-touch_tip:
feedback: {} feedback: {}
goal: {} goal: {}

View File

@@ -21,7 +21,7 @@
"_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck", "_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck",
"_resource_child_name": "PRCXI_Deck" "_resource_child_name": "PRCXI_Deck"
}, },
"host": "192.168.1.201", "host": "10.20.30.184",
"port": 9999, "port": 9999,
"debug": false, "debug": false,
"setup": true, "setup": true,
@@ -29,7 +29,7 @@
"timeout": 10, "timeout": 10,
"matrix_id": "5de524d0-3f95-406c-86dd-f83626ebc7cb", "matrix_id": "5de524d0-3f95-406c-86dd-f83626ebc7cb",
"simulator": false, "simulator": false,
"channel_num": 1 "channel_num": 2
}, },
"data": { "data": {
"reset_ok": true "reset_ok": true
@@ -9964,8 +9964,8 @@
}, },
{ {
"id": "container_for_nothing3", "id": "emptyT3",
"name": "container_for_nothing3", "name": "emptyT3",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",
@@ -9996,8 +9996,8 @@
}, },
{ {
"id": "container_for_nothing4", "id": "emptyT4",
"name": "container_for_nothing4", "name": "emptyT4",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",
@@ -19806,8 +19806,8 @@
}, },
{ {
"id": "container_for_nothing7", "id": "emptyT7",
"name": "container_for_nothing7", "name": "emptyT7",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",
@@ -19837,8 +19837,8 @@
"data": {} "data": {}
}, },
{ {
"id": "container_for_nothing8", "id": "emptyT8",
"name": "container_for_nothing8", "name": "emptyT8",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",
@@ -28015,8 +28015,8 @@
}, },
{ {
"id": "container_for_nothing11", "id": "emptyT11",
"name": "container_for_nothing11", "name": "emptyT11",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",
@@ -28046,8 +28046,8 @@
"data": {} "data": {}
}, },
{ {
"id": "container_for_nothing12", "id": "emptyT12",
"name": "container_for_nothing12", "name": "emptyT12",
"children": [], "children": [],
"parent": "PRCXI_Deck", "parent": "PRCXI_Deck",