From 3f160c204958c129eda52dbde519cec057831feb Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:40:02 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E6=9B=B4=E6=96=B0prcxi=20deck=20&=20?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=20unilabos=5Fresource=5Fslot?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- unilabos/devices/liquid_handling/prcxi/prcxi.py | 10 +++++----- unilabos/registry/registry.py | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/unilabos/devices/liquid_handling/prcxi/prcxi.py b/unilabos/devices/liquid_handling/prcxi/prcxi.py index c07a6de2..f34583fe 100644 --- a/unilabos/devices/liquid_handling/prcxi/prcxi.py +++ b/unilabos/devices/liquid_handling/prcxi/prcxi.py @@ -93,13 +93,13 @@ class PRCXI9300Deck(Deck): # T1-T16 默认位置 (4列×4行) _DEFAULT_SITE_POSITIONS = [ - (0, 288, 0), (138, 288, 0), (276, 288, 0), (414, 288, 0), # T1-T4 - (0, 192, 0), (138, 192, 0), (276, 192, 0), (414, 192, 0), # T5-T8 - (0, 96, 0), (138, 96, 0), (276, 96, 0), (414, 96, 0), # T9-T12 - (0, 0, 0), (138, 0, 0), (276, 0, 0), (414, 0, 0), # T13-T16 + (0, 0, 0), (138, 0, 0), (276, 0, 0), (414, 0, 0), # T1-T4 + (0, 96, 0), (138, 96, 0), (276, 96, 0), (414, 96, 0), # T5-T8 + (0, 192, 0), (138, 192, 0), (276, 192, 0), (414, 192, 0), # T9-T12 + (0, 288, 0), (138, 288, 0), (276, 288, 0), (414, 288, 0), # T13-T16 ] _DEFAULT_SITE_SIZE = {"width": 128.0, "height": 86, "depth": 0} - _DEFAULT_CONTENT_TYPE = ["plate", "tip_rack", "plates", "tip_racks", "tube_rack"] + _DEFAULT_CONTENT_TYPE = ["plate", "tip_rack", "plates", "tip_racks", "tube_rack", "adaptor"] def __init__(self, name: str, size_x: float, size_y: float, size_z: float, sites: Optional[List[Dict[str, Any]]] = None, **kwargs): diff --git a/unilabos/registry/registry.py b/unilabos/registry/registry.py index 844d4cf8..02d80cca 100644 --- a/unilabos/registry/registry.py +++ b/unilabos/registry/registry.py @@ -175,7 +175,8 @@ class Registry: "res_id": "unilabos_resources", # 将当前实验室的全部物料id作为下拉框可选择 "device_id": "unilabos_devices", # 将当前实验室的全部设备id作为下拉框可选择 "parent": "unilabos_nodes", # 将当前实验室的设备/物料作为下拉框可选择 - "class_name": "unilabos_class", + "class_name": "unilabos_class", # 当前实验室物料的class name + "slot_on_deck": "unilabos_resource_slot:parent", # 勾选的parent的config中的sites的name,展示name,参数对应slot(index) }, }, "test_latency": { From 7f1cc3b2a5ffe3750124f0bbba253df4598bc326 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 3 Mar 2026 11:43:41 +0800 Subject: [PATCH 2/4] update materials --- .../test/experiments/prcxi_9320_slim.json | 438 +++++++++--------- 1 file changed, 227 insertions(+), 211 deletions(-) diff --git a/unilabos/test/experiments/prcxi_9320_slim.json b/unilabos/test/experiments/prcxi_9320_slim.json index a3be4506..e97aa3d9 100644 --- a/unilabos/test/experiments/prcxi_9320_slim.json +++ b/unilabos/test/experiments/prcxi_9320_slim.json @@ -74,7 +74,7 @@ "occupied_by": null, "position": { "x": 0, - "y": 288, + "y": 0, "z": 0 }, "size": { @@ -87,7 +87,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -96,7 +97,7 @@ "occupied_by": null, "position": { "x": 138, - "y": 288, + "y": 0, "z": 0 }, "size": { @@ -109,7 +110,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -118,7 +120,7 @@ "occupied_by": null, "position": { "x": 276, - "y": 288, + "y": 0, "z": 0 }, "size": { @@ -131,7 +133,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -140,6 +143,213 @@ "occupied_by": null, "position": { "x": 414, + "y": 0, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T5", + "visible": true, + "occupied_by": null, + "position": { + "x": 0, + "y": 96, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T6", + "visible": true, + "occupied_by": null, + "position": { + "x": 138, + "y": 96, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T7", + "visible": true, + "occupied_by": null, + "position": { + "x": 276, + "y": 96, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T8", + "visible": true, + "occupied_by": null, + "position": { + "x": 414, + "y": 96, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T9", + "visible": true, + "occupied_by": null, + "position": { + "x": 0, + "y": 192, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T10", + "visible": true, + "occupied_by": null, + "position": { + "x": 138, + "y": 192, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T11", + "visible": true, + "occupied_by": null, + "position": { + "x": 276, + "y": 192, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T12", + "visible": true, + "occupied_by": null, + "position": { + "x": 414, + "y": 192, + "z": 0 + }, + "size": { + "width": 128.0, + "height": 86, + "depth": 0 + }, + "content_type": [ + "plate", + "tip_rack", + "plates", + "tip_racks", + "tube_rack", + "adaptor" + ] + }, + { + "label": "T13", + "visible": true, + "occupied_by": null, + "position": { + "x": 0, "y": 288, "z": 0 }, @@ -153,205 +363,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" - ] - }, - { - "label": "T5", - "visible": true, - "occupied_by": null, - "position": { - "x": 0, - "y": 192, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T6", - "visible": true, - "occupied_by": null, - "position": { - "x": 138, - "y": 192, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T7", - "visible": true, - "occupied_by": null, - "position": { - "x": 276, - "y": 192, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T8", - "visible": true, - "occupied_by": null, - "position": { - "x": 414, - "y": 192, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T9", - "visible": true, - "occupied_by": null, - "position": { - "x": 0, - "y": 96, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T10", - "visible": true, - "occupied_by": null, - "position": { - "x": 138, - "y": 96, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T11", - "visible": true, - "occupied_by": null, - "position": { - "x": 276, - "y": 96, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T12", - "visible": true, - "occupied_by": null, - "position": { - "x": 414, - "y": 96, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" - ] - }, - { - "label": "T13", - "visible": true, - "occupied_by": null, - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "size": { - "width": 128.0, - "height": 86, - "depth": 0 - }, - "content_type": [ - "plate", - "tip_rack", - "plates", - "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -360,7 +373,7 @@ "occupied_by": null, "position": { "x": 138, - "y": 0, + "y": 288, "z": 0 }, "size": { @@ -373,7 +386,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -382,7 +396,7 @@ "occupied_by": null, "position": { "x": 276, - "y": 0, + "y": 288, "z": 0 }, "size": { @@ -395,7 +409,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] }, { @@ -404,7 +419,7 @@ "occupied_by": null, "position": { "x": 414, - "y": 0, + "y": 288, "z": 0 }, "size": { @@ -417,7 +432,8 @@ "tip_rack", "plates", "tip_racks", - "tube_rack" + "tube_rack", + "adaptor" ] } ] From b40c08714305927ce150fe325e47d73eac473ba5 Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 3 Mar 2026 17:13:32 +0800 Subject: [PATCH 3/4] fix container volume --- unilabos/app/main.py | 3 ++- unilabos/resources/container.py | 11 +++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/unilabos/app/main.py b/unilabos/app/main.py index c652757c..93751262 100644 --- a/unilabos/app/main.py +++ b/unilabos/app/main.py @@ -1,6 +1,7 @@ import argparse import asyncio import os +import platform import shutil import signal import sys @@ -358,7 +359,7 @@ def main(): if BasicConfig.test_mode: print_status("启用测试模式:所有动作将模拟执行,不调用真实硬件", "warning") BasicConfig.communication_protocol = "websocket" - machine_name = os.popen("hostname").read().strip() + machine_name = platform.node() machine_name = "".join([c if c.isalnum() or c == "_" else "_" for c in machine_name]) BasicConfig.machine_name = machine_name BasicConfig.vis_2d_enable = args_dict["2d_vis"] diff --git a/unilabos/resources/container.py b/unilabos/resources/container.py index fe19bacf..ed3871d3 100644 --- a/unilabos/resources/container.py +++ b/unilabos/resources/container.py @@ -1,10 +1,6 @@ -import json from typing import Dict, Any from pylabrobot.resources import Container -from unilabos_msgs.msg import Resource - -from unilabos.ros.msgs.message_converter import convert_from_ros_msg class RegularContainer(Container): @@ -16,12 +12,12 @@ class RegularContainer(Container): kwargs["size_y"] = 0 if "size_z" not in kwargs: kwargs["size_z"] = 0 + self.kwargs = kwargs - self.state = {} super().__init__(*args, category="container", **kwargs) def load_state(self, state: Dict[str, Any]): - self.state = state + super().load_state(state) def get_regular_container(name="container"): @@ -29,7 +25,6 @@ def get_regular_container(name="container"): r.category = "container" return r -# # class RegularContainer(object): # # 第一个参数必须是id传入 # # noinspection PyShadowingBuiltins @@ -89,4 +84,4 @@ def get_regular_container(name="container"): # return to_dict # # def __str__(self): -# return f"{self.id}" \ No newline at end of file +# return f"{self.id}" From 5c047beb83b0ab849deab73c424d2b61c2054dde Mon Sep 17 00:00:00 2001 From: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Date: Tue, 3 Mar 2026 18:03:53 +0800 Subject: [PATCH 4/4] support container as example add z index (cherry picked from commit 145fcaae65c6e729570c2a0507d1a0f6a43252ce) --- unilabos/resources/resource_tracker.py | 12 ++++++++++++ unilabos/test/experiments/prcxi_9320_slim.json | 1 + 2 files changed, 13 insertions(+) diff --git a/unilabos/resources/resource_tracker.py b/unilabos/resources/resource_tracker.py index a3e3d3f2..8ade8e1f 100644 --- a/unilabos/resources/resource_tracker.py +++ b/unilabos/resources/resource_tracker.py @@ -16,6 +16,7 @@ if TYPE_CHECKING: EXTRA_CLASS = "unilabos_resource_class" +FRONTEND_POSE_EXTRA = "unilabos_frontend_pose_extra" EXTRA_SAMPLE_UUID = "sample_uuid" EXTRA_UNILABOS_SAMPLE_UUID = "unilabos_sample_uuid" @@ -74,6 +75,14 @@ class ResourceDictPositionObject(BaseModel): z: float = Field(description="Z coordinate", default=0.0) +class ResourceDictPoseExtraObjectType(BaseModel): + z_index: int + + +class ResourceDictPoseExtraObject(BaseModel): + z_index: Optional[int] = Field(alias="zIndex", default=None) + + class ResourceDictPositionType(TypedDict): size: ResourceDictPositionSizeType scale: ResourceDictPositionScaleType @@ -100,6 +109,7 @@ class ResourceDictPosition(BaseModel): cross_section_type: Literal["rectangle", "circle", "rounded_rectangle"] = Field( description="Cross section type", default="rectangle" ) + extra: Optional[ResourceDictPoseExtraObject] = Field(description="Extra data", default=None) class ResourceDictType(TypedDict): @@ -463,6 +473,7 @@ class ResourceTreeSet(object): "position3d": raw_pos, "rotation": d["rotation"], "cross_section_type": d.get("cross_section_type", "rectangle"), + "extra": extra.get(FRONTEND_POSE_EXTRA) } # 先构建当前节点的字典(不包含children) @@ -548,6 +559,7 @@ class ResourceTreeSet(object): name_to_uuid[node.res_content.name] = node.res_content.uuid all_states[node.res_content.name] = node.res_content.data name_to_extra[node.res_content.name] = node.res_content.extra + name_to_extra[node.res_content.name][FRONTEND_POSE_EXTRA] = node.res_content.pose.extra name_to_extra[node.res_content.name][EXTRA_CLASS] = node.res_content.klass for child in node.children: collect_node_data(child, name_to_uuid, all_states, name_to_extra) diff --git a/unilabos/test/experiments/prcxi_9320_slim.json b/unilabos/test/experiments/prcxi_9320_slim.json index e97aa3d9..2aaee6a7 100644 --- a/unilabos/test/experiments/prcxi_9320_slim.json +++ b/unilabos/test/experiments/prcxi_9320_slim.json @@ -83,6 +83,7 @@ "depth": 0 }, "content_type": [ + "container", "plate", "tip_rack", "plates",