Merge branch 'main' into dev

# Conflicts:
#	.conda/recipe.yaml
#	.github/workflows/conda-pack-build.yml
#	recipes/msgs/recipe.yaml
#	recipes/unilabos/recipe.yaml
#	scripts/verify_installation.py
#	setup.py
#	unilabos/app/main.py
#	unilabos/app/mq.py
#	unilabos/app/register.py
#	unilabos/compile/heatchill_protocol.py
#	unilabos/compile/separate_protocol.py
#	unilabos/config/config.py
#	unilabos/devices/pump_and_valve/runze_backbone.py
#	unilabos/devices/pump_and_valve/runze_multiple_backbone.py
#	unilabos/registry/devices/characterization_chromatic.yaml
#	unilabos/registry/devices/liquid_handler.yaml
#	unilabos/registry/devices/pump_and_valve.yaml
#	unilabos/registry/devices/robot_arm.yaml
#	unilabos/registry/devices/robot_linear_motion.yaml
#	unilabos/registry/devices/work_station.yaml
#	unilabos/registry/registry.py
#	unilabos/registry/resources/organic/workstation.yaml
#	unilabos/resources/plr_additional_res_reg.py
#	unilabos/ros/nodes/base_device_node.py
#	unilabos/ros/nodes/presets/host_node.py
#	unilabos/ros/nodes/presets/workstation.py
#	unilabos/ros/nodes/resource_tracker.py
#	unilabos/utils/environment_check.py
#	unilabos_msgs/package.xml
This commit is contained in:
Xuwznln
2025-10-12 22:13:49 +08:00
6 changed files with 142 additions and 8 deletions

98
.github/workflows/deploy-docs.yml vendored Normal file
View File

@@ -0,0 +1,98 @@
name: Deploy Docs
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
inputs:
branch:
description: '要部署文档的分支'
required: false
default: 'main'
type: string
deploy_to_pages:
description: '是否部署到 GitHub Pages'
required: false
default: true
type: boolean
# 设置 GITHUB_TOKEN 权限以部署到 GitHub Pages
permissions:
contents: read
pages: write
id-token: write
# 只允许一个并发部署,跳过正在进行和最新排队之间的运行
# 但是不取消正在进行的运行,因为我们希望允许这些生产部署完成
concurrency:
group: 'pages'
cancel-in-progress: false
jobs:
# Build documentation
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.branch || github.ref }}
- name: Setup Python environment
uses: actions/setup-python@v5
with:
python-version: '3.10'
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y pandoc
- name: Install Python dependencies
run: |
python -m pip install --upgrade pip
# Install package in development mode to get version info
pip install -e .
# Install documentation dependencies
pip install -r docs/requirements.txt
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true')
- name: Build Sphinx documentation
run: |
cd docs
# Clean previous builds
rm -rf _build
# Build HTML documentation
python -m sphinx -b html . _build/html -v
- name: Check build results
run: |
echo "Documentation build completed, checking output directory:"
ls -la docs/_build/html/
echo "Checking for index.html:"
test -f docs/_build/html/index.html && echo "✓ index.html exists" || echo "✗ index.html missing"
- name: Upload build artifacts
uses: actions/upload-pages-artifact@v3
if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true')
with:
path: docs/_build/html
# Deploy to GitHub Pages
deploy:
if: github.ref == 'refs/heads/main' || (github.event_name == 'workflow_dispatch' && github.event.inputs.deploy_to_pages == 'true')
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

View File

