mirror of
https://github.com/deepmodeling/Uni-Lab-OS
synced 2026-03-24 09:17:39 +00:00
11 KiB
11 KiB
name, description
| name | description |
|---|---|
| add-resource | Guide for adding new resources (materials, bottles, carriers, decks, warehouses) to Uni-Lab-OS (添加新物料/资源). Covers Bottle, Carrier, Deck, WareHouse definitions and registry YAML. Use when the user wants to add resources, define materials, create a deck layout, add bottles/carriers/plates, or mentions 物料/资源/resource/bottle/carrier/deck/plate/warehouse. |
添加新物料资源
Uni-Lab-OS 的资源体系基于 PyLabRobot,通过扩展实现 Bottle、Carrier、WareHouse、Deck 等实验室物料管理。
第一步:确认资源类型
向用户确认需要添加的资源类型:
| 类型 | 基类 | 用途 | 示例 |
|---|---|---|---|
| Bottle | Well (PyLabRobot) |
单个容器(瓶、小瓶、烧杯、反应器) | 试剂瓶、粉末瓶 |
| BottleCarrier | ItemizedCarrier |
多槽位载架(放多个 Bottle) | 6 位试剂架、枪头盒 |
| WareHouse | ItemizedCarrier |
堆栈/仓库(放多个 Carrier) | 4x4 堆栈 |
| Deck | Deck (PyLabRobot) |
工作站台面(放多个 WareHouse) | 反应站 Deck |
层级关系: Deck → WareHouse → BottleCarrier → Bottle
还需确认:
- 资源所属的项目/场景(如 bioyond、battery、通用)
- 尺寸参数(直径、高度、最大容积等)
- 布局参数(行列数、间距等)
第二步:创建资源定义
文件位置
unilabos/resources/
├── <project>/ # 按项目分组
│ ├── bottles.py # Bottle 工厂函数
│ ├── bottle_carriers.py # Carrier 工厂函数
│ ├── warehouses.py # WareHouse 工厂函数
│ └── decks.py # Deck 类定义
├── itemized_carrier.py # Bottle, BottleCarrier, ItemizedCarrier 基类
├── warehouse.py # WareHouse 基类
└── container.py # 通用容器
2A. 添加 Bottle(工厂函数)
from unilabos.resources.itemized_carrier import Bottle
def My_Reagent_Bottle(
name: str,
diameter: float = 70.0, # 瓶体直径 (mm)
height: float = 120.0, # 瓶体高度 (mm)
max_volume: float = 500000.0, # 最大容积 (μL)
barcode: str = None,
) -> Bottle:
"""创建试剂瓶"""
return Bottle(
name=name,
diameter=diameter,
height=height,
max_volume=max_volume,
barcode=barcode,
model="My_Reagent_Bottle", # 唯一标识,用于注册表和物料映射
)
Bottle 参数:
name: 实例名称(运行时唯一)diameter: 瓶体直径 (mm)height: 瓶体高度 (mm)max_volume: 最大容积 (μL,注意单位!500mL = 500000)barcode: 条形码(可选)model: 模型标识,与注册表 key 一致
2B. 添加 BottleCarrier(工厂函数)
from pylabrobot.resources import ResourceHolder
from pylabrobot.resources.carrier import create_ordered_items_2d
from unilabos.resources.itemized_carrier import BottleCarrier
def My_6SlotCarrier(name: str) -> BottleCarrier:
"""创建 3x2 六槽位载架"""
sites = create_ordered_items_2d(
klass=ResourceHolder,
num_items_x=3, # 列数
num_items_y=2, # 行数
dx=10.0, # X 起始偏移
dy=10.0, # Y 起始偏移
dz=5.0, # Z 偏移
item_dx=42.0, # X 间距
item_dy=35.0, # Y 间距
size_x=20.0, # 槽位宽
size_y=20.0, # 槽位深
size_z=50.0, # 槽位高
)
carrier = BottleCarrier(
name=name,
size_x=146.0, # 载架总宽
size_y=80.0, # 载架总深
size_z=55.0, # 载架总高
sites=sites,
model="My_6SlotCarrier",
)
carrier.num_items_x = 3
carrier.num_items_y = 2
carrier.num_items_z = 1
# 预装 Bottle(可选)
ordering = ["A01", "A02", "A03", "B01", "B02", "B03"]
for i in range(6):
carrier[i] = My_Reagent_Bottle(f"{ordering[i]}")
return carrier
2C. 添加 WareHouse(工厂函数)
from unilabos.resources.warehouse import warehouse_factory
def my_warehouse_4x4(name: str) -> "WareHouse":
"""创建 4行x4列 堆栈仓库"""
return warehouse_factory(
name=name,
num_items_x=4, # 列数
num_items_y=4, # 行数
num_items_z=1, # 层数(通常为 1)
dx=137.0, # X 起始偏移
dy=96.0, # Y 起始偏移
dz=120.0, # Z 起始偏移
item_dx=137.0, # X 间距
item_dy=125.0, # Y 间距
item_dz=10.0, # Z 间距(多层时用)
resource_size_x=127.0, # 槽位宽
resource_size_y=85.0, # 槽位深
resource_size_z=100.0, # 槽位高
model="my_warehouse_4x4",
)
warehouse_factory 参数说明:
| 参数 | 说明 |
|---|---|
num_items_x/y/z |
列数/行数/层数 |
dx, dy, dz |
第一个槽位的起始坐标偏移 |
item_dx, item_dy, item_dz |
相邻槽位间距 |
resource_size_x/y/z |
单个槽位的物理尺寸 |
col_offset |
列命名偏移(如设 4 则从 A05 开始) |
row_offset |
行命名偏移(如设 5 则从 F 行开始) |
layout |
排序方式:"col-major"(列优先,默认)/ "row-major"(行优先) |
removed_positions |
要移除的位置索引列表 |
自动生成 ResourceHolder 槽位,命名规则为 A01, B01, C01, D01, A02, ...(列优先)或 A01, A02, A03, A04, B01, ...(行优先)。
2D. 添加 Deck(类定义)
from pylabrobot.resources import Deck, Coordinate
class MyStation_Deck(Deck):
def __init__(
self,
name: str = "MyStation_Deck",
size_x: float = 2700.0,
size_y: float = 1080.0,
size_z: float = 1500.0,
category: str = "deck",
setup: bool = False,
) -> None:
super().__init__(name=name, size_x=size_x, size_y=size_y, size_z=size_z)
if setup:
self.setup()
def setup(self) -> None:
self.warehouses = {
"仓库A": my_warehouse_4x4("仓库A"),
"仓库B": my_warehouse_4x4("仓库B"),
}
self.warehouse_locations = {
"仓库A": Coordinate(-200.0, 400.0, 0.0),
"仓库B": Coordinate(2350.0, 400.0, 0.0),
}
for wh_name, wh in self.warehouses.items():
self.assign_child_resource(wh, location=self.warehouse_locations[wh_name])
Deck 要点:
- 继承
pylabrobot.resources.Deck setup()创建 WareHouse 并通过assign_child_resource放置到指定坐标setup参数控制是否在构造时自动调用setup()(图文件中通过config.setup: true触发)
第三步:创建注册表 YAML
路径:unilabos/registry/resources/<project>/<type>.yaml
Bottle 注册
My_Reagent_Bottle:
category:
- bottles
class:
module: unilabos.resources.my_project.bottles:My_Reagent_Bottle
type: pylabrobot
description: 我的试剂瓶
handles: []
icon: ''
init_param_schema: {}
version: 1.0.0
Carrier 注册
My_6SlotCarrier:
category:
- bottle_carriers
class:
module: unilabos.resources.my_project.bottle_carriers:My_6SlotCarrier
type: pylabrobot
handles: []
icon: ''
init_param_schema: {}
version: 1.0.0
Deck 注册
MyStation_Deck:
category:
- deck
class:
module: unilabos.resources.my_project.decks:MyStation_Deck
type: pylabrobot
description: 我的工作站 Deck
handles: []
icon: ''
init_param_schema: {}
registry_type: resource
version: 1.0.0
注册表规则:
class.module格式为python.module.path:ClassName_or_FunctionNameclass.type固定为pylabrobot- Key(如
My_Reagent_Bottle)必须与工厂函数名 / 类名一致 category按类型标注(bottles,bottle_carriers,deck等)
第四步:在图文件中引用
Deck 在工作站中的引用
工作站节点通过 deck 字段引用,Deck 作为子节点:
{
"id": "my_station",
"children": ["my_deck"],
"deck": {
"data": {
"_resource_child_name": "my_deck",
"_resource_type": "unilabos.resources.my_project.decks:MyStation_Deck"
}
}
},
{
"id": "my_deck",
"parent": "my_station",
"type": "deck",
"class": "MyStation_Deck",
"config": {"type": "MyStation_Deck", "setup": true}
}
物料类型映射(外部系统对接时)
如果工作站需要与外部系统同步物料,在 config 中配置 material_type_mappings:
"material_type_mappings": {
"My_Reagent_Bottle": ["试剂瓶", "external-type-uuid"],
"My_6SlotCarrier": ["六槽载架", "external-type-uuid"]
}
第五步:注册 PLR 扩展(如需要)
如果添加了新的 Deck 类,需要在 unilabos/resources/plr_additional_res_reg.py 中导入,使 find_subclass 能发现它:
def register():
from unilabos.resources.my_project.decks import MyStation_Deck
第六步:验证
# 1. 资源可导入
python -c "from unilabos.resources.my_project.bottles import My_Reagent_Bottle; print(My_Reagent_Bottle('test'))"
# 2. Deck 可创建
python -c "
from unilabos.resources.my_project.decks import MyStation_Deck
d = MyStation_Deck('test', setup=True)
print(d.children)
"
# 3. 启动测试
unilab -g <graph>.json --complete_registry
工作流清单
资源接入进度:
- [ ] 1. 确定资源类型(Bottle / Carrier / WareHouse / Deck)
- [ ] 2. 创建资源定义(工厂函数/类)
- [ ] 3. 创建注册表 YAML (unilabos/registry/resources/<project>/<type>.yaml)
- [ ] 4. 在图文件中引用(如需要)
- [ ] 5. 注册 PLR 扩展(Deck 类需要)
- [ ] 6. 验证
高级模式
实现复杂资源系统时,详见 reference.md:类继承体系完整图、序列化/反序列化流程、Bioyond 物料双向同步、非瓶类资源(ElectrodeSheet / Magazine)、仓库工厂 layout 模式。
现有资源参考
| 项目 | Bottles | Carriers | WareHouses | Decks |
|---|---|---|---|---|
| bioyond | bioyond/bottles.py |
bioyond/bottle_carriers.py |
bioyond/warehouses.py, YB_warehouses.py |
bioyond/decks.py |
| battery | — | battery/bottle_carriers.py |
— | — |
| 通用 | — | — | warehouse.py |
— |
关键路径
| 内容 | 路径 |
|---|---|
| Bottle/Carrier 基类 | unilabos/resources/itemized_carrier.py |
| WareHouse 基类 + 工厂 | unilabos/resources/warehouse.py |
| PLR 注册 | unilabos/resources/plr_additional_res_reg.py |
| 资源注册表 | unilabos/registry/resources/ |
| 图文件加载 | unilabos/resources/graphio.py |
| 资源跟踪器 | unilabos/resources/resource_tracker.py |