mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-04 13:25:13 +00:00
feat(bioyond): 更新仓库布局和尺寸,支持竖向排列的测量小瓶和试剂存放堆栈
This commit is contained in:
@@ -49,15 +49,13 @@ class BIOYOND_PolymerReactionStation_Deck(Deck):
|
||||
"测量小瓶仓库(测密度)": bioyond_warehouse_density_vial("测量小瓶仓库(测密度)"), # A01~B03
|
||||
}
|
||||
self.warehouse_locations = {
|
||||
"堆栈1左": Coordinate(0.0, 430.0, 0.0), # 左侧位置
|
||||
"堆栈1右": Coordinate(2500.0, 430.0, 0.0), # 右侧位置
|
||||
"站内试剂存放堆栈": Coordinate(640.0, 480.0, 0.0),
|
||||
"堆栈1左": Coordinate(-200.0, 450.0, 0.0), # 左侧位置
|
||||
"堆栈1右": Coordinate(2350.0, 450.0, 0.0), # 右侧位置
|
||||
"站内试剂存放堆栈": Coordinate(730.0, 390.0, 0.0),
|
||||
# "移液站内10%分装液体准备仓库": Coordinate(1200.0, 600.0, 0.0),
|
||||
"站内Tip盒堆栈": Coordinate(300.0, 150.0, 0.0),
|
||||
"测量小瓶仓库(测密度)": Coordinate(922.0, 552.0, 0.0),
|
||||
"测量小瓶仓库(测密度)": Coordinate(940.0, 530.0, 0.0),
|
||||
}
|
||||
self.warehouses["站内试剂存放堆栈"].rotation = Rotation(z=90)
|
||||
self.warehouses["测量小瓶仓库(测密度)"].rotation = Rotation(z=270)
|
||||
|
||||
for warehouse_name, warehouse in self.warehouses.items():
|
||||
self.assign_child_resource(warehouse, location=self.warehouse_locations[warehouse_name])
|
||||
|
||||
@@ -46,41 +46,55 @@ def bioyond_warehouse_1x4x4_right(name: str) -> WareHouse:
|
||||
)
|
||||
|
||||
def bioyond_warehouse_density_vial(name: str) -> WareHouse:
|
||||
"""创建测量小瓶仓库(测密度) A01~B03"""
|
||||
"""创建测量小瓶仓库(测密度) - 竖向排列2列3行
|
||||
布局(从下到上,从左到右):
|
||||
| A03 | B03 | ← 顶部
|
||||
| A02 | B02 | ← 中部
|
||||
| A01 | B01 | ← 底部
|
||||
"""
|
||||
return warehouse_factory(
|
||||
name=name,
|
||||
num_items_x=3, # 3列(01-03)
|
||||
num_items_y=2, # 2行(A-B)
|
||||
num_items_x=2, # 2列(A, B)
|
||||
num_items_y=3, # 3行(01-03,从下到上)
|
||||
num_items_z=1, # 1层
|
||||
dx=10.0,
|
||||
dy=10.0,
|
||||
dz=10.0,
|
||||
item_dx=40.0,
|
||||
item_dy=40.0,
|
||||
item_dx=40.0, # 列间距(A到B的横向距离)
|
||||
item_dy=40.0, # 行间距(01到02到03的竖向距离)
|
||||
item_dz=50.0,
|
||||
# 用更小的 resource_size 来表现 "小点的孔位"
|
||||
# ⭐ 竖向warehouse:槽位尺寸也是竖向的(小瓶已经是正方形,无需调整)
|
||||
resource_size_x=30.0,
|
||||
resource_size_y=30.0,
|
||||
resource_size_z=12.0,
|
||||
category="warehouse",
|
||||
col_offset=0,
|
||||
layout="row-major",
|
||||
layout="vertical-col-major", # ⭐ 竖向warehouse专用布局
|
||||
)
|
||||
|
||||
def bioyond_warehouse_reagent_storage(name: str) -> WareHouse:
|
||||
"""创建BioYond站内试剂存放堆栈(A01~A02, 1行×2列)"""
|
||||
"""创建BioYond站内试剂存放堆栈 - 竖向排列1列2行
|
||||
布局(竖向,从下到上):
|
||||
| A02 | ← 顶部
|
||||
| A01 | ← 底部
|
||||
"""
|
||||
return warehouse_factory(
|
||||
name=name,
|
||||
num_items_x=2, # 2列(01-02)
|
||||
num_items_y=1, # 1行(A)
|
||||
num_items_x=1, # 1列
|
||||
num_items_y=2, # 2行(01-02,从下到上)
|
||||
num_items_z=1, # 1层
|
||||
dx=10.0,
|
||||
dy=10.0,
|
||||
dz=10.0,
|
||||
item_dx=137.0,
|
||||
item_dy=96.0,
|
||||
item_dx=96.0, # 列间距(这里只有1列,不重要)
|
||||
item_dy=137.0, # 行间距(A01到A02的竖向距离)
|
||||
item_dz=120.0,
|
||||
# ⭐ 竖向warehouse:交换槽位尺寸,使槽位框也是竖向的
|
||||
resource_size_x=86.0, # 原来的 resource_size_y
|
||||
resource_size_y=127.0, # 原来的 resource_size_x
|
||||
resource_size_z=25.0,
|
||||
category="warehouse",
|
||||
layout="vertical-col-major", # ⭐ 竖向warehouse专用布局
|
||||
)
|
||||
|
||||
def bioyond_warehouse_tipbox_storage(name: str) -> WareHouse:
|
||||
|
||||
@@ -763,6 +763,22 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
||||
if not locations:
|
||||
logger.debug(f"[物料位置] {unique_name} 没有location信息,跳过warehouse放置")
|
||||
|
||||
# ⭐ 预先检查:如果物料的任何location在竖向warehouse中,提前交换尺寸
|
||||
# 这样可以避免多个location时尺寸不一致的问题
|
||||
needs_size_swap = False
|
||||
for loc in locations:
|
||||
wh_name_check = loc.get("whName")
|
||||
if wh_name_check in ["站内试剂存放堆栈", "测量小瓶仓库(测密度)"]:
|
||||
needs_size_swap = True
|
||||
break
|
||||
|
||||
if needs_size_swap and hasattr(plr_material, 'size_x') and hasattr(plr_material, 'size_y'):
|
||||
original_x = plr_material.size_x
|
||||
original_y = plr_material.size_y
|
||||
plr_material.size_x = original_y
|
||||
plr_material.size_y = original_x
|
||||
logger.debug(f" 物料 {unique_name} 将放入竖向warehouse,预先交换尺寸: {original_x}×{original_y} → {plr_material.size_x}×{plr_material.size_y}")
|
||||
|
||||
for loc in locations:
|
||||
wh_name = loc.get("whName")
|
||||
logger.debug(f"[物料位置] {unique_name} 尝试放置到 warehouse: {wh_name} (Bioyond坐标: x={loc.get('x')}, y={loc.get('y')}, z={loc.get('z')})")
|
||||
@@ -784,7 +800,6 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
||||
logger.debug(f"[Warehouse匹配] 找到warehouse: {wh_name} (容量: {warehouse.capacity}, 行×列: {warehouse.num_items_x}×{warehouse.num_items_y})")
|
||||
|
||||
# Bioyond坐标映射 (重要!): x→行(1=A,2=B...), y→列(1=01,2=02...), z→层(通常=1)
|
||||
# PyLabRobot warehouse是列优先存储: A01,B01,C01,D01, A02,B02,C02,D02, ...
|
||||
x = loc.get("x", 1) # 行号 (1-based: 1=A, 2=B, 3=C, 4=D)
|
||||
y = loc.get("y", 1) # 列号 (1-based: 1=01, 2=02, 3=03...)
|
||||
z = loc.get("z", 1) # 层号 (1-based, 通常为1)
|
||||
@@ -793,12 +808,23 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
||||
if wh_name == "堆栈1右":
|
||||
y = y - 4 # 将5-8映射到1-4
|
||||
|
||||
# 特殊处理:对于1行×N列的横向warehouse(如站内试剂存放堆栈)
|
||||
# Bioyond的y坐标表示线性位置序号,而不是列号
|
||||
if warehouse.num_items_y == 1:
|
||||
# 1行warehouse: 直接用y作为线性索引
|
||||
idx = y - 1
|
||||
logger.debug(f"1行warehouse {wh_name}: y={y} → idx={idx}")
|
||||
# 特殊处理竖向warehouse(站内试剂存放堆栈、测量小瓶仓库)
|
||||
# 这些warehouse使用 vertical-col-major 布局
|
||||
if wh_name in ["站内试剂存放堆栈", "测量小瓶仓库(测密度)"]:
|
||||
# vertical-col-major 布局的坐标映射:
|
||||
# - Bioyond的x(1=A,2=B)对应warehouse的列(col, x方向)
|
||||
# - Bioyond的y(1=01,2=02,3=03)对应warehouse的行(row, y方向),从下到上
|
||||
# vertical-col-major 中: row=0 对应底部,row=n-1 对应顶部
|
||||
# Bioyond y=1(01) 对应底部 → row=0, y=2(02) 对应中间 → row=1
|
||||
# 索引计算: idx = row * num_cols + col
|
||||
col_idx = x - 1 # Bioyond的x(A,B) → col索引(0,1)
|
||||
row_idx = y - 1 # Bioyond的y(01,02,03) → row索引(0,1,2)
|
||||
layer_idx = z - 1
|
||||
|
||||
idx = layer_idx * (warehouse.num_items_x * warehouse.num_items_y) + row_idx * warehouse.num_items_x + col_idx
|
||||
logger.debug(f"🔍 竖向warehouse {wh_name}: Bioyond(x={x},y={y},z={z}) → warehouse(col={col_idx},row={row_idx},layer={layer_idx}) → idx={idx}, capacity={warehouse.capacity}")
|
||||
|
||||
# 普通横向warehouse的处理
|
||||
else:
|
||||
# 多行warehouse: 根据 layout 使用不同的索引计算
|
||||
row_idx = x - 1 # x表示行: 转为0-based
|
||||
@@ -822,6 +848,7 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
||||
|
||||
if 0 <= idx < warehouse.capacity:
|
||||
if warehouse[idx] is None or isinstance(warehouse[idx], ResourceHolder):
|
||||
# 物料尺寸已在放入warehouse前根据需要进行了交换
|
||||
warehouse[idx] = plr_material
|
||||
logger.debug(f"✅ 物料 {unique_name} 放置到 {wh_name}[{idx}] (Bioyond坐标: x={loc.get('x')}, y={loc.get('y')})")
|
||||
else:
|
||||
|
||||
@@ -42,6 +42,10 @@ def warehouse_factory(
|
||||
if layout == "row-major":
|
||||
# 行优先:row=0(A行) 应该显示在上方,需要较小的 y 值
|
||||
y = dy + row * item_dy
|
||||
elif layout == "vertical-col-major":
|
||||
# 竖向warehouse: row=0 对应顶部(y小),row=n-1 对应底部(y大)
|
||||
# 但标签 01 应该在底部,所以使用反向映射
|
||||
y = dy + (num_items_y - row - 1) * item_dy
|
||||
else:
|
||||
# 列优先:保持原逻辑(row=0 对应较大的 y)
|
||||
y = dy + (num_items_y - row - 1) * item_dy
|
||||
@@ -66,6 +70,14 @@ def warehouse_factory(
|
||||
# 行优先顺序: A01,A02,A03,A04, B01,B02,B03,B04
|
||||
# locations[0] 对应 row=0, y最大(前端顶部)→ 应该是 A01
|
||||
keys = [f"{LETTERS[j]}{i + 1 + col_offset:02d}" for j in range(len_y) for i in range(len_x)]
|
||||
elif layout == "vertical-col-major":
|
||||
# ⭐ 竖向warehouse专用布局:
|
||||
# 字母(A,B,C...)对应列(横向, x方向),数字(01,02,03...)对应行(竖向, y方向,从下到上)
|
||||
# locations 生成顺序: row→col (row=0,col=0 → row=0,col=1 → row=1,col=0 → ...)
|
||||
# 其中 row=0 对应底部(y大),row=n-1 对应顶部(y小)
|
||||
# 标签中 01 对应底部(row=0),02 对应中间(row=1),03 对应顶部(row=2)
|
||||
# 标签顺序: A01,B01,A02,B02,A03,B03
|
||||
keys = [f"{LETTERS[col]}{row + 1 + col_offset:02d}" for row in range(len_y) for col in range(len_x)]
|
||||
else:
|
||||
# 列优先顺序: A01,B01,C01,D01, A02,B02,C02,D02
|
||||
keys = [f"{LETTERS[j]}{i + 1 + col_offset:02d}" for i in range(len_x) for j in range(len_y)]
|
||||
|
||||
Reference in New Issue
Block a user