Files
Uni-Lab-OS/unilabos/resources/bioyond/README_WAREHOUSE.md
Xuwznln 4c8022ee95 Workstation yb merge dev ready 260113 (#216)
* feat(bioyond): 添加计算实验设计功能,支持化合物配比和滴定比例参数

* feat(bioyond): 添加测量小瓶功能,支持基本参数配置

* feat(bioyond): 添加测量小瓶配置,支持新设备参数

* feat(bioyond): 更新仓库布局和尺寸,支持竖向排列的测量小瓶和试剂存放堆栈

* feat(bioyond): 优化任务创建流程,确保无论成功与否都清理任务队列以避免重复累积

* feat(bioyond): 添加设置反应器温度功能,支持温度范围和异常处理

* feat(bioyond): 调整反应器位置配置,统一坐标格式

* feat(bioyond): 添加调度器启动功能,支持任务队列执行并处理异常

* feat(bioyond): 优化调度器启动功能,添加异常处理并更新相关配置

* feat(opcua): 增强节点ID解析兼容性和数据类型处理

改进节点ID解析逻辑以支持多种格式,包括字符串和数字标识符
添加数据类型转换处理,确保写入值时类型匹配
优化错误提示信息,便于调试节点连接问题

* feat(registry): 新增后处理站的设备配置文件

添加后处理站的YAML配置文件,包含动作映射、状态类型和设备描述

* 添加调度器启动功能,合并物料参数配置,优化物料参数处理逻辑

* 添加从 Bioyond 系统自动同步工作流序列的功能,并更新相关配置

* fix:兼容 BioyondReactionStation 中 workflow_sequence 被重写为 property

* fix:同步工作流序列

* feat: remove commented workflow synchronization from `reaction_station.py`.

* 添加时间约束功能及相关配置

* fix:自动更新物料缓存功能,添加物料时更新缓存并在删除时移除缓存项

* fix:在添加物料时处理字符串和字典返回值,确保正确更新缓存

* fix:更新奔曜错误处理报送为物料变更报送,调整日志记录和响应消息

* feat:添加实验报告简化功能,去除冗余信息并保留关键信息

* feat: 添加任务状态事件发布功能,监控并报告任务运行、超时、完成和错误状态

* fix: 修复添加物料时数据格式错误

* Refactor bioyond_dispensing_station and reaction_station_bioyond YAML configurations

- Removed redundant action value mappings from bioyond_dispensing_station.
- Updated goal properties in bioyond_dispensing_station to use enums for target_stack and other parameters.
- Changed data types for end_point and start_point in reaction_station_bioyond to use string enums (Start, End).
- Simplified descriptions and updated measurement units from μL to mL where applicable.
- Removed unused commands from reaction_station_bioyond to streamline the configuration.

* fix:Change the material unit from μL to mL

* fix:refresh_material_cache

* feat: 动态获取工作流步骤ID,优化工作流配置

* feat: 添加清空服务端所有非核心工作流功能

* fix:修复Bottle类的序列化和反序列化方法

* feat:增强材料缓存更新逻辑,支持处理返回数据中的详细信息

* Add debug log

* feat(workstation): update bioyond config migration and coin cell material search logic

- Migrate bioyond_cell config to JSON structure and remove global variable dependencies
- Implement material search confirmation dialog auto-handling
- Add documentation: 20260113_物料搜寻确认弹窗自动处理功能.md and 20260113_配置迁移修改总结.md

* Refactor module paths for Bioyond devices in YAML configuration files

- Updated the module path for BioyondDispensingStation in bioyond_dispensing_station.yaml to reflect the new directory structure.
- Updated the module path for BioyondReactionStation and BioyondReactor in reaction_station_bioyond.yaml to align with the revised organization of the codebase.

* fix: WareHouse 的不可哈希类型错误,优化父节点去重逻辑

* refactor: Move config from module to instance initialization

* fix: 修正 reaction_station 目录名拼写错误

* feat: Integrate material search logic and cleanup deprecated files

- Update coin_cell_assembly.py with material search dialog handling
- Update YB_warehouses.py with latest warehouse configurations
- Remove outdated documentation and test data files

* Refactor: Use instance attributes for action names and workflow step IDs

* refactor: Split tipbox storage into left and right warehouses

* refactor: Merge tipbox storage left and right into single warehouse

---------

Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
Co-authored-by: Andy6M <xieqiming1132@qq.com>
2026-01-17 15:44:18 +08:00

17 KiB
Raw Blame History

Bioyond 仓库系统开发指南

本文档详细说明 Bioyond 仓库Warehouse系统的架构、配置和使用方法帮助开发者快速理解和维护仓库相关代码。

📚 目录


系统架构

Bioyond 仓库系统采用三层架构,实现从前端显示到后端 API 的完整映射:

┌─────────────────────────────────────────────────────────┐
│  前端显示层 (YB_warehouses.py)                          │
│  - warehouse_factory 自动生成库位网格                   │
│  - 生成库位名称A01, B02, C03...                       │
│  - 存储在 WareHouse.sites 字典中                        │
└────────────────┬────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────────────────┐
│  Deck 布局层 (decks.py)                                 │
│  - 定义仓库在 Deck 上的物理位置                         │
│  - 组织多个仓库形成完整布局                             │
└────────────────┬────────────────────────────────────────┘
                 │
                 ▼
┌─────────────────────────────────────────────────────────┐
│  UUID 映射层 (config.py)                                │
│  - 将库位名称映射到 Bioyond 系统 UUID                   │
│  - 用于 API 调用时的物料入库操作                        │
└─────────────────────────────────────────────────────────┘

核心概念

仓库Warehouse

仓库是一个三维网格,用于存放物料。由以下参数定义:

  • num_items_x: 列数X 轴)
  • num_items_y: 行数Y 轴)
  • num_items_z: 层数Z 轴)

