Files
Uni-Lab-OS/unilabos/devices/laiyu_liquid/docs/hardware/硬件连接配置指南.md
Xuwznln 9aeffebde1 0.10.7 Update (#101)
* Cleanup registry to be easy-understanding (#76)

* delete deprecated mock devices

* rename categories

* combine chromatographic devices

* rename rviz simulation nodes

* organic virtual devices

* parse vessel_id

* run registry completion before merge

---------

Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com>

* fix: workstation handlers and vessel_id parsing

* fix: working dir error when input config path
feat: report publish topic when error

* modify default discovery_interval to 15s

* feat: add trace log level

* feat: 添加ChinWe设备控制类,支持串口通信和电机控制功能 (#79)

* fix: drop_tips not using auto resource select

* fix: discard_tips error

* fix: discard_tips

* fix: prcxi_res

* add: prcxi res
fix: startup slow

* feat: workstation example

* fix pumps and liquid_handler handle

* feat: 优化protocol node节点运行日志

* fix all protocol_compilers and remove deprecated devices

* feat: 新增use_remote_resource参数

* fix and remove redundant info

* bugfixes on organic protocols

* fix filter protocol

* fix protocol node

* 临时兼容错误的driver写法

* fix: prcxi import error

* use call_async in all service to avoid deadlock

* fix: figure_resource

* Update recipe.yaml

* add workstation template and battery example

* feat: add sk & ak

* update workstation base

* Create workstation_architecture.md

* refactor: workstation_base 重构为仅含业务逻辑,通信和子设备管理交给 ProtocolNode

* refactor: ProtocolNode→WorkstationNode

* Add:msgs.action (#83)

* update: Workstation dev 将版本号从 0.10.3 更新为 0.10.4 (#84)

* Add:msgs.action

* update: 将版本号从 0.10.3 更新为 0.10.4

* simplify resource system

* uncompleted refactor

* example for use WorkstationBase

* feat: websocket

* feat: websocket test

* feat: workstation example

* feat: action status

* fix: station自己的方法注册错误

* fix: 还原protocol node处理方法

* fix: build

* fix: missing job_id key

* ws test version 1

* ws test version 2

* ws protocol

* 增加物料关系上传日志

* 增加物料关系上传日志

* 修正物料关系上传

* 修复工站的tracker实例追踪失效问题

* 增加handle检测,增加material edge关系上传

* 修复event loop错误

* 修复edge上报错误

* 修复async错误

* 更新schema的title字段

* 主机节点信息等支持自动刷新

* 注册表编辑器

* 修复status密集发送时,消息出错

* 增加addr参数

* fix: addr param

* fix: addr param

* 取消labid 和 强制config输入

* Add action definitions for LiquidHandlerSetGroup and LiquidHandlerTransferGroup

- Created LiquidHandlerSetGroup.action with fields for group name, wells, and volumes.
- Created LiquidHandlerTransferGroup.action with fields for source and target group names and unit volume.
- Both actions include response fields for return information and success status.

* Add LiquidHandlerSetGroup and LiquidHandlerTransferGroup actions to CMakeLists

* Add set_group and transfer_group methods to PRCXI9300Handler and update liquid_handler.yaml

* result_info改为字典类型

* 新增uat的地址替换

* runze multiple pump support

(cherry picked from commit 49354fcf39)

* remove runze multiple software obtainer

(cherry picked from commit 8bcc92a394)

* support multiple backbone

(cherry picked from commit 4771ff2347)

* Update runze pump format

* Correct runze multiple backbone

* Update runze_multiple_backbone

* Correct runze pump multiple receive method.

* Correct runze pump multiple receive method.

* 对于PRCXI9320的transfer_group,一对多和多对多

* 移除MQTT,更新launch文档,提供注册表示例文件,更新到0.10.5

* fix import error

* fix dupe upload registry

* refactor ws client

* add server timeout

* Fix: run-column with correct vessel id (#86)

* fix run_column

* Update run_column_protocol.py

(cherry picked from commit e5aa4d940a)

* resource_update use resource_add

* 新增版位推荐功能

* 重新规定了版位推荐的入参

* update registry with nested obj

* fix protocol node log_message, added create_resource return value

* fix protocol node log_message, added create_resource return value

* try fix add protocol

* fix resource_add

* 修复移液站错误的aspirate注册表

* Feature/xprbalance-zhida (#80)

* feat(devices): add Zhida GC/MS pretreatment automation workstation

* feat(devices): add mettler_toledo xpr balance

* balance

* 重新补全zhida注册表

* PRCXI9320 json

* PRCXI9320 json

* PRCXI9320 json

* fix resource download

* remove class for resource

* bump version to 0.10.6

* 更新所有注册表

* 修复protocolnode的兼容性

* 修复protocolnode的兼容性

* Update install md

* Add Defaultlayout

* 更新物料接口

* fix dict to tree/nested-dict converter

* coin_cell_station draft

* refactor: rename "station_resource" to "deck"

* add standardized BIOYOND resources: bottle_carrier, bottle

* refactor and add BIOYOND resources tests

* add BIOYOND deck assignment and pass all tests

* fix: update resource with correct structure; remove deprecated liquid_handler set_group action

* feat: 将新威电池测试系统驱动与配置文件并入 workstation_dev_YB2 (#92)

* feat: 新威电池测试系统驱动与注册文件

* feat: bring neware driver & battery.json into workstation_dev_YB2

* add bioyond studio draft

* bioyond station with communication init and resource sync

* fix bioyond station and registry

* fix: update resource with correct structure; remove deprecated liquid_handler set_group action

* frontend_docs

* create/update resources with POST/PUT for big amount/ small amount data

* create/update resources with POST/PUT for big amount/ small amount data

* refactor: add itemized_carrier instead of carrier consists of ResourceHolder

* create warehouse by factory func

* update bioyond launch json

* add child_size for itemized_carrier

* fix bioyond resource io

* Workstation templates: Resources and its CRUD, and workstation tasks (#95)

* coin_cell_station draft

* refactor: rename "station_resource" to "deck"

* add standardized BIOYOND resources: bottle_carrier, bottle

* refactor and add BIOYOND resources tests

* add BIOYOND deck assignment and pass all tests

* fix: update resource with correct structure; remove deprecated liquid_handler set_group action

* feat: 将新威电池测试系统驱动与配置文件并入 workstation_dev_YB2 (#92)

* feat: 新威电池测试系统驱动与注册文件

* feat: bring neware driver & battery.json into workstation_dev_YB2

* add bioyond studio draft

* bioyond station with communication init and resource sync

* fix bioyond station and registry

* create/update resources with POST/PUT for big amount/ small amount data

* refactor: add itemized_carrier instead of carrier consists of ResourceHolder

* create warehouse by factory func

* update bioyond launch json

* add child_size for itemized_carrier

* fix bioyond resource io

---------

Co-authored-by: h840473807 <47357934+h840473807@users.noreply.github.com>
Co-authored-by: Xie Qiming <97236197+Andy6M@users.noreply.github.com>

* 更新物料接口

* Workstation dev yb2 (#100)

* Refactor and extend reaction station action messages

* Refactor dispensing station tasks to enhance parameter clarity and add batch processing capabilities

- Updated `create_90_10_vial_feeding_task` to include detailed parameters for 90%/10% vial feeding, improving clarity and usability.
- Introduced `create_batch_90_10_vial_feeding_task` for batch processing of 90%/10% vial feeding tasks with JSON formatted input.
- Added `create_batch_diamine_solution_task` for batch preparation of diamine solution, also utilizing JSON formatted input.
- Refined `create_diamine_solution_task` to include additional parameters for better task configuration.
- Enhanced schema descriptions and default values for improved user guidance.

* 修复to_plr_resources

* add update remove

* 支持选择器注册表自动生成
支持转运物料

* 修复资源添加

* 修复transfer_resource_to_another生成

* 更新transfer_resource_to_another参数,支持spot入参

* 新增test_resource动作

* fix host_node error

* fix host_node test_resource error

* fix host_node test_resource error

* 过滤本地动作

* 移动内部action以兼容host node

* 修复同步任务报错不显示的bug

* feat: 允许返回非本节点物料,后面可以通过decoration进行区分,就不进行warning了

* update todo

* modify bioyond/plr converter, bioyond resource registry, and tests

* pass the tests

* update todo

* add conda-pack-build.yml

* add auto install script for conda-pack-build.yml

(cherry picked from commit 172599adcf)

* update conda-pack-build.yml

* update conda-pack-build.yml

* update conda-pack-build.yml

* update conda-pack-build.yml

* update conda-pack-build.yml

* Add version in __init__.py
Update conda-pack-build.yml
Add create_zip_archive.py

* Update conda-pack-build.yml

* Update conda-pack-build.yml (with mamba)

* Update conda-pack-build.yml

* Fix FileNotFoundError

* Try fix 'charmap' codec can't encode characters in position 16-23: character maps to <undefined>

* Fix unilabos msgs search error

* Fix environment_check.py

* Update recipe.yaml

* Update registry. Update uuid loop figure method. Update install docs.

* Fix nested conda pack

* Fix one-key installation path error

* Bump version to 0.10.7

* Workshop bj (#99)

* Add LaiYu Liquid device integration and tests

Introduce LaiYu Liquid device implementation, including backend, controllers, drivers, configuration, and resource files. Add hardware connection, tip pickup, and simplified test scripts, as well as experiment and registry configuration for LaiYu Liquid. Documentation and .gitignore for the device are also included.

* feat(LaiYu_Liquid): 重构设备模块结构并添加硬件文档

refactor: 重新组织LaiYu_Liquid模块目录结构
docs: 添加SOPA移液器和步进电机控制指令文档
fix: 修正设备配置中的最大体积默认值
test: 新增工作台配置测试用例
chore: 删除过时的测试脚本和配置文件

* add

* 重构: 将 LaiYu_Liquid.py 重命名为 laiyu_liquid_main.py 并更新所有导入引用

- 使用 git mv 将 LaiYu_Liquid.py 重命名为 laiyu_liquid_main.py
- 更新所有相关文件中的导入引用
- 保持代码功能不变,仅改善命名一致性
- 测试确认所有导入正常工作

* 修复: 在 core/__init__.py 中添加 LaiYuLiquidBackend 导出

- 添加 LaiYuLiquidBackend 到导入列表
- 添加 LaiYuLiquidBackend 到 __all__ 导出列表
- 确保所有主要类都可以正确导入

* 修复大小写文件夹名字

* 电池装配工站二次开发教程(带目录)上传至dev (#94)

* 电池装配工站二次开发教程

* Update intro.md

* 物料教程

* 更新物料教程,json格式注释

* Update prcxi driver & fix transfer_liquid mix_times (#90)

* Update prcxi driver & fix transfer_liquid mix_times

* fix: correct mix_times type

* Update liquid_handler registry

* test: prcxi.py

* Update registry from pr

* fix ony-key script not exist

* clean files

---------

Co-authored-by: Junhan Chang <changjh@dp.tech>
Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com>
Co-authored-by: Xie Qiming <97236197+Andy6M@users.noreply.github.com>
Co-authored-by: h840473807 <47357934+h840473807@users.noreply.github.com>
Co-authored-by: LccLink <1951855008@qq.com>
Co-authored-by: lixinyu1011 <61094742+lixinyu1011@users.noreply.github.com>
Co-authored-by: shiyubo0410 <shiyubo@dp.tech>
2025-10-12 23:34:26 +08:00

36 KiB
Raw Blame History

LaiYu液体处理设备硬件连接配置指南

📋 文档概述

本指南提供LaiYu液体处理设备的完整硬件连接配置方案包括快速入门、详细配置、连接验证和故障排除。适用于设备初次安装、配置变更和问题诊断。


🚀 快速入门指南

基本配置步骤

  1. 确认硬件连接

    • 将RS485转USB设备连接到计算机
    • 确保XYZ控制器和移液器通过RS485总线连接
    • 检查设备供电状态
  2. 获取串口信息

    # macOS/Linux
    ls /dev/cu.* | grep usbserial
    
    # 常见输出: /dev/cu.usbserial-3130
    
  3. 基本配置参数

    # 推荐的默认配置
    config = LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",  # 🔧 替换为实际串口号
        address=4,                       # 移液器地址(固定)
        baudrate=115200,                 # 推荐波特率
        timeout=5.0                      # 通信超时
    )
    
  4. 快速连接测试

    device = LaiYuLiquid(config)
    success = await device.setup()
    print(f"连接状态: {'成功' if success else '失败'}")
    

🏗️ 硬件架构详解

系统组成

LaiYu液体处理设备采用RS485总线架构包含以下核心组件

组件 通信协议 设备地址 默认波特率 功能描述
XYZ三轴控制器 RS485 (Modbus) X轴=1, Y轴=2, Z轴=3 115200 三维运动控制
SOPA移液器 RS485 4 (推荐) 115200 液体吸取分配
RS485转USB USB/串口 - 115200 通信接口转换

地址分配策略

RS485总线地址分配:
├── 地址 1: X轴步进电机 (自动分配)
├── 地址 2: Y轴步进电机 (自动分配)  
├── 地址 3: Z轴步进电机 (自动分配)
├── 地址 4: SOPA移液器 (推荐配置)
└── 禁用地址: 47('/'), 69('E'), 91('[')

通信参数规范

参数 XYZ控制器 SOPA移液器 说明
数据位 8 8 固定值
停止位 1 1 固定值
校验位 固定值
流控制 固定值

⚙️ 配置参数详解

1. 核心配置类

LaiYuLiquidConfig 参数说明

@dataclass
class LaiYuLiquidConfig:
    # === 通信参数 ===
    port: str = "/dev/cu.usbserial-3130"    # 串口设备路径
    address: int = 4                         # 移液器地址(推荐值)
    baudrate: int = 115200                   # 通信波特率(推荐值)
    timeout: float = 5.0                     # 通信超时时间(秒)
    
    # === 工作台物理尺寸 ===
    deck_width: float = 340.0                # 工作台宽度 (mm)
    deck_height: float = 250.0               # 工作台高度 (mm) 
    deck_depth: float = 160.0                # 工作台深度 (mm)
    
    # === 运动控制参数 ===
    max_speed: float = 100.0                 # 最大移动速度 (mm/s)
    acceleration: float = 50.0               # 加速度 (mm/s²)
    safe_height: float = 50.0                # 安全移动高度 (mm)
    
    # === 移液参数 ===
    max_volume: float = 1000.0               # 最大移液体积 (μL)
    min_volume: float = 0.1                  # 最小移液体积 (μL)
    liquid_detection: bool = True            # 启用液面检测
    
    # === 枪头操作参数 ===
    tip_pickup_speed: int = 30               # 取枪头速度 (rpm)
    tip_pickup_acceleration: int = 500       # 取枪头加速度 (rpm/s)
    tip_pickup_depth: float = 10.0           # 枪头插入深度 (mm)
    tip_drop_height: float = 10.0            # 丢弃枪头高度 (mm)

2. 配置文件位置

A. 代码配置(推荐)

# 在Python代码中直接配置
from unilabos.devices.laiyu_liquid import LaiYuLiquidConfig

config = LaiYuLiquidConfig(
    port="/dev/cu.usbserial-3130",  # 🔧 修改为实际串口
    address=4,                       # 🔧 移液器地址
    baudrate=115200,                 # 🔧 通信波特率
    timeout=5.0                      # 🔧 超时时间
)

B. JSON配置文件

{
    "laiyu_liquid_config": {
        "port": "/dev/cu.usbserial-3130",
        "address": 4,
        "baudrate": 115200,
        "timeout": 5.0,
        "deck_width": 340.0,
        "deck_height": 250.0,
        "deck_depth": 160.0,
        "max_speed": 100.0,
        "acceleration": 50.0,
        "safe_height": 50.0
    }
}

C. 实验协议配置

// test/experiments/laiyu_liquid.json
{
    "device_config": {
        "type": "laiyu_liquid",
        "config": {
            "port": "/dev/cu.usbserial-3130",
            "address": 4,
            "baudrate": 115200
        }
    }
}

2. 串口设备识别

自动识别方法(推荐)

import serial.tools.list_ports

def find_laiyu_device():
    """自动查找LaiYu设备串口"""
    ports = serial.tools.list_ports.comports()
    
    for port in ports:
        # 根据设备描述或VID/PID识别
        if 'usbserial' in port.device.lower():
            print(f"找到可能的设备: {port.device}")
            print(f"描述: {port.description}")
            print(f"硬件ID: {port.hwid}")
            return port.device
    
    return None

# 使用示例
device_port = find_laiyu_device()
if device_port:
    print(f"检测到设备端口: {device_port}")
else:
    print("未检测到设备")

手动识别方法

操作系统 命令 设备路径格式
macOS ls /dev/cu.* /dev/cu.usbserial-XXXX
Linux ls /dev/ttyUSB* /dev/ttyUSB0
Windows 设备管理器 COM3, COM4

macOS 详细识别

# 1. 列出所有USB串口设备
ls /dev/cu.usbserial-*

# 2. 查看USB设备详细信息
system_profiler SPUSBDataType | grep -A 10 "Serial"

# 3. 实时监控设备插拔
ls /dev/cu.* && echo "--- 请插入设备 ---" && sleep 3 && ls /dev/cu.*

Linux 详细识别

# 1. 列出串口设备
ls /dev/ttyUSB* /dev/ttyACM*

# 2. 查看设备信息
dmesg | grep -i "usb.*serial"
lsusb | grep -i "serial\|converter"

# 3. 查看设备属性
udevadm info --name=/dev/ttyUSB0 --attribute-walk

Windows 详细识别

# PowerShell命令
Get-WmiObject -Class Win32_SerialPort | Select-Object Name, DeviceID, Description

# 或在设备管理器中查看"端口(COM和LPT)"

3. 控制器特定配置

XYZ步进电机控制器

  • 地址范围: 1-3 (X轴=1, Y轴=2, Z轴=3)
  • 通信协议: Modbus RTU
  • 波特率: 9600 或 115200
  • 数据位: 8
  • 停止位: 1
  • 校验位: None

XYZ控制器配置 (controllers/xyz_controller.py)

XYZ控制器负责三轴运动控制提供精确的位置控制和运动规划功能。

主要功能:

  • 三轴独立控制X、Y、Z轴
  • 位置精度控制
  • 运动速度调节
  • 安全限位检测

配置参数:

xyz_config = {
    "port": "/dev/ttyUSB0",           # 串口设备
    "baudrate": 115200,               # 波特率
    "timeout": 1.0,                   # 通信超时
    "max_speed": {                    # 最大速度限制
        "x": 1000,                    # X轴最大速度
        "y": 1000,                    # Y轴最大速度  
        "z": 500                      # Z轴最大速度
    },
    "acceleration": 500,              # 加速度
    "home_position": [0, 0, 0]        # 原点位置
}
def __init__(self, port: str, baudrate: int = 115200, 
             machine_config: Optional[MachineConfig] = None,
             config_file: str = "machine_config.json",
             auto_connect: bool = True):
    """
    Args:
        port: 串口端口 (如: "/dev/cu.usbserial-3130")
        baudrate: 波特率 (默认: 115200)
        machine_config: 机械配置参数
        config_file: 配置文件路径
        auto_connect: 是否自动连接
    """

SOPA移液器

  • 地址: 通常为 4 或更高
  • 通信协议: 自定义协议
  • 波特率: 115200 (推荐)
  • 响应时间: < 100ms

移液器控制器配置 (controllers/pipette_controller.py)

移液器控制器负责精确的液体吸取和分配操作,支持多种移液模式和参数配置。

主要功能:

  • 精确体积控制
  • 液面检测
  • 枪头管理
  • 速度调节

配置参数:

@dataclass
class SOPAConfig:
    # 通信参数
    port: str = "/dev/ttyUSB0"              # 🔧 修改串口号
    baudrate: int = 115200                  # 🔧 修改波特率
    address: int = 1                        # 🔧 修改设备地址 (1-254)
    timeout: float = 5.0                    # 🔧 修改超时时间
    comm_type: CommunicationType = CommunicationType.TERMINAL_DEBUG

🔍 连接验证与测试

1. 编程方式验证连接

创建测试脚本

#!/usr/bin/env python3
"""
LaiYu液体处理设备连接测试脚本
"""

import sys
import os
sys.path.append('/Users/dp/Documents/DPT/HuaiRou/Uni-Lab-OS')

from unilabos.devices.laiyu_liquid.core.LaiYu_Liquid import (
    LaiYuLiquid, LaiYuLiquidConfig
)

def test_connection():
    """测试设备连接"""
    
    # 🔧 修改这里的配置参数
    config = LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",  # 修改为你的串口号
        address=1,                       # 修改为你的设备地址
        baudrate=9600,                   # 修改为你的波特率
        timeout=5.0
    )
    
    print("🔌 正在测试LaiYu液体处理设备连接...")
    print(f"串口: {config.port}")
    print(f"波特率: {config.baudrate}")
    print(f"设备地址: {config.address}")
    print("-" * 50)
    
    try:
        # 创建设备实例
        device = LaiYuLiquid(config)
        
        # 尝试连接和初始化
        print("📡 正在连接设备...")
        success = await device.setup()
        
        if success:
            print("✅ 设备连接成功!")
            print(f"连接状态: {device.is_connected}")
            print(f"初始化状态: {device.is_initialized}")
            print(f"当前位置: {device.current_position}")
            
            # 获取设备状态
            status = device.get_status()
            print("\n📊 设备状态:")
            for key, value in status.items():
                print(f"  {key}: {value}")
                
        else:
            print("❌ 设备连接失败!")
            print("请检查:")
            print("  1. 串口号是否正确")
            print("  2. 设备是否已连接并通电")
            print("  3. 波特率和设备地址是否匹配")
            print("  4. 串口是否被其他程序占用")
            
    except Exception as e:
        print(f"❌ 连接测试出错: {e}")
        print("\n🔧 故障排除建议:")
        print("  1. 检查串口设备是否存在:")
        print("     macOS: ls /dev/cu.*")
        print("     Linux: ls /dev/ttyUSB* /dev/ttyACM*")
        print("  2. 检查设备权限:")
        print("     sudo chmod 666 /dev/cu.usbserial-*")
        print("  3. 检查设备是否被占用:")
        print("     lsof | grep /dev/cu.usbserial")
        
    finally:
        # 清理连接
        if 'device' in locals():
            await device.stop()

if __name__ == "__main__":
    import asyncio
    asyncio.run(test_connection())

2. 命令行验证工具

串口通信测试

# 安装串口调试工具
pip install pyserial

# 使用Python测试串口
python -c "
import serial
try:
    ser = serial.Serial('/dev/cu.usbserial-3130', 9600, timeout=1)
    print('串口连接成功:', ser.is_open)
    ser.close()
except Exception as e:
    print('串口连接失败:', e)
"

设备权限检查

# macOS/Linux 检查串口权限
ls -la /dev/cu.usbserial-*

# 如果权限不足,修改权限
sudo chmod 666 /dev/cu.usbserial-*

# 检查串口是否被占用
lsof | grep /dev/cu.usbserial

3. 连接状态指示器

设备提供多种方式检查连接状态:

A. 属性检查

device = LaiYuLiquid(config)

# 检查连接状态
print(f"设备已连接: {device.is_connected}")
print(f"设备已初始化: {device.is_initialized}")
print(f"枪头已安装: {device.tip_attached}")
print(f"当前位置: {device.current_position}")
print(f"当前体积: {device.current_volume}")

B. 状态字典

status = device.get_status()
print("完整设备状态:", status)

# 输出示例:
# {
#     'connected': True,
#     'initialized': True, 
#     'position': (0.0, 0.0, 50.0),
#     'tip_attached': False,
#     'current_volume': 0.0,
#     'last_error': None
# }

🛠️ 故障排除指南

1. 连接问题诊断

🔍 问题诊断流程

def diagnose_connection_issues():
    """连接问题诊断工具"""
    import serial.tools.list_ports
    import serial
    
    print("🔍 开始连接问题诊断...")
    
    # 1. 检查串口设备
    ports = list(serial.tools.list_ports.comports())
    if not ports:
        print("❌ 未检测到任何串口设备")
        print("💡 解决方案:")
        print("   - 检查USB连接线")
        print("   - 确认设备电源")
        print("   - 安装设备驱动")
        return
    
    print(f"✅ 检测到 {len(ports)} 个串口设备")
    for port in ports:
        print(f"   📍 {port.device}: {port.description}")
    
    # 2. 测试串口访问权限
    for port in ports:
        try:
            with serial.Serial(port.device, 9600, timeout=1):
                print(f"✅ {port.device}: 访问权限正常")
        except PermissionError:
            print(f"❌ {port.device}: 权限不足")
            print("💡 解决方案: sudo chmod 666 " + port.device)
        except Exception as e:
            print(f"⚠️ {port.device}: {e}")

# 运行诊断
diagnose_connection_issues()

🚫 常见连接错误

错误类型 症状 解决方案
设备未找到 FileNotFoundError: No such file or directory 1. 检查USB连接
2. 确认设备驱动
3. 重新插拔设备
权限不足 PermissionError: Permission denied 1. sudo chmod 666 /dev/ttyUSB0
2. 添加用户到dialout组
3. 使用sudo运行
设备占用 SerialException: Device or resource busy 1. 关闭其他程序
2. lsof /dev/ttyUSB0查找占用
3. 重启系统
驱动问题 设备管理器显示未知设备 1. 安装CH340/CP210x驱动
2. 更新系统驱动
3. 使用原装USB线

2. 通信问题解决

📡 通信参数调试

def test_communication_parameters():
    """测试不同通信参数"""
    import serial
    
    port = "/dev/cu.usbserial-3130"  # 修改为实际端口
    baudrates = [9600, 19200, 38400, 57600, 115200]
    
    for baudrate in baudrates:
        print(f"🔄 测试波特率: {baudrate}")
        try:
            with serial.Serial(port, baudrate, timeout=2) as ser:
                # 发送测试命令
                test_cmd = b'\x01\x03\x00\x00\x00\x01\x84\x0A'
                ser.write(test_cmd)
                
                response = ser.read(100)
                if response:
                    print(f"   ✅ 成功: 收到 {len(response)} 字节")
                    print(f"   📦 数据: {response.hex()}")
                    return baudrate
                else:
                    print(f"   ❌ 无响应")
        except Exception as e:
            print(f"   ❌ 错误: {e}")
    
    return None

通信故障排除

问题类型 症状 诊断方法 解决方案
通信超时 TimeoutError 检查波特率和设备地址 1. 调整超时时间
2. 验证波特率
3. 检查设备地址
数据校验错误 CRCError 检查数据完整性 1. 更换USB线
2. 降低波特率
3. 检查电磁干扰
协议错误 响应格式异常 验证命令格式 1. 检查协议版本
2. 确认设备类型
3. 更新固件
间歇性故障 时好时坏 监控连接稳定性 1. 检查连接线
2. 稳定电源
3. 减少干扰源

3. 设备功能问题

🎯 设备状态检查

def check_device_health():
    """设备健康状态检查"""
    from unilabos.devices.laiyu_liquid import LaiYuLiquidConfig, LaiYuLiquidBackend
    
    config = LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",
        address=4,
        baudrate=115200,
        timeout=5.0
    )
    
    try:
        backend = LaiYuLiquidBackend(config)
        backend.connect()
        
        # 检查项目
        checks = {
            "设备连接": lambda: backend.is_connected(),
            "XYZ轴状态": lambda: backend.xyz_controller.get_all_positions(),
            "移液器状态": lambda: backend.pipette_controller.get_status(),
            "设备温度": lambda: backend.get_temperature(),
            "错误状态": lambda: backend.get_error_status(),
        }
        
        print("🏥 设备健康检查报告")
        print("=" * 40)
        
        for check_name, check_func in checks.items():
            try:
                result = check_func()
                print(f"✅ {check_name}: 正常")
                if result:
                    print(f"   📊 数据: {result}")
            except Exception as e:
                print(f"❌ {check_name}: 异常 - {e}")
        
        backend.disconnect()
        
    except Exception as e:
        print(f"❌ 无法连接设备: {e}")

4. 高级故障排除

🔧 日志分析工具

import logging

def setup_debug_logging():
    """设置调试日志"""
    logging.basicConfig(
        level=logging.DEBUG,
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler('laiyu_debug.log'),
            logging.StreamHandler()
        ]
    )
    
    # 启用串口通信日志
    serial_logger = logging.getLogger('serial')
    serial_logger.setLevel(logging.DEBUG)
    
    print("🔍 调试日志已启用,日志文件: laiyu_debug.log")

📊 性能监控

def monitor_performance():
    """性能监控工具"""
    import time
    import psutil
    
    print("📊 开始性能监控...")
    
    start_time = time.time()
    start_cpu = psutil.cpu_percent()
    start_memory = psutil.virtual_memory().percent
    
    # 执行设备操作
    # ... 你的设备操作代码 ...
    
    end_time = time.time()
    end_cpu = psutil.cpu_percent()
    end_memory = psutil.virtual_memory().percent
    
    print(f"⏱️ 执行时间: {end_time - start_time:.2f} 秒")
    print(f"💻 CPU使用: {end_cpu - start_cpu:.1f}%")
    print(f"🧠 内存使用: {end_memory - start_memory:.1f}%")

📝 配置文件模板

1. 基础配置模板

标准配置(推荐)

from unilabos.devices.laiyu_liquid import LaiYuLiquidConfig, LaiYuLiquidBackend, LaiYuLiquid

# 创建标准配置
config = LaiYuLiquidConfig(
    # === 通信参数 ===
    port="/dev/cu.usbserial-3130",    # 🔧 修改为实际串口
    address=4,                         # 移液器地址(推荐)
    baudrate=115200,                   # 通信波特率(推荐)
    timeout=5.0,                       # 通信超时时间
    
    # === 工作台尺寸 ===
    deck_width=340.0,                  # 工作台宽度 (mm)
    deck_height=250.0,                 # 工作台高度 (mm)
    deck_depth=160.0,                  # 工作台深度 (mm)
    
    # === 运动控制参数 ===
    max_speed=100.0,                   # 最大移动速度 (mm/s)
    acceleration=50.0,                 # 加速度 (mm/s²)
    safe_height=50.0,                  # 安全移动高度 (mm)
    
    # === 移液参数 ===
    max_volume=1000.0,                 # 最大移液体积 (μL)
    min_volume=0.1,                    # 最小移液体积 (μL)
    liquid_detection=True,             # 启用液面检测
    
    # === 枪头操作参数 ===
    tip_pickup_speed=30,               # 取枪头速度 (rpm)
    tip_pickup_acceleration=500,       # 取枪头加速度 (rpm/s)
    tip_pickup_depth=10.0,             # 枪头插入深度 (mm)
    tip_drop_height=10.0,              # 丢弃枪头高度 (mm)
)

# 创建设备实例
backend = LaiYuLiquidBackend(config)
device = LaiYuLiquid(backend)

2. 高级配置模板

多设备配置

# 配置多个LaiYu设备
configs = {
    "device_1": LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",
        address=4,
        baudrate=115200,
        deck_width=340.0,
        deck_height=250.0,
        deck_depth=160.0
    ),
    "device_2": LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3131",
        address=4,
        baudrate=115200,
        deck_width=340.0,
        deck_height=250.0,
        deck_depth=160.0
    )
}

# 创建设备实例
devices = {}
for name, config in configs.items():
    backend = LaiYuLiquidBackend(config)
    devices[name] = LaiYuLiquid(backend)

自定义参数配置

# 高精度移液配置
precision_config = LaiYuLiquidConfig(
    port="/dev/cu.usbserial-3130",
    address=4,
    baudrate=115200,
    timeout=10.0,                      # 增加超时时间
    
    # 精密运动控制
    max_speed=50.0,                    # 降低速度提高精度
    acceleration=25.0,                 # 降低加速度
    safe_height=30.0,                  # 降低安全高度
    
    # 精密移液参数
    max_volume=200.0,                  # 小体积移液
    min_volume=0.5,                    # 提高最小体积
    liquid_detection=True,
    
    # 精密枪头操作
    tip_pickup_speed=15,               # 降低取枪头速度
    tip_pickup_acceleration=250,       # 降低加速度
    tip_pickup_depth=8.0,              # 减少插入深度
    tip_drop_height=5.0,               # 降低丢弃高度
)

3. 实验协议配置

JSON配置文件模板

{
    "experiment_name": "LaiYu液体处理实验",
    "version": "1.0",
    "devices": {
        "laiyu_liquid": {
            "type": "LaiYu_Liquid",
            "config": {
                "port": "/dev/cu.usbserial-3130",
                "address": 4,
                "baudrate": 115200,
                "timeout": 5.0,
                "deck_width": 340.0,
                "deck_height": 250.0,
                "deck_depth": 160.0,
                "max_speed": 100.0,
                "acceleration": 50.0,
                "safe_height": 50.0,
                "max_volume": 1000.0,
                "min_volume": 0.1,
                "liquid_detection": true
            }
        }
    },
    "deck_layout": {
        "tip_rack": {
            "type": "tip_rack_96",
            "position": [10, 10, 0],
            "tips": "1000μL"
        },
        "source_plate": {
            "type": "plate_96",
            "position": [100, 10, 0],
            "contents": "样品"
        },
        "dest_plate": {
            "type": "plate_96",
            "position": [200, 10, 0],
            "contents": "目标"
        }
    }
}

4. 完整配置示例

{
    "laiyu_liquid_config": {
        "communication": {
            "xyz_controller": {
                "port": "/dev/cu.usbserial-3130",
                "baudrate": 115200,
                "timeout": 5.0
            },
            "pipette_controller": {
                "port": "/dev/cu.usbserial-3131", 
                "baudrate": 115200,
                "address": 4,
                "timeout": 5.0
            }
        },
        "mechanical": {
            "deck_width": 340.0,
            "deck_height": 250.0,
            "deck_depth": 160.0,
            "safe_height": 50.0
        },
        "motion": {
            "max_speed": 100.0,
            "acceleration": 50.0,
            "tip_pickup_speed": 30,
            "tip_pickup_acceleration": 500
        },
        "safety": {
            "position_validation": true,
            "emergency_stop_enabled": true,
            "deck_width": 300.0,
            "deck_height": 200.0,
            "deck_depth": 100.0,
            "safe_height": 50.0
        }
    }
}

5. 完整使用示例

基础移液操作

async def basic_pipetting_example():
    """基础移液操作示例"""
    
    # 1. 设备初始化
    config = LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",
        address=4,
        baudrate=115200
    )
    
    backend = LaiYuLiquidBackend(config)
    device = LaiYuLiquid(backend)
    
    try:
        # 2. 设备设置
        await device.setup()
        print("✅ 设备初始化完成")
        
        # 3. 回到原点
        await device.home_all_axes()
        print("✅ 轴归零完成")
        
        # 4. 取枪头
        tip_position = (50, 50, 10)  # 枪头架位置
        await device.pick_up_tip(tip_position)
        print("✅ 取枪头完成")
        
        # 5. 移液操作
        source_pos = (100, 100, 15)  # 源位置
        dest_pos = (200, 200, 15)    # 目标位置
        volume = 100.0               # 移液体积 (μL)
        
        await device.aspirate(volume, source_pos)
        print(f"✅ 吸取 {volume}μL 完成")
        
        await device.dispense(volume, dest_pos)
        print(f"✅ 分配 {volume}μL 完成")
        
        # 6. 丢弃枪头
        trash_position = (300, 300, 20)
        await device.drop_tip(trash_position)
        print("✅ 丢弃枪头完成")
        
    except Exception as e:
        print(f"❌ 操作失败: {e}")
        
    finally:
        # 7. 清理资源
        await device.cleanup()
        print("✅ 设备清理完成")

# 运行示例
import asyncio
asyncio.run(basic_pipetting_example())

批量处理示例

async def batch_processing_example():
    """批量处理示例"""
    
    config = LaiYuLiquidConfig(
        port="/dev/cu.usbserial-3130",
        address=4,
        baudrate=115200
    )
    
    backend = LaiYuLiquidBackend(config)
    device = LaiYuLiquid(backend)
    
    try:
        await device.setup()
        await device.home_all_axes()
        
        # 定义位置
        tip_rack = [(50 + i*9, 50, 10) for i in range(12)]  # 12个枪头位置
        source_wells = [(100 + i*9, 100, 15) for i in range(12)]  # 12个源孔
        dest_wells = [(200 + i*9, 200, 15) for i in range(12)]    # 12个目标孔
        
        # 批量移液
        for i in range(12):
            print(f"🔄 处理第 {i+1} 个样品...")
            
            # 取枪头
            await device.pick_up_tip(tip_rack[i])
            
            # 移液
            await device.aspirate(50.0, source_wells[i])
            await device.dispense(50.0, dest_wells[i])
            
            # 丢弃枪头
            await device.drop_tip((300, 300, 20))
            
            print(f"✅ 第 {i+1} 个样品处理完成")
        
        print("🎉 批量处理完成!")
        
    except Exception as e:
        print(f"❌ 批量处理失败: {e}")
        
    finally:
        await device.cleanup()

# 运行批量处理
asyncio.run(batch_processing_example())

🔧 调试与日志管理

1. 调试模式配置

启用全局调试

import logging
from unilabos.devices.laiyu_liquid import LaiYuLiquidConfig, LaiYuLiquidBackend

# 配置全局日志
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('laiyu_debug.log'),
        logging.StreamHandler()
    ]
)

# 创建调试配置
debug_config = LaiYuLiquidConfig(
    port="/dev/cu.usbserial-3130",
    address=4,
    baudrate=115200,
    timeout=10.0,                    # 增加超时时间便于调试
    debug_mode=True                  # 启用调试模式
)

分级日志配置

def setup_logging(log_level="INFO"):
    """设置分级日志"""
    
    # 日志级别映射
    levels = {
        "DEBUG": logging.DEBUG,
        "INFO": logging.INFO,
        "WARNING": logging.WARNING,
        "ERROR": logging.ERROR
    }
    
    # 创建日志记录器
    logger = logging.getLogger('LaiYu_Liquid')
    logger.setLevel(levels.get(log_level, logging.INFO))
    
    # 文件处理器
    file_handler = logging.FileHandler('laiyu_operations.log')
    file_formatter = logging.Formatter(
        '%(asctime)s - %(name)s - %(levelname)s - %(funcName)s:%(lineno)d - %(message)s'
    )
    file_handler.setFormatter(file_formatter)
    
    # 控制台处理器
    console_handler = logging.StreamHandler()
    console_formatter = logging.Formatter('%(levelname)s - %(message)s')
    console_handler.setFormatter(console_formatter)
    
    logger.addHandler(file_handler)
    logger.addHandler(console_handler)
    
    return logger

# 使用示例
logger = setup_logging("DEBUG")
logger.info("开始LaiYu设备操作")

2. 通信监控

串口通信日志

def enable_serial_logging():
    """启用串口通信日志"""
    import serial
    
    # 创建串口日志记录器
    serial_logger = logging.getLogger('serial.communication')
    serial_logger.setLevel(logging.DEBUG)
    
    # 创建专用的串口日志文件
    serial_handler = logging.FileHandler('laiyu_serial.log')
    serial_formatter = logging.Formatter(
        '%(asctime)s - SERIAL - %(message)s'
    )
    serial_handler.setFormatter(serial_formatter)
    serial_logger.addHandler(serial_handler)
    
    print("📡 串口通信日志已启用: laiyu_serial.log")
    return serial_logger

实时通信监控

class CommunicationMonitor:
    """通信监控器"""
    
    def __init__(self):
        self.sent_count = 0
        self.received_count = 0
        self.error_count = 0
        self.start_time = time.time()
    
    def log_sent(self, data):
        """记录发送数据"""
        self.sent_count += 1
        logging.debug(f"📤 发送 #{self.sent_count}: {data.hex()}")
    
    def log_received(self, data):
        """记录接收数据"""
        self.received_count += 1
        logging.debug(f"📥 接收 #{self.received_count}: {data.hex()}")
    
    def log_error(self, error):
        """记录错误"""
        self.error_count += 1
        logging.error(f"❌ 通信错误 #{self.error_count}: {error}")
    
    def get_statistics(self):
        """获取统计信息"""
        duration = time.time() - self.start_time
        return {
            "运行时间": f"{duration:.2f}秒",
            "发送次数": self.sent_count,
            "接收次数": self.received_count,
            "错误次数": self.error_count,
            "成功率": f"{((self.sent_count - self.error_count) / max(self.sent_count, 1) * 100):.1f}%"
        }

3. 性能监控

操作性能分析

import time
import functools

def performance_monitor(operation_name):
    """性能监控装饰器"""
    def decorator(func):
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            start_time = time.time()
            start_memory = psutil.Process().memory_info().rss / 1024 / 1024  # MB
            
            try:
                result = await func(*args, **kwargs)
                
                end_time = time.time()
                end_memory = psutil.Process().memory_info().rss / 1024 / 1024  # MB
                
                duration = end_time - start_time
                memory_delta = end_memory - start_memory
                
                logging.info(f"⏱️ {operation_name}: {duration:.3f}s, 内存变化: {memory_delta:+.1f}MB")
                
                return result
                
            except Exception as e:
                end_time = time.time()
                duration = end_time - start_time
                logging.error(f"❌ {operation_name} 失败 ({duration:.3f}s): {e}")
                raise
                
        return wrapper
    return decorator

# 使用示例
@performance_monitor("移液操作")
async def monitored_pipetting():
    await device.aspirate(100.0, (100, 100, 15))
    await device.dispense(100.0, (200, 200, 15))

系统资源监控

import psutil
import threading
import time

class SystemMonitor:
    """系统资源监控器"""
    
    def __init__(self, interval=1.0):
        self.interval = interval
        self.monitoring = False
        self.data = []
    
    def start_monitoring(self):
        """开始监控"""
        self.monitoring = True
        self.monitor_thread = threading.Thread(target=self._monitor_loop)
        self.monitor_thread.daemon = True
        self.monitor_thread.start()
        print("📊 系统监控已启动")
    
    def stop_monitoring(self):
        """停止监控"""
        self.monitoring = False
        if hasattr(self, 'monitor_thread'):
            self.monitor_thread.join()
        print("📊 系统监控已停止")
    
    def _monitor_loop(self):
        """监控循环"""
        while self.monitoring:
            cpu_percent = psutil.cpu_percent()
            memory = psutil.virtual_memory()
            
            self.data.append({
                'timestamp': time.time(),
                'cpu_percent': cpu_percent,
                'memory_percent': memory.percent,
                'memory_used_mb': memory.used / 1024 / 1024
            })
            
            time.sleep(self.interval)
    
    def get_report(self):
        """生成监控报告"""
        if not self.data:
            return "无监控数据"
        
        avg_cpu = sum(d['cpu_percent'] for d in self.data) / len(self.data)
        avg_memory = sum(d['memory_percent'] for d in self.data) / len(self.data)
        max_memory = max(d['memory_used_mb'] for d in self.data)
        
        return f"""
📊 系统资源监控报告
==================
监控时长: {len(self.data) * self.interval:.1f}平均CPU使用率: {avg_cpu:.1f}%
平均内存使用率: {avg_memory:.1f}%
峰值内存使用: {max_memory:.1f}MB
        """

# 使用示例
monitor = SystemMonitor()
monitor.start_monitoring()

# 执行设备操作
# ... 你的代码 ...

monitor.stop_monitoring()
print(monitor.get_report())

4. 错误追踪

异常处理和记录

import traceback

class ErrorTracker:
    """错误追踪器"""
    
    def __init__(self):
        self.errors = []
    
    def log_error(self, operation, error, context=None):
        """记录错误"""
        error_info = {
            'timestamp': time.time(),
            'operation': operation,
            'error_type': type(error).__name__,
            'error_message': str(error),
            'traceback': traceback.format_exc(),
            'context': context or {}
        }
        
        self.errors.append(error_info)
        
        # 记录到日志
        logging.error(f"❌ {operation} 失败: {error}")
        logging.debug(f"错误详情: {error_info}")
    
    def get_error_summary(self):
        """获取错误摘要"""
        if not self.errors:
            return "✅ 无错误记录"
        
        error_types = {}
        for error in self.errors:
            error_type = error['error_type']
            error_types[error_type] = error_types.get(error_type, 0) + 1
        
        summary = f"❌ 共记录 {len(self.errors)} 个错误:\n"
        for error_type, count in error_types.items():
            summary += f"  - {error_type}: {count}\n"
        
        return summary

# 全局错误追踪器
error_tracker = ErrorTracker()

# 使用示例
try:
    await device.move_to(x=1000, y=1000, z=100)  # 可能超出范围
except Exception as e:
    error_tracker.log_error("移动操作", e, {"target": (1000, 1000, 100)})

📚 总结

本文档提供了LaiYu液体处理设备的完整硬件连接配置指南涵盖了从基础设置到高级故障排除的所有方面。

🎯 关键要点

  1. 标准配置: 使用 port="/dev/cu.usbserial-3130", address=4, baudrate=115200
  2. 设备架构: XYZ轴控制器(地址1-3) + SOPA移液器(地址4)
  3. 连接验证: 使用提供的测试脚本验证硬件连接
  4. 故障排除: 参考故障排除指南解决常见问题
  5. 性能监控: 启用日志和监控确保稳定运行

🔗 相关文档

📞 技术支持

如遇到问题,请:

  1. 检查硬件连接和配置
  2. 查看调试日志
  3. 参考故障排除指南
  4. 联系技术支持团队

最后更新: 2024年1月