添加加热震荡模块与磁力模块

This commit is contained in:
q434343
2026-02-04 15:28:23 +08:00
parent aeeb36d075
commit 11a38d4558
4 changed files with 290 additions and 74 deletions

View File

@@ -1090,7 +1090,10 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
pass
if mix_times is not None:
mix_times = int(mix_times)
# 设置tip racks
self.set_tiprack(tip_racks)
# 识别传输模式mix_times 为 None 也应该能正常移液,只是不做 mix
num_sources = len(sources)
num_targets = len(targets)
@@ -1153,9 +1156,15 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
"""一对一传输模式N sources -> N targets"""
# 验证参数长度
if len(asp_vols) != len(targets):
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `targets` {len(targets)}.")
if len(asp_vols) == 1:
asp_vols = [asp_vols[0]] * len(targets)
else:
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `targets` {len(targets)}.")
if len(dis_vols) != len(targets):
raise ValueError(f"Length of `dis_vols` {len(dis_vols)} must match `targets` {len(targets)}.")
if len(dis_vols) == 1:
dis_vols = [dis_vols[0]] * len(targets)
else:
raise ValueError(f"Length of `dis_vols` {len(dis_vols)} must match `targets` {len(targets)}.")
if len(sources) != len(targets):
raise ValueError(f"Length of `sources` {len(sources)} must match `targets` {len(targets)}.")
@@ -1495,7 +1504,10 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
"""多对一传输模式N sources -> 1 target汇总/混合)"""
# 验证和扩展体积参数
if len(asp_vols) != len(sources):
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `sources` {len(sources)}.")
if len(asp_vols) == 1:
asp_vols = [asp_vols[0]] * len(sources)
else:
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `sources` {len(sources)}.")
# 支持两种模式:
# 1. dis_vols 为单个值:所有源汇总,使用总吸液体积或指定分液体积

View File

@@ -1011,6 +1011,11 @@ class PRCXI9300Handler(LiquidHandlerAbstract):
async def shaker_action(self, time: int, module_no: int, amplitude: int, is_wait: bool):
return await self._unilabos_backend.shaker_action(time, module_no, amplitude, is_wait)
async def magnetic_action(self, time: int, module_no: int, height: int, is_wait: bool):
return await self._unilabos_backend.magnetic_action(time, module_no, height, is_wait)
async def shaking_incubation_action(self, time: int, module_no: int, amplitude: int, is_wait: bool, temperature: int):
return await self._unilabos_backend.shaking_incubation_action(time, module_no, amplitude, is_wait, temperature)
async def heater_action(self, temperature: float, time: int):
return await self._unilabos_backend.heater_action(temperature, time)
async def move_plate(
@@ -1116,6 +1121,26 @@ class PRCXI9300Backend(LiquidHandlerBackend):
self.steps_todo_list.append(step)
return step
async def shaking_incubation_action(self, time: int, module_no: int, amplitude: int, is_wait: bool, temperature: int):
step = self.api_client.shaking_incubation_action(
time=time,
module_no=module_no,
amplitude=amplitude,
is_wait=is_wait,
temperature=temperature,
)
self.steps_todo_list.append(step)
return step
async def magnetic_action(self, time: int, module_no: int, height: int, is_wait: bool):
step = self.api_client.magnetic_action(
time=time,
module_no=module_no,
height=height,
is_wait=is_wait,
)
self.steps_todo_list.append(step)
return step
async def pick_up_resource(self, pickup: ResourcePickup, **backend_kwargs):
@@ -1985,6 +2010,27 @@ class PRCXI9300Api:
"AssistFun4": is_wait,
}
def shaking_incubation_action(self, time: int, module_no: int, amplitude: int, is_wait: bool, temperature: int):
return {
"StepAxis": "Left",
"Function": "Shaking_Incubation",
"AssistFun1": time,
"AssistFun2": module_no,
"AssistFun3": amplitude,
"AssistFun4": is_wait,
"AssistFun5": temperature,
}
def magnetic_action(self, time: int, module_no: int, height: int, is_wait: bool):
return {
"StepAxis": "Left",
"Function": "Magnetic",
"AssistFun1": time,
"AssistFun2": module_no,
"AssistFun3": height,
"AssistFun4": is_wait,
}
class DefaultLayout:
def __init__(self, product_name: str = "PRCXI9300"):