例如:5行×3列×1层 = 5×3×1 = 15个库位

库位Site

库位是仓库中的单个存储位置,由字母行+数字列命名:

  • 字母行A, B, C, D, E, F...(对应 Y 轴)
  • 数字列01, 02, 03, 04...(对应 X 轴或 Z 轴)

示例:A01, B02, C03

布局模式Layout

控制库位的排序和 Y 坐标计算:

模式 说明 生成顺序 Y 坐标计算 显示效果
col-major 列优先(默认) A01, B01, C01, A02... dy + (num_y - row - 1) * item_dy A 可能在下
row-major 行优先 A01, A02, A03, B01... dy + row * item_dy A 在上

重要: 使用 row-major 可以避免上下颠倒问题!


三层映射关系

示例手动传递窗右A01-E03

1 前端显示层 - YB_warehouses.py

def bioyond_warehouse_5x3x1(name: str, row_offset: int = 0) -> WareHouse:
    """创建 5行×3列×1层 仓库"""
    return warehouse_factory(
        name=name,
        num_items_x=3,      # 3列
        num_items_y=5,      # 5行
        num_items_z=1,      # 1层
        row_offset=row_offset,
        layout="row-major",
    )

自动生成的库位: A01, A02, A03, B01, B02, B03, ..., E01, E02, E03

2 Deck 布局层 - decks.py

self.warehouses = {
    "手动传递窗右": bioyond_warehouse_5x3x1("手动传递窗右", row_offset=0),
}
self.warehouse_locations = {
    "手动传递窗右": Coordinate(4160.0, 877.0, 0.0),
}

作用:

  • 创建仓库实例
  • 设置在 Deck 上的物理坐标

3 UUID 映射层 - config.py

WAREHOUSE_MAPPING = {
    "手动传递窗右": {
        "uuid": "",
        "site_uuids": {
            "A01": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",
            "A02": "3a19deae-2c7a-dc6d-c41e-ef285d946cfe",
            # ... 其他库位
        }
    }
}

作用:

  • 用户拖拽物料到"手动传递窗右"的"A01"位置时
  • 系统查找 WAREHOUSE_MAPPING["手动传递窗右"]["site_uuids"]["A01"]
  • 获取 UUID "3a19deae-2c7a-36f5-5e41-02c5b66feaea"
  • 调用 Bioyond API 将物料入库到该 UUID 位置

实际配置案例

案例:手动传递窗左/右的完整配置

本案例展示如何为"手动传递窗右"和"手动传递窗左"建立完整的三层映射。

背景需求

  • 手动传递窗右: 需要 A01-E035行×3列=15个库位
  • 手动传递窗左: 需要 F01-J035行×3列=15个库位
  • 这两个仓库共享同一个物理堆栈的 UUID"手动堆栈"

实施步骤

1 修复前端布局 - YB_warehouses.py

