新增注册表补全功能,修复Protocol执行失败

This commit is contained in:
Xuwznln
2025-06-27 23:45:05 +08:00
parent f9a9e91d56
commit bbc49e9aab
39 changed files with 21761 additions and 3336 deletions

View File

@@ -6,12 +6,12 @@ channels:
dependencies: dependencies:
# Basics # Basics
- python=3.11.11 - python=3.11.11
- compilers # - compilers
- cmake # - cmake
- make # - make
- ninja # - ninja
- sphinx # - sphinx
- sphinx_rtd_theme # - sphinx_rtd_theme
# Data Visualization # Data Visualization
- numpy - numpy
- scipy - scipy
@@ -23,7 +23,7 @@ dependencies:
- pyserial - pyserial
- pyusb - pyusb
- pylibftdi - pylibftdi
- pymodbus - pymodbus==3.6.9
- python-can - python-can
- pyvisa - pyvisa
- opencv - opencv
@@ -61,5 +61,12 @@ dependencies:
# ros-humble-gazebo-ros // ignored because of the conflict with ign-gazebo # ros-humble-gazebo-ros // ignored because of the conflict with ign-gazebo
# ilab equipments # ilab equipments
# ros-humble-unilabos-msgs # ros-humble-unilabos-msgs
# driver
#- crcmod
- pip: - pip:
- paho-mqtt - paho-mqtt
# driver
#- ur-rtde # set PYTHONUTF8=1
#- pyautogui
#- pywinauto
#- pywinauto_recorder

View File

@@ -25,12 +25,13 @@ def job_add(req: JobAddReq) -> JobData:
if req.job_id is None: if req.job_id is None:
req.job_id = str(uuid.uuid4()) req.job_id = str(uuid.uuid4())
action_name = req.data["action"] action_name = req.data["action"]
action_kwargs = req.data["action_kwargs"] action_type = req.data.get("action_type", "LocalUnknown")
req.data['action'] = action_name action_args = req.data.get("action_kwargs", None) # 兼容老版本,后续删除
if action_name == "execute_command_from_outer": if action_args is None:
action_kwargs = {"command": json.dumps(action_kwargs)} action_args = req.data.get("action_args")
elif "command" in action_kwargs: else:
action_kwargs = action_kwargs["command"] if "command" in action_args:
action_args = action_args["command"]
# print(f"job_add:{req.device_id} {action_name} {action_kwargs}") # print(f"job_add:{req.device_id} {action_name} {action_kwargs}")
HostNode.get_instance().send_goal(req.device_id, action_name=action_name, action_kwargs=action_kwargs, goal_uuid=req.job_id, server_info=req.server_info) 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)
return JobData(jobId=req.job_id) return JobData(jobId=req.job_id)

View File

@@ -13,17 +13,17 @@ def register_devices_and_resources(mqtt_client, lab_registry):
""" """
logger.info("[UniLab Register] 开始注册设备和资源...") logger.info("[UniLab Register] 开始注册设备和资源...")
# 注册设备信息 # # 注册设备信息
for device_info in lab_registry.obtain_registry_device_info(): # for device_info in lab_registry.obtain_registry_device_info():
mqtt_client.publish_registry(device_info["id"], device_info, False) # mqtt_client.publish_registry(device_info["id"], device_info, False)
logger.debug(f"[UniLab Register] 注册设备: {device_info['id']}") # logger.debug(f"[UniLab Register] 注册设备: {device_info['id']}")
#
# 注册资源信息 # # 注册资源信息
for resource_info in lab_registry.obtain_registry_resource_info(): # for resource_info in lab_registry.obtain_registry_resource_info():
mqtt_client.publish_registry(resource_info["id"], resource_info, False) # mqtt_client.publish_registry(resource_info["id"], resource_info, False)
logger.debug(f"[UniLab Register] 注册资源: {resource_info['id']}") # logger.debug(f"[UniLab Register] 注册资源: {resource_info['id']}")
#
time.sleep(10) # time.sleep(10)
logger.info("[UniLab Register] 设备和资源注册完成.") logger.info("[UniLab Register] 设备和资源注册完成.")
@@ -34,7 +34,7 @@ def main():
""" """
parser = argparse.ArgumentParser(description="注册设备和资源到 MQTT") parser = argparse.ArgumentParser(description="注册设备和资源到 MQTT")
parser.add_argument( parser.add_argument(
"--registry_path", "--registry",
type=str, type=str,
default=None, default=None,
action="append", action="append",
@@ -46,10 +46,16 @@ def main():
default=None, default=None,
help="配置文件路径,支持.py格式的Python配置文件", help="配置文件路径,支持.py格式的Python配置文件",
) )
parser.add_argument(
"--complete_registry",
action="store_true",
default=False,
help="是否补全注册表",
)
args = parser.parse_args() args = parser.parse_args()
# 构建注册表 # 构建注册表
build_registry(args.registry_path) build_registry(args.registry, args.complete_registry)
load_config_from_file(args.config) load_config_from_file(args.config)
from unilabos.app.mq import mqtt_client from unilabos.app.mq import mqtt_client

View File

@@ -40,6 +40,7 @@ class HTTPClient:
Returns: Returns:
Response: API响应对象 Response: API响应对象
""" """
return True
response = requests.post( response = requests.post(
f"{self.remote_addr}/lab/resource/edge/batch_create/?database_process_later={1 if database_process_later else 0}", f"{self.remote_addr}/lab/resource/edge/batch_create/?database_process_later={1 if database_process_later else 0}",
json=resources, json=resources,
@@ -60,6 +61,7 @@ class HTTPClient:
Returns: Returns:
Response: API响应对象 Response: API响应对象
""" """
return True
response = requests.post( response = requests.post(
f"{self.remote_addr}/lab/resource/?database_process_later={1 if database_process_later else 0}", f"{self.remote_addr}/lab/resource/?database_process_later={1 if database_process_later else 0}",
json=resources, json=resources,

View File

@@ -65,6 +65,8 @@ def get_yaml_from_goal_type(goal_type) -> str:
Returns: Returns:
str: 默认Goal参数的YAML格式字符串 str: 默认Goal参数的YAML格式字符串
""" """
if isinstance(goal_type, str):
return "{}"
if not goal_type: if not goal_type:
return "{}" return "{}"

View File

@@ -1,9 +1,12 @@
import rtde_control try:
import dashboard_client import rtde_control
import dashboard_client
import rtde_receive
except ImportError as ex:
print("Import Error, Please Install Packages in ur_arm_task.py First!", ex)
import time import time
import json import json
from unilabos.devices.agv.robotiq_gripper import RobotiqGripper from unilabos.devices.agv.robotiq_gripper import RobotiqGripper
import rtde_receive
from std_msgs.msg import Float64MultiArray from std_msgs.msg import Float64MultiArray
from pydantic import BaseModel from pydantic import BaseModel

View File

@@ -234,71 +234,71 @@ class Laiyu:
resp_reset = self.reset() resp_reset = self.reset()
return actual_mass_mg return actual_mass_mg
if __name__ == "__main__":
'''
样例:对单个粉筒进行称量
'''
modbus = Laiyu(port="COM25")
mass_test = modbus.add_powder_tube(1, 'h12', 6.0)
print(f"实际出料质量:{mass_test}mg")
''' '''
样例:对单个粉筒进行称量 样例: 对一份excel文件记录的化合物进行称量
''' '''
modbus = Laiyu(port="COM25") excel_file = r"C:\auto\laiyu\test1.xlsx"
# 定义输出文件路径,用于记录实际加样多少
output_file = r"C:\auto\laiyu\test_output.xlsx"
mass_test = modbus.add_powder_tube(1, 'h12', 6.0) # 定义物料名称和料筒位置关系
print(f"实际出料质量:{mass_test}mg") compound_positions = {
'XPhos': '1',
'Cu(OTf)2': '2',
'CuSO4': '3',
'PPh3': '4',
}
# read excel file
# excel_file = r"C:\auto\laiyu\test.xlsx"
df = pd.read_excel(excel_file, sheet_name='Sheet1')
# 读取Excel文件中的数据
# 遍历每一行数据
for index, row in df.iterrows():
# 获取物料名称和质量
copper_name = row['copper']
copper_mass = row['copper_mass']
ligand_name = row['ligand']
ligand_mass = row['ligand_mass']
target_tube_position = row['position']
# 获取物料位置 from compound_positions
copper_position = compound_positions.get(copper_name)
ligand_position = compound_positions.get(ligand_name)
# 判断物料位置是否存在
if copper_position is None:
print(f"物料位置不存在:{copper_name}")
continue
if ligand_position is None:
print(f"物料位置不存在:{ligand_name}")
continue
# 加铜
copper_actual_mass = modbus.add_powder_tube(int(copper_position), target_tube_position, copper_mass)
time.sleep(1)
# 加配体
ligand_actual_mass = modbus.add_powder_tube(int(ligand_position), target_tube_position, ligand_mass)
time.sleep(1)
# 保存至df
df.at[index, 'copper_actual_mass'] = copper_actual_mass
df.at[index, 'ligand_actual_mass'] = ligand_actual_mass
''' # 保存修改后的数据到新的Excel文件
样例: 对一份excel文件记录的化合物进行称量 df.to_excel(output_file, index=False)
''' print(f"已保存到文件:{output_file}")
excel_file = r"C:\auto\laiyu\test1.xlsx" # 关闭串口
# 定义输出文件路径,用于记录实际加样多少 modbus.ser.close()
output_file = r"C:\auto\laiyu\test_output.xlsx" print("串口已关闭")
# 定义物料名称和料筒位置关系
compound_positions = {
'XPhos': '1',
'Cu(OTf)2': '2',
'CuSO4': '3',
'PPh3': '4',
}
# read excel file
# excel_file = r"C:\auto\laiyu\test.xlsx"
df = pd.read_excel(excel_file, sheet_name='Sheet1')
# 读取Excel文件中的数据
# 遍历每一行数据
for index, row in df.iterrows():
# 获取物料名称和质量
copper_name = row['copper']
copper_mass = row['copper_mass']
ligand_name = row['ligand']
ligand_mass = row['ligand_mass']
target_tube_position = row['position']
# 获取物料位置 from compound_positions
copper_position = compound_positions.get(copper_name)
ligand_position = compound_positions.get(ligand_name)
# 判断物料位置是否存在
if copper_position is None:
print(f"物料位置不存在:{copper_name}")
continue
if ligand_position is None:
print(f"物料位置不存在:{ligand_name}")
continue
# 加铜
copper_actual_mass = modbus.add_powder_tube(int(copper_position), target_tube_position, copper_mass)
time.sleep(1)
# 加配体
ligand_actual_mass = modbus.add_powder_tube(int(ligand_position), target_tube_position, ligand_mass)
time.sleep(1)
# 保存至df
df.at[index, 'copper_actual_mass'] = copper_actual_mass
df.at[index, 'ligand_actual_mass'] = ligand_actual_mass
# 保存修改后的数据到新的Excel文件
df.to_excel(output_file, index=False)
print(f"已保存到文件:{output_file}")
# 关闭串口
modbus.ser.close()
print("串口已关闭")

View File

@@ -3,7 +3,11 @@ import sys
import io import io
# sys.path.insert(0, r'C:\kui\winprep_cli\winprep_c_Uni-lab\x64\Debug') # sys.path.insert(0, r'C:\kui\winprep_cli\winprep_c_Uni-lab\x64\Debug')
import winprep_c try:
import winprep_c
except ImportError as e:
print("Error importing winprep_c:", e)
print("Please ensure that the winprep_c module is correctly installed and accessible.")
from queue import Queue from queue import Queue

View File

@@ -21,7 +21,7 @@ except Exception as e:
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))) sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "..")))
from unilabos.utils.pywinauto_util import connect_application, get_process_pid_by_name, get_ui_path_with_window_specification, print_wrapper_identifiers from unilabos.utils.pywinauto_util import connect_application, get_process_pid_by_name, get_ui_path_with_window_specification, print_wrapper_identifiers
from unilabos.device_comms.universal_driver import UniversalDriver, SingleRunningExecutor from unilabos.device_comms.universal_driver import UniversalDriver, SingleRunningExecutor
from unilabos.devices.template_driver import universal_driver as ud from unilabos.device_comms import universal_driver as ud
print(f"使用文件DEBUG运行: {e}") print(f"使用文件DEBUG运行: {e}")

View File

@@ -9,7 +9,7 @@ from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import time import time
class RamanObj: class RamanObj:
def __init__(self, port_laser,port_ccd, baudrate_laser=9600, baudrate_ccd=921600): def __init__(self, port_laser, port_ccd, baudrate_laser=9600, baudrate_ccd=921600):
self.port_laser = port_laser self.port_laser = port_laser
self.port_ccd = port_ccd self.port_ccd = port_ccd

View File

@@ -1,11 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import socket
import json
import base64 import base64
import argparse import json
import sys import socket
import time import time
@@ -96,17 +94,20 @@ class ZhidaClient:
def abort(self) -> dict: def abort(self) -> dict:
return self._send_command({"command": "abort"}) return self._send_command({"command": "abort"})
"""
a,b,c
1,2,4
2,4,5
"""
client = ZhidaClient() if __name__ == "__main__":
# 连接
client.connect() """
# 获取状态 a,b,c
print(client.status) 1,2,4
2,4,5
"""
client = ZhidaClient()
# 连接
client.connect()
# 获取状态
print(client.status)
# 命令格式python zhida.py <subcommand> [options] # 命令格式python zhida.py <subcommand> [options]

View File

@@ -1,10 +1,10 @@
io_snrd: #io_snrd:
description: IO Board with 16 IOs # description: IO Board with 16 IOs
class: # class:
module: ilabos.device_comms.SRND_16_IO:SRND_16_IO # module: unilabos.device_comms.SRND_16_IO:SRND_16_IO
type: python # type: python
hardware_interface: # hardware_interface:
name: modbus_client # name: modbus_client
extra_info: [] # extra_info: []
read: read_io_coil # read: read_io_coil
write: write_io_coil # write: write_io_coil

View File