View File

@@ -4019,8 +4019,7 @@ liquid_handler:
mix_liquid_height: 0.0
mix_rate: 0
mix_stage: ''
mix_times:
- 0
mix_times: 0
mix_vol: 0
none_keys:
- ''
@@ -4094,29 +4093,29 @@ liquid_handler:
- 0
handles:
input:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources
label: sources
- data_key: liquid
data_source: executor
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets
label: targets
- data_key: liquid
data_source: executor
- data_key: tip_racks
data_source: handle
data_type: resource
handler_key: tip_rack
label: tip_rack
handler_key: tip_racks
label: tip_racks
output:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources_out
label: sources
- data_key: liquid
data_source: executor
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets_out
label: targets
@@ -4176,11 +4175,9 @@ liquid_handler:
mix_stage:
type: string
mix_times:
items:
maximum: 2147483647
minimum: -2147483648
type: integer
type: array
maximum: 2147483647
minimum: -2147483648
type: integer
mix_vol:
maximum: 2147483647
minimum: -2147483648
@@ -4767,13 +4764,13 @@ liquid_handler.biomek:
targets: ''
handles:
input:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources
label: sources
output:
- data_key: liquid
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets
@@ -4926,29 +4923,29 @@ liquid_handler.biomek:
volume: 0.0
handles:
input:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources
label: sources
- data_key: liquid
data_source: executor
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets
label: targets
- data_key: liquid
data_source: executor
- data_key: tip_racks
data_source: handle
data_type: resource
handler_key: tip_rack
label: tip_rack
handler_key: tip_racks
label: tip_racks
output:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources_out
label: sources
- data_key: liquid
data_source: executor
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets_out
label: targets
@@ -5043,8 +5040,7 @@ liquid_handler.biomek:
mix_liquid_height: 0.0
mix_rate: 0
mix_stage: ''
mix_times:
- 0
mix_times: 0
mix_vol: 0
none_keys:
- ''
@@ -5118,19 +5114,32 @@ liquid_handler.biomek:
- 0
handles:
input:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: liquid-input
io_type: target
label: Liquid Input
output:
- data_key: liquid
data_source: executor
handler_key: sources
label: sources
- data_key: targets
data_source: handle
data_type: resource
handler_key: liquid-output
io_type: source
label: Liquid Output
handler_key: targets
label: targets
- data_key: tip_racks
data_source: handle
data_type: resource
handler_key: tip_racks
label: tip_racks
output:
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources_out
label: sources
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets_out
label: targets
placeholder_keys:
sources: unilabos_resources
targets: unilabos_resources
@@ -5187,11 +5196,9 @@ liquid_handler.biomek:
mix_stage:
type: string
mix_times:
items:
maximum: 2147483647
minimum: -2147483648
type: integer
type: array
maximum: 2147483647
minimum: -2147483648
type: integer
mix_vol:
maximum: 2147483647
minimum: -2147483648
@@ -7610,6 +7617,43 @@ liquid_handler.prcxi:
title: iter_tips参数
type: object
type: UniLabJsonCommand
auto-magnetic_action:
feedback: {}
goal: {}
goal_default:
height: null
is_wait: null
module_no: null
time: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
height:
type: integer
is_wait:
type: boolean
module_no:
type: integer
time:
type: integer
required:
- time
- module_no
- height
- is_wait
type: object
result: {}
required:
- goal
title: magnetic_action参数
type: object
type: UniLabJsonCommandAsync
auto-move_to:
feedback: {}
goal: {}
@@ -7643,6 +7687,31 @@ liquid_handler.prcxi:
title: move_to参数
type: object
type: UniLabJsonCommandAsync
auto-plr_pos_to_prcxi:
feedback: {}
goal: {}
goal_default:
resource: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
resource:
type: object
required:
- resource
type: object
result: {}
required:
- goal
title: plr_pos_to_prcxi参数
type: object
type: UniLabJsonCommand
auto-post_init:
feedback: {}
goal: {}
@@ -7763,6 +7832,47 @@ liquid_handler.prcxi:
title: shaker_action参数
type: object
type: UniLabJsonCommandAsync
auto-shaking_incubation_action:
feedback: {}
goal: {}
goal_default:
amplitude: null
is_wait: null
module_no: null
temperature: null
time: null
handles: {}
placeholder_keys: {}
result: {}
schema:
description: ''
properties:
feedback: {}
goal:
properties:
amplitude:
type: integer
is_wait:
type: boolean
module_no:
type: integer
temperature:
type: integer
time:
type: integer
required:
- time
- module_no
- amplitude
- is_wait
- temperature
type: object
result: {}
required:
- goal
title: shaking_incubation_action参数
type: object
type: UniLabJsonCommandAsync
auto-touch_tip:
feedback: {}
goal: {}
@@ -8497,7 +8607,19 @@ liquid_handler.prcxi:
z: 0.0
sample_id: ''
type: ''
handles: {}
handles:
input:
- data_key: plate
data_source: handle
data_type: resource
handler_key: plate
label: plate
output:
- data_key: plate
data_source: handle
data_type: resource
handler_key: plate
label: plate
placeholder_keys:
plate: unilabos_resources
to: unilabos_resources
@@ -9677,8 +9799,7 @@ liquid_handler.prcxi:
mix_liquid_height: 0.0
mix_rate: 0
mix_stage: ''
mix_times:
- 0
mix_times: 0
mix_vol: 0
none_keys:
- ''
@@ -9755,26 +9876,26 @@ liquid_handler.prcxi:
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources_identifier
label: 待移动液体
handler_key: sources
label: sources
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets_identifier
label: 转移目标
- data_key: tip_rack
handler_key: targets
label: targets
- data_key: tip_racks
data_source: handle
data_type: resource
handler_key: tip_rack_identifier
label: 墙头盒
handler_key: tip_racks
label: tip_racks
output:
- data_key: liquid
- data_key: sources
data_source: handle
data_type: resource
handler_key: sources_out
label: sources
- data_key: liquid
data_source: executor
- data_key: targets
data_source: handle
data_type: resource
handler_key: targets_out
label: targets
@@ -9834,11 +9955,9 @@ liquid_handler.prcxi:
mix_stage:
type: string
mix_times:
items:
maximum: 2147483647
minimum: -2147483648
type: integer
type: array
maximum: 2147483647
minimum: -2147483648
type: integer
mix_vol:
maximum: 2147483647
minimum: -2147483648
@@ -10160,6 +10279,12 @@ liquid_handler.prcxi:
type: string
deck:
type: object
deck_y:
default: 400
type: string
deck_z:
default: 300
type: string
host:
type: string
is_9320:
@@ -10170,17 +10295,44 @@ liquid_handler.prcxi:
type: string
port:
type: integer
rail_interval:
default: 0
type: string
rail_nums:
default: 4
type: string
rail_width:
default: 27.5
type: string
setup:
default: true
type: string
simulator:
default: false
type: string
start_rail:
default: 2
type: string
step_mode:
default: false
type: string
timeout:
type: number
x_increase:
default: -0.003636
type: string
x_offset:
default: -0.8
type: string
xy_coupling:
default: -0.0045
type: string
y_increase:
default: -0.003636
type: string
y_offset:
default: -37.98
type: string
required:
- deck
- host

View File

@@ -1,3 +1,4 @@
from ast import Try
import inspect
import io
import json
@@ -1341,12 +1342,17 @@ class BaseROS2DeviceNode(Node, Generic[T]):
uuids = [item[1] for item in uuid_indices]
resource_tree = await self.get_resource(uuids)
plr_resources = resource_tree.to_plr_resources()
for i, (idx, _, resource_data) in enumerate(uuid_indices):
plr_resource = plr_resources[i]
if "sample_id" in resource_data:
plr_resource.unilabos_extra["sample_uuid"] = resource_data["sample_id"]
queried_resources[idx] = plr_resource
# 通过uuid查找对应的plr_resource
tracker = self.resource_tracker
for idx, uuid, resource_data in uuid_indices:
try:
plr_resource = tracker.loop_find_with_uuid(plr_resources, uuid)
if "sample_id" in resource_data:
plr_resource.unilabos_extra["sample_uuid"] = resource_data["sample_id"]
queried_resources[idx] = plr_resource
except Exception as e:
self.lab_logger().error(f"资源查询失败: {e}\n{traceback.format_exc()}")
continue
self.lab_logger().debug(f"资源查询结果: 共 {len(queried_resources)} 个资源")
# 通过资源跟踪器获取本地实例