# 创建新的 5×3×1 仓库函数(之前是错误的 1×3×3
def bioyond_warehouse_5x3x1(name: str, row_offset: int = 0) -> WareHouse:
    """创建5行×3列×1层仓库支持行偏移生成不同字母行"""
    return warehouse_factory(
        name=name,
        num_items_x=3,      # 3列
        num_items_y=5,      # 5行  ← 修正
        num_items_z=1,      # 1层  ← 修正
        row_offset=row_offset,  # ← 支持 F-J 行
        layout="row-major",     # ← 避免上下颠倒
    )

2 更新 Deck 配置 - decks.py

from unilabos.resources.bioyond.YB_warehouses import (
    bioyond_warehouse_5x3x1,  # 新增导入
)

class BIOYOND_YB_Deck(Deck):
    def setup(self) -> None:
        self.warehouses = {
            # 修改前: bioyond_warehouse_1x3x3 (错误尺寸)
            # 修改后: bioyond_warehouse_5x3x1 (正确尺寸)
            "手动传递窗右": bioyond_warehouse_5x3x1("手动传递窗右", row_offset=0),  # A01-E03
            "手动传递窗左": bioyond_warehouse_5x3x1("手动传递窗左", row_offset=5),  # F01-J03
        }

3 添加 UUID 映射 - config.py

WAREHOUSE_MAPPING = {
    # 保持原有的"手动堆栈"配置不变A01-J03共30个库位
    "手动堆栈": {
        "uuid": "",
        "site_uuids": {
            "A01": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",
            # ... A02-E03 共15个
            "F01": "3a19deae-2c7a-d594-fd6a-0d20de3c7c4a",
            # ... F02-J03 共15个
        }
    },
    
    # [新增] 手动传递窗右 - 复用"手动堆栈"的 A01-E03 UUID
    "手动传递窗右": {
        "uuid": "",
        "site_uuids": {
            "A01": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",  # ← 与手动堆栈A01相同
            "A02": "3a19deae-2c7a-dc6d-c41e-ef285d946cfe",
            "A03": "3a19deae-2c7a-5876-c454-6b7e224ca927",
            "B01": "3a19deae-2c7a-2426-6d71-e9de3cb158b1",
            "B02": "3a19deae-2c7a-79b0-5e44-efaafd1e4cf3",
            "B03": "3a19deae-2c7a-b9eb-f4e3-e308e0cf839a",
            "C01": "3a19deae-2c7a-32bc-768e-556647e292f3",
            "C02": "3a19deae-2c7a-e97a-8484-f5a4599447c4",
            "C03": "3a19deae-2c7a-3056-6504-10dc73fbc276",
            "D01": "3a19deae-2c7a-ffad-875e-8c4cda61d440",
            "D02": "3a19deae-2c7a-61be-601c-b6fb5610499a",
            "D03": "3a19deae-2c7a-c0f7-05a7-e3fe2491e560",
            "E01": "3a19deae-2c7a-a6f4-edd1-b436a7576363",
            "E02": "3a19deae-2c7a-4367-96dd-1ca2186f4910",
            "E03": "3a19deae-2c7a-b163-2219-23df15200311",
        }
    },
    
    # [新增] 手动传递窗左 - 复用"手动堆栈"的 F01-J03 UUID
    "手动传递窗左": {
        "uuid": "",
        "site_uuids": {
            "F01": "3a19deae-2c7a-d594-fd6a-0d20de3c7c4a",  # ← 与手动堆栈F01相同
            "F02": "3a19deae-2c7a-a194-ea63-8b342b8d8679",
            "F03": "3a19deae-2c7a-f7c4-12bd-425799425698",
            "G01": "3a19deae-2c7a-0b56-72f1-8ab86e53b955",
            "G02": "3a19deae-2c7a-204e-95ed-1f1950f28343",
            "G03": "3a19deae-2c7a-392b-62f1-4907c66343f8",
            "H01": "3a19deae-2c7a-5602-e876-d27aca4e3201",
            "H02": "3a19deae-2c7a-f15c-70e0-25b58a8c9702",
            "H03": "3a19deae-2c7a-780b-8965-2e1345f7e834",
            "I01": "3a19deae-2c7a-8849-e172-07de14ede928",
            "I02": "3a19deae-2c7a-4772-a37f-ff99270bafc0",
            "I03": "3a19deae-2c7a-cce7-6e4a-25ea4a2068c4",
            "J01": "3a19deae-2c7a-1848-de92-b5d5ed054cc6",
            "J02": "3a19deae-2c7a-1d45-b4f8-6f866530e205",
            "J03": "3a19deae-2c7a-f237-89d9-8fe19025dee9"
        }
    },
}

