fast registry load

minor fix on skill & registry

stripe ros2 schema desc
add create-device-skill

new registry system backwards to yaml

remove not exist resource

new registry sys
exp. support with add device

add ai conventions

correct raise create resource error

ret info fix revert

ret info fix

fix prcxi check

add create_resource schema

re signal host ready event

add websocket connection timeout and improve reconnection logic

add open_timeout parameter to websocket connection
add TimeoutError and InvalidStatus exception handling
implement exponential backoff for reconnection attempts
simplify reconnection logic flow

add gzip

change pose extra to any

add isFlapY
This commit is contained in:
Xuwznln
2026-03-04 18:59:45 +08:00
parent 145fcaae65
commit c001f6a151
99 changed files with 10885 additions and 7191 deletions

View File

@@ -15,6 +15,9 @@ Python 类设备驱动在完成注册表后可以直接在 Uni-Lab 中使用,
**示例:**
```python
from unilabos.registry.decorators import device, topic_config
@device(id="mock_gripper", category=["gripper"], description="Mock Gripper")
class MockGripper:
def __init__(self):
self._position: float = 0.0
@@ -23,19 +26,23 @@ class MockGripper:
self._status = "Idle"
@property
@topic_config() # 添加 @topic_config 才会定时广播
def position(self) -> float:
return self._position
@property
@topic_config()
def velocity(self) -> float:
return self._velocity
@property
@topic_config()
def torque(self) -> float:
return self._torque
# 会被自动识别的设备属性,接入 Uni-Lab 时会定时对外广播
# 使用 @topic_config 装饰的属性,接入 Uni-Lab 时会定时对外广播
@property
@topic_config(period=2.0) # 可自定义发布周期
def status(self) -> str:
return self._status
@@ -149,7 +156,7 @@ my_device: # 设备唯一标识符
系统会自动分析您的 Python 驱动类并生成:
- `status_types`:从 `@property` 装饰的方法自动识别状态属性
- `status_types`:从 `@topic_config` 装饰的 `@property` 方法自动识别状态属性
- `action_value_mappings`:从类方法自动生成动作映射
- `init_param_schema`:从 `__init__` 方法分析初始化参数
- `schema`:前端显示用的属性类型定义
@@ -179,7 +186,9 @@ Uni-Lab 设备驱动是一个 Python 类,需要遵循以下结构:
```python
from typing import Dict, Any
from unilabos.registry.decorators import device, topic_config
@device(id="my_device", category=["general"], description="My Device")
class MyDevice:
"""设备类文档字符串
@@ -198,8 +207,9 @@ class MyDevice:
# 初始化硬件连接
@property
@topic_config() # 必须添加 @topic_config 才会广播
def status(self) -> str:
"""设备状态(会自动广播)"""
"""设备状态(通过 @topic_config 广播)"""
return self._status
def my_action(self, param: float) -> Dict[str, Any]:
@@ -217,34 +227,61 @@ class MyDevice:
## 状态属性 vs 动作方法
### 状态属性(@property
### 状态属性(@property + @topic_config
状态属性会被自动识别并定期广播:
状态属性需要同时使用 `@property``@topic_config` 装饰器才会被识别并定期广播:
```python
from unilabos.registry.decorators import topic_config
@property
@topic_config() # 必须添加,否则不会广播
def temperature(self) -> float:
"""当前温度"""
return self._read_temperature()
@property
@topic_config(period=2.0) # 可自定义发布周期(秒)
def status(self) -> str:
"""设备状态: idle, running, error"""
return self._status
@property
@topic_config(name="ready") # 可自定义发布名称
def is_ready(self) -> bool:
"""设备是否就绪"""
return self._status == "idle"
```
也可以使用普通方法(非 @property)配合 `@topic_config`
```python
@topic_config(period=10.0)
def get_sensor_data(self) -> Dict[str, float]:
"""获取传感器数据get_ 前缀会自动去除,发布名为 sensor_data"""
return {"temp": self._temp, "humidity": self._humidity}
```
**`@topic_config` 参数**:
| 参数 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| `period` | float | 5.0 | 发布周期(秒) |
| `print_publish` | bool | 节点默认 | 是否打印发布日志 |
| `qos` | int | 10 | QoS 深度 |
| `name` | str | None | 自定义发布名称 |
**发布名称优先级**`@topic_config(name=...)` > `get_` 前缀去除 > 方法名
**特点**:
- 使用`@property`装饰器
- 只读,不能有参数
- 自动添加到注册表的`status_types`
- 必须使用 `@topic_config` 装饰器
- 支持 `@property` 和普通方法
- 添加到注册表的 `status_types`
- 定期发布到 ROS2 topic
> **⚠️ 重要:** 仅有 `@property` 装饰器而没有 `@topic_config` 的属性**不会**被广播。这是一个 Breaking Change。
### 动作方法
动作方法是设备可以执行的操作:
@@ -497,6 +534,7 @@ class LiquidHandler:
self._status = "idle"
@property
@topic_config()
def status(self) -> str:
return self._status
@@ -886,7 +924,52 @@ class MyDevice:
## 最佳实践
### 1. 类型注解
### 1. 使用 `@device` 装饰器标识设备
```python
from unilabos.registry.decorators import device
@device(id="my_device", category=["heating"], description="My Heating Device", icon="heater.webp")
class MyDevice:
...
```
- `id`:设备唯一标识符,用于注册表匹配
- `category`:分类列表,前端用于分组显示
- `description`:设备描述
- `icon`:图标文件名(可选)
### 2. 使用 `@topic_config` 声明需要广播的状态
```python
from unilabos.registry.decorators import topic_config
# ✓ @property + @topic_config → 会广播
@property
@topic_config(period=2.0)
def temperature(self) -> float:
return self._temp
# ✓ 普通方法 + @topic_config → 会广播get_ 前缀自动去除)
@topic_config(period=10.0)
def get_sensor_data(self) -> Dict[str, float]:
return {"temp": self._temp}
# ✓ 使用 name 参数自定义发布名称
@property
@topic_config(name="ready")
def is_ready(self) -> bool:
return self._status == "idle"
# ✗ 仅有 @property没有 @topic_config → 不会广播
@property
def internal_state(self) -> str:
return self._state
```
> **注意:** 与 `@property` 连用时,`@topic_config` 必须放在 `@property` 下面。
### 3. 类型注解
```python
from typing import Dict, Any, Optional, List
@@ -901,7 +984,7 @@ def method(
pass
```
### 2. 文档字符串
### 4. 文档字符串
```python
def method(self, param: float) -> Dict[str, Any]:
@@ -923,7 +1006,7 @@ def method(self, param: float) -> Dict[str, Any]:
pass
```
### 3. 配置验证
### 5. 配置验证
```python
def __init__(self, config: Dict[str, Any]):
@@ -937,7 +1020,7 @@ def __init__(self, config: Dict[str, Any]):
self.baudrate = config['baudrate']
```
### 4. 资源清理
### 6. 资源清理
```python
def __del__(self):
@@ -946,7 +1029,7 @@ def __del__(self):
self.connection.close()
```
### 5. 设计前端友好的返回值
### 7. 设计前端友好的返回值
**记住:返回值会直接显示在 Web 界面**