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

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 pass
if mix_times is not None: if mix_times is not None:
mix_times = int(mix_times) mix_times = int(mix_times)
# 设置tip racks
self.set_tiprack(tip_racks)
# 识别传输模式mix_times 为 None 也应该能正常移液,只是不做 mix # 识别传输模式mix_times 为 None 也应该能正常移液,只是不做 mix
num_sources = len(sources) num_sources = len(sources)
num_targets = len(targets) num_targets = len(targets)
@@ -1153,9 +1156,15 @@ class LiquidHandlerAbstract(LiquidHandlerMiddleware):
"""一对一传输模式N sources -> N targets""" """一对一传输模式N sources -> N targets"""
# 验证参数长度 # 验证参数长度
if len(asp_vols) != len(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): 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): if len(sources) != len(targets):
raise ValueError(f"Length of `sources` {len(sources)} must match `targets` {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汇总/混合)""" """多对一传输模式N sources -> 1 target汇总/混合)"""
# 验证和扩展体积参数 # 验证和扩展体积参数
if len(asp_vols) != len(sources): 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 为单个值:所有源汇总,使用总吸液体积或指定分液体积 # 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): 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) 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): async def heater_action(self, temperature: float, time: int):
return await self._unilabos_backend.heater_action(temperature, time) return await self._unilabos_backend.heater_action(temperature, time)
async def move_plate( async def move_plate(
@@ -1116,6 +1121,26 @@ class PRCXI9300Backend(LiquidHandlerBackend):
self.steps_todo_list.append(step) self.steps_todo_list.append(step)
return 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): async def pick_up_resource(self, pickup: ResourcePickup, **backend_kwargs):
@@ -1985,6 +2010,27 @@ class PRCXI9300Api:
"AssistFun4": is_wait, "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: class DefaultLayout:
def __init__(self, product_name: str = "PRCXI9300"): def __init__(self, product_name: str = "PRCXI9300"):

View File

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

View File

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