关键要点

  1. UUID 可以复用: 三个仓库(手动堆栈、手动传递窗右、手动传递窗左)可以共享相同的物理库位 UUID
  2. 库位名称必须匹配: 前端生成的库位名称(如 F01必须与 config.py 中的键名完全一致
  3. row_offset 的妙用:
    • row_offset=0 → 生成 A-E 行
    • row_offset=5 → 生成 F-J 行跳过前5个字母

验证结果

配置完成后,拖拽测试:

拖拽位置 前端库位 查找路径 UUID 结果
手动传递窗右/A01 A01 WAREHOUSE_MAPPING["手动传递窗右"]["site_uuids"]["A01"] 3a19...eaea 正确入库
手动传递窗左/F01 F01 WAREHOUSE_MAPPING["手动传递窗左"]["site_uuids"]["F01"] 3a19...c4a 正确入库
手动堆栈/A01 A01 WAREHOUSE_MAPPING["手动堆栈"]["site_uuids"]["A01"] 3a19...eaea 仍然正常

warehouse_factory 详解

函数签名

def warehouse_factory(
    name: str,
    num_items_x: int = 1,      # 列数
    num_items_y: int = 4,      # 行数
    num_items_z: int = 4,      # 层数
    dx: float = 137.0,         # X 起始偏移
    dy: float = 96.0,          # Y 起始偏移
    dz: float = 120.0,         # Z 起始偏移
    item_dx: float = 10.0,     # X 间距
    item_dy: float = 10.0,     # Y 间距
    item_dz: float = 10.0,     # Z 间距
    col_offset: int = 0,       # 列偏移(影响数字)
    row_offset: int = 0,       # 行偏移(影响字母)
    layout: str = "col-major", # 布局模式
) -> WareHouse:

参数说明

尺寸参数

  • num_items_x, y, z: 定义仓库的网格尺寸
  • 注意: 当 num_items_z > 1Z 轴会被映射为数字列

位置参数

  • dx, dy, dz: 第一个库位的起始坐标
  • item_dx, dy, dz: 库位之间的间距

偏移参数

  • col_offset: 列起始偏移,用于生成 A05-D08 等命名

    col_offset=4  # 生成 A05, A06, A07, A08
    
  • row_offset: 行起始偏移,用于生成 F01-J03 等命名

    row_offset=5  # 生成 F01, F02, F03跳过 A-E
    

布局参数

  • layout:
    • "col-major": 列优先(默认),可能导致上下颠倒
    • "row-major": 行优先,推荐使用A 显示在上

库位生成逻辑

# row-major 模式(推荐)
keys = [f"{LETTERS[j + row_offset]}{i + 1 + col_offset:02d}" 
        for j in range(num_y) 
        for i in range(num_x)]

# 示例num_y=2, num_x=3, row_offset=0, col_offset=0
# 生成A01, A02, A03, B01, B02, B03

Y 坐标计算

if layout == "row-major":
    # A 在上Y 较小)
    y = dy + row * item_dy
else:
    # A 在下Y 较大)- 不推荐
    y = dy + (num_items_y - row - 1) * item_dy

创建新仓库

步骤 1: 在 YB_warehouses.py 中创建函数

def bioyond_warehouse_3x4x1(name: str) -> WareHouse:
    """创建 3行×4列×1层 仓库
    
    布局:
    A01 | A02 | A03 | A04
    B01 | B02 | B03 | B04
    C01 | C02 | C03 | C04
    """
    return warehouse_factory(
        name=name,
        num_items_x=4,      # 4列
        num_items_y=3,      # 3行
        num_items_z=1,      # 1层
        dx=10.0,
        dy=10.0,
        dz=10.0,
        item_dx=137.0,
        item_dy=120.0,
        item_dz=120.0,
        category="warehouse",
        layout="row-major",  # ⭐ 推荐使用
    )

步骤 2: 在 decks.py 中使用

# 1. 导入函数
from unilabos.resources.bioyond.YB_warehouses import (
    bioyond_warehouse_3x4x1,  # 新增
)

# 2. 在 setup() 中添加
self.warehouses = {
    "我的新仓库": bioyond_warehouse_3x4x1("我的新仓库"),
}
self.warehouse_locations = {
    "我的新仓库": Coordinate(100.0, 200.0, 0.0),
}

步骤 3: 在 config.py 中配置 UUID可选

WAREHOUSE_MAPPING = {
    "我的新仓库": {
        "uuid": "",
        "site_uuids": {
            "A01": "从 Bioyond 系统获取的 UUID",
            "A02": "从 Bioyond 系统获取的 UUID",
            # ... 其他 11 个库位
        }
    }
}

注意: 如果不需要拖拽入库功能,可跳过此步骤。


常见问题

Q1: 为什么库位显示上下颠倒C 在上A 在下)?

