feat: migrate to pymodbus 3.11.4 and update bioyond configs

PyModbus 3.x Migration:
- Copied modbus.py and client.py from dev branch for compatibility
- Rewrote FLOAT32 decoding using struct module in coin_cell_assembly.py
- Fixed STRING decoding for QR codes (battery and electrolyte barcodes)
- Tested successfully on hardware with correct data decoding

Bioyond Studio Updates:
- Updated bioyond_studio config.py
- Modified bioyond_cell_workstation.py
- Enhanced warehouse.py and decks.py
- Added README_WAREHOUSE.md documentation

Parameter Enhancements:
- Enhanced coin_cell_workstation.yaml parameter descriptions
- Added matrix position ranges and indexing rules

Breaking changes:
- Requires pymodbus >= 3.9.0
- Removed deprecated BinaryPayloadDecoder/BinaryPayloadBuilder
- Updated to use client.convert_from/to_registers() methods
This commit is contained in:
Andy6M
2026-01-10 17:01:40 +08:00
parent 936834f8c3
commit f355722281
29 changed files with 1460 additions and 8006 deletions

View File

@@ -161,6 +161,95 @@ class BioyondCellWorkstation(BioyondWorkstation):
logger.warning(f"任务未知状态 ({status}) (orderCode={order_code})")
return {"status": f"unknown_{status}", "report": report}
def get_material_info(self, material_id: str) -> Dict[str, Any]:
"""查询物料详细信息(物料详情接口)
Args:
material_id: 物料 ID (GUID)
Returns:
物料详情,包含 name, typeName, locations 等
"""
result = self._post_lims("/api/lims/storage/material-info", material_id)
return result.get("data", {})
def _process_order_reagents(self, report: Dict[str, Any]) -> Dict[str, Any]:
"""处理订单完成报文中的试剂数据,计算质量比
Args:
report: 订单完成推送的 report 数据
Returns:
{
"real_mass_ratio": {"试剂A": 0.6, "试剂B": 0.4},
"target_mass_ratio": {"试剂A": 0.6, "试剂B": 0.4},
"reagent_details": [...] # 详细数据
}
"""
used_materials = report.get("usedMaterials", [])
# 1. 筛选试剂typemode="2",注意是小写且是字符串)
reagents = [m for m in used_materials if str(m.get("typemode")) == "2"]
if not reagents:
logger.warning("订单完成报文中没有试剂typeMode=2")
return {
"real_mass_ratio": {},
"target_mass_ratio": {},
"reagent_details": []
}
# 2. 查询试剂名称
reagent_data = []
for reagent in reagents:
material_id = reagent.get("materialId")
if not material_id:
continue
try:
info = self.get_material_info(material_id)
name = info.get("name", f"Unknown_{material_id[:8]}")
real_qty = float(reagent.get("realQuantity", 0.0))
used_qty = float(reagent.get("usedQuantity", 0.0))
reagent_data.append({
"name": name,
"material_id": material_id,
"real_quantity": real_qty,
"used_quantity": used_qty
})
logger.info(f"试剂: {name}, 目标={used_qty}g, 实际={real_qty}g")
except Exception as e:
logger.error(f"查询物料信息失败: {material_id}, {e}")
continue
if not reagent_data:
return {
"real_mass_ratio": {},
"target_mass_ratio": {},
"reagent_details": []
}
# 3. 计算质量比
def calculate_mass_ratio(items: List[Dict], key: str) -> Dict[str, float]:
total = sum(item[key] for item in items)
if total == 0:
logger.warning(f"总质量为0无法计算{key}质量比")
return {item["name"]: 0.0 for item in items}
return {item["name"]: round(item[key] / total, 4) for item in items}
real_mass_ratio = calculate_mass_ratio(reagent_data, "real_quantity")
target_mass_ratio = calculate_mass_ratio(reagent_data, "used_quantity")
logger.info(f"真实质量比: {real_mass_ratio}")
logger.info(f"目标质量比: {target_mass_ratio}")
return {
"real_mass_ratio": real_mass_ratio,
"target_mass_ratio": target_mass_ratio,
"reagent_details": reagent_data
}
# -------------------- 基础HTTP封装 --------------------
def _url(self, path: str) -> str:
@@ -643,6 +732,21 @@ class BioyondCellWorkstation(BioyondWorkstation):
# 提取报文数据
if result.get("status") == "success":
report = result.get("report", {})
# [新增] 处理试剂数据,计算质量比
try:
mass_ratios = self._process_order_reagents(report)
report["mass_ratios"] = mass_ratios # 添加到报文中
logger.info(f"已计算订单 {order_code} 的试剂质量比")
except Exception as e:
logger.error(f"计算试剂质量比失败: {e}")
report["mass_ratios"] = {
"real_mass_ratio": {},
"target_mass_ratio": {},
"reagent_details": [],
"error": str(e)
}
all_reports.append(report)
print(f"[create_orders] ✓ 订单 {order_code} 完成")
else:
@@ -672,6 +776,252 @@ class BioyondCellWorkstation(BioyondWorkstation):
return final_result
def create_orders_v2(self, xlsx_path: str) -> Dict[str, Any]:
"""
从 Excel 解析并创建实验2.14- V2版本
约定:
- batchId = Excel 文件名(不含扩展名)
- 物料列:所有以 "(g)" 结尾(不再读取"总质量(g)"列)
- totalMass 自动计算为所有物料质量之和
- createTime 缺失或为空时自动填充为当前日期YYYY/M/D
"""
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_v2] 使用 Excel 路径: {path}")
if path != default_path:
print("[create_orders_v2] 来源: 调用方传入自定义路径")
else:
print("[create_orders_v2] 来源: 使用默认模板路径")
if not path.exists():
print(f"[create_orders_v2] ⚠️ Excel 文件不存在: {path}")
raise FileNotFoundError(f"未找到 Excel 文件:{path}")
try:
df = pd.read_excel(path, sheet_name=0, engine="openpyxl")
except Exception as e:
raise RuntimeError(f"读取 Excel 失败:{e}")
print(f"[create_orders_v2] Excel 读取成功,行数: {len(df)}, 列: {list(df.columns)}")
# 列名容错:返回可选列名,找不到则返回 None
def _pick(col_names: List[str]) -> Optional[str]:
for c in col_names:
if c in df.columns:
return c
return None
col_order_name = _pick(["配方ID", "orderName", "订单编号"])
col_create_time = _pick(["创建日期", "createTime"])
col_bottle_type = _pick(["配液瓶类型", "bottleType"])
col_mix_time = _pick(["混匀时间(s)", "mixTime"])
col_load = _pick(["扣电组装分液体积", "loadSheddingInfo"])
col_pouch = _pick(["软包组装分液体积", "pouchCellInfo"])
col_cond = _pick(["电导测试分液体积", "conductivityInfo"])
col_cond_cnt = _pick(["电导测试分液瓶数", "conductivityBottleCount"])
print("[create_orders_v2] 列匹配结果:", {
"order_name": col_order_name,
"create_time": col_create_time,
"bottle_type": col_bottle_type,
"mix_time": col_mix_time,
"load": col_load,
"pouch": col_pouch,
"conductivity": col_cond,
"conductivity_bottle_count": col_cond_cnt,
})
# 物料列:所有以 (g) 结尾
material_cols = [c for c in df.columns if isinstance(c, str) and c.endswith("(g)")]
print(f"[create_orders_v2] 识别到的物料列: {material_cols}")
if not material_cols:
raise KeyError("未发现任何以“(g)”结尾的物料列,请检查表头。")
batch_id = path.stem
def _to_ymd_slash(v) -> str:
# 统一为 "YYYY/M/D";为空或解析失败则用当前日期
if v is None or (isinstance(v, float) and pd.isna(v)) or str(v).strip() == "":
ts = datetime.now()
else:
try:
ts = pd.to_datetime(v)
except Exception:
ts = datetime.now()
return f"{ts.year}/{ts.month}/{ts.day}"
def _as_int(val, default=0) -> int:
try:
if pd.isna(val):
return default
return int(val)
except Exception:
return default
def _as_float(val, default=0.0) -> float:
try:
if pd.isna(val):
return default
return float(val)
except Exception:
return default
def _as_str(val, default="") -> str:
if val is None or (isinstance(val, float) and pd.isna(val)):
return default
s = str(val).strip()
return s if s else default
orders: List[Dict[str, Any]] = []
for idx, row in df.iterrows():
mats: List[Dict[str, Any]] = []
total_mass = 0.0
for mcol in material_cols:
val = row.get(mcol, None)
if val is None or (isinstance(val, float) and pd.isna(val)):
continue
try:
mass = float(val)
except Exception:
continue
if mass > 0:
mats.append({"name": mcol.replace("(g)", ""), "mass": mass})
total_mass += mass
else:
if mass < 0:
print(f"[create_orders_v2] 第 {idx+1} 行物料 {mcol} 数值为负数: {mass}")
order_data = {
"batchId": batch_id,
"orderName": _as_str(row[col_order_name], default=f"{batch_id}_order_{idx+1}") if col_order_name else f"{batch_id}_order_{idx+1}",
"createTime": _to_ymd_slash(row[col_create_time]) if col_create_time else _to_ymd_slash(None),
"bottleType": _as_str(row[col_bottle_type], default="配液小瓶") if col_bottle_type else "配液小瓶",
"mixTime": _as_int(row[col_mix_time]) if col_mix_time else 0,
"loadSheddingInfo": _as_float(row[col_load]) if col_load else 0.0,
"pouchCellInfo": _as_float(row[col_pouch]) if col_pouch else 0,
"conductivityInfo": _as_float(row[col_cond]) if col_cond else 0,
"conductivityBottleCount": _as_int(row[col_cond_cnt]) if col_cond_cnt else 0,
"materialInfos": mats,
"totalMass": round(total_mass, 4) # 自动汇总
}
print(f"[create_orders_v2] 第 {idx+1} 行解析结果: orderName={order_data['orderName']}, "
f"loadShedding={order_data['loadSheddingInfo']}, pouchCell={order_data['pouchCellInfo']}, "
f"conductivity={order_data['conductivityInfo']}, totalMass={order_data['totalMass']}, "
f"material_count={len(mats)}")
if order_data["totalMass"] <= 0:
print(f"[create_orders_v2] ⚠️ 第 {idx+1} 行总质量 <= 0可能导致 LIMS 校验失败")
if not mats:
print(f"[create_orders_v2] ⚠️ 第 {idx+1} 行未找到有效物料")
orders.append(order_data)
print("================================================")
print("orders:", orders)
print(f"[create_orders_v2] 即将提交订单数量: {len(orders)}")
response = self._post_lims("/api/lims/order/orders", orders)
print(f"[create_orders_v2] 接口返回: {response}")
# 提取所有返回的 orderCode
data_list = response.get("data", [])
if not data_list:
logger.error("创建订单未返回有效数据!")
return response
# 收集所有 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_v2] 等待 {len(order_codes)} 个订单完成: {order_codes}")
# ========== 步骤1: 等待所有订单完成并收集报文(不计算质量比)==========
all_reports = []
for idx, order_code in enumerate(order_codes, 1):
print(f"[create_orders_v2] 正在等待第 {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_v2] ✓ 订单 {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_v2] 所有订单已完成,共收集 {len(all_reports)} 个报文")
# ========== 步骤2: 统一计算所有订单的质量比 ==========
print(f"[create_orders_v2] 开始统一计算 {len(all_reports)} 个订单的质量比...")
all_mass_ratios = [] # 存储所有订单的质量比与reports顺序一致
for idx, report in enumerate(all_reports, 1):
order_code = report.get("orderCode", "N/A")
print(f"[create_orders_v2] 计算第 {idx}/{len(all_reports)} 个订单 {order_code} 的质量比...")
# 只为成功完成的订单计算质量比
if "error" not in report:
try:
mass_ratios = self._process_order_reagents(report)
# 精简输出,只保留核心质量比信息
all_mass_ratios.append({
"orderCode": order_code,
"orderName": report.get("orderName", "N/A"),
"real_mass_ratio": mass_ratios.get("real_mass_ratio", {}),
"target_mass_ratio": mass_ratios.get("target_mass_ratio", {})
})
logger.info(f"✓ 已计算订单 {order_code} 的试剂质量比")
except Exception as e:
logger.error(f"计算订单 {order_code} 质量比失败: {e}")
all_mass_ratios.append({
"orderCode": order_code,
"orderName": report.get("orderName", "N/A"),
"real_mass_ratio": {},
"target_mass_ratio": {},
"error": str(e)
})
else:
# 失败的订单不计算质量比
all_mass_ratios.append({
"orderCode": order_code,
"orderName": report.get("orderName", "N/A"),
"real_mass_ratio": {},
"target_mass_ratio": {},
"error": "订单未成功完成"
})
print(f"[create_orders_v2] 质量比计算完成")
print("实验记录本========================create_orders_v2========================")
# 返回所有订单的完成报文
final_result = {
"status": "all_completed",
"total_orders": len(order_codes),
"bottle_count": len(order_codes), # 明确标注瓶数用于下游check
"reports": all_reports, # 原始订单报文(不含质量比)
"mass_ratios": all_mass_ratios, # 所有质量比统一放在这里
"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 final_result
# 2.7 启动调度
def scheduler_start(self) -> Dict[str, Any]:
return self._post_lims("/api/lims/scheduler/start")
@@ -683,7 +1033,7 @@ class BioyondCellWorkstation(BioyondWorkstation):
请求体只包含 apiKey 和 requestTime
"""
return self._post_lims("/api/lims/scheduler/stop")
# 2.9 继续调度
# 2.9 继续调度
def scheduler_continue(self) -> Dict[str, Any]:
"""
@@ -867,6 +1217,48 @@ class BioyondCellWorkstation(BioyondWorkstation):
result = self.wait_for_order_finish(order_code)
return result
def transfer_3_to_2(self,
source_wh_id: Optional[str] = '3a19debc-84b4-0359-e2d4-b3beea49348b',
source_x: int = 1,
source_y: int = 1,
source_z: int = 1) -> Dict[str, Any]:
"""
2.34 3-2 物料转运接口
新建从 3 -> 2 的搬运任务
Args:
source_wh_id: 来源仓库 Id (默认为3号仓库)
source_x: 来源位置 X 坐标
source_y: 来源位置 Y 坐标
source_z: 来源位置 Z 坐标
Returns:
dict: 包含任务 orderId 和 orderCode 的响应
"""
payload: Dict[str, Any] = {
"sourcePosX": source_x,
"sourcePosY": source_y,
"sourcePosZ": source_z
}
if source_wh_id:
payload["sourceWHID"] = source_wh_id
logger.info(f"[transfer_3_to_2] 开始转运: 仓库={source_wh_id}, 位置=({source_x}, {source_y}, {source_z})")
response = self._post_lims("/api/lims/order/transfer-task3To2", payload)
# 等待任务报送成功
order_code = response.get("data", {}).get("orderCode")
if not order_code:
logger.error("[transfer_3_to_2] 转运任务未返回有效 orderCode")
return response
logger.info(f"[transfer_3_to_2] 转运任务已创建: {order_code}")
# 等待完成报送
result = self.wait_for_order_finish(order_code)
logger.info(f"[transfer_3_to_2] 转运任务完成: {order_code}")
return result
# 3.35 1→2 物料转运
def transfer_1_to_2(self) -> Dict[str, Any]:
"""
@@ -874,14 +1266,28 @@ class BioyondCellWorkstation(BioyondWorkstation):
URL: /api/lims/order/transfer-task1To2
只需要 apiKey 和 requestTime
"""
logger.info("[transfer_1_to_2] 开始 1→2 物料转运")
response = self._post_lims("/api/lims/order/transfer-task1To2")
# 等待任务报送成功
order_code = response.get("data", {}).get("orderCode")
logger.info(f"[transfer_1_to_2] API Response: {response}")
# 等待任务报送成功 - 处理不同的响应格式
order_code = None
data_field = response.get("data")
if isinstance(data_field, dict):
order_code = data_field.get("orderCode")
elif isinstance(data_field, str):
# 某些接口可能直接返回 orderCode 字符串
order_code = data_field
if not order_code:
logger.error("上料任务未返回有效 orderCode")
logger.error(f"[transfer_1_to_2] 转运任务未返回有效 orderCode响应: {response}")
return response
# 等待完成报送
logger.info(f"[transfer_1_to_2] 转运任务已创建: {order_code}")
# 等待完成报送
result = self.wait_for_order_finish(order_code)
logger.info(f"[transfer_1_to_2] 转运任务完成: {order_code}")
return result
# 2.5 批量查询实验报告(post过滤关键字查询)

View File

@@ -0,0 +1,12 @@
import pubchempy as pcp
cas = "21324-40-3" # 示例
comps = pcp.get_compounds(cas, namespace="name")
if not comps:
raise ValueError("No hit")
c = comps[0]
print("Canonical SMILES:", c.canonical_smiles)
print("Isomeric SMILES:", c.isomeric_smiles)
print("MW:", c.molecular_weight)

View File

@@ -133,6 +133,46 @@ WAREHOUSE_MAPPING = {
"J03": "3a19deae-2c7a-f237-89d9-8fe19025dee9"
}
},
"手动传递窗右": {
"uuid": "",
"site_uuids": {
"A01": "3a19deae-2c7a-36f5-5e41-02c5b66feaea",
"A02": "3a19deae-2c7a-dc6d-c41e-ef285d946cfe",
"A03": "3a19deae-2c7a-5876-c454-6b7e224ca927",
"B01": "3a19deae-2c7a-2426-6d71-e9de3cb158b1",
"B02": "3a19deae-2c7a-79b0-5e44-efaafd1e4cf3",
"B03": "3a19deae-2c7a-b9eb-f4e3-e308e0cf839a",
"C01": "3a19deae-2c7a-32bc-768e-556647e292f3",
"C02": "3a19deae-2c7a-e97a-8484-f5a4599447c4",
"C03": "3a19deae-2c7a-3056-6504-10dc73fbc276",
"D01": "3a19deae-2c7a-ffad-875e-8c4cda61d440",
"D02": "3a19deae-2c7a-61be-601c-b6fb5610499a",
"D03": "3a19deae-2c7a-c0f7-05a7-e3fe2491e560",
"E01": "3a19deae-2c7a-a6f4-edd1-b436a7576363",
"E02": "3a19deae-2c7a-4367-96dd-1ca2186f4910",
"E03": "3a19deae-2c7a-b163-2219-23df15200311",
}
},
"手动传递窗左": {
"uuid": "",
"site_uuids": {
"F01": "3a19deae-2c7a-d594-fd6a-0d20de3c7c4a",
"F02": "3a19deae-2c7a-a194-ea63-8b342b8d8679",
"F03": "3a19deae-2c7a-f7c4-12bd-425799425698",
"G01": "3a19deae-2c7a-0b56-72f1-8ab86e53b955",
"G02": "3a19deae-2c7a-204e-95ed-1f1950f28343",
"G03": "3a19deae-2c7a-392b-62f1-4907c66343f8",
"H01": "3a19deae-2c7a-5602-e876-d27aca4e3201",
"H02": "3a19deae-2c7a-f15c-70e0-25b58a8c9702",
"H03": "3a19deae-2c7a-780b-8965-2e1345f7e834",
"I01": "3a19deae-2c7a-8849-e172-07de14ede928",
"I02": "3a19deae-2c7a-4772-a37f-ff99270bafc0",
"I03": "3a19deae-2c7a-cce7-6e4a-25ea4a2068c4",
"J01": "3a19deae-2c7a-1848-de92-b5d5ed054cc6",
"J02": "3a19deae-2c7a-1d45-b4f8-6f866530e205",
"J03": "3a19deae-2c7a-f237-89d9-8fe19025dee9"
}
},
"4号手套箱内部堆栈": {
"uuid": "",
"site_uuids": {

View File

@@ -20,8 +20,7 @@ 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
import struct
def _decode_float32_correct(registers):
@@ -43,13 +42,19 @@ def _decode_float32_correct(registers):
return 0.0
try:
# 使用正确的字节序配置
decoder = BinaryPayloadDecoder.fromRegisters(
registers,
byteorder=Endian.Big, # 字节序始终为Big
wordorder=Endian.Little # 字序为Little (根据PLC配置)
)
return decoder.decode_32bit_float()
# Word Order: Little - 交换两个寄存器的顺序
# Byte Order: Big - 每个寄存器内部使用大端字节序
low_word = registers[0]
high_word = registers[1]
# 将两个16位寄存器组合成一个32位值 (Little Word Order)
# 使用大端字节序 ('>') 将每个寄存器转换为字节
byte_string = struct.pack('>HH', high_word, low_word)
# 将字节字符串解码为浮点数 (大端)
value = struct.unpack('>f', byte_string)[0]
return value
except Exception as e:
logger.error(f"解码FLOAT32失败: {e}, registers: {registers}")
return 0.0
@@ -632,23 +637,22 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
# 读取 STRING 类型数据
code_little, read_err = self.client.use_node('REG_DATA_COIN_CELL_CODE').read(10, word_order=WorderOrder.LITTLE)
# 处理 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)}")
# PyModbus 3.x 返回 string 类型
if not isinstance(code_little, str):
logger.warning(f"电池二维码返回的类型不支持: {type(code_little)}, 值: {repr(code_little)}")
return "N/A"
# 取前8个字符
raw_code = code_str[:8]
# 从字符串末尾查找连续的字母数字字符(反转字符串)
import re
reversed_str = code_little[::-1]
match = re.match(r'^([A-Za-z0-9]+)', reversed_str)
# LITTLE字节序需要每2个字符交换位置
clean_code = ''.join([raw_code[i+1] + raw_code[i] for i in range(0, len(raw_code), 2)])
if not match:
logger.warning(f"未找到有效的电池二维码数据,原始字符串: {repr(code_little)}")
return "N/A"
# 去除空字符和空格
decoded = clean_code.replace('\x00', '').replace('\r', '').replace('\n', '').strip()
# 提取匹配到的字符串(已经是正确顺序)
decoded = match.group(1)[:8] # 只取前8个字符
return decoded if decoded else "N/A"
except Exception as e:
@@ -663,23 +667,22 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
# 读取 STRING 类型数据
code_little, read_err = self.client.use_node('REG_DATA_ELECTROLYTE_CODE').read(10, word_order=WorderOrder.LITTLE)
# 处理 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)}")
# PyModbus 3.x 返回 string 类型
if not isinstance(code_little, str):
logger.warning(f"电解液二维码返回的类型不支持: {type(code_little)}, 值: {repr(code_little)}")
return "N/A"
# 取前8个字符
raw_code = code_str[:8]
# 从字符串末尾查找连续的字母数字字符(反转字符串)
import re
reversed_str = code_little[::-1]
match = re.match(r'^([A-Za-z0-9]+)', reversed_str)
# LITTLE字节序需要每2个字符交换位置
clean_code = ''.join([raw_code[i+1] + raw_code[i] for i in range(0, len(raw_code), 2)])
if not match:
logger.warning(f"未找到有效的电解液二维码数据,原始字符串: {repr(code_little)}")
return "N/A"
# 去除空字符和空格
decoded = clean_code.replace('\x00', '').replace('\r', '').replace('\n', '').strip()
# 提取匹配到的字符串(已经是正确顺序)
decoded = match.group(1)[:8] # 只取前8个字符
return decoded if decoded else "N/A"
except Exception as e:
@@ -940,6 +943,111 @@ class CoinCellAssemblyWorkstation(WorkstationBase):
time.sleep(1)
#自动按钮置False
def func_sendbottle_allpack_multi(
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]:
"""
发送瓶数+简化组装函数(适用于第二批次及后续批次)
合并了发送瓶数和简化组装流程,用于连续批次生产。
适用场景:设备已完成初始化和启动,仍在自动模式下运行。
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: 包含组装结果的字典
注意:
- 第一次启动需先调用 func_pack_device_init_auto_start_combined()
- 后续批次直接调用此函数即可
"""
logger.info("=" * 60)
logger.info("开始发送瓶数+简化组装流程...")
logger.info(f"电解液瓶数: {elec_num}, 每瓶电池数: {elec_use_num}")
logger.info("=" * 60)
# 步骤1: 发送电解液瓶数(触发物料搬运)
logger.info("步骤1/2: 发送电解液瓶数,触发物料搬运...")
try:
self.func_pack_send_bottle_num(elec_num)
logger.info("✓ 瓶数发送完成,物料搬运中...")
except Exception as e:
logger.error(f"发送瓶数失败: {e}")
return {
"success": False,
"error": f"发送瓶数失败: {e}",
"total_batteries": 0,
"batteries": []
}
# 步骤2: 执行简化组装流程
logger.info("步骤2/2: 开始简化组装流程...")
result = self.func_allpack_cmd_simp(
elec_num=elec_num,
elec_use_num=elec_use_num,
elec_vol=elec_vol,
dual_drop_mode=dual_drop_mode,
dual_drop_first_volume=dual_drop_first_volume,
dual_drop_suction_timing=dual_drop_suction_timing,
dual_drop_start_timing=dual_drop_start_timing,
assembly_type=assembly_type,
assembly_pressure=assembly_pressure,
fujipian_panshu=fujipian_panshu,
fujipian_juzhendianwei=fujipian_juzhendianwei,
gemopanshu=gemopanshu,
gemo_juzhendianwei=gemo_juzhendianwei,
qiangtou_juzhendianwei=qiangtou_juzhendianwei,
lvbodian=lvbodian,
battery_pressure_mode=battery_pressure_mode,
battery_clean_ignore=battery_clean_ignore,
file_path=file_path
)
logger.info("=" * 60)
logger.info("发送瓶数+简化组装流程完成")
logger.info(f"总组装电池数: {result.get('total_batteries', 0)}")
logger.info("=" * 60)
return result
# 下发参数
#def func_pack_send_msg_cmd(self, elec_num: int, elec_use_num: int, elec_vol: float, assembly_type: int, assembly_pressure: int) -> bool:

View File

@@ -1,64 +0,0 @@
Name,DataType,InitValue,Comment,Attribute,DeviceType,Address,
COIL_SYS_START_CMD,BOOL,,,,coil,9010,
COIL_SYS_STOP_CMD,BOOL,,,,coil,9020,
COIL_SYS_RESET_CMD,BOOL,,,,coil,9030,
COIL_SYS_HAND_CMD,BOOL,,,,coil,9040,
COIL_SYS_AUTO_CMD,BOOL,,,,coil,9050,
COIL_SYS_INIT_CMD,BOOL,,,,coil,9060,
COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,,,,coil,9700,
COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,,,,coil,9710,unilab_rec_msg_succ_cmd
COIL_SYS_START_STATUS,BOOL,,,,coil,9210,
COIL_SYS_STOP_STATUS,BOOL,,,,coil,9220,
COIL_SYS_RESET_STATUS,BOOL,,,,coil,9230,
COIL_SYS_HAND_STATUS,BOOL,,,,coil,9240,
COIL_SYS_AUTO_STATUS,BOOL,,,,coil,9250,
COIL_SYS_INIT_STATUS,BOOL,,,,coil,9260,
COIL_REQUEST_REC_MSG_STATUS,BOOL,,,,coil,9500,
COIL_REQUEST_SEND_MSG_STATUS,BOOL,,,,coil,9510,request_send_msg_status
REG_MSG_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,17000,
REG_MSG_ELECTROLYTE_NUM,INT16,,,,hold_register,17002,unilab_send_msg_electrolyte_num
REG_MSG_ELECTROLYTE_VOLUME,INT16,,,,hold_register,17004,unilab_send_msg_electrolyte_vol
REG_MSG_ASSEMBLY_TYPE,INT16,,,,hold_register,17006,unilab_send_msg_assembly_type
REG_MSG_ASSEMBLY_PRESSURE,INT16,,,,hold_register,17008,unilab_send_msg_assembly_pressure
REG_DATA_ASSEMBLY_COIN_CELL_NUM,INT16,,,,hold_register,16000,data_assembly_coin_cell_num
REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,,,,hold_register,16002,data_open_circuit_voltage
REG_DATA_AXIS_X_POS,FLOAT32,,,,hold_register,16004,
REG_DATA_AXIS_Y_POS,FLOAT32,,,,hold_register,16006,
REG_DATA_AXIS_Z_POS,FLOAT32,,,,hold_register,16008,
REG_DATA_POLE_WEIGHT,FLOAT32,,,,hold_register,16010,data_pole_weight
REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,,,,hold_register,16012,data_assembly_time
REG_DATA_ASSEMBLY_PRESSURE,INT16,,,,hold_register,16014,data_assembly_pressure
REG_DATA_ELECTROLYTE_VOLUME,INT16,,,,hold_register,16016,data_electrolyte_volume
REG_DATA_COIN_NUM,INT16,,,,hold_register,16018,data_coin_num
REG_DATA_ELECTROLYTE_CODE,STRING,,,,hold_register,16020,data_electrolyte_code()
REG_DATA_COIN_CELL_CODE,STRING,,,,hold_register,16030,data_coin_cell_code()
REG_DATA_STACK_VISON_CODE,STRING,,,,hold_register,18004,data_stack_vision_code()
REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,,,,hold_register,16050,data_glove_box_pressure
REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,,,,hold_register,16052,data_glove_box_water_content
REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,,,hold_register,16054,data_glove_box_o2_content
UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,9720,
UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM,BOOL,,,,coil,9520,
REG_MSG_ELECTROLYTE_NUM_USED,INT16,,,,hold_register,17496,
REG_DATA_ELECTROLYTE_USE_NUM,INT16,,,,hold_register,16000,
UNILAB_SEND_FINISHED_CMD,BOOL,,,,coil,9730,
UNILAB_RECE_FINISHED_CMD,BOOL,,,,coil,9530,
REG_DATA_ASSEMBLY_TYPE,INT16,,,,hold_register,16018,ASSEMBLY_TYPE7or8
COIL_ALUMINUM_FOIL,BOOL,,使用铝箔垫,,coil,9340,
REG_MSG_NE_PLATE_MATRIX,INT16,,负极片矩阵点位,,hold_register,17440,
REG_MSG_SEPARATOR_PLATE_MATRIX,INT16,,隔膜矩阵点位,,hold_register,17450,
REG_MSG_TIP_BOX_MATRIX,INT16,,移液枪头矩阵点位,,hold_register,17480,
REG_MSG_NE_PLATE_NUM,INT16,,负极片盘数,,hold_register,17443,
REG_MSG_SEPARATOR_PLATE_NUM,INT16,,隔膜盘数,,hold_register,17453,
REG_MSG_PRESS_MODE,BOOL,,压制模式false:压力检测模式True:距离模式),,coil,9360,电池压制模式
,,,,,,,
,BOOL,,视觉对位false:使用true:忽略),,coil,9300,视觉对位
,BOOL,,复检false:使用true:忽略),,coil,9310,视觉复检
,BOOL,,手套箱_左仓false:使用true:忽略),,coil,9320,手套箱左仓
,BOOL,,手套箱_右仓false:使用true:忽略),,coil,9420,手套箱右仓
,BOOL,,真空检知false:使用true:忽略),,coil,9350,真空检知
,BOOL,,电解液添加模式false:单次滴液true:二次滴液),,coil,9370,滴液模式
,BOOL,,正极片称重false:使用true:忽略),,coil,9380,正极片称重
,BOOL,,正负极片组装方式false:正装true:倒装),,coil,9390,正负极反装
,BOOL,,压制清洁false:使用true:忽略),,coil,9400,压制清洁
,BOOL,,物料盘摆盘方式false:水平摆盘true:堆叠摆盘),,coil,9410,负极片摆盘方式
REG_MSG_BATTERY_CLEAN_IGNORE,BOOL,,忽略电池清洁false:使用true:忽略),,coil,9460,
1 Name DataType InitValue Comment Attribute DeviceType Address
2 COIL_SYS_START_CMD BOOL coil 9010
3 COIL_SYS_STOP_CMD BOOL coil 9020
4 COIL_SYS_RESET_CMD BOOL coil 9030
5 COIL_SYS_HAND_CMD BOOL coil 9040
6 COIL_SYS_AUTO_CMD BOOL coil 9050
7 COIL_SYS_INIT_CMD BOOL coil 9060
8 COIL_UNILAB_SEND_MSG_SUCC_CMD BOOL coil 9700
9 COIL_UNILAB_REC_MSG_SUCC_CMD BOOL coil 9710 unilab_rec_msg_succ_cmd
10 COIL_SYS_START_STATUS BOOL coil 9210
11 COIL_SYS_STOP_STATUS BOOL coil 9220
12 COIL_SYS_RESET_STATUS BOOL coil 9230
13 COIL_SYS_HAND_STATUS BOOL coil 9240
14 COIL_SYS_AUTO_STATUS BOOL coil 9250
15 COIL_SYS_INIT_STATUS BOOL coil 9260
16 COIL_REQUEST_REC_MSG_STATUS BOOL coil 9500
17 COIL_REQUEST_SEND_MSG_STATUS BOOL coil 9510 request_send_msg_status
18 REG_MSG_ELECTROLYTE_USE_NUM INT16 hold_register 17000
19 REG_MSG_ELECTROLYTE_NUM INT16 hold_register 17002 unilab_send_msg_electrolyte_num
20 REG_MSG_ELECTROLYTE_VOLUME INT16 hold_register 17004 unilab_send_msg_electrolyte_vol
21 REG_MSG_ASSEMBLY_TYPE INT16 hold_register 17006 unilab_send_msg_assembly_type
22 REG_MSG_ASSEMBLY_PRESSURE INT16 hold_register 17008 unilab_send_msg_assembly_pressure
23 REG_DATA_ASSEMBLY_COIN_CELL_NUM INT16 hold_register 16000 data_assembly_coin_cell_num
24 REG_DATA_OPEN_CIRCUIT_VOLTAGE FLOAT32 hold_register 16002 data_open_circuit_voltage
25 REG_DATA_AXIS_X_POS FLOAT32 hold_register 16004
26 REG_DATA_AXIS_Y_POS FLOAT32 hold_register 16006
27 REG_DATA_AXIS_Z_POS FLOAT32 hold_register 16008
28 REG_DATA_POLE_WEIGHT FLOAT32 hold_register 16010 data_pole_weight
29 REG_DATA_ASSEMBLY_PER_TIME FLOAT32 hold_register 16012 data_assembly_time
30 REG_DATA_ASSEMBLY_PRESSURE INT16 hold_register 16014 data_assembly_pressure
31 REG_DATA_ELECTROLYTE_VOLUME INT16 hold_register 16016 data_electrolyte_volume
32 REG_DATA_COIN_NUM INT16 hold_register 16018 data_coin_num
33 REG_DATA_ELECTROLYTE_CODE STRING hold_register 16020 data_electrolyte_code()
34 REG_DATA_COIN_CELL_CODE STRING hold_register 16030 data_coin_cell_code()
35 REG_DATA_STACK_VISON_CODE STRING hold_register 18004 data_stack_vision_code()
36 REG_DATA_GLOVE_BOX_PRESSURE FLOAT32 hold_register 16050 data_glove_box_pressure
37 REG_DATA_GLOVE_BOX_WATER_CONTENT FLOAT32 hold_register 16052 data_glove_box_water_content
38 REG_DATA_GLOVE_BOX_O2_CONTENT FLOAT32 hold_register 16054 data_glove_box_o2_content
39 UNILAB_SEND_ELECTROLYTE_BOTTLE_NUM BOOL coil 9720
40 UNILAB_RECE_ELECTROLYTE_BOTTLE_NUM BOOL coil 9520
41 REG_MSG_ELECTROLYTE_NUM_USED INT16 hold_register 17496
42 REG_DATA_ELECTROLYTE_USE_NUM INT16 hold_register 16000
43 UNILAB_SEND_FINISHED_CMD BOOL coil 9730
44 UNILAB_RECE_FINISHED_CMD BOOL coil 9530
45 REG_DATA_ASSEMBLY_TYPE INT16 hold_register 16018 ASSEMBLY_TYPE7or8
46 COIL_ALUMINUM_FOIL BOOL 使用铝箔垫 coil 9340
47 REG_MSG_NE_PLATE_MATRIX INT16 负极片矩阵点位 hold_register 17440
48 REG_MSG_SEPARATOR_PLATE_MATRIX INT16 隔膜矩阵点位 hold_register 17450
49 REG_MSG_TIP_BOX_MATRIX INT16 移液枪头矩阵点位 hold_register 17480
50 REG_MSG_NE_PLATE_NUM INT16 负极片盘数 hold_register 17443
51 REG_MSG_SEPARATOR_PLATE_NUM INT16 隔膜盘数 hold_register 17453
52 REG_MSG_PRESS_MODE BOOL 压制模式(false:压力检测模式,True:距离模式) coil 9360 电池压制模式
53
54 BOOL 视觉对位(false:使用,true:忽略) coil 9300 视觉对位
55 BOOL 复检(false:使用,true:忽略) coil 9310 视觉复检
56 BOOL 手套箱_左仓(false:使用,true:忽略) coil 9320 手套箱左仓
57 BOOL 手套箱_右仓(false:使用,true:忽略) coil 9420 手套箱右仓
58 BOOL 真空检知(false:使用,true:忽略) coil 9350 真空检知
59 BOOL 电解液添加模式(false:单次滴液,true:二次滴液) coil 9370 滴液模式
60 BOOL 正极片称重(false:使用,true:忽略) coil 9380 正极片称重
61 BOOL 正负极片组装方式(false:正装,true:倒装) coil 9390 正负极反装
62 BOOL 压制清洁(false:使用,true:忽略) coil 9400 压制清洁
63 BOOL 物料盘摆盘方式(false:水平摆盘,true:堆叠摆盘) coil 9410 负极片摆盘方式
64 REG_MSG_BATTERY_CLEAN_IGNORE BOOL 忽略电池清洁(false:使用,true:忽略) coil 9460

