mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-04 21:35:09 +00:00
Compare commits
1 Commits
a64ccfdb50
...
workstatio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
936834f8c3 |
32
fix_datatype.py
Normal file
32
fix_datatype.py
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
filepath = r'd:\UniLab\Uni-Lab-OS\unilabos\device_comms\modbus_plc\modbus.py'
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Replace the DataType placeholder with actual enum
|
||||
find_pattern = r'# DataType will be accessed via client instance.*?DataType = None # Placeholder.*?\n'
|
||||
replacement = '''# Define DataType enum for pymodbus 2.5.3 compatibility
|
||||
class DataType(Enum):
|
||||
INT16 = "int16"
|
||||
UINT16 = "uint16"
|
||||
INT32 = "int32"
|
||||
UINT32 = "uint32"
|
||||
INT64 = "int64"
|
||||
UINT64 = "uint64"
|
||||
FLOAT32 = "float32"
|
||||
FLOAT64 = "float64"
|
||||
STRING = "string"
|
||||
BOOL = "bool"
|
||||
|
||||
'''
|
||||
|
||||
new_content = re.sub(find_pattern, replacement, content, flags=re.DOTALL)
|
||||
|
||||
with open(filepath, 'w', encoding='utf-8') as f:
|
||||
f.write(new_content)
|
||||
|
||||
print('File updated successfully!')
|
||||
@@ -1,3 +1,4 @@
|
||||
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
@@ -92,4 +93,6 @@
|
||||
}
|
||||
],
|
||||
"links": []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,7 @@ import traceback
|
||||
from typing import Any, Union, List, Dict, Callable, Optional, Tuple
|
||||
from pydantic import BaseModel
|
||||
|
||||
from pymodbus.client import ModbusSerialClient, ModbusTcpClient
|
||||
from pymodbus.framer import FramerType
|
||||
from pymodbus.client.sync import ModbusSerialClient, ModbusTcpClient
|
||||
from typing import TypedDict
|
||||
|
||||
from unilabos.device_comms.modbus_plc.modbus import DeviceType, HoldRegister, Coil, InputRegister, DiscreteInputs, DataType, WorderOrder
|
||||
@@ -403,7 +402,7 @@ class TCPClient(BaseClient):
|
||||
class RTUClient(BaseClient):
|
||||
def __init__(self, port: str, baudrate: int, timeout: int):
|
||||
super().__init__()
|
||||
self._set_client(ModbusSerialClient(framer=FramerType.RTU, port=port, baudrate=baudrate, timeout=timeout))
|
||||
self._set_client(ModbusSerialClient(method='rtu', port=port, baudrate=baudrate, timeout=timeout))
|
||||
self._connect()
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
# coding=utf-8
|
||||
from enum import Enum
|
||||
from abc import ABC, abstractmethod
|
||||
from typing import Tuple, Union, Optional, TYPE_CHECKING
|
||||
from pymodbus.payload import BinaryPayloadDecoder, BinaryPayloadBuilder
|
||||
from pymodbus.constants import Endian
|
||||
|
||||
from pymodbus.client import ModbusBaseSyncClient
|
||||
from pymodbus.client.mixin import ModbusClientMixin
|
||||
from typing import Tuple, Union, Optional
|
||||
if TYPE_CHECKING:
|
||||
from pymodbus.client.sync import ModbusSerialClient, ModbusTcpClient
|
||||
|
||||
# Define DataType enum for pymodbus 2.5.3 compatibility
|
||||
class DataType(Enum):
|
||||
INT16 = "int16"
|
||||
UINT16 = "uint16"
|
||||
INT32 = "int32"
|
||||
UINT32 = "uint32"
|
||||
INT64 = "int64"
|
||||
UINT64 = "uint64"
|
||||
FLOAT32 = "float32"
|
||||
FLOAT64 = "float64"
|
||||
STRING = "string"
|
||||
BOOL = "bool"
|
||||
|
||||
DataType = ModbusClientMixin.DATATYPE
|
||||
|
||||
class WorderOrder(Enum):
|
||||
BIG = "big"
|
||||
@@ -19,8 +33,96 @@ class DeviceType(Enum):
|
||||
INPUT_REGISTER = 'input_register'
|
||||
|
||||
|
||||
def _convert_from_registers(registers, data_type: DataType, word_order: str = 'big'):
|
||||
"""Convert registers to a value using BinaryPayloadDecoder.
|
||||
|
||||
Args:
|
||||
registers: List of register values
|
||||
data_type: DataType enum specifying the target data type
|
||||
word_order: 'big' or 'little' endian
|
||||
|
||||
Returns:
|
||||
Converted value
|
||||
"""
|
||||
# Determine byte and word order based on word_order parameter
|
||||
if word_order == 'little':
|
||||
byte_order = Endian.Little
|
||||
word_order_enum = Endian.Little
|
||||
else:
|
||||
byte_order = Endian.Big
|
||||
word_order_enum = Endian.Big
|
||||
|
||||
decoder = BinaryPayloadDecoder.fromRegisters(registers, byteorder=byte_order, wordorder=word_order_enum)
|
||||
|
||||
if data_type == DataType.INT16:
|
||||
return decoder.decode_16bit_int()
|
||||
elif data_type == DataType.UINT16:
|
||||
return decoder.decode_16bit_uint()
|
||||
elif data_type == DataType.INT32:
|
||||
return decoder.decode_32bit_int()
|
||||
elif data_type == DataType.UINT32:
|
||||
return decoder.decode_32bit_uint()
|
||||
elif data_type == DataType.INT64:
|
||||
return decoder.decode_64bit_int()
|
||||
elif data_type == DataType.UINT64:
|
||||
return decoder.decode_64bit_uint()
|
||||
elif data_type == DataType.FLOAT32:
|
||||
return decoder.decode_32bit_float()
|
||||
elif data_type == DataType.FLOAT64:
|
||||
return decoder.decode_64bit_float()
|
||||
elif data_type == DataType.STRING:
|
||||
return decoder.decode_string(len(registers) * 2)
|
||||
else:
|
||||
raise ValueError(f"Unsupported data type: {data_type}")
|
||||
|
||||
|
||||
def _convert_to_registers(value, data_type: DataType, word_order: str = 'little'):
|
||||
"""Convert a value to registers using BinaryPayloadBuilder.
|
||||
|
||||
Args:
|
||||
value: Value to convert
|
||||
data_type: DataType enum specifying the source data type
|
||||
word_order: 'big' or 'little' endian
|
||||
|
||||
Returns:
|
||||
List of register values
|
||||
"""
|
||||
# Determine byte and word order based on word_order parameter
|
||||
if word_order == 'little':
|
||||
byte_order = Endian.Little
|
||||
word_order_enum = Endian.Little
|
||||
else:
|
||||
byte_order = Endian.Big
|
||||
word_order_enum = Endian.Big
|
||||
|
||||
builder = BinaryPayloadBuilder(byteorder=byte_order, wordorder=word_order_enum)
|
||||
|
||||
if data_type == DataType.INT16:
|
||||
builder.add_16bit_int(value)
|
||||
elif data_type == DataType.UINT16:
|
||||
builder.add_16bit_uint(value)
|
||||
elif data_type == DataType.INT32:
|
||||
builder.add_32bit_int(value)
|
||||
elif data_type == DataType.UINT32:
|
||||
builder.add_32bit_uint(value)
|
||||
elif data_type == DataType.INT64:
|
||||
builder.add_64bit_int(value)
|
||||
elif data_type == DataType.UINT64:
|
||||
builder.add_64bit_uint(value)
|
||||
elif data_type == DataType.FLOAT32:
|
||||
builder.add_32bit_float(value)
|
||||
elif data_type == DataType.FLOAT64:
|
||||
builder.add_64bit_float(value)
|
||||
elif data_type == DataType.STRING:
|
||||
builder.add_string(value)
|
||||
else:
|
||||
raise ValueError(f"Unsupported data type: {data_type}")
|
||||
|
||||
return builder.to_registers()
|
||||
|
||||
|
||||
class Base(ABC):
|
||||
def __init__(self, client: ModbusBaseSyncClient, name: str, address: int, typ: DeviceType, data_type: DataType):
|
||||
def __init__(self, client, name: str, address: int, typ: DeviceType, data_type):
|
||||
self._address: int = address
|
||||
self._client = client
|
||||
self._name = name
|
||||
@@ -58,7 +160,11 @@ class Coil(Base):
|
||||
count = value,
|
||||
slave = slave)
|
||||
|
||||
return resp.bits, resp.isError()
|
||||
# 检查是否读取出错
|
||||
if resp.isError():
|
||||
return [], True
|
||||
|
||||
return resp.bits, False
|
||||
|
||||
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
||||
if isinstance(value, list):
|
||||
@@ -91,8 +197,18 @@ class DiscreteInputs(Base):
|
||||
count = value,
|
||||
slave = slave)
|
||||
|
||||
# 检查是否读取出错
|
||||
if resp.isError():
|
||||
# 根据数据类型返回默认值
|
||||
if data_type in [DataType.FLOAT32, DataType.FLOAT64]:
|
||||
return 0.0, True
|
||||
elif data_type == DataType.STRING:
|
||||
return "", True
|
||||
else:
|
||||
return 0, True
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
||||
return _convert_from_registers(resp.registers, data_type, word_order=word_order.value), False
|
||||
|
||||
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
||||
raise ValueError('discrete inputs only support read')
|
||||
@@ -112,8 +228,19 @@ class HoldRegister(Base):
|
||||
address = self.address,
|
||||
count = value,
|
||||
slave = slave)
|
||||
|
||||
# 检查是否读取出错
|
||||
if resp.isError():
|
||||
# 根据数据类型返回默认值
|
||||
if data_type in [DataType.FLOAT32, DataType.FLOAT64]:
|
||||
return 0.0, True
|
||||
elif data_type == DataType.STRING:
|
||||
return "", True
|
||||
else:
|
||||
return 0, True
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
||||
return _convert_from_registers(resp.registers, data_type, word_order=word_order.value), False
|
||||
|
||||
|
||||
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
||||
@@ -132,7 +259,7 @@ class HoldRegister(Base):
|
||||
return self._client.write_register(self.address, value, slave= slave).isError()
|
||||
else:
|
||||
# noinspection PyTypeChecker
|
||||
encoder_resp = self._client.convert_to_registers(value, data_type=data_type, word_order=word_order.value)
|
||||
encoder_resp = _convert_to_registers(value, data_type=data_type, word_order=word_order.value)
|
||||
return self._client.write_registers(self.address, encoder_resp, slave=slave).isError()
|
||||
|
||||
|
||||
@@ -153,8 +280,19 @@ class InputRegister(Base):
|
||||
address = self.address,
|
||||
count = value,
|
||||
slave = slave)
|
||||
|
||||
# 检查是否读取出错
|
||||
if resp.isError():
|
||||
# 根据数据类型返回默认值
|
||||
if data_type in [DataType.FLOAT32, DataType.FLOAT64]:
|
||||
return 0.0, True
|
||||
elif data_type == DataType.STRING:
|
||||
return "", True
|
||||
else:
|
||||
return 0, True
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
||||
return _convert_from_registers(resp.registers, data_type, word_order=word_order.value), False
|
||||
|
||||
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
||||
raise ValueError('input register only support read')
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -257,7 +257,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
||||
def auto_feeding4to3(
|
||||
self,
|
||||
# ★ 修改点:默认模板路径
|
||||
xlsx_path: Optional[str] = "/Users/sml/work/Unilab/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx",
|
||||
xlsx_path: Optional[str] = "D:\\UniLab\\Uni-Lab-OS\\unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\material_template.xlsx",
|
||||
# ---------------- WH4 - 加样头面 (Z=1, 12个点位) ----------------
|
||||
WH4_x1_y1_z1_1_materialName: str = "", WH4_x1_y1_z1_1_quantity: float = 0.0,
|
||||
WH4_x2_y1_z1_2_materialName: str = "", WH4_x2_y1_z1_2_quantity: float = 0.0,
|
||||
@@ -478,7 +478,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
||||
- totalMass 自动计算为所有物料质量之和
|
||||
- createTime 缺失或为空时自动填充为当前日期(YYYY/M/D)
|
||||
"""
|
||||
default_path = Path("/Users/sml/work/Unilab/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx")
|
||||
default_path = Path("D:\\UniLab\\Uni-Lab-OS\\unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025122301.xlsx")
|
||||
path = Path(xlsx_path) if xlsx_path else default_path
|
||||
print(f"[create_orders] 使用 Excel 路径: {path}")
|
||||
if path != default_path:
|
||||
@@ -614,22 +614,63 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
||||
print(f"[create_orders] 即将提交订单数量: {len(orders)}")
|
||||
response = self._post_lims("/api/lims/order/orders", orders)
|
||||
print(f"[create_orders] 接口返回: {response}")
|
||||
# 等待任务报送成功
|
||||
|
||||
# 提取所有返回的 orderCode
|
||||
data_list = response.get("data", [])
|
||||
if data_list:
|
||||
order_code = data_list[0].get("orderCode")
|
||||
else:
|
||||
order_code = None
|
||||
|
||||
if not order_code:
|
||||
logger.error("上料任务未返回有效 orderCode!")
|
||||
if not data_list:
|
||||
logger.error("创建订单未返回有效数据!")
|
||||
return response
|
||||
# 等待完成报送
|
||||
result = self.wait_for_order_finish(order_code)
|
||||
|
||||
# 收集所有 orderCode
|
||||
order_codes = []
|
||||
for order_item in data_list:
|
||||
code = order_item.get("orderCode")
|
||||
if code:
|
||||
order_codes.append(code)
|
||||
|
||||
if not order_codes:
|
||||
logger.error("未找到任何有效的 orderCode!")
|
||||
return response
|
||||
|
||||
print(f"[create_orders] 等待 {len(order_codes)} 个订单完成: {order_codes}")
|
||||
|
||||
# 等待所有订单完成并收集报文
|
||||
all_reports = []
|
||||
for idx, order_code in enumerate(order_codes, 1):
|
||||
print(f"[create_orders] 正在等待第 {idx}/{len(order_codes)} 个订单: {order_code}")
|
||||
result = self.wait_for_order_finish(order_code)
|
||||
|
||||
# 提取报文数据
|
||||
if result.get("status") == "success":
|
||||
report = result.get("report", {})
|
||||
all_reports.append(report)
|
||||
print(f"[create_orders] ✓ 订单 {order_code} 完成")
|
||||
else:
|
||||
logger.warning(f"订单 {order_code} 状态异常: {result.get('status')}")
|
||||
# 即使订单失败,也记录下这个结果
|
||||
all_reports.append({
|
||||
"orderCode": order_code,
|
||||
"status": result.get("status"),
|
||||
"error": result.get("message", "未知错误")
|
||||
})
|
||||
|
||||
print(f"[create_orders] 所有订单已完成,共收集 {len(all_reports)} 个报文")
|
||||
print("实验记录本========================create_orders========================")
|
||||
print(result)
|
||||
|
||||
# 返回所有订单的完成报文
|
||||
final_result = {
|
||||
"status": "all_completed",
|
||||
"total_orders": len(order_codes),
|
||||
"reports": all_reports,
|
||||
"original_response": response
|
||||
}
|
||||
|
||||
print(f"返回报文数量: {len(all_reports)}")
|
||||
for i, report in enumerate(all_reports, 1):
|
||||
print(f"报文 {i}: orderCode={report.get('orderCode', 'N/A')}, status={report.get('status', 'N/A')}")
|
||||
print("========================")
|
||||
return result
|
||||
|
||||
return final_result
|
||||
|
||||
# 2.7 启动调度
|
||||
def scheduler_start(self) -> Dict[str, Any]:
|
||||
@@ -657,6 +698,146 @@ class BioyondCellWorkstation(BioyondWorkstation):
|
||||
"""
|
||||
return self._post_lims("/api/lims/scheduler/reset")
|
||||
|
||||
def scheduler_start_and_auto_feeding(
|
||||
self,
|
||||
# ★ Excel路径参数
|
||||
xlsx_path: Optional[str] = "D:\\UniLab\\Uni-Lab-OS\\unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\material_template.xlsx",
|
||||
# ---------------- WH4 - 加样头面 (Z=1, 12个点位) ----------------
|
||||
WH4_x1_y1_z1_1_materialName: str = "", WH4_x1_y1_z1_1_quantity: float = 0.0,
|
||||
WH4_x2_y1_z1_2_materialName: str = "", WH4_x2_y1_z1_2_quantity: float = 0.0,
|
||||
WH4_x3_y1_z1_3_materialName: str = "", WH4_x3_y1_z1_3_quantity: float = 0.0,
|
||||
WH4_x4_y1_z1_4_materialName: str = "", WH4_x4_y1_z1_4_quantity: float = 0.0,
|
||||
WH4_x5_y1_z1_5_materialName: str = "", WH4_x5_y1_z1_5_quantity: float = 0.0,
|
||||
WH4_x1_y2_z1_6_materialName: str = "", WH4_x1_y2_z1_6_quantity: float = 0.0,
|
||||
WH4_x2_y2_z1_7_materialName: str = "", WH4_x2_y2_z1_7_quantity: float = 0.0,
|
||||
WH4_x3_y2_z1_8_materialName: str = "", WH4_x3_y2_z1_8_quantity: float = 0.0,
|
||||
WH4_x4_y2_z1_9_materialName: str = "", WH4_x4_y2_z1_9_quantity: float = 0.0,
|
||||
WH4_x5_y2_z1_10_materialName: str = "", WH4_x5_y2_z1_10_quantity: float = 0.0,
|
||||
WH4_x1_y3_z1_11_materialName: str = "", WH4_x1_y3_z1_11_quantity: float = 0.0,
|
||||
WH4_x2_y3_z1_12_materialName: str = "", WH4_x2_y3_z1_12_quantity: float = 0.0,
|
||||
|
||||
# ---------------- WH4 - 原液瓶面 (Z=2, 9个点位) ----------------
|
||||
WH4_x1_y1_z2_1_materialName: str = "", WH4_x1_y1_z2_1_quantity: float = 0.0, WH4_x1_y1_z2_1_materialType: str = "", WH4_x1_y1_z2_1_targetWH: str = "",
|
||||
WH4_x2_y1_z2_2_materialName: str = "", WH4_x2_y1_z2_2_quantity: float = 0.0, WH4_x2_y1_z2_2_materialType: str = "", WH4_x2_y1_z2_2_targetWH: str = "",
|
||||
WH4_x3_y1_z2_3_materialName: str = "", WH4_x3_y1_z2_3_quantity: float = 0.0, WH4_x3_y1_z2_3_materialType: str = "", WH4_x3_y1_z2_3_targetWH: str = "",
|
||||
WH4_x1_y2_z2_4_materialName: str = "", WH4_x1_y2_z2_4_quantity: float = 0.0, WH4_x1_y2_z2_4_materialType: str = "", WH4_x1_y2_z2_4_targetWH: str = "",
|
||||
WH4_x2_y2_z2_5_materialName: str = "", WH4_x2_y2_z2_5_quantity: float = 0.0, WH4_x2_y2_z2_5_materialType: str = "", WH4_x2_y2_z2_5_targetWH: str = "",
|
||||
WH4_x3_y2_z2_6_materialName: str = "", WH4_x3_y2_z2_6_quantity: float = 0.0, WH4_x3_y2_z2_6_materialType: str = "", WH4_x3_y2_z2_6_targetWH: str = "",
|
||||
WH4_x1_y3_z2_7_materialName: str = "", WH4_x1_y3_z2_7_quantity: float = 0.0, WH4_x1_y3_z2_7_materialType: str = "", WH4_x1_y3_z2_7_targetWH: str = "",
|
||||
WH4_x2_y3_z2_8_materialName: str = "", WH4_x2_y3_z2_8_quantity: float = 0.0, WH4_x2_y3_z2_8_materialType: str = "", WH4_x2_y3_z2_8_targetWH: str = "",
|
||||
WH4_x3_y3_z2_9_materialName: str = "", WH4_x3_y3_z2_9_quantity: float = 0.0, WH4_x3_y3_z2_9_materialType: str = "", WH4_x3_y3_z2_9_targetWH: str = "",
|
||||
|
||||
# ---------------- WH3 - 人工堆栈 (Z=3, 15个点位) ----------------
|
||||
WH3_x1_y1_z3_1_materialType: str = "", WH3_x1_y1_z3_1_materialId: str = "", WH3_x1_y1_z3_1_quantity: float = 0,
|
||||
WH3_x2_y1_z3_2_materialType: str = "", WH3_x2_y1_z3_2_materialId: str = "", WH3_x2_y1_z3_2_quantity: float = 0,
|
||||
WH3_x3_y1_z3_3_materialType: str = "", WH3_x3_y1_z3_3_materialId: str = "", WH3_x3_y1_z3_3_quantity: float = 0,
|
||||
WH3_x1_y2_z3_4_materialType: str = "", WH3_x1_y2_z3_4_materialId: str = "", WH3_x1_y2_z3_4_quantity: float = 0,
|
||||
WH3_x2_y2_z3_5_materialType: str = "", WH3_x2_y2_z3_5_materialId: str = "", WH3_x2_y2_z3_5_quantity: float = 0,
|
||||
WH3_x3_y2_z3_6_materialType: str = "", WH3_x3_y2_z3_6_materialId: str = "", WH3_x3_y2_z3_6_quantity: float = 0,
|
||||
WH3_x1_y3_z3_7_materialType: str = "", WH3_x1_y3_z3_7_materialId: str = "", WH3_x1_y3_z3_7_quantity: float = 0,
|
||||
WH3_x2_y3_z3_8_materialType: str = "", WH3_x2_y3_z3_8_materialId: str = "", WH3_x2_y3_z3_8_quantity: float = 0,
|
||||
WH3_x3_y3_z3_9_materialType: str = "", WH3_x3_y3_z3_9_materialId: str = "", WH3_x3_y3_z3_9_quantity: float = 0,
|
||||
WH3_x1_y4_z3_10_materialType: str = "", WH3_x1_y4_z3_10_materialId: str = "", WH3_x1_y4_z3_10_quantity: float = 0,
|
||||
WH3_x2_y4_z3_11_materialType: str = "", WH3_x2_y4_z3_11_materialId: str = "", WH3_x2_y4_z3_11_quantity: float = 0,
|
||||
WH3_x3_y4_z3_12_materialType: str = "", WH3_x3_y4_z3_12_materialId: str = "", WH3_x3_y4_z3_12_quantity: float = 0,
|
||||
WH3_x1_y5_z3_13_materialType: str = "", WH3_x1_y5_z3_13_materialId: str = "", WH3_x1_y5_z3_13_quantity: float = 0,
|
||||
WH3_x2_y5_z3_14_materialType: str = "", WH3_x2_y5_z3_14_materialId: str = "", WH3_x2_y5_z3_14_quantity: float = 0,
|
||||
WH3_x3_y5_z3_15_materialType: str = "", WH3_x3_y5_z3_15_materialId: str = "", WH3_x3_y5_z3_15_quantity: float = 0,
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
组合函数:先启动调度,然后执行自动化上料
|
||||
|
||||
此函数简化了工作流操作,将两个有顺序依赖的操作组合在一起:
|
||||
1. 启动调度(scheduler_start)
|
||||
2. 自动化上料(auto_feeding4to3)
|
||||
|
||||
参数与 auto_feeding4to3 完全相同,支持 Excel 和手动参数两种模式
|
||||
|
||||
Returns:
|
||||
包含调度启动结果和上料结果的字典
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("开始执行组合操作:启动调度 + 自动化上料")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# 步骤1: 启动调度
|
||||
logger.info("【步骤 1/2】启动调度...")
|
||||
scheduler_result = self.scheduler_start()
|
||||
logger.info(f"调度启动结果: {scheduler_result}")
|
||||
|
||||
# 检查调度是否启动成功
|
||||
if scheduler_result.get("code") != 1:
|
||||
logger.error(f"调度启动失败: {scheduler_result}")
|
||||
return {
|
||||
"success": False,
|
||||
"step": "scheduler_start",
|
||||
"scheduler_result": scheduler_result,
|
||||
"error": "调度启动失败"
|
||||
}
|
||||
|
||||
logger.info("✓ 调度启动成功")
|
||||
|
||||
# 步骤2: 执行自动化上料
|
||||
logger.info("【步骤 2/2】执行自动化上料...")
|
||||
feeding_result = self.auto_feeding4to3(
|
||||
xlsx_path=xlsx_path,
|
||||
WH4_x1_y1_z1_1_materialName=WH4_x1_y1_z1_1_materialName, WH4_x1_y1_z1_1_quantity=WH4_x1_y1_z1_1_quantity,
|
||||
WH4_x2_y1_z1_2_materialName=WH4_x2_y1_z1_2_materialName, WH4_x2_y1_z1_2_quantity=WH4_x2_y1_z1_2_quantity,
|
||||
WH4_x3_y1_z1_3_materialName=WH4_x3_y1_z1_3_materialName, WH4_x3_y1_z1_3_quantity=WH4_x3_y1_z1_3_quantity,
|
||||
WH4_x4_y1_z1_4_materialName=WH4_x4_y1_z1_4_materialName, WH4_x4_y1_z1_4_quantity=WH4_x4_y1_z1_4_quantity,
|
||||
WH4_x5_y1_z1_5_materialName=WH4_x5_y1_z1_5_materialName, WH4_x5_y1_z1_5_quantity=WH4_x5_y1_z1_5_quantity,
|
||||
WH4_x1_y2_z1_6_materialName=WH4_x1_y2_z1_6_materialName, WH4_x1_y2_z1_6_quantity=WH4_x1_y2_z1_6_quantity,
|
||||
WH4_x2_y2_z1_7_materialName=WH4_x2_y2_z1_7_materialName, WH4_x2_y2_z1_7_quantity=WH4_x2_y2_z1_7_quantity,
|
||||
WH4_x3_y2_z1_8_materialName=WH4_x3_y2_z1_8_materialName, WH4_x3_y2_z1_8_quantity=WH4_x3_y2_z1_8_quantity,
|
||||
WH4_x4_y2_z1_9_materialName=WH4_x4_y2_z1_9_materialName, WH4_x4_y2_z1_9_quantity=WH4_x4_y2_z1_9_quantity,
|
||||
WH4_x5_y2_z1_10_materialName=WH4_x5_y2_z1_10_materialName, WH4_x5_y2_z1_10_quantity=WH4_x5_y2_z1_10_quantity,
|
||||
WH4_x1_y3_z1_11_materialName=WH4_x1_y3_z1_11_materialName, WH4_x1_y3_z1_11_quantity=WH4_x1_y3_z1_11_quantity,
|
||||
WH4_x2_y3_z1_12_materialName=WH4_x2_y3_z1_12_materialName, WH4_x2_y3_z1_12_quantity=WH4_x2_y3_z1_12_quantity,
|
||||
WH4_x1_y1_z2_1_materialName=WH4_x1_y1_z2_1_materialName, WH4_x1_y1_z2_1_quantity=WH4_x1_y1_z2_1_quantity,
|
||||
WH4_x1_y1_z2_1_materialType=WH4_x1_y1_z2_1_materialType, WH4_x1_y1_z2_1_targetWH=WH4_x1_y1_z2_1_targetWH,
|
||||
WH4_x2_y1_z2_2_materialName=WH4_x2_y1_z2_2_materialName, WH4_x2_y1_z2_2_quantity=WH4_x2_y1_z2_2_quantity,
|
||||
WH4_x2_y1_z2_2_materialType=WH4_x2_y1_z2_2_materialType, WH4_x2_y1_z2_2_targetWH=WH4_x2_y1_z2_2_targetWH,
|
||||
WH4_x3_y1_z2_3_materialName=WH4_x3_y1_z2_3_materialName, WH4_x3_y1_z2_3_quantity=WH4_x3_y1_z2_3_quantity,
|
||||
WH4_x3_y1_z2_3_materialType=WH4_x3_y1_z2_3_materialType, WH4_x3_y1_z2_3_targetWH=WH4_x3_y1_z2_3_targetWH,
|
||||
WH4_x1_y2_z2_4_materialName=WH4_x1_y2_z2_4_materialName, WH4_x1_y2_z2_4_quantity=WH4_x1_y2_z2_4_quantity,
|
||||
WH4_x1_y2_z2_4_materialType=WH4_x1_y2_z2_4_materialType, WH4_x1_y2_z2_4_targetWH=WH4_x1_y2_z2_4_targetWH,
|
||||
WH4_x2_y2_z2_5_materialName=WH4_x2_y2_z2_5_materialName, WH4_x2_y2_z2_5_quantity=WH4_x2_y2_z2_5_quantity,
|
||||
WH4_x2_y2_z2_5_materialType=WH4_x2_y2_z2_5_materialType, WH4_x2_y2_z2_5_targetWH=WH4_x2_y2_z2_5_targetWH,
|
||||
WH4_x3_y2_z2_6_materialName=WH4_x3_y2_z2_6_materialName, WH4_x3_y2_z2_6_quantity=WH4_x3_y2_z2_6_quantity,
|
||||
WH4_x3_y2_z2_6_materialType=WH4_x3_y2_z2_6_materialType, WH4_x3_y2_z2_6_targetWH=WH4_x3_y2_z2_6_targetWH,
|
||||
WH4_x1_y3_z2_7_materialName=WH4_x1_y3_z2_7_materialName, WH4_x1_y3_z2_7_quantity=WH4_x1_y3_z2_7_quantity,
|
||||
WH4_x1_y3_z2_7_materialType=WH4_x1_y3_z2_7_materialType, WH4_x1_y3_z2_7_targetWH=WH4_x1_y3_z2_7_targetWH,
|
||||
WH4_x2_y3_z2_8_materialName=WH4_x2_y3_z2_8_materialName, WH4_x2_y3_z2_8_quantity=WH4_x2_y3_z2_8_quantity,
|
||||
WH4_x2_y3_z2_8_materialType=WH4_x2_y3_z2_8_materialType, WH4_x2_y3_z2_8_targetWH=WH4_x2_y3_z2_8_targetWH,
|
||||
WH4_x3_y3_z2_9_materialName=WH4_x3_y3_z2_9_materialName, WH4_x3_y3_z2_9_quantity=WH4_x3_y3_z2_9_quantity,
|
||||
WH4_x3_y3_z2_9_materialType=WH4_x3_y3_z2_9_materialType, WH4_x3_y3_z2_9_targetWH=WH4_x3_y3_z2_9_targetWH,
|
||||
WH3_x1_y1_z3_1_materialType=WH3_x1_y1_z3_1_materialType, WH3_x1_y1_z3_1_materialId=WH3_x1_y1_z3_1_materialId, WH3_x1_y1_z3_1_quantity=WH3_x1_y1_z3_1_quantity,
|
||||
WH3_x2_y1_z3_2_materialType=WH3_x2_y1_z3_2_materialType, WH3_x2_y1_z3_2_materialId=WH3_x2_y1_z3_2_materialId, WH3_x2_y1_z3_2_quantity=WH3_x2_y1_z3_2_quantity,
|
||||
WH3_x3_y1_z3_3_materialType=WH3_x3_y1_z3_3_materialType, WH3_x3_y1_z3_3_materialId=WH3_x3_y1_z3_3_materialId, WH3_x3_y1_z3_3_quantity=WH3_x3_y1_z3_3_quantity,
|
||||
WH3_x1_y2_z3_4_materialType=WH3_x1_y2_z3_4_materialType, WH3_x1_y2_z3_4_materialId=WH3_x1_y2_z3_4_materialId, WH3_x1_y2_z3_4_quantity=WH3_x1_y2_z3_4_quantity,
|
||||
WH3_x2_y2_z3_5_materialType=WH3_x2_y2_z3_5_materialType, WH3_x2_y2_z3_5_materialId=WH3_x2_y2_z3_5_materialId, WH3_x2_y2_z3_5_quantity=WH3_x2_y2_z3_5_quantity,
|
||||
WH3_x3_y2_z3_6_materialType=WH3_x3_y2_z3_6_materialType, WH3_x3_y2_z3_6_materialId=WH3_x3_y2_z3_6_materialId, WH3_x3_y2_z3_6_quantity=WH3_x3_y2_z3_6_quantity,
|
||||
WH3_x1_y3_z3_7_materialType=WH3_x1_y3_z3_7_materialType, WH3_x1_y3_z3_7_materialId=WH3_x1_y3_z3_7_materialId, WH3_x1_y3_z3_7_quantity=WH3_x1_y3_z3_7_quantity,
|
||||
WH3_x2_y3_z3_8_materialType=WH3_x2_y3_z3_8_materialType, WH3_x2_y3_z3_8_materialId=WH3_x2_y3_z3_8_materialId, WH3_x2_y3_z3_8_quantity=WH3_x2_y3_z3_8_quantity,
|
||||
WH3_x3_y3_z3_9_materialType=WH3_x3_y3_z3_9_materialType, WH3_x3_y3_z3_9_materialId=WH3_x3_y3_z3_9_materialId, WH3_x3_y3_z3_9_quantity=WH3_x3_y3_z3_9_quantity,
|
||||
WH3_x1_y4_z3_10_materialType=WH3_x1_y4_z3_10_materialType, WH3_x1_y4_z3_10_materialId=WH3_x1_y4_z3_10_materialId, WH3_x1_y4_z3_10_quantity=WH3_x1_y4_z3_10_quantity,
|
||||
WH3_x2_y4_z3_11_materialType=WH3_x2_y4_z3_11_materialType, WH3_x2_y4_z3_11_materialId=WH3_x2_y4_z3_11_materialId, WH3_x2_y4_z3_11_quantity=WH3_x2_y4_z3_11_quantity,
|
||||
WH3_x3_y4_z3_12_materialType=WH3_x3_y4_z3_12_materialType, WH3_x3_y4_z3_12_materialId=WH3_x3_y4_z3_12_materialId, WH3_x3_y4_z3_12_quantity=WH3_x3_y4_z3_12_quantity,
|
||||
WH3_x1_y5_z3_13_materialType=WH3_x1_y5_z3_13_materialType, WH3_x1_y5_z3_13_materialId=WH3_x1_y5_z3_13_materialId, WH3_x1_y5_z3_13_quantity=WH3_x1_y5_z3_13_quantity,
|
||||
WH3_x2_y5_z3_14_materialType=WH3_x2_y5_z3_14_materialType, WH3_x2_y5_z3_14_materialId=WH3_x2_y5_z3_14_materialId, WH3_x2_y5_z3_14_quantity=WH3_x2_y5_z3_14_quantity,
|
||||
WH3_x3_y5_z3_15_materialType=WH3_x3_y5_z3_15_materialType, WH3_x3_y5_z3_15_materialId=WH3_x3_y5_z3_15_materialId, WH3_x3_y5_z3_15_quantity=WH3_x3_y5_z3_15_quantity,
|
||||
)
|
||||
|
||||
logger.info("=" * 60)
|
||||
logger.info("组合操作完成")
|
||||
logger.info("=" * 60)
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"scheduler_result": scheduler_result,
|
||||
"feeding_result": feeding_result
|
||||
}
|
||||
|
||||
|
||||
# 2.24 物料变更推送
|
||||
def report_material_change(self, material_obj: Dict[str, Any]) -> Dict[str, Any]:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,197 @@
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.2148671+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a082-c44a-60be-68647a35e6f1",
|
||||
"orderCode": "BSO2025122400024",
|
||||
"orderName": "DP20251224001",
|
||||
"startTime": "2025-12-24T14:51:50.549848",
|
||||
"endTime": "2025-12-24T15:32:09.000765",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"completionTime": "2025-12-24T15:32:09.000765",
|
||||
"usedMaterials": [
|
||||
{
|
||||
"materialId": "3a1e614b-53a6-0ec4-10bd-956b240c0f04",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-4da7-cf62-3a40-7e5879255c0c",
|
||||
"locationId": "3a1a224d-ed49-710c-a9c3-3fc61d479cbb",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-53a7-2850-42c8-a7a2de8ff4bf",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-4da6-ac9d-02be-4b0716796bd2",
|
||||
"locationId": "3a1a224d-ed49-710c-a9c3-3fc61d479cbb",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614d-9c9a-fafa-4757-c7411b03bd9f",
|
||||
"locationId": "3a1abd46-18fe-1f56-6ced-a1f7fe08e36c",
|
||||
"typemode": "0",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6917-b8f9-7987-7a33a3792829",
|
||||
"locationId": "3a19da43-57b5-294f-d663-154a1cc32270",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 3.51,
|
||||
"realQuantity": 3.5155000000000000000000000000
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6914-d92b-e348-f52e13817a5d",
|
||||
"locationId": "3a19da56-1379-ff7c-1745-07e200b44ce2",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 0.33,
|
||||
"realQuantity": 0.3336000000000000000000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.9999039+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0a2-f7a9-9360-610021c9479d",
|
||||
"orderCode": "BSO2025122400025",
|
||||
"orderName": "DP20251224002",
|
||||
"startTime": "2025-12-24T14:53:03.44259",
|
||||
"endTime": "2025-12-24T15:32:09.828261",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"completionTime": "2025-12-24T15:32:09.828261",
|
||||
"usedMaterials": [
|
||||
{
|
||||
"materialId": "3a1e614b-4da7-6527-9f1c-b39e3de8ff2b",
|
||||
"locationId": "3a1a224d-ed49-710c-a9c3-3fc61d479cbb",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-53a6-0ec4-10bd-956b240c0f04",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-4da6-ac9d-02be-4b0716796bd2",
|
||||
"locationId": "3a1a224d-ed49-710c-a9c3-3fc61d479cbb",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-53a8-8474-cac8-0fd7d349e4b2",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614d-9c9a-fafa-4757-c7411b03bd9f",
|
||||
"locationId": null,
|
||||
"typemode": "0",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6917-b8f9-7987-7a33a3792829",
|
||||
"locationId": "3a19da43-57b5-294f-d663-154a1cc32270",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 0.7,
|
||||
"realQuantity": 0
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6914-d92b-e348-f52e13817a5d",
|
||||
"locationId": "3a19da56-1379-ff7c-1745-07e200b44ce2",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 1.15,
|
||||
"realQuantity": 1.1627000000000000000000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:34:00.4139986+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0cd-81ca-9f7f-2f4e93af01cd",
|
||||
"orderCode": "BSO2025122400026",
|
||||
"orderName": "DP20251224003",
|
||||
"startTime": "2025-12-24T14:54:24.443344",
|
||||
"endTime": "2025-12-24T15:34:00.26321",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"completionTime": "2025-12-24T15:34:00.26321",
|
||||
"usedMaterials": [
|
||||
{
|
||||
"materialId": "3a1e614b-4da6-ac9d-02be-4b0716796bd2",
|
||||
"locationId": "3a19deae-2c7a-b9eb-f4e3-e308e0cf839a",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-4da8-b678-f204-207076f09c83",
|
||||
"locationId": "3a19deae-2c7a-b9eb-f4e3-e308e0cf839a",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-53a6-0ec4-10bd-956b240c0f04",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 2,
|
||||
"realQuantity": 2
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-53a8-e3f2-dee0-fa97b600b652",
|
||||
"locationId": "3a19debc-84b5-4c1c-d3a1-26830cf273ff",
|
||||
"typemode": "1",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614d-9c9a-fafa-4757-c7411b03bd9f",
|
||||
"locationId": null,
|
||||
"typemode": "0",
|
||||
"usedQuantity": 1,
|
||||
"realQuantity": 1
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6917-b8f9-7987-7a33a3792829",
|
||||
"locationId": "3a19da43-57b5-294f-d663-154a1cc32270",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 2.0,
|
||||
"realQuantity": 2.0075000000000000000000000000
|
||||
},
|
||||
{
|
||||
"materialId": "3a1e614b-6914-d92b-e348-f52e13817a5d",
|
||||
"locationId": "3a19da56-1379-ff7c-1745-07e200b44ce2",
|
||||
"typemode": "2",
|
||||
"usedQuantity": 1.2,
|
||||
"realQuantity": 1.2126000000000000000000000000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
# Bioyond Cell 工作站 - 多订单返回示例
|
||||
|
||||
本文档说明了 `create_orders` 函数如何收集并返回所有订单的完成报文。
|
||||
|
||||
## 问题描述
|
||||
|
||||
之前的实现只会等待并返回第一个订单的完成报文,如果有多个订单(例如从 Excel 解析出 3 个订单),只能得到第一个订单的推送信息。
|
||||
|
||||
## 解决方案
|
||||
|
||||
修改后的 `create_orders` 函数现在会:
|
||||
|
||||
1. **提取所有 orderCode**:从 LIMS 接口返回的 `data` 列表中提取所有订单编号
|
||||
2. **逐个等待完成**:遍历所有 orderCode,调用 `wait_for_order_finish` 等待每个订单完成
|
||||
3. **收集所有报文**:将每个订单的完成报文存入 `all_reports` 列表
|
||||
4. **统一返回**:返回包含所有订单报文的 JSON 格式数据
|
||||
|
||||
## 返回格式
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "all_completed",
|
||||
"total_orders": 3,
|
||||
"reports": [
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.2148671+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a082-c44a-60be-68647a35e6f1",
|
||||
"orderCode": "BSO2025122400024",
|
||||
"orderName": "DP20251224001",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
},
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:32:09.9999039+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0a2-f7a9-9360-610021c9479d",
|
||||
"orderCode": "BSO2025122400025",
|
||||
"orderName": "DP20251224002",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
},
|
||||
{
|
||||
"token": "",
|
||||
"request_time": "2025-12-24T15:34:00.4139986+08:00",
|
||||
"data": {
|
||||
"orderId": "3a1e614d-a0cd-81ca-9f7f-2f4e93af01cd",
|
||||
"orderCode": "BSO2025122400026",
|
||||
"orderName": "DP20251224003",
|
||||
"status": "30",
|
||||
"workflowStatus": "completed",
|
||||
"usedMaterials": [...]
|
||||
}
|
||||
}
|
||||
],
|
||||
"original_response": {...}
|
||||
}
|
||||
```
|
||||
|
||||
## 使用示例
|
||||
|
||||
```python
|
||||
# 调用 create_orders
|
||||
result = workstation.create_orders("20251224.xlsx")
|
||||
|
||||
# 访问返回数据
|
||||
print(f"总订单数: {result['total_orders']}")
|
||||
print(f"状态: {result['status']}")
|
||||
|
||||
# 遍历所有订单的报文
|
||||
for i, report in enumerate(result['reports'], 1):
|
||||
order_data = report.get('data', {})
|
||||
print(f"\n订单 {i}:")
|
||||
print(f" orderCode: {order_data.get('orderCode')}")
|
||||
print(f" orderName: {order_data.get('orderName')}")
|
||||
print(f" status: {order_data.get('status')}")
|
||||
print(f" 使用物料数: {len(order_data.get('usedMaterials', []))}")
|
||||
```
|
||||
|
||||
## 控制台输出示例
|
||||
|
||||
```
|
||||
[create_orders] 即将提交订单数量: 3
|
||||
[create_orders] 接口返回: {...}
|
||||
[create_orders] 等待 3 个订单完成: ['BSO2025122400024', 'BSO2025122400025', 'BSO2025122400026']
|
||||
[create_orders] 正在等待第 1/3 个订单: BSO2025122400024
|
||||
[create_orders] ✓ 订单 BSO2025122400024 完成
|
||||
[create_orders] 正在等待第 2/3 个订单: BSO2025122400025
|
||||
[create_orders] ✓ 订单 BSO2025122400025 完成
|
||||
[create_orders] 正在等待第 3/3 个订单: BSO2025122400026
|
||||
[create_orders] ✓ 订单 BSO2025122400026 完成
|
||||
[create_orders] 所有订单已完成,共收集 3 个报文
|
||||
实验记录本========================create_orders========================
|
||||
返回报文数量: 3
|
||||
报文 1: orderCode=BSO2025122400024, status=30
|
||||
报文 2: orderCode=BSO2025122400025, status=30
|
||||
报文 3: orderCode=BSO2025122400026, status=30
|
||||
========================
|
||||
```
|
||||
|
||||
## 关键改进
|
||||
|
||||
1. ✅ **等待所有订单**:不再只等待第一个订单,而是遍历所有 orderCode
|
||||
2. ✅ **收集完整报文**:每个订单的完整推送报文都被保存在 `reports` 数组中
|
||||
3. ✅ **详细日志**:清晰显示正在等待哪个订单,以及完成情况
|
||||
4. ✅ **错误处理**:即使某个订单失败,也会记录其状态信息
|
||||
5. ✅ **统一格式**:返回的 JSON 格式便于后续处理和分析
|
||||
@@ -8,8 +8,10 @@ import os
|
||||
# BioyondCellWorkstation 默认配置(包含所有必需参数)
|
||||
API_CONFIG = {
|
||||
# API 连接配置
|
||||
# "api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.118:44389"),#实机
|
||||
"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.219:44388"),# 仿真机
|
||||
# 实机
|
||||
#"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.118:44389"),
|
||||
# 仿真机
|
||||
"api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.11.219:44388"),
|
||||
"api_key": os.getenv("BIOYOND_API_KEY", "8A819E5C"),
|
||||
"timeout": int(os.getenv("BIOYOND_TIMEOUT", "30")),
|
||||
|
||||
@@ -17,7 +19,7 @@ API_CONFIG = {
|
||||
"report_token": os.getenv("BIOYOND_REPORT_TOKEN", "CHANGE_ME_TOKEN"),
|
||||
|
||||
# HTTP 服务配置
|
||||
"HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.16.10.148"), # HTTP服务监听地址,监听计算机飞连ip地址
|
||||
"HTTP_host": os.getenv("BIOYOND_HTTP_HOST", "172.16.11.206"), # HTTP服务监听地址,监听计算机飞连ip地址
|
||||
"HTTP_port": int(os.getenv("BIOYOND_HTTP_PORT", "8080")),
|
||||
"debug_mode": False,# 调试模式
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
# Modbus CSV 地址映射说明
|
||||
|
||||
本文档说明 `coin_cell_assembly_a.csv` 文件如何将命名节点映射到实际的 Modbus 地址,以及如何在代码中使用它们。
|
||||
|
||||
## 1. CSV 文件结构
|
||||
|
||||
地址表文件位于同级目录下:`coin_cell_assembly_a.csv`
|
||||
|
||||
每一行定义了一个 Modbus 节点,包含以下关键列:
|
||||
|
||||
| 列名 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| **Name** | **节点名称** (代码中引用的 Key) | `COIL_ALUMINUM_FOIL` |
|
||||
| **DataType** | 数据类型 (BOOL, INT16, FLOAT32, STRING) | `BOOL` |
|
||||
| **Comment** | 注释说明 | `使用铝箔垫` |
|
||||
| **Attribute** | 属性 (通常留空或用于额外标记) | |
|
||||
| **DeviceType** | Modbus 寄存器类型 (`coil`, `hold_register`) | `coil` |
|
||||
| **Address** | **Modbus 地址** (十进制) | `8340` |
|
||||
|
||||
### 示例行 (铝箔垫片)
|
||||
|
||||
```csv
|
||||
COIL_ALUMINUM_FOIL,BOOL,,使用铝箔垫,,coil,8340,
|
||||
```
|
||||
|
||||
- **名称**: `COIL_ALUMINUM_FOIL`
|
||||
- **类型**: `coil` (线圈,读写单个位)
|
||||
- **地址**: `8340`
|
||||
|
||||
---
|
||||
|
||||
## 2. 加载与注册流程
|
||||
|
||||
在 `coin_cell_assembly.py` 的初始化代码中:
|
||||
|
||||
1. **加载 CSV**: `BaseClient.load_csv()` 读取 CSV 并解析每行定义。
|
||||
2. **注册节点**: `modbus_client.register_node_list()` 将解析后的节点注册到 Modbus 客户端实例中。
|
||||
|
||||
```python
|
||||
# 代码位置: coin_cell_assembly.py (L174-175)
|
||||
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_a.csv'))
|
||||
self.client = modbus_client.register_node_list(self.nodes)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 代码中的使用方式
|
||||
|
||||
注册后,通过 `self.client.use_node('节点名称')` 即可获取该节点对象并进行读写操作,无需关心具体地址。
|
||||
|
||||
### 控制铝箔垫片 (COIL_ALUMINUM_FOIL)
|
||||
|
||||
```python
|
||||
# 代码位置: qiming_coin_cell_code 函数 (L1048)
|
||||
self.client.use_node('COIL_ALUMINUM_FOIL').write(not lvbodian)
|
||||
```
|
||||
|
||||
- **写入 True**: 对应 Modbus 功能码 05 (Write Single Coil),向地址 `8340` 写入 `1` (ON)。
|
||||
- **写入 False**: 向地址 `8340` 写入 `0` (OFF)。
|
||||
|
||||
> **注意**: 代码中使用了 `not lvbodian`,这意味着逻辑是反转的。如果 `lvbodian` 参数为 `True` (默认),写入的是 `False` (不使用铝箔垫)。
|
||||
|
||||
---
|
||||
|
||||
## 4. 地址转换注意事项 (Modbus vs PLC)
|
||||
|
||||
CSV 中的 `Address` 列(如 `8340`)是 **Modbus 协议地址**。
|
||||
|
||||
如果使用 InoProShop (汇川 PLC 编程软件),看到的可能是 **PLC 内部地址** (如 `%QX...` 或 `%MW...`)。这两者之间通常需要转换。
|
||||
|
||||
### 常见的转换规则 (示例)
|
||||
|
||||
- **Coil (线圈) %QX**:
|
||||
- `Modbus地址 = 字节地址 * 8 + 位偏移`
|
||||
- *例子*: `%QX834.0` -> `834 * 8 + 0` = `6672`
|
||||
- *注意*: 如果 CSV 中配置的是 `8340`,这可能是一个自定义映射,或者是基于不同规则(如直接对应 Word 地址的某种映射,或者可能就是地址写错了/使用了非标准映射)。
|
||||
|
||||
- **Register (寄存器) %MW**:
|
||||
- 通常直接对应,或者有偏移量 (如 Modbus 40001 = PLC MW0)。
|
||||
|
||||
### 验证方法
|
||||
由于 `test_unilab_interact.py` 中发现 `8450` (CSV风格) 不工作,而 `6760` (%QX845.0 计算值) 工作正常,**建议对 CSV 中的其他地址也进行核实**,特别是像 `8340` 这样以 0 结尾看起来像是 "字节地址+0" 的数值,可能实际上应该是 `%QX834.0` 对应的 `6672`。
|
||||
|
||||
如果发现设备控制无反应,请尝试按照标准的 Modbus 计算方式转换 PLC 地址。
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
import csv
|
||||
import inspect
|
||||
import json
|
||||
@@ -21,6 +20,39 @@ from unilabos.ros.nodes.presets.workstation import ROS2WorkstationNode
|
||||
from unilabos.devices.workstation.coin_cell_assembly.YB_YH_materials import CoincellDeck
|
||||
from unilabos.resources.graphio import convert_resources_to_type
|
||||
from unilabos.utils.log import logger
|
||||
from pymodbus.payload import BinaryPayloadDecoder
|
||||
from pymodbus.constants import Endian
|
||||
|
||||
|
||||
def _decode_float32_correct(registers):
|
||||
"""
|
||||
正确解码FLOAT32类型的Modbus寄存器
|
||||
|
||||
Args:
|
||||
registers: 从Modbus读取的原始寄存器值列表
|
||||
|
||||
Returns:
|
||||
正确解码的浮点数值
|
||||
|
||||
Note:
|
||||
根据test_glove_box_pressure.py验证的配置:
|
||||
- Byte Order: Big (Modbus标准)
|
||||
- Word Order: Little (PLC配置)
|
||||
"""
|
||||
if not registers or len(registers) < 2:
|
||||
return 0.0
|
||||
|
||||
try:
|
||||
# 使用正确的字节序配置
|
||||
decoder = BinaryPayloadDecoder.fromRegisters(
|
||||
registers,
|
||||
byteorder=Endian.Big, # 字节序始终为Big
|
||||
wordorder=Endian.Little # 字序为Little (根据PLC配置)
|
||||
)
|
||||
return decoder.decode_32bit_float()
|
||||
except Exception as e:
|
||||
logger.error(f"解码FLOAT32失败: {e}, registers: {registers}")
|
||||
return 0.0
|
||||
|
||||
|
||||
def _ensure_modbus_slave_kw_alias(modbus_client):
|
||||
@@ -139,7 +171,7 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
time.sleep(2)
|
||||
if not modbus_client.client.is_socket_open():
|
||||
raise ValueError('modbus tcp connection failed')
|
||||
self.nodes = BaseClient.load_csv(os.path.join(os.path.dirname(__file__), 'coin_cell_assembly_1105.csv'))
|
||||
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)
|
||||
else:
|
||||
print("测试模式,跳过连接")
|
||||
@@ -502,48 +534,72 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
"""单颗电池组装时间 (秒, REAL/FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
time, read_err = self.client.use_node('REG_DATA_ASSEMBLY_PER_TIME').read(2, word_order=WorderOrder.LITTLE)
|
||||
return time
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_ASSEMBLY_PER_TIME').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取组装时间失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_open_circuit_voltage(self) -> float:
|
||||
"""开路电压值 (FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
vol, read_err = self.client.use_node('REG_DATA_OPEN_CIRCUIT_VOLTAGE').read(2, word_order=WorderOrder.LITTLE)
|
||||
return vol
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_OPEN_CIRCUIT_VOLTAGE').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取开路电压失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_axis_x_pos(self) -> float:
|
||||
"""分液X轴当前位置 (FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
pos, read_err = self.client.use_node('REG_DATA_AXIS_X_POS').read(2, word_order=WorderOrder.LITTLE)
|
||||
return pos
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_AXIS_X_POS').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取X轴位置失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_axis_y_pos(self) -> float:
|
||||
"""分液Y轴当前位置 (FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
pos, read_err = self.client.use_node('REG_DATA_AXIS_Y_POS').read(2, word_order=WorderOrder.LITTLE)
|
||||
return pos
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_AXIS_Y_POS').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读变Y轴位置失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_axis_z_pos(self) -> float:
|
||||
"""分液Z轴当前位置 (FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
pos, read_err = self.client.use_node('REG_DATA_AXIS_Z_POS').read(2, word_order=WorderOrder.LITTLE)
|
||||
return pos
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_AXIS_Z_POS').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取Z轴位置失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_pole_weight(self) -> float:
|
||||
"""当前电池正极片称重数据 (FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
weight, read_err = self.client.use_node('REG_DATA_POLE_WEIGHT').read(2, word_order=WorderOrder.LITTLE)
|
||||
return weight
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_POLE_WEIGHT').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取极片质量失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_assembly_pressure(self) -> int:
|
||||
@@ -573,11 +629,28 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
def data_coin_cell_code(self) -> str:
|
||||
"""电池二维码序列号 (STRING)"""
|
||||
try:
|
||||
# 尝试不同的字节序读取
|
||||
# 读取 STRING 类型数据
|
||||
code_little, read_err = self.client.use_node('REG_DATA_COIN_CELL_CODE').read(10, word_order=WorderOrder.LITTLE)
|
||||
# logger.debug(f"读取电池二维码原始数据: {code_little}")
|
||||
clean_code = code_little[-8:][::-1]
|
||||
return clean_code
|
||||
|
||||
# 处理 bytes 或 string 类型
|
||||
if isinstance(code_little, bytes):
|
||||
code_str = code_little.decode('utf-8', errors='ignore')
|
||||
elif isinstance(code_little, str):
|
||||
code_str = code_little
|
||||
else:
|
||||
logger.warning(f"电池二维码返回的类型不支持: {type(code_little)}")
|
||||
return "N/A"
|
||||
|
||||
# 取前8个字符
|
||||
raw_code = code_str[:8]
|
||||
|
||||
# LITTLE字节序需要每2个字符交换位置
|
||||
clean_code = ''.join([raw_code[i+1] + raw_code[i] for i in range(0, len(raw_code), 2)])
|
||||
|
||||
# 去除空字符和空格
|
||||
decoded = clean_code.replace('\x00', '').replace('\r', '').replace('\n', '').strip()
|
||||
|
||||
return decoded if decoded else "N/A"
|
||||
except Exception as e:
|
||||
logger.error(f"读取电池二维码失败: {e}")
|
||||
return "N/A"
|
||||
@@ -585,12 +658,30 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
|
||||
@property
|
||||
def data_electrolyte_code(self) -> str:
|
||||
"""电解液二维码序列号 (STRING)"""
|
||||
try:
|
||||
# 尝试不同的字节序读取
|
||||
# 读取 STRING 类型数据
|
||||
code_little, read_err = self.client.use_node('REG_DATA_ELECTROLYTE_CODE').read(10, word_order=WorderOrder.LITTLE)
|
||||
# logger.debug(f"读取电解液二维码原始数据: {code_little}")
|
||||
clean_code = code_little[-8:][::-1]
|
||||
return clean_code
|
||||
|
||||
# 处理 bytes 或 string 类型
|
||||
if isinstance(code_little, bytes):
|
||||
code_str = code_little.decode('utf-8', errors='ignore')
|
||||
elif isinstance(code_little, str):
|
||||
code_str = code_little
|
||||
else:
|
||||
logger.warning(f"电解液二维码返回的类型不支持: {type(code_little)}")
|
||||
return "N/A"
|
||||
|
||||
# 取前8个字符
|
||||
raw_code = code_str[:8]
|
||||
|
||||
# LITTLE字节序需要每2个字符交换位置
|
||||
clean_code = ''.join([raw_code[i+1] + raw_code[i] for i in range(0, len(raw_code), 2)])
|
||||
|
||||
# 去除空字符和空格
|
||||
decoded = clean_code.replace('\x00', '').replace('\r', '').replace('\n', '').strip()
|
||||
|
||||
return decoded if decoded else "N/A"
|
||||
except Exception as e:
|
||||
logger.error(f"读取电解液二维码失败: {e}")
|
||||
return "N/A"
|
||||
@@ -598,27 +689,39 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
# ===================== 环境监控区 ======================
|
||||
@property
|
||||
def data_glove_box_pressure(self) -> float:
|
||||
"""手套箱压力 (bar, FLOAT32)"""
|
||||
"""手套箱压力 (mbar, FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
status, read_err = self.client.use_node('REG_DATA_GLOVE_BOX_PRESSURE').read(2, word_order=WorderOrder.LITTLE)
|
||||
return status
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_GLOVE_BOX_PRESSURE').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取手套箱压力失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_glove_box_o2_content(self) -> float:
|
||||
"""手套箱氧含量 (ppm, FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
value, read_err = self.client.use_node('REG_DATA_GLOVE_BOX_O2_CONTENT').read(2, word_order=WorderOrder.LITTLE)
|
||||
return value
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_GLOVE_BOX_O2_CONTENT').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取手套箱氧含量失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
@property
|
||||
def data_glove_box_water_content(self) -> float:
|
||||
"""手套箱水含量 (ppm, FLOAT32)"""
|
||||
if self.debug_mode:
|
||||
return 0
|
||||
value, read_err = self.client.use_node('REG_DATA_GLOVE_BOX_WATER_CONTENT').read(2, word_order=WorderOrder.LITTLE)
|
||||
return value
|
||||
# 读取原始寄存器并正确解码FLOAT32
|
||||
result = self.client.client.read_holding_registers(address=self.client.use_node('REG_DATA_GLOVE_BOX_WATER_CONTENT').address, count=2)
|
||||
if result.isError():
|
||||
logger.error(f"读取手套箱水含量失败")
|
||||
return 0.0
|
||||
return _decode_float32_correct(result.registers)
|
||||
|
||||
# @property
|
||||
# def data_stack_vision_code(self) -> int:
|
||||
@@ -690,6 +793,130 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
print("waiting for start_cmd")
|
||||
time.sleep(1)
|
||||
|
||||
def func_pack_device_init_auto_start_combined(self) -> bool:
|
||||
"""
|
||||
组合函数:设备初始化 + 切换自动模式 + 启动
|
||||
|
||||
整合了原有的三个独立函数:
|
||||
1. func_pack_device_init() - 设备初始化
|
||||
2. func_pack_device_auto() - 切换自动模式
|
||||
3. func_pack_device_start() - 启动设备
|
||||
|
||||
Returns:
|
||||
bool: 操作成功返回 True,失败返回 False
|
||||
"""
|
||||
logger.info("=" * 60)
|
||||
logger.info("开始组合操作:设备初始化 → 自动模式 → 启动")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# 步骤0: 前置条件检查
|
||||
logger.info("\n【步骤 0/3】前置条件检查...")
|
||||
try:
|
||||
# 检查 REG_UNILAB_INTERACT (应该为False,表示使用Unilab交互)
|
||||
unilab_interact_node = self.client.use_node('REG_UNILAB_INTERACT')
|
||||
unilab_interact_value, read_err = unilab_interact_node.read(1)
|
||||
|
||||
if read_err:
|
||||
error_msg = "❌ 无法读取 REG_UNILAB_INTERACT 状态!请检查设备连接。"
|
||||
logger.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
# 提取实际值(处理可能的列表或单值)
|
||||
if isinstance(unilab_interact_value, (list, tuple)):
|
||||
unilab_interact_actual = unilab_interact_value[0] if len(unilab_interact_value) > 0 else None
|
||||
else:
|
||||
unilab_interact_actual = unilab_interact_value
|
||||
|
||||
logger.info(f" REG_UNILAB_INTERACT 当前值: {unilab_interact_actual}")
|
||||
|
||||
if unilab_interact_actual != False:
|
||||
error_msg = (
|
||||
"❌ 前置条件检查失败!\n"
|
||||
f" REG_UNILAB_INTERACT = {unilab_interact_actual} (期望值: False)\n"
|
||||
" 说明: 当前设备设置为'忽略Unilab交互'模式\n"
|
||||
" 操作: 请在HMI上确认并切换为'使用Unilab交互'模式\n"
|
||||
" 提示: REG_UNILAB_INTERACT应该为False才能继续"
|
||||
)
|
||||
logger.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
logger.info(" ✓ REG_UNILAB_INTERACT 检查通过 (值为False,使用Unilab交互)")
|
||||
|
||||
# 检查 COIL_GB_L_IGNORE_CMD (应该为False,表示使用左手套箱)
|
||||
gb_l_ignore_node = self.client.use_node('COIL_GB_L_IGNORE_CMD')
|
||||
gb_l_ignore_value, read_err = gb_l_ignore_node.read(1)
|
||||
|
||||
if read_err:
|
||||
error_msg = "❌ 无法读取 COIL_GB_L_IGNORE_CMD 状态!请检查设备连接。"
|
||||
logger.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
# 提取实际值
|
||||
if isinstance(gb_l_ignore_value, (list, tuple)):
|
||||
gb_l_ignore_actual = gb_l_ignore_value[0] if len(gb_l_ignore_value) > 0 else None
|
||||
else:
|
||||
gb_l_ignore_actual = gb_l_ignore_value
|
||||
|
||||
logger.info(f" COIL_GB_L_IGNORE_CMD 当前值: {gb_l_ignore_actual}")
|
||||
|
||||
if gb_l_ignore_actual != False:
|
||||
error_msg = (
|
||||
"❌ 前置条件检查失败!\n"
|
||||
f" COIL_GB_L_IGNORE_CMD = {gb_l_ignore_actual} (期望值: False)\n"
|
||||
" 说明: 当前设备设置为'忽略左手套箱'模式\n"
|
||||
" 操作: 请在HMI上确认并切换为'使用左手套箱'模式\n"
|
||||
" 提示: COIL_GB_L_IGNORE_CMD应该为False才能继续"
|
||||
)
|
||||
logger.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
|
||||
logger.info(" ✓ COIL_GB_L_IGNORE_CMD 检查通过 (值为False,使用左手套箱)")
|
||||
logger.info("✓ 所有前置条件检查通过!")
|
||||
|
||||
except ValueError as e:
|
||||
# 节点未找到
|
||||
error_msg = f"❌ 配置错误:{str(e)}\n请检查CSV配置文件是否包含必要的节点。"
|
||||
logger.error(error_msg)
|
||||
raise RuntimeError(error_msg)
|
||||
except Exception as e:
|
||||
# 其他异常
|
||||
error_msg = f"❌ 前置条件检查异常:{str(e)}"
|
||||
logger.error(error_msg)
|
||||
raise
|
||||
|
||||
# 步骤1: 设备初始化
|
||||
logger.info("\n【步骤 1/3】设备初始化...")
|
||||
try:
|
||||
self.func_pack_device_init()
|
||||
logger.info("✓ 设备初始化完成")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 设备初始化失败: {e}")
|
||||
return False
|
||||
|
||||
# 步骤2: 切换自动模式
|
||||
logger.info("\n【步骤 2/3】切换自动模式...")
|
||||
try:
|
||||
self.func_pack_device_auto()
|
||||
logger.info("✓ 切换自动模式完成")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 切换自动模式失败: {e}")
|
||||
return False
|
||||
|
||||
# 步骤3: 启动设备
|
||||
logger.info("\n【步骤 3/3】启动设备...")
|
||||
try:
|
||||
self.func_pack_device_start()
|
||||
logger.info("✓ 启动设备完成")
|
||||
except Exception as e:
|
||||
logger.error(f"❌ 启动设备失败: {e}")
|
||||
return False
|
||||
|
||||
logger.info("\n" + "=" * 60)
|
||||
logger.info("组合操作完成:设备已成功初始化、切换自动模式并启动")
|
||||
logger.info("=" * 60)
|
||||
|
||||
return True
|
||||
|
||||
def func_pack_send_bottle_num(self, bottle_num):
|
||||
bottle_num = int(bottle_num)
|
||||
#发送电解液平台数
|
||||
@@ -774,14 +1001,59 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
while self.request_send_msg_status == False:
|
||||
print("waiting for send_read_msg_status to True")
|
||||
time.sleep(1)
|
||||
data_open_circuit_voltage = self.data_open_circuit_voltage
|
||||
data_pole_weight = self.data_pole_weight
|
||||
|
||||
# 处理开路电压 - 确保是数值类型
|
||||
try:
|
||||
data_open_circuit_voltage = self.data_open_circuit_voltage
|
||||
if isinstance(data_open_circuit_voltage, (list, tuple)) and len(data_open_circuit_voltage) > 0:
|
||||
data_open_circuit_voltage = float(data_open_circuit_voltage[0])
|
||||
else:
|
||||
data_open_circuit_voltage = float(data_open_circuit_voltage)
|
||||
except Exception as e:
|
||||
print(f"读取开路电压失败: {e}")
|
||||
logger.error(f"读取开路电压失败: {e}")
|
||||
data_open_circuit_voltage = 0.0
|
||||
|
||||
# 处理极片质量 - 确保是数值类型
|
||||
try:
|
||||
data_pole_weight = self.data_pole_weight
|
||||
if isinstance(data_pole_weight, (list, tuple)) and len(data_pole_weight) > 0:
|
||||
data_pole_weight = float(data_pole_weight[0])
|
||||
else:
|
||||
data_pole_weight = float(data_pole_weight)
|
||||
except Exception as e:
|
||||
print(f"读取正极片重量失败: {e}")
|
||||
logger.error(f"读取正极片重量失败: {e}")
|
||||
data_pole_weight = 0.0
|
||||
|
||||
data_assembly_time = self.data_assembly_time
|
||||
data_assembly_pressure = self.data_assembly_pressure
|
||||
data_electrolyte_volume = self.data_electrolyte_volume
|
||||
data_coin_num = self.data_coin_num
|
||||
data_electrolyte_code = self.data_electrolyte_code
|
||||
data_coin_cell_code = self.data_coin_cell_code
|
||||
|
||||
# 处理电解液二维码 - 确保是字符串类型
|
||||
try:
|
||||
data_electrolyte_code = self.data_electrolyte_code
|
||||
if isinstance(data_electrolyte_code, str):
|
||||
data_electrolyte_code = data_electrolyte_code.strip()
|
||||
else:
|
||||
data_electrolyte_code = str(data_electrolyte_code)
|
||||
except Exception as e:
|
||||
print(f"读取电解液二维码失败: {e}")
|
||||
logger.error(f"读取电解液二维码失败: {e}")
|
||||
data_electrolyte_code = "N/A"
|
||||
|
||||
# 处理电池二维码 - 确保是字符串类型
|
||||
try:
|
||||
data_coin_cell_code = self.data_coin_cell_code
|
||||
if isinstance(data_coin_cell_code, str):
|
||||
data_coin_cell_code = data_coin_cell_code.strip()
|
||||
else:
|
||||
data_coin_cell_code = str(data_coin_cell_code)
|
||||
except Exception as e:
|
||||
print(f"读取电池二维码失败: {e}")
|
||||
logger.error(f"读取电池二维码失败: {e}")
|
||||
data_coin_cell_code = "N/A"
|
||||
logger.debug(f"data_open_circuit_voltage: {data_open_circuit_voltage}")
|
||||
logger.debug(f"data_pole_weight: {data_pole_weight}")
|
||||
logger.debug(f"data_assembly_time: {data_assembly_time}")
|
||||
@@ -792,8 +1064,25 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
logger.debug(f"data_coin_cell_code: {data_coin_cell_code}")
|
||||
#接收完信息后,读取完毕标志位置True
|
||||
liaopan3 = self.deck.get_resource("成品弹夹")
|
||||
#把物料解绑后放到另一盘上
|
||||
battery = ElectrodeSheet(name=f"battery_{self.coin_num_N}", size_x=14, size_y=14, size_z=2)
|
||||
|
||||
# 生成唯一的电池名称(使用时间戳确保唯一性)
|
||||
timestamp_suffix = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
||||
battery_name = f"battery_{self.coin_num_N}_{timestamp_suffix}"
|
||||
|
||||
# 检查目标位置是否已有资源,如果有则先卸载
|
||||
target_slot = liaopan3.children[self.coin_num_N]
|
||||
if target_slot.children:
|
||||
logger.warning(f"位置 {self.coin_num_N} 已有资源,将先卸载旧资源")
|
||||
try:
|
||||
# 卸载所有现有子资源
|
||||
for child in list(target_slot.children):
|
||||
target_slot.unassign_child_resource(child)
|
||||
logger.info(f"已卸载旧资源: {child.name}")
|
||||
except Exception as e:
|
||||
logger.error(f"卸载旧资源时出错: {e}")
|
||||
|
||||
# 创建新的电池资源
|
||||
battery = ElectrodeSheet(name=battery_name, size_x=14, size_y=14, size_z=2)
|
||||
battery._unilabos_state = {
|
||||
"electrolyte_name": data_coin_cell_code,
|
||||
"data_electrolyte_code": data_electrolyte_code,
|
||||
@@ -801,7 +1090,16 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
"assembly_pressure": data_assembly_pressure,
|
||||
"electrolyte_volume": data_electrolyte_volume
|
||||
}
|
||||
liaopan3.children[self.coin_num_N].assign_child_resource(battery, location=None)
|
||||
|
||||
# 分配新资源到目标位置
|
||||
try:
|
||||
target_slot.assign_child_resource(battery, location=None)
|
||||
logger.info(f"成功分配电池 {battery_name} 到位置 {self.coin_num_N}")
|
||||
except Exception as e:
|
||||
logger.error(f"分配电池资源失败: {e}")
|
||||
# 如果分配失败,尝试使用更简单的方法
|
||||
raise
|
||||
|
||||
#print(jipian2.parent)
|
||||
ROS2DeviceNode.run_async_func(self._ros_node.update_resource, True, **{
|
||||
"resources": [self.deck]
|
||||
@@ -879,11 +1177,14 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
|
||||
return self.success
|
||||
|
||||
def func_allpack_cmd(self, elec_num, elec_use_num, elec_vol:int=50, assembly_type:int=7, assembly_pressure:int=4200, file_path: str="/Users/sml/work") -> bool:
|
||||
def func_allpack_cmd(self, elec_num, elec_use_num, elec_vol:int=50, assembly_type:int=7, assembly_pressure:int=4200, file_path: str="/Users/sml/work") -> Dict[str, Any]:
|
||||
elec_num, elec_use_num, elec_vol, assembly_type, assembly_pressure = int(elec_num), int(elec_use_num), int(elec_vol), int(assembly_type), int(assembly_pressure)
|
||||
summary_csv_file = os.path.join(file_path, "duandian.csv")
|
||||
# 如果断点文件存在,先读取之前的进度
|
||||
|
||||
# 用于收集所有电池的数据
|
||||
battery_data_list = []
|
||||
|
||||
# 如果断点文件存在,先读取之前的进度
|
||||
if os.path.exists(summary_csv_file):
|
||||
read_status_flag = True
|
||||
with open(summary_csv_file, 'r', newline='', encoding='utf-8') as csvfile:
|
||||
@@ -900,7 +1201,12 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
print("断点文件与当前任务匹配,继续")
|
||||
else:
|
||||
print("断点文件中elec_num、elec_use_num与当前任务不匹配,请检查任务下发参数或修改断点文件")
|
||||
return False
|
||||
return {
|
||||
"success": False,
|
||||
"error": "断点文件参数不匹配",
|
||||
"total_batteries": 0,
|
||||
"batteries": []
|
||||
}
|
||||
print(f"从断点文件读取进度: elec_num_N={elec_num_N}, elec_use_num_N={elec_use_num_N}, coin_num_N={coin_num_N}")
|
||||
|
||||
else:
|
||||
@@ -935,13 +1241,63 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
|
||||
for j in range(j_start, elec_use_num):
|
||||
print(f"开始第{last_i+i+1}瓶电解液的第{j+j_start+1}个电池组装")
|
||||
|
||||
#读取电池组装数据并存入csv
|
||||
self.func_pack_get_msg_cmd(file_path)
|
||||
|
||||
# 收集当前电池的数据
|
||||
# 处理电池二维码
|
||||
try:
|
||||
battery_qr_code = self.data_coin_cell_code
|
||||
except Exception as e:
|
||||
print(f"读取电池二维码失败: {e}")
|
||||
battery_qr_code = "N/A"
|
||||
|
||||
# 处理电解液二维码
|
||||
try:
|
||||
electrolyte_qr_code = self.data_electrolyte_code
|
||||
except Exception as e:
|
||||
print(f"读取电解液二维码失败: {e}")
|
||||
electrolyte_qr_code = "N/A"
|
||||
|
||||
# 处理开路电压 - 确保是数值类型
|
||||
try:
|
||||
open_circuit_voltage = self.data_open_circuit_voltage
|
||||
if isinstance(open_circuit_voltage, (list, tuple)) and len(open_circuit_voltage) > 0:
|
||||
open_circuit_voltage = float(open_circuit_voltage[0])
|
||||
else:
|
||||
open_circuit_voltage = float(open_circuit_voltage)
|
||||
except Exception as e:
|
||||
print(f"读取开路电压失败: {e}")
|
||||
open_circuit_voltage = 0.0
|
||||
|
||||
# 处理极片质量 - 确保是数值类型
|
||||
try:
|
||||
pole_weight = self.data_pole_weight
|
||||
if isinstance(pole_weight, (list, tuple)) and len(pole_weight) > 0:
|
||||
pole_weight = float(pole_weight[0])
|
||||
else:
|
||||
pole_weight = float(pole_weight)
|
||||
except Exception as e:
|
||||
print(f"读取正极片重量失败: {e}")
|
||||
pole_weight = 0.0
|
||||
|
||||
battery_info = {
|
||||
"battery_index": coin_num_N + 1,
|
||||
"battery_barcode": battery_qr_code,
|
||||
"electrolyte_barcode": electrolyte_qr_code,
|
||||
"open_circuit_voltage": open_circuit_voltage,
|
||||
"pole_weight": pole_weight,
|
||||
"assembly_time": self.data_assembly_time,
|
||||
"assembly_pressure": self.data_assembly_pressure,
|
||||
"electrolyte_volume": self.data_electrolyte_volume
|
||||
}
|
||||
battery_data_list.append(battery_info)
|
||||
print(f"已收集第 {coin_num_N + 1} 个电池数据: 电池码={battery_info['battery_barcode']}, 电解液码={battery_info['electrolyte_barcode']}")
|
||||
|
||||
time.sleep(1)
|
||||
# TODO:读完再将电池数加一还是进入循环就将电池数加一需要考虑
|
||||
|
||||
|
||||
|
||||
# 生成断点文件
|
||||
# 生成包含elec_num_N、coin_num_N、timestamp的CSV文件
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
@@ -960,8 +1316,284 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
|
||||
os.remove(summary_csv_file)
|
||||
#全部完成后等待依华发送完成信号
|
||||
self.func_pack_send_finished_cmd()
|
||||
|
||||
# 返回JSON格式数据
|
||||
result = {
|
||||
"success": True,
|
||||
"total_batteries": len(battery_data_list),
|
||||
"batteries": battery_data_list,
|
||||
"summary": {
|
||||
"electrolyte_bottles_used": elec_num,
|
||||
"batteries_per_bottle": elec_use_num,
|
||||
"electrolyte_volume": elec_vol,
|
||||
"assembly_type": assembly_type,
|
||||
"assembly_pressure": assembly_pressure
|
||||
}
|
||||
}
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"组装完成统计:")
|
||||
print(f" 总组装电池数: {result['total_batteries']}")
|
||||
print(f" 使用电解液瓶数: {elec_num}")
|
||||
print(f" 每瓶电池数: {elec_use_num}")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def func_allpack_cmd_simp(
|
||||
self,
|
||||
elec_num,
|
||||
elec_use_num,
|
||||
elec_vol: int = 50,
|
||||
# 电解液双滴模式参数
|
||||
dual_drop_mode: bool = False,
|
||||
dual_drop_first_volume: int = 25,
|
||||
dual_drop_suction_timing: bool = False,
|
||||
dual_drop_start_timing: bool = False,
|
||||
assembly_type: int = 7,
|
||||
assembly_pressure: int = 4200,
|
||||
# 来自原 qiming_coin_cell_code 的参数
|
||||
fujipian_panshu: int = 0,
|
||||
fujipian_juzhendianwei: int = 0,
|
||||
gemopanshu: int = 0,
|
||||
gemo_juzhendianwei: int = 0,
|
||||
qiangtou_juzhendianwei: int = 0,
|
||||
lvbodian: bool = True,
|
||||
battery_pressure_mode: bool = True,
|
||||
battery_clean_ignore: bool = False,
|
||||
file_path: str = "/Users/sml/work"
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
简化版电池组装函数,整合了原 qiming_coin_cell_code 的参数设置和双滴模式
|
||||
|
||||
此函数是 func_allpack_cmd 的增强版本,自动处理以下配置:
|
||||
- 负极片和隔膜的盘数及矩阵点位
|
||||
- 枪头盒矩阵点位
|
||||
- 铝箔垫片使用设置
|
||||
- 压力模式和清洁忽略选项
|
||||
- 电解液双滴模式(分两次滴液)
|
||||
|
||||
Args:
|
||||
elec_num: 电解液瓶数
|
||||
elec_use_num: 每瓶电解液组装的电池数
|
||||
elec_vol: 电解液吸液量 (μL)
|
||||
dual_drop_mode: 电解液添加模式 (False=单次滴液, True=二次滴液)
|
||||
dual_drop_first_volume: 二次滴液第一次排液体积 (μL)
|
||||
dual_drop_suction_timing: 二次滴液吸液时机 (False=正常吸液, True=先吸液)
|
||||
dual_drop_start_timing: 二次滴液开始滴液时机 (False=正极片前, True=正极片后)
|
||||
assembly_type: 组装类型 (7=不用铝箔垫, 8=使用铝箔垫)
|
||||
assembly_pressure: 电池压制力 (N)
|
||||
fujipian_panshu: 负极片盘数
|
||||
fujipian_juzhendianwei: 负极片矩阵点位
|
||||
gemopanshu: 隔膜盘数
|
||||
gemo_juzhendianwei: 隔膜矩阵点位
|
||||
qiangtou_juzhendianwei: 枪头盒矩阵点位
|
||||
lvbodian: 是否使用铝箔垫片
|
||||
battery_pressure_mode: 是否启用压力模式
|
||||
battery_clean_ignore: 是否忽略电池清洁
|
||||
file_path: 实验记录保存路径
|
||||
|
||||
Returns:
|
||||
dict: 包含组装结果的字典
|
||||
"""
|
||||
# 参数类型转换
|
||||
elec_num = int(elec_num)
|
||||
elec_use_num = int(elec_use_num)
|
||||
elec_vol = int(elec_vol)
|
||||
dual_drop_first_volume = int(dual_drop_first_volume)
|
||||
assembly_type = int(assembly_type)
|
||||
assembly_pressure = int(assembly_pressure)
|
||||
fujipian_panshu = int(fujipian_panshu)
|
||||
fujipian_juzhendianwei = int(fujipian_juzhendianwei)
|
||||
gemopanshu = int(gemopanshu)
|
||||
gemo_juzhendianwei = int(gemo_juzhendianwei)
|
||||
qiangtou_juzhendianwei = int(qiangtou_juzhendianwei)
|
||||
|
||||
# 步骤1: 设置设备参数(原 qiming_coin_cell_code 的功能)
|
||||
logger.info("=" * 60)
|
||||
logger.info("设置设备参数...")
|
||||
logger.info(f" 负极片盘数: {fujipian_panshu}, 矩阵点位: {fujipian_juzhendianwei}")
|
||||
logger.info(f" 隔膜盘数: {gemopanshu}, 矩阵点位: {gemo_juzhendianwei}")
|
||||
logger.info(f" 枪头盒矩阵点位: {qiangtou_juzhendianwei}")
|
||||
logger.info(f" 铝箔垫片: {lvbodian}, 压力模式: {battery_pressure_mode}")
|
||||
logger.info(f" 压制力: {assembly_pressure}")
|
||||
logger.info(f" 忽略电池清洁: {battery_clean_ignore}")
|
||||
logger.info("=" * 60)
|
||||
|
||||
# 写入基础参数到PLC
|
||||
self.client.use_node('REG_MSG_NE_PLATE_NUM').write(fujipian_panshu)
|
||||
self.client.use_node('REG_MSG_NE_PLATE_MATRIX').write(fujipian_juzhendianwei)
|
||||
self.client.use_node('REG_MSG_SEPARATOR_PLATE_NUM').write(gemopanshu)
|
||||
self.client.use_node('REG_MSG_SEPARATOR_PLATE_MATRIX').write(gemo_juzhendianwei)
|
||||
self.client.use_node('REG_MSG_TIP_BOX_MATRIX').write(qiangtou_juzhendianwei)
|
||||
self.client.use_node('COIL_ALUMINUM_FOIL').write(not lvbodian)
|
||||
self.client.use_node('REG_MSG_PRESS_MODE').write(not battery_pressure_mode)
|
||||
self.client.use_node('REG_MSG_BATTERY_CLEAN_IGNORE').write(battery_clean_ignore)
|
||||
|
||||
# 设置电解液双滴模式参数
|
||||
self.client.use_node('COIL_ELECTROLYTE_DUAL_DROP_MODE').write(dual_drop_mode)
|
||||
self.client.use_node('REG_MSG_DUAL_DROP_FIRST_VOLUME').write(dual_drop_first_volume)
|
||||
self.client.use_node('COIL_DUAL_DROP_SUCTION_TIMING').write(dual_drop_suction_timing)
|
||||
self.client.use_node('COIL_DUAL_DROP_START_TIMING').write(dual_drop_start_timing)
|
||||
|
||||
if dual_drop_mode:
|
||||
logger.info(f"✓ 双滴模式已启用: 第一次排液={dual_drop_first_volume}μL, "
|
||||
f"吸液时机={'先吸液' if dual_drop_suction_timing else '正常吸液'}, "
|
||||
f"滴液时机={'正极片后' if dual_drop_start_timing else '正极片前'}")
|
||||
else:
|
||||
logger.info("✓ 单次滴液模式")
|
||||
|
||||
logger.info("✓ 设备参数设置完成")
|
||||
|
||||
# 步骤2: 执行组装流程(复用 func_allpack_cmd 的主体逻辑)
|
||||
summary_csv_file = os.path.join(file_path, "duandian.csv")
|
||||
|
||||
# 用于收集所有电池的数据
|
||||
battery_data_list = []
|
||||
|
||||
# 如果断点文件存在,先读取之前的进度
|
||||
if os.path.exists(summary_csv_file):
|
||||
read_status_flag = True
|
||||
with open(summary_csv_file, 'r', newline='', encoding='utf-8') as csvfile:
|
||||
reader = csv.reader(csvfile)
|
||||
header = next(reader) # 跳过标题行
|
||||
data_row = next(reader) # 读取数据行
|
||||
if len(data_row) >= 2:
|
||||
elec_num_r = int(data_row[0])
|
||||
elec_use_num_r = int(data_row[1])
|
||||
elec_num_N = int(data_row[2])
|
||||
elec_use_num_N = int(data_row[3])
|
||||
coin_num_N = int(data_row[4])
|
||||
if elec_num_r == elec_num and elec_use_num_r == elec_use_num:
|
||||
print("断点文件与当前任务匹配,继续")
|
||||
else:
|
||||
print("断点文件中elec_num、elec_use_num与当前任务不匹配,请检查任务下发参数或修改断点文件")
|
||||
return {
|
||||
"success": False,
|
||||
"error": "断点文件参数不匹配",
|
||||
"total_batteries": 0,
|
||||
"batteries": []
|
||||
}
|
||||
print(f"从断点文件读取进度: elec_num_N={elec_num_N}, elec_use_num_N={elec_use_num_N}, coin_num_N={coin_num_N}")
|
||||
|
||||
else:
|
||||
read_status_flag = False
|
||||
print("未找到断点文件,从头开始")
|
||||
elec_num_N = 0
|
||||
elec_use_num_N = 0
|
||||
coin_num_N = 0
|
||||
|
||||
for i in range(20):
|
||||
print(f"剩余电解液瓶数: {elec_num}, 已组装电池数: {elec_use_num}")
|
||||
print(f"剩余电解液瓶数: {type(elec_num)}, 已组装电池数: {type(elec_use_num)}")
|
||||
print(f"剩余电解液瓶数: {type(int(elec_num))}, 已组装电池数: {type(int(elec_use_num))}")
|
||||
|
||||
last_i = elec_num_N
|
||||
last_j = elec_use_num_N
|
||||
for i in range(last_i, elec_num):
|
||||
print(f"开始第{last_i+i+1}瓶电解液的组装")
|
||||
# 第一个循环从上次断点继续,后续循环从0开始
|
||||
j_start = last_j if i == last_i else 0
|
||||
self.func_pack_send_msg_cmd(elec_use_num-j_start, elec_vol, assembly_type, assembly_pressure)
|
||||
|
||||
for j in range(j_start, elec_use_num):
|
||||
print(f"开始第{last_i+i+1}瓶电解液的第{j+j_start+1}个电池组装")
|
||||
|
||||
# 读取电池组装数据并存入csv
|
||||
self.func_pack_get_msg_cmd(file_path)
|
||||
|
||||
# 收集当前电池的数据
|
||||
try:
|
||||
battery_qr_code = self.data_coin_cell_code
|
||||
except Exception as e:
|
||||
print(f"读取电池二维码失败: {e}")
|
||||
battery_qr_code = "N/A"
|
||||
|
||||
try:
|
||||
electrolyte_qr_code = self.data_electrolyte_code
|
||||
except Exception as e:
|
||||
print(f"读取电解液二维码失败: {e}")
|
||||
electrolyte_qr_code = "N/A"
|
||||
|
||||
try:
|
||||
open_circuit_voltage = self.data_open_circuit_voltage
|
||||
if isinstance(open_circuit_voltage, (list, tuple)) and len(open_circuit_voltage) > 0:
|
||||
open_circuit_voltage = float(open_circuit_voltage[0])
|
||||
else:
|
||||
open_circuit_voltage = float(open_circuit_voltage)
|
||||
except Exception as e:
|
||||
print(f"读取开路电压失败: {e}")
|
||||
open_circuit_voltage = 0.0
|
||||
|
||||
try:
|
||||
pole_weight = self.data_pole_weight
|
||||
if isinstance(pole_weight, (list, tuple)) and len(pole_weight) > 0:
|
||||
pole_weight = float(pole_weight[0])
|
||||
else:
|
||||
pole_weight = float(pole_weight)
|
||||
except Exception as e:
|
||||
print(f"读取正极片重量失败: {e}")
|
||||
pole_weight = 0.0
|
||||
|
||||
battery_info = {
|
||||
"battery_index": coin_num_N + 1,
|
||||
"battery_barcode": battery_qr_code,
|
||||
"electrolyte_barcode": electrolyte_qr_code,
|
||||
"open_circuit_voltage": open_circuit_voltage,
|
||||
"pole_weight": pole_weight,
|
||||
"assembly_time": self.data_assembly_time,
|
||||
"assembly_pressure": self.data_assembly_pressure,
|
||||
"electrolyte_volume": self.data_electrolyte_volume
|
||||
}
|
||||
battery_data_list.append(battery_info)
|
||||
print(f"已收集第 {coin_num_N + 1} 个电池数据: 电池码={battery_info['battery_barcode']}, 电解液码={battery_info['electrolyte_barcode']}")
|
||||
|
||||
time.sleep(1)
|
||||
|
||||
# 生成断点文件
|
||||
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
with open(summary_csv_file, 'w', newline='', encoding='utf-8') as csvfile:
|
||||
writer = csv.writer(csvfile)
|
||||
writer.writerow(['elec_num','elec_use_num', 'elec_num_N', 'elec_use_num_N', 'coin_num_N', 'timestamp'])
|
||||
writer.writerow([elec_num, elec_use_num, elec_num_N, elec_use_num_N, coin_num_N, timestamp])
|
||||
csvfile.flush()
|
||||
coin_num_N += 1
|
||||
self.coin_num_N = coin_num_N
|
||||
elec_use_num_N += 1
|
||||
elec_num_N += 1
|
||||
elec_use_num_N = 0
|
||||
|
||||
# 循环正常结束,则删除断点文件
|
||||
os.remove(summary_csv_file)
|
||||
# 全部完成后等待依华发送完成信号
|
||||
self.func_pack_send_finished_cmd()
|
||||
|
||||
# 返回JSON格式数据
|
||||
result = {
|
||||
"success": True,
|
||||
"total_batteries": len(battery_data_list),
|
||||
"batteries": battery_data_list,
|
||||
"summary": {
|
||||
"electrolyte_bottles_used": elec_num,
|
||||
"batteries_per_bottle": elec_use_num,
|
||||
"electrolyte_volume": elec_vol,
|
||||
"assembly_type": assembly_type,
|
||||
"assembly_pressure": assembly_pressure,
|
||||
"dual_drop_mode": dual_drop_mode
|
||||
}
|
||||
}
|
||||
|
||||
print(f"\n{'='*60}")
|
||||
print(f"组装完成统计:")
|
||||
print(f" 总组装电池数: {result['total_batteries']}")
|
||||
print(f" 使用电解液瓶数: {elec_num}")
|
||||
print(f" 每瓶电池数: {elec_use_num}")
|
||||
print(f" 双滴模式: {'启用' if dual_drop_mode else '禁用'}")
|
||||
print(f"{'='*60}\n")
|
||||
|
||||
return result
|
||||
|
||||
def func_pack_device_stop(self) -> bool:
|
||||
"""打包指令:设备停止"""
|
||||
for i in range(3):
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
Name,DataType,Comment,DeviceType,Address,,
|
||||
COIL_SYS_START_CMD,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8010,,
|
||||
COIL_SYS_STOP_CMD,BOOL,<EFBFBD>豸ֹͣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8020,,
|
||||
COIL_SYS_RESET_CMD,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8030,,
|
||||
COIL_SYS_HAND_CMD,BOOL,<EFBFBD>豸<EFBFBD>ֶ<EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8040,,
|
||||
COIL_SYS_AUTO_CMD,BOOL,<EFBFBD>豸<EFBFBD>Զ<EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8050,,
|
||||
COIL_SYS_INIT_CMD,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8060,,
|
||||
COIL_SYS_STOP_STATUS,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD>ͣ<EFBFBD><EFBFBD>,coil,8220,,
|
||||
,,,,,,
|
||||
,BOOL,UNILAB<EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8720,,
|
||||
,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܵ<EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD>,coil,8520,,
|
||||
REG_MSG_ELECTROLYTE_NUM,WORD,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һʹ<EFBFBD><EFBFBD>ƿ<EFBFBD><EFBFBD>,hold_register,496,,
|
||||
,WORD,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>̾<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,440,,
|
||||
,WORD,<EFBFBD><EFBFBD>Ĥ<EFBFBD>̾<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,450,,
|
||||
,WORD,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD>_<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,460,,
|
||||
,WORD,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD>_<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>վ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,430,,
|
||||
,WORD,g_<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һƿ<EFBFBD><EFBFBD>_<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,470,,
|
||||
,WORD,<EFBFBD><EFBFBD>Һǹͷ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼλ0<EFBFBD><EFBFBD>,hold_register,480,,
|
||||
,WORD,<EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,443,,
|
||||
,WORD,<EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD>Ĥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,453,,
|
||||
,,,,,,
|
||||
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,UNILAB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>䷽<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8700,,
|
||||
COIL_REQUEST_REC_MSG_STATUS,BOOL,<EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>䷽,coil,8500,,
|
||||
REG_MSG_ELECTROLYTE_USE_NUM,INT16,<EFBFBD><EFBFBD>ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һʹ<EFBFBD>ô<EFBFBD><EFBFBD><EFBFBD>,hold_register,11000,,
|
||||
REG_MSG_ELECTROLYTE_VOLUME,INT16,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>,hold_register,11004,,
|
||||
REG_MSG_ASSEMBLY_PRESSURE,INT16,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,11008,,
|
||||
REG_DATA_ELECTROLYTE_CODE,STRING,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ά<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD>,hold_register,10020,,
|
||||
,BOOL,<EFBFBD>Ӿ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8300,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD>죨false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8310,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD><EFBFBD><EFBFBD>֣<EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8320,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_<EFBFBD>Ҳ֣<EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8420,,
|
||||
,BOOL,<EFBFBD><EFBFBD>е<EFBFBD>ְ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣<EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8330,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϣ<EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8340,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD>ռ<EFBFBD>֪<EFBFBD><EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8350,,
|
||||
,BOOL,ѹ<EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD>false:ѹ<><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<C4A3><CABD>True:<3A><><EFBFBD><EFBFBD>ģʽ<C4A3><CABD>,coil,8360,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ<EFBFBD><EFBFBD>false:<3A><><EFBFBD>ε<EFBFBD>Һ<EFBFBD><D2BA>true:<3A><><EFBFBD>ε<EFBFBD>Һ<EFBFBD><D2BA>,coil,8370,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD>أ<EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8380,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD>false:<3A><>װ<EFBFBD><D7B0>true:<3A><>װ<EFBFBD><D7B0>,coil,8390,,
|
||||
,BOOL,ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ࣨfalse:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8400,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̰<EFBFBD><EFBFBD>̷<EFBFBD>ʽ<EFBFBD><EFBFBD>false:ˮƽ<CBAE><C6BD><EFBFBD>̣<EFBFBD>true:<3A>ѵ<EFBFBD><D1B5><EFBFBD><EFBFBD>̣<EFBFBD>,coil,8410,,
|
||||
COIL_SYS_UNILAB_INTERACT ,BOOL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Unilab<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>false:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,coil,8450,,
|
||||
,BOOL,<EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ࣨfalse:ʹ<>ã<EFBFBD>true:<3A><><EFBFBD>ԣ<EFBFBD>,colil,8460,,
|
||||
,,,,,,
|
||||
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,UNILAB<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>䷽<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8510,,
|
||||
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,UNILAB<EFBFBD><EFBFBD><EFBFBD>ܲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,8710,,
|
||||
REG_DATA_POLE_WEIGHT,FLOAT32,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10010,,
|
||||
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ŵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װʱ<EFBFBD><EFBFBD>,hold_register,10012,,
|
||||
REG_DATA_ASSEMBLY_PRESSURE,INT16,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10014,,
|
||||
REG_DATA_ELECTROLYTE_VOLUME,INT16,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>,hold_register,10016,,
|
||||
REG_DATA_ASSEMBLY_TYPE,INT16,<EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD>ѵ<EFBFBD><EFBFBD><EFBFBD>ʽ(7/8),hold_register,10018,,
|
||||
REG_DATA_ELECTROLYTE_CODE,STRING,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ<EFBFBD><EFBFBD>ά<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD>,hold_register,10020,,
|
||||
REG_DATA_COIN_CELL_CODE,STRING,<EFBFBD><EFBFBD><EFBFBD>ض<EFBFBD>ά<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>к<EFBFBD>,hold_register,10030,,
|
||||
REG_DATA_STACK_VISON_CODE,STRING,<EFBFBD><EFBFBD><EFBFBD>϶ѵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͼƬ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10040,,
|
||||
REG_DATA_ELECTROLYTE_USE_NUM,INT16,<EFBFBD><EFBFBD>ǰ<EFBFBD>缫Һ<EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10000,,
|
||||
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>ѹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10002,,
|
||||
,INT,<EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ϼĴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1-<2D><><EFBFBD><EFBFBD><EFBFBD>ǡ<EFBFBD>2-<2D><><EFBFBD>桢3-<2D><><EFBFBD><EFBFBD>Ƭ<EFBFBD><C6AC>4-<2D><>Ĥ<EFBFBD><C4A4>5-<2D><><EFBFBD><EFBFBD>Ƭ<EFBFBD><C6AC>6-ƽ<>桢7-<2D><><EFBFBD>桢8-<2D><><EFBFBD><EFBFBD><EFBFBD>ǣ<EFBFBD>,hold_register,10060,,
|
||||
,,,,,,
|
||||
,INT,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10062,PLC<EFBFBD><EFBFBD>ַ,1223-<2D><><EFBFBD><EFBFBD>
|
||||
,INT,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD>Ĥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10064,,
|
||||
,INT,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Һ״̬<EFBFBD>루R<EFBFBD><EFBFBD>,hold_register,10066,,
|
||||
,REAL,<EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ѹOK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10068,,
|
||||
,REAL,<EFBFBD><EFBFBD>·<EFBFBD><EFBFBD>ѹOK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ<EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10070,,
|
||||
,INT,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10072,,
|
||||
,INT,<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,10074,,
|
||||
,REAL,10mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,520,HMI<EFBFBD><EFBFBD>ַ,
|
||||
,REAL,12mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,522,,
|
||||
,REAL,16mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,524,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,526,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,528,,
|
||||
,REAL,ƽ<EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,530,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,532,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,534,,
|
||||
,REAL,<EFBFBD><EFBFBD>Ʒ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,536,,
|
||||
,REAL,<EFBFBD><EFBFBD>Ʒ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NG<EFBFBD><EFBFBD>ʣ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>R<EFBFBD><EFBFBD>,hold_register,538,,
|
||||
,,,,,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>10mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,540,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>12mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,542,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>16mm<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,544,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,546,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǻ<EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,548,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ƽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,550,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD>ø<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ǻ<EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,552,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD>õ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,554,,
|
||||
,REAL,<EFBFBD><EFBFBD><EFBFBD>ó<EFBFBD>Ʒ<EFBFBD><EFBFBD><EFBFBD>غ<EFBFBD><EFBFBD>ȣ<EFBFBD>W<EFBFBD><EFBFBD>,hold_register,556,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѹ<EFBFBD><EFBFBD>,hold_register,10050,,
|
||||
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ˮ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10052,,
|
||||
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,hold_register,10054,,
|
||||
,,,,,,
|
||||
,BOOL,<EFBFBD>쳣100-ϵͳ<CFB5>쳣,coil,1000,,
|
||||
,BOOL,<EFBFBD>쳣101-<2D><>ͣ,coil,1010,,
|
||||
,BOOL,<EFBFBD>쳣111-<2D><><EFBFBD><EFBFBD><EFBFBD>伱ͣ,coil,1110,,
|
||||
,BOOL,<EFBFBD>쳣112-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڹ<EFBFBD>դ<EFBFBD>ڵ<EFBFBD>,coil,1120,,
|
||||
,BOOL,<EFBFBD>쳣160-<2D><>Һǹͷȱ<CDB7><C8B1>,coil,1600,,
|
||||
,BOOL,<EFBFBD>쳣161-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1>,coil,1610,,
|
||||
,BOOL,<EFBFBD>쳣162-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1>,coil,1620,,
|
||||
,BOOL,<EFBFBD>쳣163-<2D><><EFBFBD><EFBFBD>Ƭȱ<C6AC><C8B1>,coil,1630,,
|
||||
,BOOL,<EFBFBD>쳣164-<2D><>Ĥȱ<C4A4><C8B1>,coil,1640,,
|
||||
,BOOL,<EFBFBD>쳣165-<2D><><EFBFBD><EFBFBD>Ƭȱ<C6AC><C8B1>,coil,1650,,
|
||||
,BOOL,<EFBFBD>쳣166-ƽ<><C6BD>ȱ<EFBFBD><C8B1>,coil,1660,,
|
||||
,BOOL,<EFBFBD>쳣167-<2D><><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1>,coil,1670,,
|
||||
,BOOL,<EFBFBD>쳣168-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȱ<EFBFBD><C8B1>,coil,1680,,
|
||||
,BOOL,<EFBFBD>쳣169-<2D><>Ʒ<EFBFBD><C6B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,1690,,
|
||||
,BOOL,<EFBFBD>쳣201-<2D>ŷ<EFBFBD><C5B7><EFBFBD>01<30>쳣,coil,2010,,
|
||||
,BOOL,<EFBFBD>쳣202-<2D>ŷ<EFBFBD><C5B7><EFBFBD>02<30>쳣,coil,2020,,
|
||||
,BOOL,<EFBFBD>쳣203-<2D>ŷ<EFBFBD><C5B7><EFBFBD>03<30>쳣,coil,2030,,
|
||||
,BOOL,<EFBFBD>쳣204-<2D>ŷ<EFBFBD><C5B7><EFBFBD>04<30>쳣,coil,2040,,
|
||||
,BOOL,<EFBFBD>쳣205-<2D>ŷ<EFBFBD><C5B7><EFBFBD>05<30>쳣,coil,2050,,
|
||||
,BOOL,<EFBFBD>쳣206-<2D>ŷ<EFBFBD><C5B7><EFBFBD>06<30>쳣,coil,2060,,
|
||||
,BOOL,<EFBFBD>쳣207-<2D>ŷ<EFBFBD><C5B7><EFBFBD>07<30>쳣,coil,2070,,
|
||||
,BOOL,<EFBFBD>쳣208-<2D>ŷ<EFBFBD><C5B7><EFBFBD>08<30>쳣,coil,2080,,
|
||||
,BOOL,<EFBFBD>쳣209-<2D>ŷ<EFBFBD><C5B7><EFBFBD>09<30>쳣,coil,2090,,
|
||||
,BOOL,<EFBFBD>쳣210-<2D>ŷ<EFBFBD><C5B7><EFBFBD>10<31>쳣,coil,2100,,
|
||||
,BOOL,<EFBFBD>쳣211-<2D>ŷ<EFBFBD><C5B7><EFBFBD>11<31>쳣,coil,2110,,
|
||||
,BOOL,<EFBFBD>쳣212-<2D>ŷ<EFBFBD><C5B7><EFBFBD>12<31>쳣,coil,2120,,
|
||||
,BOOL,<EFBFBD>쳣213-<2D>ŷ<EFBFBD><C5B7><EFBFBD>13<31>쳣,coil,2130,,
|
||||
,BOOL,<EFBFBD>쳣214-<2D>ŷ<EFBFBD><C5B7><EFBFBD>14<31>쳣,coil,2140,,
|
||||
,BOOL,<EFBFBD>쳣250-<2D><><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD>쳣,coil,2500,,
|
||||
,BOOL,<EFBFBD>쳣251-<2D><>ҺǹͨѶ<CDA8>쳣,coil,2510,,
|
||||
,BOOL,<EFBFBD>쳣252-<2D><>Һǹ<D2BA><C7B9><EFBFBD><EFBFBD>,coil,2520,,
|
||||
,BOOL,<EFBFBD>쳣256-<2D><>צ<EFBFBD>쳣,coil,2560,,
|
||||
,BOOL,<EFBFBD>쳣262-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ֪<CEB4><D6AA>λ<EFBFBD><CEBB><EFBFBD><EFBFBD>,coil,2620,,
|
||||
,BOOL,<EFBFBD>쳣263-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>X<EFBFBD><58>Y<EFBFBD><59>Z<EFBFBD><5A><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,2630,,
|
||||
,BOOL,<EFBFBD>쳣264-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӿ<EFBFBD><D3BE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,coil,2640,,
|
||||
,BOOL,<EFBFBD>쳣265-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>1#<23><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>ʧ<EFBFBD><CAA7>,coil,2650,,
|
||||
,BOOL,<EFBFBD>쳣266-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2#<23><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>ʧ<EFBFBD><CAA7>,coil,2660,,
|
||||
,BOOL,<EFBFBD>쳣267-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>3#<23><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>ʧ<EFBFBD><CAA7>,coil,2670,,
|
||||
,BOOL,<EFBFBD>쳣268-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>4#<23><><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1>ʧ<EFBFBD><CAA7>,coil,2680,,
|
||||
,BOOL,<EFBFBD>쳣269-RB<52><42><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><CAA7>,coil,2690,,
|
||||
,BOOL,<EFBFBD>쳣280-RB<52><42>ײ<EFBFBD>쳣,coil,2800,,
|
||||
,BOOL,<EFBFBD>쳣290-<2D>Ӿ<EFBFBD>ϵͳͨѶ<CDA8>쳣,coil,2900,,
|
||||
,BOOL,<EFBFBD>쳣291-<2D>Ӿ<EFBFBD><D3BE><EFBFBD>λNG<4E>쳣,coil,2910,,
|
||||
,BOOL,<EFBFBD>쳣292-ɨ<><C9A8>ǹͨѶ<CDA8>쳣,coil,2920,,
|
||||
,BOOL,<EFBFBD>쳣310-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3100,,
|
||||
,BOOL,<EFBFBD>쳣311-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3110,,
|
||||
,BOOL,<EFBFBD>쳣312-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3120,,
|
||||
,BOOL,<EFBFBD>쳣313-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3130,,
|
||||
,BOOL,<EFBFBD>쳣340-<2D><>·<EFBFBD><C2B7>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3400,,
|
||||
,BOOL,<EFBFBD>쳣342-<2D><>·<EFBFBD><C2B7>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3420,,
|
||||
,BOOL,<EFBFBD>쳣344-<2D><>·<EFBFBD><C2B7>ѹ<EFBFBD><D1B9>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3440,,
|
||||
,BOOL,<EFBFBD>쳣350-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3500,,
|
||||
,BOOL,<EFBFBD>쳣352-<2D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3520,,
|
||||
,BOOL,<EFBFBD>쳣354-<2D><>ϴ<EFBFBD><EFBFBD><DEB3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3540,,
|
||||
,BOOL,<EFBFBD>쳣356-<2D><>ϴ<EFBFBD><EFBFBD><DEB3><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3560,,
|
||||
,BOOL,<EFBFBD>쳣360-<2D><><EFBFBD><EFBFBD>Һƿ<D2BA><C6BF>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3600,,
|
||||
,BOOL,<EFBFBD>쳣362-<2D><>Һǹͷ<C7B9>ж<EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3620,,
|
||||
COIL ALARM_364_SERVO_DRIVE_ERROR,BOOL,<EFBFBD>쳣364-<2D>Լ<EFBFBD>ƿ<EFBFBD><C6BF>צ<EFBFBD><D7A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3640,,
|
||||
COIL ALARM_367_SERVO_DRIVER_ERROR,BOOL,<EFBFBD>쳣366-<2D>Լ<EFBFBD>ƿ<EFBFBD><C6BF>צ<EFBFBD><D7A6><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3660,,
|
||||
COIL ALARM_370_SERVO_MODULE_ERROR,BOOL,<EFBFBD>쳣370-ѹ<><D1B9>ģ<EFBFBD>鴵<EFBFBD><E9B4B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>쳣,coil,3700,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
,,,,,,
|
||||
COIL + <20><><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>/<2F><><EFBFBD><EFBFBD> + <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д+<2B>»<EFBFBD><C2BB>߷ָ<DFB7><D6B8><EFBFBD>--<2D><><EFBFBD><EFBFBD>boolֵ,,,,,,
|
||||
REG + <20><><EFBFBD><EFBFBD>ģ<EFBFBD><C4A3>/<2F><><EFBFBD><EFBFBD> + <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д+<2B>»<EFBFBD><C2BB>߷ָ<DFB7><D6B8><EFBFBD>--<2D><><EFBFBD>ԼĴ<D4BC><C4B4><EFBFBD>,,,,,,
|
||||
|
Binary file not shown.
@@ -1,64 +0,0 @@
|
||||
Name,DataType,InitValue,Comment,Attribute,DeviceType,Address,
|
||||
COIL_SYS_START_CMD,BOOL,,,,coil,8010,
|
||||
COIL_SYS_STOP_CMD,BOOL,,,,coil,8020,
|
||||
COIL_SYS_RESET_CMD,BOOL,,,,coil,8030,
|
||||
COIL_SYS_HAND_CMD,BOOL,,,,coil,8040,
|
||||
COIL_SYS_AUTO_CMD,BOOL,,,,coil,8050,
|
||||
COIL_SYS_INIT_CMD,BOOL,,,,coil,8060,
|
||||
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,,,,coil,8700,
|
||||
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,,,,coil,8710,unilab_rec_msg_succ_cmd
|
||||
COIL_SYS_START_STATUS,BOOL,,,,coil,8210,
|
||||
COIL_SYS_STOP_STATUS,BOOL,,,,coil,8220,
|
||||
COIL_SYS_RESET_STATUS,BOOL,,,,coil,8230,
|
||||
COIL_SYS_HAND_STATUS,BOOL,,,,coil,8240,
|
||||
COIL_SYS_AUTO_STATUS,BOOL,,,,coil,8250,
|
||||
COIL_SYS_INIT_STATUS,BOOL,,,,coil,8260,
|
||||
COIL_REQUEST_REC_MSG_STATUS,BOOL,,,,coil,8500,
|
||||
COIL_REQUEST_SEND_MSG_STATUS,BOOL,,,,coil,8510,request_send_msg_status
|
||||
REG_MSG_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,11000,
|
||||
REG_MSG_ELECTROLYTE_NUM,INT16,,,,hold_register,11002,unilab_send_msg_electrolyte_num
|
||||
REG_MSG_ELECTROLYTE_VOLUME,INT16,,,,hold_register,11004,unilab_send_msg_electrolyte_vol
|
||||
REG_MSG_ASSEMBLY_TYPE,INT16,,,,hold_register,11006,unilab_send_msg_assembly_type
|
||||
REG_MSG_ASSEMBLY_PRESSURE,INT16,,,,hold_register,11008,unilab_send_msg_assembly_pressure
|
||||
REG_DATA_ASSEMBLY_COIN_CELL_NUM,INT16,,,,hold_register,10000,data_assembly_coin_cell_num
|
||||
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,,,,hold_register,10002,data_open_circuit_voltage
|
||||
REG_DATA_AXIS_X_POS,FLOAT32,,,,hold_register,10004,
|
||||
REG_DATA_AXIS_Y_POS,FLOAT32,,,,hold_register,10006,
|
||||
REG_DATA_AXIS_Z_POS,FLOAT32,,,,hold_register,10008,
|
||||
REG_DATA_POLE_WEIGHT,FLOAT32,,,,hold_register,10010,data_pole_weight
|
||||
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,,,,hold_register,10012,data_assembly_time
|
||||
REG_DATA_ASSEMBLY_PRESSURE,INT16,,,,hold_register,10014,data_assembly_pressure
|
||||
REG_DATA_ELECTROLYTE_VOLUME,INT16,,,,hold_register,10016,data_electrolyte_volume
|
||||
REG_DATA_COIN_NUM,INT16,,,,hold_register,10018,data_coin_num
|
||||
REG_DATA_ELECTROLYTE_CODE,STRING,,,,hold_register,10020,data_electrolyte_code()
|
||||
REG_DATA_COIN_CELL_CODE,STRING,,,,hold_register,10030,data_coin_cell_code()
|
||||
REG_DATA_STACK_VISON_CODE,STRING,,,,hold_register,12004,data_stack_vision_code()
|
||||
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,,,,hold_register,10050,data_glove_box_pressure
|
||||
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,,,,hold_register,10052,data_glove_box_water_content
|
||||
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,,,hold_register,10054,data_glove_box_o2_content
|
||||
UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,8720,
|
||||
UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,8520,
|
||||
REG_MSG_ELECTROLYTE_NUM_USED,INT16,,,,hold_register,496,
|
||||
REG_DATA_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,10000,
|
||||
UNILAB_SEND_FINISHED_CMD,BOOL,,,,coil,8730,
|
||||
UNILAB_RECE_FINISHED_CMD,BOOL,,,,coil,8530,
|
||||
REG_DATA_ASSEMBLY_TYPE,INT16,,,,hold_register,10018,ASSEMBLY_TYPE7or8
|
||||
COIL_ALUMINUM_FOIL,BOOL,,使用铝箔垫,,coil,8340,
|
||||
REG_MSG_NE_PLATE_MATRIX,INT16,,负极片矩阵点位,,hold_register,440,
|
||||
REG_MSG_SEPARATOR_PLATE_MATRIX,INT16,,隔膜矩阵点位,,hold_register,450,
|
||||
REG_MSG_TIP_BOX_MATRIX,INT16,,移液枪头矩阵点位,,hold_register,480,
|
||||
REG_MSG_NE_PLATE_NUM,INT16,,负极片盘数,,hold_register,443,
|
||||
REG_MSG_SEPARATOR_PLATE_NUM,INT16,,隔膜盘数,,hold_register,453,
|
||||
REG_MSG_PRESS_MODE,BOOL,,压制模式(false:压力检测模式,True:距离模式),,coil,8360,电池压制模式
|
||||
,,,,,,,
|
||||
,BOOL,,视觉对位(false:使用,true:忽略),,coil,8300,视觉对位
|
||||
,BOOL,,复检(false:使用,true:忽略),,coil,8310,视觉复检
|
||||
,BOOL,,手套箱_左仓(false:使用,true:忽略),,coil,8320,手套箱左仓
|
||||
,BOOL,,手套箱_右仓(false:使用,true:忽略),,coil,8420,手套箱右仓
|
||||
,BOOL,,真空检知(false:使用,true:忽略),,coil,8350,真空检知
|
||||
,BOOL,,电解液添加模式(false:单次滴液,true:二次滴液),,coil,8370,滴液模式
|
||||
,BOOL,,正极片称重(false:使用,true:忽略),,coil,8380,正极片称重
|
||||
,BOOL,,正负极片组装方式(false:正装,true:倒装),,coil,8390,正负极反装
|
||||
,BOOL,,压制清洁(false:使用,true:忽略),,coil,8400,压制清洁
|
||||
,BOOL,,物料盘摆盘方式(false:水平摆盘,true:堆叠摆盘),,coil,8410,负极片摆盘方式
|
||||
REG_MSG_BATTERY_CLEAN_IGNORE,BOOL,,忽略电池清洁(false:使用,true:忽略),,coil,8460,
|
||||
|
@@ -0,0 +1,130 @@
|
||||
Name,DataType,InitValue,Comment,Attribute,DeviceType,Address,
|
||||
COIL_SYS_START_CMD,BOOL,,,,coil,8010,
|
||||
COIL_SYS_STOP_CMD,BOOL,,,,coil,8020,
|
||||
COIL_SYS_RESET_CMD,BOOL,,,,coil,8030,
|
||||
COIL_SYS_HAND_CMD,BOOL,,,,coil,8040,
|
||||
COIL_SYS_AUTO_CMD,BOOL,,,,coil,8050,
|
||||
COIL_SYS_INIT_CMD,BOOL,,,,coil,8060,
|
||||
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,,,,coil,8700,
|
||||
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,,,,coil,8710,unilab_rec_msg_succ_cmd
|
||||
COIL_SYS_START_STATUS,BOOL,,,,coil,8210,
|
||||
COIL_SYS_STOP_STATUS,BOOL,,,,coil,8220,
|
||||
COIL_SYS_RESET_STATUS,BOOL,,,,coil,8230,
|
||||
COIL_SYS_HAND_STATUS,BOOL,,,,coil,8240,
|
||||
COIL_SYS_AUTO_STATUS,BOOL,,,,coil,8250,
|
||||
COIL_SYS_INIT_STATUS,BOOL,,,,coil,8260,
|
||||
COIL_REQUEST_REC_MSG_STATUS,BOOL,,,,coil,8500,
|
||||
COIL_REQUEST_SEND_MSG_STATUS,BOOL,,,,coil,8510,request_send_msg_status
|
||||
REG_MSG_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,11000,
|
||||
REG_MSG_ELECTROLYTE_NUM,INT16,,,,hold_register,11002,unilab_send_msg_electrolyte_num
|
||||
REG_MSG_ELECTROLYTE_VOLUME,INT16,,,,hold_register,11004,unilab_send_msg_electrolyte_vol
|
||||
REG_MSG_ASSEMBLY_TYPE,INT16,,,,hold_register,11006,unilab_send_msg_assembly_type
|
||||
REG_MSG_ASSEMBLY_PRESSURE,INT16,,,,hold_register,11008,unilab_send_msg_assembly_pressure
|
||||
REG_DATA_ASSEMBLY_COIN_CELL_NUM,INT16,,,,hold_register,10000,data_assembly_coin_cell_num
|
||||
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,,,,hold_register,10002,data_open_circuit_voltage
|
||||
REG_DATA_AXIS_X_POS,FLOAT32,,,,hold_register,10004,
|
||||
REG_DATA_AXIS_Y_POS,FLOAT32,,,,hold_register,10006,
|
||||
REG_DATA_AXIS_Z_POS,FLOAT32,,,,hold_register,10008,
|
||||
REG_DATA_POLE_WEIGHT,FLOAT32,,,,hold_register,10010,data_pole_weight
|
||||
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,,,,hold_register,10012,data_assembly_time
|
||||
REG_DATA_ASSEMBLY_PRESSURE,INT16,,,,hold_register,10014,data_assembly_pressure
|
||||
REG_DATA_ELECTROLYTE_VOLUME,INT16,,,,hold_register,10016,data_electrolyte_volume
|
||||
REG_DATA_COIN_NUM,INT16,,,,hold_register,10018,data_coin_num
|
||||
REG_DATA_ELECTROLYTE_CODE,STRING,,,,hold_register,10020,data_electrolyte_code()
|
||||
REG_DATA_COIN_CELL_CODE,STRING,,,,hold_register,10030,data_coin_cell_code()
|
||||
REG_DATA_STACK_VISON_CODE,STRING,,,,hold_register,12004,data_stack_vision_code()
|
||||
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,,,,hold_register,10050,data_glove_box_pressure
|
||||
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,,,,hold_register,10052,data_glove_box_water_content
|
||||
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,,,hold_register,10054,data_glove_box_o2_content
|
||||
UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,8720,
|
||||
UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,8520,
|
||||
REG_MSG_ELECTROLYTE_NUM_USED,INT16,,,,hold_register,496,
|
||||
REG_DATA_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,10000,
|
||||
UNILAB_SEND_FINISHED_CMD,BOOL,,,,coil,8730,
|
||||
UNILAB_RECE_FINISHED_CMD,BOOL,,,,coil,8530,
|
||||
REG_DATA_ASSEMBLY_TYPE,INT16,,,,hold_register,10018,ASSEMBLY_TYPE7or8
|
||||
REG_UNILAB_INTERACT,BOOL,,,,coil,8450,
|
||||
,,,,,coil,8320,
|
||||
COIL_ALUMINUM_FOIL,BOOL,,,,coil,8340,
|
||||
REG_MSG_NE_PLATE_MATRIX,INT16,,,,hold_register,440,
|
||||
REG_MSG_SEPARATOR_PLATE_MATRIX,INT16,,,,hold_register,450,
|
||||
REG_MSG_TIP_BOX_MATRIX,INT16,,,,hold_register,480,
|
||||
REG_MSG_NE_PLATE_NUM,INT16,,,,hold_register,443,
|
||||
REG_MSG_SEPARATOR_PLATE_NUM,INT16,,,,hold_register,453,
|
||||
REG_MSG_PRESS_MODE,BOOL,,,,coil,8360,
|
||||
,BOOL,,,,coil,8300,
|
||||
,BOOL,,,,coil,8310,
|
||||
COIL_GB_L_IGNORE_CMD,BOOL,,,,coil,8320,
|
||||
COIL_GB_R_IGNORE_CMD,BOOL,,,,coil,8420,
|
||||
,BOOL,,,,coil,8350,
|
||||
COIL_ELECTROLYTE_DUAL_DROP_MODE,BOOL,,,,coil,8370,
|
||||
,BOOL,,,,coil,8380,
|
||||
,BOOL,,,,coil,8390,
|
||||
,BOOL,,,,coil,8400,
|
||||
,BOOL,,,,coil,8410,
|
||||
REG_MSG_DUAL_DROP_FIRST_VOLUME,INT16,,,,hold_register,4001,
|
||||
COIL_DUAL_DROP_SUCTION_TIMING,BOOL,,,,coil,8430,
|
||||
COIL_DUAL_DROP_START_TIMING,BOOL,,,,coil,8470,
|
||||
REG_MSG_BATTERY_CLEAN_IGNORE,BOOL,,,,coil,8460,
|
||||
COIL_ALARM_100_SYSTEM_ERROR,BOOL,,,,coil,1000,异常100-系统异常
|
||||
COIL_ALARM_101_EMERGENCY_STOP,BOOL,,,,coil,1010,异常101-急停
|
||||
COIL_ALARM_111_GLOVEBOX_EMERGENCY_STOP,BOOL,,,,coil,1110,异常111-手套箱急停
|
||||
COIL_ALARM_112_GLOVEBOX_GRATING_BLOCKED,BOOL,,,,coil,1120,异常112-手套箱内光栅遮挡
|
||||
COIL_ALARM_160_PIPETTE_TIP_SHORTAGE,BOOL,,,,coil,1600,异常160-移液枪头缺料
|
||||
COIL_ALARM_161_POSITIVE_SHELL_SHORTAGE,BOOL,,,,coil,1610,异常161-正极壳缺料
|
||||
COIL_ALARM_162_ALUMINUM_FOIL_SHORTAGE,BOOL,,,,coil,1620,异常162-铝箔垫缺料
|
||||
COIL_ALARM_163_POSITIVE_PLATE_SHORTAGE,BOOL,,,,coil,1630,异常163-正极片缺料
|
||||
COIL_ALARM_164_SEPARATOR_SHORTAGE,BOOL,,,,coil,1640,异常164-隔膜缺料
|
||||
COIL_ALARM_165_NEGATIVE_PLATE_SHORTAGE,BOOL,,,,coil,1650,异常165-负极片缺料
|
||||
COIL_ALARM_166_FLAT_WASHER_SHORTAGE,BOOL,,,,coil,1660,异常166-平垫缺料
|
||||
COIL_ALARM_167_SPRING_WASHER_SHORTAGE,BOOL,,,,coil,1670,异常167-弹垫缺料
|
||||
COIL_ALARM_168_NEGATIVE_SHELL_SHORTAGE,BOOL,,,,coil,1680,异常168-负极壳缺料
|
||||
COIL_ALARM_169_FINISHED_BATTERY_FULL,BOOL,,,,coil,1690,异常169-成品电池满料
|
||||
COIL_ALARM_201_SERVO_AXIS_01_ERROR,BOOL,,,,coil,2010,异常201-伺服轴01异常
|
||||
COIL_ALARM_202_SERVO_AXIS_02_ERROR,BOOL,,,,coil,2020,异常202-伺服轴02异常
|
||||
COIL_ALARM_203_SERVO_AXIS_03_ERROR,BOOL,,,,coil,2030,异常203-伺服轴03异常
|
||||
COIL_ALARM_204_SERVO_AXIS_04_ERROR,BOOL,,,,coil,2040,异常204-伺服轴04异常
|
||||
COIL_ALARM_205_SERVO_AXIS_05_ERROR,BOOL,,,,coil,2050,异常205-伺服轴05异常
|
||||
COIL_ALARM_206_SERVO_AXIS_06_ERROR,BOOL,,,,coil,2060,异常206-伺服轴06异常
|
||||
COIL_ALARM_207_SERVO_AXIS_07_ERROR,BOOL,,,,coil,2070,异常207-伺服轴07异常
|
||||
COIL_ALARM_208_SERVO_AXIS_08_ERROR,BOOL,,,,coil,2080,异常208-伺服轴08异常
|
||||
COIL_ALARM_209_SERVO_AXIS_09_ERROR,BOOL,,,,coil,2090,异常209-伺服轴09异常
|
||||
COIL_ALARM_210_SERVO_AXIS_10_ERROR,BOOL,,,,coil,2100,异常210-伺服轴10异常
|
||||
COIL_ALARM_211_SERVO_AXIS_11_ERROR,BOOL,,,,coil,2110,异常211-伺服轴11异常
|
||||
COIL_ALARM_212_SERVO_AXIS_12_ERROR,BOOL,,,,coil,2120,异常212-伺服轴12异常
|
||||
COIL_ALARM_213_SERVO_AXIS_13_ERROR,BOOL,,,,coil,2130,异常213-伺服轴13异常
|
||||
COIL_ALARM_214_SERVO_AXIS_14_ERROR,BOOL,,,,coil,2140,异常214-伺服轴14异常
|
||||
COIL_ALARM_250_OTHER_COMPONENT_ERROR,BOOL,,,,coil,2500,异常250-其他元件异常
|
||||
COIL_ALARM_251_PIPETTE_COMM_ERROR,BOOL,,,,coil,2510,异常251-移液枪通讯异常
|
||||
COIL_ALARM_252_PIPETTE_ALARM,BOOL,,,,coil,2520,异常252-移液枪报警
|
||||
COIL_ALARM_256_ELECTRIC_GRIPPER_ERROR,BOOL,,,,coil,2560,异常256-电爪异常
|
||||
COIL_ALARM_262_RB_UNKNOWN_POSITION_ERROR,BOOL,,,,coil,2620,异常262-RB报警:未知点位错误
|
||||
COIL_ALARM_263_RB_XYZ_PARAM_LIMIT_ERROR,BOOL,,,,coil,2630,异常263-RB报警:X、Y、Z参数超限制
|
||||
COIL_ALARM_264_RB_VISION_PARAM_ERROR,BOOL,,,,coil,2640,异常264-RB报警:视觉参数误差过大
|
||||
COIL_ALARM_265_RB_NOZZLE_1_PICK_FAIL,BOOL,,,,coil,2650,异常265-RB报警:1#吸嘴取料失败
|
||||
COIL_ALARM_266_RB_NOZZLE_2_PICK_FAIL,BOOL,,,,coil,2660,异常266-RB报警:2#吸嘴取料失败
|
||||
COIL_ALARM_267_RB_NOZZLE_3_PICK_FAIL,BOOL,,,,coil,2670,异常267-RB报警:3#吸嘴取料失败
|
||||
COIL_ALARM_268_RB_NOZZLE_4_PICK_FAIL,BOOL,,,,coil,2680,异常268-RB报警:4#吸嘴取料失败
|
||||
COIL_ALARM_269_RB_TRAY_PICK_FAIL,BOOL,,,,coil,2690,异常269-RB报警:取物料盘失败
|
||||
COIL_ALARM_280_RB_COLLISION_ERROR,BOOL,,,,coil,2800,异常280-RB碰撞异常
|
||||
COIL_ALARM_290_VISION_SYSTEM_COMM_ERROR,BOOL,,,,coil,2900,异常290-视觉系统通讯异常
|
||||
COIL_ALARM_291_VISION_ALIGNMENT_NG,BOOL,,,,coil,2910,异常291-视觉对位NG异常
|
||||
COIL_ALARM_292_BARCODE_SCANNER_COMM_ERROR,BOOL,,,,coil,2920,异常292-扫码枪通讯异常
|
||||
COIL_ALARM_310_OCV_TRANSFER_NOZZLE_SUCTION_ERROR,BOOL,,,,coil,3100,异常310-开电移载吸嘴吸真空异常
|
||||
COIL_ALARM_311_OCV_TRANSFER_NOZZLE_BREAK_ERROR,BOOL,,,,coil,3110,异常311-开电移载吸嘴破真空异常
|
||||
COIL_ALARM_312_WEIGHT_TRANSFER_NOZZLE_SUCTION_ERROR,BOOL,,,,coil,3120,异常312-称重移载吸嘴吸真空异常
|
||||
COIL_ALARM_313_WEIGHT_TRANSFER_NOZZLE_BREAK_ERROR,BOOL,,,,coil,3130,异常313-称重移载吸嘴破真空异常
|
||||
COIL_ALARM_340_OCV_NOZZLE_TRANSFER_CYLINDER_ERROR,BOOL,,,,coil,3400,异常340-开路电压吸嘴移载气缸异常
|
||||
COIL_ALARM_342_OCV_NOZZLE_LIFT_CYLINDER_ERROR,BOOL,,,,coil,3420,异常342-开路电压吸嘴升降气缸异常
|
||||
COIL_ALARM_344_OCV_CRIMPING_CYLINDER_ERROR,BOOL,,,,coil,3440,异常344-开路电压旋压气缸异常
|
||||
COIL_ALARM_350_WEIGHT_NOZZLE_TRANSFER_CYLINDER_ERROR,BOOL,,,,coil,3500,异常350-称重吸嘴移载气缸异常
|
||||
COIL_ALARM_352_WEIGHT_NOZZLE_LIFT_CYLINDER_ERROR,BOOL,,,,coil,3520,异常352-称重吸嘴升降气缸异常
|
||||
COIL_ALARM_354_CLEANING_CLOTH_TRANSFER_CYLINDER_ERROR,BOOL,,,,coil,3540,异常354-清洗无尘布移载气缸异常
|
||||
COIL_ALARM_356_CLEANING_CLOTH_PRESS_CYLINDER_ERROR,BOOL,,,,coil,3560,异常356-清洗无尘布压紧气缸异常
|
||||
COIL_ALARM_360_ELECTROLYTE_BOTTLE_POSITION_CYLINDER_ERROR,BOOL,,,,coil,3600,异常360-电解液瓶定位气缸异常
|
||||
COIL_ALARM_362_PIPETTE_TIP_BOX_POSITION_CYLINDER_ERROR,BOOL,,,,coil,3620,异常362-移液枪头盒定位气缸异常
|
||||
COIL_ALARM_364_REAGENT_BOTTLE_GRIPPER_LIFT_CYLINDER_ERROR,BOOL,,,,coil,3640,异常364-试剂瓶夹爪升降气缸异常
|
||||
COIL_ALARM_366_REAGENT_BOTTLE_GRIPPER_CYLINDER_ERROR,BOOL,,,,coil,3660,异常366-试剂瓶夹爪气缸异常
|
||||
COIL_ALARM_370_PRESS_MODULE_BLOW_CYLINDER_ERROR,BOOL,,,,coil,3700,异常370-压制模块吹气气缸异常
|
||||
COIL_ALARM_151_ELECTROLYTE_BOTTLE_POSITION_ERROR,BOOL,,,,coil,1510,异常151-电解液瓶定位在籍异常
|
||||
COIL_ALARM_152_ELECTROLYTE_BOTTLE_CAP_ERROR,BOOL,,,,coil,1520,异常152-电解液瓶盖在籍异常
|
||||
|
@@ -0,0 +1,2 @@
|
||||
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
|
||||
20251224_172304,-5.537573695435827e-37,-48.45097351074219,1.372190511464448e+16,3820,30,7,b'\x00\x00d\x00eaoR',b'\x00\x00\x01\x00\x00\x00\r\n'
|
||||
|
@@ -0,0 +1,2 @@
|
||||
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
|
||||
20251225_105600,5.566961054206384e-37,-53149746331648.0,3271557120.0,3658,10,7,b'\x00\x00d\x00eaoR',b'\x00\x00\x01\x00\x00\x00\r\n'
|
||||
|
@@ -0,0 +1,2 @@
|
||||
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
|
||||
20251229_161836,-5.537573695435827e-37,8.919000478163591e+20,-3.806253867691382e-29,3544,20,7,b'\x00\x00d\x00eaoR',b'\x00\x00\x01\x00\x00\x00\r\n'
|
||||
|
@@ -0,0 +1,9 @@
|
||||
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
|
||||
20251230_182319,0.01600000075995922,13.899999618530273,175.0,3836,20,7,b'\x00\x00d\x00eaoR',b'\x00\x00\x01\x00\x00\x00\r\n'
|
||||
20251230_185306,0.01600000075995922,13.639999389648438,625.0,3819,20,7,deaoR,
|
||||
20251230_192124,0.0,8.949999809265137,414.0,3803,20,8,deaoR,
|
||||
20251230_195621,3.8359999656677246,10.069999694824219,205.0,3350,20,8,LG600001,19311909
|
||||
20251230_200830,0.7929999828338623,9.34999942779541,18.0,3318,20,8,LG600001,19533419
|
||||
20251230_201123,0.0,9.169999122619629,17.0,3269,20,8,LG600001,20054389
|
||||
20251230_201410,0.0,9.569999694824219,18.0,3237,20,8,LG600001,YS102704
|
||||
20251230_201659,0.0,9.699999809265137,169.0,3318,20,8,LG600001,20112754
|
||||
|
@@ -0,0 +1,3 @@
|
||||
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
|
||||
20260106_221708,0.03200000151991844,26.26999855041504,18.0,3803,30,7,NoRead88,22000063
|
||||
20260106_221957,0.11299999803304672,26.26999855041504,170.0,3787,30,7,LG600001,22124813
|
||||
|
@@ -0,0 +1,536 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""扣式电池组装系统 - 交互式CSV导出演示脚本(增强版)
|
||||
|
||||
此脚本专为交互式使用优化,提供清洁的命令行界面,
|
||||
禁用了所有调试信息输出,确保用户可以顺畅地输入命令。
|
||||
|
||||
主要功能:
|
||||
1. 手动导出设备数据到CSV文件(包含6个关键数据字段)
|
||||
2. 查看CSV文件内容和导出状态
|
||||
3. 兼容原有的电池组装完成状态自动导出功能
|
||||
4. 实时查看设备数据和电池数量
|
||||
|
||||
数据字段:
|
||||
- timestamp: 时间戳
|
||||
- assembly_time: 单颗电池组装时间(秒)
|
||||
- open_circuit_voltage: 开路电压值(V)
|
||||
- pole_weight: 正极片称重数据(g)
|
||||
- battery_qr_code: 电池二维码序列号
|
||||
- electrolyte_qr_code: 电解液二维码序列号
|
||||
|
||||
使用方法:
|
||||
1. 确保设备已连接并可正常通信
|
||||
2. 运行此脚本: python interactive_battery_export_demo.py
|
||||
3. 使用交互式命令控制导出功能
|
||||
"""
|
||||
|
||||
import time
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import csv
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
# 完全禁用所有调试和信息级别的日志输出
|
||||
logging.getLogger().setLevel(logging.CRITICAL)
|
||||
logging.getLogger('pymodbus').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('unilabos').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('pymodbus.logging').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('pymodbus.logging.tcp').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('pymodbus.logging.base').setLevel(logging.CRITICAL)
|
||||
logging.getLogger('pymodbus.logging.decoders').setLevel(logging.CRITICAL)
|
||||
|
||||
# 添加当前目录到Python路径,以便正确导入模块
|
||||
current_dir = Path(__file__).parent
|
||||
sys.path.insert(0, str(current_dir.parent.parent.parent)) # 添加unilabos根目录
|
||||
sys.path.insert(0, str(current_dir)) # 添加当前目录
|
||||
|
||||
# 导入扣式电池组装系统
|
||||
try:
|
||||
from unilabos.devices.coin_cell_assembly.coin_cell_assembly_system import Coin_Cell_Assembly
|
||||
except ImportError:
|
||||
# 如果上述导入失败,尝试直接导入
|
||||
try:
|
||||
from coin_cell_assembly_system import Coin_Cell_Assembly
|
||||
except ImportError as e:
|
||||
print(f"导入错误: {e}")
|
||||
print("请确保在正确的目录下运行此脚本,或者将unilabos添加到Python路径中")
|
||||
sys.exit(1)
|
||||
|
||||
def clear_screen():
|
||||
"""清屏函数"""
|
||||
os.system('cls' if os.name == 'nt' else 'clear')
|
||||
|
||||
def print_header():
|
||||
"""打印程序头部信息"""
|
||||
print("="*60)
|
||||
print(" 扣式电池组装系统 - 交互式CSV导出控制台")
|
||||
print("="*60)
|
||||
print()
|
||||
|
||||
def print_commands():
|
||||
"""打印可用命令"""
|
||||
print("可用命令:")
|
||||
print(" start - 启动电池组装完成状态导出")
|
||||
print(" stop - 停止导出")
|
||||
print(" status - 查看导出状态")
|
||||
print(" data - 查看当前设备数据")
|
||||
print(" count - 查看当前电池数量")
|
||||
print(" export - 手动导出当前数据到CSV")
|
||||
print(" setpath - 设置自定义CSV文件路径")
|
||||
print(" view - 查看CSV文件内容")
|
||||
print(" force - 强制继续CSV导出(即使设备停止)")
|
||||
print(" detail - 显示详细设备状态")
|
||||
print(" clear - 清屏")
|
||||
print(" help - 显示帮助信息")
|
||||
print(" quit - 退出程序")
|
||||
print("-"*60)
|
||||
|
||||
def print_status_info(device, csv_file_path):
|
||||
"""打印状态信息"""
|
||||
try:
|
||||
status = device.get_csv_export_status()
|
||||
is_running = status.get('running', False)
|
||||
export_file = status.get('file_path', None)
|
||||
thread_alive = status.get('thread_alive', False)
|
||||
device_status = status.get('device_status', 'N/A')
|
||||
battery_count = status.get('battery_count', 'N/A')
|
||||
|
||||
print(f"导出状态: {'运行中' if is_running else '已停止'}")
|
||||
print(f"导出文件: {export_file if export_file else 'N/A'}")
|
||||
print(f"线程状态: {'活跃' if thread_alive else '非活跃'}")
|
||||
print(f"设备状态: {device_status}")
|
||||
print(f"电池计数: {battery_count}")
|
||||
|
||||
# 检查手动导出的CSV文件
|
||||
if os.path.exists(csv_file_path):
|
||||
file_size = os.path.getsize(csv_file_path)
|
||||
print(f"手动导出文件: {csv_file_path} ({file_size} 字节)")
|
||||
else:
|
||||
print(f"手动导出文件: {csv_file_path} (不存在)")
|
||||
|
||||
# 显示设备运行状态
|
||||
try:
|
||||
print("\n=== 设备运行状态 ===")
|
||||
print(f"系统启动状态: {device.sys_start_status}")
|
||||
print(f"系统停止状态: {device.sys_stop_status}")
|
||||
print(f"自动模式状态: {device.sys_auto_status}")
|
||||
print(f"手动模式状态: {device.sys_hand_status}")
|
||||
except Exception as e:
|
||||
print(f"获取设备运行状态失败: {e}")
|
||||
|
||||
except Exception as e:
|
||||
print(f"获取状态失败: {e}")
|
||||
|
||||
def collect_device_data(device):
|
||||
"""收集设备的六个关键数据"""
|
||||
try:
|
||||
timestamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
|
||||
# 读取各项数据,添加错误处理和重试机制
|
||||
try:
|
||||
assembly_time = device.data_assembly_time # 单颗电池组装时间(秒)
|
||||
# 确保返回的是数值类型
|
||||
if isinstance(assembly_time, (list, tuple)) and len(assembly_time) > 0:
|
||||
assembly_time = float(assembly_time[0])
|
||||
else:
|
||||
assembly_time = float(assembly_time)
|
||||
except Exception as e:
|
||||
print(f"读取组装时间失败: {e}")
|
||||
assembly_time = 0.0
|
||||
|
||||
try:
|
||||
open_circuit_voltage = device.data_open_circuit_voltage # 开路电压值(V)
|
||||
# 确保返回的是数值类型
|
||||
if isinstance(open_circuit_voltage, (list, tuple)) and len(open_circuit_voltage) > 0:
|
||||
open_circuit_voltage = float(open_circuit_voltage[0])
|
||||
else:
|
||||
open_circuit_voltage = float(open_circuit_voltage)
|
||||
except Exception as e:
|
||||
print(f"读取开路电压失败: {e}")
|
||||
open_circuit_voltage = 0.0
|
||||
|
||||
try:
|
||||
pole_weight = device.data_pole_weight # 正极片称重数据(g)
|
||||
# 确保返回的是数值类型
|
||||
if isinstance(pole_weight, (list, tuple)) and len(pole_weight) > 0:
|
||||
pole_weight = float(pole_weight[0])
|
||||
else:
|
||||
pole_weight = float(pole_weight)
|
||||
except Exception as e:
|
||||
print(f"读取正极片重量失败: {e}")
|
||||
pole_weight = 0.0
|
||||
|
||||
try:
|
||||
assembly_pressure = device.data_assembly_pressure # 电池压制力(N)
|
||||
# 确保返回的是数值类型
|
||||
if isinstance(assembly_pressure, (list, tuple)) and len(assembly_pressure) > 0:
|
||||
assembly_pressure = int(assembly_pressure[0])
|
||||
else:
|
||||
assembly_pressure = int(assembly_pressure)
|
||||
except Exception as e:
|
||||
print(f"读取压制力失败: {e}")
|
||||
assembly_pressure = 0
|
||||
|
||||
try:
|
||||
battery_qr_code = device.data_coin_cell_code # 电池二维码序列号
|
||||
# 处理字符串类型数据
|
||||
if isinstance(battery_qr_code, str):
|
||||
battery_qr_code = battery_qr_code.strip()
|
||||
else:
|
||||
battery_qr_code = str(battery_qr_code)
|
||||
except Exception as e:
|
||||
print(f"读取电池二维码失败: {e}")
|
||||
battery_qr_code = "N/A"
|
||||
|
||||
try:
|
||||
electrolyte_qr_code = device.data_electrolyte_code # 电解液二维码序列号
|
||||
# 处理字符串类型数据
|
||||
if isinstance(electrolyte_qr_code, str):
|
||||
electrolyte_qr_code = electrolyte_qr_code.strip()
|
||||
else:
|
||||
electrolyte_qr_code = str(electrolyte_qr_code)
|
||||
except Exception as e:
|
||||
print(f"读取电解液二维码失败: {e}")
|
||||
electrolyte_qr_code = "N/A"
|
||||
|
||||
# 获取电池数量
|
||||
try:
|
||||
battery_count = device.data_assembly_coin_cell_num
|
||||
# 确保返回的是数值类型
|
||||
if isinstance(battery_count, (list, tuple)) and len(battery_count) > 0:
|
||||
battery_count = int(battery_count[0])
|
||||
else:
|
||||
battery_count = int(battery_count)
|
||||
except Exception as e:
|
||||
print(f"读取电池数量失败: {e}")
|
||||
battery_count = 0
|
||||
|
||||
return {
|
||||
'Timestamp': timestamp,
|
||||
'Battery_Count': battery_count,
|
||||
'Assembly_Time': assembly_time,
|
||||
'Open_Circuit_Voltage': open_circuit_voltage,
|
||||
'Pole_Weight': pole_weight,
|
||||
'Assembly_Pressure': assembly_pressure,
|
||||
'Battery_Code': battery_qr_code,
|
||||
'Electrolyte_Code': electrolyte_qr_code
|
||||
}
|
||||
except Exception as e:
|
||||
print(f"收集数据时出错: {e}")
|
||||
return None
|
||||
|
||||
def export_to_csv(data, csv_file_path):
|
||||
"""将数据导出到CSV文件"""
|
||||
try:
|
||||
# 检查文件是否存在,如果不存在则创建并写入表头
|
||||
file_exists = os.path.exists(csv_file_path)
|
||||
|
||||
# 确保目录存在
|
||||
csv_dir = os.path.dirname(csv_file_path)
|
||||
if csv_dir:
|
||||
os.makedirs(csv_dir, exist_ok=True)
|
||||
|
||||
# 确保数值字段为正确的数值类型,避免前导单引号问题
|
||||
processed_data = data.copy()
|
||||
|
||||
# 处理数值字段,确保它们是数值类型而不是字符串,增强错误处理
|
||||
numeric_fields = ['Battery_Count', 'Assembly_Time', 'Open_Circuit_Voltage', 'Pole_Weight', 'Assembly_Pressure']
|
||||
for field in numeric_fields:
|
||||
if field in processed_data:
|
||||
try:
|
||||
value = processed_data[field]
|
||||
# 处理可能的列表或元组类型
|
||||
if isinstance(value, (list, tuple)) and len(value) > 0:
|
||||
value = value[0]
|
||||
|
||||
if field == 'Battery_Count' or field == 'Assembly_Pressure':
|
||||
processed_data[field] = int(float(value)) # 先转float再转int,处理字符串数字
|
||||
else:
|
||||
processed_data[field] = float(value)
|
||||
except (ValueError, TypeError, IndexError) as e:
|
||||
print(f"字段 {field} 类型转换失败: {e}, 使用默认值")
|
||||
processed_data[field] = 0 if field == 'Battery_Count' else 0.0
|
||||
|
||||
# 处理字符串字段
|
||||
for field in ['Battery_Code', 'Electrolyte_Code']:
|
||||
if field in processed_data:
|
||||
try:
|
||||
value = processed_data[field]
|
||||
if isinstance(value, (list, tuple)) and len(value) > 0:
|
||||
value = value[0]
|
||||
processed_data[field] = str(value).strip()
|
||||
except Exception as e:
|
||||
print(f"字段 {field} 处理失败: {e}, 使用默认值")
|
||||
processed_data[field] = "N/A"
|
||||
|
||||
with open(csv_file_path, 'a', newline='', encoding='utf-8') as csvfile:
|
||||
fieldnames = ['Timestamp', 'Battery_Count', 'Assembly_Time', 'Open_Circuit_Voltage',
|
||||
'Pole_Weight', 'Assembly_Pressure', 'Battery_QR_Code', 'Electrolyte_QR_Code']
|
||||
writer = csv.DictWriter(csvfile, fieldnames=fieldnames, quoting=csv.QUOTE_MINIMAL)
|
||||
|
||||
# 如果文件不存在,写入表头
|
||||
if not file_exists:
|
||||
writer.writeheader()
|
||||
print(f"创建新的CSV文件: {csv_file_path}")
|
||||
|
||||
# 写入数据
|
||||
writer.writerow(processed_data)
|
||||
print(f"数据已导出到: {csv_file_path}")
|
||||
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"导出CSV时出错: {e}")
|
||||
return False
|
||||
|
||||
def view_csv_content(csv_file_path, lines=10):
|
||||
"""查看CSV文件内容"""
|
||||
try:
|
||||
if not os.path.exists(csv_file_path):
|
||||
print("CSV文件不存在")
|
||||
return
|
||||
|
||||
with open(csv_file_path, 'r', encoding='utf-8') as csvfile:
|
||||
content = csvfile.readlines()
|
||||
|
||||
if not content:
|
||||
print("CSV文件为空")
|
||||
return
|
||||
|
||||
print(f"CSV文件内容 (显示最后{min(lines, len(content))}行):")
|
||||
print("-" * 80)
|
||||
|
||||
# 显示表头
|
||||
if len(content) > 0:
|
||||
print(content[0].strip())
|
||||
print("-" * 80)
|
||||
|
||||
# 显示最后几行数据
|
||||
start_line = max(1, len(content) - lines + 1)
|
||||
for i in range(start_line, len(content)):
|
||||
print(content[i].strip())
|
||||
|
||||
print("-" * 80)
|
||||
print(f"总共 {len(content)-1} 条数据记录")
|
||||
|
||||
except Exception as e:
|
||||
print(f"读取CSV文件时出错: {e}")
|
||||
|
||||
def interactive_demo():
|
||||
"""
|
||||
交互式演示模式(优化版)
|
||||
"""
|
||||
clear_screen()
|
||||
print_header()
|
||||
|
||||
print("正在初始化设备连接...")
|
||||
print("设备地址: 192.168.1.20:502")
|
||||
print("正在尝试连接...")
|
||||
|
||||
try:
|
||||
device = Coin_Cell_Assembly(address="192.168.1.20", port="502")
|
||||
print("✓ 设备连接成功")
|
||||
|
||||
# 测试设备数据读取
|
||||
print("正在测试设备数据读取...")
|
||||
try:
|
||||
test_count = device.data_assembly_coin_cell_num
|
||||
print(f"✓ 当前电池数量: {test_count}")
|
||||
except Exception as e:
|
||||
print(f"⚠ 数据读取测试失败: {e}")
|
||||
print("设备连接正常,但数据读取可能存在问题")
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ 设备连接失败: {e}")
|
||||
print("请检查以下项目:")
|
||||
print("1. 设备是否已开机并正常运行")
|
||||
print("2. 网络连接是否正常")
|
||||
print("3. 设备IP地址是否为192.168.1.20")
|
||||
print("4. Modbus服务是否在端口502上运行")
|
||||
input("按回车键退出...")
|
||||
return
|
||||
|
||||
csv_file_path = "battery_data_export.csv"
|
||||
print(f"CSV文件路径: {os.path.abspath(csv_file_path)}")
|
||||
print()
|
||||
print("功能说明:")
|
||||
print("- 支持手动导出当前设备数据到CSV文件")
|
||||
print("- 包含六个关键数据: 组装时间、开路电压、正极片重量、电池码、电解液码")
|
||||
print("- 电池码和电解液码可能显示为N/A(当二维码读取失败时)")
|
||||
print("- 支持查看CSV文件内容和导出状态")
|
||||
print("- 兼容原有的电池组装完成状态自动导出功能")
|
||||
print()
|
||||
|
||||
print_commands()
|
||||
|
||||
while True:
|
||||
try:
|
||||
command = input("\n请输入命令 > ").strip().lower()
|
||||
|
||||
if command == "start":
|
||||
print("启动电池组装完成状态导出...")
|
||||
try:
|
||||
success, message = device.start_battery_completion_export(csv_file_path)
|
||||
if success:
|
||||
print(f"✓ {message}")
|
||||
print("系统正在监控电池组装完成状态...")
|
||||
else:
|
||||
print(f"✗ {message}")
|
||||
except Exception as e:
|
||||
print(f"启动导出时出错: {e}")
|
||||
|
||||
elif command == "stop":
|
||||
print("停止导出...")
|
||||
try:
|
||||
success, message = device.stop_csv_export()
|
||||
if success:
|
||||
print(f"✓ {message}")
|
||||
else:
|
||||
print(f"✗ {message}")
|
||||
except Exception as e:
|
||||
print(f"停止导出时出错: {e}")
|
||||
|
||||
elif command == "force":
|
||||
print("强制继续CSV导出...")
|
||||
try:
|
||||
success, message = device.force_continue_csv_export()
|
||||
if success:
|
||||
print(f"✓ {message}")
|
||||
print("注意: CSV导出将继续监控数据变化,即使设备处于停止状态")
|
||||
else:
|
||||
print(f"✗ {message}")
|
||||
except AttributeError:
|
||||
print("✗ 当前版本不支持强制继续功能")
|
||||
except Exception as e:
|
||||
print(f"✗ 强制继续失败: {e}")
|
||||
|
||||
elif command == "detail":
|
||||
print("=== 详细设备状态 ===")
|
||||
print_status_info(device, csv_file_path)
|
||||
|
||||
elif command == "status":
|
||||
print_status_info(device, csv_file_path)
|
||||
|
||||
elif command == "data":
|
||||
print("读取当前设备数据...")
|
||||
try:
|
||||
data = collect_device_data(device)
|
||||
if data:
|
||||
print("\n=== 当前设备数据 ===")
|
||||
print(f"时间戳: {data['Timestamp']}")
|
||||
print(f"电池数量: {data['Battery_Count']}")
|
||||
print(f"单颗电池组装时间: {data['Assembly_Time']:.2f} 秒")
|
||||
print(f"开路电压值: {data['Open_Circuit_Voltage']:.4f} V")
|
||||
print(f"正极片称重数据: {data['Pole_Weight']:.4f} g")
|
||||
print(f"电池压制力: {data['Assembly_Pressure']} N")
|
||||
print(f"电池二维码序列号: {data['Battery_Code']}")
|
||||
print(f"电解液二维码序列号: {data['Electrolyte_Code']}")
|
||||
print("===================")
|
||||
else:
|
||||
print("无法获取设备数据")
|
||||
except Exception as e:
|
||||
print(f"读取数据时出错: {e}")
|
||||
|
||||
elif command == "count":
|
||||
print("读取当前电池数量...")
|
||||
try:
|
||||
count = device.data_assembly_coin_cell_num
|
||||
print(f"当前已完成电池数量: {count}")
|
||||
except Exception as e:
|
||||
print(f"读取电池数量时出错: {e}")
|
||||
|
||||
elif command == "export":
|
||||
print("正在收集设备数据并导出到CSV...")
|
||||
data = collect_device_data(device)
|
||||
if data:
|
||||
print(f"收集到数据: 电池数量={data.get('Battery_Count', 'N/A')}, 组装时间={data.get('Assembly_Time', 'N/A')}s")
|
||||
if export_to_csv(data, csv_file_path):
|
||||
print("✓ 数据已成功导出到CSV文件")
|
||||
print(f"导出数据: 时间={data['Timestamp']}, 电池数量={data['Battery_Count']}, 组装时间={data['Assembly_Time']}秒, "
|
||||
f"电压={data['Open_Circuit_Voltage']}V, 重量={data['Pole_Weight']}g, 压制力={data['Assembly_Pressure']}N")
|
||||
print(f"电池码={data['Battery_Code']}, 电解液码={data['Electrolyte_Code']}")
|
||||
else:
|
||||
print("✗ 导出失败")
|
||||
else:
|
||||
print("✗ 数据收集失败,无法导出!请检查设备连接状态。")
|
||||
# 尝试重新连接设备
|
||||
try:
|
||||
if hasattr(device, 'connect'):
|
||||
device.connect()
|
||||
print("尝试重新连接设备...")
|
||||
except Exception as e:
|
||||
print(f"重新连接失败: {e}")
|
||||
|
||||
elif command == "setpath":
|
||||
print("设置自定义CSV文件路径")
|
||||
print(f"当前CSV文件路径: {csv_file_path}")
|
||||
new_path = input("请输入新的CSV文件路径(包含文件名,如: D:/data/my_battery_data.csv): ").strip()
|
||||
if new_path:
|
||||
try:
|
||||
# 确保目录存在
|
||||
new_dir = os.path.dirname(new_path)
|
||||
if new_dir and not os.path.exists(new_dir):
|
||||
os.makedirs(new_dir, exist_ok=True)
|
||||
print(f"✓ 已创建目录: {new_dir}")
|
||||
|
||||
csv_file_path = new_path
|
||||
print(f"✓ CSV文件路径已更新为: {os.path.abspath(csv_file_path)}")
|
||||
|
||||
# 检查文件是否存在
|
||||
if os.path.exists(csv_file_path):
|
||||
file_size = os.path.getsize(csv_file_path)
|
||||
print(f"文件已存在,大小: {file_size} 字节")
|
||||
else:
|
||||
print("文件不存在,将在首次导出时创建")
|
||||
except Exception as e:
|
||||
print(f"✗ 设置路径失败: {e}")
|
||||
else:
|
||||
print("路径不能为空")
|
||||
|
||||
elif command == "view":
|
||||
print("查看CSV文件内容...")
|
||||
view_csv_content(csv_file_path)
|
||||
|
||||
elif command == "clear":
|
||||
clear_screen()
|
||||
print_header()
|
||||
print_commands()
|
||||
|
||||
elif command == "help":
|
||||
print_commands()
|
||||
|
||||
elif command == "quit" or command == "exit":
|
||||
print("正在退出...")
|
||||
# 停止导出
|
||||
try:
|
||||
device.stop_csv_export()
|
||||
print("✓ 导出已停止")
|
||||
except:
|
||||
pass
|
||||
print("程序已退出")
|
||||
break
|
||||
|
||||
elif command == "":
|
||||
# 空命令,不做任何操作
|
||||
continue
|
||||
|
||||
else:
|
||||
print(f"未知命令: {command}")
|
||||
print("输入 'help' 查看可用命令")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n检测到 Ctrl+C,正在退出...")
|
||||
try:
|
||||
device.stop_csv_export()
|
||||
print("✓ 导出已停止")
|
||||
except:
|
||||
pass
|
||||
print("程序已退出")
|
||||
break
|
||||
except Exception as e:
|
||||
print(f"执行命令时出错: {e}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
interactive_demo()
|
||||
107
unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md
Normal file
107
unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md
Normal file
@@ -0,0 +1,107 @@
|
||||
# 电池组装资源冲突问题修复说明
|
||||
|
||||
## 问题描述
|
||||
|
||||
在运行 `func_allpack_cmd` 函数时,遇到以下错误:
|
||||
|
||||
```
|
||||
ValueError: Resource 'battery_0' already assigned to deck
|
||||
```
|
||||
|
||||
**错误位置**:`coin_cell_assembly.py` 第 849 行
|
||||
```python
|
||||
liaopan3.children[self.coin_num_N].assign_child_resource(battery, location=None)
|
||||
```
|
||||
|
||||
## 原因分析
|
||||
|
||||
1. **资源名称冲突**:
|
||||
- 每次创建电池资源使用固定格式 `battery_{coin_num_N}`
|
||||
- 如果程序重启或断点恢复,`coin_num_N` 可能重置为 0
|
||||
- Deck 上可能已存在 `battery_0` 等同名资源
|
||||
|
||||
2. **缺少冲突处理**:
|
||||
- 在分配资源前没有检查目标位置是否已有资源
|
||||
- 没有清理机制来移除旧资源
|
||||
|
||||
## 解决方案
|
||||
|
||||
### 1. 使用时间戳确保资源名称唯一
|
||||
|
||||
```python
|
||||
# 之前
|
||||
battery = ElectrodeSheet(name=f"battery_{self.coin_num_N}", ...)
|
||||
|
||||
# 修复后
|
||||
timestamp_suffix = datetime.now().strftime("%Y%m%d_%H%M%S_%f")
|
||||
battery_name = f"battery_{self.coin_num_N}_{timestamp_suffix}"
|
||||
battery = ElectrodeSheet(name=battery_name, ...)
|
||||
```
|
||||
|
||||
### 2. 添加资源冲突检查和清理
|
||||
|
||||
```python
|
||||
# 检查目标位置是否已有资源
|
||||
target_slot = liaopan3.children[self.coin_num_N]
|
||||
if target_slot.children:
|
||||
logger.warning(f"位置 {self.coin_num_N} 已有资源,将先卸载旧资源")
|
||||
try:
|
||||
# 卸载所有现有子资源
|
||||
for child in list(target_slot.children):
|
||||
target_slot.unassign_child_resource(child)
|
||||
logger.info(f"已卸载旧资源: {child.name}")
|
||||
except Exception as e:
|
||||
logger.error(f"卸载旧资源时出错: {e}")
|
||||
```
|
||||
|
||||
### 3. 增强错误处理
|
||||
|
||||
```python
|
||||
# 分配新资源到目标位置
|
||||
try:
|
||||
target_slot.assign_child_resource(battery, location=None)
|
||||
logger.info(f"成功分配电池 {battery_name} 到位置 {self.coin_num_N}")
|
||||
except Exception as e:
|
||||
logger.error(f"分配电池资源失败: {e}")
|
||||
raise
|
||||
```
|
||||
|
||||
## 修复效果
|
||||
|
||||
✅ **不再出现重复资源名称错误**
|
||||
- 每个电池资源都有唯一的时间戳后缀
|
||||
- 即使 `coin_num_N` 相同,资源名称也不会冲突
|
||||
|
||||
✅ **自动清理旧资源**
|
||||
- 在分配新资源前检查目标位置
|
||||
- 自动卸载已存在的旧资源
|
||||
|
||||
✅ **增强日志记录**
|
||||
- 记录资源卸载操作
|
||||
- 记录资源分配成功/失败
|
||||
- 便于调试和问题追踪
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **正常运行测试**:
|
||||
```python
|
||||
workstation.func_allpack_cmd(
|
||||
elec_num=1,
|
||||
elec_use_num=1,
|
||||
elec_vol=20,
|
||||
file_path="..."
|
||||
)
|
||||
```
|
||||
|
||||
2. **断点恢复测试**:
|
||||
- 运行一次后中断
|
||||
- 再次运行相同参数
|
||||
- 验证不会出现资源冲突错误
|
||||
|
||||
3. **连续运行测试**:
|
||||
- 连续多次运行
|
||||
- 验证每次都能正常分配资源
|
||||
|
||||
## 相关文件
|
||||
|
||||
- `coin_cell_assembly.py` - 第 838-875 行(`func_pack_get_msg_cmd` 函数)
|
||||
@@ -32,7 +32,7 @@ bioyond_cell:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
xlsx_path: /Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx
|
||||
xlsx_path: D:/UniLab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
@@ -42,323 +42,8 @@ bioyond_cell:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
WH3_x1_y1_z3_1_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y1_z3_1_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y1_z3_1_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x1_y2_z3_4_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y2_z3_4_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y2_z3_4_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x1_y3_z3_7_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y3_z3_7_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y3_z3_7_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x1_y4_z3_10_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y4_z3_10_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y4_z3_10_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x1_y5_z3_13_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y5_z3_13_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x1_y5_z3_13_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x2_y1_z3_2_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y1_z3_2_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y1_z3_2_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x2_y2_z3_5_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y2_z3_5_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y2_z3_5_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x2_y3_z3_8_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y3_z3_8_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y3_z3_8_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x2_y4_z3_11_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y4_z3_11_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y4_z3_11_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x2_y5_z3_14_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y5_z3_14_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x2_y5_z3_14_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x3_y1_z3_3_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y1_z3_3_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y1_z3_3_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x3_y2_z3_6_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y2_z3_6_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y2_z3_6_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x3_y3_z3_9_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y3_z3_9_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y3_z3_9_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x3_y4_z3_12_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y4_z3_12_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y4_z3_12_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH3_x3_y5_z3_15_materialId:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y5_z3_15_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH3_x3_y5_z3_15_quantity:
|
||||
default: 0
|
||||
type: number
|
||||
WH4_x1_y1_z1_1_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y1_z1_1_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y1_z2_1_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y1_z2_1_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y1_z2_1_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y1_z2_1_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y2_z1_6_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y2_z1_6_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y2_z2_4_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y2_z2_4_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y2_z2_4_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y2_z2_4_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y3_z1_11_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y3_z1_11_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y3_z2_7_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y3_z2_7_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x1_y3_z2_7_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x1_y3_z2_7_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y1_z1_2_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y1_z1_2_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y1_z2_2_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y1_z2_2_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y1_z2_2_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y1_z2_2_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y2_z1_7_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y2_z1_7_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y2_z2_5_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y2_z2_5_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y2_z2_5_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y2_z2_5_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y3_z1_12_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y3_z1_12_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y3_z2_8_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y3_z2_8_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x2_y3_z2_8_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x2_y3_z2_8_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y1_z1_3_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y1_z1_3_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x3_y1_z2_3_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y1_z2_3_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y1_z2_3_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x3_y1_z2_3_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y2_z1_8_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y2_z1_8_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x3_y2_z2_6_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y2_z2_6_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y2_z2_6_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x3_y2_z2_6_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y3_z2_9_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y3_z2_9_materialType:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x3_y3_z2_9_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x3_y3_z2_9_targetWH:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x4_y1_z1_4_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x4_y1_z1_4_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x4_y2_z1_9_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x4_y2_z1_9_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x5_y1_z1_5_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x5_y1_z1_5_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
WH4_x5_y2_z1_10_materialName:
|
||||
default: ''
|
||||
type: string
|
||||
WH4_x5_y2_z1_10_quantity:
|
||||
default: 0.0
|
||||
type: number
|
||||
xlsx_path:
|
||||
default: /Users/sml/work/Unilab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx
|
||||
default: D:/UniLab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122301.xlsx
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
@@ -466,7 +151,14 @@ bioyond_cell:
|
||||
goal: {}
|
||||
goal_default:
|
||||
xlsx_path: null
|
||||
handles: {}
|
||||
handles:
|
||||
output:
|
||||
- data_key: total_orders
|
||||
data_source: executor
|
||||
data_type: integer
|
||||
handler_key: bottle_count
|
||||
io_type: sink
|
||||
label: 配液瓶数
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
@@ -779,6 +471,31 @@ bioyond_cell:
|
||||
title: scheduler_start参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-scheduler_start_and_auto_feeding:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
xlsx_path: D:/UniLab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 组合函数:先启动调度,然后执行自动化上料
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
xlsx_path:
|
||||
default: D:/UniLab/Uni-Lab-OS/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx
|
||||
type: string
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: scheduler_start_and_auto_feeding参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-scheduler_stop:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
|
||||
@@ -115,6 +115,117 @@ coincellassemblyworkstation_device:
|
||||
title: func_allpack_cmd参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-func_allpack_cmd_simp:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
assembly_pressure: 4200
|
||||
assembly_type: 7
|
||||
battery_clean_ignore: false
|
||||
battery_pressure_mode: true
|
||||
dual_drop_first_volume: 25
|
||||
dual_drop_mode: false
|
||||
dual_drop_start_timing: false
|
||||
dual_drop_suction_timing: false
|
||||
elec_num: null
|
||||
elec_use_num: null
|
||||
elec_vol: 50
|
||||
file_path: /Users/sml/work
|
||||
fujipian_juzhendianwei: 0
|
||||
fujipian_panshu: 0
|
||||
gemo_juzhendianwei: 0
|
||||
gemopanshu: 0
|
||||
lvbodian: true
|
||||
qiangtou_juzhendianwei: 0
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 简化版电池组装函数,整合了参数设置和双滴模式
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
assembly_pressure:
|
||||
default: 4200
|
||||
description: 电池压制力(N)
|
||||
type: integer
|
||||
assembly_type:
|
||||
default: 7
|
||||
description: 组装类型(7=不用铝箔垫, 8=使用铝箔垫)
|
||||
type: integer
|
||||
battery_clean_ignore:
|
||||
default: false
|
||||
description: 是否忽略电池清洁步骤
|
||||
type: boolean
|
||||
battery_pressure_mode:
|
||||
default: true
|
||||
description: 是否启用压力模式
|
||||
type: boolean
|
||||
dual_drop_first_volume:
|
||||
default: 25
|
||||
description: 二次滴液第一次排液体积(μL)
|
||||
type: integer
|
||||
dual_drop_mode:
|
||||
default: false
|
||||
description: 电解液添加模式(false=单次滴液, true=二次滴液)
|
||||
type: boolean
|
||||
dual_drop_start_timing:
|
||||
default: false
|
||||
description: 二次滴液开始滴液时机(false=正极片前, true=正极片后)
|
||||
type: boolean
|
||||
dual_drop_suction_timing:
|
||||
default: false
|
||||
description: 二次滴液吸液时机(false=正常吸液, true=先吸液)
|
||||
type: boolean
|
||||
elec_num:
|
||||
description: 电解液瓶数
|
||||
type: string
|
||||
elec_use_num:
|
||||
description: 每瓶电解液组装电池数
|
||||
type: string
|
||||
elec_vol:
|
||||
default: 50
|
||||
description: 电解液吸液量(μL)
|
||||
type: integer
|
||||
file_path:
|
||||
default: /Users/sml/work
|
||||
description: 实验记录保存路径
|
||||
type: string
|
||||
fujipian_juzhendianwei:
|
||||
default: 0
|
||||
description: 负极片矩阵点位
|
||||
type: integer
|
||||
fujipian_panshu:
|
||||
default: 0
|
||||
description: 负极片盘数
|
||||
type: integer
|
||||
gemo_juzhendianwei:
|
||||
default: 0
|
||||
description: 隔膜矩阵点位
|
||||
type: integer
|
||||
gemopanshu:
|
||||
default: 0
|
||||
description: 隔膜盘数
|
||||
type: integer
|
||||
lvbodian:
|
||||
default: true
|
||||
description: 是否使用铝箔垫片
|
||||
type: boolean
|
||||
qiangtou_juzhendianwei:
|
||||
default: 0
|
||||
description: 枪头盒矩阵点位
|
||||
type: integer
|
||||
required:
|
||||
- elec_num
|
||||
- elec_use_num
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: func_allpack_cmd_simp参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-func_get_csv_export_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -178,6 +289,27 @@ coincellassemblyworkstation_device:
|
||||
title: func_pack_device_init参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-func_pack_device_init_auto_start_combined:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: {}
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
description: 组合函数:设备初始化 + 切换自动模式 + 启动
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: func_pack_device_init_auto_start_combined参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-func_pack_device_start:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -250,7 +382,15 @@ coincellassemblyworkstation_device:
|
||||
goal: {}
|
||||
goal_default:
|
||||
bottle_num: null
|
||||
handles: {}
|
||||
handles:
|
||||
input:
|
||||
- data_key: bottle_num
|
||||
data_source: workflow
|
||||
data_type: integer
|
||||
handler_key: bottle_count
|
||||
io_type: source
|
||||
label: 配液瓶数
|
||||
required: true
|
||||
placeholder_keys: {}
|
||||
result: {}
|
||||
schema:
|
||||
@@ -260,7 +400,7 @@ coincellassemblyworkstation_device:
|
||||
goal:
|
||||
properties:
|
||||
bottle_num:
|
||||
type: string
|
||||
type: integer
|
||||
required:
|
||||
- bottle_num
|
||||
type: object
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user