原因: 使用了默认的 col-major 布局。

解决:warehouse_factory 中添加 layout="row-major"

return warehouse_factory(
    ...
    layout="row-major",  # ← 添加这行
)

Q2: 我需要 1×3×3 还是 3×3×1

判断方法:

  • 1×3×3: 1列×3行×3(垂直堆叠,有高度)
  • 3×3×1: 3行×3列×1(平面网格)

推荐: 大多数情况使用 X×Y×1(平面网格)更直观。

Q3: 如何生成 F01-J03 而非 A01-E03

方法: 使用 row_offset 参数

bioyond_warehouse_5x3x1("仓库名", row_offset=5)
# row_offset=5 跳过 A-E从 F 开始

Q4: 拖拽物料后找不到 UUID 怎么办?

检查清单:

  1. config.py 中是否有该仓库的配置?
  2. 仓库名称是否完全匹配?
  3. 库位名称(如 A01是否在 site_uuids 中?

示例错误:

# decks.py
"手动传递窗右": bioyond_warehouse_5x3x1(...)

# config.py - ❌ 名称不匹配
"手动传递窗": { ... }  # 缺少"右"字

Q5: 库位重叠怎么办?

原因: 间距(item_dx/dy/dz)太小。

解决: 增大间距参数

item_dx=150.0,  # 增大 X 间距
item_dy=130.0,  # 增大 Y 间距

调试技巧

1. 查看生成的库位

warehouse = bioyond_warehouse_5x3x1("测试仓库")
print(list(warehouse.sites.keys()))
# 输出:['A01', 'A02', 'A03', 'B01', 'B02', ...]

2. 检查库位坐标

for name, site in warehouse.sites.items():
    print(f"{name}: {site.location}")
# 输出:
# A01: Coordinate(x=10.0, y=10.0, z=120.0)
# A02: Coordinate(x=147.0, y=10.0, z=120.0)
# ...

3. 验证 UUID 映射

from unilabos.devices.workstation.bioyond_studio.config import WAREHOUSE_MAPPING

warehouse_name = "手动传递窗右"
location_code = "A01"

if warehouse_name in WAREHOUSE_MAPPING:
    uuid = WAREHOUSE_MAPPING[warehouse_name]["site_uuids"].get(location_code)
    print(f"{warehouse_name}/{location_code}{uuid}")
else:
    print(f"❌ 未找到仓库: {warehouse_name}")

文件关系图

unilabos/
├── resources/
│   ├── warehouse.py              # warehouse_factory 核心实现
│   └── bioyond/
│       ├── YB_warehouses.py      # ⭐ 仓库函数定义
│       ├── decks.py              # ⭐ Deck 布局配置
│       └── README_WAREHOUSE.md   # 📖 本文档
└── devices/
    └── workstation/
        └── bioyond_studio/
            ├── config.py         # ⭐ UUID 映射配置
            └── bioyond_cell/
                └── bioyond_cell_workstation.py  # 业务逻辑

版本历史

  • v1.1 (2026-01-08): 补充实际配置案例

    • 添加"手动传递窗右"和"手动传递窗左"的完整配置示例
    • 展示 UUID 复用的实际应用
    • 说明三个仓库共享物理堆栈的配置方法
  • v1.0 (2026-01-07): 初始版本

    • 新增 row_offset 参数支持
    • 创建 bioyond_warehouse_5x3x1bioyond_warehouse_2x2x1
    • 修复多个仓库的上下颠倒问题

相关资源


维护者: Uni-Lab-OS 开发团队
最后更新: 2026-01-07