mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-15 13:44:39 +00:00
Update graphio together with workstation design.
fix(reaction_station): 为步骤参数添加Value字段传个BY后端 fix(bioyond/warehouses): 修正仓库尺寸和物品排列参数 调整仓库的x轴和z轴物品数量以及物品尺寸参数,使其符合4x1x4的规格要求 fix warehouse serialize/deserialize fix bioyond converter fix itemized_carrier.unassign_child_resource allow not-loaded MSG in registry add layout serializer & converter warehouseuse A1-D4; add warehouse layout fix(graphio): 修正bioyond到plr资源转换中的坐标计算错误 Fix resource assignment and type mapping issues Corrects resource assignment in ItemizedCarrier by using the correct spot key from _ordering. Updates graphio to use 'typeName' instead of 'name' for type mapping in resource_bioyond_to_plr. Renames DummyWorkstation to BioyondWorkstation in workstation_http_service for clarity.
This commit is contained in:
@@ -605,7 +605,8 @@ class BioyondReactionStation(BioyondWorkstation):
|
|||||||
total_params += 1
|
total_params += 1
|
||||||
step_parameters[step_id][action_name].append({
|
step_parameters[step_id][action_name].append({
|
||||||
"Key": param_key,
|
"Key": param_key,
|
||||||
"DisplayValue": param_value
|
"DisplayValue": param_value,
|
||||||
|
"Value": param_value
|
||||||
})
|
})
|
||||||
successful_params += 1
|
successful_params += 1
|
||||||
# print(f" ✓ {param_key} = {param_value}")
|
# print(f" ✓ {param_key} = {param_value}")
|
||||||
|
|||||||
@@ -668,7 +668,7 @@ __all__ = [
|
|||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 简单测试HTTP服务
|
# 简单测试HTTP服务
|
||||||
class DummyWorkstation:
|
class BioyondWorkstation:
|
||||||
device_id = "WS-001"
|
device_id = "WS-001"
|
||||||
|
|
||||||
def process_step_finish_report(self, report_request):
|
def process_step_finish_report(self, report_request):
|
||||||
|
|||||||
@@ -708,6 +708,8 @@ class Registry:
|
|||||||
for status_name, status_type in device_config["class"]["status_types"].items():
|
for status_name, status_type in device_config["class"]["status_types"].items():
|
||||||
device_config["class"]["status_types"][status_name] = status_str_type_mapping[status_type]
|
device_config["class"]["status_types"][status_name] = status_str_type_mapping[status_type]
|
||||||
for action_name, action_config in device_config["class"]["action_value_mappings"].items():
|
for action_name, action_config in device_config["class"]["action_value_mappings"].items():
|
||||||
|
if action_config["type"] not in action_str_type_mapping:
|
||||||
|
continue
|
||||||
action_config["type"] = action_str_type_mapping[action_config["type"]]
|
action_config["type"] = action_str_type_mapping[action_config["type"]]
|
||||||
# 添加内置的驱动命令动作
|
# 添加内置的驱动命令动作
|
||||||
self._add_builtin_actions(device_config, device_id)
|
self._add_builtin_actions(device_config, device_id)
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ def bioyond_warehouse_1x4x4(name: str) -> WareHouse:
|
|||||||
"""创建BioYond 4x1x4仓库"""
|
"""创建BioYond 4x1x4仓库"""
|
||||||
return warehouse_factory(
|
return warehouse_factory(
|
||||||
name=name,
|
name=name,
|
||||||
num_items_x=1,
|
num_items_x=4,
|
||||||
num_items_y=4,
|
num_items_y=4,
|
||||||
num_items_z=4,
|
num_items_z=1,
|
||||||
dx=10.0,
|
dx=10.0,
|
||||||
dy=10.0,
|
dy=10.0,
|
||||||
dz=10.0,
|
dz=10.0,
|
||||||
item_dx=137.0,
|
item_dx=147.0,
|
||||||
item_dy=96.0,
|
item_dy=106.0,
|
||||||
item_dz=120.0,
|
item_dz=130.0,
|
||||||
category="warehouse",
|
category="warehouse",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -639,25 +639,24 @@ def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: Dict[st
|
|||||||
|
|
||||||
# 处理子物料(detail)
|
# 处理子物料(detail)
|
||||||
if material.get("detail") and len(material["detail"]) > 0:
|
if material.get("detail") and len(material["detail"]) > 0:
|
||||||
|
for bottle in reversed(plr_material.children):
|
||||||
|
plr_material.unassign_child_resource(bottle)
|
||||||
child_ids = []
|
child_ids = []
|
||||||
for detail in material["detail"]:
|
for detail in material["detail"]:
|
||||||
number = (
|
number = (
|
||||||
(detail.get("z", 0) - 1) * plr_material.num_items_x * plr_material.num_items_y
|
(detail.get("z", 0) - 1) * plr_material.num_items_x * plr_material.num_items_y
|
||||||
+ (detail.get("x", 0) - 1) * plr_material.num_items_x
|
+ (detail.get("y", 0) - 1) * plr_material.num_items_y
|
||||||
+ (detail.get("y", 0) - 1)
|
+ (detail.get("x", 0) - 1)
|
||||||
)
|
)
|
||||||
bottle = plr_material[number]
|
typeName = detail.get("typeName", detail.get("name", ""))
|
||||||
if detail["name"] in type_mapping:
|
if typeName in type_mapping:
|
||||||
# plr_material.unassign_child_resource(bottle)
|
bottle = plr_material[number] = initialize_resource(
|
||||||
plr_material.sites[number] = None
|
{"name": f'{detail["name"]}_{number}', "class": type_mapping[typeName][0]}, resource_type=ResourcePLR
|
||||||
plr_material[number] = initialize_resource(
|
|
||||||
{"name": f'{detail["name"]}_{number}', "class": type_mapping[detail["name"]][0]}, resource_type=ResourcePLR
|
|
||||||
)
|
)
|
||||||
else:
|
|
||||||
bottle.tracker.liquids = [
|
bottle.tracker.liquids = [
|
||||||
(detail["name"], float(detail.get("quantity", 0)) if detail.get("quantity") else 0)
|
(detail["name"], float(detail.get("quantity", 0)) if detail.get("quantity") else 0)
|
||||||
]
|
]
|
||||||
bottle.code = detail.get("code", "")
|
bottle.code = detail.get("code", "")
|
||||||
else:
|
else:
|
||||||
bottle = plr_material[0] if plr_material.capacity > 0 else plr_material
|
bottle = plr_material[0] if plr_material.capacity > 0 else plr_material
|
||||||
bottle.tracker.liquids = [
|
bottle.tracker.liquids = [
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ class ItemizedCarrier(ResourcePLR):
|
|||||||
num_items_x: int = 0,
|
num_items_x: int = 0,
|
||||||
num_items_y: int = 0,
|
num_items_y: int = 0,
|
||||||
num_items_z: int = 0,
|
num_items_z: int = 0,
|
||||||
|
layout: str = "x-y",
|
||||||
sites: Optional[Dict[Union[int, str], Optional[ResourcePLR]]] = None,
|
sites: Optional[Dict[Union[int, str], Optional[ResourcePLR]]] = None,
|
||||||
category: Optional[str] = "carrier",
|
category: Optional[str] = "carrier",
|
||||||
model: Optional[str] = None,
|
model: Optional[str] = None,
|
||||||
@@ -88,6 +89,8 @@ class ItemizedCarrier(ResourcePLR):
|
|||||||
)
|
)
|
||||||
self.num_items = len(sites)
|
self.num_items = len(sites)
|
||||||
self.num_items_x, self.num_items_y, self.num_items_z = num_items_x, num_items_y, num_items_z
|
self.num_items_x, self.num_items_y, self.num_items_z = num_items_x, num_items_y, num_items_z
|
||||||
|
self.layout = "z-y" if self.num_items_z > 1 and self.num_items_x == 1 else "x-z" if self.num_items_z > 1 and self.num_items_y == 1 else "x-y"
|
||||||
|
|
||||||
if isinstance(sites, dict):
|
if isinstance(sites, dict):
|
||||||
sites = sites or {}
|
sites = sites or {}
|
||||||
self.sites: List[Optional[ResourcePLR]] = list(sites.values())
|
self.sites: List[Optional[ResourcePLR]] = list(sites.values())
|
||||||
@@ -150,7 +153,7 @@ class ItemizedCarrier(ResourcePLR):
|
|||||||
def assign_resource_to_site(self, resource: ResourcePLR, spot: int):
|
def assign_resource_to_site(self, resource: ResourcePLR, spot: int):
|
||||||
if self.sites[spot] is not None and not isinstance(self.sites[spot], ResourceHolder):
|
if self.sites[spot] is not None and not isinstance(self.sites[spot], ResourceHolder):
|
||||||
raise ValueError(f"spot {spot} already has a resource, {resource}")
|
raise ValueError(f"spot {spot} already has a resource, {resource}")
|
||||||
self.assign_child_resource(resource, location=self.child_locations.get(str(spot)), spot=spot)
|
self.assign_child_resource(resource, location=self.child_locations.get(list(self._ordering.keys())[spot]), spot=spot)
|
||||||
|
|
||||||
def unassign_child_resource(self, resource: ResourcePLR):
|
def unassign_child_resource(self, resource: ResourcePLR):
|
||||||
found = False
|
found = False
|
||||||
@@ -161,8 +164,9 @@ class ItemizedCarrier(ResourcePLR):
|
|||||||
break
|
break
|
||||||
if not found:
|
if not found:
|
||||||
raise ValueError(f"Resource {resource} is not assigned to this carrier")
|
raise ValueError(f"Resource {resource} is not assigned to this carrier")
|
||||||
if hasattr(resource, "unassign"):
|
super().unassign_child_resource(resource)
|
||||||
resource.unassign()
|
# if hasattr(resource, "unassign"):
|
||||||
|
# resource.unassign()
|
||||||
|
|
||||||
def get_child_identifier(self, child: ResourcePLR):
|
def get_child_identifier(self, child: ResourcePLR):
|
||||||
"""Get the identifier information for a given child resource.
|
"""Get the identifier information for a given child resource.
|
||||||
@@ -403,6 +407,7 @@ class ItemizedCarrier(ResourcePLR):
|
|||||||
"num_items_x": self.num_items_x,
|
"num_items_x": self.num_items_x,
|
||||||
"num_items_y": self.num_items_y,
|
"num_items_y": self.num_items_y,
|
||||||
"num_items_z": self.num_items_z,
|
"num_items_z": self.num_items_z,
|
||||||
|
"layout": self.layout,
|
||||||
"sites": [{
|
"sites": [{
|
||||||
"label": str(identifier),
|
"label": str(identifier),
|
||||||
"visible": True if self[identifier] is not None else False,
|
"visible": True if self[identifier] is not None else False,
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ from pylabrobot.resources.carrier import ResourceHolder, create_homogeneous_reso
|
|||||||
from unilabos.resources.itemized_carrier import ItemizedCarrier, ResourcePLR
|
from unilabos.resources.itemized_carrier import ItemizedCarrier, ResourcePLR
|
||||||
|
|
||||||
|
|
||||||
|
LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|
||||||
|
|
||||||
def warehouse_factory(
|
def warehouse_factory(
|
||||||
name: str,
|
name: str,
|
||||||
num_items_x: int = 4,
|
num_items_x: int = 1,
|
||||||
num_items_y: int = 1,
|
num_items_y: int = 4,
|
||||||
num_items_z: int = 4,
|
num_items_z: int = 4,
|
||||||
dx: float = 137.0,
|
dx: float = 137.0,
|
||||||
dy: float = 96.0,
|
dy: float = 96.0,
|
||||||
@@ -33,13 +36,16 @@ def warehouse_factory(
|
|||||||
locations.append(Coordinate(x, y, z))
|
locations.append(Coordinate(x, y, z))
|
||||||
if removed_positions:
|
if removed_positions:
|
||||||
locations = [loc for i, loc in enumerate(locations) if i not in removed_positions]
|
locations = [loc for i, loc in enumerate(locations) if i not in removed_positions]
|
||||||
sites = create_homogeneous_resources(
|
_sites = create_homogeneous_resources(
|
||||||
klass=ResourceHolder,
|
klass=ResourceHolder,
|
||||||
locations=locations,
|
locations=locations,
|
||||||
resource_size_x=127.0,
|
resource_size_x=127.0,
|
||||||
resource_size_y=86.0,
|
resource_size_y=86.0,
|
||||||
name_prefix=name,
|
name_prefix=name,
|
||||||
)
|
)
|
||||||
|
len_x, len_y = (num_items_x, num_items_y) if num_items_z == 1 else (num_items_y, num_items_z) if num_items_x == 1 else (num_items_x, num_items_z)
|
||||||
|
keys = [f"{LETTERS[j]}{i + 1}" for i in range(len_x) for j in range(len_y)]
|
||||||
|
sites = {i: site for i, site in zip(keys, _sites.values())}
|
||||||
|
|
||||||
return WareHouse(
|
return WareHouse(
|
||||||
name=name,
|
name=name,
|
||||||
@@ -68,6 +74,7 @@ class WareHouse(ItemizedCarrier):
|
|||||||
num_items_x: int,
|
num_items_x: int,
|
||||||
num_items_y: int,
|
num_items_y: int,
|
||||||
num_items_z: int,
|
num_items_z: int,
|
||||||
|
layout: str = "x-y",
|
||||||
sites: Optional[Dict[Union[int, str], Optional[ResourcePLR]]] = None,
|
sites: Optional[Dict[Union[int, str], Optional[ResourcePLR]]] = None,
|
||||||
category: str = "warehouse",
|
category: str = "warehouse",
|
||||||
model: Optional[str] = None,
|
model: Optional[str] = None,
|
||||||
@@ -83,6 +90,7 @@ class WareHouse(ItemizedCarrier):
|
|||||||
num_items_x=num_items_x,
|
num_items_x=num_items_x,
|
||||||
num_items_y=num_items_y,
|
num_items_y=num_items_y,
|
||||||
num_items_z=num_items_z,
|
num_items_z=num_items_z,
|
||||||
|
layout=layout,
|
||||||
sites=sites,
|
sites=sites,
|
||||||
category=category,
|
category=category,
|
||||||
model=model,
|
model=model,
|
||||||
|
|||||||
@@ -342,6 +342,7 @@ class ResourceTreeSet(object):
|
|||||||
pos = {
|
pos = {
|
||||||
"size": {"width": d["size_x"], "height": d["size_y"], "depth": d["size_z"]},
|
"size": {"width": d["size_x"], "height": d["size_y"], "depth": d["size_z"]},
|
||||||
"scale": {"x": 1.0, "y": 1.0, "z": 1.0},
|
"scale": {"x": 1.0, "y": 1.0, "z": 1.0},
|
||||||
|
"layout": d.get("layout", "x-y"),
|
||||||
"position": raw_pos,
|
"position": raw_pos,
|
||||||
"position3d": raw_pos,
|
"position3d": raw_pos,
|
||||||
"rotation": d["rotation"],
|
"rotation": d["rotation"],
|
||||||
|
|||||||
Reference in New Issue
Block a user