@@ -31,7 +31,7 @@ Join the [Intelligent Organic Chemistry Synthesis Competition](https://bohrium.d
Detailed documentation can be found at: Detailed documentation can be found at:
- [Online Documentation](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/) - [Online Documentation](https://dptech-corp.github.io/Uni-Lab-OS/)
## Quick Start ## Quick Start
@@ -55,7 +55,7 @@ pip install .
3. Start Uni-Lab System: 3. Start Uni-Lab System:
Please refer to [Documentation - Boot Examples](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/boot_examples/index.html) Please refer to [Documentation - Boot Examples](https://dptech-corp.github.io/Uni-Lab-OS/boot_examples/index.html)
## Message Format ## Message Format

View File

@@ -31,7 +31,7 @@ Uni-Lab-OS 是一个用于实验室自动化的综合平台,旨在连接和控
详细文档可在以下位置找到: 详细文档可在以下位置找到:
- [在线文档](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/) - [在线文档](https://dptech-corp.github.io/Uni-Lab-OS/)
## 快速开始 ## 快速开始
@@ -57,7 +57,7 @@ pip install .
3. 启动 Uni-Lab 系统: 3. 启动 Uni-Lab 系统:
请见[文档-启动样例](https://readthedocs.dp.tech/Uni-Lab/v0.8.0/boot_examples/index.html) 请见[文档-启动样例](https://dptech-corp.github.io/Uni-Lab-OS/boot_examples/index.html)
## 消息格式 ## 消息格式

13
docs/requirements.txt Normal file
View File

@@ -0,0 +1,13 @@
# Sphinx文档构建依赖
sphinx>=7.0.0
sphinx-rtd-theme>=2.0.0
myst-parser>=2.0.0
# 用于支持Jupyter notebook文档
myst-nb>=1.0.0
# 用于代码复制按钮
sphinx-copybutton>=0.5.0
# 用于自动摘要生成
sphinx-autobuild>=2024.2.4

View File

@@ -4741,7 +4741,6 @@ virtual_stirrer:
status_types: status_types:
current_speed: float current_speed: float
current_vessel: str current_vessel: str
device_info: dict
is_stirring: bool is_stirring: bool
max_speed: float max_speed: float
min_speed: float min_speed: float
@@ -4776,8 +4775,6 @@ virtual_stirrer:
type: number type: number
current_vessel: current_vessel:
type: string type: string
device_info:
type: object
is_stirring: is_stirring:
type: boolean type: boolean
max_speed: max_speed:
@@ -4799,7 +4796,6 @@ virtual_stirrer:
- remaining_time - remaining_time
- max_speed - max_speed
- min_speed - min_speed
- device_info
type: object type: object
version: 1.0.0 version: 1.0.0
virtual_transfer_pump: virtual_transfer_pump:

View File

@@ -1,8 +1,13 @@
import json import json
import time import time
import traceback import traceback
<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py
from pprint import pformat from pprint import pformat
from typing import List, Dict, Any, Optional, TYPE_CHECKING from typing import List, Dict, Any, Optional, TYPE_CHECKING
========
from pprint import pprint, saferepr, pformat
from typing import Union
>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py
import rclpy import rclpy
from rosidl_runtime_py import message_to_ordereddict from rosidl_runtime_py import message_to_ordereddict
@@ -193,8 +198,13 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
execute_callback=self._create_protocol_execute_callback(action_name, protocol_steps_generator), execute_callback=self._create_protocol_execute_callback(action_name, protocol_steps_generator),
callback_group=ReentrantCallbackGroup(), callback_group=ReentrantCallbackGroup(),
) )
<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py
self.lab_logger().trace(f"发布动作: {action_name}, 类型: {str_action_type}") self.lab_logger().trace(f"发布动作: {action_name}, 类型: {str_action_type}")
return return
========
self.lab_logger().trace(f"发布动作: {action_name}, 类型: {str_action_type}")
>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py
def _create_protocol_execute_callback(self, protocol_name, protocol_steps_generator): def _create_protocol_execute_callback(self, protocol_name, protocol_steps_generator):
async def execute_protocol(goal_handle: ServerGoalHandle): async def execute_protocol(goal_handle: ServerGoalHandle):
@@ -245,10 +255,15 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
logs.append(step) logs.append(step)
elif isinstance(step, list): elif isinstance(step, list):
logs.append(step) logs.append(step)
<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py
self.lab_logger().info( self.lab_logger().info(
f"Goal received: {protocol_kwargs}, running steps: " f"Goal received: {protocol_kwargs}, running steps: "
f"{json.dumps(logs, indent=4, ensure_ascii=False)}" f"{json.dumps(logs, indent=4, ensure_ascii=False)}"
) )
========
self.lab_logger().info(f"Goal received: {protocol_kwargs}, running steps: "
f"{json.dumps(logs, indent=4, ensure_ascii=False)}")
>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py
time_start = time.time() time_start = time.time()
time_overall = 100 time_overall = 100
@@ -263,6 +278,7 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
time.sleep(action["action_kwargs"]["time"]) time.sleep(action["action_kwargs"]["time"])
step_results.append({"step": i + 1, "action": "wait", "result": "completed"}) step_results.append({"step": i + 1, "action": "wait", "result": "completed"})
else: else:
<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py
try: try:
result = await self.execute_single_action(**action) result = await self.execute_single_action(**action)
step_results.append({"step": i + 1, "action": action["action_name"], "result": result}) step_results.append({"step": i + 1, "action": action["action_name"], "result": result})
@@ -273,6 +289,13 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
step_results.append( step_results.append(
{"step": i + 1, "action": action["action_name"], "result": ex.args[0]} {"step": i + 1, "action": action["action_name"], "result": ex.args[0]}
) )
========
result = await self.execute_single_action(**action)
step_results.append({"step": i + 1, "action": action["action_name"], "result": result})
ret_info = json.loads(getattr(result, "return_info", "{}"))
if not ret_info.get("suc", False):
raise RuntimeError(f"Step {i + 1} failed.")
>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py
elif isinstance(action, list): elif isinstance(action, list):
# 如果是并行动作,同时执行 # 如果是并行动作,同时执行
actions = action actions = action
@@ -310,6 +333,7 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
except Exception as e: except Exception as e:
# 捕获并记录错误信息 # 捕获并记录错误信息
<<<<<<<< HEAD:unilabos/ros/nodes/presets/workstation.py
str_step_results = [ str_step_results = [
{ {
k: dict(message_to_ordereddict(v)) if k == "result" and hasattr(v, "SLOT_TYPES") else v k: dict(message_to_ordereddict(v)) if k == "result" and hasattr(v, "SLOT_TYPES") else v
@@ -317,6 +341,9 @@ class ROS2WorkstationNode(BaseROS2DeviceNode):
} }
for i in step_results for i in step_results
] ]
========
str_step_results = [{k: dict(message_to_ordereddict(v)) if k == "result" and hasattr(v, "SLOT_TYPES") else v for k, v in i.items()} for i in step_results]
>>>>>>>> main:unilabos/ros/nodes/presets/protocol_node.py
execution_error = f"{traceback.format_exc()}\n\nStep Result: {pformat(str_step_results)}" execution_error = f"{traceback.format_exc()}\n\nStep Result: {pformat(str_step_results)}"
execution_success = False execution_success = False
self.lab_logger().error(f"协议 {protocol_name} 执行出错: {str(e)} \n{traceback.format_exc()}") self.lab_logger().error(f"协议 {protocol_name} 执行出错: {str(e)} \n{traceback.format_exc()}")