mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 04:51:10 +00:00
18 KiB
18 KiB
yaml 注册表编写指南
快速开始:使用注册表编辑器
推荐使用 UniLabOS 自带的可视化编辑器,它能帮你自动生成大部分配置,省去手写的麻烦。
怎么用编辑器
- 启动 UniLabOS
- 在浏览器中打开"注册表编辑器"页面
- 选择你的 Python 设备驱动文件
- 点击"分析文件",让系统读取你的类信息
- 填写一些基本信息(设备描述、图标啥的)
- 点击"生成注册表",复制生成的内容
- 把内容保存到
devices/目录下
我们为你准备了一个测试驱动,用于在界面上尝试注册表生成,参见目录:test\registry\example_devices.py
手动编写指南
如果你想自己写 yaml 文件,或者想深入了解结构,查阅下方说明。
注册表的基本结构
yaml 注册表就是设备的配置文件,里面定义了设备怎么用、有什么功能。好消息是系统会自动帮你填大部分内容,你只需要写两个必需的东西:设备名和 class 信息。
各字段用途
| 字段名 | 类型 | 需要手写 | 说明 |
|---|---|---|---|
| 设备标识符 | string | 是 | 设备的唯一名字,比如 mock_chiller |
| class | object | 部分 | 设备的核心信息,必须写 |
| description | string | 否 | 设备描述,系统默认给空字符串 |
| handles | array | 否 | 连接关系,默认是空的 |
| icon | string | 否 | 图标路径,默认为空 |
| init_param_schema | object | 否 | 初始化参数,系统自动分析生成 |
| version | string | 否 | 版本号,默认 "1.0.0" |
| category | array | 否 | 设备分类,默认用文件名 |
| config_info | array | 否 | 嵌套配置,默认为空 |
| file_path | string | 否 | 文件路径,系统自动设置 |
| registry_type | string | 否 | 注册表类型,自动设为 "device" |
class 字段里有啥
class 是核心部分,包含这些内容:
| 字段名 | 类型 | 需要手写 | 说明 |
|---|---|---|---|
| module | string | 是 | Python 类的路径,必须写 |
| type | string | 是 | 驱动类型,一般写 "python" |
| status_types | object | 否 | 状态类型,系统自动分析生成 |
| action_value_mappings | object | 部分 | 动作配置,系统会自动生成一些基础的 |
怎么创建新的注册表
创建文件
在 devices 文件夹里新建一个 yaml 文件,比如 new_device.yaml。
完整结构是什么样的
new_device: # 设备名,要唯一
class: # 核心配置
action_value_mappings: # 动作配置(后面会详细说)
action_name:
# 具体的动作设置
module: unilabos.devices.your_module.new_device:NewDeviceClass # 你的 Python 类
status_types: # 状态类型(系统会自动生成)
status: str
temperature: float
# 其他状态
type: python # 驱动类型,一般就是 python
description: New Device Description # 设备描述
handles: [] # 连接关系,通常是空的
icon: '' # 图标路径
init_param_schema: # 初始化参数(系统会自动生成)
config: # 初始化时需要的参数
properties:
port:
default: DEFAULT_PORT
type: string
required: []
type: object
data: # 前端显示用的数据类型
properties:
status:
type: string
temperature:
type: number
required:
- status
type: object
version: 0.0.1 # 版本号
category:
- device_category # 设备类别
config_info: [] # 嵌套配置,通常为空
action_value_mappings 怎么写
这个部分定义设备能做哪些动作。好消息是系统会自动生成大部分动作,你通常只需要添加一些特殊的自定义动作。
系统自动生成哪些动作
系统会帮你生成这些:
- 以
auto-开头的动作:从你 Python 类的方法自动生成 - 通用的驱动动作:
_execute_driver_command:同步执行驱动命令(仅本地可用)_execute_driver_command_async:异步执行驱动命令(仅本地可用)
如果要手动定义动作
如果你需要自定义一些特殊动作,需要这些字段:
| 字段名 | 需要手写 | 说明 |
|---|---|---|
| type | 是 | 动作类型,必须指定 |
| goal | 是 | 输入参数怎么映射 |
| feedback | 否 | 实时反馈,通常为空 |
| result | 是 | 结果怎么返回 |
| goal_default | 部分 | 参数默认值,ROS 动作会自动生成 |
| schema | 部分 | 前端表单配置,ROS 动作会自动生成 |
| handles | 否 | 连接关系,默认为空 |
| placeholder_keys | 否 | 特殊输入字段配置 |
动作类型有哪些
| 类型 | 什么时候用 | 系统会自动生成什么 |
|---|---|---|
| UniLabJsonCommand | 自定义同步 JSON 命令 | 啥都不生成 |
| UniLabJsonCommandAsync | 自定义异步 JSON 命令 | 啥都不生成 |
| ROS 动作类型 | 标准 ROS 动作 | goal_default 和 schema |
常用的 ROS 动作类型:
SendCmd:发送简单命令NavigateThroughPoses:导航动作SingleJointPosition:单关节位置控制Stir:搅拌动作HeatChill、HeatChillStart:加热冷却动作
复杂一点的例子
heat_chill_start:
type: HeatChillStart
goal:
purpose: purpose
temp: temp
goal_default: # ROS动作会自动生成,你也可以手动覆盖
purpose: ''
temp: 0.0
handles:
output:
- handler_key: labware
label: Labware
data_type: resource
data_source: handle
data_key: liquid
placeholder_keys:
purpose: unilabos_resources
result:
status: status
success: success
# schema 系统会自动生成,不用写
动作名字怎么起
根据设备用途来起名字:
- 启动停止类:
start、stop、pause、resume - 设置参数类:
set_speed、set_temperature、set_timer - 移动控制类:
move_to_position、move_through_points - 功能操作类:
stir、heat_chill_start、heat_chill_stop - 开关控制类:
valve_open_cmd、valve_close_cmd、push_to - 命令执行类:
send_nav_task、execute_command_from_outer
常用的动作类型
UniLabJsonCommand:自定义 JSON 命令(不走 ROS)UniLabJsonCommandAsync:异步 JSON 命令(不走 ROS)SendCmd:发送简单命令NavigateThroughPoses:导航相关SingleJointPosition:单关节控制Stir:搅拌HeatChill、HeatChillStart:加热冷却- 其他的 ROS 动作类型:看具体的 ROS 服务
示例:完整的动作配置
heat_chill_start:
type: HeatChillStart
goal:
purpose: purpose
temp: temp
goal_default:
purpose: ''
temp: 0.0
handles:
output:
- handler_key: labware
label: Labware
data_type: resource
data_source: handle
data_key: liquid
placeholder_keys:
purpose: unilabos_resources
result:
status: status
success: success
schema:
description: '启动加热冷却功能'
properties:
goal:
properties:
purpose:
type: string
description: '用途说明'
temp:
type: number
description: '目标温度'
required:
- purpose
- temp
title: HeatChillStart_Goal
type: object
required:
- goal
title: HeatChillStart
type: object
feedback: {}
系统自动生成的字段
status_types
系统会扫描你的 Python 类,从状态方法自动生成这部分:
status_types:
current_temperature: float # 从 get_current_temperature() 方法来的
is_heating: bool # 从 get_is_heating() 方法来的
status: str # 从 get_status() 方法来的
注意几点:
- 系统会找所有
get_开头的方法 - 类型会自动转成 ROS 类型(比如
str变成String) - 如果类型是
Any、None或者不知道的,就默认用String
init_param_schema
这个完全是系统自动生成的,你不用管:
init_param_schema:
config: # 从你类的 __init__ 方法分析出来的
properties:
port:
type: string
default: '/dev/ttyUSB0'
baudrate:
type: integer
default: 9600
required: []
type: object
data: # 根据 status_types 生成的前端用的类型
properties:
current_temperature:
type: number
is_heating:
type: boolean
status:
type: string
required:
- status
type: object
生成规则很简单:
config部分:看你类的__init__方法有什么参数,类型和默认值是啥data部分:根据status_types生成前端显示用的类型定义
其他自动填充的字段
version: '1.0.0' # 默认版本
category: ['文件名'] # 用你的 yaml 文件名当类别
description: '' # 默认为空,你可以手动改
icon: '' # 默认为空,你可以加图标
handles: [] # 默认空数组
config_info: [] # 默认空数组
file_path: '/path/to/file' # 系统自动填文件路径
registry_type: 'device' # 自动设为设备类型
handles 字段
这个是定义设备连接关系的,类似动作里的 handles 一样:
handles: # 大多数时候都是空的,除非设备本身需要连接啥
- handler_key: device_output
label: Device Output
data_type: resource
data_source: value
data_key: default_value
其他可以配置的字段
description: '设备的详细描述' # 写清楚设备是干啥的
icon: 'device_icon.webp' # 设备图标,文件名(会上传到OSS)
version: '0.0.1' # 版本号
category: # 设备分类,前端会用这个分组
- 'heating'
- 'cooling'
- 'temperature_control'
config_info: # 嵌套配置,如果设备包含子设备
- children:
- opentrons_24_tuberack_nest_1point5ml_snapcap_A1
- other_nested_component
完整的例子
这里是一个比较完整的设备配置示例:
my_temperature_controller:
class:
action_value_mappings:
heat_start:
type: HeatChillStart
goal:
target_temp: temp
vessel: vessel
goal_default:
target_temp: 25.0
vessel: ''
handles:
output:
- handler_key: heated_sample
label: Heated Sample
data_type: resource
data_source: handle
data_key: sample
placeholder_keys:
vessel: unilabos_resources
result:
status: status
success: success
schema:
description: '启动加热功能'
properties:
goal:
properties:
target_temp:
type: number
description: '目标温度'
vessel:
type: string
description: '容器标识'
required:
- target_temp
- vessel
title: HeatStart_Goal
type: object
required:
- goal
title: HeatStart
type: object
feedback: {}
stop:
type: UniLabJsonCommand
goal: {}
goal_default: {}
handles: {}
result:
status: status
schema:
description: '停止设备'
properties:
goal:
type: object
title: Stop_Goal
title: Stop
type: object
feedback: {}
module: unilabos.devices.temperature.my_controller:MyTemperatureController
status_types:
current_temperature: float
target_temperature: float
is_heating: bool
is_cooling: bool
status: str
vessel: str
type: python
description: '我的温度控制器设备'
handles: []
icon: 'temperature_controller.webp'
init_param_schema:
config:
properties:
port:
default: '/dev/ttyUSB0'
type: string
baudrate:
default: 9600
type: number
required: []
type: object
data:
properties:
current_temperature:
type: number
target_temperature:
type: number
is_heating:
type: boolean
is_cooling:
type: boolean
status:
type: string
vessel:
type: string
required:
- current_temperature
- target_temperature
- status
type: object
version: '1.0.0'
category:
- 'temperature_control'
- 'heating'
config_info: []
怎么部署和使用
方法一:用编辑器(推荐)
- 先写好你的 Python 驱动类
- 用注册表编辑器自动生成 yaml 配置
- 把生成的文件保存到
devices/目录 - 重启 UniLabOS 就能用了
方法二:手动写(简化版)
- 创建最简配置:
# devices/my_device.yaml
my_device:
class:
module: unilabos.devices.my_module.my_device:MyDevice
type: python
-
启动系统时用
complete_registry=True参数,让系统自动补全 -
检查一下生成的配置是不是你想要的
Python 驱动类要怎么写
你的设备类要符合这些要求:
from unilabos.common.device_base import DeviceBase
class MyDevice(DeviceBase):
def __init__(self, config):
"""初始化,参数会自动分析到 init_param_schema.config"""
super().__init__(config)
self.port = config.get('port', '/dev/ttyUSB0')
# 状态方法(会自动生成到 status_types)
def get_status(self):
"""返回设备状态"""
return "idle"
def get_temperature(self):
"""返回当前温度"""
return 25.0
# 动作方法(会自动生成 auto- 开头的动作)
async def start_heating(self, temperature: float):
"""开始加热到指定温度"""
pass
def stop(self):
"""停止操作"""
pass
系统集成
- 把 yaml 文件放到
devices/目录下 - 系统启动时会自动扫描并加载设备
- 系统会自动补全所有缺失的字段
- 设备马上就能在前端界面中使用
高级配置
如果需要特殊设置,可以手动加:
my_device:
class:
module: unilabos.devices.my_module.my_device:MyDevice
type: python
action_value_mappings:
# 自定义动作
special_command:
type: UniLabJsonCommand
goal: {}
result: {}
# 可选的自定义配置
description: '我的特殊设备'
icon: 'my_device.webp'
category: ['temperature', 'heating']
常见问题怎么排查
设备加载不了
- 检查模块路径:确认
class.module路径写对了 - 确认类能导入:看看你的 Python 驱动类能不能正常导入
- 检查语法:用 yaml 验证器看看文件格式对不对
- 查看日志:看 UniLabOS 启动时有没有报错信息
自动生成失败了
- 类分析出问题:确认你的类继承了正确的基类
- 方法类型不明确:确保状态方法的返回类型写清楚了
- 导入有问题:检查类能不能被动态导入
- 没开完整注册:确认启用了
complete_registry=True
前端显示有问题
- 重新生成:删掉旧的 yaml 文件,用编辑器重新生成
- 清除缓存:清除浏览器缓存,重新加载页面
- 检查字段:确认必需的字段(比如
schema)都有 - 验证数据:检查
goal_default和schema的数据类型是不是一致
动作执行出错
- 方法名不对:确认动作方法名符合规范(比如
execute_<action_name>) - 参数映射错误:检查
goal字段的参数映射是否正确 - 返回格式不对:确认方法返回值格式符合
result映射 - 没异常处理:在驱动类里加上异常处理
最佳实践
开发流程
- 优先使用编辑器:除非有特殊需求,否则优先使用注册表编辑器
- 最小化配置:手动配置时只定义必要字段,让系统自动生成其他内容
- 增量开发:先创建基本配置,后续根据需要添加特殊动作
代码规范
- 方法命名:状态方法使用
get_前缀,动作方法使用动词开头 - 类型注解:为方法参数和返回值添加类型注解
- 文档字符串:为类和方法添加详细的文档字符串
- 异常处理:实现完善的错误处理和日志记录
配置管理
- 版本控制:所有 yaml 文件纳入版本控制
- 命名一致性:设备 ID、文件名、类名保持一致的命名风格
- 定期更新:定期运行完整注册以更新自动生成的字段
- 备份配置:在修改前备份重要的手动配置
测试验证
- 本地测试:在本地环境充分测试后再部署
- 渐进部署:先部署到测试环境,验证无误后再上生产环境
- 监控日志:密切监控设备加载和运行日志
- 回滚准备:准备快速回滚机制,以应对紧急情况
性能优化
- 按需加载:只加载实际使用的设备类型
- 缓存利用:充分利用系统的注册表缓存机制
- 资源管理:合理管理设备连接和资源占用
- 监控指标:设置关键性能指标的监控和告警