View File

@@ -1,159 +0,0 @@
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>,,,,,,
1 Name DataType Comment DeviceType Address
2 COIL_SYS_START_CMD BOOL 设备启动命令 coil 8010
3 COIL_SYS_STOP_CMD BOOL 设备停止命令 coil 8020
4 COIL_SYS_RESET_CMD BOOL 设备复位命令 coil 8030
5 COIL_SYS_HAND_CMD BOOL 设备手动模式命令 coil 8040
6 COIL_SYS_AUTO_CMD BOOL 设备自动模式命令 coil 8050
7 COIL_SYS_INIT_CMD BOOL 设备初始化模式命令 coil 8060
8 COIL_SYS_STOP_STATUS BOOL 设备暂停中 coil 8220
9
10 BOOL UNILAB发送电解液瓶数完毕 coil 8720
11 BOOL 设备请求接受电解液瓶数 coil 8520
12 REG_MSG_ELECTROLYTE_NUM WORD 电解液使用瓶数 hold_register 496
13 WORD 负极片盘矩阵点位(初始位0) hold_register 440
14 WORD 隔膜盘矩阵点位(初始位0) hold_register 450
15 WORD 电解液瓶盘_缓存上料矩阵点位(初始位0) hold_register 460
16 WORD 电解液瓶盘_缓存回收矩阵点位(初始位0) hold_register 430
17 WORD g_电解液瓶盘_手套箱无杆缸矩阵点位(初始位0) hold_register 470
18 WORD 移液枪头矩阵点位(初始位0) hold_register 480
19 WORD 设置负极片盘数 hold_register 443
20 WORD 设置隔膜盘数 hold_register 453
21
22 COIL_UNILAB_SEND_MSG_SUCC_CMD BOOL UNILAB发送配方完毕 coil 8700
23 COIL_REQUEST_REC_MSG_STATUS BOOL 设备请求接受配方 coil 8500
24 REG_MSG_ELECTROLYTE_USE_NUM INT16 单瓶电解液使用次数 hold_register 11000
25 REG_MSG_ELECTROLYTE_VOLUME INT16 电解液吸取量 hold_register 11004
26 REG_MSG_ASSEMBLY_PRESSURE INT16 电池组装压制力 hold_register 11008
27 REG_DATA_ELECTROLYTE_CODE STRING 电解液二维码序列号 hold_register 10020
28 BOOL 视觉对位(false:使用,true:忽略) coil 8300
29 BOOL 复检(false:使用,true:忽略) coil 8310
30 BOOL 手套箱_左仓(false:使用,true:忽略) coil 8320
31 BOOL 手套箱_右仓(false:使用,true:忽略) coil 8420
32 BOOL 机械手搬送料盘(false:使用,true:忽略) coil 8330
33 BOOL 铝箔物料(false:使用,true:忽略) coil 8340
34 BOOL 真空检知(false:使用,true:忽略) coil 8350
35 BOOL 压制模式(false:压力检测模式,True:距离模式) coil 8360
36 BOOL 电解液添加模式(false:单次滴液,true:二次滴液) coil 8370
37 BOOL 正极片称重(false:使用,true:忽略) coil 8380
38 BOOL 正负极片组装方式(false:正装,true:倒装) coil 8390
39 BOOL 压制清洁(false:使用,true:忽略) coil 8400
40 BOOL 物料盘摆盘方式(false:水平摆盘,true:堆叠摆盘) coil 8410
41 COIL_SYS_UNILAB_INTERACT BOOL 忽略Unilab交互(false:使用,true:忽略) coil 8450
42 BOOL 忽略电池清洁(false:使用,true:忽略) colil 8460
43
44 COIL_UNILAB_SEND_MSG_SUCC_CMD BOOL UNILAB发送配方完毕 coil 8510
45 COIL_UNILAB_REC_MSG_SUCC_CMD BOOL UNILAB接受测试数据完毕 coil 8710
46 REG_DATA_POLE_WEIGHT FLOAT32 当前电池正极片称重数据 hold_register 10010
47 REG_DATA_ASSEMBLY_PER_TIME FLOAT32 当前单颗电池组装时间 hold_register 10012
48 REG_DATA_ASSEMBLY_PRESSURE INT16 当前电池组装压制力 hold_register 10014
49 REG_DATA_ELECTROLYTE_VOLUME INT16 当前电解液加注量 hold_register 10016
50 REG_DATA_ASSEMBLY_TYPE INT16 组装参数:极片堆叠方式(7/8) hold_register 10018
51 REG_DATA_ELECTROLYTE_CODE STRING 电解液二维码序列号 hold_register 10020
52 REG_DATA_COIN_CELL_CODE STRING 电池二维码序列号 hold_register 10030
53 REG_DATA_STACK_VISON_CODE STRING 物料堆叠复检图片编码 hold_register 10040
54 REG_DATA_ELECTROLYTE_USE_NUM INT16 当前电极液组装电池数量(R) hold_register 10000
55 REG_DATA_OPEN_CIRCUIT_VOLTAGE FLOAT32 当前电池电压数据 hold_register 10002
56 INT 机械手吸取物料寄存器(1-正极壳、2-铝垫、3-正极片、4-隔膜、5-负极片、6-平垫、7-弹垫、8-负极壳) hold_register 10060
57
58 INT 当前负极片剩余盘数量(R) hold_register 10062 PLC地址 1223-新增
59 INT 当前隔膜神域盘数量(R) hold_register 10064
60 INT 电解液状态码(R) hold_register 10066
61 REAL 开路电压OK下限值(R) hold_register 10068
62 REAL 开路电压OK上限值(R) hold_register 10070
63 INT 当前进行组装电池数量(R) hold_register 10072
64 INT 当前完成组装电池数量(R) hold_register 10074
65 REAL 10mm正极片剩余物料数量(R) hold_register 520 HMI地址
66 REAL 12mm正极片剩余物料数量(R) hold_register 522
67 REAL 16mm正极片剩余物料数量(R) hold_register 524
68 REAL 铝箔剩余物料数量(R) hold_register 526
69 REAL 正极壳剩余物料数量(R) hold_register 528
70 REAL 平垫剩余物料数量(R) hold_register 530
71 REAL 负极壳剩余物料数量(R) hold_register 532
72 REAL 弹垫剩余物料数量(R) hold_register 534
73 REAL 成品电池剩余可容纳数量(R) hold_register 536
74 REAL 成品电池NG槽剩余可容纳数量(R) hold_register 538
75
76 REAL 设置10mm正极片厚度(W) hold_register 540
77 REAL 设置12mm正极片厚度(W) hold_register 542
78 REAL 设置16mm正极片厚度(W) hold_register 544
79 REAL 设置铝箔厚度(W) hold_register 546
80 REAL 设置正极壳厚度(W) hold_register 548
81 REAL 设置平垫厚度(W) hold_register 550
82 REAL 设置负极壳厚度(W) hold_register 552
83 REAL 设置弹垫厚度(W) hold_register 554
84 REAL 设置成品电池厚度(W) hold_register 556
85
86
87 REG_DATA_GLOVE_BOX_PRESSURE FLOAT32 手套箱压力 hold_register 10050
88 REG_DATA_GLOVE_BOX_WATER_CONTENT FLOAT32 手套箱水含量 hold_register 10052
89 REG_DATA_GLOVE_BOX_O2_CONTENT FLOAT32 手套箱氧含量 hold_register 10054
90
91 BOOL 异常100-系统异常 coil 1000
92 BOOL 异常101-急停 coil 1010
93 BOOL 异常111-手套箱急停 coil 1110
94 BOOL 异常112-手套箱内光栅遮挡 coil 1120
95 BOOL 异常160-移液枪头缺料 coil 1600
96 BOOL 异常161-正极壳缺料 coil 1610
97 BOOL 异常162-铝箔垫缺料 coil 1620
98 BOOL 异常163-正极片缺料 coil 1630
99 BOOL 异常164-隔膜缺料 coil 1640
100 BOOL 异常165-负极片缺料 coil 1650
101 BOOL 异常166-平垫缺料 coil 1660
102 BOOL 异常167-弹垫缺料 coil 1670
103 BOOL 异常168-负极壳缺料 coil 1680
104 BOOL 异常169-成品电池满料 coil 1690
105 BOOL 异常201-伺服轴01异常 coil 2010
106 BOOL 异常202-伺服轴02异常 coil 2020
107 BOOL 异常203-伺服轴03异常 coil 2030
108 BOOL 异常204-伺服轴04异常 coil 2040
109 BOOL 异常205-伺服轴05异常 coil 2050
110 BOOL 异常206-伺服轴06异常 coil 2060
111 BOOL 异常207-伺服轴07异常 coil 2070
112 BOOL 异常208-伺服轴08异常 coil 2080
113 BOOL 异常209-伺服轴09异常 coil 2090
114 BOOL 异常210-伺服轴10异常 coil 2100
115 BOOL 异常211-伺服轴11异常 coil 2110
116 BOOL 异常212-伺服轴12异常 coil 2120
117 BOOL 异常213-伺服轴13异常 coil 2130
118 BOOL 异常214-伺服轴14异常 coil 2140
119 BOOL 异常250-其他元件异常 coil 2500
120 BOOL 异常251-移液枪通讯异常 coil 2510
121 BOOL 异常252-移液枪报警 coil 2520
122 BOOL 异常256-电爪异常 coil 2560
123 BOOL 异常262-RB报警:未知点位错误 coil 2620
124 BOOL 异常263-RB报警:X、Y、Z参数超限制 coil 2630
125 BOOL 异常264-RB报警:视觉参数误差过大 coil 2640
126 BOOL 异常265-RB报警:1#吸嘴取料失败 coil 2650
127 BOOL 异常266-RB报警:2#吸嘴取料失败 coil 2660
128 BOOL 异常267-RB报警:3#吸嘴取料失败 coil 2670
129 BOOL 异常268-RB报警:4#吸嘴取料失败 coil 2680
130 BOOL 异常269-RB报警:取物料盘失败 coil 2690
131 BOOL 异常280-RB碰撞异常 coil 2800
132 BOOL 异常290-视觉系统通讯异常 coil 2900
133 BOOL 异常291-视觉对位NG异常 coil 2910
134 BOOL 异常292-扫码枪通讯异常 coil 2920
135 BOOL 异常310-开电移载吸嘴吸真空异常 coil 3100
136 BOOL 异常311-开电移载吸嘴破真空异常 coil 3110
137 BOOL 异常312-称重移载吸嘴吸真空异常 coil 3120
138 BOOL 异常313-称重移载吸嘴破真空异常 coil 3130
139 BOOL 异常340-开路电压吸嘴移载气缸异常 coil 3400
140 BOOL 异常342-开路电压吸嘴升降气缸异常 coil 3420
141 BOOL 异常344-开路电压旋压气缸异常 coil 3440
142 BOOL 异常350-称重吸嘴移载气缸异常 coil 3500
143 BOOL 异常352-称重吸嘴升降气缸异常 coil 3520
144 BOOL 异常354-清洗无尘布移载气缸异常 coil 3540
145 BOOL 异常356-清洗无尘布压紧气缸异常 coil 3560
146 BOOL 异常360-电解液瓶定位气缸异常 coil 3600
147 BOOL 异常362-移液枪头盒定位气缸异常 coil 3620
148 COIL ALARM_364_SERVO_DRIVE_ERROR BOOL 异常364-试剂瓶夹爪升降气缸异常 coil 3640
149 COIL ALARM_367_SERVO_DRIVER_ERROR BOOL 异常366-试剂瓶夹爪气缸异常 coil 3660
150 COIL ALARM_370_SERVO_MODULE_ERROR BOOL 异常370-压制模块吹气气缸异常 coil 3700
151
152
153
154
155
156
157
158 COIL + 功能模块/类型 + 具体描述(大写+下划线分隔)--针对bool值
159 REG + 功能模块/类型 + 具体描述(大写+下划线分隔)--针对寄存器

View File

@@ -1,2 +0,0 @@
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'
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 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'

View File

@@ -1,2 +0,0 @@
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'
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 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'

View File

@@ -1,2 +0,0 @@
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'
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 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'

View File

@@ -1,9 +0,0 @@
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
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 20251230_182319 0.01600000075995922 13.899999618530273 175.0 3836 20 7 b'\x00\x00d\x00eaoR' b'\x00\x00\x01\x00\x00\x00\r\n'
3 20251230_185306 0.01600000075995922 13.639999389648438 625.0 3819 20 7 deaoR 
4 20251230_192124 0.0 8.949999809265137 414.0 3803 20 8 deaoR 
5 20251230_195621 3.8359999656677246 10.069999694824219 205.0 3350 20 8 LG600001 19311909
6 20251230_200830 0.7929999828338623 9.34999942779541 18.0 3318 20 8 LG600001 19533419
7 20251230_201123 0.0 9.169999122619629 17.0 3269 20 8 LG600001 20054389
8 20251230_201410 0.0 9.569999694824219 18.0 3237 20 8 LG600001 YS102704
9 20251230_201659 0.0 9.699999809265137 169.0 3318 20 8 LG600001 20112754

View File

@@ -1,3 +0,0 @@
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
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 20260106_221708 0.03200000151991844 26.26999855041504 18.0 3803 30 7 NoRead88 22000063
3 20260106_221957 0.11299999803304672 26.26999855041504 170.0 3787 30 7 LG600001 22124813

