feat: 更新Neware电池测试系统驱动及电芯组装工作站相关文件

- 更新 neware_battery_test_system 驱动及设备配置
- 新增 generate_xml_content.py 工具脚本
- 更新 bioyond_cell_workstation 工作站实现
- 更新 coin_cell_assembly 扣式电池组装逻辑
- 更新相关注册表 YAML 配置:neware_battery_test_system、coin_cell_workstation、bioyond_cell
This commit is contained in:
Andy6M
2026-04-09 14:16:49 +08:00
parent 467f0b1115
commit ed952e8a44
8 changed files with 1611 additions and 210 deletions

View File

@@ -14,7 +14,7 @@
"config": {
"ip": "127.0.0.1",
"port": 502,
"machine_id": 1,
"machine_ids": [1, 2, 3, 4, 5, 6, 86],
"devtype": "27",
"timeout": 20,
"size_x": 500.0,
@@ -32,4 +32,4 @@
}
],
"links": []
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -305,11 +305,12 @@ class NewareBatteryTestSystem:
ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz'
ascii_uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
LETTERS = ascii_uppercase + ascii_lowercase
DEFAULT_MACHINE_IDS = [1, 2, 3, 4, 5, 6, 86]
def __init__(self,
ip: str = None,
port: int = None,
machine_id: int = 1,
machine_ids: Optional[List[int]] = None,
devtype: str = None,
timeout: int = None,
@@ -326,16 +327,18 @@ class NewareBatteryTestSystem:
Args:
ip: TCP服务器IP地址
port: TCP端口
machine_ids: 设备ID列表
devtype: 设备类型标识
timeout: 通信超时时间(秒)
machine_id: 机器ID
size_x, size_y, size_z: 设备物理尺寸
oss_upload_enabled: 是否启用OSS上传功能默认False
oss_prefix: OSS对象路径前缀默认"neware_backup"
"""
self.ip = ip or self.BTS_IP
self.port = port or self.BTS_PORT
self.machine_id = machine_id
self.machine_ids = machine_ids
self.display_device_ids = self._resolve_display_device_ids()
self.primary_device_id = self.display_device_ids[0]
self.devtype = devtype or self.DEVTYPE
self.timeout = timeout or self.TIMEOUT
@@ -352,6 +355,12 @@ class NewareBatteryTestSystem:
self._cached_status = {}
self._last_backup_dir = None # 记录最近一次的 backup_dir供上传使用
self._ros_node: Optional[ROS2WorkstationNode] = None # ROS节点引用由框架设置
self._channels = self._build_channel_map()
def _resolve_display_device_ids(self) -> List[int]:
if self.machine_ids:
return [int(devid) for devid in self.machine_ids]
return self.DEFAULT_MACHINE_IDS.copy()
def post_init(self, ros_node):
@@ -376,27 +385,72 @@ class NewareBatteryTestSystem:
ros_node.lab_logger().error(f"新威电池测试系统初始化失败: {e}")
# 不抛出异常,允许节点继续运行,后续可以重试连接
def _plate_name(self, devid: int, plate_num: int) -> str:
return f"{devid}_P{plate_num}"
def _plate_resource_key(self, devid: int, plate_num: int, row_idx: int, col_idx: int) -> str:
return f"{self._plate_name(devid, plate_num)}_{self.LETTERS[row_idx]}{col_idx + 1}"
def _get_plate_resource(self, devid: int, plate_num: int, row_idx: int, col_idx: int):
possible_names = [
f"{self._plate_name(devid, plate_num)}_batterytestposition_{col_idx}_{row_idx}",
f"{self._plate_name(devid, plate_num)}_{self.LETTERS[row_idx]}{col_idx + 1}",
f"{self._plate_name(devid, plate_num)}_{self.LETTERS[row_idx].lower()}{col_idx + 1}",
f"P{plate_num}_batterytestposition_{col_idx}_{row_idx}",
f"P{plate_num}_{self.LETTERS[row_idx]}{col_idx + 1}",
f"P{plate_num}_{self.LETTERS[row_idx].lower()}{col_idx + 1}",
]
for name in possible_names:
if name in self.station_resources:
return self.station_resources[name], name, possible_names
return None, None, possible_names
def _setup_material_management(self):
"""设置物料管理系统"""
# 第1盘5行8列网格 (A1-E8) - 5行对应subdevid 1-58列对应chlid 1-8
# 先给物料设置一个最大的Deck并设置其在空间中的位置
deck_main = Deck("ADeckName", 2000, 1800, 100, origin=Coordinate(2000,2000,0))
plate1_resources: Dict[str, BatteryTestPosition] = create_ordered_items_2d(
BatteryTestPosition,
num_items_x=8, # 8列对应chlid 1-8
num_items_y=5, # 5行对应subdevid 1-5即A-E
dx=10,
dy=10,
dz=0,
item_dx=65,
item_dy=65
deck_main = Deck(
name="ADeckName",
size_x=2200,
size_y=2800,
size_z=100,
origin=Coordinate(2000, 2000, 0)
)
plate1 = Plate("P1", 400, 300, 50, ordered_items=plate1_resources)
deck_main.assign_child_resource(plate1, location=Coordinate(0, 0, 0))
# 只有在真实ROS环境下才调用update_resource
self.station_resources = {}
self.station_resources_by_plate = {}
for row_idx, devid in enumerate(self.display_device_ids):
for plate_num in (1, 2):
plate_resources: Dict[str, BatteryTestPosition] = create_ordered_items_2d(
BatteryTestPosition,
num_items_x=8,
num_items_y=5,
dx=10,
dy=10,
dz=0,
item_dx=65,
item_dy=65
)
plate_name = self._plate_name(devid, plate_num)
plate = Plate(
name=plate_name,
size_x=400,
size_y=300,
size_z=50,
ordered_items=plate_resources
)
location_x = 0 if plate_num == 1 else 450
location_y = row_idx * 350
deck_main.assign_child_resource(plate, location=Coordinate(location_x, location_y, 0))
plate_key = (devid, plate_num)
self.station_resources_by_plate[plate_key] = {}
for name, resource in plate_resources.items():
new_name = f"{plate_name}_{name}"
self.station_resources_by_plate[plate_key][new_name] = resource
self.station_resources[new_name] = resource
self.station_resources_plate1 = self.station_resources_by_plate.get((self.primary_device_id, 1), {})
self.station_resources_plate2 = self.station_resources_by_plate.get((self.primary_device_id, 2), {})
if hasattr(self._ros_node, 'update_resource') and callable(getattr(self._ros_node, 'update_resource')):
try:
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
@@ -405,40 +459,6 @@ class NewareBatteryTestSystem:
except Exception as e:
if hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().warning(f"更新资源失败: {e}")
# 在非ROS环境下忽略此错误
# 为第1盘资源添加P1_前缀
self.station_resources_plate1 = {}
for name, resource in plate1_resources.items():
new_name = f"P1_{name}"
self.station_resources_plate1[new_name] = resource
# 第2盘5行8列网格 (A1-E8)在Z轴上偏移 - 5行对应subdevid 6-108列对应chlid 1-8
plate2_resources = create_ordered_items_2d(
BatteryTestPosition,
num_items_x=8, # 8列对应chlid 1-8
num_items_y=5, # 5行对应subdevid 6-10即A-E
dx=10,
dy=10,
dz=0,
item_dx=65,
item_dy=65
)
plate2 = Plate("P2", 400, 300, 50, ordered_items=plate2_resources)
deck_main.assign_child_resource(plate2, location=Coordinate(0, 350, 0))
# 为第2盘资源添加P2_前缀
self.station_resources_plate2 = {}
for name, resource in plate2_resources.items():
new_name = f"P2_{name}"
self.station_resources_plate2[new_name] = resource
# 合并两盘资源为统一的station_resources
self.station_resources = {}
self.station_resources.update(self.station_resources_plate1)
self.station_resources.update(self.station_resources_plate2)
# ========================
# 核心属性Uni-Lab标准
@@ -469,16 +489,16 @@ class NewareBatteryTestSystem:
status_map = self._query_all_channels()
status_processed = {} if not status_map else self._group_by_devid(status_map)
# 修复数据过滤逻辑如果machine_id对应的数据不存在尝试使用第一个可用设备数据
status_current_machine = status_processed.get(self.machine_id, {})
# 返回主设备数据,如果主设备没有匹配数据则回退到首个可用设备
status_current_machine = status_processed.get(self.primary_device_id, {})
if not status_current_machine and status_processed:
# 如果machine_id没有匹配到数据,使用第一个可用的设备数据
# 如果主设备没有匹配到数据,使用第一个可用的设备数据
first_devid = next(iter(status_processed.keys()))
status_current_machine = status_processed[first_devid]
if self._ros_node:
self._ros_node.lab_logger().warning(
f"machine_id {self.machine_id} 没有匹配到数据使用设备ID {first_devid} 的数据"
f"主设备ID {self.primary_device_id} 没有匹配到数据使用设备ID {first_devid} 的数据"
)
# 确保有默认的数据结构
@@ -488,139 +508,57 @@ class NewareBatteryTestSystem:
"subunits": {}
}
# 确保subunits存在
subunits = status_current_machine.get("subunits", {})
# 处理2盘电池的状态映射
self._update_plate_resources(subunits)
self._update_plate_resources(status_processed)
return status_current_machine
def _update_plate_resources(self, subunits: Dict):
"""更新盘电池资源的状态"""
# 第1盘subdevid 1-5 映射到 8列5行网格 (列0-7, 行0-4)
for subdev_id in range(1, 6): # subdevid 1-5
status_row = subunits.get(subdev_id, {})
for chl_id in range(1, 9): # chlid 1-8
try:
# 根据用户描述:第一个是(0,0),最后一个是(7,4)
# 说明是8列5行列从0开始行从0开始
col_idx = (chl_id - 1) # 0-7 (chlid 1-8 -> 列0-7)
row_idx = (subdev_id - 1) # 0-4 (subdevid 1-5 -> 行0-4)
# 尝试多种可能的资源命名格式
possible_names = [
f"P1_batterytestposition_{col_idx}_{row_idx}", # 用户提到的格式
f"P1_{self.LETTERS[row_idx]}{col_idx + 1}", # 原有的A1-E8格式
f"P1_{self.LETTERS[row_idx].lower()}{col_idx + 1}", # 小写字母格式
]
r = None
resource_name = None
for name in possible_names:
if name in self.station_resources:
r = self.station_resources[name]
resource_name = name
break
if r:
status_channel = status_row.get(chl_id, {})
metrics = status_channel.get("metrics", {})
# 构建BatteryTestPosition状态数据移除capacity和energy
channel_state = {
# 基本测量数据
"voltage": metrics.get("voltage_V", 0.0),
"current": metrics.get("current_A", 0.0),
"time": metrics.get("totaltime_s", 0.0),
# 状态信息
"status": status_channel.get("state", "unknown"),
"color": status_channel.get("color", self.STATUS_COLOR["unknown"]),
# 通道名称标识
"Channel_Name": f"{self.machine_id}-{subdev_id}-{chl_id}",
}
r.load_state(channel_state)
# 调试信息
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"更新P1资源状态: {resource_name} <- subdev{subdev_id}/chl{chl_id} "
f"状态:{channel_state['status']}"
def _update_plate_resources(self, status_processed: Dict[int, Dict]):
"""更新7台设备共14盘电池资源的状态"""
for devid in self.display_device_ids:
machine_data = status_processed.get(devid, {})
subunits = machine_data.get("subunits", {})
for plate_num, subdev_start, subdev_end in ((1, 1, 5), (2, 6, 10)):
for subdev_id in range(subdev_start, subdev_end + 1):
status_row = subunits.get(subdev_id, {})
for chl_id in range(1, 9):
try:
col_idx = chl_id - 1
row_idx = subdev_id - subdev_start
r, resource_name, possible_names = self._get_plate_resource(
devid=devid,
plate_num=plate_num,
row_idx=row_idx,
col_idx=col_idx
)
else:
# 如果找不到资源,记录调试信息
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"P1未找到资源: subdev{subdev_id}/chl{chl_id} -> 尝试的名称: {possible_names}"
)
except (KeyError, IndexError) as e:
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(f"P1映射错误: subdev{subdev_id}/chl{chl_id} - {e}")
continue
# 第2盘subdevid 6-10 映射到 8列5行网格 (列0-7, 行0-4)
for subdev_id in range(6, 11): # subdevid 6-10
status_row = subunits.get(subdev_id, {})
for chl_id in range(1, 9): # chlid 1-8
try:
col_idx = (chl_id - 1) # 0-7 (chlid 1-8 -> 列0-7)
row_idx = (subdev_id - 6) # 0-4 (subdevid 6-10 -> 行0-4)
# 尝试多种可能的资源命名格式
possible_names = [
f"P2_batterytestposition_{col_idx}_{row_idx}", # 用户提到的格式
f"P2_{self.LETTERS[row_idx]}{col_idx + 1}", # 原有的A1-E8格式
f"P2_{self.LETTERS[row_idx].lower()}{col_idx + 1}", # 小写字母格式
]
r = None
resource_name = None
for name in possible_names:
if name in self.station_resources:
r = self.station_resources[name]
resource_name = name
break
if r:
status_channel = status_row.get(chl_id, {})
metrics = status_channel.get("metrics", {})
# 构建BatteryTestPosition状态数据移除capacity和energy
channel_state = {
# 基本测量数据
"voltage": metrics.get("voltage_V", 0.0),
"current": metrics.get("current_A", 0.0),
"time": metrics.get("totaltime_s", 0.0),
# 状态信息
"status": status_channel.get("state", "unknown"),
"color": status_channel.get("color", self.STATUS_COLOR["unknown"]),
# 通道名称标识
"Channel_Name": f"{self.machine_id}-{subdev_id}-{chl_id}",
}
r.load_state(channel_state)
# 调试信息
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"更新P2资源状态: {resource_name} <- subdev{subdev_id}/chl{chl_id} "
f"状态:{channel_state['status']}"
)
else:
# 如果找不到资源,记录调试信息
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"P2未找到资源: subdev{subdev_id}/chl{chl_id} -> 尝试的名称: {possible_names}"
)
except (KeyError, IndexError) as e:
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(f"P2映射错误: subdev{subdev_id}/chl{chl_id} - {e}")
continue
if r is None:
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"{devid}_P{plate_num}未找到资源: subdev{subdev_id}/chl{chl_id} -> "
f"尝试的名称: {possible_names}"
)
continue
status_channel = status_row.get(chl_id, {})
metrics = status_channel.get("metrics", {})
channel_state = {
"voltage": metrics.get("voltage_V", 0.0),
"current": metrics.get("current_A", 0.0),
"time": metrics.get("totaltime_s", 0.0),
"status": status_channel.get("state", "unknown"),
"color": status_channel.get("color", self.STATUS_COLOR["unknown"]),
"Channel_Name": f"{devid}-{subdev_id}-{chl_id}",
}
r.load_state(channel_state)
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"更新{devid}_P{plate_num}资源状态: {resource_name} <- "
f"subdev{subdev_id}/chl{chl_id} 状态:{channel_state['status']}"
)
except (KeyError, IndexError) as e:
if self._ros_node and hasattr(self._ros_node, 'lab_logger'):
self._ros_node.lab_logger().debug(
f"{devid}_P{plate_num}映射错误: subdev{subdev_id}/chl{chl_id} - {e}"
)
continue
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
"resources": list(self.station_resources.values())
})
@@ -640,6 +578,22 @@ class NewareBatteryTestSystem:
"""获取总通道数"""
return len(self._channels)
def _build_device_summary_dict(self) -> dict:
if not hasattr(self, '_channels') or not self._channels:
self._channels = self._build_channel_map()
channel_count_by_devid = {}
for channel in self._channels:
devid = channel.devid
channel_count_by_devid[devid] = channel_count_by_devid.get(devid, 0) + 1
return {
"channel_count_by_devid": channel_count_by_devid,
"display_device_ids": self.display_device_ids,
"total_channels": len(self._channels)
}
def device_summary(self) -> str:
return json.dumps(self._build_device_summary_dict(), ensure_ascii=False)
# ========================
# 设备动作方法Uni-Lab标准
# ========================
@@ -964,6 +918,7 @@ class NewareBatteryTestSystem:
'SIGR_LI': gen_mod.xml_SiGr_Li_Step,
'811_SIGR': gen_mod.xml_811_SiGr,
'811_CU_AGING': gen_mod.xml_811_Cu_aging,
'ZQXNLRMO':gen_mod.xml_ZQXNLRMO,
}
if key not in fmap:
raise ValueError(f"未定义电池体系映射: {key}")
@@ -1141,16 +1096,7 @@ class NewareBatteryTestSystem:
dict: ROS2动作结果格式 {"return_info": str, "success": bool}
"""
try:
# 确保_channels已初始化
if not hasattr(self, '_channels') or not self._channels:
self._channels = self._build_channel_map()
summary = {}
for channel in self._channels:
devid = channel.devid
summary[devid] = summary.get(devid, 0) + 1
result_info = json.dumps(summary, ensure_ascii=False)
result_info = self.device_summary()
success_msg = f"设备摘要统计: {result_info}"
if self._ros_node:
self._ros_node.lab_logger().info(success_msg)

View File

@@ -0,0 +1,49 @@
import socket
END_MARKS = [b"\r\n#\r\n", b"</bts>"] # 读到任一标志即可判定完整响应
def build_start_command(devid, subdevid, chlid, CoinID,
ip_in_xml="127.0.0.1",
devtype:int=27,
recipe_path:str=f"D:\\HHM_test\\A001.xml",
backup_dir:str=f"D:\\HHM_test\\backup") -> str:
lines = [
'<?xml version="1.0" encoding="UTF-8"?>',
'<bts version="1.0">',
' <cmd>start</cmd>',
' <list count="1">',
f' <start ip="{ip_in_xml}" devtype="{devtype}" devid="{devid}" subdevid="{subdevid}" chlid="{chlid}" barcode="{CoinID}">{recipe_path}</start>',
f' <backup backupdir="{backup_dir}" remotedir="" filenametype="1" customfilename="" createdirbydate="0" filetype="0" backupontime="1" backupontimeinterval="1" backupfree="0" />',
' </list>',
'</bts>',
]
# TCP 模式:请求必须以 #\r\n 结束(协议要求)
return "\r\n".join(lines) + "\r\n#\r\n"
def recv_until_marks(sock: socket.socket, timeout=60):
sock.settimeout(timeout) # 上限给足,协议允许到 30s:contentReference[oaicite:2]{index=2}
buf = bytearray()
while True:
chunk = sock.recv(8192)
if not chunk:
break
buf += chunk
# 读到结束标志就停,避免等对端断开
for m in END_MARKS:
if m in buf:
return bytes(buf)
# 保险:读到完整 XML 结束标签也停
if b"</bts>" in buf:
return bytes(buf)
return bytes(buf)
def start_test(ip="127.0.0.1", port=502, devid=3, subdevid=2, chlid=1, CoinID="A001", recipe_path=f"D:\\HHM_test\\A001.xml", backup_dir=f"D:\\HHM_test\\backup"):
xml_cmd = build_start_command(devid=devid, subdevid=subdevid, chlid=chlid, CoinID=CoinID, recipe_path=recipe_path, backup_dir=backup_dir)
#print(xml_cmd)
with socket.create_connection((ip, port), timeout=60) as s:
s.sendall(xml_cmd.encode("utf-8"))
data = recv_until_marks(s, timeout=60)
return data.decode("utf-8", errors="replace")
if __name__ == "__main__":
resp = start_test(ip="127.0.0.1", port=502, devid=4, subdevid=10, chlid=1, CoinID="A001", recipe_path=f"D:\\HHM_test\\A001.xml", backup_dir=f"D:\\HHM_test\\backup")
print(resp)

View File

@@ -1039,7 +1039,11 @@ class BioyondCellWorkstation(BioyondWorkstation):
logger.warning(f"[create_orders_formulation] 第 {idx + 1} 个配方无有效物料,跳过")
continue
item_mix_time = mix_time[idx] if idx < len(mix_time) else 0
raw_mix_time = mix_time[idx] if idx < len(mix_time) else None
try:
item_mix_time = int(raw_mix_time) if raw_mix_time not in (None, "", "null") else 0
except (ValueError, TypeError):
item_mix_time = 0
logger.info(f"[create_orders_formulation] 第 {idx + 1} 个配方: orderName={order_name}, "
f"coinCellVolume={coin_cell_volume}, pouchCellVolume={pouch_cell_volume}, "
f"conductivityVolume={conductivity_volume}, totalMass={total_mass}, "

View File

@@ -161,7 +161,9 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
logger.info("没有传入依华deck检查启动json文件")
super().__init__(deck=deck, *args, **kwargs,)
self.debug_mode = debug_mode
self._modbus_address = address
self._modbus_port = port
""" 连接初始化 """
modbus_client = TCPClient(addr=address, port=port)
logger.debug(f"创建 Modbus 客户端: {modbus_client}")
@@ -178,9 +180,11 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
raise ValueError('modbus tcp connection failed')
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_b.csv'))
self.client = modbus_client.register_node_list(self.nodes)
self._modbus_client_raw = modbus_client
else:
print("测试模式,跳过连接")
self.nodes, self.client = None, None
self._modbus_client_raw = None
""" 工站的配置 """
@@ -191,6 +195,32 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
self.csv_export_file = None
self.coin_num_N = 0 #已组装电池数量
def _ensure_modbus_connected(self) -> None:
"""检查 Modbus TCP 连接是否存活,若已断开则自动重连(防止长时间空闲后连接超时)"""
if self.debug_mode or self._modbus_client_raw is None:
return
raw_client = self._modbus_client_raw.client
if raw_client.is_socket_open():
return
logger.warning("[Modbus] 检测到连接已断开,尝试重连...")
try:
raw_client.close()
except Exception:
pass
count = 10
while count > 0:
count -= 1
try:
raw_client.connect()
except Exception:
pass
if raw_client.is_socket_open():
break
time.sleep(2)
if not raw_client.is_socket_open():
raise RuntimeError(f"Modbus TCP 重连失败({self._modbus_address}:{self._modbus_port}),请检查设备连接")
logger.info("[Modbus] 重连成功")
def post_init(self, ros_node: ROS2WorkstationNode):
self._ros_node = ros_node
@@ -1056,6 +1086,7 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
# 步骤0: 前置条件检查
logger.info("\n【步骤 0/4】前置条件检查...")
self._ensure_modbus_connected()
try:
# 检查 REG_UNILAB_INTERACT (应该为False表示使用Unilab交互)
unilab_interact_node = self.client.use_node('REG_UNILAB_INTERACT')

View File

@@ -102,7 +102,7 @@ coincellassemblyworkstation_device:
goal:
properties:
assembly_pressure:
default: 4200
default: 3200
description: 电池压制力(N)
type: integer
assembly_type:
@@ -118,7 +118,7 @@ coincellassemblyworkstation_device:
description: 是否启用压力模式
type: boolean
dual_drop_first_volume:
default: 25
default: 0
description: 二次滴液第一次排液体积(μL)
type: integer
dual_drop_mode:
@@ -137,6 +137,7 @@ coincellassemblyworkstation_device:
description: 电解液瓶数
type: string
elec_use_num:
default: 5
description: 每瓶电解液组装电池数
type: string
elec_vol:
@@ -144,7 +145,7 @@ coincellassemblyworkstation_device:
description: 电解液吸液量(μL)
type: integer
file_path:
default: /Users/sml/work
default: D:\UniLabdev\Uni-Lab-OS\unilabos\devices\workstation\coin_cell_assembly
description: 实验记录保存路径
type: string
fujipian_juzhendianwei:

View File

@@ -324,7 +324,7 @@ neware_battery_test_system:
status_types:
channel_status: Dict[int, Dict]
connection_info: Dict[str, str]
device_summary: dict
device_summary: str
status: str
total_channels: int
type: python
@@ -339,9 +339,18 @@ neware_battery_test_system:
type: string
ip:
type: string
machine_id:
default: 1
type: integer
machine_ids:
default:
- 1
- 2
- 3
- 4
- 5
- 6
- 86
items:
type: integer
type: array
oss_prefix:
default: neware_backup
type: string
@@ -374,7 +383,7 @@ neware_battery_test_system:
type: string
type: object
device_summary:
type: object
type: string
status:
type: string
total_channels: