From 936834f8c358ee6bc2f79263ece05310011eb438 Mon Sep 17 00:00:00 2001 From: Andy6M Date: Wed, 7 Jan 2026 11:59:32 +0800 Subject: [PATCH] Update workstation code for YB4 0107 --- fix_datatype.py | 32 + unilabos/device_comms/modbus_plc/client.py | 5 +- unilabos/device_comms/modbus_plc/modbus.py | 158 +- .../bioyond_cell/2025092701.xlsx | Bin 9782 -> 0 bytes .../bioyond_cell/2025122301.xlsx | Bin 0 -> 9971 bytes .../bioyond_cell/2025122302.xlsx | Bin 0 -> 10161 bytes .../bioyond_studio/bioyond_cell/20251224.xlsx | Bin 0 -> 10127 bytes .../bioyond_cell_workstation-2.py | 1234 ++ .../bioyond_cell/bioyond_cell_workstation.py | 216 +- .../bioyond_cell/bioyond_yihua_YB.json | 14487 ---------------- .../bioyond_cell/material_id_CAS.xlsx | Bin 0 -> 9569 bytes .../bioyond_cell/material_template.xlsx | Bin 10375 -> 10675 bytes .../bioyond_cell/output_example.json | 197 + .../bioyond_cell/多订单返回说明.md | 113 + .../workstation/bioyond_studio/config.py | 8 +- .../Modbus_CSV_Mapping_Guide.md | 84 + .../coin_cell_assembly/YB_YH_materials.py | 6 + .../coin_cell_assembly/coin_cell_assembly.py | 714 +- .../coin_cell_assembly_1223.csv | 159 + .../coin_cell_assembly_20260106.xlsx | Bin 0 -> 17996 bytes .../coin_cell_assembly_a.csv | 64 - .../coin_cell_assembly_b.csv | 130 + .../coin_cell_assembly/date_20251224.csv | 2 + .../coin_cell_assembly/date_20251225.csv | 2 + .../coin_cell_assembly/date_20251229.csv | 2 + .../coin_cell_assembly/date_20251230.csv | 9 + .../coin_cell_assembly/date_20260106.csv | 3 + .../interactive_battery_export_demo.py | 536 + .../电池资源冲突修复说明.md | 107 + unilabos/registry/devices/bioyond_cell.yaml | 353 +- .../devices/coin_cell_workstation.yaml | 144 +- unilabos/registry/devices/laiyu_liquid.yaml | 1919 -- unilabos/registry/devices/liquid_handler.yaml | 9956 ----------- unilabos/registry/resources/bioyond/deck.yaml | 14 +- unilabos/resources/battery/electrode_sheet.py | 30 +- unilabos/resources/bioyond/decks.py | 2 +- 36 files changed, 3860 insertions(+), 26826 deletions(-) create mode 100644 fix_datatype.py delete mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122301.xlsx create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122302.xlsx create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/20251224.xlsx create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation-2.py delete mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_yihua_YB.json create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_id_CAS.xlsx create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/output_example.json create mode 100644 unilabos/devices/workstation/bioyond_studio/bioyond_cell/多订单返回说明.md create mode 100644 unilabos/devices/workstation/coin_cell_assembly/Modbus_CSV_Mapping_Guide.md create mode 100644 unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_1223.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_20260106.xlsx delete mode 100644 unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_a.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_b.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/date_20251224.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/date_20251225.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/date_20251229.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/date_20251230.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/date_20260106.csv create mode 100644 unilabos/devices/workstation/coin_cell_assembly/interactive_battery_export_demo.py create mode 100644 unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md delete mode 100644 unilabos/registry/devices/laiyu_liquid.yaml delete mode 100644 unilabos/registry/devices/liquid_handler.yaml diff --git a/fix_datatype.py b/fix_datatype.py new file mode 100644 index 0000000..67147d2 --- /dev/null +++ b/fix_datatype.py @@ -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!') diff --git a/unilabos/device_comms/modbus_plc/client.py b/unilabos/device_comms/modbus_plc/client.py index c239b9d..4b46746 100644 --- a/unilabos/device_comms/modbus_plc/client.py +++ b/unilabos/device_comms/modbus_plc/client.py @@ -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__': diff --git a/unilabos/device_comms/modbus_plc/modbus.py b/unilabos/device_comms/modbus_plc/modbus.py index 028477e..7e384d7 100644 --- a/unilabos/device_comms/modbus_plc/modbus.py +++ b/unilabos/device_comms/modbus_plc/modbus.py @@ -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') diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx deleted file mode 100644 index 2a45f93792e954b6891993f8d5205786d271caea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9782 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 M7DR_b`t<9608&{WHvj+t diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122301.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122301.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..2c82befe6747a413fa83a93b33ed91c6961eed2f GIT binary patch literal 9971 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 literal 0 HcmV?d00001 diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122302.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025122302.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..3357fd7adda0fda89e9b526e7f45d36bacc27d06 GIT binary patch literal 10161 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

O(dzbW&6x+m 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 literal 0 HcmV?d00001 diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation-2.py b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation-2.py new file mode 100644 index 0000000..6ba85a6 --- /dev/null +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation-2.py @@ -0,0 +1,1234 @@ +# -*- coding: utf-8 -*- +from cgi import print_arguments +from doctest import debug +from typing import Dict, Any, List, Optional +import requests +from pylabrobot.resources.resource import Resource as ResourcePLR +from pathlib import Path +import pandas as pd +import time +from datetime import datetime, timedelta +import re +import threading +import json +from copy import deepcopy +from urllib3 import response +from unilabos.devices.workstation.bioyond_studio.station import BioyondWorkstation, BioyondResourceSynchronizer +from unilabos.devices.workstation.bioyond_studio.config import ( + API_CONFIG, MATERIAL_TYPE_MAPPINGS, WAREHOUSE_MAPPING, SOLID_LIQUID_MAPPINGS +) +from unilabos.devices.workstation.workstation_http_service import WorkstationHTTPService +from unilabos.resources.bioyond.decks import BIOYOND_YB_Deck +from unilabos.utils.log import logger +from unilabos.registry.registry import lab_registry + +def _iso_local_now_ms() -> str: + # 文档要求:到毫秒 + Z,例如 2025-08-15T05:43:22.814Z + dt = datetime.now() + # print(dt) + return dt.strftime("%Y-%m-%dT%H:%M:%S.") + f"{int(dt.microsecond/1000):03d}Z" + + +class BioyondCellWorkstation(BioyondWorkstation): + """ + 集成 Bioyond LIMS 的工作站示例, + 覆盖:入库(2.17/2.18) → 新建实验(2.14) → 启动调度(2.7) → + 运行中推送:物料变更(2.24)、步骤完成(2.21)、订单完成(2.23) → + 查询实验(2.5/2.6) → 3-2-1 转运(2.32) → 样品/废料取出(2.28) + """ + + def __init__(self, config: dict = None, deck=None, protocol_type=None, **kwargs): + + # 使用统一配置,支持自定义覆盖, 从 config.py 加载完整配置 + self.bioyond_config ={ + **API_CONFIG, + "material_type_mappings": MATERIAL_TYPE_MAPPINGS, + "warehouse_mapping": WAREHOUSE_MAPPING, + "debug_mode": False + } + + # "material_type_mappings": MATERIAL_TYPE_MAPPINGS + # "warehouse_mapping": WAREHOUSE_MAPPING + if deck is None and config: + deck = config.get('deck') + # print(self.bioyond_config) + self.debug_mode = self.bioyond_config["debug_mode"] + self.http_service_started = self.debug_mode + self._device_id = "bioyond_cell_workstation" # 默认值,后续会从_ros_node获取 + super().__init__(bioyond_config=config, deck=deck) + self.update_push_ip() #直接修改奔耀端的报送ip地址 + logger.info("已更新奔耀端推送 IP 地址") + + # 启动 HTTP 服务线程 + t = threading.Thread(target=self._start_http_service, daemon=True, name="unilab_http") + t.start() + logger.info("HTTP 服务线程已启动") + # 等到任务报送成功 + self.order_finish_event = threading.Event() + self.last_order_status = None + self.last_order_code = None + logger.info(f"Bioyond工作站初始化完成 (debug_mode={self.debug_mode})") + + @property + def device_id(self): + """获取设备ID,优先从_ros_node获取,否则返回默认值""" + if hasattr(self, '_ros_node') and self._ros_node is not None: + return getattr(self._ros_node, 'device_id', self._device_id) + return self._device_id + + def _start_http_service(self): + """启动 HTTP 服务""" + host = self.bioyond_config.get("HTTP_host", "") + port = self.bioyond_config.get("HTTP_port", None) + try: + self.service = WorkstationHTTPService(self, host=host, port=port) + self.service.start() + self.http_service_started = True + logger.info(f"WorkstationHTTPService 成功启动: {host}:{port}") + while True: + time.sleep(1) #一直挂着,直到进程退出 + except Exception as e: + self.http_service_started = False + logger.error(f"启动 WorkstationHTTPService 失败: {e}", exc_info=True) + + + # http报送服务,返回数据部分 + def process_step_finish_report(self, report_request): + stepId = report_request.data.get("stepId") + logger.info(f"步骤完成: stepId: {stepId}, stepName:{report_request.data.get('stepName')}") + return report_request.data.get('executionStatus') + + def process_sample_finish_report(self, report_request): + logger.info(f"通量完成: {report_request.data.get('sampleId')}") + return {"status": "received"} + + def process_order_finish_report(self, report_request, used_materials=None): + order_code = report_request.data.get("orderCode") + status = report_request.data.get("status") + logger.info(f"report_request: {report_request}") + logger.info(f"任务完成: {order_code}, status={status}") + + # 保存完整报文 + self.last_order_report = report_request.data + # 如果是当前等待的订单,触发事件 + if self.last_order_code == order_code: + self.order_finish_event.set() + + return {"status": "received"} + + def wait_for_order_finish(self, order_code: str, timeout: int = 36000) -> Dict[str, Any]: + """ + 等待指定 orderCode 的 /report/order_finish 报送。 + Args: + order_code: 任务编号 + timeout: 超时时间(秒) + Returns: + 完整的报送数据 + 状态判断结果 + """ + if not order_code: + logger.error("wait_for_order_finish() 被调用,但 order_code 为空!") + return {"status": "error", "message": "empty order_code"} + + self.last_order_code = order_code + self.last_order_report = None + self.order_finish_event.clear() + + logger.info(f"等待任务完成报送: orderCode={order_code} (timeout={timeout}s)") + + if not self.order_finish_event.wait(timeout=timeout): + logger.error(f"等待任务超时: orderCode={order_code}") + return {"status": "timeout", "orderCode": order_code} + + # 报送数据匹配验证 + report = self.last_order_report or {} + report_code = report.get("orderCode") + status = str(report.get("status", "")) + + if report_code != order_code: + logger.warning(f"收到的报送 orderCode 不匹配: {report_code} ≠ {order_code}") + return {"status": "mismatch", "report": report} + + if status == "30": + logger.info(f"任务成功完成 (orderCode={order_code})") + return {"status": "success", "report": report} + elif status == "-11": + logger.error(f"任务异常停止 (orderCode={order_code})") + return {"status": "abnormal_stop", "report": report} + elif status == "-12": + logger.warning(f"任务人工停止 (orderCode={order_code})") + return {"status": "manual_stop", "report": report} + else: + logger.warning(f"任务未知状态 ({status}) (orderCode={order_code})") + return {"status": f"unknown_{status}", "report": report} + + + # -------------------- 基础HTTP封装 -------------------- + def _url(self, path: str) -> str: + return f"{self.bioyond_config['api_host'].rstrip('/')}/{path.lstrip('/')}" + + def _post_lims(self, path: str, data: Optional[Any] = None) -> Dict[str, Any]: + """LIMS API:大多数接口用 {apiKey/requestTime,data} 包装""" + payload = { + "apiKey": self.bioyond_config["api_key"], + "requestTime": _iso_local_now_ms() + } + if data is not None: + payload["data"] = data + + if self.debug_mode: + # 模拟返回,不发真实请求 + logger.info(f"[DEBUG] POST {path} with payload={payload}") + + return {"debug": True, "url": self._url(path), "payload": payload, "status": "ok"} + + try: + logger.info(json.dumps(payload, ensure_ascii=False)) + response = requests.post( + self._url(path), + json=payload, + timeout=self.bioyond_config.get("timeout", 30), + headers={"Content-Type": "application/json"} + ) # 拼接网址+post bioyond接口 + response.raise_for_status() + return response.json() + except Exception as e: + logger.info(f"{self.bioyond_config['api_host'].rstrip('/')}/{path.lstrip('/')}") + logger.error(f"POST {path} 失败: {e}") + return {"error": str(e)} + + def _put_lims(self, path: str, data: Optional[Any] = None) -> Dict[str, Any]: + """LIMS API:PUT {apiKey/requestTime,data} 包装""" + payload = { + "apiKey": self.bioyond_config["api_key"], + "requestTime": _iso_local_now_ms() + } + if data is not None: + payload["data"] = data + + if self.debug_mode: + logger.info(f"[DEBUG] PUT {path} with payload={payload}") + return {"debug_mode": True, "url": self._url(path), "payload": payload, "status": "ok"} + + try: + response = requests.put( + self._url(path), + json=payload, + timeout=self.bioyond_config.get("timeout", 30), + headers={"Content-Type": "application/json"} + ) + response.raise_for_status() + return response.json() + except Exception as e: + logger.info(f"{self.bioyond_config['api_host'].rstrip('/')}/{path.lstrip('/')}") + logger.error(f"PUT {path} 失败: {e}") + return {"error": str(e)} + + # -------------------- 3.36 更新推送 IP 地址 -------------------- + def update_push_ip(self, ip: Optional[str] = None, port: Optional[int] = None) -> Dict[str, Any]: + """ + 3.36 更新推送 IP 地址接口(PUT) + URL: /api/lims/order/ip-config + 请求体:{ apiKey, requestTime, data: { ip, port } } + """ + target_ip = ip or self.bioyond_config.get("HTTP_host", "") + target_port = int(port or self.bioyond_config.get("HTTP_port", 0)) + data = {"ip": target_ip, "port": target_port} + + # 固定接口路径,不做其他路径兼容 + path = "/api/lims/order/ip-config" + return self._put_lims(path, data) + + # -------------------- 单点接口封装 -------------------- + # 2.17 入库物料(单个) + def storage_inbound(self, material_id: str, location_id: str) -> Dict[str, Any]: + return self._post_lims("/api/lims/storage/inbound", { + "materialId": material_id, + "locationId": location_id + }) + + # 2.18 批量入库(多个) + def storage_batch_inbound(self, items: List[Dict[str, str]]) -> Dict[str, Any]: + """ + items = [{"materialId": "...", "locationId": "..."}, ...] + """ + return self._post_lims("/api/lims/storage/batch-inbound", items) + + + def auto_feeding4to3( + self, + # ★ 修改点:默认模板路径 + xlsx_path: Optional[str] = "/Users/sml/work/Unilab/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, + ): + """ + 自动化上料(支持两种模式) + - Excel 路径存在 → 从 Excel 模板解析 + - Excel 路径不存在 → 使用手动参数 + """ + items: List[Dict[str, Any]] = [] + + # ---------- 模式 1: Excel 导入 ---------- + if xlsx_path: + path = Path(__file__).parent / Path(xlsx_path) + if path.exists(): # ★ 修改点:路径存在才加载 + try: + df = pd.read_excel(path, sheet_name=0, header=None, engine="openpyxl") + except Exception as e: + raise RuntimeError(f"读取 Excel 失败:{e}") + + # 四号手套箱加样头面 + for _, row in df.iloc[1:13, 2:7].iterrows(): + if pd.notna(row[5]): + items.append({ + "sourceWHName": "四号手套箱堆栈", + "posX": int(row[2]), "posY": int(row[3]), "posZ": int(row[4]), + "materialName": str(row[5]).strip(), + "quantity": float(row[6]) if pd.notna(row[6]) else 0.0, + }) + # 四号手套箱原液瓶面 + for _, row in df.iloc[14:23, 2:9].iterrows(): + if pd.notna(row[5]): + items.append({ + "sourceWHName": "四号手套箱堆栈", + "posX": int(row[2]), "posY": int(row[3]), "posZ": int(row[4]), + "materialName": str(row[5]).strip(), + "quantity": float(row[6]) if pd.notna(row[6]) else 0.0, + "materialType": str(row[7]).strip() if pd.notna(row[7]) else "", + "targetWH": str(row[8]).strip() if pd.notna(row[8]) else "", + }) + # 三号手套箱人工堆栈 + for _, row in df.iloc[25:40, 2:7].iterrows(): + if pd.notna(row[5]) or pd.notna(row[6]): + items.append({ + "sourceWHName": "三号手套箱人工堆栈", + "posX": int(row[2]), "posY": int(row[3]), "posZ": int(row[4]), + "materialType": str(row[5]).strip() if pd.notna(row[5]) else "", + "materialId": str(row[6]).strip() if pd.notna(row[6]) else "", + "quantity": 1 + }) + else: + logger.warning(f"未找到 Excel 文件 {xlsx_path},自动切换到手动参数模式。") + + # ---------- 模式 2: 手动填写 ---------- + if not items: + params = locals() + for name, value in params.items(): + if name.startswith("四号手套箱堆栈") and "materialName" in name and value: + idx = name.split("_") + items.append({ + "sourceWHName": "四号手套箱堆栈", + "posX": int(idx[1][1:]), "posY": int(idx[2][1:]), "posZ": int(idx[3][1:]), + "materialName": value, + "quantity": float(params.get(name.replace("materialName", "quantity"), 0.0)) + }) + elif name.startswith("四号手套箱堆栈") and "materialType" in name and (value or params.get(name.replace("materialType", "materialName"), "")): + idx = name.split("_") + items.append({ + "sourceWHName": "四号手套箱堆栈", + "posX": int(idx[1][1:]), "posY": int(idx[2][1:]), "posZ": int(idx[3][1:]), + "materialName": params.get(name.replace("materialType", "materialName"), ""), + "quantity": float(params.get(name.replace("materialType", "quantity"), 0.0)), + "materialType": value, + "targetWH": params.get(name.replace("materialType", "targetWH"), ""), + }) + elif name.startswith("三号手套箱人工堆栈") and "materialType" in name and (value or params.get(name.replace("materialType", "materialId"), "")): + idx = name.split("_") + items.append({ + "sourceWHName": "三号手套箱人工堆栈", + "posX": int(idx[1][1:]), "posY": int(idx[2][1:]), "posZ": int(idx[3][1:]), + "materialType": value, + "materialId": params.get(name.replace("materialType", "materialId"), ""), + "quantity": int(params.get(name.replace("materialType", "quantity"), 1)), + }) + + if not items: + logger.warning("没有有效的上料条目,已跳过提交。") + return {"code": 0, "message": "no valid items", "data": []} + logger.info(items) + response = self._post_lims("/api/lims/order/auto-feeding4to3", items) + + # 等待任务报送成功 + order_code = response.get("data", {}).get("orderCode") + if not order_code: + logger.error("上料任务未返回有效 orderCode!") + return response + # 等待完成报送 + result = self.wait_for_order_finish(order_code) + print("\n" + "="*60) + print("实验记录本结果auto_feeding4to3") + print("="*60) + print(json.dumps(result, indent=2, ensure_ascii=False)) + print("="*60 + "\n") + return result + + def auto_batch_outbound_from_xlsx(self, xlsx_path: str) -> Dict[str, Any]: + """ + 3.31 自动化下料(Excel -> JSON -> POST /api/lims/storage/auto-batch-out-bound) + """ + path = Path(xlsx_path) + if not path.exists(): + 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}") + + def pick(names: List[str]) -> Optional[str]: + for n in names: + if n in df.columns: + return n + return None + + c_loc = pick(["locationId", "库位ID", "库位Id", "库位id"]) + c_wh = pick(["warehouseId", "仓库ID", "仓库Id", "仓库id"]) + c_qty = pick(["数量", "quantity"]) + c_x = pick(["x", "X", "posX", "坐标X"]) + c_y = pick(["y", "Y", "posY", "坐标Y"]) + c_z = pick(["z", "Z", "posZ", "坐标Z"]) + + required = [c_loc, c_wh, c_qty, c_x, c_y, c_z] + if any(c is None for c in required): + raise KeyError("Excel 缺少必要列:locationId/warehouseId/数量/x/y/z(支持多别名,至少要能匹配到)。") + + def as_int(v, d=0): + try: + if pd.isna(v): return d + return int(v) + except Exception: + try: + return int(float(v)) + except Exception: + return d + + def as_float(v, d=0.0): + try: + if pd.isna(v): return d + return float(v) + except Exception: + return d + + def as_str(v, d=""): + if v is None or (isinstance(v, float) and pd.isna(v)): return d + s = str(v).strip() + return s if s else d + + items: List[Dict[str, Any]] = [] + for _, row in df.iterrows(): + items.append({ + "locationId": as_str(row[c_loc]), + "warehouseId": as_str(row[c_wh]), + "quantity": as_float(row[c_qty]), + "x": as_int(row[c_x]), + "y": as_int(row[c_y]), + "z": as_int(row[c_z]), + }) + + response = self._post_lims("/api/lims/storage/auto-batch-out-bound", items) + self.wait_for_response_orders(response, "auto_batch_outbound_from_xlsx") + return response + + # 2.14 新建实验 + def create_orders(self, xlsx_path: str) -> Dict[str, Any]: + """ + 从 Excel 解析并创建实验(2.14) + 约定: + - batchId = Excel 文件名(不含扩展名) + - 物料列:所有以 "(g)" 结尾(不再读取“总质量(g)”列) + - totalMass 自动计算为所有物料质量之和 + - createTime 缺失或为空时自动填充为当前日期(YYYY/M/D) + """ + default_path = Path("/Users/sml/work/Unilab/unilabos/devices/workstation/bioyond_studio/bioyond_cell/2025092701.xlsx") + path = Path(xlsx_path) if xlsx_path else default_path + print(f"[create_orders] 使用 Excel 路径: {path}") + if path != default_path: + print("[create_orders] 来源: 调用方传入自定义路径") + else: + print("[create_orders] 来源: 使用默认模板路径") + + if not path.exists(): + print(f"[create_orders] ⚠️ 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] 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] 列匹配结果:", { + "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] 识别到的物料列: {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] 第 {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] 第 {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] ⚠️ 第 {idx+1} 行总质量 <= 0,可能导致 LIMS 校验失败") + if not mats: + print(f"[create_orders] ⚠️ 第 {idx+1} 行未找到有效物料") + + orders.append(order_data) + print("================================================") + print("orders:", orders) + + print(f"[create_orders] 即将提交订单数量: {len(orders)}") + response = self._post_lims("/api/lims/order/orders", orders) + print(f"[create_orders] 接口返回: {response}") + # 等待任务报送成功 + 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!") + return response + # 等待完成报送 + result = self.wait_for_order_finish(order_code) + print("实验记录本========================create_orders========================") + print(result) + print("========================") + return result + + # 2.7 启动调度 + def scheduler_start(self) -> Dict[str, Any]: + return self._post_lims("/api/lims/scheduler/start") + # 3.10 停止调度 + def scheduler_stop(self) -> Dict[str, Any]: + + """ + 停止调度 (3.10) + 请求体只包含 apiKey 和 requestTime + """ + return self._post_lims("/api/lims/scheduler/stop") + # 2.9 继续调度 + # 2.9 继续调度 + def scheduler_continue(self) -> Dict[str, Any]: + """ + 继续调度 (2.9) + 请求体只包含 apiKey 和 requestTime + """ + return self._post_lims("/api/lims/scheduler/continue") + def scheduler_reset(self) -> Dict[str, Any]: + """ + 复位调度 (2.11) + 请求体只包含 apiKey 和 requestTime + """ + return self._post_lims("/api/lims/scheduler/reset") + + + # 2.24 物料变更推送 + def report_material_change(self, material_obj: Dict[str, Any]) -> Dict[str, Any]: + """ + material_obj 按 2.24 的裸对象格式(包含 id/typeName/locations/detail 等) + """ + return self._post_report_raw("/report/material_change", material_obj) + + # 2.32 3-2-1 物料转运 + def transfer_3_to_2_to_1(self, + # source_wh_id: Optional[str] = None, + 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]: + payload: Dict[str, Any] = { + "sourcePosX": source_x, "sourcePosY": source_y, "sourcePosZ": source_z + } + if source_wh_id: + payload["sourceWHID"] = source_wh_id + + response = self._post_lims("/api/lims/order/transfer-task3To2To1", payload) + # 等待任务报送成功 + order_code = response.get("data", {}).get("orderCode") + if not order_code: + logger.error("上料任务未返回有效 orderCode!") + return response + # 等待完成报送 + result = self.wait_for_order_finish(order_code) + return result + + # 3.35 1→2 物料转运 + def transfer_1_to_2(self) -> Dict[str, Any]: + """ + 1→2 物料转运 + URL: /api/lims/order/transfer-task1To2 + 只需要 apiKey 和 requestTime + """ + response = self._post_lims("/api/lims/order/transfer-task1To2") + # 等待任务报送成功 + order_code = response.get("data", {}).get("orderCode") + if not order_code: + logger.error("上料任务未返回有效 orderCode!") + return response + # 等待完成报送 + result = self.wait_for_order_finish(order_code) + return result + + # 2.5 批量查询实验报告(post过滤关键字查询) + def order_list_v2(self, + timeType: str = "", + beginTime: str = "", + endTime: str = "", + status: str = "", # 60表示正在运行,80表示完成,90表示失败 + filter: str = "", + skipCount: int = 0, + pageCount: int = 1, # 显示多少页数据 + sorting: str = "") -> Dict[str, Any]: + """ + 批量查询实验报告的详细信息 (2.5) + URL: /api/lims/order/order-list + 参数默认值和接口文档保持一致 + """ + data: Dict[str, Any] = { + "timeType": timeType, + "beginTime": beginTime, + "endTime": endTime, + "status": status, + "filter": filter, + "skipCount": skipCount, + "pageCount": pageCount, + "sorting": sorting + } + return self._post_lims("/api/lims/order/order-list", data) + + # 一直post执行bioyond接口查询任务状态 + def wait_for_transfer_task(self, timeout: int = 3000, interval: int = 5, filter_text: Optional[str] = None) -> bool: + """ + 轮询查询物料转移任务是否成功完成 (status=80) + - timeout: 最大等待秒数 (默认600秒) + - interval: 轮询间隔秒数 (默认3秒) + 返回 True 表示找到并成功完成,False 表示超时未找到 + """ + now = datetime.now() + beginTime = now.strftime("%Y-%m-%dT%H:%M:%SZ") + endTime = (now + timedelta(minutes=5)).strftime("%Y-%m-%dT%H:%M:%SZ") + print(beginTime, endTime) + + deadline = time.time() + timeout + + while time.time() < deadline: + result = self.order_list_v2( + timeType="", + beginTime=beginTime, + endTime=endTime, + status="", + filter=filter_text, + skipCount=0, + pageCount=1, + sorting="" + ) + print(result) + + items = result.get("data", {}).get("items", []) + for item in items: + name = item.get("name", "") + status = item.get("status") + # 改成用 filter_text 判断 + if (not filter_text or filter_text in name) and status == 80: + logger.info(f"硬件转移动作完成: {name}, status={status}") + return True + + logger.info(f"等待中: {name}, status={status}") + time.sleep(interval) + + logger.warning("超时未找到成功的物料转移任务") + return False + + def create_materials(self, mappings: Dict[str, Dict[str, Any]]) -> List[Dict[str, Any]]: + """ + 将 SOLID_LIQUID_MAPPINGS 中的所有物料逐个 POST 到 /api/lims/storage/material + """ + results = [] + + for name, data in mappings.items(): + data = { + "typeId": data["typeId"], + "code": data.get("code", ""), + "barCode": data.get("barCode", ""), + "name": data["name"], + "unit": data.get("unit", "g"), + "parameters": data.get("parameters", ""), + "quantity": data.get("quantity", ""), + "warningQuantity": data.get("warningQuantity", ""), + "details": data.get("details", []) + } + + logger.info(f"正在创建第 {i}/{total} 个固体物料: {name}") + result = self._post_lims("/api/lims/storage/material", material_data) + + if result and result.get("code") == 1: + # data 字段可能是字符串(物料ID)或字典(包含id字段) + data = result.get("data") + if isinstance(data, str): + # data 直接是物料ID字符串 + material_id = data + elif isinstance(data, dict): + # data 是字典,包含id字段 + material_id = data.get("id") + else: + material_id = None + + if material_id: + created_materials.append({ + "name": name, + "materialId": material_id, + "typeId": type_id + }) + logger.info(f"✓ 成功创建物料: {name}, ID: {material_id}") + else: + logger.error(f"✗ 创建物料失败: {name}, 未返回ID") + logger.error(f" 响应数据: {result}") + else: + error_msg = result.get("error") or result.get("message", "未知错误") + logger.error(f"✗ 创建物料失败: {name}") + logger.error(f" 错误信息: {error_msg}") + logger.error(f" 完整响应: {result}") + + # 避免请求过快 + time.sleep(0.3) + + logger.info(f"物料创建完成,成功创建 {len(created_materials)}/{total} 个固体物料") + return created_materials + + def _sync_materials_safe(self) -> bool: + """仅使用 BioyondResourceSynchronizer 执行同步(与 station.py 保持一致)。""" + if hasattr(self, 'resource_synchronizer') and self.resource_synchronizer: + try: + return bool(self.resource_synchronizer.sync_from_external()) + except Exception as e: + logger.error(f"同步失败: {e}") + return False + logger.warning("资源同步器未初始化") + return False + + def _load_warehouse_locations(self, warehouse_name: str) -> tuple[List[str], List[str]]: + """从配置加载仓库位置信息 + + Args: + warehouse_name: 仓库名称 + + Returns: + (location_ids, position_names) 元组 + """ + warehouse_mapping = self.bioyond_config.get("warehouse_mapping", WAREHOUSE_MAPPING) + + if warehouse_name not in warehouse_mapping: + raise ValueError(f"配置中未找到仓库: {warehouse_name}。可用: {list(warehouse_mapping.keys())}") + + site_uuids = warehouse_mapping[warehouse_name].get("site_uuids", {}) + if not site_uuids: + raise ValueError(f"仓库 {warehouse_name} 没有配置位置") + + # 按顺序获取位置ID和名称 + location_ids = [] + position_names = [] + for key in sorted(site_uuids.keys()): + location_ids.append(site_uuids[key]) + position_names.append(key) + + return location_ids, position_names + + + def create_and_inbound_materials( + self, + material_names: Optional[List[str]] = None, + type_id: str = "3a190ca0-b2f6-9aeb-8067-547e72c11469", + warehouse_name: str = "粉末加样头堆栈" + ) -> Dict[str, Any]: + """ + 传参与默认列表方式创建物料并入库(不使用CSV)。 + + Args: + material_names: 物料名称列表;默认使用 [LiPF6, LiDFOB, DTD, LiFSI, LiPO2F2] + type_id: 物料类型ID + warehouse_name: 目标仓库名(用于取位置信息) + + Returns: + 执行结果字典 + """ + logger.info("=" * 60) + logger.info(f"开始执行:从参数创建物料并批量入库到 {warehouse_name}") + logger.info("=" * 60) + + try: + # 1) 准备物料名称(默认值) + default_materials = ["LiPF6", "LiDFOB", "DTD", "LiFSI", "LiPO2F2"] + mat_names = [m.strip() for m in (material_names or default_materials) if str(m).strip()] + if not mat_names: + return {"success": False, "error": "物料名称列表为空"} + + # 2) 加载仓库位置信息 + all_location_ids, position_names = self._load_warehouse_locations(warehouse_name) + logger.info(f"✓ 加载 {len(all_location_ids)} 个位置 ({position_names[0]} ~ {position_names[-1]})") + + # 限制数量不超过可用位置 + if len(mat_names) > len(all_location_ids): + logger.warning(f"物料数量超出位置数量,仅处理前 {len(all_location_ids)} 个") + mat_names = mat_names[:len(all_location_ids)] + + # 3) 创建物料 + logger.info(f"\n【步骤1/3】创建 {len(mat_names)} 个固体物料...") + created_materials = self.create_solid_materials(mat_names, type_id) + if not created_materials: + return {"success": False, "error": "没有成功创建任何物料"} + + # 4) 批量入库 + logger.info(f"\n【步骤2/3】批量入库物料...") + location_ids = all_location_ids[:len(created_materials)] + selected_positions = position_names[:len(created_materials)] + + inbound_items = [ + {"materialId": mat["materialId"], "locationId": loc_id} + for mat, loc_id in zip(created_materials, location_ids) + ] + + for material, position in zip(created_materials, selected_positions): + logger.info(f" - {material['name']} → {position}") + + result = self.storage_batch_inbound(inbound_items) + if result.get("code") != 1: + logger.error(f"✗ 批量入库失败: {result}") + return {"success": False, "error": "批量入库失败", "created_materials": created_materials, "inbound_result": result} + + logger.info("✓ 批量入库成功") + + # 5) 同步 + logger.info(f"\n【步骤3/3】同步物料数据...") + if self._sync_materials_safe(): + logger.info("✓ 物料数据同步完成") + else: + logger.warning("⚠ 物料数据同步未完成(可忽略,不影响已创建与入库的数据)") + + logger.info("\n" + "=" * 60) + logger.info("流程完成") + logger.info("=" * 60 + "\n") + + return { + "success": True, + "created_materials": created_materials, + "inbound_result": result, + "total_created": len(created_materials), + "total_inbound": len(inbound_items), + "warehouse": warehouse_name, + "positions": selected_positions + } + + except Exception as e: + logger.error(f"✗ 执行失败: {e}") + return {"success": False, "error": str(e)} + + def create_material( + self, + material_name: str, + type_id: str, + warehouse_name: str, + location_name_or_id: Optional[str] = None + ) -> Dict[str, Any]: + """创建单个物料并可选入库。 + Args: + material_name: 物料名称(会优先匹配配置模板)。 + type_id: 物料类型 ID(若为空则尝试从配置推断)。 + warehouse_name: 需要入库的仓库名称;若为空则仅创建不入库。 + location_name_or_id: 具体库位名称(如 A01)或库位 UUID,由用户指定。 + Returns: + 包含创建结果、物料ID以及入库结果的字典。 + """ + material_name = (material_name or "").strip() + + resolved_type_id = (type_id or "").strip() + # 优先从 SOLID_LIQUID_MAPPINGS 中获取模板数据 + template = SOLID_LIQUID_MAPPINGS.get(material_name) + if not template: + raise ValueError(f"在配置中未找到物料 {material_name} 的模板,请检查 SOLID_LIQUID_MAPPINGS。") + material_data: Dict[str, Any] + material_data = deepcopy(template) + # 最终确保 typeId 为调用方传入的值 + if resolved_type_id: + material_data["typeId"] = resolved_type_id + material_data["name"] = material_name + # 生成唯一编码 + def _generate_code(prefix: str) -> str: + normalized = re.sub(r"\W+", "_", prefix) + normalized = normalized.strip("_") or "material" + return f"{normalized}_{datetime.now().strftime('%Y%m%d%H%M%S')}" + if not material_data.get("code"): + material_data["code"] = _generate_code(material_name) + if not material_data.get("barCode"): + material_data["barCode"] = "" + # 处理数量字段类型 + def _to_number(value: Any, default: float = 0.0) -> float: + try: + if value is None: + return default + if isinstance(value, (int, float)): + return float(value) + if isinstance(value, str) and value.strip() == "": + return default + return float(value) + except (TypeError, ValueError): + return default + material_data["quantity"] = _to_number(material_data.get("quantity"), 1.0) + material_data["warningQuantity"] = _to_number(material_data.get("warningQuantity"), 0.0) + unit = material_data.get("unit") or "个" + material_data["unit"] = unit + if not material_data.get("parameters"): + material_data["parameters"] = json.dumps({"unit": unit}, ensure_ascii=False) + # 补充子物料信息 + details = material_data.get("details") or [] + if not isinstance(details, list): + logger.warning("details 字段不是列表,已忽略。") + details = [] + else: + for idx, detail in enumerate(details, start=1): + if not isinstance(detail, dict): + continue + if not detail.get("code"): + detail["code"] = f"{material_data['code']}_{idx:02d}" + if not detail.get("name"): + detail["name"] = f"{material_name}_detail_{idx:02d}" + if not detail.get("unit"): + detail["unit"] = unit + if not detail.get("parameters"): + detail["parameters"] = json.dumps({"unit": detail.get("unit", unit)}, ensure_ascii=False) + if "quantity" in detail: + detail["quantity"] = _to_number(detail.get("quantity"), 1.0) + material_data["details"] = details + create_result = self._post_lims("/api/lims/storage/material", material_data) + # 解析创建结果中的物料 ID + material_id: Optional[str] = None + if isinstance(create_result, dict): + data_field = create_result.get("data") + if isinstance(data_field, str): + material_id = data_field + elif isinstance(data_field, dict): + material_id = data_field.get("id") or data_field.get("materialId") + inbound_result: Optional[Dict[str, Any]] = None + location_id: Optional[str] = None + # 按用户指定位置入库 + if warehouse_name and material_id and location_name_or_id: + try: + location_ids, position_names = self._load_warehouse_locations(warehouse_name) + position_to_id = {name: loc_id for name, loc_id in zip(position_names, location_ids)} + target_location_id = position_to_id.get(location_name_or_id, location_name_or_id) + if target_location_id: + location_id = target_location_id + inbound_result = self.storage_inbound(material_id, target_location_id) + else: + inbound_result = {"error": f"未找到匹配的库位: {location_name_or_id}"} + except Exception as exc: + logger.error(f"获取仓库 {warehouse_name} 位置失败: {exc}") + inbound_result = {"error": str(exc)} + return { + "success": bool(isinstance(create_result, dict) and create_result.get("code") == 1 and material_id), + "material_name": material_name, + "material_id": material_id, + "warehouse": warehouse_name, + "location_id": location_id, + "location_name_or_id": location_name_or_id, + "create_result": create_result, + "inbound_result": inbound_result, + } + def resource_tree_transfer(self, old_parent: ResourcePLR, plr_resource: ResourcePLR, parent_resource: ResourcePLR): + # ROS2DeviceNode.run_async_func(self._ros_node.resource_tree_transfer, True, **{ + # "old_parent": old_parent, + # "plr_resource": plr_resource, + # "parent_resource": parent_resource, + # }) + print("resource_tree_transfer", plr_resource, parent_resource) + if hasattr(plr_resource, "unilabos_extra") and plr_resource.unilabos_extra: + if "update_resource_site" in plr_resource.unilabos_extra: + site = plr_resource.unilabos_extra["update_resource_site"] + plr_model = plr_resource.model + board_type = None + for key, (moudle_name,moudle_uuid) in MATERIAL_TYPE_MAPPINGS.items(): + if plr_model == moudle_name: + board_type = key + break + if board_type is None: + pass + bottle1 = plr_resource.children[0] + + bottle_moudle = bottle1.model + bottle_type = None + for key, (moudle_name, moudle_uuid) in MATERIAL_TYPE_MAPPINGS.items(): + if bottle_moudle == moudle_name: + bottle_type = key + break + + # 从 parent_resource 获取仓库名称 + warehouse_name = parent_resource.name if parent_resource else "手动堆栈" + logger.info(f"拖拽上料: {plr_resource.name} -> {warehouse_name} / {site}") + + self.create_sample(plr_resource.name, board_type, bottle_type, site, warehouse_name) + return + self.lab_logger().warning(f"无库位的上料,不处理,{plr_resource} 挂载到 {parent_resource}") + + def create_sample( + self, + name: str, + board_type: str, + bottle_type: str, + location_code: str, + warehouse_name: str = "手动堆栈" + ) -> Dict[str, Any]: + """创建配液板物料并自动入库。 + Args: + name: 物料名称 + board_type: 板类型,如 "5ml分液瓶板"、"配液瓶(小)板" + bottle_type: 瓶类型,如 "5ml分液瓶"、"配液瓶(小)" + location_code: 库位编号,例如 "A01" + warehouse_name: 仓库名称,默认为 "手动堆栈",支持 "自动堆栈-左"、"自动堆栈-右" 等 + """ + carrier_type_id = MATERIAL_TYPE_MAPPINGS[board_type][1] + bottle_type_id = MATERIAL_TYPE_MAPPINGS[bottle_type][1] + + # 从指定仓库获取库位UUID + if warehouse_name not in WAREHOUSE_MAPPING: + logger.error(f"未找到仓库: {warehouse_name},回退到手动堆栈") + warehouse_name = "手动堆栈" + + if location_code not in WAREHOUSE_MAPPING[warehouse_name]["site_uuids"]: + logger.error(f"仓库 {warehouse_name} 中未找到库位 {location_code}") + raise ValueError(f"库位 {location_code} 在仓库 {warehouse_name} 中不存在") + + location_id = WAREHOUSE_MAPPING[warehouse_name]["site_uuids"][location_code] + logger.info(f"创建样品入库: {name} -> {warehouse_name}/{location_code} (UUID: {location_id})") + + # 新建小瓶 + details = [] + for y in range(1, 5): + for x in range(1, 3): + details.append({ + "typeId": bottle_type_id, + "code": "", + "name": str(bottle_type) + str(x) + str(y), + "quantity": "1", + "x": x, + "y": y, + "z": 1, + "unit": "个", + "parameters": json.dumps({"unit": "个"}, ensure_ascii=False), + }) + + data = { + "typeId": carrier_type_id, + "code": "", + "barCode": "", + "name": name, + "unit": "块", + "parameters": json.dumps({"unit": "块"}, ensure_ascii=False), + "quantity": "1", + "details": details, + } + # print("xxx:",data) + create_result = self._post_lims("/api/lims/storage/material", data) + sample_uuid = create_result.get("data") + + final_result = self._post_lims("/api/lims/storage/inbound", { + "materialId": sample_uuid, + "locationId": location_id, + }) + return final_result + + + + +if __name__ == "__main__": + lab_registry.setup() + deck = BIOYOND_YB_Deck(setup=True) + ws = BioyondCellWorkstation(deck=deck) + # ws.create_sample(name="test", board_type="配液瓶(小)板", bottle_type="配液瓶(小)", location_code="B01") + # logger.info(ws.scheduler_stop()) + # logger.info(ws.scheduler_start()) + + # 继续后续流程 + logger.info(ws.auto_feeding4to3()) #搬运物料到3号箱 + # # # 使用正斜杠或 Path 对象来指定文件路径 + # excel_path = Path("unilabos\\devices\\workstation\\bioyond_studio\\bioyond_cell\\2025092701.xlsx") + # logger.info(ws.create_orders(excel_path)) + # logger.info(ws.transfer_3_to_2_to_1()) + + # logger.info(ws.transfer_1_to_2()) + # logger.info(ws.scheduler_start()) + + + while True: + time.sleep(1) + # re=ws.scheduler_stop() + # re = ws.transfer_3_to_2_to_1() + + # print(re) + # logger.info("调度启动完成") + + # ws.scheduler_continue() + # 3.30 上料:读取模板 Excel 自动解析并 POST + # r1 = ws.auto_feeding4to3_from_xlsx(r"C:\ML\GitHub\Uni-Lab-OS\unilabos\devices\workstation\bioyond_cell\样品导入模板.xlsx") + # ws.wait_for_transfer_task(filter_text="物料转移任务") + # logger.info("4号箱向3号箱转运物料转移任务已完成") + + # ws.scheduler_start() + # print(r1["payload"]["data"]) # 调试模式下可直接看到要发的 JSON items + + # # 新建实验 + # response = ws.create_orders("C:/ML/GitHub/Uni-Lab-OS/unilabos/devices/workstation/bioyond_cell/2025092701.xlsx") + # logger.info(response) + # data_list = response.get("data", []) + # order_name = data_list[0].get("orderName", "") + + # ws.wait_for_transfer_task(filter_text=order_name) + # ws.wait_for_transfer_task(filter_text='DP20250927001') + # logger.info("3号站内实验完成") + # # ws.scheduler_start() + # # print(res) + # ws.transfer_3_to_2_to_1() + # ws.wait_for_transfer_task(filter_text="物料转移任务") + # logger.info("3号站向2号站向1号站转移任务完成") + # r321 = self.wait_for_transfer_task() + #1号站启动 + # ws.transfer_1_to_2() + # ws.wait_for_transfer_task(filter_text="物料转移任务") + # logger.info("1号站向2号站转移任务完成") + # logger.info("全流程结束") + + # 3.31 下料:同理 + # r2 = ws.auto_batch_outbound_from_xlsx(r"C:/path/样品导入模板 (8).xlsx") + # print(r2["payload"]["data"]) diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py index 3e3bff6..5d10f40 100644 --- a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_cell_workstation.py @@ -257,7 +257,7 @@ class BioyondCellWorkstation(BioyondWorkstation): def auto_feeding4to3( self, # ★ 修改点:默认模板路径 - xlsx_path: Optional[str] = "/Users/sml/work/Unilab/Uni-Lab-OS/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, @@ -394,9 +394,13 @@ class BioyondCellWorkstation(BioyondWorkstation): return response # 等待完成报送 result = self.wait_for_order_finish(order_code) + print("\n" + "="*60) + print("实验记录本结果auto_feeding4to3") + print("="*60) + print(json.dumps(result, indent=2, ensure_ascii=False)) + print("="*60 + "\n") return result - def auto_batch_outbound_from_xlsx(self, xlsx_path: str) -> Dict[str, Any]: """ 3.31 自动化下料(Excel -> JSON -> POST /api/lims/storage/auto-batch-out-bound) @@ -474,7 +478,7 @@ class BioyondCellWorkstation(BioyondWorkstation): - totalMass 自动计算为所有物料质量之和 - createTime 缺失或为空时自动填充为当前日期(YYYY/M/D) """ - default_path = Path("/Users/sml/work/Unilab/Uni-Lab-OS/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: @@ -610,19 +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) - return result + + # 收集所有 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========================") + + # 返回所有订单的完成报文 + 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 final_result # 2.7 启动调度 def scheduler_start(self) -> Dict[str, Any]: @@ -650,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]: diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_yihua_YB.json b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_yihua_YB.json deleted file mode 100644 index 3119d0b..0000000 --- a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/bioyond_yihua_YB.json +++ /dev/null @@ -1,14487 +0,0 @@ -{ - "nodes": [ - { - "id": "bioyond_cell_workstation", - "name": "配液分液工站", - "children": [ - ], - "parent": null, - "type": "device", - "class": "bioyond_cell", - "config": { - "protocol_type": [], - "station_resource": {} - - }, - "data": {} - }, - { - "id": "BatteryStation", - "name": "扣电组装工作站", - "children": [ - "coin_cell_deck" - ], - "parent": null, - "type": "device", - "class": "bettery_station_registry", - "position": { - "x": 600, - "y": 400, - "z": 0 - }, - "config": { - "debug_mode": false, - "_comment": "protocol_type接外部工站固定写法字段,一般为空,deck写法也固定", - "protocol_type": [], - "deck": { - "data": { - "_resource_child_name": "coin_cell_deck", - "_resource_type": "unilabos.devices.workstation.coin_cell_assembly.button_battery_station:CoincellDeck" - } - }, - - "address": "192.168.1.20", - "port": 502 - }, - "data": {} - }, - { - "id": "coin_cell_deck", - "name": "coin_cell_deck", - "sample_id": null, - "children": [ - "zi_dan_jia", - "zi_dan_jia2", - "zi_dan_jia3", - "zi_dan_jia4", - "zi_dan_jia5", - "zi_dan_jia6", - "zi_dan_jia7", - "zi_dan_jia8", - "liaopan1", - "liaopan2", - "liaopan3", - "liaopan4", - "liaopan5", - "liaopan6", - "bottle_rack_3x4", - "bottle_rack_6x2", - "bottle_rack_6x2_2", - "tip_box_64", - "waste_tip_box" - ], - "parent": null, - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "CoincellDeck", - "size_x": 1620.0, - "size_y": 1270.0, - "size_z": 500.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "coin_cell_deck", - "barcode": null - }, - "data": {} - }, - { - "id": "zi_dan_jia", - "name": "zi_dan_jia", - "sample_id": null, - "children": [ - "zi_dan_jia_clipmagazinehole_0_0", - "zi_dan_jia_clipmagazinehole_0_1", - "zi_dan_jia_clipmagazinehole_1_0", - "zi_dan_jia_clipmagazinehole_1_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1400, - "y": 50, - "z": 0 - }, - "config": { - "type": "MagazineHolder_4", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_four", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia_clipmagazinehole_0_0", - "B1": "zi_dan_jia_clipmagazinehole_0_1", - "A2": "zi_dan_jia_clipmagazinehole_1_0", - "B2": "zi_dan_jia_clipmagazinehole_1_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia_clipmagazinehole_0_0", - "name": "zi_dan_jia_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia2_jipian_0" - ], - "parent": "zi_dan_jia", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia2_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia2_jipian_0", - "name": "zi_dan_jia2_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia_clipmagazinehole_0_1", - "name": "zi_dan_jia_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia2_jipian_1" - ], - "parent": "zi_dan_jia", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia2_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia2_jipian_1", - "name": "zi_dan_jia2_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia_clipmagazinehole_1_0", - "name": "zi_dan_jia_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia2_jipian_2" - ], - "parent": "zi_dan_jia", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia2_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia2_jipian_2", - "name": "zi_dan_jia2_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia_clipmagazinehole_1_1", - "name": "zi_dan_jia_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia2_jipian_3" - ], - "parent": "zi_dan_jia", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia2_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia2_jipian_3", - "name": "zi_dan_jia2_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia2", - "name": "zi_dan_jia2", - "sample_id": null, - "children": [ - "zi_dan_jia2_clipmagazinehole_0_0", - "zi_dan_jia2_clipmagazinehole_0_1", - "zi_dan_jia2_clipmagazinehole_1_0", - "zi_dan_jia2_clipmagazinehole_1_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1600, - "y": 200, - "z": 0 - }, - "config": { - "type": "MagazineHolder_4", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_four", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia2_clipmagazinehole_0_0", - "B1": "zi_dan_jia2_clipmagazinehole_0_1", - "A2": "zi_dan_jia2_clipmagazinehole_1_0", - "B2": "zi_dan_jia2_clipmagazinehole_1_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia2_clipmagazinehole_0_0", - "name": "zi_dan_jia2_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia_jipian_0" - ], - "parent": "zi_dan_jia2", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia2_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia_jipian_0", - "name": "zi_dan_jia_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia2_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia2_clipmagazinehole_0_1", - "name": "zi_dan_jia2_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia_jipian_1" - ], - "parent": "zi_dan_jia2", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia2_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia_jipian_1", - "name": "zi_dan_jia_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia2_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia2_clipmagazinehole_1_0", - "name": "zi_dan_jia2_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia_jipian_2" - ], - "parent": "zi_dan_jia2", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia2_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia_jipian_2", - "name": "zi_dan_jia_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia2_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia2_clipmagazinehole_1_1", - "name": "zi_dan_jia2_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia_jipian_3" - ], - "parent": "zi_dan_jia2", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia2_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia_jipian_3", - "name": "zi_dan_jia_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia2_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3", - "name": "zi_dan_jia3", - "sample_id": null, - "children": [ - "zi_dan_jia3_clipmagazinehole_0_0", - "zi_dan_jia3_clipmagazinehole_0_1", - "zi_dan_jia3_clipmagazinehole_1_0", - "zi_dan_jia3_clipmagazinehole_1_1", - "zi_dan_jia3_clipmagazinehole_2_0", - "zi_dan_jia3_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1500, - "y": 200, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia3_clipmagazinehole_0_0", - "B1": "zi_dan_jia3_clipmagazinehole_0_1", - "A2": "zi_dan_jia3_clipmagazinehole_1_0", - "B2": "zi_dan_jia3_clipmagazinehole_1_1", - "A3": "zi_dan_jia3_clipmagazinehole_2_0", - "B3": "zi_dan_jia3_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia3_clipmagazinehole_0_0", - "name": "zi_dan_jia3_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_0" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_0", - "name": "zi_dan_jia3_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3_clipmagazinehole_0_1", - "name": "zi_dan_jia3_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_1" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_1", - "name": "zi_dan_jia3_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3_clipmagazinehole_1_0", - "name": "zi_dan_jia3_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_2" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_2", - "name": "zi_dan_jia3_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3_clipmagazinehole_1_1", - "name": "zi_dan_jia3_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_3" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_3", - "name": "zi_dan_jia3_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3_clipmagazinehole_2_0", - "name": "zi_dan_jia3_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_4" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_4", - "name": "zi_dan_jia3_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia3_clipmagazinehole_2_1", - "name": "zi_dan_jia3_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia3_jipian_5" - ], - "parent": "zi_dan_jia3", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia3_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia3_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia3_jipian_5", - "name": "zi_dan_jia3_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia3_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4", - "name": "zi_dan_jia4", - "sample_id": null, - "children": [ - "zi_dan_jia4_clipmagazinehole_0_0", - "zi_dan_jia4_clipmagazinehole_0_1", - "zi_dan_jia4_clipmagazinehole_1_0", - "zi_dan_jia4_clipmagazinehole_1_1", - "zi_dan_jia4_clipmagazinehole_2_0", - "zi_dan_jia4_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1500, - "y": 300, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia4_clipmagazinehole_0_0", - "B1": "zi_dan_jia4_clipmagazinehole_0_1", - "A2": "zi_dan_jia4_clipmagazinehole_1_0", - "B2": "zi_dan_jia4_clipmagazinehole_1_1", - "A3": "zi_dan_jia4_clipmagazinehole_2_0", - "B3": "zi_dan_jia4_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia4_clipmagazinehole_0_0", - "name": "zi_dan_jia4_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_0" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_0", - "name": "zi_dan_jia4_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4_clipmagazinehole_0_1", - "name": "zi_dan_jia4_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_1" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_1", - "name": "zi_dan_jia4_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4_clipmagazinehole_1_0", - "name": "zi_dan_jia4_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_2" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_2", - "name": "zi_dan_jia4_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4_clipmagazinehole_1_1", - "name": "zi_dan_jia4_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_3" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_3", - "name": "zi_dan_jia4_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4_clipmagazinehole_2_0", - "name": "zi_dan_jia4_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_4" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_4", - "name": "zi_dan_jia4_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia4_clipmagazinehole_2_1", - "name": "zi_dan_jia4_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia4_jipian_5" - ], - "parent": "zi_dan_jia4", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia4_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia4_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia4_jipian_5", - "name": "zi_dan_jia4_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia4_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5", - "name": "zi_dan_jia5", - "sample_id": null, - "children": [ - "zi_dan_jia5_clipmagazinehole_0_0", - "zi_dan_jia5_clipmagazinehole_0_1", - "zi_dan_jia5_clipmagazinehole_1_0", - "zi_dan_jia5_clipmagazinehole_1_1", - "zi_dan_jia5_clipmagazinehole_2_0", - "zi_dan_jia5_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1600, - "y": 300, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia5_clipmagazinehole_0_0", - "B1": "zi_dan_jia5_clipmagazinehole_0_1", - "A2": "zi_dan_jia5_clipmagazinehole_1_0", - "B2": "zi_dan_jia5_clipmagazinehole_1_1", - "A3": "zi_dan_jia5_clipmagazinehole_2_0", - "B3": "zi_dan_jia5_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia5_clipmagazinehole_0_0", - "name": "zi_dan_jia5_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_0" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_0", - "name": "zi_dan_jia5_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5_clipmagazinehole_0_1", - "name": "zi_dan_jia5_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_1" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_1", - "name": "zi_dan_jia5_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5_clipmagazinehole_1_0", - "name": "zi_dan_jia5_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_2" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_2", - "name": "zi_dan_jia5_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5_clipmagazinehole_1_1", - "name": "zi_dan_jia5_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_3" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_3", - "name": "zi_dan_jia5_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5_clipmagazinehole_2_0", - "name": "zi_dan_jia5_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_4" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_4", - "name": "zi_dan_jia5_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia5_clipmagazinehole_2_1", - "name": "zi_dan_jia5_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia5_jipian_5" - ], - "parent": "zi_dan_jia5", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia5_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia5_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia5_jipian_5", - "name": "zi_dan_jia5_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia5_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6", - "name": "zi_dan_jia6", - "sample_id": null, - "children": [ - "zi_dan_jia6_clipmagazinehole_0_0", - "zi_dan_jia6_clipmagazinehole_0_1", - "zi_dan_jia6_clipmagazinehole_1_0", - "zi_dan_jia6_clipmagazinehole_1_1", - "zi_dan_jia6_clipmagazinehole_2_0", - "zi_dan_jia6_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1530, - "y": 500, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia6_clipmagazinehole_0_0", - "B1": "zi_dan_jia6_clipmagazinehole_0_1", - "A2": "zi_dan_jia6_clipmagazinehole_1_0", - "B2": "zi_dan_jia6_clipmagazinehole_1_1", - "A3": "zi_dan_jia6_clipmagazinehole_2_0", - "B3": "zi_dan_jia6_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia6_clipmagazinehole_0_0", - "name": "zi_dan_jia6_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_0" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_0", - "name": "zi_dan_jia6_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6_clipmagazinehole_0_1", - "name": "zi_dan_jia6_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_1" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_1", - "name": "zi_dan_jia6_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6_clipmagazinehole_1_0", - "name": "zi_dan_jia6_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_2" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_2", - "name": "zi_dan_jia6_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6_clipmagazinehole_1_1", - "name": "zi_dan_jia6_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_3" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_3", - "name": "zi_dan_jia6_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6_clipmagazinehole_2_0", - "name": "zi_dan_jia6_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_4" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_4", - "name": "zi_dan_jia6_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia6_clipmagazinehole_2_1", - "name": "zi_dan_jia6_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia6_jipian_5" - ], - "parent": "zi_dan_jia6", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia6_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia6_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia6_jipian_5", - "name": "zi_dan_jia6_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia6_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7", - "name": "zi_dan_jia7", - "sample_id": null, - "children": [ - "zi_dan_jia7_clipmagazinehole_0_0", - "zi_dan_jia7_clipmagazinehole_0_1", - "zi_dan_jia7_clipmagazinehole_1_0", - "zi_dan_jia7_clipmagazinehole_1_1", - "zi_dan_jia7_clipmagazinehole_2_0", - "zi_dan_jia7_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1180, - "y": 400, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia7_clipmagazinehole_0_0", - "B1": "zi_dan_jia7_clipmagazinehole_0_1", - "A2": "zi_dan_jia7_clipmagazinehole_1_0", - "B2": "zi_dan_jia7_clipmagazinehole_1_1", - "A3": "zi_dan_jia7_clipmagazinehole_2_0", - "B3": "zi_dan_jia7_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia7_clipmagazinehole_0_0", - "name": "zi_dan_jia7_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_0" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_0", - "name": "zi_dan_jia7_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7_clipmagazinehole_0_1", - "name": "zi_dan_jia7_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_1" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_1", - "name": "zi_dan_jia7_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7_clipmagazinehole_1_0", - "name": "zi_dan_jia7_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_2" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_2", - "name": "zi_dan_jia7_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7_clipmagazinehole_1_1", - "name": "zi_dan_jia7_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_3" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_3", - "name": "zi_dan_jia7_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7_clipmagazinehole_2_0", - "name": "zi_dan_jia7_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_4" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_4", - "name": "zi_dan_jia7_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia7_clipmagazinehole_2_1", - "name": "zi_dan_jia7_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia7_jipian_5" - ], - "parent": "zi_dan_jia7", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia7_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia7_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia7_jipian_5", - "name": "zi_dan_jia7_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia7_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8", - "name": "zi_dan_jia8", - "sample_id": null, - "children": [ - "zi_dan_jia8_clipmagazinehole_0_0", - "zi_dan_jia8_clipmagazinehole_0_1", - "zi_dan_jia8_clipmagazinehole_1_0", - "zi_dan_jia8_clipmagazinehole_1_1", - "zi_dan_jia8_clipmagazinehole_2_0", - "zi_dan_jia8_clipmagazinehole_2_1" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1280, - "y": 400, - "z": 0 - }, - "config": { - "type": "MagazineHolder_6", - "size_x": 80, - "size_y": 80, - "size_z": 10, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine", - "model": null, - "barcode": null, - "ordering": { - "A1": "zi_dan_jia8_clipmagazinehole_0_0", - "B1": "zi_dan_jia8_clipmagazinehole_0_1", - "A2": "zi_dan_jia8_clipmagazinehole_1_0", - "B2": "zi_dan_jia8_clipmagazinehole_1_1", - "A3": "zi_dan_jia8_clipmagazinehole_2_0", - "B3": "zi_dan_jia8_clipmagazinehole_2_1" - }, - "hole_diameter": 14.0, - "hole_depth": 10.0, - "max_sheets_per_hole": 100 - }, - "data": {} - }, - { - "id": "zi_dan_jia8_clipmagazinehole_0_0", - "name": "zi_dan_jia8_clipmagazinehole_0_0", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_0" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_0", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_0_0" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_0", - "name": "zi_dan_jia8_jipian_0", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8_clipmagazinehole_0_1", - "name": "zi_dan_jia8_clipmagazinehole_0_1", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_1" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 15.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_1", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_0_1" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_1", - "name": "zi_dan_jia8_jipian_1", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8_clipmagazinehole_1_0", - "name": "zi_dan_jia8_clipmagazinehole_1_0", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_2" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_2", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_1_0" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_2", - "name": "zi_dan_jia8_jipian_2", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8_clipmagazinehole_1_1", - "name": "zi_dan_jia8_clipmagazinehole_1_1", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_3" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 40.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_3", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_1_1" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_3", - "name": "zi_dan_jia8_jipian_3", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8_clipmagazinehole_2_0", - "name": "zi_dan_jia8_clipmagazinehole_2_0", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_4" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 52.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_4", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_2_0" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_4", - "name": "zi_dan_jia8_jipian_4", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "zi_dan_jia8_clipmagazinehole_2_1", - "name": "zi_dan_jia8_clipmagazinehole_2_1", - "sample_id": null, - "children": [ - "zi_dan_jia8_jipian_5" - ], - "parent": "zi_dan_jia8", - "type": "container", - "class": "", - "position": { - "x": 65.0, - "y": 27.5, - "z": 10 - }, - "config": { - "type": "Magazine", - "size_x": 14.0, - "size_y": 14.0, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "clip_magazine_hole", - "model": null, - "barcode": null, - "max_volume": 1960.0, - "material_z_thickness": null, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "sheet_count": 1, - "sheets": [ - { - "name": "zi_dan_jia8_jipian_5", - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "location": null, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null, - "children": [], - "parent_name": "zi_dan_jia8_clipmagazinehole_2_1" - } - ] - } - }, - { - "id": "zi_dan_jia8_jipian_5", - "name": "zi_dan_jia8_jipian_5", - "sample_id": null, - "children": [], - "parent": "zi_dan_jia8_clipmagazinehole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1", - "name": "liaopan1", - "sample_id": null, - "children": [ - "liaopan1_materialhole_0_0", - "liaopan1_materialhole_0_1", - "liaopan1_materialhole_0_2", - "liaopan1_materialhole_0_3", - "liaopan1_materialhole_1_0", - "liaopan1_materialhole_1_1", - "liaopan1_materialhole_1_2", - "liaopan1_materialhole_1_3", - "liaopan1_materialhole_2_0", - "liaopan1_materialhole_2_1", - "liaopan1_materialhole_2_2", - "liaopan1_materialhole_2_3", - "liaopan1_materialhole_3_0", - "liaopan1_materialhole_3_1", - "liaopan1_materialhole_3_2", - "liaopan1_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1010, - "y": 50, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan1_materialhole_0_0", - "B1": "liaopan1_materialhole_0_1", - "C1": "liaopan1_materialhole_0_2", - "D1": "liaopan1_materialhole_0_3", - "A2": "liaopan1_materialhole_1_0", - "B2": "liaopan1_materialhole_1_1", - "C2": "liaopan1_materialhole_1_2", - "D2": "liaopan1_materialhole_1_3", - "A3": "liaopan1_materialhole_2_0", - "B3": "liaopan1_materialhole_2_1", - "C3": "liaopan1_materialhole_2_2", - "D3": "liaopan1_materialhole_2_3", - "A4": "liaopan1_materialhole_3_0", - "B4": "liaopan1_materialhole_3_1", - "C4": "liaopan1_materialhole_3_2", - "D4": "liaopan1_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan1_materialhole_0_0", - "name": "liaopan1_materialhole_0_0", - "sample_id": null, - "children": [ - "liaopan1_jipian_0" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_0", - "name": "liaopan1_jipian_0", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_0_1", - "name": "liaopan1_materialhole_0_1", - "sample_id": null, - "children": [ - "liaopan1_jipian_1" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_1", - "name": "liaopan1_jipian_1", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_0_2", - "name": "liaopan1_materialhole_0_2", - "sample_id": null, - "children": [ - "liaopan1_jipian_2" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_2", - "name": "liaopan1_jipian_2", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_0_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_0_3", - "name": "liaopan1_materialhole_0_3", - "sample_id": null, - "children": [ - "liaopan1_jipian_3" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_3", - "name": "liaopan1_jipian_3", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_0_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_1_0", - "name": "liaopan1_materialhole_1_0", - "sample_id": null, - "children": [ - "liaopan1_jipian_4" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_4", - "name": "liaopan1_jipian_4", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_1_1", - "name": "liaopan1_materialhole_1_1", - "sample_id": null, - "children": [ - "liaopan1_jipian_5" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_5", - "name": "liaopan1_jipian_5", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_1_2", - "name": "liaopan1_materialhole_1_2", - "sample_id": null, - "children": [ - "liaopan1_jipian_6" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_6", - "name": "liaopan1_jipian_6", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_1_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_1_3", - "name": "liaopan1_materialhole_1_3", - "sample_id": null, - "children": [ - "liaopan1_jipian_7" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_7", - "name": "liaopan1_jipian_7", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_1_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_2_0", - "name": "liaopan1_materialhole_2_0", - "sample_id": null, - "children": [ - "liaopan1_jipian_8" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_8", - "name": "liaopan1_jipian_8", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_2_1", - "name": "liaopan1_materialhole_2_1", - "sample_id": null, - "children": [ - "liaopan1_jipian_9" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_9", - "name": "liaopan1_jipian_9", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_2_2", - "name": "liaopan1_materialhole_2_2", - "sample_id": null, - "children": [ - "liaopan1_jipian_10" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_10", - "name": "liaopan1_jipian_10", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_2_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_2_3", - "name": "liaopan1_materialhole_2_3", - "sample_id": null, - "children": [ - "liaopan1_jipian_11" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_11", - "name": "liaopan1_jipian_11", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_2_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_3_0", - "name": "liaopan1_materialhole_3_0", - "sample_id": null, - "children": [ - "liaopan1_jipian_12" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_12", - "name": "liaopan1_jipian_12", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_3_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_3_1", - "name": "liaopan1_materialhole_3_1", - "sample_id": null, - "children": [ - "liaopan1_jipian_13" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_13", - "name": "liaopan1_jipian_13", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_3_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_3_2", - "name": "liaopan1_materialhole_3_2", - "sample_id": null, - "children": [ - "liaopan1_jipian_14" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_14", - "name": "liaopan1_jipian_14", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_3_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan1_materialhole_3_3", - "name": "liaopan1_materialhole_3_3", - "sample_id": null, - "children": [ - "liaopan1_jipian_15" - ], - "parent": "liaopan1", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan1_jipian_15", - "name": "liaopan1_jipian_15", - "sample_id": null, - "children": [], - "parent": "liaopan1_materialhole_3_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan2", - "name": "liaopan2", - "sample_id": null, - "children": [ - "liaopan2_materialhole_0_0", - "liaopan2_materialhole_0_1", - "liaopan2_materialhole_0_2", - "liaopan2_materialhole_0_3", - "liaopan2_materialhole_1_0", - "liaopan2_materialhole_1_1", - "liaopan2_materialhole_1_2", - "liaopan2_materialhole_1_3", - "liaopan2_materialhole_2_0", - "liaopan2_materialhole_2_1", - "liaopan2_materialhole_2_2", - "liaopan2_materialhole_2_3", - "liaopan2_materialhole_3_0", - "liaopan2_materialhole_3_1", - "liaopan2_materialhole_3_2", - "liaopan2_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1130, - "y": 50, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan2_materialhole_0_0", - "B1": "liaopan2_materialhole_0_1", - "C1": "liaopan2_materialhole_0_2", - "D1": "liaopan2_materialhole_0_3", - "A2": "liaopan2_materialhole_1_0", - "B2": "liaopan2_materialhole_1_1", - "C2": "liaopan2_materialhole_1_2", - "D2": "liaopan2_materialhole_1_3", - "A3": "liaopan2_materialhole_2_0", - "B3": "liaopan2_materialhole_2_1", - "C3": "liaopan2_materialhole_2_2", - "D3": "liaopan2_materialhole_2_3", - "A4": "liaopan2_materialhole_3_0", - "B4": "liaopan2_materialhole_3_1", - "C4": "liaopan2_materialhole_3_2", - "D4": "liaopan2_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan2_materialhole_0_0", - "name": "liaopan2_materialhole_0_0", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_0_1", - "name": "liaopan2_materialhole_0_1", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_0_2", - "name": "liaopan2_materialhole_0_2", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_0_3", - "name": "liaopan2_materialhole_0_3", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_1_0", - "name": "liaopan2_materialhole_1_0", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_1_1", - "name": "liaopan2_materialhole_1_1", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_1_2", - "name": "liaopan2_materialhole_1_2", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_1_3", - "name": "liaopan2_materialhole_1_3", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_2_0", - "name": "liaopan2_materialhole_2_0", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_2_1", - "name": "liaopan2_materialhole_2_1", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_2_2", - "name": "liaopan2_materialhole_2_2", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_2_3", - "name": "liaopan2_materialhole_2_3", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_3_0", - "name": "liaopan2_materialhole_3_0", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_3_1", - "name": "liaopan2_materialhole_3_1", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_3_2", - "name": "liaopan2_materialhole_3_2", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan2_materialhole_3_3", - "name": "liaopan2_materialhole_3_3", - "sample_id": null, - "children": [], - "parent": "liaopan2", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3", - "name": "liaopan3", - "sample_id": null, - "children": [ - "liaopan3_materialhole_0_0", - "liaopan3_materialhole_0_1", - "liaopan3_materialhole_0_2", - "liaopan3_materialhole_0_3", - "liaopan3_materialhole_1_0", - "liaopan3_materialhole_1_1", - "liaopan3_materialhole_1_2", - "liaopan3_materialhole_1_3", - "liaopan3_materialhole_2_0", - "liaopan3_materialhole_2_1", - "liaopan3_materialhole_2_2", - "liaopan3_materialhole_2_3", - "liaopan3_materialhole_3_0", - "liaopan3_materialhole_3_1", - "liaopan3_materialhole_3_2", - "liaopan3_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1250, - "y": 50, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan3_materialhole_0_0", - "B1": "liaopan3_materialhole_0_1", - "C1": "liaopan3_materialhole_0_2", - "D1": "liaopan3_materialhole_0_3", - "A2": "liaopan3_materialhole_1_0", - "B2": "liaopan3_materialhole_1_1", - "C2": "liaopan3_materialhole_1_2", - "D2": "liaopan3_materialhole_1_3", - "A3": "liaopan3_materialhole_2_0", - "B3": "liaopan3_materialhole_2_1", - "C3": "liaopan3_materialhole_2_2", - "D3": "liaopan3_materialhole_2_3", - "A4": "liaopan3_materialhole_3_0", - "B4": "liaopan3_materialhole_3_1", - "C4": "liaopan3_materialhole_3_2", - "D4": "liaopan3_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan3_materialhole_0_0", - "name": "liaopan3_materialhole_0_0", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_0_1", - "name": "liaopan3_materialhole_0_1", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_0_2", - "name": "liaopan3_materialhole_0_2", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_0_3", - "name": "liaopan3_materialhole_0_3", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_1_0", - "name": "liaopan3_materialhole_1_0", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_1_1", - "name": "liaopan3_materialhole_1_1", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_1_2", - "name": "liaopan3_materialhole_1_2", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_1_3", - "name": "liaopan3_materialhole_1_3", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_2_0", - "name": "liaopan3_materialhole_2_0", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_2_1", - "name": "liaopan3_materialhole_2_1", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_2_2", - "name": "liaopan3_materialhole_2_2", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_2_3", - "name": "liaopan3_materialhole_2_3", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_3_0", - "name": "liaopan3_materialhole_3_0", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_3_1", - "name": "liaopan3_materialhole_3_1", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_3_2", - "name": "liaopan3_materialhole_3_2", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan3_materialhole_3_3", - "name": "liaopan3_materialhole_3_3", - "sample_id": null, - "children": [], - "parent": "liaopan3", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4", - "name": "liaopan4", - "sample_id": null, - "children": [ - "liaopan4_materialhole_0_0", - "liaopan4_materialhole_0_1", - "liaopan4_materialhole_0_2", - "liaopan4_materialhole_0_3", - "liaopan4_materialhole_1_0", - "liaopan4_materialhole_1_1", - "liaopan4_materialhole_1_2", - "liaopan4_materialhole_1_3", - "liaopan4_materialhole_2_0", - "liaopan4_materialhole_2_1", - "liaopan4_materialhole_2_2", - "liaopan4_materialhole_2_3", - "liaopan4_materialhole_3_0", - "liaopan4_materialhole_3_1", - "liaopan4_materialhole_3_2", - "liaopan4_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1010, - "y": 150, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan4_materialhole_0_0", - "B1": "liaopan4_materialhole_0_1", - "C1": "liaopan4_materialhole_0_2", - "D1": "liaopan4_materialhole_0_3", - "A2": "liaopan4_materialhole_1_0", - "B2": "liaopan4_materialhole_1_1", - "C2": "liaopan4_materialhole_1_2", - "D2": "liaopan4_materialhole_1_3", - "A3": "liaopan4_materialhole_2_0", - "B3": "liaopan4_materialhole_2_1", - "C3": "liaopan4_materialhole_2_2", - "D3": "liaopan4_materialhole_2_3", - "A4": "liaopan4_materialhole_3_0", - "B4": "liaopan4_materialhole_3_1", - "C4": "liaopan4_materialhole_3_2", - "D4": "liaopan4_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan4_materialhole_0_0", - "name": "liaopan4_materialhole_0_0", - "sample_id": null, - "children": [ - "liaopan4_jipian_0" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_0", - "name": "liaopan4_jipian_0", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_0_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_0_1", - "name": "liaopan4_materialhole_0_1", - "sample_id": null, - "children": [ - "liaopan4_jipian_1" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_1", - "name": "liaopan4_jipian_1", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_0_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_0_2", - "name": "liaopan4_materialhole_0_2", - "sample_id": null, - "children": [ - "liaopan4_jipian_2" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_2", - "name": "liaopan4_jipian_2", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_0_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_0_3", - "name": "liaopan4_materialhole_0_3", - "sample_id": null, - "children": [ - "liaopan4_jipian_3" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_3", - "name": "liaopan4_jipian_3", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_0_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_1_0", - "name": "liaopan4_materialhole_1_0", - "sample_id": null, - "children": [ - "liaopan4_jipian_4" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_4", - "name": "liaopan4_jipian_4", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_1_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_1_1", - "name": "liaopan4_materialhole_1_1", - "sample_id": null, - "children": [ - "liaopan4_jipian_5" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_5", - "name": "liaopan4_jipian_5", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_1_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_1_2", - "name": "liaopan4_materialhole_1_2", - "sample_id": null, - "children": [ - "liaopan4_jipian_6" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_6", - "name": "liaopan4_jipian_6", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_1_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_1_3", - "name": "liaopan4_materialhole_1_3", - "sample_id": null, - "children": [ - "liaopan4_jipian_7" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_7", - "name": "liaopan4_jipian_7", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_1_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_2_0", - "name": "liaopan4_materialhole_2_0", - "sample_id": null, - "children": [ - "liaopan4_jipian_8" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_8", - "name": "liaopan4_jipian_8", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_2_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_2_1", - "name": "liaopan4_materialhole_2_1", - "sample_id": null, - "children": [ - "liaopan4_jipian_9" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_9", - "name": "liaopan4_jipian_9", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_2_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_2_2", - "name": "liaopan4_materialhole_2_2", - "sample_id": null, - "children": [ - "liaopan4_jipian_10" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_10", - "name": "liaopan4_jipian_10", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_2_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_2_3", - "name": "liaopan4_materialhole_2_3", - "sample_id": null, - "children": [ - "liaopan4_jipian_11" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_11", - "name": "liaopan4_jipian_11", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_2_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_3_0", - "name": "liaopan4_materialhole_3_0", - "sample_id": null, - "children": [ - "liaopan4_jipian_12" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_12", - "name": "liaopan4_jipian_12", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_3_0", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_3_1", - "name": "liaopan4_materialhole_3_1", - "sample_id": null, - "children": [ - "liaopan4_jipian_13" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_13", - "name": "liaopan4_jipian_13", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_3_1", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_3_2", - "name": "liaopan4_materialhole_3_2", - "sample_id": null, - "children": [ - "liaopan4_jipian_14" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_14", - "name": "liaopan4_jipian_14", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_3_2", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan4_materialhole_3_3", - "name": "liaopan4_materialhole_3_3", - "sample_id": null, - "children": [ - "liaopan4_jipian_15" - ], - "parent": "liaopan4", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan4_jipian_15", - "name": "liaopan4_jipian_15", - "sample_id": null, - "children": [], - "parent": "liaopan4_materialhole_3_3", - "type": "container", - "class": "", - "position": { - "x": 0, - "y": 0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "liaopan5", - "name": "liaopan5", - "sample_id": null, - "children": [ - "liaopan5_materialhole_0_0", - "liaopan5_materialhole_0_1", - "liaopan5_materialhole_0_2", - "liaopan5_materialhole_0_3", - "liaopan5_materialhole_1_0", - "liaopan5_materialhole_1_1", - "liaopan5_materialhole_1_2", - "liaopan5_materialhole_1_3", - "liaopan5_materialhole_2_0", - "liaopan5_materialhole_2_1", - "liaopan5_materialhole_2_2", - "liaopan5_materialhole_2_3", - "liaopan5_materialhole_3_0", - "liaopan5_materialhole_3_1", - "liaopan5_materialhole_3_2", - "liaopan5_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1130, - "y": 150, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan5_materialhole_0_0", - "B1": "liaopan5_materialhole_0_1", - "C1": "liaopan5_materialhole_0_2", - "D1": "liaopan5_materialhole_0_3", - "A2": "liaopan5_materialhole_1_0", - "B2": "liaopan5_materialhole_1_1", - "C2": "liaopan5_materialhole_1_2", - "D2": "liaopan5_materialhole_1_3", - "A3": "liaopan5_materialhole_2_0", - "B3": "liaopan5_materialhole_2_1", - "C3": "liaopan5_materialhole_2_2", - "D3": "liaopan5_materialhole_2_3", - "A4": "liaopan5_materialhole_3_0", - "B4": "liaopan5_materialhole_3_1", - "C4": "liaopan5_materialhole_3_2", - "D4": "liaopan5_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan5_materialhole_0_0", - "name": "liaopan5_materialhole_0_0", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_0_1", - "name": "liaopan5_materialhole_0_1", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_0_2", - "name": "liaopan5_materialhole_0_2", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_0_3", - "name": "liaopan5_materialhole_0_3", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_1_0", - "name": "liaopan5_materialhole_1_0", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_1_1", - "name": "liaopan5_materialhole_1_1", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_1_2", - "name": "liaopan5_materialhole_1_2", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_1_3", - "name": "liaopan5_materialhole_1_3", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_2_0", - "name": "liaopan5_materialhole_2_0", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_2_1", - "name": "liaopan5_materialhole_2_1", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_2_2", - "name": "liaopan5_materialhole_2_2", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_2_3", - "name": "liaopan5_materialhole_2_3", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_3_0", - "name": "liaopan5_materialhole_3_0", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_3_1", - "name": "liaopan5_materialhole_3_1", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_3_2", - "name": "liaopan5_materialhole_3_2", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan5_materialhole_3_3", - "name": "liaopan5_materialhole_3_3", - "sample_id": null, - "children": [], - "parent": "liaopan5", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6", - "name": "liaopan6", - "sample_id": null, - "children": [ - "liaopan6_materialhole_0_0", - "liaopan6_materialhole_0_1", - "liaopan6_materialhole_0_2", - "liaopan6_materialhole_0_3", - "liaopan6_materialhole_1_0", - "liaopan6_materialhole_1_1", - "liaopan6_materialhole_1_2", - "liaopan6_materialhole_1_3", - "liaopan6_materialhole_2_0", - "liaopan6_materialhole_2_1", - "liaopan6_materialhole_2_2", - "liaopan6_materialhole_2_3", - "liaopan6_materialhole_3_0", - "liaopan6_materialhole_3_1", - "liaopan6_materialhole_3_2", - "liaopan6_materialhole_3_3" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 1250, - "y": 150, - "z": 0 - }, - "config": { - "type": "MaterialPlate", - "size_x": 120, - "size_y": 100, - "size_z": 10.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_plate", - "model": null, - "barcode": null, - "ordering": { - "A1": "liaopan6_materialhole_0_0", - "B1": "liaopan6_materialhole_0_1", - "C1": "liaopan6_materialhole_0_2", - "D1": "liaopan6_materialhole_0_3", - "A2": "liaopan6_materialhole_1_0", - "B2": "liaopan6_materialhole_1_1", - "C2": "liaopan6_materialhole_1_2", - "D2": "liaopan6_materialhole_1_3", - "A3": "liaopan6_materialhole_2_0", - "B3": "liaopan6_materialhole_2_1", - "C3": "liaopan6_materialhole_2_2", - "D3": "liaopan6_materialhole_2_3", - "A4": "liaopan6_materialhole_3_0", - "B4": "liaopan6_materialhole_3_1", - "C4": "liaopan6_materialhole_3_2", - "D4": "liaopan6_materialhole_3_3" - } - }, - "data": {} - }, - { - "id": "liaopan6_materialhole_0_0", - "name": "liaopan6_materialhole_0_0", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_0_1", - "name": "liaopan6_materialhole_0_1", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_0_2", - "name": "liaopan6_materialhole_0_2", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_0_3", - "name": "liaopan6_materialhole_0_3", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 12.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_1_0", - "name": "liaopan6_materialhole_1_0", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_1_1", - "name": "liaopan6_materialhole_1_1", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_1_2", - "name": "liaopan6_materialhole_1_2", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_1_3", - "name": "liaopan6_materialhole_1_3", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 36.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_2_0", - "name": "liaopan6_materialhole_2_0", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_2_1", - "name": "liaopan6_materialhole_2_1", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_2_2", - "name": "liaopan6_materialhole_2_2", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_2_3", - "name": "liaopan6_materialhole_2_3", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 60.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_3_0", - "name": "liaopan6_materialhole_3_0", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 74.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_3_1", - "name": "liaopan6_materialhole_3_1", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 50.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_3_2", - "name": "liaopan6_materialhole_3_2", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 26.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "liaopan6_materialhole_3_3", - "name": "liaopan6_materialhole_3_3", - "sample_id": null, - "children": [], - "parent": "liaopan6", - "type": "container", - "class": "", - "position": { - "x": 84.0, - "y": 2.0, - "z": 10.0 - }, - "config": { - "type": "MaterialHole", - "size_x": 16, - "size_y": 16, - "size_z": 16, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "material_hole", - "model": null, - "barcode": null - }, - "data": { - "diameter": 20, - "depth": 10, - "max_sheets": 1, - "info": null - } - }, - { - "id": "bottle_rack_3x4", - "name": "bottle_rack_3x4", - "sample_id": null, - "children": [ - "sheet_3x4_0", - "sheet_3x4_1", - "sheet_3x4_2", - "sheet_3x4_3", - "sheet_3x4_4", - "sheet_3x4_5", - "sheet_3x4_6", - "sheet_3x4_7", - "sheet_3x4_8", - "sheet_3x4_9", - "sheet_3x4_10", - "sheet_3x4_11" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 100, - "y": 200, - "z": 0 - }, - "config": { - "type": "BottleRack", - "size_x": 210.0, - "size_y": 140.0, - "size_z": 100.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "bottle_rack", - "model": null, - "barcode": null, - "num_items_x": 3, - "num_items_y": 4, - "position_spacing": 35.0, - "orientation": "vertical", - "padding_x": 20.0, - "padding_y": 20.0 - }, - "data": { - "bottle_diameter": 30.0, - "bottle_height": 100.0, - "position_spacing": 35.0, - "name_to_index": {} - } - }, - { - "id": "sheet_3x4_0", - "name": "sheet_3x4_0", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_1", - "name": "sheet_3x4_1", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_2", - "name": "sheet_3x4_2", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_3", - "name": "sheet_3x4_3", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_4", - "name": "sheet_3x4_4", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_5", - "name": "sheet_3x4_5", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_6", - "name": "sheet_3x4_6", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 90.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_7", - "name": "sheet_3x4_7", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 90.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_8", - "name": "sheet_3x4_8", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 90.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_9", - "name": "sheet_3x4_9", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 125.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_10", - "name": "sheet_3x4_10", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 125.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_3x4_11", - "name": "sheet_3x4_11", - "sample_id": null, - "children": [], - "parent": "bottle_rack_3x4", - "type": "container", - "class": "", - "position": { - "x": 125.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "bottle_rack_6x2", - "name": "bottle_rack_6x2", - "sample_id": null, - "children": [ - "sheet_6x2_0", - "sheet_6x2_1", - "sheet_6x2_2", - "sheet_6x2_3", - "sheet_6x2_4", - "sheet_6x2_5", - "sheet_6x2_6", - "sheet_6x2_7", - "sheet_6x2_8", - "sheet_6x2_9", - "sheet_6x2_10", - "sheet_6x2_11" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 300, - "y": 300, - "z": 0 - }, - "config": { - "type": "BottleRack", - "size_x": 120.0, - "size_y": 250.0, - "size_z": 100.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "bottle_rack", - "model": null, - "barcode": null, - "num_items_x": 6, - "num_items_y": 2, - "position_spacing": 35.0, - "orientation": "vertical", - "padding_x": 20.0, - "padding_y": 20.0 - }, - "data": { - "bottle_diameter": 30.0, - "bottle_height": 100.0, - "position_spacing": 35.0, - "name_to_index": {} - } - }, - { - "id": "sheet_6x2_0", - "name": "sheet_6x2_0", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_1", - "name": "sheet_6x2_1", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_2", - "name": "sheet_6x2_2", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_3", - "name": "sheet_6x2_3", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 125.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_4", - "name": "sheet_6x2_4", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 160.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_5", - "name": "sheet_6x2_5", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 20.0, - "y": 195.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_6", - "name": "sheet_6x2_6", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 20.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_7", - "name": "sheet_6x2_7", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 55.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_8", - "name": "sheet_6x2_8", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 90.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_9", - "name": "sheet_6x2_9", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 125.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_10", - "name": "sheet_6x2_10", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 160.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "sheet_6x2_11", - "name": "sheet_6x2_11", - "sample_id": null, - "children": [], - "parent": "bottle_rack_6x2", - "type": "container", - "class": "", - "position": { - "x": 55.0, - "y": 195.0, - "z": 0 - }, - "config": { - "type": "ElectrodeSheet", - "size_x": 12, - "size_y": 12, - "size_z": 0.1, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "electrode_sheet", - "model": null, - "barcode": null - }, - "data": { - "diameter": 14, - "thickness": 0.1, - "mass": 0.5, - "material_type": "copper", - "info": null - } - }, - { - "id": "bottle_rack_6x2_2", - "name": "bottle_rack_6x2_2", - "sample_id": null, - "children": [], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 430, - "y": 300, - "z": 0 - }, - "config": { - "type": "BottleRack", - "size_x": 120.0, - "size_y": 250.0, - "size_z": 100.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "bottle_rack", - "model": null, - "barcode": null, - "num_items_x": 6, - "num_items_y": 2, - "position_spacing": 35.0, - "orientation": "vertical", - "padding_x": 20.0, - "padding_y": 20.0 - }, - "data": { - "bottle_diameter": 30.0, - "bottle_height": 100.0, - "position_spacing": 35.0, - "name_to_index": {} - } - }, - { - "id": "tip_box_64", - "name": "tip_box_64", - "sample_id": null, - "children": [ - "tip_box_64_tipspot_0_0", - "tip_box_64_tipspot_0_1", - "tip_box_64_tipspot_0_2", - "tip_box_64_tipspot_0_3", - "tip_box_64_tipspot_0_4", - "tip_box_64_tipspot_0_5", - "tip_box_64_tipspot_0_6", - "tip_box_64_tipspot_0_7", - "tip_box_64_tipspot_1_0", - "tip_box_64_tipspot_1_1", - "tip_box_64_tipspot_1_2", - "tip_box_64_tipspot_1_3", - "tip_box_64_tipspot_1_4", - "tip_box_64_tipspot_1_5", - "tip_box_64_tipspot_1_6", - "tip_box_64_tipspot_1_7", - "tip_box_64_tipspot_2_0", - "tip_box_64_tipspot_2_1", - "tip_box_64_tipspot_2_2", - "tip_box_64_tipspot_2_3", - "tip_box_64_tipspot_2_4", - "tip_box_64_tipspot_2_5", - "tip_box_64_tipspot_2_6", - "tip_box_64_tipspot_2_7", - "tip_box_64_tipspot_3_0", - "tip_box_64_tipspot_3_1", - "tip_box_64_tipspot_3_2", - "tip_box_64_tipspot_3_3", - "tip_box_64_tipspot_3_4", - "tip_box_64_tipspot_3_5", - "tip_box_64_tipspot_3_6", - "tip_box_64_tipspot_3_7", - "tip_box_64_tipspot_4_0", - "tip_box_64_tipspot_4_1", - "tip_box_64_tipspot_4_2", - "tip_box_64_tipspot_4_3", - "tip_box_64_tipspot_4_4", - "tip_box_64_tipspot_4_5", - "tip_box_64_tipspot_4_6", - "tip_box_64_tipspot_4_7", - "tip_box_64_tipspot_5_0", - "tip_box_64_tipspot_5_1", - "tip_box_64_tipspot_5_2", - "tip_box_64_tipspot_5_3", - "tip_box_64_tipspot_5_4", - "tip_box_64_tipspot_5_5", - "tip_box_64_tipspot_5_6", - "tip_box_64_tipspot_5_7", - "tip_box_64_tipspot_6_0", - "tip_box_64_tipspot_6_1", - "tip_box_64_tipspot_6_2", - "tip_box_64_tipspot_6_3", - "tip_box_64_tipspot_6_4", - "tip_box_64_tipspot_6_5", - "tip_box_64_tipspot_6_6", - "tip_box_64_tipspot_6_7", - "tip_box_64_tipspot_7_0", - "tip_box_64_tipspot_7_1", - "tip_box_64_tipspot_7_2", - "tip_box_64_tipspot_7_3", - "tip_box_64_tipspot_7_4", - "tip_box_64_tipspot_7_5", - "tip_box_64_tipspot_7_6", - "tip_box_64_tipspot_7_7" - ], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 300, - "y": 100, - "z": 0 - }, - "config": { - "type": "TipBox64", - "size_x": 127.8, - "size_y": 85.5, - "size_z": 60.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_box_64", - "model": null, - "barcode": null, - "ordering": { - "A1": "tip_box_64_tipspot_0_0", - "B1": "tip_box_64_tipspot_0_1", - "C1": "tip_box_64_tipspot_0_2", - "D1": "tip_box_64_tipspot_0_3", - "E1": "tip_box_64_tipspot_0_4", - "F1": "tip_box_64_tipspot_0_5", - "G1": "tip_box_64_tipspot_0_6", - "H1": "tip_box_64_tipspot_0_7", - "A2": "tip_box_64_tipspot_1_0", - "B2": "tip_box_64_tipspot_1_1", - "C2": "tip_box_64_tipspot_1_2", - "D2": "tip_box_64_tipspot_1_3", - "E2": "tip_box_64_tipspot_1_4", - "F2": "tip_box_64_tipspot_1_5", - "G2": "tip_box_64_tipspot_1_6", - "H2": "tip_box_64_tipspot_1_7", - "A3": "tip_box_64_tipspot_2_0", - "B3": "tip_box_64_tipspot_2_1", - "C3": "tip_box_64_tipspot_2_2", - "D3": "tip_box_64_tipspot_2_3", - "E3": "tip_box_64_tipspot_2_4", - "F3": "tip_box_64_tipspot_2_5", - "G3": "tip_box_64_tipspot_2_6", - "H3": "tip_box_64_tipspot_2_7", - "A4": "tip_box_64_tipspot_3_0", - "B4": "tip_box_64_tipspot_3_1", - "C4": "tip_box_64_tipspot_3_2", - "D4": "tip_box_64_tipspot_3_3", - "E4": "tip_box_64_tipspot_3_4", - "F4": "tip_box_64_tipspot_3_5", - "G4": "tip_box_64_tipspot_3_6", - "H4": "tip_box_64_tipspot_3_7", - "A5": "tip_box_64_tipspot_4_0", - "B5": "tip_box_64_tipspot_4_1", - "C5": "tip_box_64_tipspot_4_2", - "D5": "tip_box_64_tipspot_4_3", - "E5": "tip_box_64_tipspot_4_4", - "F5": "tip_box_64_tipspot_4_5", - "G5": "tip_box_64_tipspot_4_6", - "H5": "tip_box_64_tipspot_4_7", - "A6": "tip_box_64_tipspot_5_0", - "B6": "tip_box_64_tipspot_5_1", - "C6": "tip_box_64_tipspot_5_2", - "D6": "tip_box_64_tipspot_5_3", - "E6": "tip_box_64_tipspot_5_4", - "F6": "tip_box_64_tipspot_5_5", - "G6": "tip_box_64_tipspot_5_6", - "H6": "tip_box_64_tipspot_5_7", - "A7": "tip_box_64_tipspot_6_0", - "B7": "tip_box_64_tipspot_6_1", - "C7": "tip_box_64_tipspot_6_2", - "D7": "tip_box_64_tipspot_6_3", - "E7": "tip_box_64_tipspot_6_4", - "F7": "tip_box_64_tipspot_6_5", - "G7": "tip_box_64_tipspot_6_6", - "H7": "tip_box_64_tipspot_6_7", - "A8": "tip_box_64_tipspot_7_0", - "B8": "tip_box_64_tipspot_7_1", - "C8": "tip_box_64_tipspot_7_2", - "D8": "tip_box_64_tipspot_7_3", - "E8": "tip_box_64_tipspot_7_4", - "F8": "tip_box_64_tipspot_7_5", - "G8": "tip_box_64_tipspot_7_6", - "H8": "tip_box_64_tipspot_7_7" - }, - "num_items_x": 8, - "num_items_y": 8, - "dx": 8.0, - "dy": 8.0, - "item_dx": 9.0, - "item_dy": 9.0 - }, - "data": {} - }, - { - "id": "tip_box_64_tipspot_0_0", - "name": "tip_box_64_tipspot_0_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_1", - "name": "tip_box_64_tipspot_0_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_2", - "name": "tip_box_64_tipspot_0_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_3", - "name": "tip_box_64_tipspot_0_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_4", - "name": "tip_box_64_tipspot_0_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_5", - "name": "tip_box_64_tipspot_0_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_6", - "name": "tip_box_64_tipspot_0_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_0_7", - "name": "tip_box_64_tipspot_0_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 8.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_0", - "name": "tip_box_64_tipspot_1_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_1", - "name": "tip_box_64_tipspot_1_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_2", - "name": "tip_box_64_tipspot_1_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_3", - "name": "tip_box_64_tipspot_1_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_4", - "name": "tip_box_64_tipspot_1_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_5", - "name": "tip_box_64_tipspot_1_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_6", - "name": "tip_box_64_tipspot_1_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_1_7", - "name": "tip_box_64_tipspot_1_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 17.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_0", - "name": "tip_box_64_tipspot_2_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_1", - "name": "tip_box_64_tipspot_2_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_2", - "name": "tip_box_64_tipspot_2_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_3", - "name": "tip_box_64_tipspot_2_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_4", - "name": "tip_box_64_tipspot_2_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_5", - "name": "tip_box_64_tipspot_2_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_6", - "name": "tip_box_64_tipspot_2_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_2_7", - "name": "tip_box_64_tipspot_2_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 26.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_0", - "name": "tip_box_64_tipspot_3_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_1", - "name": "tip_box_64_tipspot_3_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_2", - "name": "tip_box_64_tipspot_3_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_3", - "name": "tip_box_64_tipspot_3_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_4", - "name": "tip_box_64_tipspot_3_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_5", - "name": "tip_box_64_tipspot_3_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_6", - "name": "tip_box_64_tipspot_3_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_3_7", - "name": "tip_box_64_tipspot_3_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 35.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_0", - "name": "tip_box_64_tipspot_4_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_1", - "name": "tip_box_64_tipspot_4_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_2", - "name": "tip_box_64_tipspot_4_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_3", - "name": "tip_box_64_tipspot_4_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_4", - "name": "tip_box_64_tipspot_4_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_5", - "name": "tip_box_64_tipspot_4_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_6", - "name": "tip_box_64_tipspot_4_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_4_7", - "name": "tip_box_64_tipspot_4_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 44.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_0", - "name": "tip_box_64_tipspot_5_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_1", - "name": "tip_box_64_tipspot_5_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_2", - "name": "tip_box_64_tipspot_5_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_3", - "name": "tip_box_64_tipspot_5_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_4", - "name": "tip_box_64_tipspot_5_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_5", - "name": "tip_box_64_tipspot_5_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_6", - "name": "tip_box_64_tipspot_5_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_5_7", - "name": "tip_box_64_tipspot_5_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 53.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_0", - "name": "tip_box_64_tipspot_6_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_1", - "name": "tip_box_64_tipspot_6_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_2", - "name": "tip_box_64_tipspot_6_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_3", - "name": "tip_box_64_tipspot_6_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_4", - "name": "tip_box_64_tipspot_6_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_5", - "name": "tip_box_64_tipspot_6_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_6", - "name": "tip_box_64_tipspot_6_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_6_7", - "name": "tip_box_64_tipspot_6_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 62.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_0", - "name": "tip_box_64_tipspot_7_0", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 71.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_1", - "name": "tip_box_64_tipspot_7_1", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 62.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_2", - "name": "tip_box_64_tipspot_7_2", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 53.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_3", - "name": "tip_box_64_tipspot_7_3", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 44.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_4", - "name": "tip_box_64_tipspot_7_4", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 35.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_5", - "name": "tip_box_64_tipspot_7_5", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 26.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_6", - "name": "tip_box_64_tipspot_7_6", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 17.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "tip_box_64_tipspot_7_7", - "name": "tip_box_64_tipspot_7_7", - "sample_id": null, - "children": [], - "parent": "tip_box_64", - "type": "container", - "class": "", - "position": { - "x": 71.0, - "y": 8.0, - "z": 0.0 - }, - "config": { - "type": "TipSpot", - "size_x": 10, - "size_y": 10, - "size_z": 0.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "tip_spot", - "model": null, - "barcode": null, - "prototype_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - }, - "data": { - "tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - }, - "tip_state": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - }, - "pending_tip": { - "type": "Tip", - "total_tip_length": 20.0, - "has_filter": false, - "maximal_volume": 1000, - "fitting_depth": 8.0 - } - } - }, - { - "id": "waste_tip_box", - "name": "waste_tip_box", - "sample_id": null, - "children": [], - "parent": "coin_cell_deck", - "type": "container", - "class": "", - "position": { - "x": 300, - "y": 200, - "z": 0 - }, - "config": { - "type": "WasteTipBox", - "size_x": 127.8, - "size_y": 85.5, - "size_z": 60.0, - "rotation": { - "x": 0, - "y": 0, - "z": 0, - "type": "Rotation" - }, - "category": "waste_tip_box", - "model": null, - "barcode": null, - "max_volume": "Infinity", - "material_z_thickness": 0, - "compute_volume_from_height": null, - "compute_height_from_volume": null - }, - "data": { - "liquids": [], - "pending_liquids": [], - "liquid_history": [] - } - } - ], - "links": [] -} \ No newline at end of file diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_id_CAS.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_id_CAS.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1fefc1bf665a2f1969aa4fb26fc0ac06cf602f55 GIT binary patch literal 9569 zcmeHtgVXmcEgERi!H`aE zV^V&OzJWdZ4nks(tG?c0HXf-s7qN*+tYrou&84A7gI9V*Lb0608lT{K&|22F0Uhk6 z{wB0i{bE7LeAlvy&Ub8qp_0#7Ym>Oswl>VZ#;0p+3h>c1z6%7N#szBBx|+m>PLzUYWsu=L}0|!&n?!LTqX0r%>i4sVRv%E7k8$uw(7;GxU4Y!4wyLrgqcJ zhi`4dW&josrUp*U0o3fGYY8g29moB9#qjf93?Fqz+VqY2s>O@5aIY+xdTV{4eI< zUw(QyNLjUq6D{me{w^GHIkT96C8^{kA>Tr+6%eGbfLRxtM@PEY!AORsMG^uh7uXhX zH#EN}61xMTzF6fgkH*0hrmgp?2uraD6B1QohoQ?KyKkbCE8m=)>gM7SB@F zSe&CYxI`=a`B=IdYn=Th2?}ljSr~z6da!=KvflUCSCud`lA8M!VO0(M**i(&8G*C! z3b)b4A_QOTO{L>Q++JIKt@MM~Q=eaxXlq&v+El#;y9&|xn3&slo=RtQ;NJVOsboSl zXn1k1xX0xN=(EoQ^=o;LhqHWo`B8exAV-71Xv*U6&`J320!dzzogA?FWbd=@mQkq+|KXN3p3<&hG%#}O5 zm)3stA5fc8GH%|_?F}Ioc+TV2|6R=RWx;7@@`gq}^5Hea6gZR_-GXOiMA1UKZY?FP zqR6Zp#rGnwC**MH;-$tSM}DgpKzs`izkfP%(?-84YD-j)2L@cAh0n#Q?FFvHr)^>< z;?dqlXs7hWUxD>Nj=Vt*Gh`RENY7X93*8pSV~vElX-IS`a3>A((w(?UH<5aT~VNrnw?0G7fpJrC1!CR66w3;QbInYUuS zL!sPl#!sYNEk>l=?aUnje5IACra+=865T0T!~~2wYzzQ-9Cigv9o@a{&wKQ1`qEDN zW+@4M&e3Z&v*Ik;aBo^~$vJUYJ4!M;JX2W=Jy$&66-3@L`%lnMXj zO7QdK)Klmu%}~CO0FYszT=_kx{FO2P$uBU_au3S5|L&t)Ls_Yp6RYjXLpY~bh9^Gu zS9cDYJ?&jgC~i=%Mh-{9IG z3L`j;o{qvHzuvE)0LmfY;_U70mhC^mc<+YW^c)0v3dR%IxMHFw4$mv3kv?mh3gfjM z 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 literal 0 HcmV?d00001 diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/material_template.xlsx index 698bf962c59c5dcddbd543886bf0d66899e1c60d..1b0eb9b20ea509e4085d4b7150cbc330f83f316a 100644 GIT binary patch literal 10675 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 literal 10375 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 OZW}C!&XW9@@BaYpy(vxr diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/output_example.json b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/output_example.json new file mode 100644 index 0000000..ae404c4 --- /dev/null +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/output_example.json @@ -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 + } + ] + } +} \ No newline at end of file diff --git a/unilabos/devices/workstation/bioyond_studio/bioyond_cell/多订单返回说明.md b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/多订单返回说明.md new file mode 100644 index 0000000..baecac9 --- /dev/null +++ b/unilabos/devices/workstation/bioyond_studio/bioyond_cell/多订单返回说明.md @@ -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 格式便于后续处理和分析 diff --git a/unilabos/devices/workstation/bioyond_studio/config.py b/unilabos/devices/workstation/bioyond_studio/config.py index 736ca66..9a70d5c 100644 --- a/unilabos/devices/workstation/bioyond_studio/config.py +++ b/unilabos/devices/workstation/bioyond_studio/config.py @@ -8,8 +8,10 @@ import os # BioyondCellWorkstation 默认配置(包含所有必需参数) API_CONFIG = { # API 连接配置 - # "api_host": os.getenv("BIOYOND_API_HOST", "http://172.16.1.143: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.11.2"), # 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,# 调试模式 } diff --git a/unilabos/devices/workstation/coin_cell_assembly/Modbus_CSV_Mapping_Guide.md b/unilabos/devices/workstation/coin_cell_assembly/Modbus_CSV_Mapping_Guide.md new file mode 100644 index 0000000..8af63e7 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/Modbus_CSV_Mapping_Guide.md @@ -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 地址。 diff --git a/unilabos/devices/workstation/coin_cell_assembly/YB_YH_materials.py b/unilabos/devices/workstation/coin_cell_assembly/YB_YH_materials.py index bc8dc4f..c9187e6 100644 --- a/unilabos/devices/workstation/coin_cell_assembly/YB_YH_materials.py +++ b/unilabos/devices/workstation/coin_cell_assembly/YB_YH_materials.py @@ -634,6 +634,12 @@ class CoincellDeck(Deck): self.assign_child_resource(waste_tip_box, Coordinate(x=778.0, y=622.0, z=0)) +def YH_Deck(name=""): + cd = CoincellDeck(name=name) + cd.setup() + return cd + + if __name__ == "__main__": deck = create_coin_cell_deck() print(deck) \ No newline at end of file diff --git a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly.py b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly.py index ef942e2..f47f560 100644 --- a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly.py +++ b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly.py @@ -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): diff --git a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_1223.csv b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_1223.csv new file mode 100644 index 0000000..9212f9b --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_1223.csv @@ -0,0 +1,159 @@ +Name,DataType,Comment,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_SYS_STOP_STATUS,BOOL,豸ͣ,coil,8220,, +,,,,,, +,BOOL,UNILAB͵Һƿ,coil,8720,, +,BOOL,豸ܵҺƿ,coil,8520,, +REG_MSG_ELECTROLYTE_NUM,WORD,Һʹƿ,hold_register,496,, +,WORD,Ƭ̾λʼλ0,hold_register,440,, +,WORD,Ĥ̾λʼλ0,hold_register,450,, +,WORD,Һƿ_Ͼλʼλ0,hold_register,460,, +,WORD,Һƿ_վλʼλ0,hold_register,430,, +,WORD,g_Һƿ_޸˸׾λʼλ0,hold_register,470,, +,WORD,Һǹͷλʼλ0,hold_register,480,, +,WORD,øƬ,hold_register,443,, +,WORD,øĤ,hold_register,453,, +,,,,,, +COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,UNILAB䷽,coil,8700,, +COIL_REQUEST_REC_MSG_STATUS,BOOL,豸䷽,coil,8500,, +REG_MSG_ELECTROLYTE_USE_NUM,INT16,ƿҺʹô,hold_register,11000,, +REG_MSG_ELECTROLYTE_VOLUME,INT16,Һȡ,hold_register,11004,, +REG_MSG_ASSEMBLY_PRESSURE,INT16,װѹ,hold_register,11008,, +REG_DATA_ELECTROLYTE_CODE,STRING,Һάк,hold_register,10020,, +,BOOL,Ӿλfalse:ʹãtrue:ԣ,coil,8300,, +,BOOL,죨false:ʹãtrue:ԣ,coil,8310,, +,BOOL,_֣false:ʹãtrue:ԣ,coil,8320,, +,BOOL,_Ҳ֣false:ʹãtrue:ԣ,coil,8420,, +,BOOL,еְ̣false:ʹãtrue:ԣ,coil,8330,, +,BOOL,ϣfalse:ʹãtrue:ԣ,coil,8340,, +,BOOL,ռ֪false:ʹãtrue:ԣ,coil,8350,, +,BOOL,ѹģʽfalse:ѹģʽTrue:ģʽ,coil,8360,, +,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,, +COIL_SYS_UNILAB_INTERACT ,BOOL,Unilabfalse:ʹãtrue:ԣ,coil,8450,, +,BOOL,Եࣨfalse:ʹãtrue:ԣ,colil,8460,, +,,,,,, +COIL_UNILAB_SEND_MSG_SUCC_CMD,BOOL,UNILAB䷽,coil,8510,, +COIL_UNILAB_REC_MSG_SUCC_CMD,BOOL,UNILABܲ,coil,8710,, +REG_DATA_POLE_WEIGHT,FLOAT32,ǰƬ,hold_register,10010,, +REG_DATA_ASSEMBLY_PER_TIME,FLOAT32,ǰŵװʱ,hold_register,10012,, +REG_DATA_ASSEMBLY_PRESSURE,INT16,ǰװѹ,hold_register,10014,, +REG_DATA_ELECTROLYTE_VOLUME,INT16,ǰҺע,hold_register,10016,, +REG_DATA_ASSEMBLY_TYPE,INT16,װƬѵʽ(7/8),hold_register,10018,, +REG_DATA_ELECTROLYTE_CODE,STRING,Һάк,hold_register,10020,, +REG_DATA_COIN_CELL_CODE,STRING,ضάк,hold_register,10030,, +REG_DATA_STACK_VISON_CODE,STRING,϶ѵͼƬ,hold_register,10040,, +REG_DATA_ELECTROLYTE_USE_NUM,INT16,ǰ缫ҺװR,hold_register,10000,, +REG_DATA_OPEN_CIRCUIT_VOLTAGE,FLOAT32,ǰصѹ,hold_register,10002,, +,INT,еȡϼĴ1-ǡ2-桢3-Ƭ4-Ĥ5-Ƭ6-ƽ桢7-桢8-ǣ,hold_register,10060,, +,,,,,, +,INT,ǰƬʣR,hold_register,10062,PLCַ,1223- +,INT,ǰĤR,hold_register,10064,, +,INT,Һ״̬루R,hold_register,10066,, +,REAL,·ѹOKֵR,hold_register,10068,, +,REAL,·ѹOKֵR,hold_register,10070,, +,INT,ǰװR,hold_register,10072,, +,INT,ǰװR,hold_register,10074,, +,REAL,10mmƬʣR,hold_register,520,HMIַ, +,REAL,12mmƬʣR,hold_register,522,, +,REAL,16mmƬʣR,hold_register,524,, +,REAL,ʣR,hold_register,526,, +,REAL,ʣR,hold_register,528,, +,REAL,ƽʣR,hold_register,530,, +,REAL,ʣR,hold_register,532,, +,REAL,ʣR,hold_register,534,, +,REAL,ƷʣR,hold_register,536,, +,REAL,ƷNGʣR,hold_register,538,, +,,,,,, +,REAL,10mmƬȣW,hold_register,540,, +,REAL,12mmƬȣW,hold_register,542,, +,REAL,16mmƬȣW,hold_register,544,, +,REAL,ȣW,hold_register,546,, +,REAL,ǺȣW,hold_register,548,, +,REAL,ƽȣW,hold_register,550,, +,REAL,øǺȣW,hold_register,552,, +,REAL,õȣW,hold_register,554,, +,REAL,óƷغȣW,hold_register,556,, +,,,,,, +,,,,,, +REG_DATA_GLOVE_BOX_PRESSURE,FLOAT32,ѹ,hold_register,10050,, +REG_DATA_GLOVE_BOX_WATER_CONTENT,FLOAT32,ˮ,hold_register,10052,, +REG_DATA_GLOVE_BOX_O2_CONTENT,FLOAT32,,hold_register,10054,, +,,,,,, +,BOOL,쳣100-ϵͳ쳣,coil,1000,, +,BOOL,쳣101-ͣ,coil,1010,, +,BOOL,쳣111-伱ͣ,coil,1110,, +,BOOL,쳣112-ڹդڵ,coil,1120,, +,BOOL,쳣160-Һǹͷȱ,coil,1600,, +,BOOL,쳣161-ȱ,coil,1610,, +,BOOL,쳣162-ȱ,coil,1620,, +,BOOL,쳣163-Ƭȱ,coil,1630,, +,BOOL,쳣164-Ĥȱ,coil,1640,, +,BOOL,쳣165-Ƭȱ,coil,1650,, +,BOOL,쳣166-ƽȱ,coil,1660,, +,BOOL,쳣167-ȱ,coil,1670,, +,BOOL,쳣168-ȱ,coil,1680,, +,BOOL,쳣169-Ʒ,coil,1690,, +,BOOL,쳣201-ŷ01쳣,coil,2010,, +,BOOL,쳣202-ŷ02쳣,coil,2020,, +,BOOL,쳣203-ŷ03쳣,coil,2030,, +,BOOL,쳣204-ŷ04쳣,coil,2040,, +,BOOL,쳣205-ŷ05쳣,coil,2050,, +,BOOL,쳣206-ŷ06쳣,coil,2060,, +,BOOL,쳣207-ŷ07쳣,coil,2070,, +,BOOL,쳣208-ŷ08쳣,coil,2080,, +,BOOL,쳣209-ŷ09쳣,coil,2090,, +,BOOL,쳣210-ŷ10쳣,coil,2100,, +,BOOL,쳣211-ŷ11쳣,coil,2110,, +,BOOL,쳣212-ŷ12쳣,coil,2120,, +,BOOL,쳣213-ŷ13쳣,coil,2130,, +,BOOL,쳣214-ŷ14쳣,coil,2140,, +,BOOL,쳣250-Ԫ쳣,coil,2500,, +,BOOL,쳣251-ҺǹͨѶ쳣,coil,2510,, +,BOOL,쳣252-Һǹ,coil,2520,, +,BOOL,쳣256-צ쳣,coil,2560,, +,BOOL,쳣262-RBδ֪λ,coil,2620,, +,BOOL,쳣263-RBXYZ,coil,2630,, +,BOOL,쳣264-RBӾ,coil,2640,, +,BOOL,쳣265-RB1#ȡʧ,coil,2650,, +,BOOL,쳣266-RB2#ȡʧ,coil,2660,, +,BOOL,쳣267-RB3#ȡʧ,coil,2670,, +,BOOL,쳣268-RB4#ȡʧ,coil,2680,, +,BOOL,쳣269-RBȡʧ,coil,2690,, +,BOOL,쳣280-RBײ쳣,coil,2800,, +,BOOL,쳣290-ӾϵͳͨѶ쳣,coil,2900,, +,BOOL,쳣291-ӾλNG쳣,coil,2910,, +,BOOL,쳣292-ɨǹͨѶ쳣,coil,2920,, +,BOOL,쳣310-쳣,coil,3100,, +,BOOL,쳣311-쳣,coil,3110,, +,BOOL,쳣312-쳣,coil,3120,, +,BOOL,쳣313-쳣,coil,3130,, +,BOOL,쳣340-·ѹ쳣,coil,3400,, +,BOOL,쳣342-·ѹ쳣,coil,3420,, +,BOOL,쳣344-·ѹѹ쳣,coil,3440,, +,BOOL,쳣350-쳣,coil,3500,, +,BOOL,쳣352-쳣,coil,3520,, +,BOOL,쳣354-ϴ޳쳣,coil,3540,, +,BOOL,쳣356-ϴ޳ѹ쳣,coil,3560,, +,BOOL,쳣360-Һƿλ쳣,coil,3600,, +,BOOL,쳣362-Һǹͷжλ쳣,coil,3620,, +COIL ALARM_364_SERVO_DRIVE_ERROR,BOOL,쳣364-Լƿצ쳣,coil,3640,, +COIL ALARM_367_SERVO_DRIVER_ERROR,BOOL,쳣366-Լƿצ쳣,coil,3660,, +COIL ALARM_370_SERVO_MODULE_ERROR,BOOL,쳣370-ѹģ鴵쳣,coil,3700,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +,,,,,, +COIL + ģ/ + д+»߷ָ--boolֵ,,,,,, +REG + ģ/ + д+»߷ָ--ԼĴ,,,,,, diff --git a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_20260106.xlsx b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_20260106.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..1add6c15bd014b303d24ea6130e02b05dd23d251 GIT binary patch literal 17996 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�XbbAr@e=ByThq!TAHAyK5os0t=7=E2qPOzlF1(UiFd5 zExy{r=CG&=!||u?zKWM-tx@txMS8S70+3fosV%cOe|Y7iyWl+}&)g z8wu%f7x&YRUeOLVyXgS63afUDvKQ-*Kwmg-K7wBO<*Rh=rft6_;ApXGq>bys4J2Ti z9S#kblH;kvnWcQjmHB%+curUg#L@*U$CZpfoSI1TL4BM!*U#iP_eo2VNySN!c&O5|oze_bSVrHPot0miV2 z*^e28N@FfP5VZ;*F;)Y96ZMY)=8vk5s_VdHqlyN<{`LTstDfIx&rR1wb;VA~>il}r zD#9PGCANfPH+uLs;&eC3dzpgTppfshlyJSL8P-e_}Ak8G1tzA8qMO%*Ok}-Pyp-NDM>vJ8(7Z{r%4j-KS_F#6aMpedY8h z2sr5{Ln#hxdxLEZHY&#zMqe%`mg8j$!y1^m3Y#Iw6Ug`r#Oe|l_B1JMe^;o+yH30D6~zqgK(M@LwM zTf0NtPU;gwLcA4`q&F?#>+o!dVq+q#Z2OIE7xL+2{0Mme7Yx3S*#u=22!V{>>(!pv z{D)n%JJu_2t!R93{KZJsEi5C-YjuwxvF8DWg!s)~x4QM#TL`anZ0RexPxZfW5{{AP ze+3DBXf@wrqwM=)^-wi)dSm^Hldx@N_2Btq4emI}7a^Qd5^-U&uuAoeUackYGuE0z zce(-NcQxicF4!7_L>Q9GK(j-kHsB5e9d}V`R_Y-5uYH zl(PY8Mj1Gjka|92G$WUdqDB;cEH{YQG1|Kq(Mba@VIH#3Mp|u1;qP=Cr)yW-ku-BKOyoEcfO=(+O`JoqxR7! zil8gaY_&*;(UabP@HXCl5*98fPGPPT=ofA@u5eJVM7g2qWIV6Bm=d)nZ6fQH3;C|~1FkqDUaE3x zDi@|zDhD>$+kty84S+A^c+X+cMnHUWsyNY|SqW#`cj0k|bvm-b(99qN*--_L{Ot5> z`t>`TP!^*II7DcKtxzwlAAR1q3LU%Kunce{{{;k=v~)d8@@jPZKzRx6jmIRW#h)uE zaG?A_MJiJ!p~k7Cb1C>4DT$4bRj$H_Q*xf`q_u>r((>iqN2S(+A$x)OpnlYYZpZW4 zldk@=Zo8mKyqkyf#K-l;t5jsE`@O(zo!l0F&~@{EFs#`#%C&gydVm><_bAS1Oxxku zq)X2D3l!`#adXJ>+!|YbSQ-#DNv7$Z=KOHEqj{fVkJf>Hi{e^sRh_Zf5YQp- zR`iPgTxoJ8=khGK3)N#60q2sIGHI}c(+Dhs&!)HvE?5eBh{EVurop;Psp?bC>QnN^ z$+?(un@&K zD=jrUcv!kvl<{=EZ1b%gzLz19JPRAB}!7< z7(hXxG}+5z`&e%YolHZ@YW0YAh}ART4%tLHtMwsIsnG{pGRyWM*&qq~L(P{@3EbN8 zvcr%}u_;~&y>xnXeu)UIQ+RncG;03H>*_mcf;4t%4#>_tgYL{-q!yuTSPEIPgaKPh z752WReR>3CWJ`G6ZG=%VZD8C79LNRg>I^hc(P91(L5{~`OabXt7_obgZpZq=<_oRi z(_9JBq}&nmu6ZfOS>0@56{AyfG=x}kOKDxXC-l52C17`na%*OUbHh%M7W-yJebmRZ z&hbYlJi7>`S0b}D)P=UMvUH9WR`gAXsB<1tygRc#(O_MSblIcKG8(P2J>j*r3M+Li zw9xQ!v+NHxE@GT~mo*;+1~bPsT?A=Qq%t3#_E%fyOraVAcs=d?IExhz<-0T4#N}@a zIlfWZbYeD<*5aV>dpOBzzO5-PA~q*hX;HFu`x1YLEEFcSR)afZEK7PeXqr7yKJV%x z$#29fYPbVy?9PceJ=cw?T-z8J(Mp3O#r%-kp3Pv{bNlMkwB6i6Sd#9sK`O}YW|b&Z zyL>teJ7(!65AB&Lmb+B$0^6q9u#S7vY>>~@c;F?DgI8C&mNRdMZn zk3^m5DsRW}B=oGS+TS^>^fc%Vaz5v31HAR@KdcxFBQ{fz!vFwtQUCzLU*Xuv*~8kz z>Gv}6thQFnNP1wx%l2-!6F~-# zED7KfvRmIZS!$+)A}_a_H&6SA@eBZeYH+OGM|*6ULU&BAJ5I4gZ#hMiCaTAuxL>Kd z!vwZLF3%39yyvk(-bQ6tb5ELvAo@`u{G6}uSfNS14ngKZ@>WO;K{~$`O}2Nhw(VhAEm`nEs+L-4|0eo!b_^Awln16k{l`S^18-)8&?Y;+t^MNc}TJX$#0NbiQ6AB}dY8$7#>6VZXI=t5jR-`t0`%R^UM*3agfHI&p*1;tYlNJS+?53 zck|3zExWj@WWVwGN}G_rzDcT(ca*yC5QDwPvAn51R>`wooxZVqJ>|TJK?j!?OEQwK zy*U`2U2lhIoFi}YELJ-FW|d@GAHC++|4em1!YYWzdNPP}x~0Enm#O-rr@XFX3{vCm zhdoxFpuO{Ti!-9STTfDmE=H5Vt&;zW;s$S8$ffbe(52`Tk3MgB3ULd`N-&lM;A9&d zKW5E65`!t@C9Hm2l)B{i{dGGz(r00XOT55JVLZ=stm+iRU(O70UP1e*Y@9u3ilgot z)*$s|LMPBUWr`u`rOsnxb#~4!n<_z&)U5Z*tWkp@K-acr{fsTl_ujsrs8&$-<&daQL1O$^rlyfGzN}Pf zDnSnlS1!a-E}&kor*7($WCLT}lD5mFbs*SoZqk8#=vS`x>Pw8Z>=3Mp}QDsS)=kdkN z=aV*?<@G}veKF&eSNvk@uj59FXr||at}bK+dK83a2()afX|zmWE;1kjbzjkuG$R&`iIuG);Xxy+w6H4H;WoR=$wZrrHc zbhD_AR}0N;UgMU47H`P2+3s`TLJ`yo)oiSfF1Sq%3iBC9$L@F_$v)y57gI|27#$>m3Bx50aiLqHH?ep_Qn(IB=GjYEekx%m?4-^pD$>(=W3z zDEs;n88afk(T!|9W;3(H9Q+y?RT5-lHI6LyN#+&R70od{aPkJQ*7x8#fLIpg6iwv9 z$JH&xZ~zVVBMZ-9EzT)8_Y)`R7XG@&DpPrmacqd=FHvDwELCyXyel!qL`_SrX|UQk zvKK1lq#z;b-r$Ji-qobVW84I)`=CbQQRojX387pIHZo=jHcgHFVugzMRb;9mRqDx? zA|~AWDigHATpwZAZ$H8WpUBnxjAsbBl0@G)u^V0LO@`P}IWHMWvzJwuiXqfss~ zEju*IdTc305wnoEt24-D>EndBmtep0`IWR#bE81yOlmbGBY&RbU{coOLtOOlpSbq^ zE_asTMto%MW{{h|1}vkJ_6vDa94^zabz(f`L+DMbm-9k9#9Q1ucm~hVB!i zV;R2$r3z)jM`Cntq6=<(r_j}wX9r95NMX|dB*RKo(3!IU6@b{ zejgG;$Yil(1VXc09%d*6{T6~^Wq{IlG<&|@CW{7}eEI~1#9JiAB#~jtr@N)hAVQVl zU(dRX!{;xZ%a8j3T^7wu8+J*-MTg@lh+un9}Fur5R?L-z; z3cNZz4j`-<4uREE7L2zJ{;Z7xrKzNSBiMqv=R~W4+$+o zN1_TK^)KJp6$)hJGX@b4g|N}3`4D!77GTV~u#OXFRujX7)K`vMY`}*Wpw2%#kH@BU zeS;yeGR&Om9r1fb5L4S?rkQe#ST(kRJ_)=GT;2Ujsuh^^7G&o~s|xGS;!1J1Doub% z=qh^kcJNSSFVFEj-*Udg*oCYU+d6<07?1%@L!n;MhSr0>`m2L6X0_tsq}F$Ym#=nK zOzXS>w|O56VdgNK9o}bBfUo|uMj}*4fN!2Sd1j}Qhi^C9*I%UZn-$Wc0%3gavI+?< z?4vbzpu1YL8Nx9#PW!n5q)gk-V8n@!Z zjU^SP%?OCE`X#rYq7NXORGWmIslI|I^KcXINlEN_D7XFR@zkuZ^>8mN0AN840HFUp zo-#LZG%;3kcC@fH`!lSn)6`NT(LnXh{`!an{#=8L29HjuE1a1VTOB53-{dTJ0oO&j zCKD`NIa$kMXBiXz0cZJHr)93cow9j49CRl}LssQ-*3Y2!7~P&WJWudIDF6HLi)_{? zZ|Z?@Rt2FiF1G6HF(Cq!aF;FHZJTWQ6%>?+NWf;TZT-M&evwW&thjd<@rFI+;f3n^ zIZ~KR)+;Zn$JCFxP^j!@aqq1Q5r!9`hbvZA?(K-qi7B(?Ul9r& zc9bux7cr6WR=3=l3Ow6z;BzHilOy^CT5I!DxvFjOkZ-TkcKvoY&8jYPYMhfZ7)RC5 zVlO(&5^~8&&rutJ7Yrrq=^~`0Z~6t{tM69&lMH?OI5;@BUwRB7YkMrOo3k2Q z=^KWQ?$VyU`p}W^5Yr#g9h51#Xc5;W-wY1+kU)A|_1Ki~BErS`#j zKB8xi&ipX3;AMA_%$Av~L{jip>7_8W*L-Syt>CZhGi7SYL|j2@=(D=Ni5Mc_$xu00 z7o*>`ODQC!O-i}+Fn1s1IrhVZ7JtcCnJ#iW%5*R_O+_jPahS;?sixhA!eWD(I=6SO<2MF z(d_1!ppCC@mlF!^VYb@DAWLFM@ta0o)Ast!*bO!e^$ zwI*KE+F3`k*Je)ae6@;#wNxk<&9|fK##PIfu1; z6wgpC0%5unxrY#GYYD<9Y)vu^No`A0S|R(6Jmq)oY1^0;2dUO+OSs|-4(K|fmm|~z zlCsr9*a@gfw@MrKiyL8J{R^w!#y5o>XluKvdm>>b(TIjOZ&=_#p^d|(gAw!_A8I1p zHe<3mdOBQWI(Q(c4tvd@SG1j%w5^oCZf~f1Mb8;QpOI<8hv%n_#dy;apFwrj>S$Umjp0f?fl zrJw~d_aVWtymYco9(ha)oa>dnT)rXpu^&G$>;U*_(`$^P>3(&T^di?Kq!!HVAZUGQ zplSqvH4T4eK;2}Gsu;g4uEFwBqHI_5RHK9M@aFC6thz|KoTYWcZ!oSD#lK-drGeL8o!H#%(&o296X`r1i%2;n_ zIZ+%cRP7QQwh^R;dW%b}n)AhYbg>B1iZ_HHPp~3y4OxZKi&56x@j6X_)-T z@P^>kZEk^*Sax@voGs$&)*xMu)5OW{^zoXRlH)H-M%}D3p}O{-XK0jD5hq z+^Pv~rxoho0|8t7DUUkh9IMKIRJC{stQe{)V`WyY@Kg)2`Uav^XxYW!UV-m}(i{kK zPc=vSsn%eh_PiQV)#j;v@K*|S7KP^6*sDAd7DCuZ7i-vW9Y1X;eU!BOO&jg!m1%LZ z;Fkr|MnS5v&%6~sN5{*EfbCY`U;{?KU^c}Q2h-4EgcnZ^VL18FTcO8Itc!oVj$+&a z>#?zOZwsi{=s9+$t>y-Q((=vme@lXzE&gDwmtAFe`&1X$c7mo#TMj^9Q4c66aM>Fi zxh$U8cQ?M|w|~*Tc9&nr-;vQ7GuIIEw00C3X5~4xm3H}5f~R4y6Zb%t96xdvbszW5Y22qdM0@E+N<36%NfA!W(z-<;K#XB|`u$fc7 z8>BZPl99z{9J3(}h3ZqP0Okck z@uYw`{(XUyP#@2>w&ND%7`*XZQ(Mza=?BiH7}(I=^?QGRcIQS1vY(|s14YCM3?=)V zp)GN$hBkV4#t-ynUIV+LDWMunCz_$puTeB{<%PMjkSBQf8P!KUnvr603L5|;+#z#w z|LRO*YYYGCAmiYst#USHXk)X*3NUuaVHr4{8up7xi>hgddF4%K{DjT`E4Mp-4{v%Q z-@u&@v)Ly>xI~aSt5^r6L$v7=aF8;__D52-WMI3ema3)<<-v(s;@WH9!xRuu%Z9~l zwho4Mi}agUiz3`~X+eCN!9{(Sj(#3C9fdb4ST{EkD0QznMx^Uz?nI~GiihZjvd!hx zm6IdDVX9D@Sw)2ImspfeJ_;6FQC>?`2NLavsT+iU=Ki6dv`P?VUXmM+aL7TmMY_$j zV7;XMePY;!S(zezXz79tODjiY+k5xd9d~(^P6KBqVzDzgm?DDm%;YHe4c=rI#)svT zRo4{=;7R?86l{3njC7e|MbRxd3u&9h#kl&yuRI=OA=8njLM-tE#pfEQh&uEAr z_>64-Obprp-#pj#jSC(9T=IK;Lj{Sw8tyrK&g+CZQJ@_QD-D#6rOW2eMEMjNnfDdD zPLkd!NLRR*M+jKFUlJMen`%c`pfSA~V7`fn=)cst**ZxbSSc~^(lWtTv;3!zGV8eX z=gnEc*ss?Ft$Byn1P51$3QxetsKq+B<)-CLLnhq?zV6yY^H{*cNvt0=LUDRu0Bl|D z+aeCvk}QT8^s#wQ8?NXb)$Gc5OPAnq&Vx@KUO!flmFICcmBM=^>p7)A$!gDph=a9e z_Sk7HzL?!nOnH1Hhnd@-HUY^+g|#UwLA9SbiM{CA%6&dn2jgau`vHd*!3Y~7*wLdsw;8`;C|-vv*=JvU4=~JGK1(GL(RS2fX9-R7lXSqfQ4*X15fhOj3S zemBpKZq#!x&w|GJ#d%xyC{5#j7Qzl)?fO7W!Zs7E^i_{ee=0#~khv=!PpB~&ahy-Lp!Vt{^Vzl91o|!DTR{8v2K>@S z_k{OVT{pc)dc-kNz@qa;eVk%OGQvS=Cc1cCjCkW;u9nXZeV2=T{q|sx@kN?D=E$0# zI16Oy+w&EV@qbQ!A`|H3%mR`S5jfF}{O=?*u($s|4g$&d_m&aYWr@p#9C{Jb-jnB5 zR<9(?q!|)dw>zmAl&Kw+msu}bKb@CK>zZAdOaSW>l=Z|;b;HEmBAwwftz^e?jnu*a z8ppjc$8SZP81Pgb1eM;0USQI3IN~sp@ z6t)gaYf3P0kjKra!c+fYSc2e?&d#iwSZj}crh^c$OFJ<^b_y*FvnT1qh#s`lTKLXJ zmw)!~%e3AOOTE-hW+#)aw_!FrLk7i2bm=)0qHakC*R><5L!gUl}XkV+F>vNB+Hi*by4;Esc zH#XjU-+z#u^pr6Slu>6BrP%Kcg85cpQcMZ>7aMJ68Fb>?TRR(! zEj`u?1wYMSEX*vO-ayzBf)Ku*R>jbJcb%AGFd%dpB@Kwwucm>M5BLo}G0Lmq8C_)# z_00z(B*gGAgq-i$gJLPn3V&bn-8huOxp^{&@?^KLP%^O!hB;55S2YV0Her zX!cLlf6fT~OVy0!FV%m}5B(G2zem@9=>q^d`~blJh_(Mz|L^_czpHNx{+s&Wy`;P} V1h91h09fG59~jPmiv0fe{{bF7P>%or literal 0 HcmV?d00001 diff --git a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_a.csv b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_a.csv deleted file mode 100644 index 98f9038..0000000 --- a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_a.csv +++ /dev/null @@ -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, \ No newline at end of file diff --git a/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_b.csv b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_b.csv new file mode 100644 index 0000000..fc10967 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/coin_cell_assembly_b.csv @@ -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-电解液瓶盖在籍异常 diff --git a/unilabos/devices/workstation/coin_cell_assembly/date_20251224.csv b/unilabos/devices/workstation/coin_cell_assembly/date_20251224.csv new file mode 100644 index 0000000..8a8c176 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/date_20251224.csv @@ -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' diff --git a/unilabos/devices/workstation/coin_cell_assembly/date_20251225.csv b/unilabos/devices/workstation/coin_cell_assembly/date_20251225.csv new file mode 100644 index 0000000..d51070e --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/date_20251225.csv @@ -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' diff --git a/unilabos/devices/workstation/coin_cell_assembly/date_20251229.csv b/unilabos/devices/workstation/coin_cell_assembly/date_20251229.csv new file mode 100644 index 0000000..124bff1 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/date_20251229.csv @@ -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' diff --git a/unilabos/devices/workstation/coin_cell_assembly/date_20251230.csv b/unilabos/devices/workstation/coin_cell_assembly/date_20251230.csv new file mode 100644 index 0000000..7fefb59 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/date_20251230.csv @@ -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 diff --git a/unilabos/devices/workstation/coin_cell_assembly/date_20260106.csv b/unilabos/devices/workstation/coin_cell_assembly/date_20260106.csv new file mode 100644 index 0000000..f9cde47 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/date_20260106.csv @@ -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 diff --git a/unilabos/devices/workstation/coin_cell_assembly/interactive_battery_export_demo.py b/unilabos/devices/workstation/coin_cell_assembly/interactive_battery_export_demo.py new file mode 100644 index 0000000..adf2082 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/interactive_battery_export_demo.py @@ -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() \ No newline at end of file diff --git a/unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md b/unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md new file mode 100644 index 0000000..685fc08 --- /dev/null +++ b/unilabos/devices/workstation/coin_cell_assembly/电池资源冲突修复说明.md @@ -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` 函数) diff --git a/unilabos/registry/devices/bioyond_cell.yaml b/unilabos/registry/devices/bioyond_cell.yaml index c379e27..09690f1 100644 --- a/unilabos/registry/devices/bioyond_cell.yaml +++ b/unilabos/registry/devices/bioyond_cell.yaml @@ -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: {} diff --git a/unilabos/registry/devices/coin_cell_workstation.yaml b/unilabos/registry/devices/coin_cell_workstation.yaml index b3eb7b4..e2cb91a 100644 --- a/unilabos/registry/devices/coin_cell_workstation.yaml +++ b/unilabos/registry/devices/coin_cell_workstation.yaml @@ -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 diff --git a/unilabos/registry/devices/laiyu_liquid.yaml b/unilabos/registry/devices/laiyu_liquid.yaml deleted file mode 100644 index 64c0c18..0000000 --- a/unilabos/registry/devices/laiyu_liquid.yaml +++ /dev/null @@ -1,1919 +0,0 @@ -laiyu_liquid: - category: - - liquid_handler - - workstation - - laiyu_liquid - class: - action_value_mappings: - add_liquid: - feedback: {} - goal: - asp_vols: asp_vols - dis_vols: dis_vols - flow_rates: flow_rates - offsets: offsets - reagent_sources: reagent_sources - targets: targets - use_channels: use_channels - goal_default: - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - dis_vols: - - 0.0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - reagent_sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - reagent_sources: unilabos_resources - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAdd_Feedback - type: object - goal: - properties: - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - reagent_sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: reagent_sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - reagent_sources - - targets - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_time - - mix_vol - - mix_rate - - mix_liquid_height - - none_keys - title: LiquidHandlerAdd_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAdd_Result - type: object - required: - - goal - title: LiquidHandlerAdd - type: object - type: LiquidHandlerAdd - aspirate: - feedback: {} - goal: - flow_rates: flow_rates - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0.0 - flow_rates: - - 0.0 - liquid_height: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAspirate_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - liquid_height: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - title: LiquidHandlerAspirate_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAspirate_Result - type: object - required: - - goal - title: LiquidHandlerAspirate - type: object - type: LiquidHandlerAspirate - auto-add_resource: - feedback: {} - goal: {} - goal_default: - name: null - position: null - resource_type: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - name: - type: string - position: - items: - type: number - type: array - resource_type: - type: string - required: - - name - - resource_type - - position - type: object - result: {} - required: - - goal - title: add_resource参数 - type: object - type: UniLabJsonCommand - dispense: - feedback: {} - goal: - flow_rates: flow_rates - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0 - flow_rates: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDispense_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - blow_out_air_volume - - spread - title: LiquidHandlerDispense_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDispense_Result - type: object - required: - - goal - title: LiquidHandlerDispense - type: object - type: LiquidHandlerDispense - drop_tip: - feedback: {} - goal: - use_channels: use_channels - goal_default: - allow_nonzero_volume: false - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDropTips_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - - allow_nonzero_volume - title: LiquidHandlerDropTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDropTips_Result - type: object - required: - - goal - title: LiquidHandlerDropTips - type: object - type: LiquidHandlerDropTips - move_to: - feedback: {} - goal: - channel: channel - dis_to_top: dis_to_top - well: well - goal_default: - channel: 0 - dis_to_top: 0.0 - well: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - well: unilabos_resources - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMoveTo_Feedback - type: object - goal: - properties: - channel: - maximum: 2147483647 - minimum: -2147483648 - type: integer - dis_to_top: - type: number - well: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: well - type: object - required: - - well - - dis_to_top - - channel - title: LiquidHandlerMoveTo_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMoveTo_Result - type: object - required: - - goal - title: LiquidHandlerMoveTo - type: object - type: LiquidHandlerMoveTo - pick_up_tip: - feedback: {} - goal: - tip_rack: tip_rack - use_channels: use_channels - goal_default: - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_rack: unilabos_resources - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerPickUpTips_Feedback - type: object - goal: - properties: - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - title: LiquidHandlerPickUpTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerPickUpTips_Result - type: object - required: - - goal - title: LiquidHandlerPickUpTips - type: object - type: LiquidHandlerPickUpTips - setup: - feedback: {} - goal: - string: string - goal_default: - string: '' - handles: {} - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: StrSingleInput_Result - type: object - required: - - goal - title: StrSingleInput - type: object - type: StrSingleInput - stop: - feedback: {} - goal: - string: string - goal_default: - string: '' - handles: {} - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: StrSingleInput_Result - type: object - required: - - goal - title: StrSingleInput - type: object - type: StrSingleInput - transfer: - feedback: {} - goal: - source: source - target: target - tip_position: tip_position - tip_rack: tip_rack - volume: volume - goal_default: - asp_flow_rates: - - 0.0 - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - delays: - - 0 - dis_flow_rates: - - 0.0 - dis_vols: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_stage: '' - mix_times: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - tip_racks: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - touch_tip: false - use_channels: - - 0 - handles: {} - placeholder_keys: - source: unilabos_resources - target: unilabos_resources - tip_rack: unilabos_resources - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerTransfer_Feedback - type: object - goal: - properties: - asp_flow_rates: - items: - type: number - type: array - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - dis_flow_rates: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_stage: - type: string - mix_times: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - tip_racks: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_racks - type: object - type: array - touch_tip: - type: boolean - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - sources - - targets - - tip_racks - - use_channels - - asp_flow_rates - - dis_flow_rates - - offsets - - touch_tip - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_stage - - mix_times - - mix_vol - - mix_rate - - mix_liquid_height - - delays - - none_keys - title: LiquidHandlerTransfer_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerTransfer_Result - type: object - required: - - goal - title: LiquidHandlerTransfer - type: object - type: LiquidHandlerTransfer - module: unilabos.devices.laiyu_liquid.core.laiyu_liquid_main:LaiYuLiquid - status_types: - current_position: String - current_volume: float - is_connected: bool - is_initialized: bool - status: dict - tip_attached: bool - type: python - config_info: - - default: /dev/cu.usbserial-3130 - description: RS485转USB端口 - name: port - type: string - - default: 1 - description: 设备地址 - name: address - type: integer - - default: 9600 - description: 波特率 - name: baudrate - type: integer - - default: 5.0 - description: 通信超时时间 (秒) - name: timeout - type: number - - default: 340.0 - description: 工作台宽度 (mm) - name: deck_width - type: number - - default: 250.0 - description: 工作台高度 (mm) - name: deck_height - type: number - - default: 160.0 - description: 工作台深度 (mm) - name: deck_depth - type: number - - default: 77000.0 - description: 最大体积 (μL) - name: max_volume - type: number - - default: 0.1 - description: 最小体积 (μL) - name: min_volume - type: number - - default: 100.0 - description: 最大速度 (mm/s) - name: max_speed - type: number - - default: 50.0 - description: 加速度 (mm/s²) - name: acceleration - type: number - - default: 50.0 - description: 安全高度 (mm) - name: safe_height - type: number - - default: 10.0 - description: 吸头拾取深度 (mm) - name: tip_pickup_depth - type: number - - default: true - description: 液面检测功能 - name: liquid_detection - type: boolean - - default: 10.0 - description: X轴最小安全边距 (mm) - name: safety_margin_x_min - type: number - - default: 10.0 - description: X轴最大安全边距 (mm) - name: safety_margin_x_max - type: number - - default: 10.0 - description: Y轴最小安全边距 (mm) - name: safety_margin_y_min - type: number - - default: 10.0 - description: Y轴最大安全边距 (mm) - name: safety_margin_y_max - type: number - - default: 20.0 - description: Z轴安全间隙 (mm) - name: safety_margin_z_clearance - type: number - description: LaiYu液体处理工作站,基于RS485通信协议的自动化液体处理设备。集成XYZ三轴运动平台和SOPA气动式移液器,支持精确的液体分配和转移操作。具备完整的硬件控制、资源管理和标准化接口,适用于实验室自动化液体处理、样品制备、试剂分配等应用场景。设备通过RS485总线控制步进电机和移液器,提供高精度的位置控制和液体处理能力。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - config: - type: string - required: [] - type: object - data: - properties: - current_position: - items: - type: number - type: array - current_volume: - type: number - is_connected: - type: boolean - is_initialized: - type: boolean - status: - type: object - tip_attached: - type: boolean - required: - - current_position - - current_volume - - is_connected - - is_initialized - - tip_attached - - status - type: object - model: - mesh: laiyu_liquid_handler - type: device - version: 1.0.0 diff --git a/unilabos/registry/devices/liquid_handler.yaml b/unilabos/registry/devices/liquid_handler.yaml deleted file mode 100644 index fdfb6b5..0000000 --- a/unilabos/registry/devices/liquid_handler.yaml +++ /dev/null @@ -1,9956 +0,0 @@ -liquid_handler: - category: - - liquid_handler - class: - action_value_mappings: - add_liquid: - feedback: {} - goal: - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - dis_vols: dis_vols - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - reagent_sources: reagent_sources - spread: spread - targets: targets - use_channels: use_channels - goal_default: - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - dis_vols: - - 0.0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - reagent_sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - reagent_sources: unilabos_resources - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAdd_Feedback - type: object - goal: - properties: - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - reagent_sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: reagent_sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - reagent_sources - - targets - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_time - - mix_vol - - mix_rate - - mix_liquid_height - - none_keys - title: LiquidHandlerAdd_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAdd_Result - type: object - required: - - goal - title: LiquidHandlerAdd - type: object - type: LiquidHandlerAdd - aspirate: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - liquid_height: liquid_height - offsets: offsets - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0.0 - flow_rates: - - 0.0 - liquid_height: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAspirate_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - liquid_height: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - title: LiquidHandlerAspirate_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAspirate_Result - type: object - required: - - goal - title: LiquidHandlerAspirate - type: object - type: LiquidHandlerAspirate - auto-create_protocol: - feedback: {} - goal: {} - goal_default: - none_keys: [] - protocol_author: null - protocol_date: null - protocol_description: null - protocol_name: null - protocol_type: null - protocol_version: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: 创建实验协议函数。用于建立新的液体处理实验协议,定义协议名称、描述、版本、作者、日期等基本信息。该函数支持协议模板化管理,便于实验流程的标准化和重复性。适用于实验设计、方法开发、标准操作程序建立等需要协议管理的应用场景。 - properties: - feedback: {} - goal: - properties: - none_keys: - default: [] - type: string - protocol_author: - type: string - protocol_date: - type: string - protocol_description: - type: string - protocol_name: - type: string - protocol_type: - type: string - protocol_version: - type: string - required: - - protocol_name - - protocol_description - - protocol_version - - protocol_author - - protocol_date - - protocol_type - type: object - result: {} - required: - - goal - title: create_protocol参数 - type: object - type: UniLabJsonCommandAsync - auto-custom_delay: - feedback: {} - goal: {} - goal_default: - msg: null - seconds: 0 - handles: {} - placeholder_keys: {} - result: {} - schema: - description: 自定义延时函数。在实验流程中插入可配置的等待时间,用于满足特定的反应时间、孵育时间或设备稳定时间要求。支持自定义延时消息和秒数设置,提供流程控制和时间管理功能。适用于酶反应等待、温度平衡、样品孵育等需要时间控制的实验步骤。 - properties: - feedback: {} - goal: - properties: - msg: - type: string - seconds: - default: 0 - type: string - required: [] - type: object - result: {} - required: - - goal - title: custom_delay参数 - type: object - type: UniLabJsonCommandAsync - auto-iter_tips: - feedback: {} - goal: {} - goal_default: - tip_racks: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: 吸头迭代函数。用于自动管理和切换吸头架中的吸头,实现批量实验中的吸头自动分配和追踪。该函数监控吸头使用状态,自动切换到下一个可用吸头位置,确保实验流程的连续性。适用于高通量实验、批量处理、自动化流水线等需要大量吸头管理的应用场景。 - properties: - feedback: {} - goal: - properties: - tip_racks: - type: string - required: - - tip_racks - type: object - result: {} - required: - - goal - title: iter_tips参数 - type: object - type: UniLabJsonCommand - auto-post_init: - feedback: {} - goal: {} - goal_default: - ros_node: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - ros_node: - type: string - required: - - ros_node - type: object - result: {} - required: - - goal - title: post_init参数 - type: object - type: UniLabJsonCommand - auto-set_group: - feedback: {} - goal: {} - goal_default: - group_name: null - volumes: null - wells: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - group_name: - type: string - volumes: - type: string - wells: - type: string - required: - - group_name - - wells - - volumes - type: object - result: {} - required: - - goal - title: set_group参数 - type: object - type: UniLabJsonCommand - auto-set_tiprack: - feedback: {} - goal: {} - goal_default: - tip_racks: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: 吸头架设置函数。用于配置和初始化液体处理系统的吸头架信息,包括吸头架位置、类型、容量等参数。该函数建立吸头资源管理系统,为后续的吸头选择和使用提供基础配置。适用于系统初始化、吸头架更换、实验配置等需要吸头资源管理的操作场景。 - properties: - feedback: {} - goal: - properties: - tip_racks: - type: string - required: - - tip_racks - type: object - result: {} - required: - - goal - title: set_tiprack参数 - type: object - type: UniLabJsonCommand - auto-touch_tip: - feedback: {} - goal: {} - goal_default: - targets: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: 吸头碰触函数。控制移液器吸头轻触容器边缘或底部,用于去除吸头外壁附着的液滴,提高移液精度和减少污染。该函数支持多目标位置操作,可配置碰触参数和位置偏移。适用于精密移液、减少液体残留、防止交叉污染等需要提高移液质量的实验操作。 - properties: - feedback: {} - goal: - properties: - targets: - type: string - required: - - targets - type: object - result: {} - required: - - goal - title: touch_tip参数 - type: object - type: UniLabJsonCommandAsync - auto-transfer_group: - feedback: {} - goal: {} - goal_default: - source_group_name: null - target_group_name: null - unit_volume: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - source_group_name: - type: string - target_group_name: - type: string - unit_volume: - type: number - required: - - source_group_name - - target_group_name - - unit_volume - type: object - result: {} - required: - - goal - title: transfer_group参数 - type: object - type: UniLabJsonCommandAsync - discard_tips: - feedback: {} - goal: - use_channels: use_channels - goal_default: - use_channels: - - 0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDiscardTips_Feedback - type: object - goal: - properties: - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - use_channels - title: LiquidHandlerDiscardTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDiscardTips_Result - type: object - required: - - goal - title: LiquidHandlerDiscardTips - type: object - type: LiquidHandlerDiscardTips - dispense: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - offsets: offsets - resources: resources - spread: spread - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0 - flow_rates: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDispense_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - blow_out_air_volume - - spread - title: LiquidHandlerDispense_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDispense_Result - type: object - required: - - goal - title: LiquidHandlerDispense - type: object - type: LiquidHandlerDispense - drop_tips: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - allow_nonzero_volume: false - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_spots: unilabos_resources - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDropTips_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - - allow_nonzero_volume - title: LiquidHandlerDropTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDropTips_Result - type: object - required: - - goal - title: LiquidHandlerDropTips - type: object - type: LiquidHandlerDropTips - drop_tips96: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - offset: offset - tip_rack: tip_rack - goal_default: - allow_nonzero_volume: false - offset: - x: 0.0 - y: 0.0 - z: 0.0 - tip_rack: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDropTips96_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offset - type: object - tip_rack: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_rack - type: object - required: - - tip_rack - - offset - - allow_nonzero_volume - title: LiquidHandlerDropTips96_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDropTips96_Result - type: object - required: - - goal - title: LiquidHandlerDropTips96 - type: object - type: LiquidHandlerDropTips96 - mix: - feedback: {} - goal: - height_to_bottom: height_to_bottom - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - targets: targets - goal_default: - height_to_bottom: 0.0 - mix_rate: 0.0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMix_Feedback - type: object - goal: - properties: - height_to_bottom: - type: number - mix_rate: - type: number - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - required: - - targets - - mix_time - - mix_vol - - height_to_bottom - - offsets - - mix_rate - - none_keys - title: LiquidHandlerMix_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMix_Result - type: object - required: - - goal - title: LiquidHandlerMix - type: object - type: LiquidHandlerMix - move_lid: - feedback: {} - goal: - destination_offset: destination_offset - drop_direction: drop_direction - get_direction: get_direction - intermediate_locations: intermediate_locations - lid: lid - pickup_direction: pickup_direction - pickup_distance_from_top: pickup_distance_from_top - put_direction: put_direction - resource_offset: resource_offset - to: to - goal_default: - destination_offset: - x: 0.0 - y: 0.0 - z: 0.0 - drop_direction: '' - get_direction: '' - intermediate_locations: - - x: 0.0 - y: 0.0 - z: 0.0 - lid: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - pickup_direction: '' - pickup_distance_from_top: 0.0 - put_direction: '' - resource_offset: - x: 0.0 - y: 0.0 - z: 0.0 - to: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMoveLid_Feedback - type: object - goal: - properties: - destination_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: destination_offset - type: object - drop_direction: - type: string - get_direction: - type: string - intermediate_locations: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: intermediate_locations - type: object - type: array - lid: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: lid - type: object - pickup_direction: - type: string - pickup_distance_from_top: - type: number - put_direction: - type: string - resource_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: resource_offset - type: object - to: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: to - type: object - required: - - lid - - to - - intermediate_locations - - resource_offset - - destination_offset - - pickup_direction - - drop_direction - - get_direction - - put_direction - - pickup_distance_from_top - title: LiquidHandlerMoveLid_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMoveLid_Result - type: object - required: - - goal - title: LiquidHandlerMoveLid - type: object - type: LiquidHandlerMoveLid - move_plate: - feedback: {} - goal: - destination_offset: destination_offset - drop_direction: drop_direction - get_direction: get_direction - intermediate_locations: intermediate_locations - pickup_direction: pickup_direction - pickup_offset: pickup_offset - plate: plate - put_direction: put_direction - resource_offset: resource_offset - to: to - goal_default: - destination_offset: - x: 0.0 - y: 0.0 - z: 0.0 - drop_direction: '' - get_direction: '' - intermediate_locations: - - x: 0.0 - y: 0.0 - z: 0.0 - pickup_direction: '' - pickup_distance_from_top: 0.0 - pickup_offset: - x: 0.0 - y: 0.0 - z: 0.0 - plate: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - put_direction: '' - resource_offset: - x: 0.0 - y: 0.0 - z: 0.0 - to: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMovePlate_Feedback - type: object - goal: - properties: - destination_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: destination_offset - type: object - drop_direction: - type: string - get_direction: - type: string - intermediate_locations: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: intermediate_locations - type: object - type: array - pickup_direction: - type: string - pickup_distance_from_top: - type: number - pickup_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: pickup_offset - type: object - plate: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: plate - type: object - put_direction: - type: string - resource_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: resource_offset - type: object - to: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: to - type: object - required: - - plate - - to - - intermediate_locations - - resource_offset - - pickup_offset - - destination_offset - - pickup_direction - - drop_direction - - get_direction - - put_direction - - pickup_distance_from_top - title: LiquidHandlerMovePlate_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMovePlate_Result - type: object - required: - - goal - title: LiquidHandlerMovePlate - type: object - type: LiquidHandlerMovePlate - move_resource: - feedback: {} - goal: - destination_offset: destination_offset - drop_direction: drop_direction - get_direction: get_direction - intermediate_locations: intermediate_locations - pickup_direction: pickup_direction - pickup_distance_from_top: pickup_distance_from_top - put_direction: put_direction - resource: resource - resource_offset: resource_offset - to: to - goal_default: - destination_offset: - x: 0.0 - y: 0.0 - z: 0.0 - drop_direction: '' - get_direction: '' - intermediate_locations: - - x: 0.0 - y: 0.0 - z: 0.0 - pickup_direction: '' - pickup_distance_from_top: 0.0 - put_direction: '' - resource: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - resource_offset: - x: 0.0 - y: 0.0 - z: 0.0 - to: - x: 0.0 - y: 0.0 - z: 0.0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMoveResource_Feedback - type: object - goal: - properties: - destination_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: destination_offset - type: object - drop_direction: - type: string - get_direction: - type: string - intermediate_locations: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: intermediate_locations - type: object - type: array - pickup_direction: - type: string - pickup_distance_from_top: - type: number - put_direction: - type: string - resource: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resource - type: object - resource_offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: resource_offset - type: object - to: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: to - type: object - required: - - resource - - to - - intermediate_locations - - resource_offset - - destination_offset - - pickup_distance_from_top - - pickup_direction - - drop_direction - - get_direction - - put_direction - title: LiquidHandlerMoveResource_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMoveResource_Result - type: object - required: - - goal - title: LiquidHandlerMoveResource - type: object - type: LiquidHandlerMoveResource - move_to: - feedback: {} - goal: - channel: channel - dis_to_top: dis_to_top - well: well - goal_default: - channel: 0 - dis_to_top: 0.0 - well: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMoveTo_Feedback - type: object - goal: - properties: - channel: - maximum: 2147483647 - minimum: -2147483648 - type: integer - dis_to_top: - type: number - well: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: well - type: object - required: - - well - - dis_to_top - - channel - title: LiquidHandlerMoveTo_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMoveTo_Result - type: object - required: - - goal - title: LiquidHandlerMoveTo - type: object - type: LiquidHandlerMoveTo - pick_up_tips: - feedback: {} - goal: - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerPickUpTips_Feedback - type: object - goal: - properties: - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - title: LiquidHandlerPickUpTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerPickUpTips_Result - type: object - required: - - goal - title: LiquidHandlerPickUpTips - type: object - type: LiquidHandlerPickUpTips - pick_up_tips96: - feedback: {} - goal: - offset: offset - tip_rack: tip_rack - goal_default: - offset: - x: 0.0 - y: 0.0 - z: 0.0 - tip_rack: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerPickUpTips96_Feedback - type: object - goal: - properties: - offset: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offset - type: object - tip_rack: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_rack - type: object - required: - - tip_rack - - offset - title: LiquidHandlerPickUpTips96_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerPickUpTips96_Result - type: object - required: - - goal - title: LiquidHandlerPickUpTips96 - type: object - type: LiquidHandlerPickUpTips96 - remove: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - delays: delays - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - top: top - use_channels: use_channels - vols: vols - waste_liquid: waste_liquid - goal_default: - blow_out_air_volume: - - 0.0 - delays: - - 0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - top: - - 0.0 - use_channels: - - 0 - vols: - - 0.0 - waste_liquid: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerRemove_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - top: - items: - type: number - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - waste_liquid: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: waste_liquid - type: object - required: - - vols - - sources - - waste_liquid - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - delays - - is_96_well - - top - - none_keys - title: LiquidHandlerRemove_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerRemove_Result - type: object - required: - - goal - title: LiquidHandlerRemove - type: object - type: LiquidHandlerRemove - remove_liquid: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - delays: delays - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - top: top - use_channels: use_channels - vols: vols - waste_liquid: waste_liquid - goal_default: - blow_out_air_volume: - - 0.0 - delays: - - 0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - top: - - 0.0 - use_channels: - - 0 - vols: - - 0.0 - waste_liquid: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - sources: unilabos_resources - waste_liquid: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerRemove_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - top: - items: - type: number - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - waste_liquid: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: waste_liquid - type: object - required: - - vols - - sources - - waste_liquid - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - delays - - is_96_well - - top - - none_keys - title: LiquidHandlerRemove_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerRemove_Result - type: object - required: - - goal - title: LiquidHandlerRemove - type: object - type: LiquidHandlerRemove - return_tips: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - use_channels: use_channels - goal_default: - allow_nonzero_volume: false - use_channels: - - 0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerReturnTips_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - use_channels - - allow_nonzero_volume - title: LiquidHandlerReturnTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerReturnTips_Result - type: object - required: - - goal - title: LiquidHandlerReturnTips - type: object - type: LiquidHandlerReturnTips - return_tips96: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - goal_default: - allow_nonzero_volume: false - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerReturnTips96_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - required: - - allow_nonzero_volume - title: LiquidHandlerReturnTips96_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerReturnTips96_Result - type: object - required: - - goal - title: LiquidHandlerReturnTips96 - type: object - type: LiquidHandlerReturnTips96 - stamp: - feedback: {} - goal: - aspiration_flow_rate: aspiration_flow_rate - dispense_flow_rate: dispense_flow_rate - source: source - target: target - volume: volume - goal_default: - aspiration_flow_rate: 0.0 - dispense_flow_rate: 0.0 - source: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - target: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - volume: 0.0 - handles: {} - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerStamp_Feedback - type: object - goal: - properties: - aspiration_flow_rate: - type: number - dispense_flow_rate: - type: number - source: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: source - type: object - target: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: target - type: object - volume: - type: number - required: - - source - - target - - volume - - aspiration_flow_rate - - dispense_flow_rate - title: LiquidHandlerStamp_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerStamp_Result - type: object - required: - - goal - title: LiquidHandlerStamp - type: object - type: LiquidHandlerStamp - transfer: - goal: - aspiration_flow_rate: aspiration_flow_rate - dispense_flow_rates: dispense_flow_rates - ratios: ratios - source: source - source_vol: source_vol - target_vols: target_vols - targets: targets - goal_default: - amount: '' - from_vessel: '' - rinsing_repeats: 0 - rinsing_solvent: '' - rinsing_volume: 0.0 - solid: false - time: 0.0 - to_vessel: '' - viscous: false - volume: 0.0 - handles: {} - schema: - description: '' - properties: - feedback: - properties: - current_status: - type: string - progress: - type: number - transferred_volume: - type: number - required: - - progress - - transferred_volume - - current_status - title: Transfer_Feedback - type: object - goal: - properties: - amount: - type: string - from_vessel: - type: string - rinsing_repeats: - maximum: 2147483647 - minimum: -2147483648 - type: integer - rinsing_solvent: - type: string - rinsing_volume: - type: number - solid: - type: boolean - time: - type: number - to_vessel: - type: string - viscous: - type: boolean - volume: - type: number - required: - - from_vessel - - to_vessel - - volume - - amount - - time - - viscous - - rinsing_solvent - - rinsing_volume - - rinsing_repeats - - solid - title: Transfer_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: Transfer_Result - type: object - required: - - goal - title: Transfer - type: object - type: Transfer - transfer_liquid: - feedback: {} - goal: - asp_flow_rates: asp_flow_rates - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - delays: delays - dis_flow_rates: dis_flow_rates - dis_vols: dis_vols - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_stage: mix_stage - mix_times: mix_times - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - targets: targets - tip_racks: tip_racks - touch_tip: touch_tip - use_channels: use_channels - goal_default: - asp_flow_rates: - - 0.0 - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - delays: - - 0 - dis_flow_rates: - - 0.0 - dis_vols: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_stage: '' - mix_times: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - tip_racks: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - touch_tip: false - use_channels: - - 0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets - label: targets - - data_key: liquid - data_source: executor - data_type: resource - handler_key: tip_rack - label: tip_rack - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources_out - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets_out - label: targets - placeholder_keys: - sources: unilabos_resources - targets: unilabos_resources - tip_racks: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerTransfer_Feedback - type: object - goal: - properties: - asp_flow_rates: - items: - type: number - type: array - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - dis_flow_rates: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_stage: - type: string - mix_times: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - tip_racks: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_racks - type: object - type: array - touch_tip: - type: boolean - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - sources - - targets - - tip_racks - - use_channels - - asp_flow_rates - - dis_flow_rates - - offsets - - touch_tip - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_stage - - mix_times - - mix_vol - - mix_rate - - mix_liquid_height - - delays - - none_keys - title: LiquidHandlerTransfer_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerTransfer_Result - type: object - required: - - goal - title: LiquidHandlerTransfer - type: object - type: LiquidHandlerTransfer - module: unilabos.devices.liquid_handling.liquid_handler_abstract:LiquidHandlerAbstract - status_types: {} - type: python - config_info: [] - description: Liquid handler device controlled by pylabrobot - handles: [] - icon: icon_yiyezhan.webp - init_param_schema: - config: - properties: - backend: - type: string - channel_num: - default: 8 - type: integer - deck: - type: string - simulator: - default: false - type: boolean - required: - - backend - - deck - type: object - data: - properties: {} - required: [] - type: object - version: 1.0.0 -liquid_handler.biomek: - category: - - liquid_handler - class: - action_value_mappings: - auto-create_resource: - feedback: {} - goal: {} - goal_default: - bind_location: null - bind_parent_id: null - liquid_input_slot: null - liquid_type: null - liquid_volume: null - resource_tracker: null - resources: null - slot_on_deck: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: create_resource的参数schema - properties: - feedback: {} - goal: - properties: - bind_location: - type: object - bind_parent_id: - type: string - liquid_input_slot: - items: - type: integer - type: array - liquid_type: - items: - type: string - type: array - liquid_volume: - items: - type: integer - type: array - resource_tracker: - type: object - resources: - items: - type: object - type: array - slot_on_deck: - type: integer - required: - - resource_tracker - - resources - - bind_parent_id - - bind_location - - liquid_input_slot - - liquid_type - - liquid_volume - - slot_on_deck - type: object - result: {} - required: - - goal - title: create_resource参数 - type: object - type: UniLabJsonCommand - auto-instrument_setup_biomek: - feedback: {} - goal: {} - goal_default: - class_name: null - id: null - liquid_input_wells: null - liquid_type: null - liquid_volume: null - parent: null - slot_on_deck: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: instrument_setup_biomek的参数schema - properties: - feedback: {} - goal: - properties: - class_name: - type: string - id: - type: string - liquid_input_wells: - items: - type: string - type: array - liquid_type: - items: - type: string - type: array - liquid_volume: - items: - type: integer - type: array - parent: - type: string - slot_on_deck: - type: string - required: - - id - - parent - - slot_on_deck - - class_name - - liquid_type - - liquid_volume - - liquid_input_wells - type: object - result: {} - required: - - goal - title: instrument_setup_biomek参数 - type: object - type: UniLabJsonCommand - create_protocol: - feedback: {} - goal: - none_keys: none_keys - protocol_author: protocol_author - protocol_date: protocol_date - protocol_description: protocol_description - protocol_name: protocol_name - protocol_type: protocol_type - protocol_version: protocol_version - goal_default: - none_keys: - - '' - protocol_author: '' - protocol_date: '' - protocol_description: '' - protocol_name: '' - protocol_type: '' - protocol_version: '' - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerProtocolCreation_Feedback - type: object - goal: - properties: - none_keys: - items: - type: string - type: array - protocol_author: - type: string - protocol_date: - type: string - protocol_description: - type: string - protocol_name: - type: string - protocol_type: - type: string - protocol_version: - type: string - required: - - protocol_name - - protocol_description - - protocol_version - - protocol_author - - protocol_date - - protocol_type - - none_keys - title: LiquidHandlerProtocolCreation_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: LiquidHandlerProtocolCreation_Result - type: object - required: - - goal - title: LiquidHandlerProtocolCreation - type: object - type: LiquidHandlerProtocolCreation - incubation_biomek: - feedback: {} - goal: - time: time - goal_default: - time: 0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: plate - label: plate - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: plate_out - label: plate - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerIncubateBiomek_Feedback - type: object - goal: - properties: - time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - required: - - time - title: LiquidHandlerIncubateBiomek_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerIncubateBiomek_Result - type: object - required: - - goal - title: LiquidHandlerIncubateBiomek - type: object - type: LiquidHandlerIncubateBiomek - move_biomek: - feedback: {} - goal: - source: sources - target: targets - goal_default: - sources: '' - targets: '' - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources - label: sources - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: targets - label: targets - result: - name: name - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMoveBiomek_Feedback - type: object - goal: - properties: - sources: - type: string - targets: - type: string - required: - - sources - - targets - title: LiquidHandlerMoveBiomek_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMoveBiomek_Result - type: object - required: - - goal - title: LiquidHandlerMoveBiomek - type: object - type: LiquidHandlerMoveBiomek - oscillation_biomek: - feedback: {} - goal: - rpm: rpm - time: time - goal_default: - rpm: 0 - time: 0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: plate - label: plate - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: plate_out - label: plate - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerOscillateBiomek_Feedback - type: object - goal: - properties: - rpm: - maximum: 2147483647 - minimum: -2147483648 - type: integer - time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - required: - - rpm - - time - title: LiquidHandlerOscillateBiomek_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerOscillateBiomek_Result - type: object - required: - - goal - title: LiquidHandlerOscillateBiomek - type: object - type: LiquidHandlerOscillateBiomek - run_protocol: - feedback: {} - goal: {} - goal_default: {} - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - transfer_biomek: - feedback: {} - goal: - aspirate_techniques: aspirate_techniques - dispense_techniques: dispense_techniques - sources: sources - targets: targets - tip_rack: tip_rack - volume: volume - goal_default: - aspirate_technique: '' - dispense_technique: '' - sources: '' - targets: '' - tip_rack: '' - volume: 0.0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets - label: targets - - data_key: liquid - data_source: executor - data_type: resource - handler_key: tip_rack - label: tip_rack - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources_out - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets_out - label: targets - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerTransferBiomek_Feedback - type: object - goal: - properties: - aspirate_technique: - type: string - dispense_technique: - type: string - sources: - type: string - targets: - type: string - tip_rack: - type: string - volume: - type: number - required: - - sources - - targets - - tip_rack - - volume - - aspirate_technique - - dispense_technique - title: LiquidHandlerTransferBiomek_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerTransferBiomek_Result - type: object - required: - - goal - title: LiquidHandlerTransferBiomek - type: object - type: LiquidHandlerTransferBiomek - transfer_liquid: - feedback: {} - goal: - asp_flow_rates: asp_flow_rates - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - delays: delays - dis_flow_rates: dis_flow_rates - dis_vols: dis_vols - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_stage: mix_stage - mix_times: mix_times - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - targets: targets - tip_racks: tip_racks - touch_tip: touch_tip - use_channels: use_channels - goal_default: - asp_flow_rates: - - 0.0 - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - delays: - - 0 - dis_flow_rates: - - 0.0 - dis_vols: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_stage: '' - mix_times: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - tip_racks: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - touch_tip: false - use_channels: - - 0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: liquid-input - io_type: target - label: Liquid Input - output: - - data_key: liquid - data_source: executor - data_type: resource - handler_key: liquid-output - io_type: source - label: Liquid Output - placeholder_keys: - sources: unilabos_resources - targets: unilabos_resources - tip_racks: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerTransfer_Feedback - type: object - goal: - properties: - asp_flow_rates: - items: - type: number - type: array - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - dis_flow_rates: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_stage: - type: string - mix_times: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - tip_racks: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_racks - type: object - type: array - touch_tip: - type: boolean - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - sources - - targets - - tip_racks - - use_channels - - asp_flow_rates - - dis_flow_rates - - offsets - - touch_tip - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_stage - - mix_times - - mix_vol - - mix_rate - - mix_liquid_height - - delays - - none_keys - title: LiquidHandlerTransfer_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerTransfer_Result - type: object - required: - - goal - title: LiquidHandlerTransfer - type: object - type: LiquidHandlerTransfer - module: unilabos.devices.liquid_handling.biomek:LiquidHandlerBiomek - status_types: - success: String - type: python - config_info: [] - description: Biomek液体处理器设备,基于pylabrobot控制 - handles: [] - icon: icon_yiyezhan.webp - init_param_schema: - config: - properties: {} - required: [] - type: object - data: - properties: - success: - type: string - required: - - success - type: object - version: 1.0.0 -liquid_handler.laiyu: - category: - - liquid_handler - class: - action_value_mappings: - add_liquid: - feedback: {} - goal: - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - dis_vols: dis_vols - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - reagent_sources: reagent_sources - spread: spread - targets: targets - use_channels: use_channels - goal_default: - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - dis_vols: - - 0.0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - reagent_sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - reagent_sources: unilabos_resources - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAdd_Feedback - type: object - goal: - properties: - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - reagent_sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: reagent_sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - reagent_sources - - targets - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_time - - mix_vol - - mix_rate - - mix_liquid_height - - none_keys - title: LiquidHandlerAdd_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAdd_Result - type: object - required: - - goal - title: LiquidHandlerAdd - type: object - type: LiquidHandlerAdd - aspirate: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - liquid_height: liquid_height - offsets: offsets - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0.0 - flow_rates: - - 0.0 - liquid_height: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAspirate_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - liquid_height: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - title: LiquidHandlerAspirate_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAspirate_Result - type: object - required: - - goal - title: LiquidHandlerAspirate - type: object - type: LiquidHandlerAspirate - auto-transfer_liquid: - feedback: {} - goal: {} - goal_default: - asp_flow_rates: null - asp_vols: null - blow_out_air_volume: null - delays: null - dis_flow_rates: null - dis_vols: null - is_96_well: false - liquid_height: null - mix_liquid_height: null - mix_rate: null - mix_stage: none - mix_times: null - mix_vol: null - none_keys: [] - offsets: null - sources: null - spread: wide - targets: null - tip_racks: null - touch_tip: false - use_channels: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - asp_flow_rates: - type: string - asp_vols: - type: string - blow_out_air_volume: - type: string - delays: - type: string - dis_flow_rates: - type: string - dis_vols: - type: string - is_96_well: - default: false - type: boolean - liquid_height: - type: string - mix_liquid_height: - type: string - mix_rate: - type: string - mix_stage: - default: none - type: string - mix_times: - type: string - mix_vol: - type: string - none_keys: - default: [] - items: - type: string - type: array - offsets: - type: string - sources: - type: string - spread: - default: wide - type: string - targets: - type: string - tip_racks: - type: string - touch_tip: - default: false - type: boolean - use_channels: - type: string - required: - - sources - - targets - - tip_racks - - asp_vols - - dis_vols - type: object - result: {} - required: - - goal - title: transfer_liquid参数 - type: object - type: UniLabJsonCommandAsync - dispense: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - liquid_height: liquid_height - offsets: offsets - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0 - flow_rates: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDispense_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - blow_out_air_volume - - spread - title: LiquidHandlerDispense_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDispense_Result - type: object - required: - - goal - title: LiquidHandlerDispense - type: object - type: LiquidHandlerDispense - drop_tips: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - allow_nonzero_volume: false - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_spots: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDropTips_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - - allow_nonzero_volume - title: LiquidHandlerDropTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDropTips_Result - type: object - required: - - goal - title: LiquidHandlerDropTips - type: object - type: LiquidHandlerDropTips - mix: - feedback: {} - goal: - height_to_bottom: height_to_bottom - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - targets: targets - goal_default: - height_to_bottom: 0.0 - mix_rate: 0.0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMix_Feedback - type: object - goal: - properties: - height_to_bottom: - type: number - mix_rate: - type: number - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - required: - - targets - - mix_time - - mix_vol - - height_to_bottom - - offsets - - mix_rate - - none_keys - title: LiquidHandlerMix_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMix_Result - type: object - required: - - goal - title: LiquidHandlerMix - type: object - type: LiquidHandlerMix - pick_up_tips: - feedback: {} - goal: - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_spots: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerPickUpTips_Feedback - type: object - goal: - properties: - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - title: LiquidHandlerPickUpTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerPickUpTips_Result - type: object - required: - - goal - title: LiquidHandlerPickUpTips - type: object - type: LiquidHandlerPickUpTips - module: unilabos.devices.liquid_handling.laiyu.laiyu:TransformXYZHandler - properties: - support_touch_tip: bool - status_types: {} - type: python - config_info: [] - description: Laiyu液体处理器设备,基于pylabrobot控制 - handles: [] - icon: icon_yiyezhan.webp - init_param_schema: - config: - properties: - channel_num: - default: 1 - type: string - deck: - type: object - host: - default: 127.0.0.1 - type: string - port: - default: 9999 - type: integer - simulator: - default: true - type: string - timeout: - default: 10.0 - type: number - required: - - deck - type: object - data: - properties: {} - required: [] - type: object - version: 1.0.0 -liquid_handler.prcxi: - category: - - liquid_handler - class: - action_value_mappings: - add_liquid: - feedback: {} - goal: - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - dis_vols: dis_vols - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - reagent_sources: reagent_sources - spread: spread - targets: targets - use_channels: use_channels - goal_default: - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - dis_vols: - - 0.0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - reagent_sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - reagent_sources: unilabos_resources - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAdd_Feedback - type: object - goal: - properties: - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - reagent_sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: reagent_sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - reagent_sources - - targets - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_time - - mix_vol - - mix_rate - - mix_liquid_height - - none_keys - title: LiquidHandlerAdd_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAdd_Result - type: object - required: - - goal - title: LiquidHandlerAdd - type: object - type: LiquidHandlerAdd - aspirate: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - liquid_height: liquid_height - offsets: offsets - resources: resources - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0.0 - flow_rates: - - 0.0 - liquid_height: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerAspirate_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - flow_rates: - items: - type: number - type: array - liquid_height: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - title: LiquidHandlerAspirate_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerAspirate_Result - type: object - required: - - goal - title: LiquidHandlerAspirate - type: object - type: LiquidHandlerAspirate - auto-create_protocol: - feedback: {} - goal: {} - goal_default: - none_keys: [] - protocol_author: '' - protocol_date: '' - protocol_description: '' - protocol_name: '' - protocol_type: '' - protocol_version: '' - handles: {} - placeholder_keys: {} - result: {} - schema: - description: create_protocol的参数schema - properties: - feedback: {} - goal: - properties: - none_keys: - default: [] - items: - type: string - type: array - protocol_author: - default: '' - type: string - protocol_date: - default: '' - type: string - protocol_description: - default: '' - type: string - protocol_name: - default: '' - type: string - protocol_type: - default: '' - type: string - protocol_version: - default: '' - type: string - required: [] - type: object - result: {} - required: - - goal - title: create_protocol参数 - type: object - type: UniLabJsonCommandAsync - auto-custom_delay: - feedback: {} - goal: {} - goal_default: - msg: null - seconds: 0 - handles: {} - placeholder_keys: {} - result: {} - schema: - description: custom_delay的参数schema - properties: - feedback: {} - goal: - properties: - msg: - type: string - seconds: - default: 0 - type: string - required: [] - type: object - result: {} - required: - - goal - title: custom_delay参数 - type: object - type: UniLabJsonCommandAsync - auto-iter_tips: - feedback: {} - goal: {} - goal_default: - tip_racks: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: iter_tips的参数schema - properties: - feedback: {} - goal: - properties: - tip_racks: - type: string - required: - - tip_racks - type: object - result: {} - required: - - goal - title: iter_tips参数 - type: object - type: UniLabJsonCommand - auto-move_to: - feedback: {} - goal: {} - goal_default: - channel: 0 - dis_to_top: 0 - well: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: move_to的参数schema - properties: - feedback: {} - goal: - properties: - channel: - default: 0 - type: integer - dis_to_top: - default: 0 - type: number - well: - type: object - required: - - well - type: object - result: {} - required: - - goal - title: move_to参数 - type: object - type: UniLabJsonCommandAsync - auto-post_init: - feedback: {} - goal: {} - goal_default: - ros_node: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - ros_node: - type: object - required: - - ros_node - type: object - result: {} - required: - - goal - title: post_init参数 - type: object - type: UniLabJsonCommand - auto-run_protocol: - feedback: {} - goal: {} - goal_default: {} - handles: {} - placeholder_keys: {} - result: {} - schema: - description: run_protocol的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: run_protocol参数 - type: object - type: UniLabJsonCommandAsync - auto-set_group: - feedback: {} - goal: {} - goal_default: - group_name: null - volumes: null - wells: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - group_name: - type: string - volumes: - items: - type: number - type: array - wells: - items: - type: object - type: array - required: - - group_name - - wells - - volumes - type: object - result: {} - required: - - goal - title: set_group参数 - type: object - type: UniLabJsonCommand - auto-touch_tip: - feedback: {} - goal: {} - goal_default: - targets: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: touch_tip的参数schema - properties: - feedback: {} - goal: - properties: - targets: - type: string - required: - - targets - type: object - result: {} - required: - - goal - title: touch_tip参数 - type: object - type: UniLabJsonCommandAsync - auto-transfer_group: - feedback: {} - goal: {} - goal_default: - source_group_name: null - target_group_name: null - unit_volume: null - handles: {} - placeholder_keys: {} - result: {} - schema: - description: '' - properties: - feedback: {} - goal: - properties: - source_group_name: - type: string - target_group_name: - type: string - unit_volume: - type: number - required: - - source_group_name - - target_group_name - - unit_volume - type: object - result: {} - required: - - goal - title: transfer_group参数 - type: object - type: UniLabJsonCommandAsync - discard_tips: - feedback: {} - goal: - use_channels: use_channels - goal_default: - use_channels: - - 0 - handles: {} - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDiscardTips_Feedback - type: object - goal: - properties: - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - use_channels - title: LiquidHandlerDiscardTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDiscardTips_Result - type: object - required: - - goal - title: LiquidHandlerDiscardTips - type: object - type: LiquidHandlerDiscardTips - dispense: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - flow_rates: flow_rates - offsets: offsets - resources: resources - spread: spread - use_channels: use_channels - vols: vols - goal_default: - blow_out_air_volume: - - 0 - flow_rates: - - 0.0 - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - resources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - use_channels: - - 0 - vols: - - 0.0 - handles: {} - placeholder_keys: - resources: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDispense_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - resources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resources - type: object - type: array - spread: - type: string - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - required: - - resources - - vols - - use_channels - - flow_rates - - offsets - - blow_out_air_volume - - spread - title: LiquidHandlerDispense_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDispense_Result - type: object - required: - - goal - title: LiquidHandlerDispense - type: object - type: LiquidHandlerDispense - drop_tips: - feedback: {} - goal: - allow_nonzero_volume: allow_nonzero_volume - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - allow_nonzero_volume: false - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_spots: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerDropTips_Feedback - type: object - goal: - properties: - allow_nonzero_volume: - type: boolean - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - - allow_nonzero_volume - title: LiquidHandlerDropTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerDropTips_Result - type: object - required: - - goal - title: LiquidHandlerDropTips - type: object - type: LiquidHandlerDropTips - mix: - feedback: {} - goal: - height_to_bottom: height_to_bottom - mix_rate: mix_rate - mix_time: mix_time - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - targets: targets - goal_default: - height_to_bottom: 0.0 - mix_rate: 0.0 - mix_time: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - targets: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerMix_Feedback - type: object - goal: - properties: - height_to_bottom: - type: number - mix_rate: - type: number - mix_time: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - required: - - targets - - mix_time - - mix_vol - - height_to_bottom - - offsets - - mix_rate - - none_keys - title: LiquidHandlerMix_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerMix_Result - type: object - required: - - goal - title: LiquidHandlerMix - type: object - type: LiquidHandlerMix - pick_up_tips: - feedback: {} - goal: - offsets: offsets - tip_spots: tip_spots - use_channels: use_channels - goal_default: - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - tip_spots: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - use_channels: - - 0 - handles: {} - placeholder_keys: - tip_spots: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerPickUpTips_Feedback - type: object - goal: - properties: - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - tip_spots: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_spots - type: object - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - tip_spots - - use_channels - - offsets - title: LiquidHandlerPickUpTips_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerPickUpTips_Result - type: object - required: - - goal - title: LiquidHandlerPickUpTips - type: object - type: LiquidHandlerPickUpTips - remove_liquid: - feedback: {} - goal: - blow_out_air_volume: blow_out_air_volume - delays: delays - flow_rates: flow_rates - is_96_well: is_96_well - liquid_height: liquid_height - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - top: top - use_channels: use_channels - vols: vols - waste_liquid: waste_liquid - goal_default: - blow_out_air_volume: - - 0.0 - delays: - - 0 - flow_rates: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - top: - - 0.0 - use_channels: - - 0 - vols: - - 0.0 - waste_liquid: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - sources: unilabos_resources - waste_liquid: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerRemove_Feedback - type: object - goal: - properties: - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - flow_rates: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - top: - items: - type: number - type: array - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - vols: - items: - type: number - type: array - waste_liquid: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: waste_liquid - type: object - required: - - vols - - sources - - waste_liquid - - use_channels - - flow_rates - - offsets - - liquid_height - - blow_out_air_volume - - spread - - delays - - is_96_well - - top - - none_keys - title: LiquidHandlerRemove_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerRemove_Result - type: object - required: - - goal - title: LiquidHandlerRemove - type: object - type: LiquidHandlerRemove - set_liquid: - feedback: {} - goal: - liquid_names: liquid_names - volumes: volumes - wells: wells - goal_default: - liquid_names: - - '' - volumes: - - 0.0 - wells: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - wells: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerSetLiquid_Feedback - type: object - goal: - properties: - liquid_names: - items: - type: string - type: array - volumes: - items: - type: number - type: array - wells: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: wells - type: object - type: array - required: - - wells - - liquid_names - - volumes - title: LiquidHandlerSetLiquid_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: LiquidHandlerSetLiquid_Result - type: object - required: - - goal - title: LiquidHandlerSetLiquid - type: object - type: LiquidHandlerSetLiquid - set_tiprack: - feedback: {} - goal: - tip_racks: tip_racks - goal_default: - tip_racks: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: {} - placeholder_keys: - tip_racks: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerSetTipRack_Feedback - type: object - goal: - properties: - tip_racks: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_racks - type: object - type: array - required: - - tip_racks - title: LiquidHandlerSetTipRack_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerSetTipRack_Result - type: object - required: - - goal - title: LiquidHandlerSetTipRack - type: object - type: LiquidHandlerSetTipRack - transfer: - goal: - aspiration_flow_rate: aspiration_flow_rate - dispense_flow_rates: dispense_flow_rates - ratios: ratios - source: source - source_vol: source_vol - target_vols: target_vols - targets: targets - goal_default: - amount: '' - from_vessel: '' - rinsing_repeats: 0 - rinsing_solvent: '' - rinsing_volume: 0.0 - solid: false - time: 0.0 - to_vessel: '' - viscous: false - volume: 0.0 - handles: {} - schema: - description: '' - properties: - feedback: - properties: - current_status: - type: string - progress: - type: number - transferred_volume: - type: number - required: - - progress - - transferred_volume - - current_status - title: Transfer_Feedback - type: object - goal: - properties: - amount: - type: string - from_vessel: - type: string - rinsing_repeats: - maximum: 2147483647 - minimum: -2147483648 - type: integer - rinsing_solvent: - type: string - rinsing_volume: - type: number - solid: - type: boolean - time: - type: number - to_vessel: - type: string - viscous: - type: boolean - volume: - type: number - required: - - from_vessel - - to_vessel - - volume - - amount - - time - - viscous - - rinsing_solvent - - rinsing_volume - - rinsing_repeats - - solid - title: Transfer_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: Transfer_Result - type: object - required: - - goal - title: Transfer - type: object - type: Transfer - transfer_liquid: - feedback: {} - goal: - asp_flow_rates: asp_flow_rates - asp_vols: asp_vols - blow_out_air_volume: blow_out_air_volume - delays: delays - dis_flow_rates: dis_flow_rates - dis_vols: dis_vols - is_96_well: is_96_well - liquid_height: liquid_height - mix_liquid_height: mix_liquid_height - mix_rate: mix_rate - mix_stage: mix_stage - mix_times: mix_times - mix_vol: mix_vol - none_keys: none_keys - offsets: offsets - sources: sources - spread: spread - targets: targets - tip_racks: tip_racks - touch_tip: touch_tip - use_channels: use_channels - goal_default: - asp_flow_rates: - - 0.0 - asp_vols: - - 0.0 - blow_out_air_volume: - - 0.0 - delays: - - 0 - dis_flow_rates: - - 0.0 - dis_vols: - - 0.0 - is_96_well: false - liquid_height: - - 0.0 - mix_liquid_height: 0.0 - mix_rate: 0 - mix_stage: '' - mix_times: 0 - mix_vol: 0 - none_keys: - - '' - offsets: - - x: 0.0 - y: 0.0 - z: 0.0 - sources: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - spread: '' - targets: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - tip_racks: - - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - touch_tip: false - use_channels: - - 0 - handles: - input: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets - label: targets - - data_key: liquid - data_source: executor - data_type: resource - handler_key: tip_rack - label: tip_rack - output: - - data_key: liquid - data_source: handle - data_type: resource - handler_key: sources_out - label: sources - - data_key: liquid - data_source: executor - data_type: resource - handler_key: targets_out - label: targets - placeholder_keys: - sources: unilabos_resources - targets: unilabos_resources - tip_racks: unilabos_resources - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: LiquidHandlerTransfer_Feedback - type: object - goal: - properties: - asp_flow_rates: - items: - type: number - type: array - asp_vols: - items: - type: number - type: array - blow_out_air_volume: - items: - type: number - type: array - delays: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - dis_flow_rates: - items: - type: number - type: array - dis_vols: - items: - type: number - type: array - is_96_well: - type: boolean - liquid_height: - items: - type: number - type: array - mix_liquid_height: - type: number - mix_rate: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_stage: - type: string - mix_times: - maximum: 2147483647 - minimum: -2147483648 - type: integer - mix_vol: - maximum: 2147483647 - minimum: -2147483648 - type: integer - none_keys: - items: - type: string - type: array - offsets: - items: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: offsets - type: object - type: array - sources: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: sources - type: object - type: array - spread: - type: string - targets: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: targets - type: object - type: array - tip_racks: - items: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: tip_racks - type: object - type: array - touch_tip: - type: boolean - use_channels: - items: - maximum: 2147483647 - minimum: -2147483648 - type: integer - type: array - required: - - asp_vols - - dis_vols - - sources - - targets - - tip_racks - - use_channels - - asp_flow_rates - - dis_flow_rates - - offsets - - touch_tip - - liquid_height - - blow_out_air_volume - - spread - - is_96_well - - mix_stage - - mix_times - - mix_vol - - mix_rate - - mix_liquid_height - - delays - - none_keys - title: LiquidHandlerTransfer_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: LiquidHandlerTransfer_Result - type: object - required: - - goal - title: LiquidHandlerTransfer - type: object - type: LiquidHandlerTransfer - module: unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Handler - status_types: - reset_ok: bool - type: python - config_info: [] - description: prcxi液体处理器设备,基于pylabrobot控制 - handles: [] - icon: icon_yiyezhan.webp - init_param_schema: - config: - properties: - axis: - default: Left - type: string - channel_num: - default: 8 - type: string - debug: - default: false - type: string - deck: - type: object - host: - type: string - is_9320: - default: false - type: string - matrix_id: - default: '' - type: string - port: - type: integer - setup: - default: true - type: string - simulator: - default: false - type: string - step_mode: - default: false - type: string - timeout: - type: number - required: - - deck - - host - - port - - timeout - type: object - data: - properties: - reset_ok: - type: boolean - required: - - reset_ok - type: object - version: 1.0.0 -liquid_handler.revvity: - category: - - liquid_handler - class: - action_value_mappings: - run: - feedback: - status: status - goal: - params: params - resource: resource - wf_name: file_path - goal_default: - params: '' - resource: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - wf_name: '' - handles: {} - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - gantt: - type: string - status: - type: string - required: - - status - - gantt - title: WorkStationRun_Feedback - type: object - goal: - properties: - params: - type: string - resource: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - pose: - properties: - orientation: - properties: - w: - type: number - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - - w - title: orientation - type: object - position: - properties: - x: - type: number - y: - type: number - z: - type: number - required: - - x - - y - - z - title: position - type: object - required: - - position - - orientation - title: pose - type: object - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: resource - type: object - wf_name: - type: string - required: - - wf_name - - params - - resource - title: WorkStationRun_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: WorkStationRun_Result - type: object - required: - - goal - title: WorkStationRun - type: object - type: WorkStationRun - module: unilabos.devices.liquid_handling.revvity:Revvity - status_types: - status: str - success: bool - type: python - config_info: [] - description: '' - handles: [] - icon: '' - init_param_schema: - config: - properties: {} - required: [] - type: object - data: - properties: - status: - type: string - success: - type: boolean - required: - - success - - status - type: object - version: 1.0.0 diff --git a/unilabos/registry/resources/bioyond/deck.yaml b/unilabos/registry/resources/bioyond/deck.yaml index bc15850..9fc73f3 100644 --- a/unilabos/registry/resources/bioyond/deck.yaml +++ b/unilabos/registry/resources/bioyond/deck.yaml @@ -22,7 +22,7 @@ BIOYOND_PolymerReactionStation_Deck: init_param_schema: {} registry_type: resource version: 1.0.0 -YB_Deck11: +BIOYOND_YB_Deck: category: - deck class: @@ -34,3 +34,15 @@ YB_Deck11: init_param_schema: {} registry_type: resource version: 1.0.0 +CoincellDeck: + category: + - deck + class: + module: unilabos.devices.workstation.coin_cell_assembly.YB_YH_materials:YH_Deck + type: pylabrobot + description: BIOYOND PolymerReactionStation Deck + handles: [] + icon: koudian.webp + init_param_schema: {} + registry_type: resource + version: 1.0.0 diff --git a/unilabos/resources/battery/electrode_sheet.py b/unilabos/resources/battery/electrode_sheet.py index e86af24..22f98af 100644 --- a/unilabos/resources/battery/electrode_sheet.py +++ b/unilabos/resources/battery/electrode_sheet.py @@ -16,9 +16,12 @@ electrode_colors = { } class ElectrodeSheetState(TypedDict): + diameter: float # 直径 (mm) + thickness: float # 厚度 (mm) mass: float # 质量 (g) material_type: str # 材料类型(铜、铝、不锈钢、弹簧钢等) color: str # 材料类型对应的颜色 + info: Optional[str] # 附加信息 class ElectrodeSheet(ResourcePLR): @@ -27,18 +30,23 @@ class ElectrodeSheet(ResourcePLR): def __init__( self, name: str = "极片", - size_x=10, - size_y=10, - size_z=10, + size_x: float = 10, + size_y: float = 10, + size_z: float = 10, category: str = "electrode_sheet", model: Optional[str] = None, + **kwargs ): """初始化极片 Args: name: 极片名称 + size_x: 长度 (mm) + size_y: 宽度 (mm) + size_z: 高度 (mm) category: 类别 model: 型号 + **kwargs: 其他参数传递给父类 """ super().__init__( name=name, @@ -47,12 +55,14 @@ class ElectrodeSheet(ResourcePLR): size_z=size_z, category=category, model=model, + **kwargs ) self._unilabos_state: ElectrodeSheetState = ElectrodeSheetState( diameter=14, thickness=0.1, mass=0.5, material_type="copper", + color="#8b4513", info=None ) @@ -72,7 +82,7 @@ class ElectrodeSheet(ResourcePLR): def PositiveCan(name: str) -> ElectrodeSheet: """创建正极壳""" sheet = ElectrodeSheet(name=name, size_x=12, size_y=12, size_z=3.0, model="PositiveCan") - sheet.load_state({"material_type": "aluminum", "color": electrode_colors["PositiveCan"]}) + sheet.load_state({"diameter": 20.0, "thickness": 0.5, "mass": 0.5, "material_type": "aluminum", "color": electrode_colors["PositiveCan"], "info": None}) return sheet @@ -135,18 +145,23 @@ class Battery(Container): def __init__( self, name: str = "电池", - size_x=12, - size_y=12, - size_z=6, + size_x: float = 12, + size_y: float = 12, + size_z: float = 6, category: str = "battery", model: Optional[str] = None, + **kwargs ): """初始化电池 Args: name: 电池名称 + size_x: 长度 (mm) + size_y: 宽度 (mm) + size_z: 高度 (mm) category: 类别 model: 型号 + **kwargs: 其他参数传递给父类 """ super().__init__( name=name, @@ -155,6 +170,7 @@ class Battery(Container): size_z=size_z, category=category, model=model, + **kwargs ) self._unilabos_state: BatteryState = BatteryState( color=electrode_colors["Battery"], diff --git a/unilabos/resources/bioyond/decks.py b/unilabos/resources/bioyond/decks.py index 5572536..67e6d79 100644 --- a/unilabos/resources/bioyond/decks.py +++ b/unilabos/resources/bioyond/decks.py @@ -1,7 +1,7 @@ from os import name from pylabrobot.resources import Deck, Coordinate, Rotation -from unilabos.resources.bioyond.warehouses import ( +from unilabos.resources.bioyond.YB_warehouses import ( bioyond_warehouse_1x4x4, bioyond_warehouse_1x4x4_right, # 新增:右侧仓库 (A05~D08) bioyond_warehouse_1x4x2,