mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-04 13:25:13 +00:00
Merge branch 'dev' into fork/KCFeng425/fix-protocol-parameter
# Conflicts: # unilabos/app/mq.py # unilabos/registry/devices/virtual_device.yaml # unilabos/registry/devices/work_station.yaml
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
configs/
|
||||
temp/
|
||||
## Python
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
|
||||
217
test/experiments/prcxi.json
Normal file
217
test/experiments/prcxi.json
Normal file
@@ -0,0 +1,217 @@
|
||||
{
|
||||
"nodes": [
|
||||
{
|
||||
"id": "PRCXI",
|
||||
"name": "PRCXI",
|
||||
"parent": null,
|
||||
"type": "device",
|
||||
"class": "liquid_handler.prcxi",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"deck": {
|
||||
"_resource_child_name": "deck",
|
||||
"_resource_type": "unilabos.devices.liquid_handling.prcxi.prcxi:PRCXI9300Deck"
|
||||
},
|
||||
"host": "192.168.3.9",
|
||||
"port": 9999,
|
||||
"timeout": 10.0,
|
||||
"setup": false,
|
||||
"debug": true
|
||||
},
|
||||
"data": {},
|
||||
"children": [
|
||||
"deck"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "deck",
|
||||
"name": "deck",
|
||||
"sample_id": null,
|
||||
"children": [
|
||||
"rackT1",
|
||||
"plateT2",
|
||||
"plateT3",
|
||||
"rackT4",
|
||||
"plateT5",
|
||||
"plateT6"
|
||||
],
|
||||
"parent": "PRCXI",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Deck"
|
||||
},
|
||||
"data": {}
|
||||
},
|
||||
{
|
||||
"id": "rackT1",
|
||||
"name": "rackT1",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plateT2",
|
||||
"name": "plateT2",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plateT3",
|
||||
"name": "plateT3",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "rackT4",
|
||||
"name": "rackT4",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plateT5",
|
||||
"name": "plateT5",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "plateT6",
|
||||
"name": "plateT6",
|
||||
"sample_id": null,
|
||||
"children": [],
|
||||
"parent": "deck",
|
||||
"type": "device",
|
||||
"class": "",
|
||||
"position": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"config": {
|
||||
"type": "PRCXI9300Container",
|
||||
"size_x": 120.98,
|
||||
"size_y": 82.12,
|
||||
"size_z": 50.3
|
||||
},
|
||||
"data": {
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f"
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"links": []
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
import json
|
||||
import traceback
|
||||
import uuid
|
||||
from unilabos.app.model import JobAddReq, JobData
|
||||
from unilabos.ros.nodes.presets.host_node import HostNode
|
||||
from unilabos.utils.type_check import serialize_result_info
|
||||
|
||||
|
||||
def get_resources() -> tuple:
|
||||
@@ -33,5 +35,10 @@ def job_add(req: JobAddReq) -> JobData:
|
||||
if "command" in action_args:
|
||||
action_args = action_args["command"]
|
||||
# print(f"job_add:{req.device_id} {action_name} {action_kwargs}")
|
||||
HostNode.get_instance().send_goal(req.device_id, action_type=action_type, action_name=action_name, action_kwargs=action_args, goal_uuid=req.job_id, server_info=req.server_info)
|
||||
try:
|
||||
HostNode.get_instance().send_goal(req.device_id, action_type=action_type, action_name=action_name, action_kwargs=action_args, goal_uuid=req.job_id, server_info=req.server_info)
|
||||
except Exception as e:
|
||||
for bridge in HostNode.get_instance().bridges:
|
||||
if hasattr(bridge, "publish_job_status"):
|
||||
bridge.publish_job_status({}, req.job_id, "failed", serialize_result_info(traceback.format_exc(), False, {}))
|
||||
return JobData(jobId=req.job_id)
|
||||
|
||||
@@ -163,10 +163,10 @@ class MQTTClient:
|
||||
# status = device_status.get(device_id, {})
|
||||
if self.mqtt_disable:
|
||||
return
|
||||
status = {"data": device_status.get(device_id, {}), "device_id": device_id}
|
||||
status = {"data": device_status.get(device_id, {}), "device_id": device_id, "timestamp": time.time()}
|
||||
address = f"labs/{MQConfig.lab_id}/devices/"
|
||||
self.client.publish(address, json.dumps(status), qos=2)
|
||||
# logger.debug(f"Device status published: address: {address}, {status}")
|
||||
logger.debug(f"Device status published: address: {address}, {status}")
|
||||
|
||||
def publish_job_status(self, feedback_data: dict, job_id: str, status: str, return_info: Optional[str] = None):
|
||||
if self.mqtt_disable:
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import traceback
|
||||
from typing import List, Sequence, Optional, Literal, Union, Iterator
|
||||
|
||||
import asyncio
|
||||
@@ -117,7 +118,7 @@ class LiquidHandlerAbstract(LiquidHandler):
|
||||
pass # This mode is not verified.
|
||||
else:
|
||||
if len(asp_vols) != len(targets):
|
||||
raise ValueError("Length of `vols` must match `targets`.")
|
||||
raise ValueError(f"Length of `asp_vols` {len(asp_vols)} must match `targets` {len(targets)}.")
|
||||
tip = next(self.current_tip)
|
||||
await self.pick_up_tips(tip)
|
||||
|
||||
@@ -160,6 +161,7 @@ class LiquidHandlerAbstract(LiquidHandler):
|
||||
await self.discard_tips()
|
||||
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
raise RuntimeError(f"Liquid addition failed: {e}") from e
|
||||
|
||||
# ---------------------------------------------------------------
|
||||
@@ -183,7 +185,7 @@ class LiquidHandlerAbstract(LiquidHandler):
|
||||
spread: Literal["wide", "tight", "custom"] = "wide",
|
||||
is_96_well: bool = False,
|
||||
mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none",
|
||||
mix_times: Optional[List(int)] = None,
|
||||
mix_times: Optional[List[int]] = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
mix_rate: Optional[int] = None,
|
||||
mix_liquid_height: Optional[float] = None,
|
||||
|
||||
@@ -1,23 +1,667 @@
|
||||
import socket, json, contextlib
|
||||
from typing import Any, List, Dict, Optional
|
||||
import asyncio
|
||||
import collections
|
||||
import contextlib
|
||||
import json
|
||||
import socket
|
||||
import time
|
||||
from typing import Any, List, Dict, Optional, TypedDict, Union, Sequence, Iterator, Literal
|
||||
|
||||
from pylabrobot.liquid_handling import (
|
||||
LiquidHandlerBackend,
|
||||
Pickup,
|
||||
SingleChannelAspiration,
|
||||
Drop,
|
||||
SingleChannelDispense,
|
||||
PickupTipRack,
|
||||
DropTipRack,
|
||||
MultiHeadAspirationPlate,
|
||||
)
|
||||
from pylabrobot.liquid_handling.standard import (
|
||||
MultiHeadAspirationContainer,
|
||||
MultiHeadDispenseContainer,
|
||||
MultiHeadDispensePlate,
|
||||
ResourcePickup,
|
||||
ResourceMove,
|
||||
ResourceDrop,
|
||||
)
|
||||
from pylabrobot.resources import Tip, Deck, Plate, Well, TipRack, Resource, Container, Coordinate, TipSpot, Trash
|
||||
|
||||
from unilabos.devices.liquid_handling.liquid_handler_abstract import LiquidHandlerAbstract
|
||||
|
||||
|
||||
class PRCXIError(RuntimeError):
|
||||
"""Lilith 返回 Success=false 时抛出的业务异常"""
|
||||
|
||||
|
||||
class PRCXI9300:
|
||||
class Material(TypedDict): # 和Plate同关系
|
||||
uuid: str
|
||||
Code: Optional[str]
|
||||
Name: Optional[str]
|
||||
SummaryName: Optional[str]
|
||||
PipetteHeight: Optional[int]
|
||||
materialEnum: Optional[int]
|
||||
|
||||
def __init__(self, host: str = "127.0.0.1", port: int = 9999,
|
||||
timeout: float = 10.0) -> None:
|
||||
|
||||
class WorkTablets(TypedDict):
|
||||
Number: int
|
||||
Code: str
|
||||
Material: Dict[str, Any]
|
||||
|
||||
|
||||
class MatrixInfo(TypedDict):
|
||||
MatrixId: str
|
||||
MatrixName: str
|
||||
MatrixCount: int
|
||||
WorkTablets: list[WorkTablets]
|
||||
|
||||
|
||||
class PRCXI9300Deck(Deck):
|
||||
"""PRCXI 9300 的专用 Deck 类,继承自 Deck。
|
||||
|
||||
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, size_x: float, size_y: float, size_z: float):
|
||||
super().__init__(name, size_x, size_y, size_z)
|
||||
self.slots = [None] * 6 # PRCXI 9300 有 6 个槽位
|
||||
|
||||
|
||||
class PRCXI9300Container(Plate):
|
||||
"""PRCXI 9300 的专用 Deck 类,继承自 Deck。
|
||||
|
||||
该类定义了 PRCXI 9300 的工作台布局和槽位信息。
|
||||
"""
|
||||
|
||||
def __init__(self, name: str, size_x: float, size_y: float, size_z: float, category: str):
|
||||
super().__init__(name, size_x, size_y, size_z, category=category, ordering=collections.OrderedDict())
|
||||
self._unilabos_state = {}
|
||||
|
||||
def load_state(self, state: Dict[str, Any]) -> None:
|
||||
"""从给定的状态加载工作台信息。"""
|
||||
super().load_state(state)
|
||||
self._unilabos_state = state
|
||||
|
||||
def serialize_state(self) -> Dict[str, Dict[str, Any]]:
|
||||
data = super().serialize_state()
|
||||
data.update(self._unilabos_state)
|
||||
return data
|
||||
|
||||
|
||||
class PRCXI9300Handler(LiquidHandlerAbstract):
|
||||
@property
|
||||
def reset_ok(self) -> bool:
|
||||
"""检查设备是否已重置成功。"""
|
||||
if self._unilabos_backend.debug:
|
||||
return True
|
||||
return self._unilabos_backend.is_reset_ok
|
||||
|
||||
def __init__(self, deck: Deck, host: str, port: int, timeout: float, setup=True, debug=False):
|
||||
tablets_info = []
|
||||
count = 0
|
||||
for child in deck.children:
|
||||
if "Material" in child._unilabos_state:
|
||||
count += 1
|
||||
tablets_info.append(
|
||||
WorkTablets(Number=count, Code=f"T{count}", Material=child._unilabos_state["Material"])
|
||||
)
|
||||
self._unilabos_backend = PRCXI9300Backend(tablets_info, host, port, timeout, setup, debug)
|
||||
super().__init__(backend=self._unilabos_backend, deck=deck)
|
||||
|
||||
async def create_protocol(
|
||||
self,
|
||||
protocol_name: str = "",
|
||||
protocol_description: str = "",
|
||||
protocol_version: str = "",
|
||||
protocol_author: str = "",
|
||||
protocol_date: str = "",
|
||||
protocol_type: str = "",
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
self._unilabos_backend.create_protocol(protocol_name)
|
||||
|
||||
async def run_protocol(self):
|
||||
return self._unilabos_backend.run_protocol()
|
||||
|
||||
async def remove_liquid(
|
||||
self,
|
||||
vols: List[float],
|
||||
sources: Sequence[Container],
|
||||
waste_liquid: Optional[Container] = None,
|
||||
*,
|
||||
use_channels: Optional[List[int]] = None,
|
||||
flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Optional[Literal["wide", "tight", "custom"]] = "wide",
|
||||
delays: Optional[List[int]] = None,
|
||||
is_96_well: Optional[bool] = False,
|
||||
top: Optional[List[float]] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
return await super().remove_liquid(
|
||||
vols,
|
||||
sources,
|
||||
waste_liquid,
|
||||
use_channels=use_channels,
|
||||
flow_rates=flow_rates,
|
||||
offsets=offsets,
|
||||
liquid_height=liquid_height,
|
||||
blow_out_air_volume=blow_out_air_volume,
|
||||
spread=spread,
|
||||
delays=delays,
|
||||
is_96_well=is_96_well,
|
||||
top=top,
|
||||
none_keys=none_keys,
|
||||
)
|
||||
|
||||
async def add_liquid(
|
||||
self,
|
||||
asp_vols: Union[List[float], float],
|
||||
dis_vols: Union[List[float], float],
|
||||
reagent_sources: Sequence[Container],
|
||||
targets: Sequence[Container],
|
||||
*,
|
||||
use_channels: Optional[List[int]] = None,
|
||||
flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Optional[Literal["wide", "tight", "custom"]] = "wide",
|
||||
is_96_well: bool = False,
|
||||
delays: Optional[List[int]] = None,
|
||||
mix_time: Optional[int] = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
mix_rate: Optional[int] = None,
|
||||
mix_liquid_height: Optional[float] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
return await super().add_liquid(
|
||||
asp_vols,
|
||||
dis_vols,
|
||||
reagent_sources,
|
||||
targets,
|
||||
use_channels=use_channels,
|
||||
flow_rates=flow_rates,
|
||||
offsets=offsets,
|
||||
liquid_height=liquid_height,
|
||||
blow_out_air_volume=blow_out_air_volume,
|
||||
spread=spread,
|
||||
is_96_well=is_96_well,
|
||||
delays=delays,
|
||||
mix_time=mix_time,
|
||||
mix_vol=mix_vol,
|
||||
mix_rate=mix_rate,
|
||||
mix_liquid_height=mix_liquid_height,
|
||||
none_keys=none_keys,
|
||||
)
|
||||
|
||||
async def transfer_liquid(
|
||||
self,
|
||||
sources: Sequence[Container],
|
||||
targets: Sequence[Container],
|
||||
tip_racks: Sequence[TipRack],
|
||||
*,
|
||||
use_channels: Optional[List[int]] = None,
|
||||
asp_vols: Union[List[float], float],
|
||||
dis_vols: Union[List[float], float],
|
||||
asp_flow_rates: Optional[List[Optional[float]]] = None,
|
||||
dis_flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
touch_tip: bool = False,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Literal["wide", "tight", "custom"] = "wide",
|
||||
is_96_well: bool = False,
|
||||
mix_stage: Optional[Literal["none", "before", "after", "both"]] = "none",
|
||||
mix_times: Optional[List[int]] = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
mix_rate: Optional[int] = None,
|
||||
mix_liquid_height: Optional[float] = None,
|
||||
delays: Optional[List[int]] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
return await super().transfer_liquid(
|
||||
sources,
|
||||
targets,
|
||||
tip_racks,
|
||||
use_channels=use_channels,
|
||||
asp_vols=asp_vols,
|
||||
dis_vols=dis_vols,
|
||||
asp_flow_rates=asp_flow_rates,
|
||||
dis_flow_rates=dis_flow_rates,
|
||||
offsets=offsets,
|
||||
touch_tip=touch_tip,
|
||||
liquid_height=liquid_height,
|
||||
blow_out_air_volume=blow_out_air_volume,
|
||||
spread=spread,
|
||||
is_96_well=is_96_well,
|
||||
mix_stage=mix_stage,
|
||||
mix_times=mix_times,
|
||||
mix_vol=mix_vol,
|
||||
mix_rate=mix_rate,
|
||||
mix_liquid_height=mix_liquid_height,
|
||||
delays=delays,
|
||||
none_keys=none_keys,
|
||||
)
|
||||
|
||||
async def custom_delay(self, seconds=0, msg=None):
|
||||
return await super().custom_delay(seconds, msg)
|
||||
|
||||
async def touch_tip(self, targets: Sequence[Container]):
|
||||
return await super().touch_tip(targets)
|
||||
|
||||
async def mix(
|
||||
self,
|
||||
targets: Sequence[Container],
|
||||
mix_time: int = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
height_to_bottom: Optional[float] = None,
|
||||
offsets: Optional[Coordinate] = None,
|
||||
mix_rate: Optional[float] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
return await self._unilabos_backend.mix(targets, mix_time, mix_vol, height_to_bottom, offsets, mix_rate, none_keys)
|
||||
|
||||
def iter_tips(self, tip_racks: Sequence[TipRack]) -> Iterator[Resource]:
|
||||
return super().iter_tips(tip_racks)
|
||||
|
||||
async def pick_up_tips(self, tip_spots: List[TipSpot], use_channels: Optional[List[int]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||||
return await super().pick_up_tips(tip_spots, use_channels, offsets, **backend_kwargs)
|
||||
|
||||
async def aspirate(self, resources: Sequence[Container], vols: List[float],
|
||||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||||
|
||||
return await super().aspirate(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||||
blow_out_air_volume, spread, **backend_kwargs)
|
||||
|
||||
async def drop_tips(self, tip_spots: Sequence[Union[TipSpot, Trash]], use_channels: Optional[List[int]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None, allow_nonzero_volume: bool = False,
|
||||
**backend_kwargs):
|
||||
return await super().drop_tips(tip_spots, use_channels, offsets, allow_nonzero_volume, **backend_kwargs)
|
||||
|
||||
async def dispense(self, resources: Sequence[Container], vols: List[float],
|
||||
use_channels: Optional[List[int]] = None, flow_rates: Optional[List[Optional[float]]] = None,
|
||||
offsets: Optional[List[Coordinate]] = None,
|
||||
liquid_height: Optional[List[Optional[float]]] = None,
|
||||
blow_out_air_volume: Optional[List[Optional[float]]] = None,
|
||||
spread: Literal["wide", "tight", "custom"] = "wide", **backend_kwargs):
|
||||
return await super().dispense(resources, vols, use_channels, flow_rates, offsets, liquid_height,
|
||||
blow_out_air_volume, spread, **backend_kwargs)
|
||||
|
||||
async def discard_tips(self, use_channels: Optional[List[int]] = None, allow_nonzero_volume: bool = True,
|
||||
offsets: Optional[List[Coordinate]] = None, **backend_kwargs):
|
||||
return await super().discard_tips(use_channels, allow_nonzero_volume, offsets, **backend_kwargs)
|
||||
|
||||
def set_tiprack(self, tip_racks: Sequence[TipRack]):
|
||||
super().set_tiprack(tip_racks)
|
||||
|
||||
async def move_to(self, well: Well, dis_to_top: float = 0, channel: int = 0):
|
||||
return await super().move_to(well, dis_to_top, channel)
|
||||
|
||||
|
||||
class PRCXI9300Backend(LiquidHandlerBackend):
|
||||
"""PRCXI 9300 的后端实现,继承自 LiquidHandlerBackend。
|
||||
|
||||
该类提供了与 PRCXI 9300 设备进行通信的基本方法,包括方案管理、自动化控制、运行状态查询等。
|
||||
"""
|
||||
|
||||
_num_channels = 8 # 默认通道数为 8
|
||||
_is_reset_ok = False
|
||||
|
||||
@property
|
||||
def is_reset_ok(self) -> bool:
|
||||
self._is_reset_ok = self.api_client.get_reset_status()
|
||||
return self._is_reset_ok
|
||||
|
||||
matrix_info: MatrixInfo
|
||||
protocol_name: str
|
||||
steps_todo_list = []
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
tablets_info: list[WorkTablets],
|
||||
host: str = "127.0.0.1",
|
||||
port: int = 9999,
|
||||
timeout: float = 10.0,
|
||||
setup=True,
|
||||
debug=False,
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.tablets_info = tablets_info
|
||||
self.api_client = PRCXI9300Api(host, port, timeout, debug)
|
||||
self.host, self.port, self.timeout = host, port, timeout
|
||||
self._num_channels = 8
|
||||
self._execute_setup = setup
|
||||
self.debug = debug
|
||||
|
||||
def create_protocol(self, protocol_name):
|
||||
self.protocol_name = protocol_name
|
||||
self.steps_todo_list = []
|
||||
|
||||
def run_protocol(self):
|
||||
assert self.is_reset_ok, "PRCXI9300Backend is not reset successfully. Please call setup() first."
|
||||
run_time = time.time()
|
||||
self.matrix_info = MatrixInfo(
|
||||
MatrixId=f"{int(run_time)}",
|
||||
MatrixName=f"protocol_{run_time}",
|
||||
MatrixCount=len(self.tablets_info),
|
||||
WorkTablets=self.tablets_info,
|
||||
)
|
||||
#print(json.dumps(self.matrix_info, indent=2))
|
||||
res = self.api_client.add_WorkTablet_Matrix(self.matrix_info)
|
||||
assert res["Success"], f"Failed to create matrix: {res.get('Message', 'Unknown error')}"
|
||||
print(f"PRCXI9300Backend created matrix with ID: {self.matrix_info['MatrixId']}, result: {res}")
|
||||
solution_id = self.api_client.add_solution(
|
||||
f"protocol_{run_time}", self.matrix_info["MatrixId"], self.steps_todo_list
|
||||
)
|
||||
print(f"PRCXI9300Backend created solution with ID: {solution_id}")
|
||||
self.api_client.load_solution(solution_id)
|
||||
return self.api_client.start()
|
||||
|
||||
@classmethod
|
||||
def check_channels(cls, use_channels: List[int]) -> List[int]:
|
||||
"""检查通道是否符合要求,PRCXI9300Backend 只支持所有 8 个通道。"""
|
||||
if use_channels != [0, 1, 2, 3, 4, 5, 6, 7]:
|
||||
print("PRCXI9300Backend only supports all 8 channels, using default [0, 1, 2, 3, 4, 5, 6, 7].")
|
||||
return [0, 1, 2, 3, 4, 5, 6, 7]
|
||||
return use_channels
|
||||
|
||||
async def setup(self):
|
||||
await super().setup()
|
||||
try:
|
||||
if self._execute_setup:
|
||||
self.api_client.call("IAutomation", "Reset")
|
||||
while not self.is_reset_ok:
|
||||
print("Waiting for PRCXI9300 to reset...")
|
||||
await asyncio.sleep(1)
|
||||
print("PRCXI9300 reset successfully.")
|
||||
except ConnectionRefusedError as e:
|
||||
raise RuntimeError(
|
||||
f"Failed to connect to PRCXI9300 API at {self.host}:{self.port}. "
|
||||
"Please ensure the PRCXI9300 service is running."
|
||||
) from e
|
||||
|
||||
async def stop(self):
|
||||
self.api_client.call("IAutomation", "Stop")
|
||||
|
||||
async def pick_up_tips(self, ops: List[Pickup], use_channels: List[int] = None):
|
||||
"""Pick up tips from the specified resource."""
|
||||
|
||||
if len(ops) != 8:
|
||||
raise ValueError(f"PRCXI9300Backend pick_up_tips: Expected 8 pickups, got {len(ops)}")
|
||||
|
||||
plate_indexes = []
|
||||
for op in ops:
|
||||
plate = op.resource.parent.parent
|
||||
deck = plate.parent
|
||||
plate_index = deck.children.index(plate)
|
||||
plate_indexes.append(plate_index)
|
||||
if len(set(plate_indexes)) != 1:
|
||||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||||
|
||||
tip_columns = []
|
||||
for op in ops:
|
||||
tipspot = op.resource
|
||||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||||
tip_columns.append(tipspot_index // 8)
|
||||
if len(set(tip_columns)) != 1:
|
||||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||||
|
||||
PlateNo = plate_indexes[0] + 1
|
||||
hole_col = tip_columns[0] + 1
|
||||
|
||||
step = self.api_client.Load(
|
||||
"Left",
|
||||
dosage=0,
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=0,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
|
||||
async def drop_tips(self, ops: List[Drop], use_channels: List[int] = None):
|
||||
|
||||
"""Pick up tips from the specified resource."""
|
||||
|
||||
if len(ops) != 8:
|
||||
raise ValueError(f"PRCXI9300Backend drop_tips: Expected 8 pickups, got {len(ops)}")
|
||||
|
||||
plate_indexes = []
|
||||
for op in ops:
|
||||
plate = op.resource.parent.parent
|
||||
deck = plate.parent
|
||||
plate_index = deck.children.index(plate)
|
||||
plate_indexes.append(plate_index)
|
||||
if len(set(plate_indexes)) != 1:
|
||||
raise ValueError("All drop_tips must be from the same plate. Found different plates: " + str(plate_indexes))
|
||||
|
||||
tip_columns = []
|
||||
for op in ops:
|
||||
tipspot = op.resource
|
||||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||||
tip_columns.append(tipspot_index // 8)
|
||||
if len(set(tip_columns)) != 1:
|
||||
raise ValueError("All drop_tips must be from the same tip column. Found different columns: " + str(tip_columns))
|
||||
|
||||
PlateNo = plate_indexes[0] + 1
|
||||
hole_col = tip_columns[0] + 1
|
||||
|
||||
step = self.api_client.UnLoad(
|
||||
"Left",
|
||||
dosage=0,
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=0,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
async def mix(
|
||||
self,
|
||||
targets: Sequence[Container],
|
||||
mix_time: int = None,
|
||||
mix_vol: Optional[int] = None,
|
||||
height_to_bottom: Optional[float] = None,
|
||||
offsets: Optional[Coordinate] = None,
|
||||
mix_rate: Optional[float] = None,
|
||||
none_keys: List[str] = [],
|
||||
):
|
||||
|
||||
"""Mix liquid in the specified resources."""
|
||||
|
||||
if len(targets) != 8:
|
||||
raise ValueError(f"PRCXI9300Backend aspirate: Expected 8 aspirate, got {len(targets)}")
|
||||
|
||||
plate_indexes = []
|
||||
for op in targets:
|
||||
deck = op.parent.parent.parent
|
||||
plate = op.parent.parent
|
||||
plate_index = deck.children.index(plate)
|
||||
plate_indexes.append(plate_index)
|
||||
|
||||
if len(set(plate_indexes)) != 1:
|
||||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||||
|
||||
tip_columns = []
|
||||
for op in targets:
|
||||
tipspot_index = op.parent.children.index(op)
|
||||
tip_columns.append(tipspot_index // 8)
|
||||
|
||||
if len(set(tip_columns)) != 1:
|
||||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||||
|
||||
PlateNo = plate_indexes[0] + 1
|
||||
hole_col = tip_columns[0] + 1
|
||||
assert mix_time > 0
|
||||
step = self.api_client.Blending(
|
||||
"Left",
|
||||
dosage=mix_vol,
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=mix_time,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
async def aspirate(self, ops: List[SingleChannelAspiration], use_channels: List[int] = None):
|
||||
|
||||
"""Aspirate liquid from the specified resources."""
|
||||
|
||||
if len(ops) != 8:
|
||||
raise ValueError(f"PRCXI9300Backend aspirate: Expected 8 aspirate, got {len(ops)}")
|
||||
|
||||
plate_indexes = []
|
||||
for op in ops:
|
||||
plate = op.resource.parent.parent
|
||||
deck = plate.parent
|
||||
plate_index = deck.children.index(plate)
|
||||
plate_indexes.append(plate_index)
|
||||
|
||||
if len(set(plate_indexes)) != 1:
|
||||
raise ValueError("All pickups must be from the same plate. Found different plates: " + str(plate_indexes))
|
||||
|
||||
tip_columns = []
|
||||
for op in ops:
|
||||
tipspot = op.resource
|
||||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||||
tip_columns.append(tipspot_index // 8)
|
||||
|
||||
if len(set(tip_columns)) != 1:
|
||||
raise ValueError("All pickups must be from the same tip column. Found different columns: " + str(tip_columns))
|
||||
|
||||
volumes = [op.volume for op in ops]
|
||||
if len(set(volumes)) != 1:
|
||||
raise ValueError("All aspirate volumes must be the same. Found different volumes: " + str(volumes))
|
||||
|
||||
PlateNo = plate_indexes[0] + 1
|
||||
hole_col = tip_columns[0] + 1
|
||||
|
||||
step = self.api_client.Imbibing(
|
||||
"Left",
|
||||
dosage=int(volumes[0]),
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=0,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
|
||||
async def dispense(self, ops: List[SingleChannelDispense], use_channels: List[int] = None):
|
||||
|
||||
"""Dispense liquid into the specified resources."""
|
||||
|
||||
if len(ops) != 8:
|
||||
raise ValueError(f"PRCXI9300Backend dispense: Expected 8 dispense, got {len(ops)}")
|
||||
|
||||
plate_indexes = []
|
||||
for op in ops:
|
||||
plate = op.resource.parent.parent
|
||||
deck = plate.parent
|
||||
plate_index = deck.children.index(plate)
|
||||
plate_indexes.append(plate_index)
|
||||
|
||||
if len(set(plate_indexes)) != 1:
|
||||
raise ValueError("All dispense must be from the same plate. Found different plates: " + str(plate_indexes))
|
||||
|
||||
tip_columns = []
|
||||
for op in ops:
|
||||
tipspot = op.resource
|
||||
tipspot_index = tipspot.parent.children.index(tipspot)
|
||||
tip_columns.append(tipspot_index // 8)
|
||||
|
||||
if len(set(tip_columns)) != 1:
|
||||
raise ValueError("All dispense must be from the same tip column. Found different columns: " + str(tip_columns))
|
||||
|
||||
volumes = [op.volume for op in ops]
|
||||
if len(set(volumes)) != 1:
|
||||
raise ValueError("All dispense volumes must be the same. Found different volumes: " + str(volumes))
|
||||
|
||||
PlateNo = plate_indexes[0] + 1
|
||||
hole_col = tip_columns[0] + 1
|
||||
|
||||
step = self.api_client.Tapping(
|
||||
"Left",
|
||||
dosage=int(volumes[0]),
|
||||
plate_no=PlateNo,
|
||||
is_whole_plate=False,
|
||||
hole_row=1,
|
||||
hole_col=hole_col,
|
||||
blending_times=0,
|
||||
balance_height=0,
|
||||
plate_or_hole=f"H{hole_col}-8,T{PlateNo}",
|
||||
hole_numbers="1,2,3,4,5,6,7,8",
|
||||
)
|
||||
self.steps_todo_list.append(step)
|
||||
|
||||
async def pick_up_tips96(self, pickup: PickupTipRack):
|
||||
raise NotImplementedError("The PRCXI backend does not support the 96 head.")
|
||||
|
||||
async def drop_tips96(self, drop: DropTipRack):
|
||||
raise NotImplementedError("The PRCXI backend does not support the 96 head.")
|
||||
|
||||
async def aspirate96(self, aspiration: Union[MultiHeadAspirationPlate, MultiHeadAspirationContainer]):
|
||||
raise NotImplementedError("The Opentrons backend does not support the 96 head.")
|
||||
|
||||
async def dispense96(self, dispense: Union[MultiHeadDispensePlate, MultiHeadDispenseContainer]):
|
||||
raise NotImplementedError("The Opentrons backend does not support the 96 head.")
|
||||
|
||||
async def pick_up_resource(self, pickup: ResourcePickup):
|
||||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||||
|
||||
async def move_picked_up_resource(self, move: ResourceMove):
|
||||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||||
|
||||
async def drop_resource(self, drop: ResourceDrop):
|
||||
raise NotImplementedError("The Opentrons backend does not support the robotic arm.")
|
||||
|
||||
def can_pick_up_tip(self, channel_idx: int, tip: Tip) -> bool:
|
||||
return True # PRCXI9300Backend does not have tip compatibility issues
|
||||
|
||||
def serialize(self) -> dict:
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def num_channels(self) -> int:
|
||||
return self._num_channels
|
||||
|
||||
|
||||
class PRCXI9300Api:
|
||||
def __init__(self, host: str = "127.0.0.1", port: int = 9999, timeout: float = 10.0, debug: bool = False) -> None:
|
||||
self.host, self.port, self.timeout = host, port, timeout
|
||||
self.debug = debug
|
||||
|
||||
@staticmethod
|
||||
def _len_prefix(n: int) -> bytes:
|
||||
return bytes.fromhex(format(n, "016x"))
|
||||
|
||||
def _raw_request(self, payload: str) -> str:
|
||||
if self.debug:
|
||||
return " "
|
||||
with contextlib.closing(socket.socket()) as sock:
|
||||
sock.settimeout(self.timeout)
|
||||
sock.connect((self.host, self.port))
|
||||
@@ -34,13 +678,26 @@ class PRCXI9300:
|
||||
chunks.append(chunk)
|
||||
return b"".join(chunks).decode()
|
||||
|
||||
def _call(self, service: str, method: str,
|
||||
params: Optional[list] = None) -> Any:
|
||||
# ---------------------------------------------------- 方案相关(ISolution)
|
||||
def list_solutions(self) -> List[Dict[str, Any]]:
|
||||
"""GetSolutionList"""
|
||||
return self.call("ISolution", "GetSolutionList")
|
||||
|
||||
def load_solution(self, solution_id: str) -> bool:
|
||||
"""LoadSolution"""
|
||||
return self.call("ISolution", "LoadSolution", [solution_id])
|
||||
|
||||
def add_solution(self, name: str, matrix_id: str, steps: List[Dict[str, Any]]) -> str:
|
||||
"""AddSolution → 返回新方案 GUID"""
|
||||
return self.call("ISolution", "AddSolution", [name, matrix_id, steps])
|
||||
|
||||
# ---------------------------------------------------- 自动化控制(IAutomation)
|
||||
def start(self) -> bool:
|
||||
return self.call("IAutomation", "Start")
|
||||
|
||||
def call(self, service: str, method: str, params: Optional[list] = None) -> Any:
|
||||
payload = json.dumps(
|
||||
{"ServiceName": service,
|
||||
"MethodName": method,
|
||||
"Paramters": params or []},
|
||||
separators=(",", ":")
|
||||
{"ServiceName": service, "MethodName": method, "Paramters": params or []}, separators=(",", ":")
|
||||
)
|
||||
resp = json.loads(self._raw_request(payload))
|
||||
if not resp.get("Success", False):
|
||||
@@ -51,84 +708,55 @@ class PRCXI9300:
|
||||
except (TypeError, json.JSONDecodeError):
|
||||
return data
|
||||
|
||||
# ---------------------------------------------------- 方案相关(ISolution)
|
||||
def list_solutions(self) -> List[Dict[str, Any]]:
|
||||
"""GetSolutionList"""
|
||||
return self._call("ISolution", "GetSolutionList")
|
||||
|
||||
def load_solution(self, solution_id: str) -> bool:
|
||||
"""LoadSolution"""
|
||||
return self._call("ISolution", "LoadSolution", [solution_id])
|
||||
|
||||
def add_solution(self, name: str, matrix_id: str,
|
||||
steps: List[Dict[str, Any]]) -> str:
|
||||
"""AddSolution → 返回新方案 GUID"""
|
||||
return self._call("ISolution", "AddSolution",
|
||||
[name, matrix_id, steps])
|
||||
|
||||
# ---------------------------------------------------- 自动化控制(IAutomation)
|
||||
def start(self) -> bool:
|
||||
return self._call("IAutomation", "Start")
|
||||
|
||||
def stop(self) -> bool:
|
||||
"""Stop"""
|
||||
return self._call("IAutomation", "Stop")
|
||||
|
||||
def reset(self) -> bool:
|
||||
"""Reset"""
|
||||
return self._call("IAutomation", "Reset")
|
||||
|
||||
def pause(self) -> bool:
|
||||
"""Pause"""
|
||||
return self._call("IAutomation", "Pause")
|
||||
return self.call("IAutomation", "Pause")
|
||||
|
||||
def resume(self) -> bool:
|
||||
"""Resume"""
|
||||
return self._call("IAutomation", "Resume")
|
||||
return self.call("IAutomation", "Resume")
|
||||
|
||||
def get_error_code(self) -> Optional[str]:
|
||||
"""GetErrorCode"""
|
||||
return self._call("IAutomation", "GetErrorCode")
|
||||
return self.call("IAutomation", "GetErrorCode")
|
||||
|
||||
def get_reset_status(self) -> Optional[str]:
|
||||
"""GetErrorCode"""
|
||||
res = self.call("IAutomation", "GetResetStatus")
|
||||
return not res
|
||||
|
||||
def clear_error_code(self) -> bool:
|
||||
"""RemoveErrorCodet"""
|
||||
return self._call("IAutomation", "RemoveErrorCodet")
|
||||
return self.call("IAutomation", "RemoveErrorCodet")
|
||||
|
||||
# ---------------------------------------------------- 运行状态(IMachineState)
|
||||
def step_state_list(self) -> List[Dict[str, Any]]:
|
||||
"""GetStepStateList"""
|
||||
return self._call("IMachineState", "GetStepStateList")
|
||||
return self.call("IMachineState", "GetStepStateList")
|
||||
|
||||
def step_status(self, seq_num: int) -> Dict[str, Any]:
|
||||
"""GetStepStatus"""
|
||||
return self._call("IMachineState", "GetStepStatus", [seq_num])
|
||||
return self.call("IMachineState", "GetStepStatus", [seq_num])
|
||||
|
||||
def step_state(self, seq_num: int) -> Dict[str, Any]:
|
||||
"""GetStepState"""
|
||||
return self._call("IMachineState", "GetStepState", [seq_num])
|
||||
return self.call("IMachineState", "GetStepState", [seq_num])
|
||||
|
||||
def axis_location(self, axis_num: int = 1) -> Dict[str, Any]:
|
||||
"""GetLocation"""
|
||||
return self._call("IMachineState", "GetLocation", [axis_num])
|
||||
return self.call("IMachineState", "GetLocation", [axis_num])
|
||||
|
||||
# ---------------------------------------------------- 版位矩阵(IMatrix)
|
||||
def list_matrices(self) -> List[Dict[str, Any]]:
|
||||
"""GetWorkTabletMatrices"""
|
||||
return self._call("IMatrix", "GetWorkTabletMatrices")
|
||||
return self.call("IMatrix", "GetWorkTabletMatrices")
|
||||
|
||||
def matrix_by_id(self, matrix_id: str) -> Dict[str, Any]:
|
||||
"""GetWorkTabletMatrixById"""
|
||||
return self._call("IMatrix", "GetWorkTabletMatrixById", [matrix_id])
|
||||
return self.call("IMatrix", "GetWorkTabletMatrixById", [matrix_id])
|
||||
|
||||
def add_WorkTablet_Matrix(self,matrix):
|
||||
return self._call("IMatrix", "AddWorkTabletMatrix", [matrix])
|
||||
|
||||
# ---------------------------------------------------- 一键运行
|
||||
def run_solution(self, solution_id: str, channel_idx: int = 1) -> None:
|
||||
self.load_solution(solution_id)
|
||||
self.start(channel_idx)
|
||||
|
||||
# ---------------------------------------------------- 单点动作
|
||||
def add_WorkTablet_Matrix(self, matrix: MatrixInfo):
|
||||
return self.call("IMatrix", "AddWorkTabletMatrix", [matrix])
|
||||
|
||||
def Load(
|
||||
self,
|
||||
@@ -147,7 +775,7 @@ class PRCXI9300:
|
||||
assist_fun3: str = "",
|
||||
assist_fun4: str = "",
|
||||
assist_fun5: str = "",
|
||||
liquid_method: str = "NormalDispense"
|
||||
liquid_method: str = "NormalDispense",
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"StepAxis": axis,
|
||||
@@ -166,7 +794,7 @@ class PRCXI9300:
|
||||
"AssistFun4": assist_fun4,
|
||||
"AssistFun5": assist_fun5,
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
def Imbibing(
|
||||
@@ -186,7 +814,7 @@ class PRCXI9300:
|
||||
assist_fun3: str = "",
|
||||
assist_fun4: str = "",
|
||||
assist_fun5: str = "",
|
||||
liquid_method: str = "NormalDispense"
|
||||
liquid_method: str = "NormalDispense",
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"StepAxis": axis,
|
||||
@@ -205,10 +833,9 @@ class PRCXI9300:
|
||||
"AssistFun4": assist_fun4,
|
||||
"AssistFun5": assist_fun5,
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
|
||||
def Tapping(
|
||||
self,
|
||||
axis: str,
|
||||
@@ -226,7 +853,7 @@ class PRCXI9300:
|
||||
assist_fun3: str = "",
|
||||
assist_fun4: str = "",
|
||||
assist_fun5: str = "",
|
||||
liquid_method: str = "NormalDispense"
|
||||
liquid_method: str = "NormalDispense",
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"StepAxis": axis,
|
||||
@@ -245,10 +872,9 @@ class PRCXI9300:
|
||||
"AssistFun4": assist_fun4,
|
||||
"AssistFun5": assist_fun5,
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
|
||||
def Blending(
|
||||
self,
|
||||
axis: str,
|
||||
@@ -266,7 +892,7 @@ class PRCXI9300:
|
||||
assist_fun3: str = "",
|
||||
assist_fun4: str = "",
|
||||
assist_fun5: str = "",
|
||||
liquid_method: str = "NormalDispense"
|
||||
liquid_method: str = "NormalDispense",
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"StepAxis": axis,
|
||||
@@ -285,7 +911,7 @@ class PRCXI9300:
|
||||
"AssistFun4": assist_fun4,
|
||||
"AssistFun5": assist_fun5,
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
def UnLoad(
|
||||
@@ -305,7 +931,7 @@ class PRCXI9300:
|
||||
assist_fun3: str = "",
|
||||
assist_fun4: str = "",
|
||||
assist_fun5: str = "",
|
||||
liquid_method: str = "NormalDispense"
|
||||
liquid_method: str = "NormalDispense",
|
||||
) -> Dict[str, Any]:
|
||||
return {
|
||||
"StepAxis": axis,
|
||||
@@ -324,5 +950,103 @@ class PRCXI9300:
|
||||
"AssistFun4": assist_fun4,
|
||||
"AssistFun5": assist_fun5,
|
||||
"HoleNumbers": hole_numbers,
|
||||
"LiquidDispensingMethod": liquid_method
|
||||
"LiquidDispensingMethod": liquid_method,
|
||||
}
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Example usage
|
||||
deck = PRCXI9300Deck(name="PRCXI Deck", size_x=100, size_y=100, size_z=100)
|
||||
plate1 = PRCXI9300Container(name="rackT1", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate1.load_state({
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
})
|
||||
|
||||
plate2 = PRCXI9300Container(name="plateT2", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate2.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
plate3 = PRCXI9300Container(name="plateT3", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate3.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
plate4 = PRCXI9300Container(name="rackT4", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate4.load_state({
|
||||
"Material": {
|
||||
"uuid": "80652665f6a54402b2408d50b40398df",
|
||||
"Code": "ZX-001-1000",
|
||||
"Name": "1000μL Tip头",
|
||||
"SummaryName": "1000μL Tip头",
|
||||
"PipetteHeight": 100,
|
||||
"materialEnum": 1
|
||||
}
|
||||
})
|
||||
|
||||
plate5 = PRCXI9300Container(name="plateT5", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate5.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
plate6 = PRCXI9300Container(name="plateT6", size_x=50, size_y=50, size_z=10, category="plate")
|
||||
plate6.load_state({
|
||||
"Material": {
|
||||
"uuid": "57b1e4711e9e4a32b529f3132fc5931f",
|
||||
}
|
||||
})
|
||||
|
||||
from pylabrobot.resources.opentrons.tip_racks import tipone_96_tiprack_200ul
|
||||
from pylabrobot.resources.opentrons.plates import corning_96_wellplate_360ul_flat
|
||||
tip_rack = tipone_96_tiprack_200ul("TipRack")
|
||||
well_containers = corning_96_wellplate_360ul_flat("Plate")
|
||||
# from pprint import pprint
|
||||
# pprint(well_containers.children)
|
||||
plate1.assign_child_resource(tip_rack, location=Coordinate(0, 0, 0))
|
||||
plate2.assign_child_resource(well_containers, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate1, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate2, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate3, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate4, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate5, location=Coordinate(0, 0, 0))
|
||||
deck.assign_child_resource(plate6, location=Coordinate(0, 0, 0))
|
||||
|
||||
handler = PRCXI9300Handler(deck=deck, host="192.168.3.9", port=9999, timeout=10.0, setup=False, debug=True)
|
||||
handler.set_tiprack([tip_rack]) # Set the tip rack for the handler
|
||||
asyncio.run(handler.setup()) # Initialize the handler and setup the connection
|
||||
asyncio.run(handler.create_protocol(protocol_name="Test Protocol")) # Initialize the backend and setup the connection
|
||||
asyncio.run(handler.pick_up_tips(tip_rack.children[:8],[0,1,2,3,4,5,6,7]))
|
||||
asyncio.run(handler.aspirate(well_containers.children[:8],[50]*8, [0,1,2,3,4,5,6,7]))
|
||||
asyncio.run(handler.dispense(well_containers.children[:8],[50]*8,[0,1,2,3,4,5,6,7]))
|
||||
asyncio.run(handler.drop_tips(tip_rack.children[8:16],[0,1,2,3,4,5,6,7]))
|
||||
asyncio.run(handler.mix(well_containers.children[:8], mix_time=3, mix_vol=50, height_to_bottom=0.5, offsets=Coordinate(0, 0, 0), mix_rate=100))
|
||||
print(json.dumps(handler._unilabos_backend.steps_todo_list, indent=2)) # Print matrix info
|
||||
# asyncio.run(handler.add_liquid(
|
||||
# asp_vols=[100]*8,
|
||||
# dis_vols=[100]*8,
|
||||
# reagent_sources=well_containers.children[-8:],
|
||||
# targets=well_containers.children[:8],
|
||||
# use_channels=[0, 1, 2, 3, 4, 5, 6, 7],
|
||||
# flow_rates=[None] * 8,
|
||||
# offsets=[Coordinate(0, 0, 0)] * 8,
|
||||
# liquid_height=[None] * 8,
|
||||
# blow_out_air_volume=[None] * 8,
|
||||
# spread="wide",
|
||||
# ))
|
||||
# input("pick_up_tips add step")
|
||||
asyncio.run(handler.run_protocol()) # Run the protocol
|
||||
# input("Running protocol...")
|
||||
# input("Press Enter to continue...") # Wait for user input before proceeding
|
||||
# print("PRCXI9300Handler initialized with deck and host settings.")
|
||||
|
||||
@@ -17,7 +17,7 @@ class MoveitInterface:
|
||||
tf_buffer: Buffer
|
||||
tf_listener: TransformListener
|
||||
|
||||
def __init__(self, moveit_type, joint_poses, rotation=None, device_config=None):
|
||||
def __init__(self, moveit_type, joint_poses, rotation=None, device_config=None, **kwargs):
|
||||
self.device_config = device_config
|
||||
self.rotation = rotation
|
||||
self.data_config = json.load(
|
||||
|
||||
@@ -100,3 +100,4 @@ serial:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -8,7 +8,7 @@ camera:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: destroy_node的参数schema
|
||||
description: 用于安全地关闭摄像头设备,释放摄像头资源,停止视频采集和发布服务。调用此函数将清理OpenCV摄像头连接并销毁ROS2节点。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -28,7 +28,7 @@ camera:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: timer_callback的参数schema
|
||||
description: 定时器回调函数的参数schema。此函数负责定期采集摄像头视频帧,将OpenCV格式的图像转换为ROS Image消息格式,并发布到指定的视频话题。默认以10Hz频率执行,确保视频流的连续性和实时性。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -44,7 +44,7 @@ camera:
|
||||
module: unilabos.ros.nodes.presets.camera:VideoPublisher
|
||||
status_types: {}
|
||||
type: ros2
|
||||
description: ''
|
||||
description: VideoPublisher摄像头设备节点,用于实时视频采集和流媒体发布。该设备通过OpenCV连接本地摄像头(如USB摄像头、内置摄像头等),定时采集视频帧并将其转换为ROS2的sensor_msgs/Image消息格式发布到视频话题。主要用于实验室自动化系统中的视觉监控、图像分析、实时观察等应用场景。支持可配置的摄像头索引、发布频率等参数。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -67,3 +67,4 @@ camera:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -8,7 +8,7 @@ hplc.agilent:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: check_status的参数schema
|
||||
description: 检查安捷伦HPLC设备状态的函数。用于监控设备的运行状态、连接状态、错误信息等关键指标。该函数定期查询设备状态,确保系统稳定运行,及时发现和报告设备异常。适用于自动化流程中的设备监控、故障诊断、系统维护等场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -29,7 +29,7 @@ hplc.agilent:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: extract_data_from_txt的参数schema
|
||||
description: 从文本文件中提取分析数据的函数。用于解析安捷伦HPLC生成的结果文件,提取峰面积、保留时间、浓度等关键分析数据。支持多种文件格式的自动识别和数据结构化处理,为后续数据分析和报告生成提供标准化的数据格式。适用于批量数据处理、结果验证、质量控制等分析工作流程。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -55,7 +55,7 @@ hplc.agilent:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: start_sequence的参数schema
|
||||
description: 启动安捷伦HPLC分析序列的函数。用于执行预定义的分析方法序列,包括样品进样、色谱分离、检测等完整的分析流程。支持参数配置、资源分配、工作流程管理等功能,实现全自动的样品分析。适用于批量样品处理、标准化分析、质量检测等需要连续自动分析的应用场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -83,7 +83,7 @@ hplc.agilent:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: try_close_sub_device的参数schema
|
||||
description: 尝试关闭HPLC子设备的函数。用于安全地关闭泵、检测器、进样器等各个子模块,确保设备正常断开连接并保护硬件安全。该函数提供错误处理和状态确认机制,避免强制关闭可能造成的设备损坏。适用于设备维护、系统重启、紧急停机等需要安全关闭设备的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -106,7 +106,7 @@ hplc.agilent:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: try_open_sub_device的参数schema
|
||||
description: 尝试打开HPLC子设备的函数。用于初始化和连接泵、检测器、进样器等各个子模块,建立设备通信并进行自检。该函数提供连接验证和错误恢复机制,确保子设备正常启动并准备就绪。适用于设备初始化、系统启动、设备重连等需要建立设备连接的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -131,10 +131,9 @@ hplc.agilent:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -143,7 +142,6 @@ hplc.agilent:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -152,7 +150,6 @@ hplc.agilent:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -179,7 +176,7 @@ hplc.agilent:
|
||||
status_text: str
|
||||
success: bool
|
||||
type: python
|
||||
description: HPLC device
|
||||
description: 安捷伦高效液相色谱(HPLC)分析设备,用于复杂化合物的分离、检测和定量分析。该设备通过UI自动化技术控制安捷伦ChemStation软件,实现全自动的样品分析流程。具备序列启动、设备状态监控、数据文件提取、结果处理等功能。支持多样品批量处理和实时状态反馈,适用于药物分析、环境检测、食品安全、化学研究等需要高精度色谱分析的实验室应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -218,6 +215,7 @@ hplc.agilent:
|
||||
- finish_status
|
||||
- data_file
|
||||
type: object
|
||||
version: 0.0.1
|
||||
raman_home_made:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -229,7 +227,7 @@ raman_home_made:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ccd_time的参数schema
|
||||
description: 设置CCD检测器积分时间的函数。用于配置拉曼光谱仪的信号采集时间,控制光谱数据的质量和信噪比。较长的积分时间可获得更高的信号强度和更好的光谱质量,但会增加测量时间。该函数允许根据样品特性和测量要求动态调整检测参数,优化测量效果。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -253,7 +251,7 @@ raman_home_made:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: laser_on_power的参数schema
|
||||
description: 设置激光器输出功率的函数。用于控制拉曼光谱仪激光器的功率输出,调节激光强度以适应不同样品的测量需求。适当的激光功率能够获得良好的拉曼信号同时避免样品损伤。该函数支持精确的功率控制,确保测量结果的稳定性和重现性。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -269,30 +267,6 @@ raman_home_made:
|
||||
title: laser_on_power参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-raman_cmd:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: raman_cmd的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: raman_cmd参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-raman_without_background:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -302,7 +276,7 @@ raman_home_made:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: raman_without_background的参数schema
|
||||
description: 执行无背景扣除的拉曼光谱测量函数。用于直接采集样品的拉曼光谱信号,不进行背景校正处理。该函数配置积分时间和激光功率参数,获取原始光谱数据用于后续的数据处理分析。适用于对光谱数据质量要求较高或需要自定义背景处理流程的测量场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -332,7 +306,7 @@ raman_home_made:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: raman_without_background_average的参数schema
|
||||
description: 执行多次平均的无背景拉曼光谱测量函数。通过多次测量取平均值来提高光谱数据的信噪比和测量精度,减少随机噪声影响。该函数支持自定义平均次数、积分时间、激光功率等参数,并可为样品指定名称便于数据管理。适用于对测量精度要求较高的定量分析和研究应用。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -367,10 +341,9 @@ raman_home_made:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -379,7 +352,6 @@ raman_home_made:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -388,7 +360,6 @@ raman_home_made:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -407,7 +378,7 @@ raman_home_made:
|
||||
module: unilabos.devices.raman_uv.home_made_raman:RamanObj
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Raman spectroscopy device
|
||||
description: 拉曼光谱分析设备,用于物质的分子结构和化学成分表征。该设备集成激光器和CCD检测器,通过串口通信控制激光功率和光谱采集。具备背景扣除、多次平均、自动数据处理等功能,支持高精度的拉曼光谱测量。适用于材料表征、化学分析、质量控制、研究开发等需要分子指纹识别和结构分析的实验应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -431,3 +402,4 @@ raman_home_made:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -5,7 +5,7 @@ hotel.thermo_orbitor_rs2_hotel:
|
||||
status_types:
|
||||
rotation: String
|
||||
type: python
|
||||
description: Thermo Orbitor RS2 Hotel
|
||||
description: Thermo Orbitor RS2 Hotel容器设备,用于实验室样品的存储和管理。该设备通过HotelContainer类实现容器的旋转控制和状态监控,主要用于存储实验样品、试剂瓶或其他实验器具,支持旋转功能以便于样品的自动化存取。适用于需要有序存储和快速访问大量样品的实验室自动化场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -29,3 +29,4 @@ hotel.thermo_orbitor_rs2_hotel:
|
||||
model:
|
||||
mesh: thermo_orbitor_rs2_hotel
|
||||
type: device
|
||||
version: 0.0.1
|
||||
|
||||
@@ -15,16 +15,14 @@ laiyu_add_solid:
|
||||
result:
|
||||
actual_mass_mg: actual_mass_mg
|
||||
schema:
|
||||
description: ROS Action SolidDispenseAddPowderTube 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: SolidDispenseAddPowderTube_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
compound_mass:
|
||||
type: number
|
||||
@@ -41,7 +39,6 @@ laiyu_add_solid:
|
||||
title: SolidDispenseAddPowderTube_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
actual_mass_mg:
|
||||
type: number
|
||||
@@ -60,38 +57,6 @@ laiyu_add_solid:
|
||||
title: SolidDispenseAddPowderTube
|
||||
type: object
|
||||
type: SolidDispenseAddPowderTube
|
||||
auto-add_powder_tube:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
compound_mass: null
|
||||
powder_tube_number: null
|
||||
target_tube_position: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: add_powder_tube的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
compound_mass:
|
||||
type: string
|
||||
powder_tube_number:
|
||||
type: string
|
||||
target_tube_position:
|
||||
type: string
|
||||
required:
|
||||
- powder_tube_number
|
||||
- target_tube_position
|
||||
- compound_mass
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: add_powder_tube参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-calculate_crc:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -100,7 +65,7 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: calculate_crc的参数schema
|
||||
description: Modbus CRC-16校验码计算函数。计算Modbus RTU通信协议所需的CRC-16校验码,确保数据传输的完整性和可靠性。该函数实现标准的CRC-16算法,用于构造完整的Modbus指令帧。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -116,154 +81,6 @@ laiyu_add_solid:
|
||||
title: calculate_crc参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-discharge:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
float_in: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: discharge的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
float_in:
|
||||
type: number
|
||||
required:
|
||||
- float_in
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: discharge参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-move_to_plate:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
string: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: move_to_plate的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
required:
|
||||
- string
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: move_to_plate参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-move_to_xyz:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
x: null
|
||||
y: null
|
||||
z: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: move_to_xyz的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
x:
|
||||
type: number
|
||||
y:
|
||||
type: number
|
||||
z:
|
||||
type: number
|
||||
required:
|
||||
- x
|
||||
- y
|
||||
- z
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: move_to_xyz参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-pick_powder_tube:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
int_input: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: pick_powder_tube的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
int_input:
|
||||
type: integer
|
||||
required:
|
||||
- int_input
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: pick_powder_tube参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-put_powder_tube:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
int_input: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: put_powder_tube的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
int_input:
|
||||
type: integer
|
||||
required:
|
||||
- int_input
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: put_powder_tube参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-reset:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: reset的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: reset参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-send_command:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -272,7 +89,7 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: send_command的参数schema
|
||||
description: Modbus指令发送函数。构造完整的Modbus RTU指令帧(包含CRC校验),发送给分装设备并等待响应。该函数处理底层通信协议,确保指令的正确传输和响应接收,支持最长3分钟的响应等待时间。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -297,16 +114,14 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action FloatSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: FloatSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
float_in:
|
||||
type: number
|
||||
@@ -315,7 +130,6 @@ laiyu_add_solid:
|
||||
title: FloatSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -340,16 +154,14 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action StrSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: StrSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
@@ -358,7 +170,6 @@ laiyu_add_solid:
|
||||
title: StrSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -387,16 +198,14 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action Point3DSeparateInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: Point3DSeparateInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
x:
|
||||
type: number
|
||||
@@ -411,7 +220,6 @@ laiyu_add_solid:
|
||||
title: Point3DSeparateInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -436,16 +244,14 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action IntSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: IntSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
int_input:
|
||||
maximum: 2147483647
|
||||
@@ -456,7 +262,6 @@ laiyu_add_solid:
|
||||
title: IntSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -481,16 +286,14 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action IntSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: IntSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
int_input:
|
||||
maximum: 2147483647
|
||||
@@ -501,7 +304,6 @@ laiyu_add_solid:
|
||||
title: IntSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -524,22 +326,19 @@ laiyu_add_solid:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -556,7 +355,7 @@ laiyu_add_solid:
|
||||
status_types:
|
||||
status: str
|
||||
type: python
|
||||
description: Laiyu Add Solid
|
||||
description: 来渝固体粉末自动分装设备,用于实验室化学试剂的精确称量和分装。该设备通过Modbus RTU协议与控制系统通信,集成了精密天平、三轴运动平台、粉筒管理系统等组件。支持多种粉末试剂的自动拿取、精确称量、定点分装和归位操作。具备高精度称量、位置控制和批量处理能力,适用于化学合成、药物研发、材料制备等需要精确固体试剂配制的实验室应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -580,3 +379,4 @@ laiyu_add_solid:
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -117,30 +117,6 @@ moveit.arm_slider:
|
||||
title: moveit_task参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-pick_and_place:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: pick_and_place的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: pick_and_place参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-post_init:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -193,54 +169,6 @@ moveit.arm_slider:
|
||||
title: resource_manager参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_position:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_position的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_position参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_status的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_status参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-wait_for_resource_action:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -270,10 +198,9 @@ moveit.arm_slider:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -282,7 +209,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -291,7 +217,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -316,10 +241,9 @@ moveit.arm_slider:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -328,7 +252,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -337,7 +260,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -362,10 +284,9 @@ moveit.arm_slider:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -374,7 +295,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -383,7 +303,6 @@ moveit.arm_slider:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -402,7 +321,7 @@ moveit.arm_slider:
|
||||
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Arm with Slider
|
||||
description: 机械臂与滑块运动系统,基于MoveIt2运动规划框架的多自由度机械臂控制设备。该系统集成机械臂和线性滑块,通过ROS2和MoveIt2实现精确的轨迹规划和协调运动控制。支持笛卡尔空间和关节空间的运动规划、碰撞检测、逆运动学求解等功能。适用于复杂的pick-and-place操作、精密装配、多工位协作等需要高精度多轴协调运动的实验室自动化应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -427,6 +346,7 @@ moveit.arm_slider:
|
||||
model:
|
||||
mesh: arm_slider
|
||||
type: device
|
||||
version: 0.0.1
|
||||
moveit.toyo_xyz:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -546,30 +466,6 @@ moveit.toyo_xyz:
|
||||
title: moveit_task参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-pick_and_place:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: pick_and_place的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: pick_and_place参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-post_init:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -622,54 +518,6 @@ moveit.toyo_xyz:
|
||||
title: resource_manager参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_position:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_position的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_position参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_status的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_status参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-wait_for_resource_action:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -699,10 +547,9 @@ moveit.toyo_xyz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -711,7 +558,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -720,7 +566,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -745,10 +590,9 @@ moveit.toyo_xyz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -757,7 +601,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -766,7 +609,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -791,10 +633,9 @@ moveit.toyo_xyz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -803,7 +644,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -812,7 +652,6 @@ moveit.toyo_xyz:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -831,7 +670,7 @@ moveit.toyo_xyz:
|
||||
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Toyo XYZ
|
||||
description: 东洋XYZ三轴运动平台,基于MoveIt2运动规划框架的精密定位设备。该设备通过ROS2和MoveIt2实现三维空间的精确运动控制,支持复杂轨迹规划、多点定位、速度控制等功能。具备高精度定位、平稳运动、实时轨迹监控等特性。适用于精密加工、样品定位、检测扫描、自动化装配等需要高精度三维运动控制的实验室和工业应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -856,3 +695,4 @@ moveit.toyo_xyz:
|
||||
model:
|
||||
mesh: toyo_xyz
|
||||
type: device
|
||||
version: 0.0.1
|
||||
|
||||
@@ -93,30 +93,6 @@ rotavap.one:
|
||||
title: set_rotate_time参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_timer:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_timer的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_timer参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
set_timer:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -127,10 +103,9 @@ rotavap.one:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -139,7 +114,6 @@ rotavap.one:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -148,7 +122,6 @@ rotavap.one:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -167,7 +140,7 @@ rotavap.one:
|
||||
module: unilabos.devices.rotavap.rotavap_one:RotavapOne
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Rotavap device
|
||||
description: 旋转蒸发仪设备,用于有机化学实验中的溶剂回收和浓缩操作。该设备通过串口通信控制,集成旋转和真空泵功能,支持定时控制和自动化操作。具备旋转速度调节、真空度控制、温度管理等功能,实现高效的溶剂蒸发和回收。适用于有机合成、天然产物提取、药物制备等需要溶剂去除和浓缩的实验室应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -185,6 +158,7 @@ rotavap.one:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
separator.homemade:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -208,38 +182,6 @@ separator.homemade:
|
||||
title: read_sensor_loop参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-stir:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
settling_time: 10
|
||||
stir_speed: 300
|
||||
stir_time: 10
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: stir的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
settling_time:
|
||||
default: 10
|
||||
type: number
|
||||
stir_speed:
|
||||
default: 300
|
||||
type: number
|
||||
stir_time:
|
||||
default: 10
|
||||
type: number
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: stir参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-valve_open:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -268,30 +210,6 @@ separator.homemade:
|
||||
title: valve_open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-valve_open_cmd:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: valve_open_cmd的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: valve_open_cmd参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-write:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -335,10 +253,9 @@ separator.homemade:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action Stir 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -347,7 +264,6 @@ separator.homemade:
|
||||
title: Stir_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
event:
|
||||
type: string
|
||||
@@ -374,7 +290,6 @@ separator.homemade:
|
||||
title: Stir_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
@@ -401,13 +316,12 @@ separator.homemade:
|
||||
goal_default:
|
||||
command: ''
|
||||
handles: []
|
||||
result":
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -416,7 +330,6 @@ separator.homemade:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -425,7 +338,6 @@ separator.homemade:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -444,7 +356,7 @@ separator.homemade:
|
||||
module: unilabos.devices.separator.homemade_grbl_conductivity:SeparatorController
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Separator device with homemade grbl controller
|
||||
description: 液-液分离器设备,基于自制Grbl控制器的自动化分离系统。该设备集成搅拌、沉降、阀门控制和电导率传感器,通过串口通信实现精确的分离操作控制。支持自动搅拌、分层沉降、基于传感器反馈的智能分液等功能。适用于有机化学中的萃取分离、相分离、液-液提取等需要精确分离控制的实验应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -468,3 +380,4 @@ separator.homemade:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -125,30 +125,6 @@ solenoid_valve:
|
||||
title: send_command参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_valve_position:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
position: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_valve_position的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
position:
|
||||
type: string
|
||||
required:
|
||||
- position
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_valve_position参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
set_valve_position:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -158,16 +134,14 @@ solenoid_valve:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action StrSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: StrSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
@@ -176,7 +150,6 @@ solenoid_valve:
|
||||
title: StrSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -197,7 +170,7 @@ solenoid_valve:
|
||||
status: str
|
||||
valve_position: str
|
||||
type: python
|
||||
description: Solenoid valve
|
||||
description: 电磁阀控制设备,用于精确的流体路径控制和开关操作。该设备通过串口通信控制电磁阀的开关状态,支持远程操作和状态监测。具备快速响应、可靠密封、状态反馈等特性,广泛应用于流体输送、样品进样、路径切换等需要精确流体控制的实验室自动化应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -218,29 +191,10 @@ solenoid_valve:
|
||||
- status
|
||||
- valve_position
|
||||
type: object
|
||||
version: 0.0.1
|
||||
solenoid_valve.mock:
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: close的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: close参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-is_closed:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -281,26 +235,6 @@ solenoid_valve.mock:
|
||||
title: is_open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-open:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: open的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_valve_position:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -332,22 +266,19 @@ solenoid_valve.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -367,22 +298,19 @@ solenoid_valve.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -400,7 +328,7 @@ solenoid_valve.mock:
|
||||
status: str
|
||||
valve_position: str
|
||||
type: python
|
||||
description: Mock solenoid valve
|
||||
description: 模拟电磁阀设备,用于系统测试和开发调试。该设备模拟真实电磁阀的开关操作和状态变化,提供与实际设备相同的控制接口和反馈机制。支持流体路径的虚拟控制,便于在没有实际硬件的情况下进行流体系统的集成测试和算法验证。适用于系统开发、流程调试和培训演示等场景。
|
||||
handles:
|
||||
- data_type: fluid
|
||||
handler_key: in
|
||||
@@ -431,6 +359,7 @@ solenoid_valve.mock:
|
||||
- status
|
||||
- valve_position
|
||||
type: object
|
||||
version: 0.0.1
|
||||
syringe_pump_with_valve.runze:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -825,7 +754,7 @@ syringe_pump_with_valve.runze:
|
||||
velocity_grade: String
|
||||
velocity_init: String
|
||||
type: python
|
||||
description: Runze Syringe pump with valve
|
||||
description: 润泽精密注射泵设备,集成阀门控制的高精度流体输送系统。该设备通过串口通信控制,支持多种运行模式和精确的体积控制。具备可变速度控制、精密定位、阀门切换、实时状态监控等功能。适用于微量液体输送、精密进样、流速控制、化学反应进料等需要高精度流体操作的实验室自动化应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -875,3 +804,4 @@ syringe_pump_with_valve.runze:
|
||||
- position
|
||||
- plunger_position
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -11,7 +11,7 @@ agv.SEER:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: send的参数schema
|
||||
description: AGV底层通信命令发送函数。通过TCP socket连接向AGV发送底层控制命令,支持pose(位置)、status(状态)、nav(导航)等命令类型。用于获取AGV当前位置坐标、运行状态或发送导航指令。该函数封装了AGV的通信协议,将命令转换为十六进制数据包并处理响应解析。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -33,30 +33,6 @@ agv.SEER:
|
||||
title: send参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-send_nav_task:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: send_nav_task的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: send_nav_task参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
send_nav_task:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -67,10 +43,9 @@ agv.SEER:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -79,7 +54,6 @@ agv.SEER:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -88,7 +62,6 @@ agv.SEER:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -109,7 +82,7 @@ agv.SEER:
|
||||
pose: list
|
||||
status: str
|
||||
type: python
|
||||
description: SEER AGV
|
||||
description: SEER AGV自动导引车设备,用于实验室内物料和设备的自主移动运输。该AGV通过TCP socket与导航系统通信,具备精确的定位和路径规划能力。支持实时位置监控、状态查询和导航任务执行,可在预设的实验室环境中自主移动至指定位置。适用于样品运输、设备转移、多工位协作等实验室自动化物流场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -130,3 +103,4 @@ agv.SEER:
|
||||
- pose
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -8,7 +8,7 @@ robotic_arm.UR:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: arm_init的参数schema
|
||||
description: 机械臂初始化函数。执行UR机械臂的完整初始化流程,包括上电、释放制动器、解除保护停止状态等。该函数确保机械臂从安全停止状态恢复到可操作状态,是机械臂使用前的必要步骤。初始化完成后机械臂将处于就绪状态,可以接收后续的运动指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -29,7 +29,7 @@ robotic_arm.UR:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: load_pose_data的参数schema
|
||||
description: 从JSON字符串加载位置数据函数。接收包含机械臂位置信息的JSON格式字符串,解析并存储位置数据供后续运动任务使用。位置数据通常包含多个预定义的工作位置坐标,用于实现精确的多点运动控制。适用于动态配置机械臂工作位置的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -53,7 +53,7 @@ robotic_arm.UR:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: load_pose_file的参数schema
|
||||
description: 从文件加载位置数据函数。读取指定的JSON文件并加载其中的机械臂位置信息。该函数支持从外部配置文件中获取预设的工作位置,便于位置数据的管理和重用。适用于需要从固定配置文件中读取复杂位置序列的应用场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -69,30 +69,6 @@ robotic_arm.UR:
|
||||
title: load_pose_file参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-move_pos_task:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: move_pos_task的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: move_pos_task参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-reload_pose:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -100,7 +76,7 @@ robotic_arm.UR:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: reload_pose的参数schema
|
||||
description: 重新加载位置数据函数。重新读取并解析之前设置的位置文件,更新内存中的位置数据。该函数用于在位置文件被修改后刷新机械臂的位置配置,无需重新初始化整个系统。适用于动态更新机械臂工作位置的场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -123,10 +99,9 @@ robotic_arm.UR:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -135,7 +110,6 @@ robotic_arm.UR:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -144,7 +118,6 @@ robotic_arm.UR:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -167,7 +140,7 @@ robotic_arm.UR:
|
||||
gripper_pose: float
|
||||
gripper_status: str
|
||||
type: python
|
||||
description: UR robotic arm
|
||||
description: Universal Robots机械臂设备,用于实验室精密操作和自动化作业。该设备集成了UR机械臂本体、Robotiq夹爪和RTDE通信接口,支持六自由度精确运动控制和力觉反馈。具备实时位置监控、状态反馈、轨迹规划等功能,可执行复杂的多点位运动任务。适用于样品抓取、精密装配、实验器具操作等需要高精度和高重复性的实验室自动化场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -197,3 +170,4 @@ robotic_arm.UR:
|
||||
- arm_status
|
||||
- gripper_status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -51,7 +51,7 @@ gripper.misumi_rz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: gripper_move的参数schema
|
||||
description: 夹爪抓取运动控制函数。控制夹爪的开合运动,支持位置、速度、力矩的精确设定。位置参数控制夹爪开合程度,速度参数控制运动快慢,力矩参数控制夹持强度。该函数提供安全的力控制,避免损坏被抓取物体,适用于各种形状和材质的物品抓取。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -80,7 +80,7 @@ gripper.misumi_rz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: init_gripper的参数schema
|
||||
description: 夹爪初始化函数。执行Misumi RZ夹爪的完整初始化流程,包括Modbus通信建立、电机参数配置、传感器校准等。该函数确保夹爪系统从安全状态恢复到可操作状态,是夹爪使用前的必要步骤。初始化完成后夹爪将处于就绪状态,可接收抓取和旋转指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -169,7 +169,7 @@ gripper.misumi_rz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: node_gripper_move的参数schema
|
||||
description: 节点夹爪移动任务函数。接收逗号分隔的命令字符串,解析位置、速度、力矩参数并执行夹爪抓取动作。该函数等待运动完成并返回执行结果,提供同步的运动控制接口。适用于需要可靠完成确认的精密抓取操作。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -193,7 +193,7 @@ gripper.misumi_rz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: node_rotate_move的参数schema
|
||||
description: 节点旋转移动任务函数。接收逗号分隔的命令字符串,解析角度、速度、力矩参数并执行夹爪旋转动作。该函数等待旋转完成并返回执行结果,提供同步的旋转控制接口。适用于需要精确角度定位和完成确认的旋转操作。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -251,7 +251,7 @@ gripper.misumi_rz:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: rotate_move_abs的参数schema
|
||||
description: 夹爪绝对位置旋转控制函数。控制夹爪主轴旋转到指定的绝对角度位置,支持360度连续旋转。位置参数指定目标角度,速度参数控制旋转速率,力矩参数设定旋转阻力限制。该函数提供高精度的角度定位,适用于需要精确方向控制的操作场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -379,10 +379,9 @@ gripper.misumi_rz:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -391,7 +390,6 @@ gripper.misumi_rz:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -400,7 +398,6 @@ gripper.misumi_rz:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -420,7 +417,7 @@ gripper.misumi_rz:
|
||||
status_types:
|
||||
status: str
|
||||
type: python
|
||||
description: Misumi RZ gripper
|
||||
description: Misumi RZ系列电子夹爪设备,集成旋转和抓取双重功能的精密夹爪系统。该设备通过Modbus RTU协议与控制系统通信,支持位置、速度、力矩的精确控制。具备高精度的位置反馈、实时状态监控和故障检测功能。适用于需要精密抓取和旋转操作的实验室自动化场景,如样品管理、精密装配、器件操作等应用。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -447,6 +444,7 @@ gripper.misumi_rz:
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
gripper.mock:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -461,7 +459,7 @@ gripper.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: edit_id的参数schema
|
||||
description: 模拟夹爪资源ID编辑函数。用于测试和演示资源管理功能,模拟修改夹爪资源的标识信息。该函数接收工作流名称、参数和资源对象,模拟真实的资源更新过程并返回修改后的资源信息。适用于系统测试和开发调试场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -484,38 +482,6 @@ gripper.mock:
|
||||
title: edit_id参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-push_to:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
position: null
|
||||
torque: null
|
||||
velocity: 0.0
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: push_to的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
position:
|
||||
type: number
|
||||
torque:
|
||||
type: number
|
||||
velocity:
|
||||
default: 0.0
|
||||
type: number
|
||||
required:
|
||||
- position
|
||||
- torque
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: push_to参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
push_to:
|
||||
feedback:
|
||||
effort: torque
|
||||
@@ -532,10 +498,9 @@ gripper.mock:
|
||||
effort: torque
|
||||
position: position
|
||||
schema:
|
||||
description: ROS Action GripperCommand 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
effort:
|
||||
type: number
|
||||
@@ -553,7 +518,6 @@ gripper.mock:
|
||||
title: GripperCommand_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
properties:
|
||||
@@ -571,7 +535,6 @@ gripper.mock:
|
||||
title: GripperCommand_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
effort:
|
||||
type: number
|
||||
@@ -600,7 +563,7 @@ gripper.mock:
|
||||
torque: float
|
||||
velocity: float
|
||||
type: python
|
||||
description: Mock gripper
|
||||
description: 模拟夹爪设备,用于系统测试和开发调试。该设备模拟真实夹爪的位置、速度、力矩等物理特性,支持虚拟的抓取和移动操作。提供与真实夹爪相同的接口和状态反馈,便于在没有实际硬件的情况下进行系统集成测试和算法验证。适用于软件开发、系统调试和培训演示等场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -624,3 +587,4 @@ gripper.mock:
|
||||
- torque
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -8,7 +8,7 @@ linear_motion.grbl:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: initialize的参数schema
|
||||
description: CNC设备初始化函数。执行Grbl CNC的完整初始化流程,包括归零操作、轴校准和状态复位。该函数将所有轴移动到原点位置(0,0,0),确保设备处于已知的参考状态。初始化完成后设备进入空闲状态,可接收后续的运动指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -21,30 +21,6 @@ linear_motion.grbl:
|
||||
title: initialize参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-move_through_points:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
positions: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: move_through_points的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
positions:
|
||||
type: array
|
||||
required:
|
||||
- positions
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: move_through_points参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_position:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -53,7 +29,7 @@ linear_motion.grbl:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_position的参数schema
|
||||
description: CNC绝对位置设定函数。控制CNC设备移动到指定的三维坐标位置(x,y,z)。该函数支持安全限位检查,防止超出设备工作范围。移动过程中会监控设备状态,确保安全到达目标位置。适用于精确定位和轨迹控制操作。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -69,34 +45,6 @@ linear_motion.grbl:
|
||||
title: set_position参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_spindle_speed:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
max_velocity: 500
|
||||
spindle_speed: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_spindle_speed的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
max_velocity:
|
||||
default: 500
|
||||
type: number
|
||||
spindle_speed:
|
||||
type: number
|
||||
required:
|
||||
- spindle_speed
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_spindle_speed参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-stop_operation:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -104,7 +52,7 @@ linear_motion.grbl:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: stop_operation的参数schema
|
||||
description: CNC操作停止函数。立即停止当前正在执行的所有CNC运动,包括轴移动和主轴旋转。该函数用于紧急停止或任务中断,确保设备和工件的安全。停止后设备将保持当前位置,等待新的指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -166,10 +114,9 @@ linear_motion.grbl:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action NavigateThroughPoses 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
current_pose:
|
||||
properties:
|
||||
@@ -290,7 +237,6 @@ linear_motion.grbl:
|
||||
title: NavigateThroughPoses_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
behavior_tree:
|
||||
type: string
|
||||
@@ -371,7 +317,6 @@ linear_motion.grbl:
|
||||
title: NavigateThroughPoses_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
result:
|
||||
properties: {}
|
||||
@@ -401,10 +346,9 @@ linear_motion.grbl:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action SingleJointPosition 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
error:
|
||||
type: number
|
||||
@@ -444,7 +388,6 @@ linear_motion.grbl:
|
||||
title: SingleJointPosition_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
max_velocity:
|
||||
type: number
|
||||
@@ -472,7 +415,6 @@ linear_motion.grbl:
|
||||
title: SingleJointPosition_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: SingleJointPosition_Result
|
||||
@@ -488,7 +430,7 @@ linear_motion.grbl:
|
||||
spindle_speed: float
|
||||
status: str
|
||||
type: python
|
||||
description: Grbl CNC
|
||||
description: Grbl数控机床(CNC)设备,用于实验室精密加工和三轴定位操作。该设备基于Grbl固件,通过串口通信控制步进电机实现X、Y、Z三轴的精确运动。支持绝对定位、轨迹规划、主轴控制和实时状态监控。具备安全限位保护和运动平滑控制功能。适用于精密钻孔、铣削、雕刻、样品制备等需要高精度定位和加工的实验室应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -524,6 +466,7 @@ linear_motion.grbl:
|
||||
- position
|
||||
- spindle_speed
|
||||
type: object
|
||||
version: 0.0.1
|
||||
motor.iCL42:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -537,7 +480,7 @@ motor.iCL42:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: execute_run_motor的参数schema
|
||||
description: 步进电机执行运动函数。直接执行电机运动命令,包括位置设定、速度控制和路径规划。该函数处理底层的电机控制协议,消除警告信息,设置运动参数并启动电机运行。适用于需要直接控制电机运动的应用场景。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -566,7 +509,7 @@ motor.iCL42:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: init_device的参数schema
|
||||
description: iCL42电机设备初始化函数。建立与iCL42步进电机驱动器的串口通信连接,配置通信参数包括波特率、数据位、校验位等。该函数是电机使用前的必要步骤,确保驱动器处于可控状态并准备接收运动指令。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -589,7 +532,7 @@ motor.iCL42:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: run_motor的参数schema
|
||||
description: 步进电机运动控制函数。根据指定的运动模式、目标位置和速度参数控制电机运动。支持多种运动模式和精确的位置控制,自动处理运动轨迹规划和执行。该函数提供异步执行和状态反馈,确保运动的准确性和可靠性。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -621,10 +564,9 @@ motor.iCL42:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -633,7 +575,6 @@ motor.iCL42:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -642,7 +583,6 @@ motor.iCL42:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -664,7 +604,7 @@ motor.iCL42:
|
||||
motor_position: int
|
||||
success: bool
|
||||
type: python
|
||||
description: iCL42 motor
|
||||
description: iCL42步进电机驱动器,用于实验室设备的精密线性运动控制。该设备通过串口通信控制iCL42型步进电机驱动器,支持多种运动模式和精确的位置、速度控制。具备位置反馈、运行状态监控和故障检测功能。适用于自动进样器、样品传送、精密定位平台等需要准确线性运动控制的实验室自动化设备。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -691,3 +631,4 @@ motor.iCL42:
|
||||
- is_executing_run
|
||||
- success
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -285,7 +285,7 @@ lh_joint_publisher:
|
||||
module: unilabos.devices.ros_dev.liquid_handler_joint_publisher:LiquidHandlerJointPublisher
|
||||
status_types: {}
|
||||
type: ros2
|
||||
description: ''
|
||||
description: 液体处理器关节发布器,用于ROS2仿真系统中的液体处理设备运动控制。该节点通过发布关节状态驱动仿真模型中的机械臂运动,支持三维坐标到关节空间的逆运动学转换、多关节协调控制、资源跟踪和TF变换。具备精确的位置控制、速度调节、pick-and-place操作等功能。适用于液体处理系统的虚拟仿真、运动规划验证、系统集成测试等应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -309,3 +309,4 @@ lh_joint_publisher:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -89,30 +89,6 @@ chiller:
|
||||
title: modbus_crc参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_temperature:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_temperature的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_temperature参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-stop:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -143,10 +119,9 @@ chiller:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -155,7 +130,6 @@ chiller:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -164,7 +138,6 @@ chiller:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -183,7 +156,7 @@ chiller:
|
||||
module: unilabos.devices.temperature.chiller:Chiller
|
||||
status_types: {}
|
||||
type: python
|
||||
description: Chiller
|
||||
description: 实验室制冷设备,用于精确的温度控制和冷却操作。该设备通过Modbus RTU协议与控制系统通信,支持精确的温度设定和监控。具备快速降温、恒温控制和温度保持功能,广泛应用于需要低温环境的化学反应、样品保存、结晶操作等实验场景。提供稳定可靠的冷却性能,确保实验过程的温度精度。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -201,6 +174,7 @@ chiller:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
version: 0.0.1
|
||||
heaterstirrer.dalong:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -224,50 +198,6 @@ heaterstirrer.dalong:
|
||||
title: close参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-heatchill:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
purpose: reaction
|
||||
stir: true
|
||||
stir_speed: 300
|
||||
temp: null
|
||||
time: 3600
|
||||
vessel: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: heatchill的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
purpose:
|
||||
default: reaction
|
||||
type: string
|
||||
stir:
|
||||
default: true
|
||||
type: boolean
|
||||
stir_speed:
|
||||
default: 300
|
||||
type: number
|
||||
temp:
|
||||
type: number
|
||||
time:
|
||||
default: 3600
|
||||
type: number
|
||||
vessel:
|
||||
type: string
|
||||
required:
|
||||
- vessel
|
||||
- temp
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: heatchill参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_stir_speed:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -320,54 +250,6 @@ heaterstirrer.dalong:
|
||||
title: set_temp_inner参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_temp_target:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
temp: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_temp_target的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
temp:
|
||||
type: string
|
||||
required:
|
||||
- temp
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_temp_target参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_temp_warning:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
temp: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_temp_warning的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
temp:
|
||||
type: string
|
||||
required:
|
||||
- temp
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_temp_warning参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
heatchill:
|
||||
feedback:
|
||||
status: status
|
||||
@@ -391,10 +273,9 @@ heaterstirrer.dalong:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action HeatChill 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -403,7 +284,6 @@ heaterstirrer.dalong:
|
||||
title: HeatChill_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
pressure:
|
||||
type: string
|
||||
@@ -439,7 +319,6 @@ heaterstirrer.dalong:
|
||||
title: HeatChill_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
@@ -468,10 +347,9 @@ heaterstirrer.dalong:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -480,7 +358,6 @@ heaterstirrer.dalong:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -489,7 +366,6 @@ heaterstirrer.dalong:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -515,10 +391,9 @@ heaterstirrer.dalong:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -527,7 +402,6 @@ heaterstirrer.dalong:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -536,7 +410,6 @@ heaterstirrer.dalong:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -560,7 +433,7 @@ heaterstirrer.dalong:
|
||||
temp_target: float
|
||||
temp_warning: float
|
||||
type: python
|
||||
description: DaLong heater stirrer
|
||||
description: 大龙加热搅拌器,集成加热和搅拌双重功能的实验室设备。该设备通过串口通信控制,支持精确的温度调节、搅拌速度控制和安全保护功能。具备实时温度监测、目标温度设定、安全温度报警等特性。适用于化学合成、样品制备、反应控制等需要同时进行加热和搅拌的实验操作,提供稳定均匀的反应环境。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -596,6 +469,7 @@ heaterstirrer.dalong:
|
||||
- temp_warning
|
||||
- temp_target
|
||||
type: object
|
||||
version: 0.0.1
|
||||
tempsensor:
|
||||
class:
|
||||
action_value_mappings:
|
||||
@@ -707,30 +581,6 @@ tempsensor:
|
||||
title: send_prototype_command参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_warning:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
command: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_warning的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
required:
|
||||
- command
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_warning参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
set_warning:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -741,10 +591,9 @@ tempsensor:
|
||||
result:
|
||||
success: success
|
||||
schema:
|
||||
description: ROS Action SendCmd 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
@@ -753,7 +602,6 @@ tempsensor:
|
||||
title: SendCmd_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
command:
|
||||
type: string
|
||||
@@ -762,7 +610,6 @@ tempsensor:
|
||||
title: SendCmd_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -782,7 +629,7 @@ tempsensor:
|
||||
status_types:
|
||||
value: float
|
||||
type: python
|
||||
description: Temperature sensor
|
||||
description: 高精度温度传感器设备,用于实验室环境和设备的温度监测。该传感器通过Modbus RTU协议与控制系统通信,提供实时准确的温度数据。具备高精度测量、报警温度设定、数据稳定性好等特点。适用于反应器监控、环境温度监测、设备保护等需要精确温度测量的实验场景,为实验安全和数据可靠性提供保障。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -809,3 +656,4 @@ tempsensor:
|
||||
required:
|
||||
- value
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -1,26 +1,6 @@
|
||||
gas_source.mock:
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: close的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: close参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-is_closed:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -61,50 +41,6 @@ gas_source.mock:
|
||||
title: is_open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-open:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: open的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
string: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_status的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
required:
|
||||
- string
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_status参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -112,22 +48,19 @@ gas_source.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -147,22 +80,19 @@ gas_source.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -184,16 +114,14 @@ gas_source.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action StrSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: StrSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
@@ -202,7 +130,6 @@ gas_source.mock:
|
||||
title: StrSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -222,7 +149,7 @@ gas_source.mock:
|
||||
status_types:
|
||||
status: str
|
||||
type: python
|
||||
description: Mock gas source
|
||||
description: 模拟气体源设备,用于系统测试和开发调试。该设备模拟真实气体源的开关控制和状态监测功能,支持气体供应的启停操作。提供与真实气体源相同的接口和状态反馈,便于在没有实际硬件的情况下进行系统集成测试和算法验证。适用于气路系统调试、软件开发和实验流程验证等场景。
|
||||
handles:
|
||||
- data_key: fluid_out
|
||||
data_source: executor
|
||||
@@ -246,29 +173,10 @@ gas_source.mock:
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
vacuum_pump.mock:
|
||||
class:
|
||||
action_value_mappings:
|
||||
auto-close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: close的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: close参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-is_closed:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -309,50 +217,6 @@ vacuum_pump.mock:
|
||||
title: is_open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-open:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: open的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: open参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-set_status:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
string: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: set_status的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
required:
|
||||
- string
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: set_status参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -360,22 +224,19 @@ vacuum_pump.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -395,22 +256,19 @@ vacuum_pump.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -432,16 +290,14 @@ vacuum_pump.mock:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action StrSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: StrSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
@@ -450,7 +306,6 @@ vacuum_pump.mock:
|
||||
title: StrSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -470,7 +325,7 @@ vacuum_pump.mock:
|
||||
status_types:
|
||||
status: str
|
||||
type: python
|
||||
description: Mock vacuum pump
|
||||
description: 模拟真空泵设备,用于系统测试和开发调试。该设备模拟真实真空泵的抽气功能和状态控制,支持真空系统的启停操作和状态监测。提供与真实真空泵相同的接口和控制逻辑,便于在没有实际硬件的情况下进行真空系统的集成测试。适用于真空工艺调试、软件开发和实验流程验证等场景。
|
||||
handles:
|
||||
- data_key: fluid_in
|
||||
data_source: handle
|
||||
@@ -494,3 +349,4 @@ vacuum_pump.mock:
|
||||
required:
|
||||
- status
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -8,22 +8,19 @@ zhida_hplc:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -36,26 +33,6 @@ zhida_hplc:
|
||||
title: EmptyIn
|
||||
type: object
|
||||
type: EmptyIn
|
||||
auto-abort:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default: {}
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: abort的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties: {}
|
||||
required: []
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: abort参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-close:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -63,7 +40,7 @@ zhida_hplc:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: close的参数schema
|
||||
description: HPLC设备连接关闭函数。安全地断开与智达HPLC设备的TCP socket连接,释放网络资源。该函数确保连接的正确关闭,避免网络资源泄露。通常在设备使用完毕或系统关闭时调用。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -83,7 +60,7 @@ zhida_hplc:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: connect的参数schema
|
||||
description: HPLC设备连接建立函数。与智达HPLC设备建立TCP socket通信连接,配置通信超时参数。该函数是设备使用前的必要步骤,建立成功后可进行状态查询、方法获取、任务启动等操作。连接失败时会抛出异常。
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
@@ -96,30 +73,6 @@ zhida_hplc:
|
||||
title: connect参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
auto-start:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
goal_default:
|
||||
text: null
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: start的参数schema
|
||||
properties:
|
||||
feedback: {}
|
||||
goal:
|
||||
properties:
|
||||
text:
|
||||
type: string
|
||||
required:
|
||||
- text
|
||||
type: object
|
||||
result: {}
|
||||
required:
|
||||
- goal
|
||||
title: start参数
|
||||
type: object
|
||||
type: UniLabJsonCommand
|
||||
get_methods:
|
||||
feedback: {}
|
||||
goal: {}
|
||||
@@ -127,22 +80,19 @@ zhida_hplc:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action EmptyIn 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties: {}
|
||||
required: []
|
||||
title: EmptyIn_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -164,16 +114,14 @@ zhida_hplc:
|
||||
handles: []
|
||||
result: {}
|
||||
schema:
|
||||
description: ROS Action StrSingleInput 的 JSON Schema
|
||||
description: ''
|
||||
properties:
|
||||
feedback:
|
||||
description: Action 反馈 - 执行过程中从服务器发送到客户端
|
||||
properties: {}
|
||||
required: []
|
||||
title: StrSingleInput_Feedback
|
||||
type: object
|
||||
goal:
|
||||
description: Action 目标 - 从客户端发送到服务器
|
||||
properties:
|
||||
string:
|
||||
type: string
|
||||
@@ -182,7 +130,6 @@ zhida_hplc:
|
||||
title: StrSingleInput_Goal
|
||||
type: object
|
||||
result:
|
||||
description: Action 结果 - 完成后从服务器发送到客户端
|
||||
properties:
|
||||
return_info:
|
||||
type: string
|
||||
@@ -203,7 +150,7 @@ zhida_hplc:
|
||||
methods: dict
|
||||
status: dict
|
||||
type: python
|
||||
description: Zhida HPLC
|
||||
description: 智达高效液相色谱(HPLC)分析设备,用于实验室样品的分离、检测和定量分析。该设备通过TCP socket与HPLC控制系统通信,支持远程控制和状态监控。具备自动进样、梯度洗脱、多检测器数据采集等功能,可执行复杂的色谱分析方法。适用于化学分析、药物检测、环境监测、生物样品分析等需要高精度分离分析的实验室应用场景。
|
||||
handles: []
|
||||
icon: ''
|
||||
init_param_schema:
|
||||
@@ -230,3 +177,4 @@ zhida_hplc:
|
||||
- status
|
||||
- methods
|
||||
type: object
|
||||
version: 0.0.1
|
||||
|
||||
@@ -2,6 +2,8 @@ import copy
|
||||
import io
|
||||
import os
|
||||
import sys
|
||||
import inspect
|
||||
import importlib
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List
|
||||
|
||||
@@ -63,7 +65,7 @@ class Registry:
|
||||
},
|
||||
"feedback": {},
|
||||
"result": {"success": "success"},
|
||||
"schema": ros_action_to_json_schema(self.ResourceCreateFromOuter),
|
||||
"schema": ros_action_to_json_schema(self.ResourceCreateFromOuter, '用于创建或更新物料资源,每次传入多个物料信息。'),
|
||||
"goal_default": yaml.safe_load(
|
||||
io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuter.Goal))
|
||||
),
|
||||
@@ -84,7 +86,7 @@ class Registry:
|
||||
},
|
||||
"feedback": {},
|
||||
"result": {"success": "success"},
|
||||
"schema": ros_action_to_json_schema(self.ResourceCreateFromOuterEasy),
|
||||
"schema": ros_action_to_json_schema(self.ResourceCreateFromOuterEasy, '用于创建或更新物料资源,每次传入一个物料信息。'),
|
||||
"goal_default": yaml.safe_load(
|
||||
io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuterEasy.Goal))
|
||||
),
|
||||
@@ -99,18 +101,25 @@ class Registry:
|
||||
}
|
||||
]
|
||||
},
|
||||
# todo: support nested keys, switch to non ros message schema
|
||||
"placeholder_keys": {
|
||||
"res_id": "unilabos_resources", # 将当前实验室的全部物料id作为下拉框可选择
|
||||
"device_id": "unilabos_devices", # 将当前实验室的全部设备id作为下拉框可选择
|
||||
"parent": "unilabos_devices", # 将当前实验室的全部设备id作为下拉框可选择
|
||||
},
|
||||
},
|
||||
"test_latency": {
|
||||
"type": self.EmptyIn,
|
||||
"goal": {},
|
||||
"feedback": {},
|
||||
"result": {"latency_ms": "latency_ms", "time_diff_ms": "time_diff_ms"},
|
||||
"schema": ros_action_to_json_schema(self.EmptyIn),
|
||||
"schema": ros_action_to_json_schema(self.EmptyIn, '用于测试延迟的动作,返回延迟时间和时间差。'),
|
||||
"goal_default": {},
|
||||
"handles": {},
|
||||
},
|
||||
},
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"icon": "icon_device.webp",
|
||||
"registry_type": "device",
|
||||
"handles": [],
|
||||
@@ -161,6 +170,54 @@ class Registry:
|
||||
else:
|
||||
logger.debug(f"[UniLab Registry] Res File-{i+1}/{len(files)} Not Valid YAML File: {file.absolute()}")
|
||||
|
||||
def _extract_class_docstrings(self, module_string: str) -> Dict[str, str]:
|
||||
"""
|
||||
从模块字符串中提取类和方法的docstring信息
|
||||
|
||||
Args:
|
||||
module_string: 模块字符串,格式为 "module.path:ClassName"
|
||||
|
||||
Returns:
|
||||
包含类和方法docstring信息的字典
|
||||
"""
|
||||
docstrings = {"class_docstring": "", "methods": {}}
|
||||
|
||||
if not module_string or ":" not in module_string:
|
||||
return docstrings
|
||||
|
||||
try:
|
||||
module_path, class_name = module_string.split(":", 1)
|
||||
|
||||
# 动态导入模块
|
||||
module = importlib.import_module(module_path)
|
||||
|
||||
# 获取类
|
||||
if hasattr(module, class_name):
|
||||
cls = getattr(module, class_name)
|
||||
|
||||
# 获取类的docstring
|
||||
class_doc = inspect.getdoc(cls)
|
||||
if class_doc:
|
||||
docstrings["class_docstring"] = class_doc.strip()
|
||||
|
||||
# 获取所有方法的docstring
|
||||
for method_name, method in inspect.getmembers(cls, predicate=inspect.isfunction):
|
||||
method_doc = inspect.getdoc(method)
|
||||
if method_doc:
|
||||
docstrings["methods"][method_name] = method_doc.strip()
|
||||
|
||||
# 也获取属性方法的docstring
|
||||
for method_name, method in inspect.getmembers(cls, predicate=lambda x: isinstance(x, property)):
|
||||
if hasattr(method, "fget") and method.fget:
|
||||
method_doc = inspect.getdoc(method.fget)
|
||||
if method_doc:
|
||||
docstrings["methods"][method_name] = method_doc.strip()
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"[UniLab Registry] 无法提取docstring信息,模块: {module_string}, 错误: {str(e)}")
|
||||
|
||||
return docstrings
|
||||
|
||||
def _replace_type_with_class(self, type_name: str, device_id: str, field_name: str) -> Any:
|
||||
"""
|
||||
将类型名称替换为实际的类对象
|
||||
@@ -274,15 +331,13 @@ class Registry:
|
||||
param_type = arg_info.get("type", "")
|
||||
param_default = arg_info.get("default")
|
||||
param_required = arg_info.get("required", True)
|
||||
schema["properties"][param_name] = self._generate_schema_from_info(
|
||||
param_name, param_type, param_default
|
||||
)
|
||||
schema["properties"][param_name] = self._generate_schema_from_info(param_name, param_type, param_default)
|
||||
if param_required:
|
||||
schema["required"].append(param_name)
|
||||
|
||||
return {
|
||||
"title": f"{method_name}参数",
|
||||
"description": f"{method_name}的参数schema",
|
||||
"description": f"",
|
||||
"type": "object",
|
||||
"properties": {"goal": schema, "feedback": {}, "result": {}},
|
||||
"required": ["goal"],
|
||||
@@ -313,6 +368,8 @@ class Registry:
|
||||
# 在添加到注册表前处理类型替换
|
||||
for device_id, device_config in data.items():
|
||||
# 添加文件路径信息 - 使用规范化的完整文件路径
|
||||
if "version" not in device_config:
|
||||
device_config["version"] = "0.0.1"
|
||||
if "description" not in device_config:
|
||||
device_config["description"] = ""
|
||||
if "icon" not in device_config:
|
||||
@@ -348,6 +405,14 @@ class Registry:
|
||||
sorted(device_config["class"]["status_types"].items())
|
||||
)
|
||||
if complete_registry:
|
||||
# 保存原有的description信息
|
||||
old_descriptions = {}
|
||||
for action_name, action_config in device_config["class"]["action_value_mappings"].items():
|
||||
if "description" in action_config.get("schema", {}):
|
||||
description = action_config["schema"]["description"]
|
||||
if len(description):
|
||||
old_descriptions[action_name] = action_config["schema"]["description"]
|
||||
|
||||
device_config["class"]["action_value_mappings"] = {
|
||||
k: v
|
||||
for k, v in device_config["class"]["action_value_mappings"].items()
|
||||
@@ -365,9 +430,15 @@ class Registry:
|
||||
"goal_default": {i["name"]: i["default"] for i in v["args"]},
|
||||
"handles": [],
|
||||
}
|
||||
# 不生成已配置action的动作
|
||||
for k, v in enhanced_info["action_methods"].items()
|
||||
if k not in device_config["class"]["action_value_mappings"]
|
||||
}
|
||||
)
|
||||
|
||||
# 恢复原有的description信息(auto开头的不修改)
|
||||
for action_name, description in old_descriptions.items():
|
||||
device_config["class"]["action_value_mappings"][action_name]["schema"]["description"] = description
|
||||
device_config["init_param_schema"] = {}
|
||||
device_config["init_param_schema"]["config"] = self._generate_unilab_json_command_schema(
|
||||
enhanced_info["init_params"], "__init__"
|
||||
@@ -471,6 +542,13 @@ class Registry:
|
||||
},
|
||||
**schema["properties"]["goal"]["properties"],
|
||||
}
|
||||
# 将 placeholder_keys 信息添加到 schema 中
|
||||
if "placeholder_keys" in action_config and action_config.get("schema", {}).get(
|
||||
"properties", {}
|
||||
).get("goal", {}):
|
||||
action_config["schema"]["properties"]["goal"]["_unilabos_placeholder_info"] = action_config[
|
||||
"placeholder_keys"
|
||||
]
|
||||
|
||||
msg = {"id": device_id, **device_info_copy}
|
||||
devices.append(msg)
|
||||
|
||||
@@ -132,7 +132,11 @@ _msg_converter: Dict[Type, Any] = {
|
||||
Bool: lambda x: Bool(data=bool(x)),
|
||||
str: str,
|
||||
String: lambda x: String(data=str(x)),
|
||||
Point: lambda x: Point(x=x.x, y=x.y, z=x.z) if not isinstance(x, dict) else Point(x=x.get("x", 0.0), y=x.get("y", 0.0), z=x.get("z", 0.0)),
|
||||
Point: lambda x: (
|
||||
Point(x=x.x, y=x.y, z=x.z)
|
||||
if not isinstance(x, dict)
|
||||
else Point(x=float(x.get("x", 0.0)), y=float(x.get("y", 0.0)), z=float(x.get("z", 0.0)))
|
||||
),
|
||||
Resource: lambda x: Resource(
|
||||
id=x.get("id", ""),
|
||||
name=x.get("name", ""),
|
||||
@@ -142,7 +146,13 @@ _msg_converter: Dict[Type, Any] = {
|
||||
type=x.get("type", ""),
|
||||
category=x.get("class", "") or x.get("type", ""),
|
||||
pose=(
|
||||
Pose(position=Point(x=float(x.get("position", {}).get("x", 0.0)), y=float(x.get("position", {}).get("y", 0.0)), z=float(x.get("position", {}).get("z", 0.0))))
|
||||
Pose(
|
||||
position=Point(
|
||||
x=float(x.get("position", {}).get("x", 0.0)),
|
||||
y=float(x.get("position", {}).get("y", 0.0)),
|
||||
z=float(x.get("position", {}).get("z", 0.0)),
|
||||
)
|
||||
)
|
||||
if x.get("position", None) is not None
|
||||
else Pose()
|
||||
),
|
||||
@@ -151,6 +161,7 @@ _msg_converter: Dict[Type, Any] = {
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def json_or_yaml_loads(data: str) -> Any:
|
||||
try:
|
||||
return json.loads(data)
|
||||
@@ -161,6 +172,7 @@ def json_or_yaml_loads(data: str) -> Any:
|
||||
pass
|
||||
raise e
|
||||
|
||||
|
||||
# ROS消息到Python转换器
|
||||
_msg_converter_back: Dict[Type, Any] = {
|
||||
float: float,
|
||||
@@ -571,27 +583,27 @@ from unilabos.utils.import_manager import ImportManager
|
||||
from unilabos.config.config import ROSConfig
|
||||
|
||||
basic_type_map = {
|
||||
'bool': {'type': 'boolean'},
|
||||
'int8': {'type': 'integer', 'minimum': -128, 'maximum': 127},
|
||||
'uint8': {'type': 'integer', 'minimum': 0, 'maximum': 255},
|
||||
'int16': {'type': 'integer', 'minimum': -32768, 'maximum': 32767},
|
||||
'uint16': {'type': 'integer', 'minimum': 0, 'maximum': 65535},
|
||||
'int32': {'type': 'integer', 'minimum': -2147483648, 'maximum': 2147483647},
|
||||
'uint32': {'type': 'integer', 'minimum': 0, 'maximum': 4294967295},
|
||||
'int64': {'type': 'integer'},
|
||||
'uint64': {'type': 'integer', 'minimum': 0},
|
||||
'double': {'type': 'number'},
|
||||
'float': {'type': 'number'},
|
||||
'float32': {'type': 'number'},
|
||||
'float64': {'type': 'number'},
|
||||
'string': {'type': 'string'},
|
||||
'boolean': {'type': 'boolean'},
|
||||
'char': {'type': 'string', 'maxLength': 1},
|
||||
'byte': {'type': 'integer', 'minimum': 0, 'maximum': 255},
|
||||
"bool": {"type": "boolean"},
|
||||
"int8": {"type": "integer", "minimum": -128, "maximum": 127},
|
||||
"uint8": {"type": "integer", "minimum": 0, "maximum": 255},
|
||||
"int16": {"type": "integer", "minimum": -32768, "maximum": 32767},
|
||||
"uint16": {"type": "integer", "minimum": 0, "maximum": 65535},
|
||||
"int32": {"type": "integer", "minimum": -2147483648, "maximum": 2147483647},
|
||||
"uint32": {"type": "integer", "minimum": 0, "maximum": 4294967295},
|
||||
"int64": {"type": "integer"},
|
||||
"uint64": {"type": "integer", "minimum": 0},
|
||||
"double": {"type": "number"},
|
||||
"float": {"type": "number"},
|
||||
"float32": {"type": "number"},
|
||||
"float64": {"type": "number"},
|
||||
"string": {"type": "string"},
|
||||
"boolean": {"type": "boolean"},
|
||||
"char": {"type": "string", "maxLength": 1},
|
||||
"byte": {"type": "integer", "minimum": 0, "maximum": 255},
|
||||
}
|
||||
|
||||
|
||||
def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) -> Dict[str, Any]:
|
||||
def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str = None) -> Dict[str, Any]:
|
||||
"""
|
||||
将 ROS 字段类型转换为 JSON Schema 类型定义
|
||||
|
||||
@@ -603,10 +615,7 @@ def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) ->
|
||||
对应的 JSON Schema 类型定义
|
||||
"""
|
||||
if isinstance(type_info, UnboundedSequence):
|
||||
return {
|
||||
'type': 'array',
|
||||
'items': ros_field_type_to_json_schema(type_info.value_type)
|
||||
}
|
||||
return {"type": "array", "items": ros_field_type_to_json_schema(type_info.value_type)}
|
||||
if isinstance(type_info, NamespacedType):
|
||||
cls_name = ".".join(type_info.namespaces) + ":" + type_info.name
|
||||
type_class = msg_converter_manager.get_class(cls_name)
|
||||
@@ -614,20 +623,20 @@ def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) ->
|
||||
elif isinstance(type_info, BasicType):
|
||||
return ros_field_type_to_json_schema(type_info.typename)
|
||||
elif isinstance(type_info, UnboundedString):
|
||||
return basic_type_map['string']
|
||||
return basic_type_map["string"]
|
||||
elif isinstance(type_info, str):
|
||||
if type_info in basic_type_map:
|
||||
return basic_type_map[type_info]
|
||||
|
||||
# 处理时间和持续时间类型
|
||||
if type_info in ('time', 'duration', 'builtin_interfaces/Time', 'builtin_interfaces/Duration'):
|
||||
if type_info in ("time", "duration", "builtin_interfaces/Time", "builtin_interfaces/Duration"):
|
||||
return {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'sec': {'type': 'integer', 'description': '秒'},
|
||||
'nanosec': {'type': 'integer', 'description': '纳秒'}
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sec": {"type": "integer", "description": "秒"},
|
||||
"nanosec": {"type": "integer", "description": "纳秒"},
|
||||
},
|
||||
'required': ['sec', 'nanosec']
|
||||
"required": ["sec", "nanosec"],
|
||||
}
|
||||
else:
|
||||
return ros_message_to_json_schema(type_info)
|
||||
@@ -639,8 +648,6 @@ def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) ->
|
||||
# 'items': ros_field_type_to_json_schema(item_type)
|
||||
# }
|
||||
|
||||
|
||||
|
||||
# # 处理复杂类型(尝试加载并处理)
|
||||
# try:
|
||||
# # 如果它是一个完整的消息类型规范 (包名/msg/类型名)
|
||||
@@ -655,6 +662,7 @@ def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) ->
|
||||
# logger.debug(f"无法解析类型 {field_type}: {str(e)}")
|
||||
# return {'type': 'object', 'description': f'未知类型: {field_type}'}
|
||||
|
||||
|
||||
def ros_message_to_json_schema(msg_class: Any) -> Dict[str, Any]:
|
||||
"""
|
||||
将 ROS 消息类转换为 JSON Schema
|
||||
@@ -665,15 +673,11 @@ def ros_message_to_json_schema(msg_class: Any) -> Dict[str, Any]:
|
||||
Returns:
|
||||
对应的 JSON Schema 定义
|
||||
"""
|
||||
schema = {
|
||||
'type': 'object',
|
||||
'properties': {},
|
||||
'required': []
|
||||
}
|
||||
schema = {"type": "object", "properties": {}, "required": []}
|
||||
|
||||
# 获取类名作为标题
|
||||
if hasattr(msg_class, '__name__'):
|
||||
schema['title'] = msg_class.__name__
|
||||
if hasattr(msg_class, "__name__"):
|
||||
schema["title"] = msg_class.__name__
|
||||
|
||||
# 获取消息的字段和字段类型
|
||||
try:
|
||||
@@ -681,8 +685,8 @@ def ros_message_to_json_schema(msg_class: Any) -> Dict[str, Any]:
|
||||
slot_name, slot_type = slot_info
|
||||
type_info = msg_class.SLOT_TYPES[ind]
|
||||
field_schema = ros_field_type_to_json_schema(type_info, slot_type)
|
||||
schema['properties'][slot_name] = field_schema
|
||||
schema['required'].append(slot_name)
|
||||
schema["properties"][slot_name] = field_schema
|
||||
schema["required"].append(slot_name)
|
||||
# if hasattr(msg_class, 'get_fields_and_field_types'):
|
||||
# fields_and_types = msg_class.get_fields_and_field_types()
|
||||
#
|
||||
@@ -707,52 +711,57 @@ def ros_message_to_json_schema(msg_class: Any) -> Dict[str, Any]:
|
||||
# schema['required'].append(clean_name)
|
||||
except Exception as e:
|
||||
# 如果获取字段类型失败,添加错误信息
|
||||
schema['description'] = f"解析消息字段时出错: {str(e)}"
|
||||
schema["description"] = f"解析消息字段时出错: {str(e)}"
|
||||
logger.error(f"解析 {msg_class.__name__} 消息字段失败: {str(e)}")
|
||||
|
||||
return schema
|
||||
|
||||
def ros_action_to_json_schema(action_class: Any) -> Dict[str, Any]:
|
||||
|
||||
def ros_action_to_json_schema(action_class: Any, description="") -> Dict[str, Any]:
|
||||
"""
|
||||
将 ROS Action 类转换为 JSON Schema
|
||||
|
||||
Args:
|
||||
action_class: ROS Action 类
|
||||
description: 描述
|
||||
|
||||
Returns:
|
||||
完整的 JSON Schema 定义
|
||||
"""
|
||||
if not hasattr(action_class, 'Goal') or not hasattr(action_class, 'Feedback') or not hasattr(action_class, 'Result'):
|
||||
if (
|
||||
not hasattr(action_class, "Goal")
|
||||
or not hasattr(action_class, "Feedback")
|
||||
or not hasattr(action_class, "Result")
|
||||
):
|
||||
raise ValueError(f"{action_class.__name__} 不是有效的 ROS Action 类")
|
||||
|
||||
# 创建基础 schema
|
||||
schema = {
|
||||
'title': action_class.__name__,
|
||||
'description': f"ROS Action {action_class.__name__} 的 JSON Schema",
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'goal': {
|
||||
'description': 'Action 目标 - 从客户端发送到服务器',
|
||||
"title": action_class.__name__,
|
||||
"description": description,
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"goal": {
|
||||
# 'description': 'Action 目标 - 从客户端发送到服务器',
|
||||
**ros_message_to_json_schema(action_class.Goal)
|
||||
},
|
||||
'feedback': {
|
||||
'description': 'Action 反馈 - 执行过程中从服务器发送到客户端',
|
||||
"feedback": {
|
||||
# 'description': 'Action 反馈 - 执行过程中从服务器发送到客户端',
|
||||
**ros_message_to_json_schema(action_class.Feedback)
|
||||
},
|
||||
'result': {
|
||||
'description': 'Action 结果 - 完成后从服务器发送到客户端',
|
||||
"result": {
|
||||
# 'description': 'Action 结果 - 完成后从服务器发送到客户端',
|
||||
**ros_message_to_json_schema(action_class.Result)
|
||||
}
|
||||
},
|
||||
},
|
||||
'required': ['goal']
|
||||
"required": ["goal"],
|
||||
}
|
||||
|
||||
return schema
|
||||
|
||||
|
||||
def convert_ros_action_to_jsonschema(
|
||||
action_name_or_type: Union[str, Type],
|
||||
output_file: Optional[str] = None,
|
||||
format: str = 'json'
|
||||
action_name_or_type: Union[str, Type], output_file: Optional[str] = None, format: str = "json"
|
||||
) -> Dict[str, Any]:
|
||||
"""
|
||||
将 ROS Action 类型转换为 JSON Schema,并可选地保存到文件
|
||||
@@ -777,11 +786,11 @@ def convert_ros_action_to_jsonschema(
|
||||
|
||||
# 如果指定了输出文件,将 Schema 保存到文件
|
||||
if output_file:
|
||||
if format.lower() == 'json':
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
if format.lower() == "json":
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
json.dump(schema, f, indent=2, ensure_ascii=False)
|
||||
elif format.lower() == 'yaml':
|
||||
with open(output_file, 'w', encoding='utf-8') as f:
|
||||
elif format.lower() == "yaml":
|
||||
with open(output_file, "w", encoding="utf-8") as f:
|
||||
yaml.safe_dump(schema, f, default_flow_style=False, allow_unicode=True)
|
||||
else:
|
||||
raise ValueError(f"不支持的格式: {format},请使用 'json' 或 'yaml'")
|
||||
|
||||
@@ -307,7 +307,7 @@ class BaseROS2DeviceNode(Node, Generic[T]):
|
||||
# 创建动作服务
|
||||
if self.create_action_server:
|
||||
for action_name, action_value_mapping in self._action_value_mappings.items():
|
||||
if action_name.startswith("auto-"):
|
||||
if action_name.startswith("auto-") or str(action_value_mapping.get("type", "")).startswith("UniLabJsonCommand"):
|
||||
continue
|
||||
self.create_ros_action_server(action_name, action_value_mapping)
|
||||
|
||||
@@ -923,11 +923,18 @@ class ROS2DeviceNode:
|
||||
driver_class.__module__.startswith("pylabrobot")
|
||||
or driver_class.__name__ == "LiquidHandlerAbstract"
|
||||
or driver_class.__name__ == "LiquidHandlerBiomek"
|
||||
or driver_class.__name__ == "PRCXI9300Handler"
|
||||
)
|
||||
|
||||
# TODO: 要在创建之前预先请求服务器是否有当前id的物料,放到resource_tracker中,让pylabrobot进行创建
|
||||
# 创建设备类实例
|
||||
if use_pylabrobot_creator:
|
||||
# 先对pylabrobot的子资源进行加载,不然subclass无法认出
|
||||
# 在下方对于加载Deck等Resource要手动import
|
||||
# noinspection PyUnresolvedReferences
|
||||
from unilabos.devices.liquid_handling.prcxi.prcxi import PRCXI9300Deck
|
||||
# noinspection PyUnresolvedReferences
|
||||
from unilabos.devices.liquid_handling.prcxi.prcxi import PRCXI9300Container
|
||||
self._driver_creator = PyLabRobotCreator(
|
||||
driver_class, children=children, resource_tracker=self.resource_tracker
|
||||
)
|
||||
|
||||
@@ -459,7 +459,7 @@ class HostNode(BaseROS2DeviceNode):
|
||||
self.devices_instances[device_id] = d
|
||||
# noinspection PyProtectedMember
|
||||
for action_name, action_value_mapping in d._ros_node._action_value_mappings.items():
|
||||
if action_name.startswith("auto-"):
|
||||
if action_name.startswith("auto-") or str(action_value_mapping.get("type", "")).startswith("UniLabJsonCommand"):
|
||||
continue
|
||||
action_id = f"/devices/{device_id}/{action_name}"
|
||||
if action_id not in self._action_clients:
|
||||
@@ -603,8 +603,7 @@ class HostNode(BaseROS2DeviceNode):
|
||||
if action_name == "test_latency" and server_info is not None:
|
||||
self.server_latest_timestamp = server_info.get("send_timestamp", 0.0)
|
||||
if action_id not in self._action_clients:
|
||||
self.lab_logger().error(f"[Host Node] ActionClient {action_id} not found.")
|
||||
return
|
||||
raise ValueError(f"ActionClient {action_id} not found.")
|
||||
|
||||
action_client: ActionClient = self._action_clients[action_id]
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
|
||||
if d is not None and hasattr(d, "ros_node_instance"):
|
||||
node = d.ros_node_instance
|
||||
for action_name, action_mapping in node._action_value_mappings.items():
|
||||
if action_name.startswith("auto-"):
|
||||
if action_name.startswith("auto-") or str(action_mapping.get("type", "")).startswith("UniLabJsonCommand"):
|
||||
continue
|
||||
action_id = f"/devices/{device_id_abs}/{action_name}"
|
||||
if action_id not in self._action_clients:
|
||||
|
||||
@@ -148,7 +148,7 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
contain_model = not issubclass(target_type, Deck)
|
||||
resource, target_type = self._process_resource_mapping(resource, target_type)
|
||||
resource_instance: Resource = resource_ulab_to_plr(resource, contain_model)
|
||||
|
||||
states[prefix_path] = resource_instance.serialize_all_state()
|
||||
# 使用 prefix_path 作为 key 存储资源状态
|
||||
if to_dict:
|
||||
serialized = resource_instance.serialize()
|
||||
@@ -199,7 +199,7 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
spect = inspect.signature(deserialize_method)
|
||||
spec_args = spect.parameters
|
||||
for param_name, param_value in data.copy().items():
|
||||
if "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
arg_value = spec_args[param_name].annotation
|
||||
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
|
||||
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
|
||||
@@ -230,7 +230,7 @@ class PyLabRobotCreator(DeviceClassCreator[T]):
|
||||
spect = inspect.signature(self.device_cls.__init__)
|
||||
spec_args = spect.parameters
|
||||
for param_name, param_value in data.copy().items():
|
||||
if "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
if isinstance(param_value, dict) and "_resource_child_name" in param_value and "_resource_type" not in param_value:
|
||||
arg_value = spec_args[param_name].annotation
|
||||
data[param_name]["_resource_type"] = self.device_cls.__module__ + ":" + arg_value
|
||||
logger.debug(f"自动补充 _resource_type: {data[param_name]['_resource_type']}")
|
||||
|
||||
@@ -148,7 +148,7 @@ def configure_logger():
|
||||
"""配置日志记录器"""
|
||||
# 获取根日志记录器
|
||||
root_logger = logging.getLogger()
|
||||
root_logger.setLevel(logging.DEBUG) # 修改为DEBUG以显示所有级别
|
||||
root_logger.setLevel(logging.INFO) # 修改为DEBUG以显示所有级别
|
||||
|
||||
# 移除已存在的处理器
|
||||
for handler in root_logger.handlers[:]:
|
||||
@@ -156,7 +156,7 @@ def configure_logger():
|
||||
|
||||
# 创建控制台处理器
|
||||
console_handler = logging.StreamHandler()
|
||||
console_handler.setLevel(logging.DEBUG) # 修改为DEBUG以显示所有级别
|
||||
console_handler.setLevel(logging.INFO) # 修改为DEBUG以显示所有级别
|
||||
|
||||
# 使用自定义的颜色格式化器
|
||||
color_formatter = ColoredFormatter()
|
||||
|
||||
Reference in New Issue
Block a user