@@ -1,7 +1,117 @@
serial: serial:
description: Serial communication interface, used when sharing same serial port for multiple devices
class: class:
action_value_mappings:
auto-handle_serial_request:
feedback: {}
goal: {}
goal_default:
request: null
response: null
handles: []
result: {}
schema:
description: UniLabJsonCommand handle_serial_request 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand handle_serial_request 的参数schema
properties:
request:
description: '参数: request'
type: string
response:
description: '参数: response'
type: string
required:
- request
- response
type: object
result: {}
required:
- goal
title: handle_serial_request 命令参数
type: object
type: UniLabJsonCommand
auto-read_data:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand read_data 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand read_data 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: read_data 命令参数
type: object
type: UniLabJsonCommand
auto-send_command:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand send_command 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send_command 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: send_command 命令参数
type: object
type: UniLabJsonCommand
module: unilabos.ros.nodes.presets.serial_node:ROS2SerialNode module: unilabos.ros.nodes.presets.serial_node:ROS2SerialNode
status_types: {}
type: ros2 type: ros2
schema: description: Serial communication interface, used when sharing same serial port
properties: {} for multiple devices
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
baudrate:
default: 9600
description: '参数: baudrate'
type: integer
device_id:
description: '参数: device_id'
type: string
port:
description: '参数: port'
type: string
resource_tracker:
description: '参数: resource_tracker'
type: string
required:
- device_id
- port
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,67 +0,0 @@
# 光学表征设备:红外、紫外可见、拉曼等
raman_home_made:
description: Raman spectroscopy device
class:
module: unilabos.devices.raman_uv.home_made_raman:RamanObj
type: python
status_types:
status: String
action_value_mappings:
raman_cmd:
type: SendCmd
goal:
command: command
feedback: {}
result:
success: success
schema:
properties:
status:
type: string
required:
- status
additionalProperties: false
type: object
hplc.agilent:
description: HPLC device
class:
module: unilabos.devices.hplc.AgilentHPLC:HPLCDriver
type: python
status_types:
device_status: String
could_run: Bool
driver_init_ok: Bool
is_running: Bool
finish_status: String
status_text: String
action_value_mappings:
execute_command_from_outer:
type: SendCmd
goal:
command: command
feedback: {}
result:
success: success
schema:
properties:
device_status:
type: string
could_run:
type: boolean
driver_init_ok:
type: boolean
is_running:
type: boolean
finish_status:
type: string
status_text:
type: string
required:
- device_status
- could_run
- driver_init_ok
- is_running
- finish_status
- status_text
additionalProperties: false
type: object

View File

@@ -1,9 +1,55 @@
hotel.thermo_orbitor_rs2_hotel: hotel.thermo_orbitor_rs2_hotel:
description: Thermo Orbitor RS2 Hotel
class: class:
action_value_mappings:
auto-get_rotation:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_rotation 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_rotation 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_rotation 命令参数
type: object
type: UniLabJsonCommand
module: unilabos.devices.resource_container.container:HotelContainer module: unilabos.devices.resource_container.container:HotelContainer
status_types: {}
type: python type: python
description: Thermo Orbitor RS2 Hotel
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
device_config:
description: '参数: device_config'
type: object
rotation:
description: '参数: rotation'
type: object
required:
- rotation
- device_config
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
model: model:
type: device
mesh: thermo_orbitor_rs2_hotel mesh: thermo_orbitor_rs2_hotel
type: device

View File

@@ -1,56 +1,608 @@
laiyu_add_solid: laiyu_add_solid:
description: Laiyu Add Solid
class: class:
module: unilabos.devices.laiyu_add_solid.laiyu:Laiyu
type: python
status_types: {}
action_value_mappings: action_value_mappings:
add_powder_tube:
feedback: {}
goal:
compound_mass: compound_mass
powder_tube_number: powder_tube_number
target_tube_position: target_tube_position
goal_default:
compound_mass: 0.0
powder_tube_number: 0
target_tube_position: ''
handles: []
result:
actual_mass_mg: actual_mass_mg
schema:
description: ROS Action SolidDispenseAddPowderTube 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: SolidDispenseAddPowderTube_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
compound_mass:
type: number
powder_tube_number:
maximum: 2147483647
minimum: -2147483648
type: integer
target_tube_position:
type: string
required:
- powder_tube_number
- target_tube_position
- compound_mass
title: SolidDispenseAddPowderTube_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
actual_mass_mg:
type: number
return_info:
type: string
success:
type: boolean
required:
- return_info
- actual_mass_mg
- success
title: SolidDispenseAddPowderTube_Result
type: object
required:
- goal
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: UniLabJsonCommand add_powder_tube 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand add_powder_tube 的参数schema
properties:
compound_mass:
description: '参数: compound_mass'
type: string
powder_tube_number:
description: '参数: powder_tube_number'
type: string
target_tube_position:
description: '参数: 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: {}
goal_default:
data: null
handles: []
result: {}
schema:
description: UniLabJsonCommand calculate_crc 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand calculate_crc 的参数schema
properties:
data:
description: '参数: data'
type: string
required:
- data
type: object
result: {}
required:
- goal
title: calculate_crc 命令参数
type: object
type: UniLabJsonCommand
auto-discharge:
feedback: {}
goal: {}
goal_default:
float_in: null
handles: []
result: {}
schema:
description: UniLabJsonCommand discharge 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand discharge 的参数schema
properties:
float_in:
description: '参数: 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: UniLabJsonCommand move_to_plate 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand move_to_plate 的参数schema
properties:
string:
description: '参数: 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: UniLabJsonCommand move_to_xyz 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand move_to_xyz 的参数schema
properties:
x:
description: '参数: x'
type: number
y:
description: '参数: y'
type: number
z:
description: '参数: 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: UniLabJsonCommand pick_powder_tube 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand pick_powder_tube 的参数schema
properties:
int_input:
description: '参数: 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: UniLabJsonCommand put_powder_tube 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand put_powder_tube 的参数schema
properties:
int_input:
description: '参数: 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: UniLabJsonCommand reset 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand reset 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: reset 命令参数
type: object
type: UniLabJsonCommand
auto-send_command:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand send_command 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send_command 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: send_command 命令参数
type: object
type: UniLabJsonCommand
discharge:
feedback: {}
goal:
float_input: float_input
goal_default:
float_in: 0.0
handles: []
result: {}
schema:
description: ROS Action FloatSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: FloatSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
float_in:
type: number
required:
- float_in
title: FloatSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: FloatSingleInput_Result
type: object
required:
- goal
title: FloatSingleInput
type: object
type: FloatSingleInput
move_to_plate:
feedback: {}
goal:
string: string
goal_default:
string: ''
handles: []
result: {}
schema:
description: ROS Action StrSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: StrSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
string:
type: string
required:
- string
title: StrSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: StrSingleInput_Result
type: object
required:
- goal
title: StrSingleInput
type: object
type: StrSingleInput
move_to_xyz: move_to_xyz:
type: Point3DSeparateInput feedback: {}
goal: goal:
x: x x: x
y: y y: y
z: z z: z
feedback: {} goal_default:
x: 0.0
y: 0.0
z: 0.0
handles: []
result: {} result: {}
schema:
description: ROS Action Point3DSeparateInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: Point3DSeparateInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
x:
type: number
y:
type: number
z:
type: number
required:
- x
- y
- z
title: Point3DSeparateInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: Point3DSeparateInput_Result
type: object
required:
- goal
title: Point3DSeparateInput
type: object
type: Point3DSeparateInput
pick_powder_tube: pick_powder_tube:
type: IntSingleInput feedback: {}
goal: goal:
int_input: int_input int_input: int_input
feedback: {} goal_default:
int_input: 0
handles: []
result: {} result: {}
schema:
description: ROS Action IntSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: IntSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
int_input:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- int_input
title: IntSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: IntSingleInput_Result
type: object
required:
- goal
title: IntSingleInput
type: object
type: IntSingleInput
put_powder_tube: put_powder_tube:
type: IntSingleInput feedback: {}
goal: goal:
int_input: int_input int_input: int_input
feedback: {} goal_default:
int_input: 0
handles: []
result: {} result: {}
schema:
description: ROS Action IntSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: IntSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
int_input:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- int_input
title: IntSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: IntSingleInput_Result
type: object
required:
- goal
title: IntSingleInput
type: object
type: IntSingleInput
reset: reset:
type: EmptyIn feedback: {}
goal: {} goal: {}
feedback: {} goal_default: {}
handles: []
result: {} result: {}
add_powder_tube: schema:
type: SolidDispenseAddPowderTube description: ROS Action EmptyIn 的 JSON Schema
goal: properties:
powder_tube_number: powder_tube_number feedback:
target_tube_position: target_tube_position description: Action 反馈 - 执行过程中从服务器发送到客户端
compound_mass: compound_mass properties: {}
feedback: {} required: []
result: title: EmptyIn_Feedback
actual_mass_mg: actual_mass_mg type: object
move_to_plate: goal:
type: StrSingleInput description: Action 目标 - 从客户端发送到服务器
goal: properties: {}
string: string required: []
feedback: {} title: EmptyIn_Goal
result: {} type: object
discharge: result:
type: FloatSingleInput description: Action 结果 - 完成后从服务器发送到客户端
goal: properties:
float_input: float_input return_info:
feedback: {} type: string
result: {} required:
- return_info
schema: title: EmptyIn_Result
properties: {} type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
module: unilabos.devices.laiyu_add_solid.laiyu:Laiyu
status_types:
status: str
type: python
description: Laiyu Add Solid
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
baudrate:
default: 115200
description: '参数: baudrate'
type: integer
port:
description: '参数: port'
type: string
timeout:
default: 0.5
description: '参数: timeout'
type: number
required:
- port
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,56 +1,328 @@
moveit.toyo_xyz:
description: Toyo XYZ
class:
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
type: python
action_value_mappings:
set_position:
type: SendCmd
goal:
command: command
feedback: { }
result: { }
pick_and_place:
type: SendCmd
goal:
command: command
feedback: { }
result: { }
set_status:
type: SendCmd
goal:
command: command
feedback: { }
result: { }
model:
type: device
mesh: toyo_xyz
moveit.arm_slider: moveit.arm_slider:
description: Arm with Slider
model:
type: device
mesh: arm_slider
class: class:
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
type: python
action_value_mappings: action_value_mappings:
set_position:
type: SendCmd
goal:
command: command
feedback: {}
result: {}
pick_and_place: pick_and_place:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: {} result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
set_position:
feedback: {}
goal:
command: command
goal_default:
command: ''
handles: []
result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
set_status: set_status:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: {} result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
status_types: {}
type: python
description: Arm with Slider
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
model:
mesh: arm_slider
type: device
moveit.toyo_xyz:
class:
action_value_mappings:
pick_and_place:
feedback: {}
goal:
command: command
goal_default:
command: ''
handles: []
result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
set_position:
feedback: {}
goal:
command: command
goal_default:
command: ''
handles: []
result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
set_status:
feedback: {}
goal:
command: command
goal_default:
command: ''
handles: []
result: {}
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.ros_dev.moveit_interface:MoveitInterface
status_types: {}
type: python
description: Toyo XYZ
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
model:
mesh: toyo_xyz
type: device

View File

@@ -1,73 +1,492 @@
separator.homemade: rotavap.one:
description: Separator device with homemade grbl controller
class: class:
module: unilabos.devices.separator.homemade_grbl_conductivity:SeparatorController
type: python
status_types:
sensordata: Float64
status: String
action_value_mappings: action_value_mappings:
stir: auto-cmd_write:
type: Stir feedback: {}
goal: goal: {}
stir_time: stir_time, goal_default:
stir_speed: stir_speed cmd: null
settling_time: settling_time handles: []
feedback: result: {}
status: status schema:
result: description: UniLabJsonCommand cmd_write 的参数schema
success: success properties:
valve_open_cmd: feedback: {}
type: SendCmd goal:
description: UniLabJsonCommand cmd_write 的参数schema
properties:
cmd:
description: '参数: cmd'
type: string
required:
- cmd
type: object
result: {}
required:
- goal
title: cmd_write 命令参数
type: object
type: UniLabJsonCommand
auto-main_loop:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand main_loop 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand main_loop 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: main_loop 命令参数
type: object
type: UniLabJsonCommand
auto-set_pump_time:
feedback: {}
goal: {}
goal_default:
time: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_pump_time 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_pump_time 的参数schema
properties:
time:
description: '参数: time'
type: string
required:
- time
type: object
result: {}
required:
- goal
title: set_pump_time 命令参数
type: object
type: UniLabJsonCommand
auto-set_rotate_time:
feedback: {}
goal: {}
goal_default:
time: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_rotate_time 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_rotate_time 的参数schema
properties:
time:
description: '参数: time'
type: string
required:
- time
type: object
result: {}
required:
- goal
title: set_rotate_time 命令参数
type: object
type: UniLabJsonCommand
auto-set_timer:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_timer 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_timer 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: set_timer 命令参数
type: object
type: UniLabJsonCommand
set_timer:
feedback: {}
goal: goal:
command: command command: command
feedback: goal_default:
status: status command: ''
result": handles: []
result:
success: success success: success
schema: schema:
type: object description: ROS Action SendCmd 的 JSON Schema
properties: properties:
status: feedback:
type: string description: Action 反馈 - 执行过程中从服务器发送到客户端
description: The status of the device properties:
sensordata: status:
type: number type: string
description: 电导传感器数据 required:
required: - status
- status title: SendCmd_Feedback
- sensordata type: object
additionalProperties: false goal:
description: Action 目标 - 从客户端发送到服务器
rotavap.one: properties:
description: Rotavap device command:
class: type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.rotavap.rotavap_one:RotavapOne module: unilabos.devices.rotavap.rotavap_one:RotavapOne
type: python
status_types: status_types:
pump_time: Float64 pump_time: Float64
rotate_time: Float64 rotate_time: Float64
type: python
description: Rotavap device
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
port:
description: '参数: port'
type: string
rate:
default: 9600
description: '参数: rate'
type: integer
required:
- port
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
separator.homemade:
class:
action_value_mappings: action_value_mappings:
set_timer: auto-read_sensor_loop:
type: SendCmd
goal:
command: command
feedback: {} feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand read_sensor_loop 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand read_sensor_loop 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
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: UniLabJsonCommand stir 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand stir 的参数schema
properties:
settling_time:
default: 10
description: '参数: settling_time'
type: number
stir_speed:
default: 300
description: '参数: stir_speed'
type: number
stir_time:
default: 10
description: '参数: stir_time'
type: number
required: []
type: object
result: {}
required:
- goal
title: stir 命令参数
type: object
type: UniLabJsonCommand
auto-valve_open:
feedback: {}
goal: {}
goal_default:
condition: null
value: null
handles: []
result: {}
schema:
description: UniLabJsonCommand valve_open 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand valve_open 的参数schema
properties:
condition:
description: '参数: condition'
type: string
value:
description: '参数: value'
type: string
required:
- condition
- value
type: object
result: {}
required:
- goal
title: valve_open 命令参数
type: object
type: UniLabJsonCommand
auto-valve_open_cmd:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand valve_open_cmd 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand valve_open_cmd 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: valve_open_cmd 命令参数
type: object
type: UniLabJsonCommand
auto-write:
feedback: {}
goal: {}
goal_default:
data: null
handles: []
result: {}
schema:
description: UniLabJsonCommand write 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand write 的参数schema
properties:
data:
description: '参数: data'
type: string
required:
- data
type: object
result: {}
required:
- goal
title: write 命令参数
type: object
type: UniLabJsonCommand
stir:
feedback:
status: status
goal:
settling_time: settling_time
stir_speed: stir_speed
stir_time: stir_time,
goal_default:
settling_time: 0.0
stir_speed: 0.0
stir_time: 0.0
handles: []
result: result:
success: success success: success
schema: schema:
type: object description: ROS Action Stir 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: Stir_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
settling_time:
type: number
stir_speed:
type: number
stir_time:
type: number
required:
- stir_time
- stir_speed
- settling_time
title: Stir_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: Stir_Result
type: object
required:
- goal
title: Stir
type: object
type: Stir
valve_open_cmd:
feedback:
status: status
goal:
command: command
goal_default:
command: ''
handles: []
result":
success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.separator.homemade_grbl_conductivity:SeparatorController
status_types:
sensordata: Float64
status: String
type: python
description: Separator device with homemade grbl controller
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties: properties:
temperature: feedback: {}
type: number goal:
description: 旋蒸水浴温度 description: UniLabJsonCommand __init__ 的参数schema
pump_time: properties:
type: number baudrate_executor:
description: The pump time of the device default: 115200
rotate_time: description: '参数: baudrate_executor'
type: number type: integer
description: The rotate time of the device baudrate_sensor:
default: 115200
description: '参数: baudrate_sensor'
type: integer
port_executor:
description: '参数: port_executor'
type: string
port_sensor:
description: '参数: port_sensor'
type: string
required:
- port_executor
- port_sensor
type: object
result: {}
required: required:
- pump_time - goal
- rotate_time title: __init__ 命令参数
additionalProperties: false type: object

