Merge pull request #206 from ALITTLELZ/prcxi9320

Fix startup json for 9320
This commit is contained in:
q434343
2025-12-25 16:50:25 +08:00
committed by GitHub
2 changed files with 158 additions and 28 deletions

View File

@@ -1,10 +1,12 @@
import asyncio import asyncio
import collections import collections
from collections import OrderedDict
import contextlib import contextlib
import json import json
import os import os
import socket import socket
import time import time
import uuid
from typing import Any, List, Dict, Optional, Tuple, TypedDict, Union, Sequence, Iterator, Literal from typing import Any, List, Dict, Optional, Tuple, TypedDict, Union, Sequence, Iterator, Literal
from pylabrobot.liquid_handling.standard import GripDirection from pylabrobot.liquid_handling.standard import GripDirection
@@ -28,7 +30,7 @@ from pylabrobot.liquid_handling.standard import (
ResourceMove, ResourceMove,
ResourceDrop, ResourceDrop,
) )
from pylabrobot.resources import ResourceHolder, ResourceStack, Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash from pylabrobot.resources import ResourceHolder, ResourceStack, Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash, PlateAdapter, TubeRack
from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract, SimpleReturn from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract, SimpleReturn
from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode
@@ -69,7 +71,35 @@ class PRCXI9300Deck(Deck):
def __init__(self, name: str, size_x: float, size_y: float, size_z: float, **kwargs): def __init__(self, name: str, size_x: float, size_y: float, size_z: float, **kwargs):
super().__init__(name, size_x, size_y, size_z) super().__init__(name, size_x, size_y, size_z)
self.slots = [None] * 6 # PRCXI 9300 有 6 个槽位 self.slots = [None] * 6 # PRCXI 9300 有 6 个槽位
class PRCXI9300Container(Plate):
"""PRCXI 9300 的专用 Container 类,继承自 Plate用于槽位定位和未知模块。
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
"""
def __init__(
self,
name: str,
size_x: float,
size_y: float,
size_z: float,
category: str,
ordering: collections.OrderedDict,
model: Optional[str] = None,
**kwargs,
):
super().__init__(name, size_x, size_y, size_z, category=category, ordering=ordering, model=model)
self._unilabos_state = {}
def load_state(self, state: Dict[str, Any]) -> None:
"""从给定的状态加载工作台信息。"""
super().load_state(state)
self._unilabos_state = state
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
data = super().serialize_state()
data.update(self._unilabos_state)
return data
class PRCXI9300Plate(Plate): class PRCXI9300Plate(Plate):
""" """
专用孔板类: 专用孔板类:
@@ -83,11 +113,43 @@ class PRCXI9300Plate(Plate):
model: Optional[str] = None, model: Optional[str] = None,
material_info: Optional[Dict[str, Any]] = None, material_info: Optional[Dict[str, Any]] = None,
**kwargs): **kwargs):
items = ordered_items if ordered_items is not None else ordering # 如果 ordered_items 不为 None直接使用
super().__init__(name, size_x, size_y, size_z, if ordered_items is not None:
ordered_items=items, items = ordered_items
category=category, elif ordering is not None:
model=model, **kwargs) # 检查 ordering 中的值是否是字符串(从 JSON 反序列化时的情况)
# 如果是字符串,说明这是位置名称,需要让 Plate 自己创建 Well 对象
# 我们只传递位置信息(键),不传递值,使用 ordering 参数
if ordering and isinstance(next(iter(ordering.values()), None), str):
# ordering 的值是字符串,只使用键(位置信息)创建新的 OrderedDict
# 传递 ordering 参数而不是 ordered_items让 Plate 自己创建 Well 对象
items = None
# 使用 ordering 参数,只包含位置信息(键)
ordering_param = collections.OrderedDict((k, None) for k in ordering.keys())
else:
# ordering 的值已经是对象,可以直接使用
items = ordering
ordering_param = None
else:
items = None
ordering_param = None
# 根据情况传递不同的参数
if items is not None:
super().__init__(name, size_x, size_y, size_z,
ordered_items=items,
category=category,
model=model, **kwargs)
elif ordering_param is not None:
# 传递 ordering 参数,让 Plate 自己创建 Well 对象
super().__init__(name, size_x, size_y, size_z,
ordering=ordering_param,
category=category,
model=model, **kwargs)
else:
super().__init__(name, size_x, size_y, size_z,
category=category,
model=model, **kwargs)
self._unilabos_state = {} self._unilabos_state = {}
if material_info: if material_info:
@@ -124,8 +186,7 @@ class PRCXI9300Plate(Plate):
safe_state[k] = v safe_state[k] = v
data.update(safe_state) data.update(safe_state)
return data return data # 其他顶层属性也进行类型检查
class PRCXI9300TipRack(TipRack): class PRCXI9300TipRack(TipRack):
""" 专用吸头盒类 """ """ 专用吸头盒类 """
def __init__(self, name: str, size_x: float, size_y: float, size_z: float, def __init__(self, name: str, size_x: float, size_y: float, size_z: float,
@@ -135,11 +196,43 @@ class PRCXI9300TipRack(TipRack):
model: Optional[str] = None, model: Optional[str] = None,
material_info: Optional[Dict[str, Any]] = None, material_info: Optional[Dict[str, Any]] = None,
**kwargs): **kwargs):
items = ordered_items if ordered_items is not None else ordering # 如果 ordered_items 不为 None直接使用
super().__init__(name, size_x, size_y, size_z, if ordered_items is not None:
ordered_items=items, items = ordered_items
category=category, elif ordering is not None:
model=model, **kwargs) # 检查 ordering 中的值是否是字符串(从 JSON 反序列化时的情况)
# 如果是字符串,说明这是位置名称,需要让 TipRack 自己创建 Tip 对象
# 我们只传递位置信息(键),不传递值,使用 ordering 参数
if ordering and isinstance(next(iter(ordering.values()), None), str):
# ordering 的值是字符串,只使用键(位置信息)创建新的 OrderedDict
# 传递 ordering 参数而不是 ordered_items让 TipRack 自己创建 Tip 对象
items = None
# 使用 ordering 参数,只包含位置信息(键)
ordering_param = collections.OrderedDict((k, None) for k in ordering.keys())
else:
# ordering 的值已经是对象,可以直接使用
items = ordering
ordering_param = None
else:
items = None
ordering_param = None
# 根据情况传递不同的参数
if items is not None:
super().__init__(name, size_x, size_y, size_z,
ordered_items=items,
category=category,
model=model, **kwargs)
elif ordering_param is not None:
# 传递 ordering 参数,让 TipRack 自己创建 Tip 对象
super().__init__(name, size_x, size_y, size_z,
ordering=ordering_param,
category=category,
model=model, **kwargs)
else:
super().__init__(name, size_x, size_y, size_z,
category=category,
model=model, **kwargs)
self._unilabos_state = {} self._unilabos_state = {}
if material_info: if material_info:
self._unilabos_state["Material"] = material_info self._unilabos_state["Material"] = material_info
@@ -235,16 +328,53 @@ class PRCXI9300TubeRack(TubeRack):
category: str = "tube_rack", category: str = "tube_rack",
items: Optional[Dict[str, Any]] = None, items: Optional[Dict[str, Any]] = None,
ordered_items: Optional[OrderedDict] = None, ordered_items: Optional[OrderedDict] = None,
ordering: Optional[OrderedDict] = None,
model: Optional[str] = None, model: Optional[str] = None,
material_info: Optional[Dict[str, Any]] = None, material_info: Optional[Dict[str, Any]] = None,
**kwargs): **kwargs):
# 兼容处理PLR 的 TubeRack 构造函数可能接受 items 或 ordered_items # 如果 ordered_items 不为 None直接使用
items_to_pass = items if items is not None else ordered_items if ordered_items is not None:
super().__init__(name, size_x, size_y, size_z, items_to_pass = ordered_items
ordered_items=ordered_items, ordering_param = None
model=model, elif ordering is not None:
**kwargs) # 检查 ordering 中的值是否是字符串(从 JSON 反序列化时的情况)
# 如果是字符串,说明这是位置名称,需要让 TubeRack 自己创建 Tube 对象
# 我们只传递位置信息(键),不传递值,使用 ordering 参数
if ordering and isinstance(next(iter(ordering.values()), None), str):
# ordering 的值是字符串,只使用键(位置信息)创建新的 OrderedDict
# 传递 ordering 参数而不是 ordered_items让 TubeRack 自己创建 Tube 对象
items_to_pass = None
# 使用 ordering 参数,只包含位置信息(键)
ordering_param = collections.OrderedDict((k, None) for k in ordering.keys())
else:
# ordering 的值已经是对象,可以直接使用
items_to_pass = ordering
ordering_param = None
elif items is not None:
# 兼容旧的 items 参数
items_to_pass = items
ordering_param = None
else:
items_to_pass = None
ordering_param = None
# 根据情况传递不同的参数
if items_to_pass is not None:
super().__init__(name, size_x, size_y, size_z,
ordered_items=items_to_pass,
model=model,
**kwargs)
elif ordering_param is not None:
# 传递 ordering 参数,让 TubeRack 自己创建 Tube 对象
super().__init__(name, size_x, size_y, size_z,
ordering=ordering_param,
model=model,
**kwargs)
else:
super().__init__(name, size_x, size_y, size_z,
model=model,
**kwargs)
self._unilabos_state = {} self._unilabos_state = {}
if material_info: if material_info:

View File

@@ -812,7 +812,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300TipRack",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -6515,7 +6515,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -10587,7 +10587,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300TipRack",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -16291,7 +16291,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -20365,7 +20365,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -24438,7 +24438,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -28512,7 +28512,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -32585,7 +32585,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,
@@ -36658,7 +36658,7 @@
"z": 0 "z": 0
}, },
"config": { "config": {
"type": "PRCXI9300Container", "type": "PRCXI9300Plate",
"size_x": 127, "size_x": 127,
"size_y": 85.5, "size_y": 85.5,
"size_z": 10, "size_z": 10,