mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 21:11:12 +00:00
feat(workstation): 支持多种输入类型的 station_resource 并优化物料系统初始化
- 新增 `_coerce_station_resource_input` 函数以支持 dict、list 和其他类型转换为 Deck - 添加对 Modbus 客户端方法的兼容性封装,确保 slave/unit 参数正确传递- 在初始化时根据 station_resource 动态创建或赋值 deck - 自动构建默认物料台面及三个料盘,并分配初始电极片资源 - 移除旧有的硬编码物料系统注释代码 - 更新资源导出逻辑以使用工作站实例中的 deck 属性
This commit is contained in:
@@ -1,11 +1,15 @@
|
||||
|
||||
import csv
|
||||
import inspect
|
||||
import json
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
import types
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, Optional
|
||||
from pylabrobot.resources import Resource as PLRResource
|
||||
from functools import wraps
|
||||
from pylabrobot.resources import Deck, Resource as PLRResource
|
||||
from unilabos_msgs.msg import Resource
|
||||
from unilabos.device_comms.modbus_plc.client import ModbusTcpClient
|
||||
from unilabos.devices.workstation.workstation_base import WorkstationBase
|
||||
@@ -15,12 +19,99 @@ from unilabos.devices.workstation.coin_cell_assembly.button_battery_station impo
|
||||
from unilabos.ros.nodes.base_device_node import ROS2DeviceNode, BaseROS2DeviceNode
|
||||
from unilabos.ros.nodes.presets.workstation import ROS2WorkstationNode
|
||||
from unilabos.devices.workstation.coin_cell_assembly.button_battery_station import CoincellDeck
|
||||
from unilabos.resources.graphio import convert_resources_to_type
|
||||
from unilabos.utils.log import logger
|
||||
|
||||
|
||||
def _ensure_modbus_slave_kw_alias(modbus_client):
|
||||
if modbus_client is None:
|
||||
return
|
||||
|
||||
method_names = [
|
||||
"read_coils",
|
||||
"write_coils",
|
||||
"write_coil",
|
||||
"read_discrete_inputs",
|
||||
"read_holding_registers",
|
||||
"write_register",
|
||||
"write_registers",
|
||||
]
|
||||
|
||||
def _wrap(func):
|
||||
signature = inspect.signature(func)
|
||||
has_var_kwargs = any(param.kind == param.VAR_KEYWORD for param in signature.parameters.values())
|
||||
accepts_unit = has_var_kwargs or "unit" in signature.parameters
|
||||
accepts_slave = has_var_kwargs or "slave" in signature.parameters
|
||||
|
||||
@wraps(func)
|
||||
def _wrapped(self, *args, **kwargs):
|
||||
if "slave" in kwargs and not accepts_slave:
|
||||
slave_value = kwargs.pop("slave")
|
||||
if accepts_unit and "unit" not in kwargs:
|
||||
kwargs["unit"] = slave_value
|
||||
if "unit" in kwargs and not accepts_unit:
|
||||
unit_value = kwargs.pop("unit")
|
||||
if accepts_slave and "slave" not in kwargs:
|
||||
kwargs["slave"] = unit_value
|
||||
return func(self, *args, **kwargs)
|
||||
|
||||
_wrapped._has_slave_alias = True
|
||||
return _wrapped
|
||||
|
||||
for name in method_names:
|
||||
if not hasattr(modbus_client, name):
|
||||
continue
|
||||
bound_method = getattr(modbus_client, name)
|
||||
func = getattr(bound_method, "__func__", None)
|
||||
if func is None:
|
||||
continue
|
||||
if getattr(func, "_has_slave_alias", False):
|
||||
continue
|
||||
wrapped = _wrap(func)
|
||||
setattr(modbus_client, name, types.MethodType(wrapped, modbus_client))
|
||||
|
||||
|
||||
def _coerce_station_resource_input(station_resource: Any) -> Optional[Deck]:
|
||||
if station_resource is None:
|
||||
return None
|
||||
|
||||
if isinstance(station_resource, Deck):
|
||||
return station_resource
|
||||
|
||||
if isinstance(station_resource, PLRResource):
|
||||
return station_resource if isinstance(station_resource, Deck) else None
|
||||
|
||||
candidates = None
|
||||
if isinstance(station_resource, dict):
|
||||
if "nodes" in station_resource and isinstance(station_resource["nodes"], list):
|
||||
candidates = station_resource["nodes"]
|
||||
else:
|
||||
candidates = [station_resource]
|
||||
elif isinstance(station_resource, list):
|
||||
candidates = station_resource
|
||||
|
||||
if candidates is None:
|
||||
return None
|
||||
|
||||
try:
|
||||
converted = convert_resources_to_type(resources_list=candidates, resource_type=Deck)
|
||||
if isinstance(converted, Deck):
|
||||
return converted
|
||||
if isinstance(converted, list):
|
||||
for item in converted:
|
||||
if isinstance(item, Deck):
|
||||
return item
|
||||
except Exception as exc:
|
||||
logger.warning(f"station_resource 转换 Deck 失败: {exc}")
|
||||
return None
|
||||
|
||||
|
||||
#构建物料系统
|
||||
|
||||
class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
def __init__(
|
||||
self,
|
||||
station_resource: Optional[Any] = None,
|
||||
deck: Deck=None,
|
||||
address: str = "172.21.32.20",
|
||||
port: str = "502",
|
||||
@@ -28,6 +119,16 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
*args,
|
||||
**kwargs,
|
||||
):
|
||||
if station_resource is None and "station_resource" in kwargs:
|
||||
station_resource = kwargs.pop("station_resource")
|
||||
else:
|
||||
kwargs.pop("station_resource", None)
|
||||
|
||||
normalized_station_resource = _coerce_station_resource_input(station_resource)
|
||||
|
||||
if deck is None and isinstance(normalized_station_resource, Deck):
|
||||
deck = normalized_station_resource
|
||||
|
||||
super().__init__(
|
||||
#桌子
|
||||
deck=deck,
|
||||
@@ -35,10 +136,34 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
**kwargs,
|
||||
)
|
||||
self.debug_mode = debug_mode
|
||||
self.deck = deck
|
||||
|
||||
self.station_resource = normalized_station_resource if isinstance(normalized_station_resource, Deck) else None
|
||||
|
||||
if self.deck is None:
|
||||
self.deck = CoincellDeck(size_x=1000, size_y=1000, size_z=900)
|
||||
self.station_resource = self.deck
|
||||
# 创建料盘1并添加极片
|
||||
liaopan1 = MaterialPlate(name="liaopan1", size_x=120.8, size_y=120.5, size_z=10.0, fill=True)
|
||||
self.deck.assign_child_resource(liaopan1, Coordinate(x=0, y=0, z=0))
|
||||
for i in range(16):
|
||||
jipian = ElectrodeSheet(name=f"jipian1_{i}", size_x=12, size_y=12, size_z=0.1)
|
||||
liaopan1.children[i].assign_child_resource(jipian, location=None)
|
||||
# 创建料盘2
|
||||
liaopan2 = MaterialPlate(name="liaopan2", size_x=120.8, size_y=120.5, size_z=10.0, fill=True)
|
||||
self.deck.assign_child_resource(liaopan2, Coordinate(x=500, y=0, z=0))
|
||||
# 创建电池料盘
|
||||
liaopan3 = MaterialPlate(name="电池料盘", size_x=120.8, size_y=160.5, size_z=10.0, fill=True)
|
||||
self.deck.assign_child_resource(liaopan3, Coordinate(x=100, y=100, z=0))
|
||||
else:
|
||||
if self.station_resource is None:
|
||||
self.station_resource = self.deck
|
||||
elif self.deck is not self.station_resource:
|
||||
self.deck = self.station_resource
|
||||
|
||||
""" 连接初始化 """
|
||||
modbus_client = TCPClient(addr=address, port=port)
|
||||
print("modbus_client", modbus_client)
|
||||
_ensure_modbus_slave_kw_alias(modbus_client.client)
|
||||
if not debug_mode:
|
||||
modbus_client.client.connect()
|
||||
count = 100
|
||||
@@ -62,8 +187,6 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
self.csv_export_file = None
|
||||
self.coin_num_N = 0 #已组装电池数量
|
||||
#创建一个物料台面,包含两个极片板
|
||||
#self.deck = create_a_coin_cell_deck()
|
||||
|
||||
#self._ros_node.update_resource(self.deck)
|
||||
|
||||
#ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
|
||||
@@ -907,7 +1030,10 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
|
||||
"resources": [self.station_resource]
|
||||
})
|
||||
time.sleep(4)
|
||||
# for i in range(40):
|
||||
# print(f"fun_wuliao_test 运行结束{i}")
|
||||
# time.sleep(1)
|
||||
# time.sleep(40)
|
||||
# 数据读取与输出
|
||||
def func_read_data_and_output(self, file_path: str="D:\\coin_cell_data"):
|
||||
# 检查CSV导出是否正在运行,已运行则跳出,防止同时启动两个while循环
|
||||
@@ -1145,8 +1271,11 @@ if __name__ == "__main__":
|
||||
#liaopan2.children[1].assign_child_resource(jipian1, location=None)
|
||||
##print(jipian2.parent)
|
||||
|
||||
liaopan1 = deck.get_resource("liaopan1")
|
||||
liaopan2 = deck.get_resource("liaopan2")
|
||||
# 使用 Coin_Cell 对象的 deck 属性
|
||||
deck = Coin_Cell.deck
|
||||
|
||||
liaopan1 = Coin_Cell.deck.get_resource("liaopan1")
|
||||
liaopan2 = Coin_Cell.deck.get_resource("liaopan2")
|
||||
for i in range(16):
|
||||
#找到liaopan1上每一个jipian
|
||||
jipian_linshi = liaopan1.children[i].children[0]
|
||||
@@ -1172,7 +1301,7 @@ if __name__ == "__main__":
|
||||
BasicConfig.sk = "15d4f25e-3512-4f9c-9bfb-43ab85e7b561"
|
||||
from unilabos.app.web.client import http_client
|
||||
|
||||
resources = convert_resources_from_type([deck], [Resource])
|
||||
resources = convert_resources_from_type([Coin_Cell.deck], [Resource])
|
||||
json.dump({"nodes": resources, "links": []}, open("button_battery_station_resources_unilab.json", "w"), indent=2)
|
||||
|
||||
#print(resources)
|
||||
@@ -1180,4 +1309,6 @@ if __name__ == "__main__":
|
||||
|
||||
http_client.resource_add(resources)
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user