File diff suppressed because it is too large Load Diff

View File

@@ -1,29 +1,138 @@
# 仙工智能底盘(知行使用)
agv.SEER: agv.SEER:
description: SEER AGV
class: class:
module: unilabos.devices.agv.agv_navigator:AgvNavigator
type: python
status_types:
pose: Float64MultiArray
status: String
action_value_mappings: action_value_mappings:
auto-send:
feedback: {}
goal: {}
goal_default:
cmd: null
ex_data: ''
obj: receive_socket
handles: []
result: {}
schema:
description: UniLabJsonCommand send 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send 的参数schema
properties:
cmd:
description: '参数: cmd'
type: string
ex_data:
default: ''
description: '参数: ex_data'
type: string
obj:
default: receive_socket
description: '参数: obj'
type: string
required:
- cmd
type: object
result: {}
required:
- goal
title: send 命令参数
type: object
type: UniLabJsonCommand
auto-send_nav_task:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand send_nav_task 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send_nav_task 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: send_nav_task 命令参数
type: object
type: UniLabJsonCommand
send_nav_task: send_nav_task:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: result:
success: success success: success
schema: schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.agv.agv_navigator:AgvNavigator
status_types:
pose: list
status: str
type: python
description: SEER AGV
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties: properties:
pose: feedback: {}
type: array goal:
items: description: UniLabJsonCommand __init__ 的参数schema
type: number properties:
status: host:
type: string description: '参数: host'
type: string
required:
- host
type: object
result: {}
required: required:
- status - goal
additionalProperties: false title: __init__ 命令参数
type: object type: object

View File

@@ -1,37 +1,202 @@
robotic_arm.UR: robotic_arm.UR:
description: UR robotic arm
class: class:
module: unilabos.devices.agv.ur_arm_task:UrArmTask
type: python
status_types:
arm_pose: Float64MultiArray
gripper_pose: Float64
arm_status: String
gripper_status: String
action_value_mappings: action_value_mappings:
auto-arm_init:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand arm_init 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand arm_init 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: arm_init 命令参数
type: object
type: UniLabJsonCommand
auto-load_pose_data:
feedback: {}
goal: {}
goal_default:
data: null
handles: []
result: {}
schema:
description: UniLabJsonCommand load_pose_data 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand load_pose_data 的参数schema
properties:
data:
description: '参数: data'
type: string
required:
- data
type: object
result: {}
required:
- goal
title: load_pose_data 命令参数
type: object
type: UniLabJsonCommand
auto-load_pose_file:
feedback: {}
goal: {}
goal_default:
file: null
handles: []
result: {}
schema:
description: UniLabJsonCommand load_pose_file 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand load_pose_file 的参数schema
properties:
file:
description: '参数: file'
type: string
required:
- file
type: object
result: {}
required:
- goal
title: load_pose_file 命令参数
type: object
type: UniLabJsonCommand
auto-move_pos_task:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand move_pos_task 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand move_pos_task 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: move_pos_task 命令参数
type: object
type: UniLabJsonCommand
auto-reload_pose:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand reload_pose 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand reload_pose 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: reload_pose 命令参数
type: object
type: UniLabJsonCommand
move_pos_task: move_pos_task:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: result:
success: success success: success
schema: schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.agv.ur_arm_task:UrArmTask
status_types:
arm_pose: list
arm_status: str
gripper_pose: float
gripper_status: str
type: python
description: UR robotic arm
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties: properties:
arm_pose: feedback: {}
type: array goal:
items: description: UniLabJsonCommand __init__ 的参数schema
type: number properties:
gripper_pose: host:
type: number description: '参数: host'
arm_status: type: string
type: string retry:
description: 机械臂设备状态 default: 30
gripper_status: description: '参数: retry'
type: string type: integer
description: 机械爪设备状态 required:
- host
type: object
result: {}
required: required:
- arm_status - goal
- gripper_status title: __init__ 命令参数
additionalProperties: false
type: object type: object

View File

@@ -1,37 +1,174 @@
gripper.mock:
description: Mock gripper
class:
module: unilabos.devices.gripper.mock:MockGripper
type: python
status_types:
position: Float64
torque: Float64
status: String
action_value_mappings:
push_to:
type: GripperCommand
goal:
command.position: position
command.max_effort: torque
feedback:
position: position
effort: torque
result:
position: position
effort: torque
gripper.misumi_rz: gripper.misumi_rz:
description: Misumi RZ gripper
class: class:
module: unilabos.devices.motor:Grasp.EleGripper
type: python
status_types:
status: String
action_value_mappings: action_value_mappings:
execute_command_from_outer: execute_command_from_outer:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: result:
success: success success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.motor.Grasp:EleGripper
status_types:
status: String
type: python
description: Misumi RZ gripper
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
gripper.mock:
class:
action_value_mappings:
push_to:
feedback:
effort: torque
position: position
goal:
command.max_effort: torque
command.position: position
goal_default:
command:
max_effort: 0.0
position: 0.0
handles: []
result:
effort: torque
position: position
schema:
description: ROS Action GripperCommand 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
effort:
type: number
position:
type: number
reached_goal:
type: boolean
stalled:
type: boolean
required:
- position
- effort
- stalled
- reached_goal
title: GripperCommand_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
properties:
max_effort:
type: number
position:
type: number
required:
- position
- max_effort
title: GripperCommand
type: object
required:
- command
title: GripperCommand_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
effort:
type: number
position:
type: number
reached_goal:
type: boolean
stalled:
type: boolean
required:
- position
- effort
- stalled
- reached_goal
title: GripperCommand_Result
type: object
required:
- goal
title: GripperCommand
type: object
type: GripperCommand
module: unilabos.devices.gripper.mock:MockGripper
status_types:
position: Float64
status: String
torque: Float64
type: python
description: Mock gripper
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,57 +1,542 @@
linear_motion.grbl: linear_motion.grbl:
description: Grbl CNC
class: class:
module: unilabos.devices.cnc.grbl_sync:GrblCNC
type: python
action_value_mappings: action_value_mappings:
move_through_points: &move_through_points move_through_points:
type: NavigateThroughPoses
goal:
poses[].pose.position: positions[]
feedback: feedback:
current_pose.pose.position: position current_pose.pose.position: position
navigation_time.sec: time_spent
estimated_time_remaining.sec: time_remaining estimated_time_remaining.sec: time_remaining
navigation_time.sec: time_spent
number_of_poses_remaining: pose_number_remaining number_of_poses_remaining: pose_number_remaining
result: {}
set_spindle_speed:
type: SingleJointPosition
goal: goal:
position: spindle_speed poses[].pose.position: positions[]
goal_default:
behavior_tree: ''
poses:
- header:
frame_id: ''
stamp:
nanosec: 0
sec: 0
pose:
orientation:
w: 1.0
x: 0.0
y: 0.0
z: 0.0
position:
x: 0.0
y: 0.0
z: 0.0
handles: []
result: {}
schema:
description: ROS Action NavigateThroughPoses 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
current_pose:
properties:
header:
properties:
frame_id:
type: string
stamp:
properties:
nanosec:
maximum: 4294967295
minimum: 0
type: integer
sec:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Time
type: object
required:
- stamp
- frame_id
title: Header
type: object
pose:
properties:
orientation:
properties:
w:
type: number
x:
type: number
y:
type: number
z:
type: number
required:
- x
- y
- z
- w
title: Quaternion
type: object
position:
properties:
x:
type: number
y:
type: number
z:
type: number
required:
- x
- y
- z
title: Point
type: object
required:
- position
- orientation
title: Pose
type: object
required:
- header
- pose
title: PoseStamped
type: object
distance_remaining:
type: number
estimated_time_remaining:
properties:
nanosec:
maximum: 4294967295
minimum: 0
type: integer
sec:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Duration
type: object
navigation_time:
properties:
nanosec:
maximum: 4294967295
minimum: 0
type: integer
sec:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Duration
type: object
number_of_poses_remaining:
maximum: 32767
minimum: -32768
type: integer
number_of_recoveries:
maximum: 32767
minimum: -32768
type: integer
required:
- current_pose
- navigation_time
- estimated_time_remaining
- number_of_recoveries
- distance_remaining
- number_of_poses_remaining
title: NavigateThroughPoses_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
behavior_tree:
type: string
poses:
items:
properties:
header:
properties:
frame_id:
type: string
stamp:
properties:
nanosec:
maximum: 4294967295
minimum: 0
type: integer
sec:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Time
type: object
required:
- stamp
- frame_id
title: Header
type: object
pose:
properties:
orientation:
properties:
w:
type: number
x:
type: number
y:
type: number
z:
type: number
required:
- x
- y
- z
- w
title: Quaternion
type: object
position:
properties:
x:
type: number
y:
type: number
z:
type: number
required:
- x
- y
- z
title: Point
type: object
required:
- position
- orientation
title: Pose
type: object
required:
- header
- pose
title: PoseStamped
type: object
type: array
required:
- poses
- behavior_tree
title: NavigateThroughPoses_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
result:
properties: {}
required: []
title: Empty
type: object
required:
- result
title: NavigateThroughPoses_Result
type: object
required:
- goal
title: NavigateThroughPoses
type: object
type: NavigateThroughPoses
set_spindle_speed:
feedback: feedback:
position: spindle_speed position: spindle_speed
goal:
position: spindle_speed
goal_default:
max_velocity: 0.0
min_duration:
nanosec: 0
sec: 0
position: 0.0
handles: []
result: {} result: {}
schema: schema:
type: object description: ROS Action SingleJointPosition 的 JSON Schema
properties: properties:
position: feedback:
type: array description: Action 反馈 - 执行过程中从服务器发送到客户端
items: properties:
type: number error:
description: The position of the device type: number
spindle_speed: header:
type: number properties:
description: The spindle speed of the device frame_id:
required: type: string
- position stamp:
- spindle_speed properties:
additionalProperties: false nanosec:
maximum: 4294967295
minimum: 0
motor.iCL42: type: integer
description: iCL42 motor sec:
class: maximum: 2147483647
module: unilabos.devices.motor.iCL42:iCL42Driver minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Time
type: object
required:
- stamp
- frame_id
title: Header
type: object
position:
type: number
velocity:
type: number
required:
- header
- position
- velocity
- error
title: SingleJointPosition_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
max_velocity:
type: number
min_duration:
properties:
nanosec:
maximum: 4294967295
minimum: 0
type: integer
sec:
maximum: 2147483647
minimum: -2147483648
type: integer
required:
- sec
- nanosec
title: Duration
type: object
position:
type: number
required:
- position
- min_duration
- max_velocity
title: SingleJointPosition_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties: {}
required: []
title: SingleJointPosition_Result
type: object
required:
- goal
title: SingleJointPosition
type: object
type: SingleJointPosition
module: unilabos.devices.cnc.grbl_sync:GrblCNC
status_types: {}
type: python type: python
status_types: description: Grbl CNC
motor_position: Int64 handles: []
is_executing_run: Bool icon: ''
success: Bool init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
motor.iCL42:
class:
action_value_mappings: action_value_mappings:
auto-execute_run_motor:
feedback: {}
goal: {}
goal_default:
mode: null
position: null
velocity: null
handles: []
result: {}
schema:
description: UniLabJsonCommand execute_run_motor 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand execute_run_motor 的参数schema
properties:
mode:
description: '参数: mode'
type: string
position:
description: '参数: position'
type: number
velocity:
description: '参数: velocity'
type: integer
required:
- mode
- position
- velocity
type: object
result: {}
required:
- goal
title: execute_run_motor 命令参数
type: object
type: UniLabJsonCommand
auto-init_device:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand init_device 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand init_device 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: init_device 命令参数
type: object
type: UniLabJsonCommand
auto-run_motor:
feedback: {}
goal: {}
goal_default:
mode: null
position: null
velocity: null
handles: []
result: {}
schema:
description: UniLabJsonCommand run_motor 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand run_motor 的参数schema
properties:
mode:
description: '参数: mode'
type: string
position:
description: '参数: position'
type: number
velocity:
description: '参数: velocity'
type: integer
required:
- mode
- position
- velocity
type: object
result: {}
required:
- goal
title: run_motor 命令参数
type: object
type: UniLabJsonCommand
execute_command_from_outer: execute_command_from_outer:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: result:
success: success success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.motor.iCL42:iCL42Driver
status_types:
is_executing_run: bool
motor_position: int
success: bool
type: python
description: iCL42 motor
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
device_address:
default: 1
description: '参数: device_address'
type: integer
device_com:
default: COM9
description: '参数: device_com'
type: string
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,5 +1,355 @@
lh_joint_publisher: lh_joint_publisher:
class: class:
action_value_mappings:
auto-check_tf_update_actions:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand check_tf_update_actions 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand check_tf_update_actions 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: check_tf_update_actions 命令参数
type: object
type: UniLabJsonCommand
auto-find_resource_parent:
feedback: {}
goal: {}
goal_default:
resource_id: null
handles: []
result: {}
schema:
description: UniLabJsonCommand find_resource_parent 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand find_resource_parent 的参数schema
properties:
resource_id:
description: '参数: resource_id'
type: string
required:
- resource_id
type: object
result: {}
required:
- goal
title: find_resource_parent 命令参数
type: object
type: UniLabJsonCommand
auto-inverse_kinematics:
feedback: {}
goal: {}
goal_default:
parent_id: null
x: null
x_joint: null
y: null
y_joint: null
z: null
z_joint: null
handles: []
result: {}
schema:
description: UniLabJsonCommand inverse_kinematics 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand inverse_kinematics 的参数schema
properties:
parent_id:
description: '参数: parent_id'
type: string
x:
description: '参数: x'
type: string
x_joint:
description: '参数: x_joint'
type: object
y:
description: '参数: y'
type: string
y_joint:
description: '参数: y_joint'
type: object
z:
description: '参数: z'
type: string
z_joint:
description: '参数: z_joint'
type: object
required:
- x
- y
- z
- parent_id
- x_joint
- y_joint
- z_joint
type: object
result: {}
required:
- goal
title: inverse_kinematics 命令参数
type: object
type: UniLabJsonCommand
auto-lh_joint_action_callback:
feedback: {}
goal: {}
goal_default:
goal_handle: null
handles: []
result: {}
schema:
description: UniLabJsonCommand lh_joint_action_callback 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand lh_joint_action_callback 的参数schema
properties:
goal_handle:
description: '参数: goal_handle'
type: string
required:
- goal_handle
type: object
result: {}
required:
- goal
title: lh_joint_action_callback 命令参数
type: object
type: UniLabJsonCommand
auto-lh_joint_pub_callback:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand lh_joint_pub_callback 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand lh_joint_pub_callback 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: lh_joint_pub_callback 命令参数
type: object
type: UniLabJsonCommand
auto-move_joints:
feedback: {}
goal: {}
goal_default:
option: null
resource_names: null
speed: 0.1
x: null
x_joint: null
y: null
y_joint: null
z: null
z_joint: null
handles: []
result: {}
schema:
description: UniLabJsonCommand move_joints 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand move_joints 的参数schema
properties:
option:
description: '参数: option'
type: string
resource_names:
description: '参数: resource_names'
type: string
speed:
default: 0.1
description: '参数: speed'
type: number
x:
description: '参数: x'
type: string
x_joint:
description: '参数: x_joint'
type: string
y:
description: '参数: y'
type: string
y_joint:
description: '参数: y_joint'
type: string
z:
description: '参数: z'
type: string
z_joint:
description: '参数: z_joint'
type: string
required:
- resource_names
- x
- y
- z
- option
type: object
result: {}
required:
- goal
title: move_joints 命令参数
type: object
type: UniLabJsonCommand
auto-move_to:
feedback: {}
goal: {}
goal_default:
joint_positions: null
parent_id: null
speed: null
handles: []
result: {}
schema:
description: UniLabJsonCommand move_to 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand move_to 的参数schema
properties:
joint_positions:
description: '参数: joint_positions'
type: string
parent_id:
description: '参数: parent_id'
type: string
speed:
description: '参数: speed'
type: string
required:
- joint_positions
- speed
- parent_id
type: object
result: {}
required:
- goal
title: move_to 命令参数
type: object
type: UniLabJsonCommand
auto-resource_move:
feedback: {}
goal: {}
goal_default:
channels: null
link_name: null
resource_id: null
handles: []
result: {}
schema:
description: UniLabJsonCommand resource_move 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand resource_move 的参数schema
properties:
channels:
description: '参数: channels'
type: string
link_name:
description: '参数: link_name'
type: string
resource_id:
description: '参数: resource_id'
type: string
required:
- resource_id
- link_name
- channels
type: object
result: {}
required:
- goal
title: resource_move 命令参数
type: object
type: UniLabJsonCommand
auto-send_resource_action:
feedback: {}
goal: {}
goal_default:
link_name: null
resource_id_list: null
handles: []
result: {}
schema:
description: UniLabJsonCommand send_resource_action 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send_resource_action 的参数schema
properties:
link_name:
description: '参数: link_name'
type: string
resource_id_list:
description: '参数: resource_id_list'
type: string
required:
- resource_id_list
- link_name
type: object
result: {}
required:
- goal
title: send_resource_action 命令参数
type: object
type: UniLabJsonCommand
module: unilabos.devices.ros_dev.liquid_handler_joint_publisher:LiquidHandlerJointPublisher module: unilabos.devices.ros_dev.liquid_handler_joint_publisher:LiquidHandlerJointPublisher
status_types: {}
type: ros2 type: ros2
description: ''
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
device_id:
default: lh_joint_publisher
description: '参数: device_id'
type: string
rate:
default: 50
description: '参数: rate'
type: integer
resource_tracker:
description: '参数: resource_tracker'
type: string
resources_config:
description: '参数: resources_config'
type: array
required:
- resources_config
- resource_tracker
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,65 +1,884 @@
heaterstirrer.dalong: chiller:
description: DaLong heater stirrer
class: class:
module: unilabos.devices.heaterstirrer.dalong:HeaterStirrer_DaLong
type: python
status_types:
temp: Float64
temp_warning: Float64
stir_speed: Float64
action_value_mappings: action_value_mappings:
set_temp_warning: auto-build_modbus_frame:
type: SendCmd
goal:
command: temp
feedback: {} feedback: {}
goal: {}
goal_default:
device_address: null
function_code: null
register_address: null
value: null
handles: []
result: {}
schema:
description: UniLabJsonCommand build_modbus_frame 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand build_modbus_frame 的参数schema
properties:
device_address:
description: '参数: device_address'
type: integer
function_code:
description: '参数: function_code'
type: integer
register_address:
description: '参数: register_address'
type: integer
value:
description: '参数: value'
type: integer
required:
- device_address
- function_code
- register_address
- value
type: object
result: {}
required:
- goal
title: build_modbus_frame 命令参数
type: object
type: UniLabJsonCommand
auto-convert_temperature_to_modbus_value:
feedback: {}
goal: {}
goal_default:
decimal_points: 1
temperature: null
handles: []
result: {}
schema:
description: UniLabJsonCommand convert_temperature_to_modbus_value 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand convert_temperature_to_modbus_value 的参数schema
properties:
decimal_points:
default: 1
description: '参数: decimal_points'
type: integer
temperature:
description: '参数: temperature'
type: number
required:
- temperature
type: object
result: {}
required:
- goal
title: convert_temperature_to_modbus_value 命令参数
type: object
type: UniLabJsonCommand
auto-modbus_crc:
feedback: {}
goal: {}
goal_default:
data: null
handles: []
result: {}
schema:
description: UniLabJsonCommand modbus_crc 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand modbus_crc 的参数schema
properties:
data:
description: '参数: data'
type: string
required:
- data
type: object
result: {}
required:
- goal
title: modbus_crc 命令参数
type: object
type: UniLabJsonCommand
auto-set_temperature:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_temperature 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_temperature 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: set_temperature 命令参数
type: object
type: UniLabJsonCommand
auto-stop:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand stop 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand stop 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: stop 命令参数
type: object
type: UniLabJsonCommand
set_temperature:
feedback: {}
goal:
command: command
goal_default:
command: ''
handles: []
result: result:
success: success success: success
set_temp_target: schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd type: SendCmd
goal: module: unilabos.devices.temperature.chiller:Chiller
command: temp status_types: {}
type: python
description: Chiller
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
port:
description: '参数: port'
type: string
rate:
default: 9600
description: '参数: rate'
type: integer
required:
- port
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
heaterstirrer.dalong:
class:
action_value_mappings:
auto-close:
feedback: {} feedback: {}
result: goal: {}
success: success goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand close 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand close 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: close 命令参数
type: object
type: UniLabJsonCommand
auto-get_status:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_status 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_status 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_status 命令参数
type: object
type: UniLabJsonCommand
auto-get_temp:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_temp 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_temp 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_temp 命令参数
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: UniLabJsonCommand heatchill 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand heatchill 的参数schema
properties:
purpose:
default: reaction
description: '参数: purpose'
type: string
stir:
default: true
description: '参数: stir'
type: boolean
stir_speed:
default: 300
description: '参数: stir_speed'
type: number
temp:
description: '参数: temp'
type: number
time:
default: 3600
description: '参数: time'
type: number
vessel:
description: '参数: vessel'
type: string
required:
- vessel
- temp
type: object
result: {}
required:
- goal
title: heatchill 命令参数
type: object
type: UniLabJsonCommand
auto-set_stir_speed:
feedback: {}
goal: {}
goal_default:
speed: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_stir_speed 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_stir_speed 的参数schema
properties:
speed:
description: '参数: speed'
type: number
required:
- speed
type: object
result: {}
required:
- goal
title: set_stir_speed 命令参数
type: object
type: UniLabJsonCommand
auto-set_temp_inner:
feedback: {}
goal: {}
goal_default:
temp: null
type: warning
handles: []
result: {}
schema:
description: UniLabJsonCommand set_temp_inner 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_temp_inner 的参数schema
properties:
temp:
description: '参数: temp'
type: number
type:
default: warning
description: '参数: type'
type: string
required:
- temp
type: object
result: {}
required:
- goal
title: set_temp_inner 命令参数
type: object
type: UniLabJsonCommand
auto-set_temp_target:
feedback: {}
goal: {}
goal_default:
temp: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_temp_target 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_temp_target 的参数schema
properties:
temp:
description: '参数: 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: UniLabJsonCommand set_temp_warning 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_temp_warning 的参数schema
properties:
temp:
description: '参数: temp'
type: string
required:
- temp
type: object
result: {}
required:
- goal
title: set_temp_warning 命令参数
type: object
type: UniLabJsonCommand
heatchill: heatchill:
type: HeatChill
goal:
vessel: vessel
temp: temp
time: time
purpose: purpose
feedback: feedback:
status: status status: status
result:
success: success
chiller:
description: Chiller
class:
module: unilabos.devices.temperature.chiller:Chiller
type: python
action_value_mappings:
set_temperature:
type: SendCmd
goal: goal:
command: command purpose: purpose
feedback: {} temp: temp
time: time
vessel: vessel
goal_default:
purpose: ''
stir: false
stir_speed: 0.0
temp: 0.0
time: 0.0
vessel: ''
handles: []
result: result:
success: success success: success
tempsensor: schema:
description: Temperature sensor description: ROS Action HeatChill 的 JSON Schema
class: properties:
module: unilabos.devices.temperature.sensor_node:TempSensorNode feedback:
type: python description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: HeatChill_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
purpose:
type: string
stir:
type: boolean
stir_speed:
type: number
temp:
type: number
time:
type: number
vessel:
type: string
required:
- vessel
- temp
- time
- stir
- stir_speed
- purpose
title: HeatChill_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: HeatChill_Result
type: object
required:
- goal
title: HeatChill
type: object
type: HeatChill
set_temp_target:
feedback: {}
goal:
command: temp
goal_default:
command: ''
handles: []
result:
success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
set_temp_warning:
feedback: {}
goal:
command: temp
goal_default:
command: ''
handles: []
result:
success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.heaterstirrer.dalong:HeaterStirrer_DaLong
status_types: status_types:
value: Float64 status: str
warning: Float64 stir_speed: float
temp: float
temp_target: float
temp_warning: float
type: python
description: DaLong heater stirrer
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
baudrate:
default: 9600
description: '参数: baudrate'
type: integer
port:
default: COM6
description: '参数: port'
type: string
temp_warning:
default: 50.0
description: '参数: temp_warning'
type: number
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object
tempsensor:
class:
action_value_mappings: action_value_mappings:
auto-build_modbus_request:
feedback: {}
goal: {}
goal_default:
device_id: null
function_code: null
register_address: null
register_count: null
handles: []
result: {}
schema:
description: UniLabJsonCommand build_modbus_request 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand build_modbus_request 的参数schema
properties:
device_id:
description: '参数: device_id'
type: string
function_code:
description: '参数: function_code'
type: string
register_address:
description: '参数: register_address'
type: string
register_count:
description: '参数: register_count'
type: string
required:
- device_id
- function_code
- register_address
- register_count
type: object
result: {}
required:
- goal
title: build_modbus_request 命令参数
type: object
type: UniLabJsonCommand
auto-calculate_crc:
feedback: {}
goal: {}
goal_default:
data: null
handles: []
result: {}
schema:
description: UniLabJsonCommand calculate_crc 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand calculate_crc 的参数schema
properties:
data:
description: '参数: data'
type: string
required:
- data
type: object
result: {}
required:
- goal
title: calculate_crc 命令参数
type: object
type: UniLabJsonCommand
auto-read_modbus_response:
feedback: {}
goal: {}
goal_default:
response: null
handles: []
result: {}
schema:
description: UniLabJsonCommand read_modbus_response 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand read_modbus_response 的参数schema
properties:
response:
description: '参数: response'
type: string
required:
- response
type: object
result: {}
required:
- goal
title: read_modbus_response 命令参数
type: object
type: UniLabJsonCommand
auto-send_prototype_command:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand send_prototype_command 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand send_prototype_command 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: send_prototype_command 命令参数
type: object
type: UniLabJsonCommand
auto-set_warning:
feedback: {}
goal: {}
goal_default:
command: null
handles: []
result: {}
schema:
description: UniLabJsonCommand set_warning 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_warning 的参数schema
properties:
command:
description: '参数: command'
type: string
required:
- command
type: object
result: {}
required:
- goal
title: set_warning 命令参数
type: object
type: UniLabJsonCommand
set_warning: set_warning:
type: SendCmd feedback: {}
goal: goal:
command: command command: command
feedback: {} goal_default:
command: ''
handles: []
result: result:
success: success success: success
schema:
description: ROS Action SendCmd 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties:
status:
type: string
required:
- status
title: SendCmd_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
command:
type: string
required:
- command
title: SendCmd_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: SendCmd_Result
type: object
required:
- goal
title: SendCmd
type: object
type: SendCmd
module: unilabos.devices.temperature.sensor_node:TempSensorNode
status_types:
value: float
warning: Float64
type: python
description: Temperature sensor
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
address:
description: '参数: address'
type: string
baudrate:
default: 9600
description: '参数: baudrate'
type: integer
port:
description: '参数: port'
type: string
warning:
description: '参数: warning'
type: string
required:
- port
- warning
- address
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,81 +1,556 @@
vacuum_pump.mock:
description: Mock vacuum pump
class:
module: unilabos.devices.pump_and_valve.vacuum_pump_mock:VacuumPumpMock
type: python
status_types:
status: String
action_value_mappings:
open:
type: EmptyIn
goal: {}
feedback: {}
result: {}
close:
type: EmptyIn
goal: {}
feedback: {}
result: {}
set_status:
type: StrSingleInput
goal:
string: string
feedback: {}
result: {}
handles:
- handler_key: out
label: out
data_type: fluid
io_type: source
data_source: handle
data_key: fluid_in
init_param_schema:
type: object
properties:
port:
type: string
description: "通信端口"
default: "COM6"
required:
- port
gas_source.mock: gas_source.mock:
description: Mock gas source
class: class:
module: unilabos.devices.pump_and_valve.vacuum_pump_mock:VacuumPumpMock
type: python
status_types:
status: String
action_value_mappings: action_value_mappings:
open: auto-close:
type: EmptyIn
goal: {}
feedback: {} feedback: {}
goal: {}
goal_default: {}
handles: []
result: {} result: {}
schema:
description: UniLabJsonCommand close 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand close 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: close 命令参数
type: object
type: UniLabJsonCommand
auto-get_status:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_status 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_status 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_status 命令参数
type: object
type: UniLabJsonCommand
auto-is_closed:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand is_closed 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand is_closed 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: is_closed 命令参数
type: object
type: UniLabJsonCommand
auto-is_open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand is_open 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand is_open 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: is_open 命令参数
type: object
type: UniLabJsonCommand
auto-open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand open 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand open 的参数schema
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: UniLabJsonCommand set_status 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_status 的参数schema
properties:
string:
description: '参数: string'
type: string
required:
- string
type: object
result: {}
required:
- goal
title: set_status 命令参数
type: object
type: UniLabJsonCommand
close: close:
type: EmptyIn
goal: {}
feedback: {} feedback: {}
goal: {}
goal_default: {}
handles: []
result: {} result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
set_status: set_status:
type: StrSingleInput feedback: {}
goal: goal:
string: string string: string
feedback: {} goal_default:
string: ''
handles: []
result: {} result: {}
schema:
description: ROS Action StrSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: StrSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
string:
type: string
required:
- string
title: StrSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: StrSingleInput_Result
type: object
required:
- goal
title: StrSingleInput
type: object
type: StrSingleInput
module: unilabos.devices.pump_and_valve.vacuum_pump_mock:VacuumPumpMock
status_types:
status: str
type: python
description: Mock gas source
handles: handles:
- handler_key: out - data_key: fluid_out
label: out data_source: executor
data_type: fluid data_type: fluid
io_type: source handler_key: out
data_source: executor io_type: source
data_key: fluid_out label: out
icon: ''
init_param_schema: init_param_schema:
type: object description: UniLabJsonCommand __init__ 的参数schema
properties: properties:
port: feedback: {}
type: string goal:
description: "通信端口" description: UniLabJsonCommand __init__ 的参数schema
default: "COM6" properties:
port:
default: COM6
description: '参数: port'
type: string
required: []
type: object
result: {}
required: required:
- port - goal
title: __init__ 命令参数
type: object
vacuum_pump.mock:
class:
action_value_mappings:
auto-close:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand close 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand close 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: close 命令参数
type: object
type: UniLabJsonCommand
auto-get_status:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_status 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_status 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_status 命令参数
type: object
type: UniLabJsonCommand
auto-is_closed:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand is_closed 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand is_closed 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: is_closed 命令参数
type: object
type: UniLabJsonCommand
auto-is_open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand is_open 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand is_open 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: is_open 命令参数
type: object
type: UniLabJsonCommand
auto-open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand open 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand open 的参数schema
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: UniLabJsonCommand set_status 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand set_status 的参数schema
properties:
string:
description: '参数: string'
type: string
required:
- string
type: object
result: {}
required:
- goal
title: set_status 命令参数
type: object
type: UniLabJsonCommand
close:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
open:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
set_status:
feedback: {}
goal:
string: string
goal_default:
string: ''
handles: []
result: {}
schema:
description: ROS Action StrSingleInput 的 JSON Schema
properties:
feedback:
description: Action 反馈 - 执行过程中从服务器发送到客户端
properties: {}
required: []
title: StrSingleInput_Feedback
type: object
goal:
description: Action 目标 - 从客户端发送到服务器
properties:
string:
type: string
required:
- string
title: StrSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: StrSingleInput_Result
type: object
required:
- goal
title: StrSingleInput
type: object
type: StrSingleInput
module: unilabos.devices.pump_and_valve.vacuum_pump_mock:VacuumPumpMock
status_types:
status: str
type: python
description: Mock vacuum pump
handles:
- data_key: fluid_in
data_source: handle
data_type: fluid
handler_key: out
io_type: source
label: out
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
port:
default: COM6
description: '参数: port'
type: string
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,259 @@
zhida_hplc: zhida_hplc:
description: Zhida HPLC
class: class:
module: unilabos.devices.zhida_hplc.zhida:ZhidaClient
type: python
status_types:
status: String
action_value_mappings: action_value_mappings:
abort:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
auto-abort:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand abort 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand abort 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: abort 命令参数
type: object
type: UniLabJsonCommand
auto-close:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand close 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand close 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: close 命令参数
type: object
type: UniLabJsonCommand
auto-connect:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand connect 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand connect 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: connect 命令参数
type: object
type: UniLabJsonCommand
auto-get_methods:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: UniLabJsonCommand get_methods 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand get_methods 的参数schema
properties: {}
required: []
type: object
result: {}
required:
- goal
title: get_methods 命令参数
type: object
type: UniLabJsonCommand
auto-start:
feedback: {}
goal: {}
goal_default:
text: null
handles: []
result: {}
schema:
description: UniLabJsonCommand start 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand start 的参数schema
properties:
text:
description: '参数: text'
type: string
required:
- text
type: object
result: {}
required:
- goal
title: start 命令参数
type: object
type: UniLabJsonCommand
get_methods:
feedback: {}
goal: {}
goal_default: {}
handles: []
result: {}
schema:
description: ROS Action EmptyIn 的 JSON Schema
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
required:
- return_info
title: EmptyIn_Result
type: object
required:
- goal
title: EmptyIn
type: object
type: EmptyIn
start: start:
type: StrSingleInput feedback: {}
goal: goal:
string: string string: string
feedback: {} goal_default:
string: ''
handles: []
result: {} result: {}
abort: schema:
type: EmptyIn description: ROS Action StrSingleInput 的 JSON Schema
goal: {} properties:
feedback: {} feedback:
result: {} description: Action 反馈 - 执行过程中从服务器发送到客户端
get_methods: properties: {}
type: EmptyIn required: []
goal: {} title: StrSingleInput_Feedback
feedback: {} type: object
result: {} goal:
description: Action 目标 - 从客户端发送到服务器
schema: properties:
properties: {} string:
type: string
required:
- string
title: StrSingleInput_Goal
type: object
result:
description: Action 结果 - 完成后从服务器发送到客户端
properties:
return_info:
type: string
success:
type: boolean
required:
- return_info
- success
title: StrSingleInput_Result
type: object
required:
- goal
title: StrSingleInput
type: object
type: StrSingleInput
module: unilabos.devices.zhida_hplc.zhida:ZhidaClient
status_types:
status: dict
type: python
description: Zhida HPLC
handles: []
icon: ''
init_param_schema:
description: UniLabJsonCommand __init__ 的参数schema
properties:
feedback: {}
goal:
description: UniLabJsonCommand __init__ 的参数schema
properties:
host:
default: 192.168.1.47
description: '参数: host'
type: string
port:
default: 5792
description: '参数: port'
type: integer
timeout:
default: 10.0
description: '参数: timeout'
type: number
required: []
type: object
result: {}
required:
- goal
title: __init__ 命令参数
type: object