View File

@@ -0,0 +1,6 @@
Time,open_circuit_voltage,pole_weight,assembly_time,assembly_pressure,electrolyte_volume,coin_num,electrolyte_code,coin_cell_code
20260110_153356,0.0,23.889999389648438,17.0,3609,40,7,deaoR,
20260110_153640,3.430999994277954,23.719999313354492,162.0,3560,40,7,deaoR,
20260110_162905,0.0,23.920000076293945,772.0,3625,30,7,LG600001,YS103130
20260110_163526,3.430999994277954,24.010000228881836,234.0,3690,30,7,LG600001,YS102964
20260110_164530,0.0,23.589998245239258,219.0,3690,30,7,LG600001,YS102857
1 Time open_circuit_voltage pole_weight assembly_time assembly_pressure electrolyte_volume coin_num electrolyte_code coin_cell_code
2 20260110_153356 0.0 23.889999389648438 17.0 3609 40 7 deaoR 
3 20260110_153640 3.430999994277954 23.719999313354492 162.0 3560 40 7 deaoR 
4 20260110_162905 0.0 23.920000076293945 772.0 3625 30 7 LG600001 YS103130
5 20260110_163526 3.430999994277954 24.010000228881836 234.0 3690 30 7 LG600001 YS102964
6 20260110_164530 0.0 23.589998245239258 219.0 3690 30 7 LG600001 YS102857

View File

@@ -1,536 +0,0 @@
#!/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()