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>
This commit is contained in:
Xuwznln
2025-10-12 23:34:26 +08:00
committed by GitHub
parent 172599adcf
commit 9aeffebde1
229 changed files with 136969 additions and 17429 deletions

View File

@@ -13,18 +13,16 @@
```json
{
"nodes": [
{
"id": "PLR_STATION",
"name": "PLR_LH_TEST",
"parent": null,
"type": "device",
"class": "liquid_handler",
"config": {},
"data": {},
"children": [
"deck"
]
},
{
"id": "PLR_STATION",
"name": "PLR_LH_TEST",
"parent": null,
"type": "device",
"class": "liquid_handler",
"config": {},
"data": {},
"children": ["deck"]
},
{
"id": "deck",
"name": "deck",
@@ -32,12 +30,12 @@
"class": null,
"parent": "PLR_STATION",
"children": [
"trash",
"trash_core96",
"teaching_carrier",
"tip_rack",
"plate"
]
"trash",
"trash_core96",
"teaching_carrier",
"tip_rack",
"plate"
]
}
],
"links": []
@@ -45,6 +43,7 @@
```
配置文件定义了移液站的组成部分,主要包括:
- 移液站本体LiquidHandler- 设备类型
- 移液站携带物料实例deck- 物料类型
@@ -55,7 +54,7 @@
使用以下命令启动移液站设备:
```bash
unilab -g test/experiments/plr_test.json --app_bridges ""
unilab -g test/experiments/plr_test.json --ak [通过网页获取的ak值] --sk [通过网页获取的sk值]
```
### 2. 执行枪头插入操作
@@ -66,35 +65,50 @@ unilab -g test/experiments/plr_test.json --app_bridges ""
ros2 action send_goal /devices/PLR_STATION/pick_up_tips unilabos_msgs/action/_liquid_handler_pick_up_tips/LiquidHandlerPickUpTips "{ tip_spots: [ { id: 'tip_rack_tipspot_0_0', name: 'tip_rack_tipspot_0_0', sample_id: null, children: [], parent: 'tip_rack', type: 'device', config: { position: { x: 7.2, y: 68.3, z: -83.5 }, size_x: 9.0, size_y: 9.0, size_z: 0, rotation: { x: 0, y: 0, z: 0, type: 'Rotation' }, category: 'tip_spot', model: null, type: 'TipSpot', prototype_tip: { type: 'HamiltonTip', total_tip_length: 95.1, has_filter: true, maximal_volume: 1065, pickup_method: 'OUT_OF_RACK', tip_size: 'HIGH_VOLUME' } }, data: { tip: { type: 'HamiltonTip', total_tip_length: 95.1, has_filter: true, maximal_volume: 1065, pickup_method: 'OUT_OF_RACK', tip_size: 'HIGH_VOLUME' }, tip_state: { liquids: [], pending_liquids: [], liquid_history: [] }, pending_tip: { type: 'HamiltonTip', total_tip_length: 95.1, has_filter: true, maximal_volume: 1065, pickup_method: 'OUT_OF_RACK', tip_size: 'HIGH_VOLUME' } } } ], use_channels: [ 0 ], offsets: [ { x: 0.0, y: 0.0, z: 0.0 } ] }"
```
此命令会通过ros通信触发移液站执行枪头插入操作得到如下的PyLabRobot的输出日志。
此命令会通过 ros 通信触发移液站执行枪头插入操作,得到如下的 PyLabRobot 的输出日志。
```log
Picking up tips:
pip# resource offset tip type max volume (µL) fitting depth (mm) tip length (mm) filter
p0: tip_rack_tipspot_0_0 0.0,0.0,0.0 HamiltonTip 1065 8 95.1 Yes
pip# resource offset tip type max volume (µL) fitting depth (mm) tip length (mm) filter
p0: tip_rack_tipspot_0_0 0.0,0.0,0.0 HamiltonTip 1065 8 95.1 Yes
```
也可以登陆网页,给`tip_spots`选择`tip_rack_tipspot_0_0``use_channels``0``offsets`均填写`0`,同样可观察到上面的日志
## 常见问题
1. **重复插入枪头不成功**操作编排应该符合实际操作顺序可自行通过PyLabRobot进行测试
1. **重复插入枪头不成功**:操作编排应该符合实际操作顺序,可自行通过 PyLabRobot 进行测试
## 移液站支持的操作
移液站支持多种操作,以下是当前系统支持的操作列表:
1. **LiquidHandlerAspirate** - 吸液操作
2. **LiquidHandlerDispense** - 液操作
3. **LiquidHandlerDiscardTips** - 丢弃枪头
4. **LiquidHandlerDropTips** - 卸下枪头
5. **LiquidHandlerDropTips96** - 卸下96通道枪头
6. **LiquidHandlerMoveLid** - 移动盖子
7. **LiquidHandlerMovePlate** - 移动
8. **LiquidHandlerMoveResource** - 移动资源
9. **LiquidHandlerPickUpTips** - 插入枪头
10. **LiquidHandlerPickUpTips96** - 插入96通道枪头
11. **LiquidHandlerReturnTips** - 归还枪头
12. **LiquidHandlerReturnTips96** - 归还96通道枪头
13. **LiquidHandlerStamp** - 打印标记
14. **LiquidHandlerTransfer** - 液体转移
1. **LiquidHandlerProtocolCreation** - 协议创建
2. **LiquidHandlerAspirate** - 液操作
3. **LiquidHandlerDispense** - 排液操作
4. **LiquidHandlerDiscardTips** - 丢弃枪头
5. **LiquidHandlerDropTips** - 卸下枪头
6. **LiquidHandlerDropTips96** - 卸下 96 通道枪头
7. **LiquidHandlerMoveLid** - 移动
8. **LiquidHandlerMovePlate** - 移动板子
9. **LiquidHandlerMoveResource** - 移动资源
10. **LiquidHandlerPickUpTips** - 插入枪头
11. **LiquidHandlerPickUpTips96** - 插入 96 通道枪头
12. **LiquidHandlerReturnTips** - 归还枪头
13. **LiquidHandlerReturnTips96** - 归还 96 通道枪头
14. **LiquidHandlerSetLiquid** - 设置液体
15. **LiquidHandlerSetTipRack** - 设置枪头架
16. **LiquidHandlerStamp** - 打印标记
17. **LiquidHandlerTransfer** - 液体转移
18. **LiquidHandlerSetGroup** - 设置分组
19. **LiquidHandlerTransferBiomek** - Biomek 液体转移
20. **LiquidHandlerIncubateBiomek** - Biomek 孵育
21. **LiquidHandlerMoveBiomek** - Biomek 移动
22. **LiquidHandlerOscillateBiomek** - Biomek 振荡
23. **LiquidHandlerTransferGroup** - 分组转移
24. **LiquidHandlerAdd** - 添加操作
25. **LiquidHandlerMix** - 混合操作
26. **LiquidHandlerMoveTo** - 移动到指定位置
27. **LiquidHandlerRemove** - 移除操作
这些操作可通过ROS2 Action接口进行调用以实现复杂的移液流程。
这些操作可通过 ROS2 Action 接口进行调用,以实现复杂的移液流程。

View File

@@ -19,7 +19,7 @@ Uni-Lab 的组态图当前支持 node-link json 和 graphml 格式,其中包
对用户来说,“直接操作设备执行单个指令”不是个真实需求,真正的需求是**“执行对实验有意义的单个完整动作”——加入某种液体多少量;萃取分液;洗涤仪器等等。就像实验步骤文字书写的那样。**
而这些对实验有意义的单个完整动作,**一般需要多个设备的协同**,还依赖于他们的**物理连接关系(管道相连;机械臂可转运)**。
于是 Uni-Lab 实现了抽象的“工作站”,即注册表中的 `workstation` 设备(`ProtocolNode`类)来处理编译、规划操作。以泵骨架组成的自动有机实验室为例,设备管道连接关系如下:
于是 Uni-Lab 实现了抽象的“工作站”,即注册表中的 `workstation` 设备(`WorkstationNode`类)来处理编译、规划操作。以泵骨架组成的自动有机实验室为例,设备管道连接关系如下:
![topology](image/02-topology-and-chemputer-compile/topology.png)

View File

@@ -1,26 +1,64 @@
## 简单单变量动作函数
### `SendCmd`
```{literalinclude} ../../unilabos_msgs/action/SendCmd.action
:language: yaml
```
----
---
### `StrSingleInput`
```{literalinclude} ../../unilabos_msgs/action/StrSingleInput.action
:language: yaml
```
---
### `IntSingleInput`
```{literalinclude} ../../unilabos_msgs/action/IntSingleInput.action
:language: yaml
```
---
### `FloatSingleInput`
```{literalinclude} ../../unilabos_msgs/action/FloatSingleInput.action
:language: yaml
```
---
### `Point3DSeparateInput`
```{literalinclude} ../../unilabos_msgs/action/Point3DSeparateInput.action
:language: yaml
```
---
### `Wait`
```{literalinclude} ../../unilabos_msgs/action/Wait.action
:language: yaml
```
---
## 常量有机化学操作
Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab.io/chemputer/xdl/standard/full_steps_specification.html#),包含有机合成实验中常见的操作,如加热、搅拌、冷却等。
### `Clean`
```{literalinclude} ../../unilabos_msgs/action/Clean.action
:language: yaml
```
----
---
### `EvacuateAndRefill`
@@ -28,7 +66,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `Evaporate`
@@ -36,7 +74,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `HeatChill`
@@ -44,7 +82,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `HeatChillStart`
@@ -52,7 +90,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `HeatChillStop`
@@ -60,7 +98,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `PumpTransfer`
@@ -68,7 +106,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `Separate`
@@ -76,7 +114,7 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `Stir`
@@ -84,20 +122,179 @@ Uni-Lab 常量有机化学指令集多数来自 [XDL](https://croningroup.gitlab
:language: yaml
```
----
---
### `Add`
```{literalinclude} ../../unilabos_msgs/action/Add.action
:language: yaml
```
---
### `AddSolid`
```{literalinclude} ../../unilabos_msgs/action/AddSolid.action
:language: yaml
```
---
### `AdjustPH`
```{literalinclude} ../../unilabos_msgs/action/AdjustPH.action
:language: yaml
```
---
### `Centrifuge`
```{literalinclude} ../../unilabos_msgs/action/Centrifuge.action
:language: yaml
```
---
### `CleanVessel`
```{literalinclude} ../../unilabos_msgs/action/CleanVessel.action
:language: yaml
```
---
### `Crystallize`
```{literalinclude} ../../unilabos_msgs/action/Crystallize.action
:language: yaml
```
---
### `Dissolve`
```{literalinclude} ../../unilabos_msgs/action/Dissolve.action
:language: yaml
```
---
### `Dry`
```{literalinclude} ../../unilabos_msgs/action/Dry.action
:language: yaml
```
---
### `Filter`
```{literalinclude} ../../unilabos_msgs/action/Filter.action
:language: yaml
```
---
### `FilterThrough`
```{literalinclude} ../../unilabos_msgs/action/FilterThrough.action
:language: yaml
```
---
### `Hydrogenate`
```{literalinclude} ../../unilabos_msgs/action/Hydrogenate.action
:language: yaml
```
---
### `Purge`
```{literalinclude} ../../unilabos_msgs/action/Purge.action
:language: yaml
```
---
### `Recrystallize`
```{literalinclude} ../../unilabos_msgs/action/Recrystallize.action
:language: yaml
```
---
### `RunColumn`
```{literalinclude} ../../unilabos_msgs/action/RunColumn.action
:language: yaml
```
---
### `StartPurge`
```{literalinclude} ../../unilabos_msgs/action/StartPurge.action
:language: yaml
```
---
### `StartStir`
```{literalinclude} ../../unilabos_msgs/action/StartStir.action
:language: yaml
```
---
### `StopPurge`
```{literalinclude} ../../unilabos_msgs/action/StopPurge.action
:language: yaml
```
---
### `StopStir`
```{literalinclude} ../../unilabos_msgs/action/StopStir.action
:language: yaml
```
---
### `Transfer`
```{literalinclude} ../../unilabos_msgs/action/Transfer.action
:language: yaml
```
---
### `WashSolid`
```{literalinclude} ../../unilabos_msgs/action/WashSolid.action
:language: yaml
```
---
## 移液工作站及相关生物自动化设备操作
Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.org/user_guide/index.html),包含生物实验中常见的操作,如移液、混匀、离心等。
### `LiquidHandlerAspirate`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerAspirate.action
:language: yaml
```
----
---
### `LiquidHandlerDiscardTips`
@@ -105,7 +302,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerDispense`
@@ -113,7 +310,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerDropTips`
@@ -121,7 +318,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerDropTips96`
@@ -129,7 +326,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerMoveLid`
@@ -137,7 +334,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerMovePlate`
@@ -145,7 +342,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerMoveResource`
@@ -153,7 +350,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerPickUpTips`
@@ -161,7 +358,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerPickUpTips96`
@@ -169,7 +366,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerReturnTips`
@@ -177,7 +374,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerReturnTips96`
@@ -185,7 +382,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerStamp`
@@ -193,7 +390,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `LiquidHandlerTransfer`
@@ -201,9 +398,113 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
## 多工作站及小车运行、物料转移
---
### `LiquidHandlerAdd`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerAdd.action
:language: yaml
```
---
### `LiquidHandlerIncubateBiomek`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerIncubateBiomek.action
:language: yaml
```
---
### `LiquidHandlerMix`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerMix.action
:language: yaml
```
---
### `LiquidHandlerMoveBiomek`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerMoveBiomek.action
:language: yaml
```
---
### `LiquidHandlerMoveTo`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerMoveTo.action
:language: yaml
```
---
### `LiquidHandlerOscillateBiomek`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerOscillateBiomek.action
:language: yaml
```
---
### `LiquidHandlerProtocolCreation`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerProtocolCreation.action
:language: yaml
```
---
### `LiquidHandlerRemove`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerRemove.action
:language: yaml
```
---
### `LiquidHandlerSetGroup`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerSetGroup.action
:language: yaml
```
---
### `LiquidHandlerSetLiquid`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerSetLiquid.action
:language: yaml
```
---
### `LiquidHandlerSetTipRack`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerSetTipRack.action
:language: yaml
```
---
### `LiquidHandlerTransferBiomek`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerTransferBiomek.action
:language: yaml
```
---
### `LiquidHandlerTransferGroup`
```{literalinclude} ../../unilabos_msgs/action/LiquidHandlerTransferGroup.action
:language: yaml
```
---
## 多工作站及小车运行、物料转移
### `AGVTransfer`
@@ -211,7 +512,7 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `WorkStationRun`
@@ -219,12 +520,64 @@ Uni-Lab 生物操作指令集多数来自 [PyLabRobot](https://docs.pylabrobot.o
:language: yaml
```
----
---
### `ResetHandling`
```{literalinclude} ../../unilabos_msgs/action/ResetHandling.action
:language: yaml
```
---
### `ResourceCreateFromOuter`
```{literalinclude} ../../unilabos_msgs/action/ResourceCreateFromOuter.action
:language: yaml
```
---
### `ResourceCreateFromOuterEasy`
```{literalinclude} ../../unilabos_msgs/action/ResourceCreateFromOuterEasy.action
:language: yaml
```
---
### `SetPumpPosition`
```{literalinclude} ../../unilabos_msgs/action/SetPumpPosition.action
:language: yaml
```
---
## 固体分配与处理设备操作
### `SolidDispenseAddPowderTube`
```{literalinclude} ../../unilabos_msgs/action/SolidDispenseAddPowderTube.action
:language: yaml
```
---
## 其他设备操作
### `EmptyIn`
```{literalinclude} ../../unilabos_msgs/action/EmptyIn.action
:language: yaml
```
---
## 机械臂、夹爪等机器人设备
Uni-Lab 机械臂、机器人、夹爪和导航指令集沿用 ROS2 的 `control_msgs` 和 `nav2_msgs`
### `FollowJointTrajectory`
```yaml
@@ -292,7 +645,8 @@ trajectory_msgs/MultiDOFJointTrajectoryPoint multi_dof_error
```
----
---
### `GripperCommand`
```yaml
@@ -310,17 +664,19 @@ bool reached_goal # True iff the gripper position has reached the commanded setp
```
----
---
### `JointTrajectory`
```yaml
trajectory_msgs/JointTrajectory trajectory
---
---
---
```
----
---
### `PointHead`
```yaml
@@ -330,12 +686,13 @@ string pointing_frame
builtin_interfaces/Duration min_duration
float64 max_velocity
---
---
float64 pointing_angle_error
```
----
---
### `SingleJointPosition`
```yaml
@@ -343,15 +700,16 @@ float64 position
builtin_interfaces/Duration min_duration
float64 max_velocity
---
---
std_msgs/Header header
float64 position
float64 velocity
float64 error
```
----
---
### `AssistedTeleop`
```yaml
@@ -363,10 +721,10 @@ builtin_interfaces/Duration total_elapsed_time
---
#feedback
builtin_interfaces/Duration current_teleop_duration
```
----
---
### `BackUp`
```yaml
@@ -380,10 +738,10 @@ builtin_interfaces/Duration total_elapsed_time
---
#feedback definition
float32 distance_traveled
```
----
---
### `ComputePathThroughPoses`
```yaml
@@ -398,10 +756,10 @@ nav_msgs/Path path
builtin_interfaces/Duration planning_time
---
#feedback definition
```
----
---
### `ComputePathToPose`
```yaml
@@ -416,10 +774,10 @@ nav_msgs/Path path
builtin_interfaces/Duration planning_time
---
#feedback definition
```
----
---
### `DriveOnHeading`
```yaml
@@ -433,10 +791,10 @@ builtin_interfaces/Duration total_elapsed_time
---
#feedback definition
float32 distance_traveled
```
----
---
### `DummyBehavior`
```yaml
@@ -447,10 +805,10 @@ std_msgs/String command
builtin_interfaces/Duration total_elapsed_time
---
#feedback definition
```
----
---
### `FollowPath`
```yaml
@@ -465,10 +823,10 @@ std_msgs/Empty result
#feedback definition
float32 distance_to_goal
float32 speed
```
----
---
### `FollowWaypoints`
```yaml
@@ -480,10 +838,10 @@ int32[] missed_waypoints
---
#feedback definition
uint32 current_waypoint
```
----
---
### `NavigateThroughPoses`
```yaml
@@ -501,10 +859,10 @@ builtin_interfaces/Duration estimated_time_remaining
int16 number_of_recoveries
float32 distance_remaining
int16 number_of_poses_remaining
```
----
---
### `NavigateToPose`
```yaml
@@ -521,10 +879,10 @@ builtin_interfaces/Duration navigation_time
builtin_interfaces/Duration estimated_time_remaining
int16 number_of_recoveries
float32 distance_remaining
```
----
---
### `SmoothPath`
```yaml
@@ -540,10 +898,10 @@ builtin_interfaces/Duration smoothing_duration
bool was_completed
---
#feedback definition
```
----
---
### `Spin`
```yaml
@@ -556,10 +914,10 @@ builtin_interfaces/Duration total_elapsed_time
---
#feedback definition
float32 angular_distance_traveled
```
----
---
### `Wait`
```yaml
@@ -571,7 +929,6 @@ builtin_interfaces/Duration total_elapsed_time
---
#feedback definition
builtin_interfaces/Duration time_left
```
----
---

View File

@@ -1,37 +1,142 @@
# 添加新动作指令Action
1.`unilabos_msgs/action` 中新建实验操作名和参数列表,如 `MyDeviceCmd.action`。一个 Action 定义由三个部分组成分别是目标Goal、结果Result和反馈Feedback之间使用 `---` 分隔:
本指南将引导你完成添加新动作指令的整个流程,包括编写、在线构建和测试。
## 1. 编写新的 Action
### 1.1 创建 Action 文件
`unilabos_msgs/action` 目录中新建实验操作文件,如 `MyDeviceCmd.action`。一个 Action 定义由三个部分组成分别是目标Goal、结果Result和反馈Feedback之间使用 `---` 分隔:
```action
# 目标Goal
# 目标Goal- 定义动作执行所需的参数
string command
float64 timeout
---
# 结果Result
bool success
# 结果Result- 定义动作完成后返回的结果
bool success # 要求必须包含success以便回传执行结果
string return_info # 要求必须包含return_info以便回传执行结果
... # 其他
---
# 反馈Feedback
# 反馈Feedback- 定义动作执行过程中的反馈信息
float64 progress
string status
```
2.`unilabos_msgs/CMakeLists.txt` 中添加新定义的 action
### 1.2 更新 CMakeLists.txt
`unilabos_msgs/CMakeLists.txt` 中的 `add_action_files()` 部分添加新定义的 action
```cmake
add_action_files(
FILES
MyDeviceCmd.action
# 其他已有的 action 文件...
)
```
3. 因为在指令集中新建了指令,因此调试时需要编译,并在终端环境中加载临时路径:
## 2. 在线构建和测试
为了简化开发流程并确保构建环境的一致性,我们使用 GitHub Actions 进行在线构建。
### 2.1 Fork 仓库并创建分支
1. **Fork 仓库**:在 GitHub 上 fork `Uni-Lab-OS` 仓库到你的个人账户
2. **Clone 你的 fork**
```bash
git clone https://github.com/YOUR_USERNAME/Uni-Lab-OS.git
cd Uni-Lab-OS
```
3. **创建功能分支**
```bash
git checkout -b add-my-device-action
```
4. **提交你的更改**
```bash
git add unilabos_msgs/action/MyDeviceCmd.action
git add unilabos_msgs/CMakeLists.txt
git commit -m "Add MyDeviceCmd action for device control"
git push origin add-my-device-action
```
### 2.2 触发在线构建
1. **访问你的 fork 仓库**:在浏览器中打开你的 fork 仓库页面
2. **手动触发构建**
- 点击 "Actions" 标签
- 选择 "Multi-Platform Conda Build" 工作流
- 点击 "Run workflow" 按钮
3. **监控构建状态**
- 构建过程大约需要 5-10 分钟
- 在 Actions 页面可以实时查看构建日志
- 构建完成后,可以下载生成的 conda 包进行测试
### 2.3 下载和测试构建包
1. **下载构建产物**
- 在构建完成的 Action 页面,找到 "Artifacts" 部分
- 下载对应平台的 `conda-package-*` 文件
2. **本地测试安装**
```bash
# 解压下载的构建产物
unzip conda-package-linux-64.zip # 或其他平台
# 安装测试包
mamba install ./ros-humble-unilabos-msgs-*.conda
```
3. **验证 Action 是否正确添加**
```bash
# 检查 action 是否可用
ros2 interface show unilabos_msgs/action/MyDeviceCmd
```
## 3. 提交 Pull Request
测试成功后,向主仓库提交 Pull Request
1. **创建 Pull Request**
- 在你的 fork 仓库页面,点击 "New Pull Request"
- 选择你的功能分支作为源分支
- 填写详细的 PR 描述,包括:
- 添加的 Action 功能说明
- 测试结果
- 相关的设备或用例
2. **等待审核和合并**
- 维护者会审核你的代码
- CI/CD 系统会自动运行完整的测试套件
- 合并后,新的指令集会自动发布到官方 conda 仓库
## 4. 使用新的 Action
如果采用自己构建的action包可以通过以下命令更新安装
```bash
cd unilabos_msgs
colcon build
source ./install/local_setup.sh
cd ..
mamba remove --force ros-humble-unilabos-msgs
mamba config set safety_checks disabled # 如果没有提升版本号会触发md5与网络上md5不一致是正常现象因此通过本指令关闭md5检查
mamba install xxx.conda --offline
```
调试成功后,发起 pull requestUni-Lab 的 CI/CD 系统会自动将新的指令集编译打包mamba执行升级即可永久生效
## 常见问题
```bash
mamba update ros-humble-unilabos-msgs -c http://quetz.dp.tech:8088/get/unilab -c robostack-humble -c robostack-staging
```
**Q: 构建失败怎么办?**
A: 检查 Actions 日志中的错误信息,通常是语法错误或依赖问题。修复后重新推送代码即可自动触发新的构建。
**Q: 如何测试特定平台?**
A: 在手动触发构建时,在平台选择中只填写你需要的平台,如 `linux-64` 或 `win-64`。
**Q: 构建包在哪里下载?**
A: 在 Actions 页面的构建结果中,查找 "Artifacts" 部分,每个平台都有对应的构建包可供下载。

View File

@@ -0,0 +1,147 @@
# 电池装配工站接入PLC
本指南将引导你完成电池装配工站(以 PLC 控制为例)的接入流程,包括新建工站文件、编写驱动与寄存器读写、生成注册表、上传及注意事项。
## 1. 新建工站文件
### 1.1 创建工站文件
`unilabos/devices/workstation/coin_cell_assembly` 目录下新建工站文件,如 `coin_cell_assembly.py`。工站类需继承 `WorkstationBase`,并在构造函数中初始化通信客户端与寄存器映射。
```python
from typing import Optional
# 工站基类
from unilabos.devices.workstation.workstation_base import WorkstationBase
# Modbus 通讯与寄存器 CSV 支持
from unilabos.device_comms.modbus_plc.client import TCPClient, BaseClient
class CoinCellAssemblyWorkstation(WorkstationBase):
def __init__(
self,
station_resource,
address: str = "192.168.1.20",
port: str = "502",
*args,
**kwargs,
):
super().__init__(station_resource=station_resource, *args, **kwargs)
self.station_resource = station_resource # 物料台面Deck
self.success: bool = False
self.allow_data_read: bool = False
self.csv_export_thread = None
self.csv_export_running = False
self.csv_export_file: Optional[str] = None
# 连接 PLC并注册寄存器节点
tcp = TCPClient(addr=address, port=port)
tcp.client.connect()
self.nodes = BaseClient.load_csv(".../PLC_register.csv")
self.client = tcp.register_node_list(self.nodes)
```
## 2. 编写驱动与寄存器读写
### 2.1 寄存器示例
- `COIL_SYS_START_CMD`BOOL地址 8010启动命令脉冲式
- `COIL_SYS_START_STATUS`BOOL地址 8210启动状态
- `REG_DATA_OPEN_CIRCUIT_VOLTAGE`FLOAT32地址 10002开路电压
- `REG_DATA_ASSEMBLY_PRESSURE`INT16地址 10014压制扣电压力
### 2.2 最小驱动示例
```python
from unilabos.device_comms.modbus_plc.modbus import WorderOrder
def start_and_read_metrics(self):
# 1) 下发启动(置 True 再复位 False
self.client.use_node('COIL_SYS_START_CMD').write(True)
self.client.use_node('COIL_SYS_START_CMD').write(False)
# 2) 等待进入启动状态
while True:
status, _ = self.client.use_node('COIL_SYS_START_STATUS').read(1)
if bool(status[0]):
break
# 3) 读取关键数据FLOAT32 需读 2 个寄存器并指定字节序)
voltage, _ = self.client.use_node('REG_DATA_OPEN_CIRCUIT_VOLTAGE').read(
2, word_order=WorderOrder.LITTLE
)
pressure, _ = self.client.use_node('REG_DATA_ASSEMBLY_PRESSURE').read(1)
return {
'open_circuit_voltage': voltage,
'assembly_pressure': pressure,
}
```
> 提示:若需参数下发,可在 PLC 端设置标志寄存器并完成握手复位,避免粘连与竞争。
## 3. 本地生成注册表并校验
完成工站类与驱动后,需要生成(或更新)工站注册表供系统识别。
### 3.1 新增工站设备(或资源)首次生成注册表
首先通过以下命令启动unilab。进入unilab系统状态检查页面
```bash
python unilabos\app\main.py -g celljson.json --ak <user的AK> --sk <user的SK>
```
点击注册表编辑,进入注册表编辑页面
![Layers](image_add_batteryPLC/unilab_sys_status.png)
按照图示步骤填写自动生成注册表信息:
![Layers](image_add_batteryPLC/unilab_registry_process.png)
步骤说明:
1. 选择新增的工站`coin_cell_assembly.py`文件
2. 点击分析按钮,分析`coin_cell_assembly.py`文件
3. 选择`coin_cell_assembly.py`文件中继承`WorkstationBase`
4. 填写新增的工站.py文件与`unilabos`目录的距离。例如,新增的工站文件`coin_cell_assembly.py`路径为`unilabos\devices\workstation\coin_cell_assembly\coin_cell_assembly.py`,则此处填写`unilabos.devices.workstation.coin_cell_assembly`
5. 此处填写新定义工站的类的名字(名称可以自拟)
6. 填写新的工站注册表备注信息
7. 生成注册表
以上操作步骤完成则会生成的新的注册表ymal文件如下图
![Layers](image_add_batteryPLC/unilab_new_yaml.png)
### 3.2 添加新生成注册表
`unilabos\registry\devices`目录下新建一个yaml文件此处新建文件命名为`coincellassemblyworkstation_device.yaml`,将上面生成的新的注册表信息粘贴到`coincellassemblyworkstation_device.yaml`文件中。
在终端输入以下命令进行注册表补全操作。
```bash
python unilabos\app\register.py --complete_registry
```
### 3.3 启动并上传注册表
新增设备之后启动unilab需要增加`--upload_registry`参数,来上传注册表信息。
```bash
python unilabos\app\main.py -g celljson.json --ak <user的AK> --sk <user的SK> --upload_registry
```
## 4. 注意事项
- 在新生成的 YAML 中,确认 `module` 指向新工站类,本例中需检查`coincellassemblyworkstation_device.yaml`文件中是否指向了`coin_cell_assembly.py`文件中定义的`CoinCellAssemblyWorkstation`类文件:
```
module: unilabos.devices.workstation.coin_cell_assembly.coin_cell_assembly:CoinCellAssemblyWorkstation
```
- 首次新增设备(或资源)需要在网页端新增注册表信息,`--complete_registry`补全注册表,`--upload_registry`上传注册表信息。
- 如果不是新增设备(或资源),仅对工站驱动的.py文件进行了修改则不需要在网页端新增注册表信息。只需要运行补全注册表信息之后上传注册表即可。

View File

@@ -13,36 +13,36 @@ class MockGripper:
self._velocity: float = 2.0
self._torque: float = 0.0
self._status = "Idle"
@property
def position(self) -> float:
return self._position
@property
def velocity(self) -> float:
return self._velocity
@property
def torque(self) -> float:
return self._torque
# 会被自动识别的设备属性,接入 Uni-Lab 时会定时对外广播
@property
def status(self) -> str:
return self._status
# 会被自动识别的设备动作,接入 Uni-Lab 时会作为 ActionServer 接受任意控制者的指令
@status.setter
def status(self, target):
self._status = target
# 需要在注册表添加的设备动作,接入 Uni-Lab 时会作为 ActionServer 接受任意控制者的指令
def push_to(self, position: float, torque: float, velocity: float = 0.0):
self._status = "Running"
current_pos = self.position
if velocity == 0.0:
velocity = self.velocity
move_time = abs(position - current_pos) / velocity
for i in range(20):
self._position = current_pos + (position - current_pos) / 20 * (i+1)
@@ -68,7 +68,7 @@ public class MockGripper
public double velocity { get; private set; } = 2.0;
public double torque { get; private set; } = 0.0;
public string status { get; private set; } = "Idle";
// 需要在注册表添加的设备动作,接入 Uni-Lab 时会作为 ActionServer 接受任意控制者的指令
public async Task PushToAsync(double Position, double Torque, double Velocity = 0.0)
{
@@ -94,107 +94,61 @@ public class MockGripper
C# 驱动设备在完成注册表后,需要调用 Uni-Lab C# 编译后才能使用,但只需一次。
## 注册表文件位置
## 快速开始:使用注册表编辑器(推荐)
Uni-Lab 启动时会自动读取默认注册表路径 `unilabos/registry/devices` 下的所有注册设备。您也可以任意维护自己的注册表路径,只需要在 Uni-Lab 启动时使用 `--registry` 参数将路径添加即可。
推荐使用 Uni-Lab-OS 自带的可视化编辑器,它能自动分析您的设备驱动并生成大部分配置:
`<path-to-registry>/devices` 中新建一个 yaml 文件,即可开始撰写。您可以将多个设备写到同一个 yaml 文件中。
1. 启动 Uni-Lab-OS
2. 在浏览器中打开"注册表编辑器"页面
3. 选择您的 Python 设备驱动文件
4. 点击"分析文件",让系统读取类信息
5. 填写基本信息(设备描述、图标等)
6. 点击"生成注册表",复制生成的内容
7. 保存到 `devices/` 目录下
## 注册表的结构
---
1. 顶层名称:每个设备的注册表以设备名称开头,例如 `new_device`, `gripper.mock`
1. `class` 字段:定义设备的模块路径和驱动程序语言。
1. `status_types` 字段:定义设备定时对 Uni-Lab 实验室内发送的属性名及其类型。
1. `action_value_mappings` 字段:定义设备支持的动作及其目标、反馈和结果。
1. `schema` 字段:定义设备定时对 Uni-Lab 云端监控发送的属性名及其类型、描述(非必须)
## 手动编写注册表(简化版)
## 创建新的注册表教程
如果需要手动编写,只需要提供两个必需字段,系统会自动补全其余内容:
1. 创建文件
在 devices 文件夹中创建一个新的 YAML 文件,例如 `new_device.yaml`
2. 定义设备名称
在文件中定义设备的顶层名称,例如:`new_device``gripper.mock`
3. 定义设备的类信息
添加设备的模块路径和类型:
### 最小配置示例
```yaml
gripper.mock:
class: # 定义设备的类信息
module: unilabos.devices.gripper.mock:MockGripper
type: python # 指定驱动语言为 Python
status_types:
position: Float64
torque: Float64
status: String
my_device: # 设备唯一标识符
class:
module: unilabos.devices.your_module.my_device:MyDevice # Python 类路径
type: python # 驱动类型
```
4. 定义设备的定时发布属性。注意,对于 Python Class 来说PROP 是 class 的 `property`,或满足能被 `getattr(cls, PROP)``cls.get_PROP` 读取到的属性值的对象。
### 注册表文件位置
- 默认路径:`unilabos/registry/devices`
- 自定义路径:启动时使用 `--registry` 参数指定
- 可将多个设备写在同一个 yaml 文件中
### 系统自动生成的内容
系统会自动分析您的 Python 驱动类并生成:
- `status_types`:从 `get_*` 方法自动识别状态属性
- `action_value_mappings`:从类方法自动生成动作映射
- `init_param_schema`:从 `__init__` 方法分析初始化参数
- `schema`:前端显示用的属性类型定义
### 完整结构概览
```yaml
status_types:
PROP: TYPE
```
5. 定义设备支持的动作
添加设备支持的动作及其目标、反馈和结果:
```yaml
action_value_mappings:
set_speed:
type: SendCmd
goal:
command: speed
feedback: {}
result:
success: success
my_device:
class:
module: unilabos.devices.your_module.my_device:MyDevice
type: python
status_types: {} # 自动生成
action_value_mappings: {} # 自动生成
description: '' # 可选:设备描述
icon: '' # 可选:设备图标
init_param_schema: {} # 自动生成
schema: {} # 自动生成
```
在 devices 文件夹中的 YAML 文件中action_value_mappings 是用来将驱动内的动作函数,映射到 Uni-Lab 标准动作actions及其目标参数值goal、反馈值feedback和结果值result的映射规则。若在 Uni-Lab 指令集内找不到符合心意的,请【创建新指令】
```yaml
action_value_mappings:
<action_name>: # <action_name>:动作的名称
# start启动设备或某个功能。
# stop停止设备或某个功能。
# set_speed设置设备的速度。
# set_temperature设置设备的温度。
# move_to_position移动设备到指定位置。
# stir执行搅拌操作。
# heatchill执行加热或冷却操作。
# send_nav_task发送导航任务例如机器人导航
# set_timer设置设备的计时器。
# valve_open_cmd打开阀门。
# valve_close_cmd关闭阀门。
# execute_command_from_outer执行外部命令。
# push_to控制设备推送到某个位置例如机械爪
# move_through_points导航设备通过多个点。
type: <ActionType> # 动作的类型,表示动作的功能
# 根据动作的功能选择合适的类型,请查阅 Uni-Lab 已支持的指令集。
goal: # 定义动作的目标值映射,表示需要传递给设备的参数。
<goal_key>: <mapped_value> #确定设备需要的输入参数,并将其映射到设备的字段。
feedback: # 定义动作的反馈值映射,表示设备执行动作时返回的实时状态。
<feedback_key>: <mapped_value>
result: # 定义动作的结果值映射,表示动作完成后返回的最终结果。
<result_key>: <mapped_value>
```
6. 定义设备的网页展示属性类型,这部分会被用于在 Uni-Lab 网页端渲染成状态监控
添加设备的属性模式,包括属性类型和描述:
```yaml
schema:
type: object
properties:
status:
type: string
description: The status of the device
speed:
type: number
description: The speed of the device
required:
- status
- speed
additionalProperties: false
```
详细的注册表编写指南和高级配置,请参考{doc}`yaml 注册表编写指南 <add_yaml>`

View File

@@ -1,95 +1,610 @@
# yaml注册表编写指南
# yaml 注册表编写指南
`注册表的结构`
## 快速开始:使用注册表编辑器
1. 顶层名称:每个设备的注册表以设备名称开头,例如 new_device
2. class 字段:定义设备的模块路径和类型。
3. schema 字段:定义设备的属性模式,包括属性类型、描述和必需字段。
4. action_value_mappings 字段:定义设备支持的动作及其目标、反馈和结果。
推荐使用 UniLabOS 自带的可视化编辑器,它能帮你自动生成大部分配置,省去手写的麻烦
`创建新的注册表教程`
1. 创建文件
在 devices 文件夹中创建一个新的 YAML 文件,例如 new_device.yaml。
### 怎么用编辑器
2. 定义设备名称
在文件中定义设备的顶层名称例如new_device
1. 启动 UniLabOS
2. 在浏览器中打开"注册表编辑器"页面
3. 选择你的 Python 设备驱动文件
4. 点击"分析文件",让系统读取你的类信息
5. 填写一些基本信息(设备描述、图标啥的)
6. 点击"生成注册表",复制生成的内容
7. 把内容保存到 `devices/` 目录下
3. 定义设备的类信息
添加设备的模块路径和类型:
我们为你准备了一个测试驱动用于在界面上尝试注册表生成参见目录test\registry\example_devices.py
```python
new_device: # 定义一个名为 linear_motion.grbl 的设备
---
## 手动编写指南
class: # 定义设备的类信息
module: unilabos.devices_names.new_device:NewDeviceClass # 指定模块路径和类名
type: python # 指定类型为 Python 类
status_types:
```
4. 定义设备支持的动作
添加设备支持的动作及其目标、反馈和结果:
```python
action_value_mappings:
set_speed:
type: SendCmd
goal:
command: speed
feedback: {}
result:
success: success
```
`如何编写action_valve_mappings`
1. 在 devices 文件夹中的 YAML 文件中action_value_mappings 是用来定义设备支持的动作actions及其目标值goal、反馈值feedback和结果值result的映射规则。以下是规则和编写方法
```python
action_value_mappings:
<action_name>: # <action_name>:动作的名称
# start启动设备或某个功能。
# stop停止设备或某个功能。
# set_speed设置设备的速度。
# set_temperature设置设备的温度。
# move_to_position移动设备到指定位置。
# stir执行搅拌操作。
# heatchill执行加热或冷却操作。
# send_nav_task发送导航任务例如机器人导航
# set_timer设置设备的计时器。
# valve_open_cmd打开阀门。
# valve_close_cmd关闭阀门。
# execute_command_from_outer执行外部命令。
# push_to控制设备推送到某个位置例如机械爪
# move_through_points导航设备通过多个点。
如果你想自己写 yaml 文件,或者想深入了解结构,查阅下方说明。
type: <ActionType> # 动作的类型,表示动作的功能
# 根据动作的功能选择合适的类型:
# SendCmd发送简单命令。
# NavigateThroughPoses导航动作。
# SingleJointPosition设置单一关节的位置。
# Stir搅拌动作。
# HeatChill加热或冷却动作。
## 注册表的基本结构
goal: # 定义动作的目标值映射,表示需要传递给设备的参数。
<goal_key>: <mapped_value> #确定设备需要的输入参数,并将其映射到设备的字段。
yaml 注册表就是设备的配置文件,里面定义了设备怎么用、有什么功能。好消息是系统会自动帮你填大部分内容,你只需要写两个必需的东西:设备名和 class 信息。
feedback: # 定义动作的反馈值映射,表示设备执行动作时返回的实时状态。
<feedback_key>: <mapped_value>
result: # 定义动作的结果值映射,表示动作完成后返回的最终结果。
<result_key>: <mapped_value>
### 各字段用途
| 字段名 | 类型 | 需要手写 | 说明 |
| ----------------- | ------ | -------- | ----------------------------------- |
| 设备标识符 | 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`
### 完整结构是什么样的
```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: [] # 嵌套配置,通常为空
```
6. 定义设备的属性模式
添加设备的属性模式,包括属性类型和描述:
```python
schema:
type: object
## action_value_mappings 怎么写
这个部分定义设备能做哪些动作。好消息是系统会自动生成大部分动作,你通常只需要添加一些特殊的自定义动作。
### 系统自动生成哪些动作
系统会帮你生成这些:
1.`auto-` 开头的动作:从你 Python 类的方法自动生成
2. 通用的驱动动作:
- `_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`:加热冷却动作
### 复杂一点的例子
```yaml
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 服务
### 示例:完整的动作配置
```yaml
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 类,从状态方法自动生成这部分:
```yaml
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
这个完全是系统自动生成的,你不用管:
```yaml
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
description: The status of the device
speed:
type: number
description: The speed of the device
required:
- status
- speed
additionalProperties: false
type: object
```
# 写完yaml注册表后需要添加到哪些其他文件
生成规则很简单:
- `config` 部分:看你类的 `__init__` 方法有什么参数,类型和默认值是啥
- `data` 部分:根据 `status_types` 生成前端显示用的类型定义
### 其他自动填充的字段
```yaml
version: '1.0.0' # 默认版本
category: ['文件名'] # 用你的 yaml 文件名当类别
description: '' # 默认为空,你可以手动改
icon: '' # 默认为空,你可以加图标
handles: [] # 默认空数组
config_info: [] # 默认空数组
file_path: '/path/to/file' # 系统自动填文件路径
registry_type: 'device' # 自动设为设备类型
```
### handles 字段
这个是定义设备连接关系的,类似动作里的 handles 一样:
```yaml
handles: # 大多数时候都是空的,除非设备本身需要连接啥
- handler_key: device_output
label: Device Output
data_type: resource
data_source: value
data_key: default_value
```
### 其他可以配置的字段
```yaml
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
```
## 完整的例子
这里是一个比较完整的设备配置示例:
```yaml
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: []
```
## 怎么部署和使用
### 方法一:用编辑器(推荐)
1. 先写好你的 Python 驱动类
2. 用注册表编辑器自动生成 yaml 配置
3. 把生成的文件保存到 `devices/` 目录
4. 重启 UniLabOS 就能用了
### 方法二:手动写(简化版)
1. 创建最简配置:
```yaml
# devices/my_device.yaml
my_device:
class:
module: unilabos.devices.my_module.my_device:MyDevice
type: python
```
2. 启动系统时用 `complete_registry=True` 参数,让系统自动补全
3. 检查一下生成的配置是不是你想要的
### Python 驱动类要怎么写
你的设备类要符合这些要求:
```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
```
### 系统集成
1. 把 yaml 文件放到 `devices/` 目录下
2. 系统启动时会自动扫描并加载设备
3. 系统会自动补全所有缺失的字段
4. 设备马上就能在前端界面中使用
### 高级配置
如果需要特殊设置,可以手动加:
```yaml
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']
```
## 常见问题怎么排查
### 设备加载不了
1. 检查模块路径:确认 `class.module` 路径写对了
2. 确认类能导入:看看你的 Python 驱动类能不能正常导入
3. 检查语法:用 yaml 验证器看看文件格式对不对
4. 查看日志:看 UniLabOS 启动时有没有报错信息
### 自动生成失败了
1. 类分析出问题:确认你的类继承了正确的基类
2. 方法类型不明确:确保状态方法的返回类型写清楚了
3. 导入有问题:检查类能不能被动态导入
4. 没开完整注册:确认启用了 `complete_registry=True`
### 前端显示有问题
1. 重新生成:删掉旧的 yaml 文件,用编辑器重新生成
2. 清除缓存:清除浏览器缓存,重新加载页面
3. 检查字段:确认必需的字段(比如 `schema`)都有
4. 验证数据:检查 `goal_default``schema` 的数据类型是不是一致
### 动作执行出错
1. 方法名不对:确认动作方法名符合规范(比如 `execute_<action_name>`
2. 参数映射错误:检查 `goal` 字段的参数映射是否正确
3. 返回格式不对:确认方法返回值格式符合 `result` 映射
4. 没异常处理:在驱动类里加上异常处理
## 最佳实践
### 开发流程
1. **优先使用编辑器**:除非有特殊需求,否则优先使用注册表编辑器
2. **最小化配置**:手动配置时只定义必要字段,让系统自动生成其他内容
3. **增量开发**:先创建基本配置,后续根据需要添加特殊动作
### 代码规范
1. **方法命名**:状态方法使用 `get_` 前缀,动作方法使用动词开头
2. **类型注解**:为方法参数和返回值添加类型注解
3. **文档字符串**:为类和方法添加详细的文档字符串
4. **异常处理**:实现完善的错误处理和日志记录
### 配置管理
1. **版本控制**:所有 yaml 文件纳入版本控制
2. **命名一致性**:设备 ID、文件名、类名保持一致的命名风格
3. **定期更新**:定期运行完整注册以更新自动生成的字段
4. **备份配置**:在修改前备份重要的手动配置
### 测试验证
1. **本地测试**:在本地环境充分测试后再部署
2. **渐进部署**:先部署到测试环境,验证无误后再上生产环境
3. **监控日志**:密切监控设备加载和运行日志
4. **回滚准备**:准备快速回滚机制,以应对紧急情况
### 性能优化
1. **按需加载**:只加载实际使用的设备类型
2. **缓存利用**:充分利用系统的注册表缓存机制
3. **资源管理**:合理管理设备连接和资源占用
4. **监控指标**:设置关键性能指标的监控和告警

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

View File

@@ -0,0 +1,409 @@
# 物料教程Resource
本教程面向 Uni-Lab-OS 的开发者讲解“物料”的核心概念、3种物料格式UniLab、PyLabRobot、奔耀Bioyond及其相互转换方法并说明4种 children 结构表现形式及使用场景。
---
## 1. 物料是什么
- **物料Resource**指实验工作站中的实体对象包括设备device、操作甲板 deck、试剂、实验耗材也包括设备上承载的具体物料或者包含的容器如container/plate/well/瓶/孔/片等)。
- **物料基本信息**(以 UniLab list格式为例
```jsonc
{
"id": "plate", // 某一类物料的唯一名称
"name": "50ml瓶装试剂托盘", // 在云端显示的名称
"sample_id": null, // 同类物料的不同样品
"children": [
"50ml试剂瓶" // 表示托盘上有一个 50ml 试剂瓶
],
"parent": "deck", // 此物料放置在 deck 上
"type": "plate", // 物料类型
"class": "plate", // 物料对应的注册/类名
"position": {
"x": 0, // 初始放置位置
"y": 0,
"z": 0
},
"config": { // 固有配置(尺寸、旋转等)
"size_x": 400.0,
"size_y": 400.0,
"size_z": 400.0,
"rotation": {
"x": 0,
"y": 0,
"z": 0,
"type": "Rotation"
}
},
"data": {
"bottle_number": 1 // 动态数据(可变化)
}
}
```
## 2. 3种物料格式概览(UniLab、PyLabRobot、奔耀Bioyond)
### 2.1 UniLab 物料格式(云端/项目内通用)
- 结构特征:顶层通常是 `nodes` 列表;每个节点是扁平字典,`children` 是子节点 `id` 列表;`parent` 为父节点 `id``null`
- 用途:
- 云端数据存储、前端可视化、与图结构算法互操作
- 在上传/下载/部署配置时作为标准交换格式
示例片段UniLab 物料格式):
```jsonc
{
"nodes": [
{
"id": "a",
"name": "name_a",
"sample_id": 1,
"type": "deck",
"class": "deck",
"parent": null,
"children": ["b1"],
"position": {"x": 0, "y": 0, "z": 0},
"config": {},
"data": {}
},
{
"id": "b1",
"name": "name_b1",
"sample_id": 1,
"type": "plate",
"class": "plate",
"parent": "a1",
"children": [],
"position": {"x": 0, "y": 0, "z": 0},
"config": {},
"data": {}
}
]
}
```
### 2.2 PyLabRobotPLR物料格式实验流程运行时
- 结构特征:严格的层级树,`children` 为“子资源字典列表”(每个子节点本身是完整对象)。
- 用途:
- 实验流程执行与调度PLR 运行时期望的资源对象格式
- 通过 `Resource.deserialize/serialize``load_all_state/serialize_all_state` 与对象交互
示例片段PRL 物料格式)::
```json
{
"name": "deck",
"type": "Deck",
"category": "deck",
"location": {"x": 0, "y": 0, "z": 0, "type": "Coordinate"},
"rotation": {"x": 0, "y": 0, "z": 0, "type": "Rotation"},
"parent_name": null,
"children": [
{
"name": "plate_1",
"type": "Plate",
"category": "plate_96",
"location": {"x": 100, "y": 0, "z": 0, "type": "Coordinate"},
"rotation": {"x": 0, "y": 0, "z": 0, "type": "Rotation"},
"parent_name": "deck",
"children": [
{
"name": "A1",
"type": "Well",
"category": "well",
"location": {"x": 0, "y": 0, "z": 0, "type": "Coordinate"},
"rotation": {"x": 0, "y": 0, "z": 0, "type": "Rotation"},
"parent_name": "plate_1",
"children": []
}
]
}
]
}
```
### 2.3 奔耀 Bioyond 物料格式(第三方来源)
一般是厂商自己定义的json格式和字段信息需要提取和对应。以下为示例说明。
- 结构特征:顶层 `data` 列表,每项包含 `typeName``code``barCode``name``quantity``unit``locations`(仓位 `whName``x/y/z`)、`detail`(细粒度内容,如瓶内液体或孔位物料)。
- 用途:
- 第三方 WMS/设备的物料清单输入
- 需要自定义映射表将 `typeName` → PLR 类名,对 `locations`/`detail` 进行落位/赋值
示例片段奔耀Bioyond 物料格式):
```json
{
"data": [
{
"id": "3a1b5c10-d4f3-01ac-1e64-5b4be2add4b1",
"typeName": "液",
"code": "0006-00014",
"barCode": "",
"name": "EMC",
"quantity": 50,
"lockQuantity": 2.057,
"unit": "瓶",
"status": 1,
"isUse": false,
"locations": [
{
"id": "3a19da43-57b5-5e75-552f-8dbd0ad1075f",
"whid": "3a19da43-57b4-a2a8-3f52-91dbbeb836db",
"whName": "配液站内试剂仓库",
"code": "0003-0003",
"x": 1,
"y": 3,
"z": 1,
"quantity": 0
}
],
"detail": [
{
"code": "0006-00014-01",
"name": "EMC-瓶-1",
"x": 1,
"y": 3,
"z": 1,
"quantity": 500.0
}
]
}
],
"code": 1,
"message": "",
"timestamp": 0
}
```
### 2.4 3种物料格式关键字段对应(UniLab、PyLabRobot、奔耀Bioyond)
| 含义 | UniLab | PyLabRobot (PLR) | 奔耀 Bioyond |
| - | - | - | - |
| 节点唯一名 | `id` | `name` | `name` |
| 父节点引用 | `parent` | `parent_name` | `locations` 坐标(无直接父名,需映射坐标下的物料) |
| 子节点集合 | `children`id 列表或对象列表,视结构而定) | `children`(对象列表) | `detail`(明细,非严格树结构,需要自定义映射) |
| 类型(抽象类别) | `type`device/container/plate/deck/…) | `category`plate/well/…),以及类名 `type` | `typeName`(厂商自定义,如“液”、“加样头(大)”) |
| 运行/业务数据 | `data` | 通过 `serialize_all_state()`/`load_all_state()` 管理的状态 | `quantity``lockQuantity` 等业务数值 |
| 固有配置 | `config`size_x/size_y/size_z/model/ordering… | 资源字典中的同名键(反序列化时按构造签名取用) | 厂商自定义字段(需映射入 PLR/UniLab 的 `config``data` |
| 空间位置 | `position`x/y/z | `location`Coordinate + `rotation`Rotation | `locations`whName、x/y/z不含旋转 |
| 条码/标识 | `config.barcode`(可选) | 常放在配置键中(如 `barcode` | `barCode` |
| 数量单位 | 无固定键,通常在 `data` | 无固定键,通常在配置或状态中 | `unit` |
| 物料编码 | 通常在 `config``data` 自定义 | 通常在配置中自定义 | `code` |
说明:
- Bioyond 不提供显式的树形父子关系,通常通过 `locations` 将物料落位到某仓位/坐标。用 `detail` 表示子级明细。
---
## 3. children 的四种结构表示
- **list扁平列表**:每个节点是扁平字典,`children` 为子节点 `id` 数组。示例UniLab `nodes` 中的单个节点。
```json
{
"nodes": [
{ "id": "root", "parent": null, "children": ["child1"] },
{ "id": "child1", "parent": "root", "children": [] }
]
}
```
- **dict嵌套字典**:节点的 `children``{ child_id: child_node_dict }` 字典。
```json
{
"id": "root",
"parent": null,
"children": {
"child1": { "id": "child1", "parent": "root", "children": {} }
}
}
```
- **tree树形列表**:顶层是 `[root_node, ...]`,每个 `node.children` 是“子节点对象列表”(而非 id 列表)。
```json
[
{
"id": "root",
"parent": null,
"children": [
{ "id": "child1", "parent": "root", "children": [] }
]
}
]
```
- **nestdict顶层嵌套字典**:顶层是 `{root_id: root_node, ...}`,或者根节点自身带 `children: {id: node}` 形态。
```json
{
"root": {
"id": "root",
"parent": null,
"children": {
"child1": { "id": "child1", "parent": "root", "children": {} }
}
}
}
```
这些结构之间可使用 `graphio.py` 中的工具函数互转(见下一节)。
---
## 4. 转换函数及调用
核心代码文件:`unilabos/resources/graphio.py`
### 4.1 结构互转list/dict/tree/nestdict
代码引用:
```217:239:unilabos/resources/graphio.py
def dict_to_tree(nodes: dict, devices_only: bool = False) -> list[dict]:
# ... 由扁平 dictid->node生成树children 为对象列表)
```
```241:267:unilabos/resources/graphio.py
def dict_to_nested_dict(nodes: dict, devices_only: bool = False) -> dict:
# ... 由扁平 dict 生成嵌套字典children 为 {id:node}
```
```270:273:unilabos/resources/graphio.py
def list_to_nested_dict(nodes: list[dict]) -> dict:
# ... 由扁平列表children 为 id 列表)转嵌套字典
```
```275:286:unilabos/resources/graphio.py
def tree_to_list(tree: list[dict]) -> list[dict]:
# ... 由树形列表转回扁平列表children 还原为 id 列表)
```
```289:337:unilabos/resources/graphio.py
def nested_dict_to_list(nested_dict: dict) -> list[dict]:
# ... 由嵌套字典转回扁平列表
```
常见路径:
- UniLab 扁平列表 → 树:`dict_to_tree({r["id"]: r for r in resources})`
- 树 → UniLab 扁平列表:`tree_to_list(resources_tree)`
- 扁平列表 ↔ 嵌套字典:`list_to_nested_dict` / `nested_dict_to_list`
### 4.2 UniLab ↔ PyLabRobotPLR
高层封装:
```339:368:unilabos/resources/graphio.py
def convert_resources_to_type(resources_list: list[dict], resource_type: Union[type, list[type]], *, plr_model: bool = False):
# UniLab -> (NestedDict or PLR)
```
```371:395:unilabos/resources/graphio.py
def convert_resources_from_type(resources_list, resource_type: Union[type, list[type]], *, is_plr: bool = False):
# (NestedDict or PLR) -> UniLab 扁平列表
```
底层转换:
```398:441:unilabos/resources/graphio.py
def resource_ulab_to_plr(resource: dict, plr_model=False) -> "ResourcePLR":
# UniLab 单节点(树根) -> PLR Resource 对象
```
```443:481:unilabos/resources/graphio.py
def resource_plr_to_ulab(resource_plr: "ResourcePLR", parent_name: str = None, with_children=True):
# PLR Resource -> UniLab 单节点(dict)
```
示例:
```python
from unilabos.resources.graphio import convert_resources_to_type, convert_resources_from_type
from pylabrobot.resources.resource import Resource as ResourcePLR
# UniLab 扁平列表 -> PLR 根资源对象
plr_root = convert_resources_to_type(resources_list=ulab_list, resource_type=ResourcePLR)
# PLR 资源对象 -> UniLab 扁平列表(用于保存/上传)
ulab_flat = convert_resources_from_type(resources_list=plr_root, resource_type=ResourcePLR)
```
可选项:
- `plr_model=True`:保留 `model` 字段(默认会移除)。
- `with_children=False``resource_plr_to_ulab` 仅转换当前节点。
### 4.3 奔耀Bioyond→ PLR及进一步到 UniLab
转换入口:
```483:527:unilabos/resources/graphio.py
def resource_bioyond_to_plr(bioyond_materials: list[dict], type_mapping: dict = {}, deck: Any = None) -> list[dict]:
# Bioyond 列表 -> PLR 资源列表,并可根据 deck.warehouses 将资源落位
```
使用示例:
```python
import json
from unilabos.resources.graphio import resource_bioyond_to_plr, convert_resources_from_type
from pylabrobot.resources.resource import Resource as ResourcePLR
resp = json.load(open("unilabos/devices/workstation/bioyond_cell/bioyond_test_yibin.json", encoding="utf-8"))
materials = resp["data"]
# 将第三方类型name映射到 PLR 资源类名(需根据现场定义)
type_mapping = {
"液": "RegularContainer",
"加样头(大)": "RegularContainer"
}
plr_list = resource_bioyond_to_plr(materials, type_mapping=type_mapping, deck=None)
# 如需上传云端UniLab 扁平格式):
ulab_flat = convert_resources_from_type(plr_list, [ResourcePLR])
```
说明:
- `type_mapping` 必须由开发者根据设备/物料种类人工维护。
- 如传入 `deck`,且 `deck.warehouses` 命名与 `whName` 对应可将物料安放到仓库坐标x/y/z
---
## 5. 何时使用哪种格式
- **云端/持久化**:使用 UniLab 物料格式(扁平 `nodes` 列表children 为 id 列表)。便于版本化、可视化与网络传输。
- **实验工作流执行**:使用 PyLabRobotPLR格式。PLR 运行时依赖严格的树形资源结构与对象 API。
- **第三方设备/系统Bioyond输入**:保持来源格式不变,使用 `resource_bioyond_to_plr` + 人工 `type_mapping` 将其转换为 PLR必要时再转 UniLab
---
## 6. 常见问题与注意事项
- **children 形态不一致**:不同函数期望不同 children 形态,注意在进入转换前先用“结构互转”工具函数标准化形态。
- **devices_only**`dict_to_tree/dict_to_nested_dict` 支持仅保留 `type == device` 的节点。
- **模型/类型字段**PLR 对象序列化参数有所差异,`resource_ulab_to_plr` 内部会根据构造签名移除不兼容字段(如 `category`)。
- **驱动初始化**`initialize_resource(s)` 支持从注册表/类路径创建 PLR/UniLab 资源或列表。
参考代码:
```530:577:unilabos/resources/graphio.py
def initialize_resource(resource_config: dict, resource_type: Any = None) -> Union[list[dict], ResourcePLR]:
# 从注册类/模块反射创建资源,或将 UniLab 字典包装为列表
```
```580:597:unilabos/resources/graphio.py
def initialize_resources(resources_config) -> list[dict]:
# 批量初始化
```

View File

@@ -0,0 +1,378 @@
# 工作站基础架构设计文档
## 1. 整体架构图
```mermaid
graph TB
subgraph "工作站基础架构"
WB[WorkstationBase]
WB --> |继承| RPN[ROS2WorkstationNode]
WB --> |组合| WCB[WorkstationCommunicationBase]
WB --> |组合| MMB[MaterialManagementBase]
WB --> |组合| WHS[WorkstationHTTPService]
end
subgraph "通信层实现"
WCB --> |实现| PLC[PLCCommunication]
WCB --> |实现| SER[SerialCommunication]
WCB --> |实现| ETH[EthernetCommunication]
end
subgraph "物料管理实现"
MMB --> |实现| PLR[PyLabRobotMaterialManager]
MMB --> |实现| BIO[BioyondMaterialManager]
MMB --> |实现| SIM[SimpleMaterialManager]
end
subgraph "HTTP服务"
WHS --> |处理| LIMS[LIMS协议报送]
WHS --> |处理| MAT[物料变更报送]
WHS --> |处理| ERR[错误处理报送]
end
subgraph "具体工作站实现"
WB --> |继承| WS1[PLCWorkstation]
WB --> |继承| WS2[ReportingWorkstation]
WB --> |继承| WS3[HybridWorkstation]
end
subgraph "外部系统"
EXT1[PLC设备] --> |通信| PLC
EXT2[外部工作站] --> |HTTP报送| WHS
EXT3[LIMS系统] --> |HTTP报送| WHS
EXT4[Bioyond物料系统] --> |查询| BIO
end
```
## 2. 类关系图
```mermaid
classDiagram
class WorkstationBase {
<<abstract>>
+device_id: str
+communication: WorkstationCommunicationBase
+material_management: MaterialManagementBase
+http_service: WorkstationHTTPService
+workflow_status: WorkflowStatus
+supported_workflows: Dict
+_create_communication_module()*
+_create_material_management_module()*
+_register_supported_workflows()*
+process_step_finish_report()
+process_sample_finish_report()
+process_order_finish_report()
+process_material_change_report()
+handle_external_error()
+start_workflow()
+stop_workflow()
+get_workflow_status()
+get_device_status()
}
class ROS2WorkstationNode {
+sub_devices: Dict
+protocol_names: List
+execute_single_action()
+create_ros_action_server()
+initialize_device()
}
class WorkstationCommunicationBase {
<<abstract>>
+config: CommunicationConfig
+is_connected: bool
+connect()
+disconnect()
+start_workflow()*
+stop_workflow()*
+get_device_status()*
+write_register()
+read_register()
}
class MaterialManagementBase {
<<abstract>>
+device_id: str
+deck_config: Dict
+resource_tracker: DeviceNodeResourceTracker
+plr_deck: Deck
+find_materials_by_type()
+update_material_location()
+convert_to_unilab_format()
+_create_resource_by_type()*
}
class WorkstationHTTPService {
+workstation_instance: WorkstationBase
+host: str
+port: int
+start()
+stop()
+_handle_step_finish_report()
+_handle_material_change_report()
}
class PLCWorkstation {
+plc_config: Dict
+modbus_client: ModbusTCPClient
+_create_communication_module()
+_create_material_management_module()
+_register_supported_workflows()
}
class ReportingWorkstation {
+report_handlers: Dict
+_create_communication_module()
+_create_material_management_module()
+_register_supported_workflows()
}
WorkstationBase --|> ROS2WorkstationNode
WorkstationBase *-- WorkstationCommunicationBase
WorkstationBase *-- MaterialManagementBase
WorkstationBase *-- WorkstationHTTPService
PLCWorkstation --|> WorkstationBase
ReportingWorkstation --|> WorkstationBase
WorkstationCommunicationBase <|-- PLCCommunication
WorkstationCommunicationBase <|-- DummyCommunication
MaterialManagementBase <|-- PyLabRobotMaterialManager
MaterialManagementBase <|-- SimpleMaterialManager
```
## 3. 工作站启动时序图
```mermaid
sequenceDiagram
participant APP as Application
participant WS as WorkstationBase
participant COMM as CommunicationModule
participant MAT as MaterialManager
participant HTTP as HTTPService
participant ROS as ROS2WorkstationNode
APP->>WS: 创建工作站实例
WS->>ROS: 初始化ROS2WorkstationNode
ROS->>ROS: 初始化子设备
ROS->>ROS: 设置硬件接口代理
WS->>COMM: _create_communication_module()
COMM->>COMM: 初始化通信配置
COMM->>COMM: 建立PLC/串口连接
COMM-->>WS: 返回通信模块实例
WS->>MAT: _create_material_management_module()
MAT->>MAT: 创建PyLabRobot Deck
MAT->>MAT: 初始化物料资源
MAT->>MAT: 注册到ResourceTracker
MAT-->>WS: 返回物料管理实例
WS->>WS: _register_supported_workflows()
WS->>WS: _create_workstation_services()
WS->>HTTP: _start_http_service()
HTTP->>HTTP: 创建HTTP服务器
HTTP->>HTTP: 启动监听线程
HTTP-->>WS: HTTP服务启动完成
WS-->>APP: 工作站初始化完成
```
## 4. 工作流执行时序图
```mermaid
sequenceDiagram
participant EXT as ExternalSystem
participant WS as WorkstationBase
participant COMM as CommunicationModule
participant MAT as MaterialManager
participant ROS as ROS2WorkstationNode
participant DEV as SubDevice
EXT->>WS: start_workflow(type, params)
WS->>WS: 验证工作流类型
WS->>COMM: start_workflow(type, params)
COMM->>COMM: 发送启动命令到PLC
COMM-->>WS: 启动成功
WS->>WS: 更新workflow_status = RUNNING
loop 工作流步骤执行
WS->>ROS: execute_single_action(device_id, action, params)
ROS->>DEV: 发送ROS Action请求
DEV->>DEV: 执行设备动作
DEV-->>ROS: 返回执行结果
ROS-->>WS: 返回动作结果
WS->>MAT: update_material_location(material_id, location)
MAT->>MAT: 更新PyLabRobot资源状态
MAT-->>WS: 更新完成
end
WS->>COMM: get_workflow_status()
COMM->>COMM: 查询PLC状态寄存器
COMM-->>WS: 返回状态信息
WS->>WS: 更新workflow_status = COMPLETED
WS-->>EXT: 工作流执行完成
```
## 5. HTTP报送处理时序图
```mermaid
sequenceDiagram
participant EXT as ExternalWorkstation
participant HTTP as HTTPService
participant WS as WorkstationBase
participant MAT as MaterialManager
participant DB as DataStorage
EXT->>HTTP: POST /report/step_finish
HTTP->>HTTP: 解析请求数据
HTTP->>HTTP: 验证LIMS协议字段
HTTP->>WS: process_step_finish_report(request)
WS->>WS: 增加接收计数
WS->>WS: 记录步骤完成事件
WS->>MAT: 更新相关物料状态
MAT->>MAT: 更新PyLabRobot资源
MAT-->>WS: 更新完成
WS->>DB: 保存报送记录
DB-->>WS: 保存完成
WS-->>HTTP: 返回处理结果
HTTP->>HTTP: 构造HTTP响应
HTTP-->>EXT: 200 OK + acknowledgment_id
Note over EXT,DB: 类似处理sample_finish, order_finish, material_change等报送
```
## 6. 错误处理时序图
```mermaid
sequenceDiagram
participant DEV as Device
participant WS as WorkstationBase
participant COMM as CommunicationModule
participant HTTP as HTTPService
participant EXT as ExternalSystem
DEV->>WS: 设备错误事件
WS->>WS: handle_external_error(error_data)
WS->>WS: 记录错误历史
alt 关键错误
WS->>COMM: emergency_stop()
COMM->>COMM: 发送紧急停止命令
WS->>WS: 更新workflow_status = ERROR
else 普通错误
WS->>WS: 标记动作失败
WS->>WS: 触发重试逻辑
end
WS->>HTTP: 记录错误报送
HTTP->>EXT: 主动通知错误状态
WS-->>DEV: 错误处理完成
```
## 7. 典型工作站实现示例
### 7.1 PLC工作站实现
```python
class PLCWorkstation(WorkstationBase):
def _create_communication_module(self):
return PLCCommunication(self.communication_config)
def _create_material_management_module(self):
return PyLabRobotMaterialManager(
self.device_id,
self.deck_config,
self.resource_tracker
)
def _register_supported_workflows(self):
self.supported_workflows = {
"battery_assembly": WorkflowInfo(...),
"quality_check": WorkflowInfo(...)
}
```
### 7.2 报送接收工作站实现
```python
class ReportingWorkstation(WorkstationBase):
def _create_communication_module(self):
return DummyCommunication(self.communication_config)
def _create_material_management_module(self):
return SimpleMaterialManager(
self.device_id,
self.deck_config,
self.resource_tracker
)
def _register_supported_workflows(self):
self.supported_workflows = {
"data_collection": WorkflowInfo(...),
"report_processing": WorkflowInfo(...)
}
```
## 8. 核心接口说明
### 8.1 必须实现的抽象方法
- `_create_communication_module()`: 创建通信模块
- `_create_material_management_module()`: 创建物料管理模块
- `_register_supported_workflows()`: 注册支持的工作流
### 8.2 可重写的报送处理方法
- `process_step_finish_report()`: 步骤完成处理
- `process_sample_finish_report()`: 样本完成处理
- `process_order_finish_report()`: 订单完成处理
- `process_material_change_report()`: 物料变更处理
- `handle_external_error()`: 错误处理
### 8.3 工作流控制接口
- `start_workflow()`: 启动工作流
- `stop_workflow()`: 停止工作流
- `get_workflow_status()`: 获取状态
## 9. 配置参数说明
```python
workstation_config = {
"communication_config": {
"protocol": "modbus_tcp",
"host": "192.168.1.100",
"port": 502
},
"deck_config": {
"size_x": 1000.0,
"size_y": 1000.0,
"size_z": 500.0
},
"http_service_config": {
"enabled": True,
"host": "127.0.0.1",
"port": 8081
},
"communication_interfaces": {
"logical_device_1": CommunicationInterface(...)
}
}
```
这个架构设计支持:
1. **灵活的通信方式**: 通过CommunicationBase支持PLC、串口、以太网等
2. **多样的物料管理**: 支持PyLabRobot、Bioyond、简单物料系统
3. **统一的HTTP报送**: 基于LIMS协议的标准化报送接口
4. **完整的工作流控制**: 支持动态和静态工作流
5. **强大的错误处理**: 多层次的错误处理和恢复机制

View File

@@ -33,6 +33,8 @@ developer_guide/add_device
developer_guide/add_action
developer_guide/actions
developer_guide/add_protocol
developer_guide/add_batteryPLC
developer_guide/materials_tutorial.md
```
## 接口文档

View File

@@ -1,82 +1,75 @@
# Uni-Lab 配置指南
Uni-Lab支持通过Python配置文件进行灵活的系统配置。本指南将帮助您理解配置选项并设置您的Uni-Lab环境。
Uni-Lab 支持通过 Python 配置文件进行灵活的系统配置。本指南将帮助您理解配置选项并设置您的 Uni-Lab 环境。
## 配置文件格式
Uni-Lab支持Python格式的配置文件它比YAMLJSON提供更多的灵活性包括支持注释、条件逻辑和复杂数据结构。
Uni-Lab 支持 Python 格式的配置文件,它比 YAMLJSON 提供更多的灵活性,包括支持注释、条件逻辑和复杂数据结构。
### 基本配置示例
### 默认配置示例
一个典型的配置文件包含以下部分
首次使用时,系统会自动创建一个基础配置文件 `local_config.py`
```python
# unilabos的配置文件
class BasicConfig:
ak = "" # 实验室网页给您提供的ak代码您可以在配置文件中指定也可以通过运行unilabos时以 --ak 传入,优先按照传入参数解析
sk = "" # 实验室网页给您提供的sk代码您可以在配置文件中指定也可以通过运行unilabos时以 --sk 传入,优先按照传入参数解析
# WebSocket配置一般无需调整
class WSConfig:
reconnect_interval = 5 # 重连间隔(秒)
max_reconnect_attempts = 999 # 最大重连次数
ping_interval = 30 # ping间隔
```
您可以进入实验室点击左下角的头像在实验室详情中获取所在实验室的ak sk
![copy_aksk.gif](image/copy_aksk.gif)
### 完整配置示例
您可以根据需要添加更多配置选项:
```python
#!/usr/bin/env python
# coding=utf-8
"""Uni-Lab 配置文件"""
from dataclasses import dataclass
# 基础配置
class BasicConfig:
ak = "your_access_key" # 实验室访问密钥
sk = "your_secret_key" # 实验室私钥
working_dir = "" # 工作目录(通常自动设置)
config_path = "" # 配置文件路径(自动设置)
is_host_mode = True # 是否为主站模式
slave_no_host = False # 从站模式下是否跳过等待主机服务
upload_registry = False # 是否上传注册表
machine_name = "undefined" # 机器名称(自动获取)
vis_2d_enable = False # 是否启用2D可视化
enable_resource_load = True # 是否启用资源加载
communication_protocol = "websocket" # 通信协议
# 配置类定义
# WebSocket配置
class WSConfig:
reconnect_interval = 5 # 重连间隔(秒)
max_reconnect_attempts = 999 # 最大重连次数
ping_interval = 30 # ping间隔
class MQConfig:
"""MQTT 配置类"""
lab_id: str = "YOUR_LAB_ID"
# 更多配置...
# OSS上传配置
class OSSUploadConfig:
api_host = "" # API主机地址
authorization = "" # 授权信息
init_endpoint = "" # 初始化端点
complete_endpoint = "" # 完成端点
max_retries = 3 # 最大重试次数
# 其他配置类...
```
## 配置选项说明
### MQTT配置 (MQConfig)
MQTT配置用于连接消息队列服务是Uni-Lab与云端通信的主要方式。
```python
class MQConfig:
"""MQTT 配置类"""
lab_id: str = "7AAEDBEA" # 实验室唯一标识
instance_id: str = "mqtt-cn-instance"
access_key: str = "your-access-key"
secret_key: str = "your-secret-key"
group_id: str = "GID_labs"
broker_url: str = "mqtt-cn-instance.mqtt.aliyuncs.com"
port: int = 8883
# 可以直接提供证书文件路径
ca_file: str = "/path/to/ca.pem" # 相对config.py所在目录的路径
cert_file: str = "/path/to/cert.pem" # 相对config.py所在目录的路径
key_file: str = "/path/to/key.pem" # 相对config.py所在目录的路径
# 或者直接提供证书内容
ca_content: str = ""
cert_content: str = ""
key_content: str = ""
```
#### 证书配置
MQTT连接支持两种方式配置证书
1. **文件路径方式**(推荐):指定证书文件的路径,系统会自动读取文件内容
2. **直接内容方式**:直接在配置中提供证书内容
推荐使用文件路径方式,便于证书的更新和管理。
### HTTP客户端配置 (HTTPConfig)
即将开放 Uni-Lab 云端实验室。
### ROS模块配置 (ROSConfig)
配置ROS消息转换器需要加载的模块
```python
# HTTP配置
class HTTPConfig:
remote_addr = "http://127.0.0.1:48197/api/v1" # 远程地址
# ROS配置
class ROSConfig:
"""ROS模块配置"""
modules = [
"std_msgs.msg",
"geometry_msgs.msg",
@@ -85,25 +78,365 @@ class ROSConfig:
"nav2_msgs.action",
"unilabos_msgs.msg",
"unilabos_msgs.action",
] # 需要加载的ROS模块
```
## 命令行参数覆盖配置
Uni-Lab 允许通过命令行参数覆盖配置文件中的设置,提供更灵活的配置方式。命令行参数的优先级高于配置文件。
### 支持命令行覆盖的配置项
以下配置项可以通过命令行参数进行覆盖:
| 配置类 | 配置字段 | 命令行参数 | 说明 |
| ------------- | ----------------- | ------------------- | -------------------------------- |
| `BasicConfig` | `ak` | `--ak` | 实验室访问密钥 |
| `BasicConfig` | `sk` | `--sk` | 实验室私钥 |
| `BasicConfig` | `working_dir` | `--working_dir` | 工作目录路径 |
| `BasicConfig` | `is_host_mode` | `--is_slave` | 主站模式(参数为从站模式,取反) |
| `BasicConfig` | `slave_no_host` | `--slave_no_host` | 从站模式下跳过等待主机服务 |
| `BasicConfig` | `upload_registry` | `--upload_registry` | 启动时上传注册表信息 |
| `BasicConfig` | `vis_2d_enable` | `--2d_vis` | 启用 2D 可视化 |
| `HTTPConfig` | `remote_addr` | `--addr` | 远程服务地址 |
### 特殊命令行参数
除了直接覆盖配置项的参数外,还有一些特殊的命令行参数:
| 参数 | 说明 |
| ------------------- | ------------------------------------ |
| `--config` | 指定配置文件路径 |
| `--port` | Web 服务端口(不影响配置文件) |
| `--disable_browser` | 禁用自动打开浏览器(不影响配置文件) |
| `--visual` | 可视化工具选择(不影响配置文件) |
| `--skip_env_check` | 跳过环境检查(不影响配置文件) |
### 配置优先级
配置项的生效优先级从高到低为:
1. **命令行参数**:最高优先级
2. **环境变量**:中等优先级
3. **配置文件**:基础优先级
### 使用示例
```bash
# 通过命令行覆盖认证信息
unilab --ak "new_access_key" --sk "new_secret_key"
# 覆盖服务器地址
unilab --addr "https://custom.server.com/api/v1"
# 启用从站模式并跳过等待主机
unilab --is_slave --slave_no_host
# 启用上传注册表和2D可视化
unilab --upload_registry --2d_vis
# 组合使用多个覆盖参数
unilab --ak "key" --sk "secret" --addr "test" --upload_registry --2d_vis
```
### 预设环境地址
`--addr` 参数支持以下预设值,会自动转换为对应的完整 URL
- `test``https://uni-lab.test.bohrium.com/api/v1`
- `uat``https://uni-lab.uat.bohrium.com/api/v1`
- `local``http://127.0.0.1:48197/api/v1`
- 其他值 → 直接使用作为完整 URL
## 配置选项详解
### 基础配置 (BasicConfig)
基础配置包含了系统运行的核心参数:
| 参数 | 类型 | 默认值 | 说明 |
| ------------------------ | ---- | ------------- | ------------------------------------------ |
| `ak` | str | `""` | 实验室访问密钥(必需) |
| `sk` | str | `""` | 实验室私钥(必需) |
| `working_dir` | str | `""` | 工作目录,通常自动设置 |
| `is_host_mode` | bool | `True` | 是否为主站模式 |
| `slave_no_host` | bool | `False` | 从站模式下是否跳过等待主机服务 |
| `upload_registry` | bool | `False` | 启动时是否上传注册表信息 |
| `machine_name` | str | `"undefined"` | 机器名称,自动从 hostname 获取(不可配置) |
| `vis_2d_enable` | bool | `False` | 是否启用 2D 可视化 |
| `communication_protocol` | str | `"websocket"` | 通信协议,固定为 websocket |
#### 认证配置
`ak``sk` 是必需的认证参数:
1. **获取方式**:在 [Uni-Lab 官网](https://uni-lab.bohrium.com) 注册实验室后获得
2. **配置方式**
- **命令行参数**`--ak "your_key" --sk "your_secret"`(最高优先级)
- **配置文件**:在 `BasicConfig` 类中设置
- **环境变量**`UNILABOS_BASICCONFIG_AK``UNILABOS_BASICCONFIG_SK`
3. **优先级顺序**:命令行参数 > 环境变量 > 配置文件
4. **安全注意**:请妥善保管您的密钥信息
**推荐做法**
- 开发环境:使用配置文件
- 生产环境:使用环境变量或命令行参数
- 临时测试:使用命令行参数
### WebSocket 配置 (WSConfig)
WebSocket 是 Uni-Lab 的主要通信方式:
| 参数 | 类型 | 默认值 | 说明 |
| ------------------------ | ---- | ------ | ------------------ |
| `reconnect_interval` | int | `5` | 断线重连间隔(秒) |
| `max_reconnect_attempts` | int | `999` | 最大重连次数 |
| `ping_interval` | int | `30` | 心跳检测间隔(秒) |
### HTTP 配置 (HTTPConfig)
HTTP 客户端配置用于与云端服务通信:
| 参数 | 类型 | 默认值 | 说明 |
| ------------- | ---- | --------------------------------- | ------------ |
| `remote_addr` | str | `"http://127.0.0.1:48197/api/v1"` | 远程服务地址 |
**预设环境地址**
- 生产环境:`https://uni-lab.bohrium.com/api/v1`
- 测试环境:`https://uni-lab.test.bohrium.com/api/v1`
- UAT 环境:`https://uni-lab.uat.bohrium.com/api/v1`
- 本地环境:`http://127.0.0.1:48197/api/v1`
### ROS 配置 (ROSConfig)
配置 ROS 消息转换器需要加载的模块:
```python
class ROSConfig:
modules = [
"std_msgs.msg", # 标准消息类型
"geometry_msgs.msg", # 几何消息类型
"control_msgs.msg", # 控制消息类型
"control_msgs.action", # 控制动作类型
"nav2_msgs.action", # 导航动作类型
"unilabos_msgs.msg", # UniLab 自定义消息类型
"unilabos_msgs.action", # UniLab 自定义动作类型
]
```
您可以根据需要添加其他ROS模块。
您可以根据实际使用的设备和功能添加其他 ROS 模块。
### 其他配置选项
### OSS 上传配置 (OSSUploadConfig)
- **OSSUploadConfig**: 对象存储上传配置
对象存储服务配置,用于文件上传功能:
## 如何使用配置文件
| 参数 | 类型 | 默认值 | 说明 |
| ------------------- | ---- | ------ | -------------------- |
| `api_host` | str | `""` | OSS API 主机地址 |
| `authorization` | str | `""` | 授权认证信息 |
| `init_endpoint` | str | `""` | 上传初始化端点 |
| `complete_endpoint` | str | `""` | 上传完成端点 |
| `max_retries` | int | `3` | 上传失败最大重试次数 |
启动Uni-Lab时通过`--config`参数指定配置文件路径:
## 环境变量支持
Uni-Lab 支持通过环境变量覆盖配置文件中的设置。环境变量格式为:
```
UNILABOS_{配置类名}_{字段名}
```
### 环境变量示例
```bash
unilab --config path/to/your/config.py
# 设置基础配置
export UNILABOS_BASICCONFIG_AK="your_access_key"
export UNILABOS_BASICCONFIG_SK="your_secret_key"
export UNILABOS_BASICCONFIG_IS_HOST_MODE="true"
# 设置WebSocket配置
export UNILABOS_WSCONFIG_RECONNECT_INTERVAL="10"
export UNILABOS_WSCONFIG_MAX_RECONNECT_ATTEMPTS="500"
# 设置HTTP配置
export UNILABOS_HTTPCONFIG_REMOTE_ADDR="https://uni-lab.bohrium.com/api/v1"
```
如果您不涉及多环境开发可以在unilabos的安装路径中手动添加local_config.py的文件
### 环境变量类型转换
# 启动Uni-Lab
python -m unilabos.app.main --config path/to/your/config.py
- **布尔值**`"true"`, `"1"`, `"yes"``True`;其他 → `False`
- **整数**:自动转换为 `int` 类型
- **浮点数**:自动转换为 `float` 类型
- **字符串**:保持原值
## 配置文件使用方法
### 1. 指定配置文件启动
```bash
# 使用指定配置文件启动
unilab --config /path/to/your/config.py
```
### 2. 使用默认配置文件
如果不指定配置文件,系统会按以下顺序查找:
1. 环境变量 `UNILABOS_BASICCONFIG_CONFIG_PATH` 指定的路径
2. 工作目录下的 `local_config.py`
3. 首次使用时会引导创建配置文件
### 3. 配置文件验证
系统启动时会自动验证配置文件:
- **语法检查**:确保 Python 语法正确
- **类型检查**:验证配置项类型是否匹配
- **必需项检查**:确保 `ak``sk` 已配置
## 最佳实践
### 1. 安全配置
- 不要将包含密钥的配置文件提交到版本控制系统
- 使用环境变量或命令行参数在生产环境中配置敏感信息
- 定期更换访问密钥
- **推荐配置方式**
```bash
# 生产环境 - 使用环境变量
export UNILABOS_BASICCONFIG_AK="your_access_key"
export UNILABOS_BASICCONFIG_SK="your_secret_key"
unilab
# 或使用命令行参数
unilab --ak "your_access_key" --sk "your_secret_key"
```
### 2. 多环境配置
为不同环境创建不同的配置文件并结合命令行参数:
```
configs/
├── local_config.py # 本地开发
├── test_config.py # 测试环境
├── prod_config.py # 生产环境
└── example_config.py # 示例配置
```
**环境切换示例**
```bash
# 本地开发环境
unilab --config configs/local_config.py --addr local
# 测试环境
unilab --config configs/test_config.py --addr test --upload_registry
# 生产环境
unilab --config configs/prod_config.py --ak "$PROD_AK" --sk "$PROD_SK"
```
### 3. 配置管理
- 保持配置文件简洁,只包含需要修改的配置项
- 为配置项添加注释说明其作用
- 定期检查和更新配置文件
- **命令行参数优先使用场景**
- 临时测试不同配置
- CI/CD 流水线中的动态配置
- 不同环境间快速切换
- 敏感信息的安全传递
### 4. 灵活配置策略
**基础配置文件 + 命令行覆盖**的推荐方式:
```python
# base_config.py - 基础配置
class BasicConfig:
# 非敏感配置写在文件中
is_host_mode = True
upload_registry = False
vis_2d_enable = False
class WSConfig:
reconnect_interval = 5
max_reconnect_attempts = 999
ping_interval = 30
```
```bash
# 启动时通过命令行覆盖关键参数
unilab --config base_config.py \
--ak "$AK" \
--sk "$SK" \
--addr "test" \
--upload_registry \
--2d_vis
```
## 故障排除
### 1. 配置文件加载失败
**错误信息**`[ENV] 配置文件 xxx 不存在`
**解决方法**
- 确认配置文件路径正确
- 检查文件权限是否可读
- 确保配置文件是 `.py` 格式
### 2. 语法错误
**错误信息**`[ENV] 加载配置文件 xxx 失败`
**解决方法**
- 检查 Python 语法是否正确
- 确认类名和字段名拼写正确
- 验证缩进是否正确(使用空格而非制表符)
### 3. 认证失败
**错误信息**`后续运行必须拥有一个实验室`
**解决方法**
- 确认 `ak` 和 `sk` 已正确配置
- 检查密钥是否有效
- 确认网络连接正常
### 4. 环境变量不生效
**解决方法**
- 确认环境变量名格式正确(`UNILABOS_CLASS_FIELD`
- 检查环境变量是否已正确设置
- 重启系统或重新加载环境变量
### 5. 命令行参数不生效
**错误现象**:设置了命令行参数但配置没有生效
**解决方法**
- 确认参数名拼写正确(如 `--ak` 而不是 `--access_key`
- 检查参数格式是否正确(布尔参数如 `--is_slave` 不需要值)
- 确认参数位置正确(所有参数都应在 `unilab` 之后)
- 查看启动日志确认参数是否被正确解析
### 6. 配置优先级混淆
**错误现象**:不确定哪个配置生效
**解决方法**
- 记住优先级:命令行参数 > 环境变量 > 配置文件
- 使用 `--ak` 和 `--sk` 参数时会看到提示信息
- 检查启动日志中的配置加载信息
- 临时移除低优先级配置来测试高优先级配置是否生效

Binary file not shown.

After

Width:  |  Height:  |  Size: 526 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 327 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@@ -1,24 +1,43 @@
# **Uni-Lab 安装**
请先 `git clone` 本仓库,随后按照以下步骤安装项目:
## 快速开始
`Uni-Lab` 建议您采用 `mamba` 管理环境。若需从头建立 `Uni-Lab` 的运行依赖环境,请执行
1. **配置 Conda 环境**
Uni-Lab-OS 建议使用 `mamba` 管理环境。创建新的环境:
```shell
mamba env create -f unilabos-<YOUR_OS>.yaml
mamba activate unilab
mamba create -n unilab uni-lab::unilabos -c robostack-staging -c conda-forge
```
其中 `YOUR_OS` 是您的操作系统,可选值 `win64`, `linux-64`, `osx-64`, `osx-arm64`
若需将依赖安装进当前环境,请执行
2. **安装开发版 Uni-Lab-OS**
```shell
conda env update --file unilabos-<YOUR_OS>.yml
# 配置好conda环境后克隆仓库
git clone https://github.com/dptech-corp/Uni-Lab-OS.git -b dev
cd Uni-Lab-OS
# 安装 Uni-Lab-OS
pip install -e .
```
随后,可在本仓库安装 `unilabos` 的开发版:
3. **安装开发版 ros-humble-unilabos-msgs**
**卸载老版本:**
```shell
pip install .
conda activate unilab
conda remove --force ros-humble-unilabos-msgs
```
有时相同的安装包版本会由于dev构建得到的md5不一样触发安全检查可输入 `config set safety_checks disabled` 来关闭安全检查。
**安装新版本:**
访问 https://github.com/dptech-corp/Uni-Lab-OS/actions/workflows/multi-platform-build.yml 选择最新的构建,下载对应平台的压缩包(仅解压一次,得到.conda文件使用如下指令
```shell
conda activate base
conda install ros-humble-unilabos-msgs-<version>-<platform>.conda --offline -n <环境名>
```
4. **启动 Uni-Lab 系统**
请参见{doc}`启动样例 <../boot_examples/index>`或{doc}`启动指南 <launch>`了解详细的启动方法。

View File

@@ -1,4 +1,4 @@
# Uni-Lab 启动
# Uni-Lab 启动指南
安装完毕后,可以通过 `unilab` 命令行启动:
@@ -8,70 +8,315 @@ Start Uni-Lab Edge server.
options:
-h, --help show this help message and exit
-g GRAPH, --graph GRAPH
Physical setup graph.
-d DEVICES, --devices DEVICES
Devices config file.
-r RESOURCES, --resources RESOURCES
Resources config file.
Physical setup graph file path.
-c CONTROLLERS, --controllers CONTROLLERS
Controllers config file.
Controllers config file path.
--registry_path REGISTRY_PATH
Path to the registry
Path to the registry directory
--working_dir WORKING_DIR
Path to the working directory
--backend {ros,simple,automancer}
Choose the backend to run with: 'ros', 'simple', or 'automancer'.
--app_bridges APP_BRIDGES [APP_BRIDGES ...]
Bridges to connect to. Now support 'mqtt' and 'fastapi'.
--without_host Run the backend as slave (without host).
--config CONFIG Configuration file path for system settings
Bridges to connect to. Now support 'websocket' and 'fastapi'.
--is_slave Run the backend as slave node (without host privileges).
--slave_no_host Skip waiting for host service in slave mode
--upload_registry Upload registry information when starting unilab
--use_remote_resource Use remote resources when starting unilab
--config CONFIG Configuration file path, supports .py format Python config files
--port PORT Port for web service information page
--disable_browser Disable opening information page on startup
--2d_vis Enable 2D visualization when starting pylabrobot instance
--visual {rviz,web,disable}
Choose visualization tool: rviz, web, or disable
--ak AK Access key for laboratory requests
--sk SK Secret key for laboratory requests
--addr ADDR Laboratory backend address
--skip_env_check Skip environment dependency check on startup
--complete_registry Complete registry information
```
## 启动流程详解
Uni-Lab 的启动过程分为以下几个阶段:
### 1. 参数解析阶段
- 解析命令行参数
- 处理参数格式转换(支持 dash 和 underscore 格式)
### 2. 环境检查阶段 (可选)
- 默认进行环境依赖检查并自动安装必需包
- 使用 `--skip_env_check` 可跳过此步骤
### 3. 配置文件处理阶段
您可以直接跟随 unilabos 的提示进行,无需查阅本节
- **工作目录设置**
- 如果当前目录以 `unilabos_data` 结尾,则使用当前目录
- 否则使用 `当前目录/unilabos_data` 作为工作目录
- 可通过 `--working_dir` 指定自定义工作目录
- **配置文件查找顺序**
1. 使用 `--config` 参数指定的配置文件
2. 在工作目录中查找 `local_config.py`
3. 首次使用时会引导创建配置文件
### 4. 服务器地址配置
支持多种后端环境:
- `--addr test`:测试环境 (`https://uni-lab.test.bohrium.com/api/v1`)
- `--addr uat`UAT 环境 (`https://uni-lab.uat.bohrium.com/api/v1`)
- `--addr local`:本地环境 (`http://127.0.0.1:48197/api/v1`)
- 自定义地址:直接指定完整 URL
### 5. 认证配置
- **必需参数**`--ak``--sk` 必须同时提供
- 命令行参数优先于配置文件中的设置
- 未提供认证信息会导致启动失败并提示注册实验室
### 6. 设备图谱加载
支持两种方式:
- **本地文件**:使用 `-g` 指定图谱文件(支持 JSON 和 GraphML 格式)
- **远程资源**:使用 `--use_remote_resource` 从云端获取
### 7. 注册表构建
- 构建设备和资源注册表
- 支持自定义注册表路径 (`--registry_path`)
- 可选择补全注册表信息 (`--complete_registry`)
### 8. 设备验证和注册
- 验证设备连接和端点配置
- 自动注册设备到云端服务
### 9. 通信桥接配置
- **WebSocket**:实时通信和任务下发
- **FastAPI**HTTP API 服务和物料更新
### 10. 可视化和服务启动
- 可选启动可视化工具 (`--visual`)
- 启动 Web 信息服务 (默认端口 8002)
- 启动后端通信服务
## 使用配置文件
Uni-Lab支持使用Python格式的配置文件进行系统设置。通过 `--config` 参数指定配置文件路径:
Uni-Lab 支持使用 Python 格式的配置文件进行系统设置。通过 `--config` 参数指定配置文件路径:
```bash
# 使用配置文件启动
unilab --config path/to/your/config.py
```
配置文件包含MQTT、HTTP、ROS等系统设置。有关配置文件的详细信息,请参阅[配置指南](configuration.md)。
配置文件包含实验室和 WebSocket 连接等设置。有关配置文件的详细信息,请参阅[配置指南](configuration.md)。
## 初始化信息来源
启动 Uni-Lab 时,可以选用两种方式之一配置实验室设备、耗材、通信、控制逻辑
启动 Uni-Lab 时,可以选用两种方式之一配置实验室设备:
### 1. 组态&拓扑图
使用 `-g` 时,组态&拓扑图应包含实验室所有信息,详见{ref}`graph`。目前支持 graphml 和 node-link json 两种格式。格式可参照 `tests/experiments` 下的启动文件。
使用 `-g` 时,组态&拓扑图应包含实验室所有信息,详见{ref}`graph`。目前支持 GraphML 和 node-link JSON 两种格式。格式可参照 `tests/experiments` 下的启动文件。
### 2. 分别指定设备、耗材、控制逻辑
### 2. 分别指定控制逻辑
分别使用 `-d, -r, -c` 依次传入设备组态配置、耗材列表、控制逻辑。
使用 `-c` 传入控制逻辑配置
可参照 `devices.json``resources.json`
不管使用哪一种初始化方式,设备/物料字典均需包含 `class` 属性,用于查找注册表信息。默认查找范围都是 Uni-Lab 内部注册表 `unilabos/registry/{devices,device_comms,resources}`。要添加额外的注册表路径,可以使用 `--registry` 加入 `<your-registry-path>/{devices,device_comms,resources}`
不管使用哪一种初始化方式,设备/物料字典均需包含 `class` 属性,用于查找注册表信息。默认查找范围都是 Uni-Lab 内部注册表 `unilabos/registry/{devices,device_comms,resources}`。要添加额外的注册表路径,可以使用 `--registry_path` 加入 `<your-registry-path>/{devices,device_comms,resources}`
## 通信中间件 `--backend`
目前 Uni-Lab 支持 ros2 作为通信中间件
目前 Uni-Lab 支持以下通信中间件
- **ros** (默认):基于 ROS2 的通信
- **simple**:简化通信模式
- **automancer**Automancer 兼容模式
## 端云桥接 `--app_bridges`
目前 Uni-Lab 提供 FastAPI (http), MQTT 两种端云通信方式。其中默认 MQTT 负责端对云状态同步和云对端任务下发FastAPI 负责端对云物料更新。
目前 Uni-Lab 提供 WebSocket、FastAPI (http) 两种端云通信方式
- **WebSocket**:负责实时通信和任务下发
- **FastAPI**:负责端对云物料更新和 HTTP API
## 分布式组网
启动 Uni-Lab 时,加入 `--without_host` 将作为从站,不加将作为主站,主站 (host) 持有物料修改权以及对云端的通信。局域网内分别启动的 Uni-Lab 主站/从站将自动组网,互相能访问所有设备状态、传感器信息并发送指令。
启动 Uni-Lab 时,加入 `--is_slave` 将作为从站,不加将作为主站
- **主站 (host)**:持有物料修改权以及对云端的通信
- **从站 (slave)**:无主机权限,可选择跳过等待主机服务 (`--slave_no_host`)
局域网内分别启动的 Uni-Lab 主站/从站将自动组网,互相能访问所有设备状态、传感器信息并发送指令。
## 可视化选项
### 2D 可视化
使用 `--2d_vis` 在 PyLabRobot 实例启动时同时启动 2D 可视化。
### 3D 可视化
通过 `--visual` 参数选择:
- **rviz**:使用 RViz 进行 3D 可视化
- **web**:使用 Web 界面进行可视化
- **disable** (默认):禁用可视化
## 实验室管理
### 首次使用
如果是首次使用,系统会:
1. 提示前往 https://uni-lab.bohrium.com 注册实验室
2. 引导创建配置文件
3. 设置工作目录
### 认证设置
- `--ak`:实验室访问密钥
- `--sk`:实验室私钥
- 两者必须同时提供才能正常启动
## 完整启动示例
以下是一些常用的启动命令示例:
```bash
# 使用配置文件和组态图启动
unilab -g path/to/graph.json
# 使用组态图启动,上传注册表
unilab --ak your_ak --sk your_sk -g path/to/graph.json --upload_registry
# 使用配置文件和分离的设备/资源文件启动
unilab -d devices.json -r resources.json
# 使用远程资源启动
unilab --ak your_ak --sk your_sk --use_remote_resource
# 更新注册表
unilab --ak your_ak --sk your_sk --complete_registry
# 启动从站模式
unilab --ak your_ak --sk your_sk --is_slave
# 启用可视化
unilab --ak your_ak --sk your_sk --visual web --2d_vis
# 指定本地信息网页服务端口和禁用自动跳出浏览器
unilab --ak your_ak --sk your_sk --port 8080 --disable_browser
```
## 常见问题
### 1. 认证失败
如果提示 "后续运行必须拥有一个实验室",请确保:
- 已在 https://uni-lab.bohrium.com 注册实验室
- 正确设置了 `--ak``--sk` 参数
- 配置文件中包含正确的认证信息
### 2. 配置文件问题
如果配置文件加载失败:
- 确保配置文件是 `.py` 格式
- 检查配置文件语法是否正确
- 首次使用可让系统自动创建示例配置文件
### 3. 网络连接问题
如果无法连接到服务器:
- 检查网络连接
- 确认服务器地址是否正确
- 尝试使用不同的环境地址test、uat、local
### 4. 设备图谱问题
如果设备加载失败:
- 检查图谱文件格式是否正确
- 验证设备连接和端点配置
- 确保注册表路径正确
## 页面操作
### 1. 启动成功
当您启动成功后,可以看到物料列表,节点模版和组态图如图展示
![material.png](image/material.png)
### 2. 根据需求创建设备和物料
我们可以做一个简单的案例
* 在容器1中加入水
* 通过传输泵将容器1中的水转移到容器2中
#### 2.1 添加所需的设备和物料
仪器设备work_station中的workstation 数量x1
仪器设备virtual_device中的virtual_transfer_pump 数量x1
物料耗材container中的container 数量x2
#### 2.2 将设备和物料根据父子关系进行关联
当我们添加设备时,仪器耗材模块的物料列表也会实时更新
我们需要将设备和物料拖拽到workstation中并在画布上将它们连接起来就像真实的设备操作一样
![links.png](image/links.png)
### 3. 创建工作流
进入工作流模块 → 点击"我创建的" → 新建工作流
![new.png](image/new.png)
#### 3.1 新增工作流节点
我们可以进入指定工作流,在空白处右键
* 选择Laboratory→host_node中的creat_resource
* 选择Laboratory→workstation中的PumpTransferProtocol
![creatworkfollow.gif](image/creatworkfollow.gif)
#### 3.2 配置节点参数
根据案例,工作流包含两个步骤:
1. 使用creat_resource在容器中创建水
2. 通过泵传输协议将水传输到另一个容器
我们点击creat_resource卡片上的编辑按钮来配置参数⭐
class_name container
device_id workstation
liquid_input_slot 0或-1均可
liquid_type : water
liquid_volume 根据需求填写即可默认单位ml这里举例50
parent workstation
res_id containe
关联设备名称(原unilabos_device_id) 这里就填写host_node
**配置完成后点击底部保存按钮**
我们点击PumpTransferProtocol卡片上的编辑按钮来配置参数⭐
event transfer_liquid
from_vessel water
to_vessel container1
volume 根据需求填写即可默认单位ml这里举例50
关联设备名称(原unilabos_device_id) 这里就填写workstation
**配置完成后点击底部保存按钮**
#### 3.3 运行工作流
1. 连接两个节点卡片
2. 点击底部保存按钮
3. 点击运行按钮执行工作流
![linksandrun.png](image/linksandrun.png)
### 运行监控
* 运行状态和消息实时显示在底部控制台
* 如有报错,可点击查看详细信息
### 结果验证
工作流完成后,返回仪器耗材模块:
* 点击 container1卡片查看详情
* 确认其中包含参数指定的水和容量

View File

@@ -0,0 +1,197 @@
# Uni-Lab-OS 一键安装快速指南
## 概述
本指南提供最快速的 Uni-Lab-OS 安装方法,使用预打包的 conda 环境,无需手动配置依赖。
## 前置要求
- 已安装 Conda/Miniconda/Miniforge/Mamba
- 至少 10GB 可用磁盘空间
- Windows 10+, macOS 10.14+, 或 Linux (Ubuntu 20.04+)
## 安装步骤
### 第一步:下载预打包环境
1. 访问 [GitHub Actions - Conda Pack Build](https://github.com/dptech-corp/Uni-Lab-OS/actions/workflows/conda-pack-build.yml)
2. 选择最新的成功构建记录(绿色勾号 ✓)
3. 在页面底部的 "Artifacts" 部分,下载对应你操作系统的压缩包:
- Windows: `unilab-pack-win-64-{branch}.zip`
- macOS (Intel): `unilab-pack-osx-64-{branch}.tar.gz`
- macOS (Apple Silicon): `unilab-pack-osx-arm64-{branch}.tar.gz`
- Linux: `unilab-pack-linux-64-{branch}.tar.gz`
### 第二步:解压并运行安装脚本
#### Windows
```batch
REM 使用 Windows 资源管理器解压下载的 zip 文件
REM 或使用命令行:
tar -xzf unilab-pack-win-64-dev.zip
REM 进入解压后的目录
cd unilab-pack-win-64-dev
REM 双击运行 install_unilab.bat
REM 或在命令行中执行:
install_unilab.bat
```
#### macOS
```bash
# 解压下载的压缩包
tar -xzf unilab-pack-osx-arm64-dev.tar.gz
# 进入解压后的目录
cd unilab-pack-osx-arm64-dev
# 运行安装脚本
bash install_unilab.sh
```
#### Linux
```bash
# 解压下载的压缩包
tar -xzf unilab-pack-linux-64-dev.tar.gz
# 进入解压后的目录
cd unilab-pack-linux-64-dev
# 添加执行权限(如果需要)
chmod +x install_unilab.sh
# 运行安装脚本
./install_unilab.sh
```
### 第三步:激活环境
```bash
conda activate unilab
```
### 第四步:验证安装(推荐)
```bash
# 确保已激活环境
conda activate unilab
# 运行验证脚本
python verify_installation.py
```
如果看到 "✓ All checks passed!",说明安装成功!
## 常见问题
### Q: 安装脚本找不到 conda
**A:** 确保你已经安装了 conda/miniconda/miniforge并且安装在标准位置
- **Windows**:
- `%USERPROFILE%\miniforge3`
- `%USERPROFILE%\miniconda3`
- `%USERPROFILE%\anaconda3`
- `C:\ProgramData\miniforge3`
- **macOS/Linux**:
- `~/miniforge3`
- `~/miniconda3`
- `~/anaconda3`
- `/opt/conda`
如果安装在其他位置,可以先激活 conda base 环境,然后手动运行安装脚本。
### Q: 安装后激活环境提示找不到?
**A:** 尝试以下方法:
```bash
# 方法 1: 使用 conda activate
conda activate unilab
# 方法 2: 使用完整路径激活Windows
call C:\Users\{YourUsername}\miniforge3\envs\unilab\Scripts\activate.bat
# 方法 2: 使用完整路径激活Unix
source ~/miniforge3/envs/unilab/bin/activate
```
### Q: conda-unpack 失败怎么办?
**A:** 尝试手动运行:
```bash
# Windows
cd %CONDA_PREFIX%\envs\unilab
.\Scripts\conda-unpack.exe
# macOS/Linux
cd $CONDA_PREFIX/envs/unilab
./bin/conda-unpack
```
### Q: 验证脚本报错?
**A:** 首先确认环境已激活:
```bash
# 检查当前环境
conda env list
# 应该看到 unilab 前面有 * 标记
```
如果仍有问题,查看具体报错信息,可能需要:
- 重新运行安装脚本
- 检查磁盘空间
- 查看详细文档
### Q: 环境很大,有办法减小吗?
**A:** 预打包的环境包含所有依赖,通常较大(压缩后 2-5GB。这是为了确保离线安装和完整功能。如果空间有限考虑使用手动安装方式只安装需要的组件。
### Q: 如何更新到最新版本?
**A:** 重新下载最新的预打包环境,运行安装脚本时选择覆盖现有环境。
或者在现有环境中更新:
```bash
conda activate unilab
# 更新 unilabos
cd /path/to/Uni-Lab-OS
git pull
pip install -e . --upgrade
# 更新 ros-humble-unilabos-msgs
mamba update ros-humble-unilabos-msgs -c uni-lab -c robostack-staging -c conda-forge
```
## 下一步
安装完成后,你可以:
1. **查看启动指南**: {doc}`launch`
2. **运行示例**: {doc}`../boot_examples/index`
3. **配置设备**: 编辑 `unilabos_data/startup_config.json`
4. **阅读开发文档**: {doc}`../developer_guide/workstation_architecture`
## 需要帮助?
- **文档**: [docs/user_guide/installation.md](installation.md)
- **问题反馈**: [GitHub Issues](https://github.com/dptech-corp/Uni-Lab-OS/issues)
- **开发版安装**: 参考 {doc}`installation` 的方式二
---
**提示**: 这个预打包环境包含了从指定分支(通常是 `dev`)构建的最新代码。如果需要稳定版本,请使用方式二手动安装 release 版本。