View File

@@ -1,14 +1,17 @@
import copy
import io import io
import os import os
import sys import sys
from pathlib import Path from pathlib import Path
from typing import Any from typing import Any, Dict, List
import yaml import yaml
from unilabos.ros.msgs.message_converter import msg_converter_manager, ros_action_to_json_schema from unilabos.ros.msgs.message_converter import msg_converter_manager, ros_action_to_json_schema
from unilabos.utils import logger from unilabos.utils import logger
from unilabos.utils.decorator import singleton from unilabos.utils.decorator import singleton
from unilabos.utils.import_manager import get_enhanced_class_info
from unilabos.utils.type_check import NoAliasDumper
DEFAULT_PATHS = [Path(__file__).absolute().parent] DEFAULT_PATHS = [Path(__file__).absolute().parent]
@@ -32,7 +35,7 @@ class Registry:
# 其他状态变量 # 其他状态变量
# self.is_host_mode = False # 移至BasicConfig中 # self.is_host_mode = False # 移至BasicConfig中
def setup(self): def setup(self, complete_registry=False):
# 检查是否已调用过setup # 检查是否已调用过setup
if self._setup_called: if self._setup_called:
logger.critical("[UniLab Registry] setup方法已被调用过不允许多次调用") logger.critical("[UniLab Registry] setup方法已被调用过不允许多次调用")
@@ -86,13 +89,15 @@ class Registry:
io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuterEasy.Goal)) io.StringIO(get_yaml_from_goal_type(self.ResourceCreateFromOuterEasy.Goal))
), ),
"handles": { "handles": {
"output": [{ "output": [
"handler_key": "labware", {
"label": "Labware", "handler_key": "labware",
"data_type": "resource", "label": "Labware",
"data_source": "handle", "data_type": "resource",
"data_key": "liquid" "data_source": "handle",
}] "data_key": "liquid",
}
]
}, },
}, },
"test_latency": { "test_latency": {
@@ -110,7 +115,6 @@ class Registry:
"registry_type": "device", "registry_type": "device",
"handles": [], "handles": [],
"init_param_schema": {}, "init_param_schema": {},
"schema": {"properties": {}, "additionalProperties": False, "type": "object"},
"file_path": "/", "file_path": "/",
} }
} }
@@ -121,13 +125,13 @@ class Registry:
sys_path = path.parent sys_path = path.parent
logger.debug(f"[UniLab Registry] Path {i+1}/{len(self.registry_paths)}: {sys_path}") logger.debug(f"[UniLab Registry] Path {i+1}/{len(self.registry_paths)}: {sys_path}")
sys.path.append(str(sys_path)) sys.path.append(str(sys_path))
self.load_device_types(path) self.load_device_types(path, complete_registry)
self.load_resource_types(path) self.load_resource_types(path, complete_registry)
logger.info("[UniLab Registry] 注册表设置完成") logger.info("[UniLab Registry] 注册表设置完成")
# 标记setup已被调用 # 标记setup已被调用
self._setup_called = True self._setup_called = True
def load_resource_types(self, path: os.PathLike): def load_resource_types(self, path: os.PathLike, complete_registry: bool):
abs_path = Path(path).absolute() abs_path = Path(path).absolute()
resource_path = abs_path / "resources" resource_path = abs_path / "resources"
files = list(resource_path.glob("*/*.yaml")) files = list(resource_path.glob("*/*.yaml"))
@@ -176,7 +180,7 @@ class Registry:
if not type_name or type_name == "": if not type_name or type_name == "":
logger.warning(f"[UniLab Registry] 设备 {device_id}{field_name} 类型为空,跳过替换") logger.warning(f"[UniLab Registry] 设备 {device_id}{field_name} 类型为空,跳过替换")
return type_name return type_name
if "." in type_name: if ":" in type_name:
type_class = msg_converter_manager.get_class(type_name) type_class = msg_converter_manager.get_class(type_name)
else: else:
type_class = msg_converter_manager.search_class(type_name) type_class = msg_converter_manager.search_class(type_name)
@@ -186,7 +190,72 @@ class Registry:
logger.error(f"[UniLab Registry] 无法找到类型 '{type_name}' 用于设备 {device_id}{field_name}") logger.error(f"[UniLab Registry] 无法找到类型 '{type_name}' 用于设备 {device_id}{field_name}")
sys.exit(1) sys.exit(1)
def load_device_types(self, path: os.PathLike): def _generate_unilab_json_command_schema(self, method_args: List[Dict[str, Any]], method_name: str) -> Dict[str, Any]:
"""
根据UniLabJsonCommand方法信息生成JSON Schema暂不支持嵌套类型
Args:
method_args: 方法信息字典包含args等
method_name: 方法名称
Returns:
JSON Schema格式的参数schema
"""
schema = {
"description": f"UniLabJsonCommand {method_name} 的参数schema",
"type": "object",
"properties": {},
"required": [],
}
for arg_info in method_args:
param_name = arg_info.get("name", "")
param_type = arg_info.get("type")
param_default = arg_info.get("default")
param_required = arg_info.get("required", True)
prop_schema = {"description": f"参数: {param_name}"}
# 根据类型设置schema FIXME 不完整
if param_type:
param_type_lower = param_type.lower()
if param_type_lower in ["str", "string"]:
prop_schema["type"] = "string"
elif param_type_lower in ["int", "integer"]:
prop_schema["type"] = "integer"
elif param_type_lower in ["float", "number"]:
prop_schema["type"] = "number"
elif param_type_lower in ["bool", "boolean"]:
prop_schema["type"] = "boolean"
elif param_type_lower in ["list", "array"]:
prop_schema["type"] = "array"
elif param_type_lower in ["dict", "object"]:
prop_schema["type"] = "object"
else:
# 默认为字符串类型
prop_schema["type"] = "string"
else:
# 如果没有类型信息,默认为字符串
prop_schema["type"] = "string"
# 设置默认值
if param_default is not None:
prop_schema["default"] = param_default
schema["properties"][param_name] = prop_schema
# 如果是必需参数添加到required列表
if param_required:
schema["required"].append(param_name)
return {
"title": f"{method_name} 命令参数",
"description": f"UniLabJsonCommand {method_name} 的参数schema",
"type": "object",
"properties": {"goal": schema, "feedback": {}, "result": {}},
"required": ["goal"],
}
def load_device_types(self, path: os.PathLike, complete_registry: bool):
abs_path = Path(path).absolute() abs_path = Path(path).absolute()
devices_path = abs_path / "devices" devices_path = abs_path / "devices"
device_comms_path = abs_path / "device_comms" device_comms_path = abs_path / "device_comms"
@@ -199,12 +268,18 @@ class Registry:
from unilabos.app.web.utils.action_utils import get_yaml_from_goal_type from unilabos.app.web.utils.action_utils import get_yaml_from_goal_type
for i, file in enumerate(files): for i, file in enumerate(files):
data = yaml.safe_load(open(file, encoding="utf-8")) with open(file, encoding="utf-8", mode="r") as f:
data = yaml.safe_load(io.StringIO(f.read()))
complete_data = {}
action_str_type_mapping = {
"UniLabJsonCommand": "UniLabJsonCommand",
"UniLabJsonCommandAsync": "UniLabJsonCommandAsync",
}
status_str_type_mapping = {}
if data: if data:
# 在添加到注册表前处理类型替换 # 在添加到注册表前处理类型替换
for device_id, device_config in data.items(): for device_id, device_config in data.items():
# 添加文件路径信息 - 使用规范化的完整文件路径 # 添加文件路径信息 - 使用规范化的完整文件路径
device_config["file_path"] = str(file.absolute()).replace("\\", "/")
if "description" not in device_config: if "description" not in device_config:
device_config["description"] = "" device_config["description"] = ""
if "icon" not in device_config: if "icon" not in device_config:
@@ -213,42 +288,108 @@ class Registry:
device_config["handles"] = [] device_config["handles"] = []
if "init_param_schema" not in device_config: if "init_param_schema" not in device_config:
device_config["init_param_schema"] = {} device_config["init_param_schema"] = {}
device_config["registry_type"] = "device"
if "class" in device_config: if "class" in device_config:
# 处理状态类型 if "status_types" not in device_config["class"]:
if "status_types" in device_config["class"]: device_config["class"]["status_types"] = {}
for status_name, status_type in device_config["class"]["status_types"].items(): if "action_value_mappings" not in device_config["class"]:
device_config["class"]["status_types"][status_name] = self._replace_type_with_class( device_config["class"]["action_value_mappings"] = {}
status_type, device_id, f"状态 {status_name}" enhanced_info = {}
) if complete_registry:
enhanced_info = get_enhanced_class_info(device_config["class"]["module"], use_dynamic=True)
device_config["class"]["status_types"].update(
{k: v["return_type"] for k, v in enhanced_info["status_methods"].items()}
)
for status_name, status_type in device_config["class"]["status_types"].items():
if status_type in ["Any", "None"]:
status_type = "String" # 替换成ROS的String便于显示
target_type = self._replace_type_with_class(status_type, device_id, f"状态 {status_name}")
status_str_type_mapping[status_type] = target_type
device_config["class"]["status_types"] = dict(
sorted(device_config["class"]["status_types"].items())
)
# 处理动作值映射 # 处理动作值映射
if "action_value_mappings" in device_config["class"]: device_config["class"]["action_value_mappings"].update(
for action_name, action_config in device_config["class"]["action_value_mappings"].items(): {
if "handles" not in action_config: f"auto-{k}": {
action_config["handles"] = [] "type": "UniLabJsonCommandAsync" if v["is_async"] else "UniLabJsonCommand",
if "type" in action_config: "goal": {},
action_config["type"] = self._replace_type_with_class( "feedback": {},
action_config["type"], device_id, f"动作 {action_name}" "result": {},
"schema": self._generate_unilab_json_command_schema(v["args"], k),
"goal_default": {i["name"]: i["default"] for i in v["args"]},
"handles": [],
}
for k, v in enhanced_info["action_methods"].items()
}
)
device_config["init_param_schema"] = self._generate_unilab_json_command_schema(enhanced_info["init_params"], "__init__")
device_config.pop("schema", None)
device_config["class"]["action_value_mappings"] = dict(
sorted(device_config["class"]["action_value_mappings"].items())
)
for action_name, action_config in device_config["class"]["action_value_mappings"].items():
if "handles" not in action_config:
action_config["handles"] = []
if "type" in action_config:
action_type_str: str = action_config["type"]
# 通过Json发放指令而不是通过特殊的ros action进行处理
if not action_type_str.startswith("UniLabJsonCommand"):
target_type = self._replace_type_with_class(
action_type_str, device_id, f"动作 {action_name}"
) )
if action_config["type"] is not None: action_str_type_mapping[action_type_str] = target_type
if target_type is not None:
action_config["goal_default"] = yaml.safe_load( action_config["goal_default"] = yaml.safe_load(
io.StringIO(get_yaml_from_goal_type(action_config["type"].Goal)) io.StringIO(get_yaml_from_goal_type(target_type.Goal))
) )
action_config["schema"] = ros_action_to_json_schema(action_config["type"]) action_config["schema"] = ros_action_to_json_schema(target_type)
else: else:
logger.warning( logger.warning(
f"[UniLab Registry] 设备 {device_id} 的动作 {action_name} 类型为空,跳过替换" f"[UniLab Registry] 设备 {device_id} 的动作 {action_name} 类型为空,跳过替换"
) )
complete_data[device_id] = copy.deepcopy(dict(sorted(device_config.items()))) # 稍后dump到文件
self.device_type_registry.update(data) for status_name, status_type in device_config["class"]["status_types"].items():
device_config["class"]["status_types"][status_name] = status_str_type_mapping[status_type]
for device_id in data.keys(): for action_name, action_config in device_config["class"]["action_value_mappings"].items():
action_config["type"] = action_str_type_mapping[action_config["type"]]
for additional_action in ["_execute_driver_command", "_execute_driver_command_async"]:
device_config["class"]["action_value_mappings"][additional_action] = {
"type": self._replace_type_with_class(
"StrSingleInput", device_id, f"动作 {additional_action}"
),
"goal": {"string": "string"},
"feedback": {},
"result": {},
"schema": ros_action_to_json_schema(
self._replace_type_with_class(
"StrSingleInput", device_id, f"动作 {additional_action}"
)
),
"goal_default": yaml.safe_load(
io.StringIO(
get_yaml_from_goal_type(
self._replace_type_with_class(
"StrSingleInput", device_id, f"动作 {additional_action}"
).Goal
)
)
),
"handles": [],
}
if "registry_type" not in device_config:
device_config["registry_type"] = "device"
device_config["file_path"] = str(file.absolute()).replace("\\", "/")
device_config["registry_type"] = "device"
logger.debug( logger.debug(
f"[UniLab Registry] Device-{current_device_number} File-{i+1}/{len(files)} Add {device_id} " f"[UniLab Registry] Device-{current_device_number} File-{i+1}/{len(files)} Add {device_id} "
+ f"[{data[device_id].get('name', '未命名设备')}]" + f"[{data[device_id].get('name', '未命名设备')}]"
) )
current_device_number += 1 current_device_number += 1
complete_data = dict(sorted(complete_data.items()))
complete_data = copy.deepcopy(complete_data)
with open(file, "w", encoding="utf-8") as f:
yaml.dump(complete_data, f, allow_unicode=True, default_flow_style=False, Dumper=NoAliasDumper)
self.device_type_registry.update(data)
else: else:
logger.debug( logger.debug(
f"[UniLab Registry] Device File-{i+1}/{len(files)} Not Valid YAML File: {file.absolute()}" f"[UniLab Registry] Device File-{i+1}/{len(files)} Not Valid YAML File: {file.absolute()}"
@@ -273,7 +414,7 @@ class Registry:
lab_registry = Registry() lab_registry = Registry()
def build_registry(registry_paths=None): def build_registry(registry_paths=None, complete_registry=False):
""" """
构建或获取Registry单例实例 构建或获取Registry单例实例
@@ -297,6 +438,6 @@ def build_registry(registry_paths=None):
lab_registry.registry_paths.append(path) lab_registry.registry_paths.append(path)
# 初始化注册表 # 初始化注册表
lab_registry.setup() lab_registry.setup(complete_registry)
return lab_registry return lab_registry

View File

@@ -55,7 +55,7 @@ def ros2_device_node(
"read": "read_data", "read": "read_data",
"extra_info": [], "extra_info": [],
} }
# FIXME 后面要删除
for k, v in cls.__dict__.items(): for k, v in cls.__dict__.items():
if not k.startswith("_") and isinstance(v, property): if not k.startswith("_") and isinstance(v, property):
# noinspection PyUnresolvedReferences # noinspection PyUnresolvedReferences

View File

@@ -727,7 +727,6 @@ def ros_action_to_json_schema(action_class: Any) -> Dict[str, Any]:
# 创建基础 schema # 创建基础 schema
schema = { schema = {
'$schema': 'http://json-schema.org/draft-07/schema#',
'title': action_class.__name__, 'title': action_class.__name__,
'description': f"ROS Action {action_class.__name__} 的 JSON Schema", 'description': f"ROS Action {action_class.__name__} 的 JSON Schema",
'type': 'object', 'type': 'object',

View File

@@ -1,4 +1,5 @@
import copy import copy
import io
import json import json
import threading import threading
import time import time
@@ -10,6 +11,7 @@ from concurrent.futures import ThreadPoolExecutor
import asyncio import asyncio
import rclpy import rclpy
import yaml
from rclpy.node import Node from rclpy.node import Node
from rclpy.action import ActionServer, ActionClient from rclpy.action import ActionServer, ActionClient
from rclpy.action.server import ServerGoalHandle from rclpy.action.server import ServerGoalHandle
@@ -302,6 +304,8 @@ class BaseROS2DeviceNode(Node, Generic[T]):
# 创建动作服务 # 创建动作服务
if self.create_action_server: if self.create_action_server:
for action_name, action_value_mapping in self._action_value_mappings.items(): for action_name, action_value_mapping in self._action_value_mappings.items():
if action_name.startswith("auto-"):
continue
self.create_ros_action_server(action_name, action_value_mapping) self.create_ros_action_server(action_name, action_value_mapping)
# 创建线程池执行器 # 创建线程池执行器
@@ -838,6 +842,8 @@ class BaseROS2DeviceNode(Node, Generic[T]):
class DeviceInitError(Exception): class DeviceInitError(Exception):
pass pass
class JsonCommandInitError(Exception):
pass
class ROS2DeviceNode: class ROS2DeviceNode:
""" """
@@ -954,12 +960,51 @@ class ROS2DeviceNode:
self._ros_node: BaseROS2DeviceNode self._ros_node: BaseROS2DeviceNode
self._ros_node.lab_logger().info(f"初始化完成 {self._ros_node.uuid} {self.driver_is_ros}") self._ros_node.lab_logger().info(f"初始化完成 {self._ros_node.uuid} {self.driver_is_ros}")
self.driver_instance._ros_node = self._ros_node # type: ignore self.driver_instance._ros_node = self._ros_node # type: ignore
self.driver_instance._execute_driver_command = self._execute_driver_command # type: ignore
self.driver_instance._execute_driver_command_async = self._execute_driver_command_async # type: ignore
if hasattr(self.driver_instance, "post_init"): if hasattr(self.driver_instance, "post_init"):
try: try:
self.driver_instance.post_init(self._ros_node) # type: ignore self.driver_instance.post_init(self._ros_node) # type: ignore
except Exception as e: except Exception as e:
self._ros_node.lab_logger().error(f"设备后初始化失败: {e}") self._ros_node.lab_logger().error(f"设备后初始化失败: {e}")
def _execute_driver_command(self, string: str):
try:
target = json.loads(string)
except Exception as ex:
try:
target = yaml.safe_load(io.StringIO(string))
except Exception as ex2:
raise JsonCommandInitError(f"执行动作时JSON/YAML解析失败: \n{ex}\n{ex2}\n原内容: {string}\n{traceback.format_exc()}")
try:
function_name = target["function_name"]
function_args = target["function_args"]
assert isinstance(function_args, dict), "执行动作时JSON必须为dict类型\n原JSON: {string}"
function = getattr(self.driver_instance, function_name)
assert callable(function), f"执行动作时JSON中的function_name对应的函数不可调用: {function_name}\n原JSON: {string}"
return function(**function_args)
except KeyError as ex:
raise JsonCommandInitError(f"执行动作时JSON缺少function_name或function_args: {ex}\n原JSON: {string}\n{traceback.format_exc()}")
async def _execute_driver_command_async(self, string: str):
try:
target = json.loads(string)
except Exception as ex:
try:
target = yaml.safe_load(io.StringIO(string))
except Exception as ex2:
raise JsonCommandInitError(f"执行动作时JSON/YAML解析失败: \n{ex}\n{ex2}\n原内容: {string}\n{traceback.format_exc()}")
try:
function_name = target["function_name"]
function_args = target["function_args"]
assert isinstance(function_args, dict), "执行动作时JSON必须为dict类型\n原JSON: {string}"
function = getattr(self.driver_instance, function_name)
assert callable(function), f"执行动作时JSON中的function_name对应的函数不可调用: {function_name}\n原JSON: {string}"
assert asyncio.iscoroutinefunction(function), f"执行动作时JSON中的function并非异步: {function_name}\n原JSON: {string}"
return await function(**function_args)
except KeyError as ex:
raise JsonCommandInitError(f"执行动作时JSON缺少function_name或function_args: {ex}\n原JSON: {string}\n{traceback.format_exc()}")
def _start_loop(self): def _start_loop(self):
def run_event_loop(): def run_event_loop():
loop = asyncio.new_event_loop() loop = asyncio.new_event_loop()

View File

@@ -567,6 +567,7 @@ class HostNode(BaseROS2DeviceNode):
def send_goal( def send_goal(
self, self,
device_id: str, device_id: str,
action_type: str,
action_name: str, action_name: str,
action_kwargs: Dict[str, Any], action_kwargs: Dict[str, Any],
goal_uuid: Optional[str] = None, goal_uuid: Optional[str] = None,
@@ -577,11 +578,26 @@ class HostNode(BaseROS2DeviceNode):
Args: Args:
device_id: 设备ID device_id: 设备ID
action_type: 动作类型
action_name: 动作名称 action_name: 动作名称
action_kwargs: 动作参数 action_kwargs: 动作参数
goal_uuid: 目标UUID如果为None则自动生成 goal_uuid: 目标UUID如果为None则自动生成
server_info: 服务器发送信息,包含发送时间戳等
""" """
action_id = f"/devices/{device_id}/{action_name}" if action_type.startswith("UniLabJsonCommand"):
if action_name.startswith("auto-"):
action_name = action_name[5:]
action_id = f"/devices/{device_id}/_execute_driver_command"
action_kwargs = {
"string": json.dumps({
"function_name": action_name,
"function_args": action_kwargs,
})
}
if action_type.startswith("UniLabJsonCommandAsync"):
action_id = f"/devices/{device_id}/_execute_driver_command_async"
else:
action_id = f"/devices/{device_id}/{action_name}"
if action_name == "test_latency" and server_info is not None: if action_name == "test_latency" and server_info is not None:
self.server_latest_timestamp = server_info.get("send_timestamp", 0.0) self.server_latest_timestamp = server_info.get("send_timestamp", 0.0)
if action_id not in self._action_clients: if action_id not in self._action_clients:

View File

@@ -1,7 +1,5 @@
import time import time
import asyncio
import traceback import traceback
from types import MethodType
from typing import Union from typing import Union
import rclpy import rclpy
@@ -22,6 +20,8 @@ from unilabos.ros.msgs.message_converter import (
convert_from_ros_msg_with_mapping, convert_from_ros_msg_with_mapping,
) )
from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode, DeviceNodeResourceTracker, ROS2DeviceNode from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode, DeviceNodeResourceTracker, ROS2DeviceNode
from unilabos.utils.log import error
from unilabos.utils.type_check import serialize_result_info
class ROS2ProtocolNode(BaseROS2DeviceNode): class ROS2ProtocolNode(BaseROS2DeviceNode):
@@ -33,7 +33,15 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
# create_action_server = False # Action Server要自己创建 # create_action_server = False # Action Server要自己创建
def __init__(self, device_id: str, children: dict, protocol_type: Union[str, list[str]], resource_tracker: DeviceNodeResourceTracker, *args, **kwargs): def __init__(
self,
device_id: str,
children: dict,
protocol_type: Union[str, list[str]],
resource_tracker: DeviceNodeResourceTracker,
*args,
**kwargs,
):
self._setup_protocol_names(protocol_type) self._setup_protocol_names(protocol_type)
# 初始化其它属性 # 初始化其它属性
@@ -60,7 +68,9 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
for device_id, device_config in self.children.items(): for device_id, device_config in self.children.items():
if device_config.get("type", "device") != "device": if device_config.get("type", "device") != "device":
self.lab_logger().debug(f"[Protocol Node] Skipping type {device_config['type']} {device_id} already existed, skipping.") self.lab_logger().debug(
f"[Protocol Node] Skipping type {device_config['type']} {device_id} already existed, skipping."
)
continue continue
try: try:
d = self.initialize_device(device_id, device_config) d = self.initialize_device(device_id, device_config)
@@ -76,22 +86,27 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
# 设置硬件接口代理 # 设置硬件接口代理
if d: if d:
hardware_interface = d.ros_node_instance._hardware_interface
if ( if (
hasattr(d.driver_instance, d.ros_node_instance._hardware_interface["name"]) hasattr(d.driver_instance, hardware_interface["name"])
and hasattr(d.driver_instance, d.ros_node_instance._hardware_interface["write"]) and hasattr(d.driver_instance, hardware_interface["write"])
and (d.ros_node_instance._hardware_interface["read"] is None or hasattr(d.driver_instance, d.ros_node_instance._hardware_interface["read"])) and (hardware_interface["read"] is None or hasattr(d.driver_instance, hardware_interface["read"]))
): ):
name = getattr(d.driver_instance, d.ros_node_instance._hardware_interface["name"]) name = getattr(d.driver_instance, hardware_interface["name"])
read = d.ros_node_instance._hardware_interface.get("read", None) read = hardware_interface.get("read", None)
write = d.ros_node_instance._hardware_interface.get("write", None) write = hardware_interface.get("write", None)
# 如果硬件接口是字符串,通过通信设备提供 # 如果硬件接口是字符串,通过通信设备提供
if isinstance(name, str) and name in self.sub_devices: if isinstance(name, str) and name in self.sub_devices:
communicate_device = self.sub_devices[name] communicate_device = self.sub_devices[name]
communicate_hardware_info = communicate_device.ros_node_instance._hardware_interface communicate_hardware_info = communicate_device.ros_node_instance._hardware_interface
self._setup_hardware_proxy(d, self.sub_devices[name], read, write) self._setup_hardware_proxy(d, self.sub_devices[name], read, write)
self.lab_logger().info(f"\n通信代理:为子设备{device_id}\n 添加了{read}方法(来源:{name} {communicate_hardware_info['write']}) \n 添加了{write}方法(来源:{name} {communicate_hardware_info['read']})") self.lab_logger().info(
f"\n通信代理:为子设备{device_id}\n "
f"添加了{read}方法(来源:{name} {communicate_hardware_info['write']}) \n "
f"添加了{write}方法(来源:{name} {communicate_hardware_info['read']})"
)
def _setup_protocol_names(self, protocol_type): def _setup_protocol_names(self, protocol_type):
# 处理协议类型 # 处理协议类型
@@ -149,63 +164,127 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
def _create_protocol_execute_callback(self, protocol_name, protocol_steps_generator): def _create_protocol_execute_callback(self, protocol_name, protocol_steps_generator):
async def execute_protocol(goal_handle: ServerGoalHandle): async def execute_protocol(goal_handle: ServerGoalHandle):
"""执行完整的工作流""" """执行完整的工作流"""
self.get_logger().info(f'Executing {protocol_name} action...') # 初始化结果信息变量
action_value_mapping = self._action_value_mappings[protocol_name] execution_error = ""
print('+'*30) execution_success = False
print(protocol_steps_generator) protocol_return_value = None
# 从目标消息中提取参数, 并调用Protocol生成器(根据设备连接图)生成action步骤
goal = goal_handle.request
protocol_kwargs = convert_from_ros_msg_with_mapping(goal, action_value_mapping["goal"])
# 向Host查询物料当前状态 try:
for k, v in goal.get_fields_and_field_types().items(): self.get_logger().info(f"Executing {protocol_name} action...")
if v in ["unilabos_msgs/Resource", "sequence<unilabos_msgs/Resource>"]: action_value_mapping = self._action_value_mappings[protocol_name]
r = ResourceGet.Request() print("+" * 30)
r.id = protocol_kwargs[k]["id"] if v == "unilabos_msgs/Resource" else protocol_kwargs[k][0]["id"] print(protocol_steps_generator)
r.with_children = True # 从目标消息中提取参数, 并调用Protocol生成器(根据设备连接图)生成action步骤
response = await self._resource_clients["resource_get"].call_async(r) goal = goal_handle.request
protocol_kwargs[k] = list_to_nested_dict([convert_from_ros_msg(rs) for rs in response.resources]) protocol_kwargs = convert_from_ros_msg_with_mapping(goal, action_value_mapping["goal"])
from unilabos.resources.graphio import physical_setup_graph # 向Host查询物料当前状态
self.get_logger().info(f'Working on physical setup: {physical_setup_graph}') for k, v in goal.get_fields_and_field_types().items():
protocol_steps = protocol_steps_generator(G=physical_setup_graph, **protocol_kwargs) if v in ["unilabos_msgs/Resource", "sequence<unilabos_msgs/Resource>"]:
r = ResourceGet.Request()
resource_id = (
protocol_kwargs[k]["id"] if v == "unilabos_msgs/Resource" else protocol_kwargs[k][0]["id"]
)
r.id = resource_id
r.with_children = True
response = await self._resource_clients["resource_get"].call_async(r)
protocol_kwargs[k] = list_to_nested_dict(
[convert_from_ros_msg(rs) for rs in response.resources]
)
self.get_logger().info(f'Goal received: {protocol_kwargs}, running steps: \n{protocol_steps}') from unilabos.resources.graphio import physical_setup_graph
time_start = time.time() self.lab_logger().info(f"Working on physical setup: {physical_setup_graph}")
time_overall = 100 protocol_steps = protocol_steps_generator(G=physical_setup_graph, **protocol_kwargs)
self._busy = True
# 逐步执行工作流 self.lab_logger().info(f"Goal received: {protocol_kwargs}, running steps: \n{protocol_steps}")
for i, action in enumerate(protocol_steps):
self.get_logger().info(f'Running step {i+1}: {action}')
if type(action) == dict:
# 如果是单个动作,直接执行
if action["action_name"] == "wait":
time.sleep(action["action_kwargs"]["time"])
else:
result = await self.execute_single_action(**action)
elif type(action) == list:
# 如果是并行动作,同时执行
actions = action
futures = [rclpy.get_global_executor().create_task(self.execute_single_action(**a)) for a in actions]
results = [await f for f in futures]
# 向Host更新物料当前状态 time_start = time.time()
for k, v in goal.get_fields_and_field_types().items(): time_overall = 100
if v in ["unilabos_msgs/Resource", "sequence<unilabos_msgs/Resource>"]: self._busy = True
r = ResourceUpdate.Request()
r.resources = [
convert_to_ros_msg(Resource, rs) for rs in nested_dict_to_list(protocol_kwargs[k])
]
response = await self._resource_clients["resource_update"].call_async(r)
goal_handle.succeed() # 逐步执行工作流
step_results = []
for i, action in enumerate(protocol_steps):
self.get_logger().info(f"Running step {i + 1}: {action}")
if isinstance(action, dict):
# 如果是单个动作,直接执行
if action["action_name"] == "wait":
time.sleep(action["action_kwargs"]["time"])
step_results.append({"step": i + 1, "action": "wait", "result": "completed"})
else:
result = await self.execute_single_action(**action)
step_results.append({"step": i + 1, "action": action["action_name"], "result": result})
elif isinstance(action, list):
# 如果是并行动作,同时执行
actions = action
futures = [
rclpy.get_global_executor().create_task(self.execute_single_action(**a)) for a in actions
]
results = [await f for f in futures]
step_results.append(
{
"step": i + 1,
"parallel_actions": [a["action_name"] for a in actions],
"results": results,
}
)
# 向Host更新物料当前状态
for k, v in goal.get_fields_and_field_types().items():
if v in ["unilabos_msgs/Resource", "sequence<unilabos_msgs/Resource>"]:
r = ResourceUpdate.Request()
r.resources = [
convert_to_ros_msg(Resource, rs) for rs in nested_dict_to_list(protocol_kwargs[k])
]
response = await self._resource_clients["resource_update"].call_async(r)
# 设置成功状态和返回值
execution_success = True
protocol_return_value = {
"protocol_name": protocol_name,
"steps_executed": len(protocol_steps),
"step_results": step_results,
"total_time": time.time() - time_start,
}
goal_handle.succeed()
except Exception as e:
# 捕获并记录错误信息
execution_error = traceback.format_exc()
execution_success = False
error(f"协议 {protocol_name} 执行失败")
error(traceback.format_exc())
self.lab_logger().error(f"协议执行出错: {str(e)}")
# 设置动作失败
goal_handle.abort()
finally:
self._busy = False
# 创建结果消息
result = action_value_mapping["type"].Result() result = action_value_mapping["type"].Result()
result.success = True result.success = execution_success
self._busy = False # 获取结果消息类型信息检查是否有return_info字段
result_msg_types = action_value_mapping["type"].Result.get_fields_and_field_types()
# 设置return_info字段如果存在
for attr_name in result_msg_types.keys():
if attr_name in ["success", "reached_goal"]:
setattr(result, attr_name, execution_success)
elif attr_name == "return_info":
setattr(
result,
attr_name,
serialize_result_info(execution_error, execution_success, protocol_return_value),
)
self.lab_logger().info(f"协议 {protocol_name} 完成并返回结果")
return result return result
return execute_protocol return execute_protocol
async def execute_single_action(self, device_id, action_name, action_kwargs): async def execute_single_action(self, device_id, action_name, action_kwargs):
@@ -241,14 +320,19 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
return result_future.result return result_future.result
"""还没有改过的部分""" """还没有改过的部分"""
def _setup_hardware_proxy(self, device: ROS2DeviceNode, communication_device: ROS2DeviceNode, read_method, write_method): def _setup_hardware_proxy(
self, device: ROS2DeviceNode, communication_device: ROS2DeviceNode, read_method, write_method
):
"""为设备设置硬件接口代理""" """为设备设置硬件接口代理"""
# extra_info = [getattr(device.driver_instance, info) for info in communication_device.ros_node_instance._hardware_interface.get("extra_info", [])] # extra_info = [getattr(device.driver_instance, info) for info in communication_device.ros_node_instance._hardware_interface.get("extra_info", [])]
write_func = getattr(communication_device.driver_instance, communication_device.ros_node_instance._hardware_interface["write"]) write_func = getattr(
read_func = getattr(communication_device.driver_instance, communication_device.ros_node_instance._hardware_interface["read"]) communication_device.driver_instance, communication_device.ros_node_instance._hardware_interface["write"]
)
read_func = getattr(
communication_device.driver_instance, communication_device.ros_node_instance._hardware_interface["read"]
)
def _read(*args, **kwargs): def _read(*args, **kwargs):
return read_func(*args, **kwargs) return read_func(*args, **kwargs)
@@ -264,7 +348,6 @@ class ROS2ProtocolNode(BaseROS2DeviceNode):
# bound_write = MethodType(_write, device.driver_instance) # bound_write = MethodType(_write, device.driver_instance)
setattr(device.driver_instance, write_method, _write) setattr(device.driver_instance, write_method, _write)
async def _update_resources(self, goal, protocol_kwargs): async def _update_resources(self, goal, protocol_kwargs):
"""更新资源状态""" """更新资源状态"""
for k, v in goal.get_fields_and_field_types().items(): for k, v in goal.get_fields_and_field_types().items():

View File

@@ -7,7 +7,11 @@
import builtins import builtins
import importlib import importlib
import inspect import inspect
import sys
import traceback import traceback
import ast
import os
from pathlib import Path
from typing import Dict, List, Any, Optional, Callable, Type from typing import Dict, List, Any, Optional, Callable, Type
@@ -18,8 +22,12 @@ __all__ = [
"get_class", "get_class",
"get_module", "get_module",
"init_from_list", "init_from_list",
"get_class_info_static",
"get_registry_class_info",
] ]
from ast import Constant
from unilabos.utils import logger from unilabos.utils import logger
@@ -114,15 +122,16 @@ class ImportManager:
# 尝试动态导入 # 尝试动态导入
if ":" in class_name: if ":" in class_name:
module_path, cls_name = class_name.rsplit(":", 1) module_path, cls_name = class_name.rsplit(":", 1)
# 如果cls_name是builtins中的关键字则返回对应类
if cls_name in builtins.__dict__:
return builtins.__dict__[cls_name]
module = self.load_module(module_path) module = self.load_module(module_path)
if hasattr(module, cls_name): if hasattr(module, cls_name):
cls = getattr(module, cls_name) cls = getattr(module, cls_name)
self._classes[class_name] = cls self._classes[class_name] = cls
self._classes[cls_name] = cls self._classes[cls_name] = cls
return cls return cls
else:
# 如果cls_name是builtins中的关键字则返回对应类
if class_name in builtins.__dict__:
return builtins.__dict__[class_name]
raise KeyError(f"找不到类: {class_name}") raise KeyError(f"找不到类: {class_name}")
@@ -149,6 +158,9 @@ class ImportManager:
Returns: Returns:
找到的类对象如果未找到则返回None 找到的类对象如果未找到则返回None
""" """
# 如果cls_name是builtins中的关键字则返回对应类
if class_name in builtins.__dict__:
return builtins.__dict__[class_name]
# 首先在已索引的类中查找 # 首先在已索引的类中查找
if class_name in self._classes: if class_name in self._classes:
return self._classes[class_name] return self._classes[class_name]
@@ -161,7 +173,9 @@ class ImportManager:
# 遍历所有已加载的模块进行搜索 # 遍历所有已加载的模块进行搜索
for module_path, module in self._modules.items(): for module_path, module in self._modules.items():
for name, obj in inspect.getmembers(module): for name, obj in inspect.getmembers(module):
if inspect.isclass(obj) and ((name.lower() == class_name.lower()) if search_lower else (name == class_name)): if inspect.isclass(obj) and (
(name.lower() == class_name.lower()) if search_lower else (name == class_name)
):
# 将找到的类添加到索引中 # 将找到的类添加到索引中
self._classes[name] = obj self._classes[name] = obj
self._classes[f"{module_path}:{name}"] = obj self._classes[f"{module_path}:{name}"] = obj
@@ -169,6 +183,559 @@ class ImportManager:
return None return None
def get_enhanced_class_info(self, module_path: str, use_dynamic: bool = True) -> Dict[str, Any]:
"""
获取增强的类信息,支持动态导入和静态分析
Args:
module_path: 模块路径,格式为 "module.path""module.path:ClassName"
use_dynamic: 是否优先使用动态导入
Returns:
包含详细类信息的字典
"""
result = {
"module_path": module_path,
"dynamic_import_success": False,
"static_analysis_success": False,
"init_params": {},
"status_methods": {}, # get_ 开头和 @property 方法
"action_methods": {}, # set_ 开头和其他非_开头方法
}
# 尝试动态导入
dynamic_info = None
if use_dynamic:
try:
raise ValueError("强制使用动态导入") # 强制使用动态导入以测试功能
dynamic_info = self._get_dynamic_class_info(module_path)
result["dynamic_import_success"] = True
logger.debug(f"[ImportManager] 动态导入类 {module_path} 成功")
except Exception as e:
logger.warning(
f"[UniLab Registry] 在补充注册表时,动态导入类 "
f"{module_path} 失败(将使用静态分析,"
f"建议修复导入错误,以实现更好的注册表识别效果!): {e}"
)
# 尝试静态分析
static_info = None
try:
static_info = self._get_static_class_info(module_path)
result["static_analysis_success"] = True
logger.debug(f"[ImportManager] 静态分析类 {module_path} 成功")
except Exception as e:
logger.warning(f"[ImportManager] 静态分析类 {module_path} 失败: {e}")
# 合并信息(优先使用动态导入的信息)
if dynamic_info:
result.update(dynamic_info)
elif static_info:
result.update(static_info)
return result
def _get_dynamic_class_info(self, class_path: str) -> Dict[str, Any]:
"""使用inspect模块动态获取类信息"""
cls = get_class(class_path)
class_name = cls.__name__
result = {
"class_name": class_name,
"init_params": {},
"status_methods": {},
"action_methods": {},
}
init_signature = inspect.signature(cls.__init__)
for param_name, param in init_signature.parameters.items():
if param_name == "self":
continue
# 先获取注解类型
param_type = self._get_type_string(param.annotation)
param_default = None if param.default == inspect.Parameter.empty else param.default
# 如果type为Any或None尝试用default的类型推断
if param_type in ["Any", "None"]:
if param.default != inspect.Parameter.empty and param.default is not None:
default_type = type(param.default)
param_type = self._get_type_string(default_type)
param_info = {
"name": param_name,
"type": param_type,
"required": param.default == inspect.Parameter.empty,
"default": param_default,
}
result["init_params"][param_name] = param_info
# 分析类的所有成员
for name, method in inspect.getmembers(cls):
if name.startswith("_"):
continue
# 检查是否是property
if isinstance(method, property):
# @property 装饰的方法
# noinspection PyTypeChecker
return_type = self._get_return_type_from_method(method.fget) if method.fget else "Any"
prop_info = {
"name": name,
"return_type": return_type,
}
result["status_methods"][name] = prop_info
# 检查是否有对应的setter
if method.fset:
setter_info = self._analyze_method_signature(method.fset)
result["action_methods"][name] = setter_info
elif inspect.ismethod(method) or inspect.isfunction(method):
if name.startswith("get_"):
# get_ 开头的方法归类为status
method_info = self._analyze_method_signature(method)
result["status_methods"][name] = method_info
elif not name.startswith("_"):
# 其他非_开头的方法归类为action
method_info = self._analyze_method_signature(method)
result["action_methods"][name] = method_info
return result
def _get_static_class_info(self, module_path: str) -> Dict[str, Any]:
"""使用AST静态分析获取类信息"""
module_name, class_name = module_path.rsplit(":", 1)
# 将模块路径转换为文件路径
file_path = self._module_path_to_file_path(module_name)
if not file_path or not os.path.exists(file_path):
raise FileNotFoundError(f"找不到模块文件: {module_name} -> {file_path}")
with open(file_path, "r", encoding="utf-8") as f:
source_code = f.read()
tree = ast.parse(source_code)
# 查找目标类
target_class = None
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef):
if node.name == class_name:
target_class = node
break
if target_class is None:
raise AttributeError(f"在文件 {file_path} 中找不到类 {class_name}")
result = {
"class_name": class_name,
"init_params": {},
"status_methods": {},
"action_methods": {},
}
# 分析类的方法
for node in target_class.body:
if isinstance(node, ast.FunctionDef):
method_info = self._analyze_method_node(node)
method_name = node.name
if method_name == "__init__":
result["init_params"] = method_info["args"]
elif method_name.startswith("_"):
continue
elif self._is_property_method(node):
# @property 装饰的方法
result["status_methods"][method_name] = method_info
else:
# set_ 开头或其他非_开头的方法
result["action_methods"][method_name] = method_info
return result
def _analyze_method_signature(self, method) -> Dict[str, Any]:
"""分析方法签名"""
signature = inspect.signature(method)
args = []
num_required = 0
for param_name, param in signature.parameters.items():
if param_name == "self":
continue
is_required = param.default == inspect.Parameter.empty
if is_required:
num_required += 1
args.append(
{
"name": param_name,
"type": self._get_type_string(param.annotation),
"required": is_required,
"default": None if param.default == inspect.Parameter.empty else param.default,
}
)
return {
"name": method.__name__,
"args": args,
"return_type": self._get_type_string(signature.return_annotation),
"is_async": inspect.iscoroutinefunction(method),
}
def _get_return_type_from_method(self, method) -> str:
"""从方法中获取返回类型"""
if hasattr(method, "__annotations__") and "return" in method.__annotations__:
return self._get_type_string(method.__annotations__["return"])
signature = inspect.signature(method)
return self._get_type_string(signature.return_annotation)
def _get_type_string(self, annotation) -> str:
"""将类型注解转换为字符串"""
if annotation == inspect.Parameter.empty:
return "Any" # 如果没有注解返回Any
if annotation is None:
return "None" # 明确的None类型
# 如果是类型对象
if hasattr(annotation, "__name__"):
# 如果是内置类型
if annotation.__module__ == "builtins":
return annotation.__name__
else:
# 如果是自定义类,返回完整路径
return f"{annotation.__module__}:{annotation.__name__}"
# 如果是typing模块的类型
elif hasattr(annotation, "_name"):
return annotation._name
# 如果是字符串形式的类型注解
elif isinstance(annotation, str):
return annotation
# 其他情况,尝试转换为字符串
else:
annotation_str = str(annotation)
# 处理typing模块的复杂类型
if "typing." in annotation_str:
# 简化typing类型显示
return annotation_str.replace("typing.", "")
return annotation_str
def _is_property_method(self, node: ast.FunctionDef) -> bool:
"""检查是否是@property装饰的方法"""
for decorator in node.decorator_list:
if isinstance(decorator, ast.Name) and decorator.id == "property":
return True
return False
def _is_setter_method(self, node: ast.FunctionDef) -> bool:
"""检查是否是@xxx.setter装饰的方法"""
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute) and decorator.attr == "setter":
return True
return False
def _get_property_name_from_setter(self, node: ast.FunctionDef) -> str:
"""从setter装饰器中获取属性名"""
for decorator in node.decorator_list:
if isinstance(decorator, ast.Attribute) and decorator.attr == "setter":
if isinstance(decorator.value, ast.Name):
return decorator.value.id
return node.name
def get_class_info_static(self, module_class_path: str) -> Dict[str, Any]:
"""
静态分析获取类的方法信息,不需要实际导入模块
Args:
module_class_path: 格式为 "module.path:ClassName" 的字符串
Returns:
包含类方法信息的字典
"""
try:
if ":" not in module_class_path:
raise ValueError("module_class_path必须是 'module.path:ClassName' 格式")
module_path, class_name = module_class_path.rsplit(":", 1)
# 将模块路径转换为文件路径
file_path = self._module_path_to_file_path(module_path)
if not file_path or not os.path.exists(file_path):
logger.warning(f"找不到模块文件: {module_path} -> {file_path}")
return {}
# 解析源码
with open(file_path, "r", encoding="utf-8") as f:
source_code = f.read()
tree = ast.parse(source_code)
# 查找目标类
class_node = None
for node in ast.walk(tree):
if isinstance(node, ast.ClassDef) and node.name == class_name:
class_node = node
break
if not class_node:
logger.warning(f"在模块 {module_path} 中找不到类 {class_name}")
return {}
# 分析类的方法
methods_info = {}
for node in class_node.body:
if isinstance(node, ast.FunctionDef):
method_info = self._analyze_method_node(node)
methods_info[node.name] = method_info
return {
"class_name": class_name,
"module_path": module_path,
"file_path": file_path,
"methods": methods_info,
}
except Exception as e:
logger.error(f"静态分析类 {module_class_path} 时出错: {str(e)}")
return {}
def _module_path_to_file_path(self, module_path: str) -> Optional[str]:
for path in sys.path:
potential_path = Path(path) / module_path.replace(".", "/")
# 检查是否为包
if (potential_path / "__init__.py").exists():
return str(potential_path / "__init__.py")
# 检查是否为模块文件
if (potential_path.parent / f"{potential_path.name}.py").exists():
return str(potential_path.parent / f"{potential_path.name}.py")
return None
def _analyze_method_node(self, node: ast.FunctionDef) -> Dict[str, Any]:
"""分析方法节点,提取参数和返回类型信息"""
method_info = {
"name": node.name,
"args": [],
"return_type": None,
"is_async": isinstance(node, ast.AsyncFunctionDef),
}
# 获取默认值列表
defaults = node.args.defaults
num_defaults = len(defaults)
# 计算必需参数数量
total_args = len(node.args.args)
num_required = total_args - num_defaults
# 提取参数信息
for i, arg in enumerate(node.args.args):
if arg.arg == "self":
continue
arg_info = {
"name": arg.arg,
"type": None,
"default": None,
"required": i < num_required,
}
# 提取类型注解
if arg.annotation:
arg_info["type"] = ast.unparse(arg.annotation) if hasattr(ast, "unparse") else str(arg.annotation)
# 提取默认值并推断类型
if i >= num_required:
default_index = i - num_required
if default_index < len(defaults):
default_value: Constant = defaults[default_index]
assert isinstance(default_value, Constant), "暂不支持对非常量类型进行推断,可反馈开源仓库"
arg_info["default"] = default_value.value
# 如果没有类型注解,尝试从默认值推断类型
if not arg_info["type"]:
arg_info["type"] = self._get_type_string(type(arg_info["default"]))
method_info["args"].append(arg_info)
# 提取返回类型
if node.returns:
method_info["return_type"] = ast.unparse(node.returns) if hasattr(ast, "unparse") else str(node.returns)
return method_info
def _infer_type_from_default(self, node: ast.AST) -> Optional[str]:
"""从默认值推断参数类型"""
if isinstance(node, ast.Constant):
value = node.value
if isinstance(value, bool):
return "bool"
elif isinstance(value, int):
return "int"
elif isinstance(value, float):
return "float"
elif isinstance(value, str):
return "str"
elif value is None:
return "Optional[Any]"
elif isinstance(node, ast.List):
return "List"
elif isinstance(node, ast.Dict):
return "Dict"
elif isinstance(node, ast.Tuple):
return "Tuple"
elif isinstance(node, ast.Set):
return "Set"
elif isinstance(node, ast.Name):
# 常见的默认值模式
if node.id in ["None"]:
return "Optional[Any]"
elif node.id in ["True", "False"]:
return "bool"
elif isinstance(node, ast.Attribute):
# 处理类似 os.path.join 的情况
attr_str = self._extract_default_value(node)
if "path" in attr_str.lower():
return "str"
return None
def _infer_types_from_docstring(self, method_info: Dict[str, Any]) -> None:
"""从docstring中推断参数类型"""
docstring = method_info.get("docstring", "")
if not docstring:
return
lines = docstring.split("\n")
in_args_section = False
for line in lines:
line = line.strip()
# 检测Args或Arguments段落
if line.lower().startswith(("args:", "arguments:")):
in_args_section = True
continue
elif line.startswith(("returns:", "return:", "yields:", "raises:")):
in_args_section = False
continue
elif not line or not in_args_section:
continue
# 解析参数行,格式通常是: param_name (type): description 或 param_name: description
if ":" in line:
parts = line.split(":", 1)
param_part = parts[0].strip()
# 提取参数名和类型
param_name = None
param_type = None
if "(" in param_part and ")" in param_part:
# 格式: param_name (type)
param_name = param_part.split("(")[0].strip()
type_part = param_part.split("(")[1].split(")")[0].strip()
param_type = type_part
else:
# 格式: param_name
param_name = param_part
# 更新对应参数的类型信息
if param_name:
for arg_info in method_info["args"]:
if arg_info["name"] == param_name and not arg_info["type"]:
if param_type:
arg_info["inferred_type"] = param_type
elif not arg_info["inferred_type"]:
# 从描述中推断类型
description = parts[1].strip().lower()
if any(word in description for word in ["path", "file", "directory", "filename"]):
arg_info["inferred_type"] = "str"
elif any(
word in description for word in ["port", "number", "count", "size", "length"]
):
arg_info["inferred_type"] = "int"
elif any(
word in description for word in ["rate", "ratio", "percentage", "temperature"]
):
arg_info["inferred_type"] = "float"
elif any(word in description for word in ["flag", "enable", "disable", "option"]):
arg_info["inferred_type"] = "bool"
def get_registry_class_info(self, module_class_path: str) -> Dict[str, Any]:
"""
获取适用于注册表的类信息,包含完整的类型推断
Args:
module_class_path: 格式为 "module.path:ClassName" 的字符串
Returns:
适用于注册表的类信息字典
"""
class_info = self.get_class_info_static(module_class_path)
if not class_info:
return {}
registry_info = {
"class_name": class_info["class_name"],
"module_path": class_info["module_path"],
"file_path": class_info["file_path"],
"methods": {},
"properties": [],
"init_params": {},
"action_methods": {},
}
for method_name, method_info in class_info["methods"].items():
# 分类处理不同类型的方法
if method_info["is_property"]:
registry_info["properties"].append(
{
"name": method_name,
"return_type": method_info.get("return_type"),
"docstring": method_info.get("docstring"),
}
)
elif method_name == "__init__":
# 处理初始化参数
init_params = {}
for arg in method_info["args"]:
if arg["name"] != "self":
param_info = {
"name": arg["name"],
"type": arg.get("type") or arg.get("inferred_type"),
"required": arg.get("is_required", True),
"default": arg.get("default"),
}
init_params[arg["name"]] = param_info
registry_info["init_params"] = init_params
elif not method_name.startswith("_"):
# 处理公共方法可能的action方法
action_info = {
"name": method_name,
"params": {},
"return_type": method_info.get("return_type"),
"docstring": method_info.get("docstring"),
"num_required": method_info.get("num_required", 0) - 1, # 减去self
"num_defaults": method_info.get("num_defaults", 0),
}
for arg in method_info["args"]:
if arg["name"] != "self":
param_info = {
"name": arg["name"],
"type": arg.get("type") or arg.get("inferred_type"),
"required": arg.get("is_required", True),
"default": arg.get("default"),
}
action_info["params"][arg["name"]] = param_info
registry_info["action_methods"][method_name] = action_info
return registry_info
# 全局实例,便于直接使用 # 全局实例,便于直接使用
default_manager = ImportManager() default_manager = ImportManager()
@@ -193,3 +760,18 @@ def init_from_list(module_list: List[str]) -> None:
"""从模块列表初始化默认管理器""" """从模块列表初始化默认管理器"""
global default_manager global default_manager
default_manager = ImportManager(module_list) default_manager = ImportManager(module_list)
def get_class_info_static(module_class_path: str) -> Dict[str, Any]:
"""静态分析获取类信息的便捷函数"""
return default_manager.get_class_info_static(module_class_path)
def get_registry_class_info(module_class_path: str) -> Dict[str, Any]:
"""获取适用于注册表的类信息的便捷函数"""
return default_manager.get_registry_class_info(module_class_path)
def get_enhanced_class_info(module_path: str, use_dynamic: bool = True) -> Dict[str, Any]:
"""获取增强的类信息的便捷函数"""
return default_manager.get_enhanced_class_info(module_path, use_dynamic)

View File

@@ -2,6 +2,8 @@ import collections.abc
import json import json
from typing import get_origin, get_args from typing import get_origin, get_args
import yaml
def get_type_class(type_hint): def get_type_class(type_hint):
origin = get_origin(type_hint) origin = get_origin(type_hint)
@@ -22,6 +24,12 @@ class TypeEncoder(json.JSONEncoder):
return super().default(obj) return super().default(obj)
class NoAliasDumper(yaml.SafeDumper):
def ignore_aliases(self, data):
return True
class ResultInfoEncoder(json.JSONEncoder): class ResultInfoEncoder(json.JSONEncoder):
"""专门用于处理任务执行结果信息的JSON编码器""" """专门用于处理任务执行结果信息的JSON编码器"""