From a66369e2c31c408c47c92050114a7f152c016922 Mon Sep 17 00:00:00 2001 From: Junhan Chang Date: Sun, 3 Aug 2025 11:21:37 +0800 Subject: [PATCH] Cleanup registry to be easy-understanding (#76) * delete deprecated mock devices * rename categories * combine chromatographic devices * rename rviz simulation nodes * organic virtual devices * parse vessel_id * run registry completion before merge --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> --- test/experiments/mock_reactor.json | 4 +- test/experiments/plr_test_converted.json | 8 +- test/experiments/test_moveit.json | 2 +- test/experiments/workshop.json | 949 ++++ unilabos/compile/add_protocol.py | 12 +- unilabos/compile/adjustph_protocol.py | 12 +- unilabos/compile/clean_vessel_protocol.py | 12 +- .../compile/evacuateandrefill_protocol.py | 12 +- unilabos/compile/evaporate_protocol.py | 12 +- unilabos/compile/filter_protocol.py | 12 +- unilabos/compile/heatchill_protocol.py | 12 +- unilabos/compile/hydrogenate_protocol.py | 12 +- unilabos/compile/recrystallize_protocol.py | 12 +- unilabos/compile/separate_protocol.py | 888 ++-- .../mock => compile/utils}/__init__.py | 0 unilabos/compile/utils/vessel_parser.py | 20 + unilabos/devices/mock/mock_chiller.py | 177 - unilabos/devices/mock/mock_filter.py | 235 - unilabos/devices/mock/mock_heater.py | 247 - unilabos/devices/mock/mock_pump.py | 360 -- unilabos/devices/mock/mock_rotavap.py | 390 -- unilabos/devices/mock/mock_separator.py | 399 -- unilabos/devices/mock/mock_solenoid_valve.py | 89 - unilabos/devices/mock/mock_stirrer.py | 307 -- unilabos/devices/mock/mock_stirrer_new.py | 229 - unilabos/devices/mock/mock_vacuum.py | 410 -- ...serial.yaml => communication_devices.yaml} | 2 +- unilabos/registry/devices/camera.yaml | 2 +- .../devices/characterization_chromatic.yaml | 404 ++ .../devices/characterization_optic.yaml | 223 +- ...vacuum_and_purge.yaml => gas_handler.yaml} | 3 +- unilabos/registry/devices/mock_devices.yaml | 4685 ----------------- unilabos/registry/devices/moveit_config.yaml | 704 --- unilabos/registry/devices/robot_arm.yaml | 352 ++ .../registry/devices/robot_linear_motion.yaml | 352 ++ unilabos/registry/devices/sim_nodes.yaml | 315 -- ...yu_add_solid.yaml => solid_dispenser.yaml} | 4 +- unilabos/registry/devices/virtual_device.yaml | 16 +- unilabos/registry/devices/work_station.yaml | 5 + unilabos/registry/devices/zhida_hplc.yaml | 183 - .../registry/resources/organic/container.yaml | 2 +- 41 files changed, 2629 insertions(+), 9445 deletions(-) create mode 100644 test/experiments/workshop.json rename unilabos/{devices/mock => compile/utils}/__init__.py (100%) create mode 100644 unilabos/compile/utils/vessel_parser.py delete mode 100644 unilabos/devices/mock/mock_chiller.py delete mode 100644 unilabos/devices/mock/mock_filter.py delete mode 100644 unilabos/devices/mock/mock_heater.py delete mode 100644 unilabos/devices/mock/mock_pump.py delete mode 100644 unilabos/devices/mock/mock_rotavap.py delete mode 100644 unilabos/devices/mock/mock_separator.py delete mode 100644 unilabos/devices/mock/mock_solenoid_valve.py delete mode 100644 unilabos/devices/mock/mock_stirrer.py delete mode 100644 unilabos/devices/mock/mock_stirrer_new.py delete mode 100644 unilabos/devices/mock/mock_vacuum.py rename unilabos/registry/device_comms/{serial.yaml => communication_devices.yaml} (98%) create mode 100644 unilabos/registry/devices/characterization_chromatic.yaml rename unilabos/registry/devices/{vacuum_and_purge.yaml => gas_handler.yaml} (99%) delete mode 100644 unilabos/registry/devices/mock_devices.yaml delete mode 100644 unilabos/registry/devices/moveit_config.yaml delete mode 100644 unilabos/registry/devices/sim_nodes.yaml rename unilabos/registry/devices/{laiyu_add_solid.yaml => solid_dispenser.yaml} (99%) delete mode 100644 unilabos/registry/devices/zhida_hplc.yaml diff --git a/test/experiments/mock_reactor.json b/test/experiments/mock_reactor.json index 1c03d315..fa35ad02 100644 --- a/test/experiments/mock_reactor.json +++ b/test/experiments/mock_reactor.json @@ -14,8 +14,8 @@ "type": "device", "class": "workstation", "position": { - "x": 620.6111111111111, - "y": 171, + "x": 0, + "y": 0, "z": 0 }, "config": { diff --git a/test/experiments/plr_test_converted.json b/test/experiments/plr_test_converted.json index 6b5cae4e..b3ec7053 100644 --- a/test/experiments/plr_test_converted.json +++ b/test/experiments/plr_test_converted.json @@ -1,8 +1,8 @@ { "nodes": [ { - "id": "PLR_STATION", - "name": "PLR_LH_TEST", + "id": "liquid_handler", + "name": "liquid_handler", "parent": null, "type": "device", "class": "liquid_handler", @@ -37,7 +37,7 @@ "tip_rack", "plate_well" ], - "parent": "PLR_STATION", + "parent": "liquid_handler", "type": "deck", "class": "OTDeck", "position": { @@ -9650,7 +9650,7 @@ "children": [], "parent": null, "type": "device", - "class": "moveit.arm_slider", + "class": "robotic_arm.SCARA_with_slider.virtual", "position": { "x": -500, "y": 1000, diff --git a/test/experiments/test_moveit.json b/test/experiments/test_moveit.json index c1df5e99..e67f56b1 100644 --- a/test/experiments/test_moveit.json +++ b/test/experiments/test_moveit.json @@ -8,7 +8,7 @@ "children": [], "parent": null, "type": "device", - "class": "moveit.arm_slider", + "class": "robotic_arm.SCARA_with_slider.virtual", "position": { "x": -500, "y": 1000, diff --git a/test/experiments/workshop.json b/test/experiments/workshop.json new file mode 100644 index 00000000..60d731d0 --- /dev/null +++ b/test/experiments/workshop.json @@ -0,0 +1,949 @@ +{ + "nodes": [ + { + "id": "simple_station", + "name": "愚公常量合成工作站", + "children": [ + "serial_pump", + "pump_reagents", + "pump_workup", + "flask_CH2Cl2", + "waste_workup", + "separator_controller", + "flask_separator", + "flask_air" + ], + "parent": null, + "type": "device", + "class": "workstation", + "position": { + "x": 620.6111111111111, + "y": 171, + "z": 0 + }, + "config": { + "protocol_type": ["PumpTransferProtocol", "CleanProtocol", "SeparateProtocol", "EvaporateProtocol"] + }, + "data": { + } + }, + { + "id": "serial_pump", + "name": "serial_pump", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "serial", + "position": { + "x": 620.6111111111111, + "y": 171, + "z": 0 + }, + "config": { + "port": "COM7", + "baudrate": 9600 + }, + "data": { + } + }, + { + "id": "pump_reagents", + "name": "pump_reagents", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "syringepump.runze", + "position": { + "x": 620.6111111111111, + "y": 171, + "z": 0 + }, + "config": { + "port": "/devices/PumpBackbone/Serial/serialwrite", + "address": "1", + "max_volume": 25.0 + }, + "data": { + "max_velocity": 1.0, + "position": 0.0, + "status": "Idle", + "valve_position": "0" + } + }, + { + "id": "flask_CH2Cl2", + "name": "flask_CH2Cl2", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 430.4087301587302, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "CH2Cl2", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "flask_acetone", + "name": "flask_acetone", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 295.36944444444447, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "acetone", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "flask_NH4Cl", + "name": "flask_NH4Cl", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 165.36944444444444, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "NH4Cl", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "flask_grignard", + "name": "flask_grignard", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 165.36944444444444, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "grignard", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "flask_THF", + "name": "flask_THF", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 35, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "THF", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "reactor", + "name": "reactor", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 698.1111111111111, + "y": 428, + "z": 0 + }, + "config": { + "max_volume": 5000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "stirrer", + "name": "stirrer", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "heaterstirrer.dalong", + "position": { + "x": 698.1111111111111, + "y": 478, + "z": 0 + }, + "config": { + "port": "COM43", + "temp_warning": 60.0 + }, + "data": { + "status": "Idle", + "temp": 0.0, + "stir_speed": 0.0 + } + }, + { + "id": "pump_workup", + "name": "pump_workup", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "syringepump.runze", + "position": { + "x": 1195.611507936508, + "y": 686, + "z": 0 + }, + "config": { + "port": "/devices/PumpBackbone/Serial/serialwrite", + "address": "2", + "max_volume": 25.0 + }, + "data": { + "max_velocity": 1.0, + "position": 0.0, + "status": "Idle", + "valve_position": "0" + } + }, + { + "id": "waste_workup", + "name": "waste_workup", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1587.703373015873, + "y": 1172.5, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "separator_controller", + "name": "separator_controller", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "separator.homemade", + "position": { + "x": 1624.4027777777778, + "y": 665.5, + "z": 0 + }, + "config": { + "port_executor": "/dev/tty.usbserial-11140", + "port_sensor": "/dev/tty.usbserial-11130" + }, + "data": { + "sensordata": 0.0, + "status": "Idle" + } + }, + { + "id": "flask_separator", + "name": "flask_separator", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1614.404365079365, + "y": 948, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "flask_holding", + "name": "flask_holding", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1915.7035714285714, + "y": 665.5, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "flask_H2O", + "name": "flask_H2O", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1785.7035714285714, + "y": 665.5, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "H2O", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "flask_NaHCO3", + "name": "flask_NaHCO3", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 2054.0650793650793, + "y": 665.5, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + { + "liquid_type": "NaHCO3", + "liquid_volume": 1500.0 + } + ] + } + }, + { + "id": "pump_column", + "name": "pump_column", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "syringepump.runze", + "position": { + "x": 1630.6527777777778, + "y": 448.5, + "z": 0 + }, + "config": { + "port": "/devices/PumpBackbone/Serial/serialwrite", + "address": "3", + "max_volume": 25.0 + }, + "data": { + "max_velocity": 1.0, + "position": 0.0, + "status": "Idle", + "valve_position": "0" + } + }, + { + "id": "rotavap", + "name": "rotavap", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "rotavap", + "position": { + "x": 1339.7031746031746, + "y": 968.5, + "z": 0 + }, + "config": { + "port": "COM15" + }, + "data": { + "temperature": 0.0, + "rotate_time": 0.0, + "status": "Idle" + } + }, + { + "id": "flask_rv", + "name": "flask_rv", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1339.7031746031746, + "y": 1152, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "column", + "name": "column", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 909.722619047619, + "y": 948, + "z": 0 + }, + "config": { + "max_volume": 200.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "flask_column", + "name": "flask_column", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 867.972619047619, + "y": 1152, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "flask_air", + "name": "flask_air", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 742.722619047619, + "y": 948, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "dry_column", + "name": "dry_column", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1206.722619047619, + "y": 948, + "z": 0 + }, + "config": { + "max_volume": 200.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "flask_dry_column", + "name": "flask_dry_column", + "children": [], + "parent": "simple_station", + "type": "container", + "class": null, + "position": { + "x": 1148.222619047619, + "y": 1152, + "z": 0 + }, + "config": { + "max_volume": 2000.0 + }, + "data": { + "liquid": [ + ] + } + }, + { + "id": "pump_ext", + "name": "pump_ext", + "children": [], + "parent": "simple_station", + "type": "device", + "class": "syringepump.runze", + "position": { + "x": 1469.7031746031746, + "y": 968.5, + "z": 0 + }, + "config": { + "port": "/devices/PumpBackbone/Serial/serialwrite", + "address": "4", + "max_volume": 25.0 + }, + "data": { + "max_velocity": 1.0, + "position": 0.0, + "status": "Idle", + "valve_position": "0" + } + }, + { + "id": "AGV", + "name": "AGV", + "children": ["zhixing_agv", "zhixing_ur_arm"], + "parent": null, + "type": "device", + "class": "workstation", + "position": { + "x": 698.1111111111111, + "y": 478, + "z": 0 + }, + "config": { + "protocol_type": ["AGVTransferProtocol"] + }, + "data": { + } + }, + { + "id": "zhixing_agv", + "name": "zhixing_agv", + "children": [], + "parent": "AGV", + "type": "device", + "class": "zhixing_agv", + "position": { + "x": 698.1111111111111, + "y": 478, + "z": 0 + }, + "config": { + "host": "192.168.1.42" + }, + "data": { + } + }, + { + "id": "zhixing_ur_arm", + "name": "zhixing_ur_arm", + "children": [], + "parent": "AGV", + "type": "device", + "class": "zhixing_ur_arm", + "position": { + "x": 698.1111111111111, + "y": 478, + "z": 0 + }, + "config": { + "host": "192.168.1.178" + }, + "data": { + } + } + ], + "links": [ + { + "source": "pump_reagents", + "target": "serial_pump", + "type": "communication", + "port": { + "pump_reagents": "port", + "serial_pump": "port" + } + }, + { + "source": "pump_workup", + "target": "serial_pump", + "type": "communication", + "port": { + "pump_reagents": "port", + "serial_pump": "port" + } + }, + { + "source": "pump_column", + "target": "serial_pump", + "type": "communication", + "port": { + "pump_reagents": "port", + "serial_pump": "port" + } + }, + { + "source": "pump_ext", + "target": "serial_pump", + "type": "communication", + "port": { + "pump_reagents": "port", + "serial_pump": "port" + } + }, + { + "source": "reactor", + "target": "pump_reagents", + "type": "physical", + "port": { + "reactor": "top", + "pump_reagents": "5" + } + }, + { + "source": "rotavap", + "target": "flask_rv", + "type": "physical", + "port": { + "rotavap": "bottom", + "flask_rv": "top" + } + }, + { + "source": "separator_controller", + "target": "flask_separator", + "type": "physical", + "port": { + "separator_controller": "bottom", + "flask_separator": "top" + } + }, + { + "source": "column", + "target": "flask_column", + "type": "physical", + "port": { + "column": "bottom", + "flask_column": "top" + } + }, + { + "source": "dry_column", + "target": "flask_dry_column", + "type": "physical", + "port": { + "dry_column": "bottom", + "flask_dry_column": "top" + } + }, + { + "source": "pump_ext", + "target": "pump_column", + "type": "physical", + "port": { + "pump_ext": "8", + "pump_column": "1" + } + }, + { + "source": "pump_ext", + "target": "waste_workup", + "type": "physical", + "port": { + "pump_ext": "2", + "waste_workup": "-1" + } + }, + { + "source": "pump_reagents", + "target": "flask_THF", + "type": "physical", + "port": { + "pump_reagents": "7", + "flask_THF": "top" + } + }, + { + "source": "pump_reagents", + "target": "flask_NH4Cl", + "type": "physical", + "port": { + "pump_reagents": "4", + "flask_NH4Cl": "top" + } + }, + { + "source": "pump_reagents", + "target": "flask_CH2Cl2", + "type": "physical", + "port": { + "pump_reagents": "2", + "flask_CH2Cl2": "top" + } + }, + { + "source": "pump_reagents", + "target": "flask_acetone", + "type": "physical", + "port": { + "pump_reagents": "3", + "flask_acetone": "top" + } + }, + { + "source": "pump_reagents", + "target": "pump_workup", + "type": "physical", + "port": { + "pump_reagents": "1", + "pump_workup": "8" + } + }, + { + "source": "pump_reagents", + "target": "flask_grignard", + "type": "physical", + "port": { + "pump_reagents": "6", + "flask_grignard": "top" + } + }, + { + "source": "pump_reagents", + "target": "reactor", + "type": "physical", + "port": { + "pump_reagents": "5", + "reactor": "top" + } + }, + { + "source": "pump_reagents", + "target": "flask_air", + "type": "physical", + "port": { + "pump_reagents": "8", + "flask_air": "-1" + } + }, + { + "source": "pump_workup", + "target": "waste_workup", + "type": "physical", + "port": { + "pump_workup": "2", + "waste_workup": "-1" + } + }, + { + "source": "pump_workup", + "target": "flask_H2O", + "type": "physical", + "port": { + "pump_workup": "7", + "flask_H2O": "top" + } + }, + { + "source": "pump_workup", + "target": "flask_NaHCO3", + "type": "physical", + "port": { + "pump_workup": "6", + "flask_NaHCO3": "top" + } + }, + { + "source": "pump_workup", + "target": "pump_reagents", + "type": "physical", + "port": { + "pump_workup": "8", + "pump_reagents": "1" + } + }, + { + "source": "pump_workup", + "target": "flask_holding", + "type": "physical", + "port": { + "pump_workup": "5", + "flask_holding": "top" + } + }, + { + "source": "pump_workup", + "target": "separator_controller", + "type": "physical", + "port": { + "pump_workup": "4", + "separator_controller": "top" + } + }, + { + "source": "pump_workup", + "target": "flask_separator", + "type": "physical", + "port": { + "pump_workup": "3", + "flask_separator": "top" + } + }, + { + "source": "pump_workup", + "target": "pump_column", + "type": "physical", + "port": { + "pump_workup": "1", + "pump_column": "8" + } + }, + { + "source": "pump_column", + "target": "column", + "type": "physical", + "port": { + "pump_column": "4", + "column": "top" + } + }, + { + "source": "pump_column", + "target": "flask_column", + "type": "physical", + "port": { + "pump_column": "3", + "flask_column": "top" + } + }, + { + "source": "pump_column", + "target": "rotavap", + "type": "physical", + "port": { + "pump_column": "2", + "rotavap": "-1" + } + }, + { + "source": "pump_column", + "target": "pump_workup", + "type": "physical", + "port": { + "pump_column": "8", + "pump_workup": "1" + } + }, + { + "source": "pump_column", + "target": "flask_air", + "type": "physical", + "port": { + "pump_column": "5", + "flask_air": "-1" + } + }, + { + "source": "pump_column", + "target": "dry_column", + "type": "physical", + "port": { + "pump_column": "7", + "dry_column": "top" + } + }, + { + "source": "pump_column", + "target": "flask_dry_column", + "type": "physical", + "port": { + "pump_column": "6", + "flask_dry_column": "top" + } + }, + { + "source": "pump_column", + "target": "pump_ext", + "type": "physical", + "port": { + "pump_column": "1", + "pump_ext": "8" + } + } + ] +} \ No newline at end of file diff --git a/unilabos/compile/add_protocol.py b/unilabos/compile/add_protocol.py index 35e6baf7..e5f02393 100644 --- a/unilabos/compile/add_protocol.py +++ b/unilabos/compile/add_protocol.py @@ -2,6 +2,7 @@ import networkx as nx import re import logging from typing import List, Dict, Any, Union +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing logger = logging.getLogger(__name__) @@ -346,16 +347,7 @@ def generate_add_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) # 🔧 修改:更新容器的液体体积(假设有 liquid_volume 字段) if "data" in vessel and "liquid_volume" in vessel["data"]: diff --git a/unilabos/compile/adjustph_protocol.py b/unilabos/compile/adjustph_protocol.py index 87fbbb96..f6db7ba2 100644 --- a/unilabos/compile/adjustph_protocol.py +++ b/unilabos/compile/adjustph_protocol.py @@ -1,6 +1,7 @@ import networkx as nx import logging from typing import List, Dict, Any, Union +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing logger = logging.getLogger(__name__) @@ -235,16 +236,7 @@ def generate_adjust_ph_protocol( List[Dict[str, Any]]: 动作序列 """ - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) if not vessel_id: debug_print(f"❌ vessel 参数无效,必须包含id字段或直接提供容器ID. vessel: {vessel}") diff --git a/unilabos/compile/clean_vessel_protocol.py b/unilabos/compile/clean_vessel_protocol.py index dd7b1712..10d2e690 100644 --- a/unilabos/compile/clean_vessel_protocol.py +++ b/unilabos/compile/clean_vessel_protocol.py @@ -1,5 +1,6 @@ from typing import List, Dict, Any import networkx as nx +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol @@ -181,16 +182,7 @@ def generate_clean_vessel_protocol( clean_protocol = generate_clean_vessel_protocol(G, {"id": "main_reactor"}, "water", 100.0, 60.0, 2) """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) action_sequence = [] diff --git a/unilabos/compile/evacuateandrefill_protocol.py b/unilabos/compile/evacuateandrefill_protocol.py index 6c21f0a5..5e6a4b48 100644 --- a/unilabos/compile/evacuateandrefill_protocol.py +++ b/unilabos/compile/evacuateandrefill_protocol.py @@ -3,6 +3,7 @@ import logging import uuid import sys from typing import List, Dict, Any, Optional +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing, generate_pump_protocol # 设置日志 @@ -288,16 +289,7 @@ def generate_evacuateandrefill_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) # 硬编码重复次数为 3 repeats = 3 diff --git a/unilabos/compile/evaporate_protocol.py b/unilabos/compile/evaporate_protocol.py index ea15ae2f..33bae762 100644 --- a/unilabos/compile/evaporate_protocol.py +++ b/unilabos/compile/evaporate_protocol.py @@ -2,6 +2,7 @@ from typing import List, Dict, Any, Optional, Union import networkx as nx import logging import re +from .utils.vessel_parser import get_vessel logger = logging.getLogger(__name__) @@ -201,16 +202,7 @@ def generate_evaporate_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) debug_print("🌟" * 20) debug_print("🌪️ 开始生成蒸发协议(支持单位和体积运算)✨") diff --git a/unilabos/compile/filter_protocol.py b/unilabos/compile/filter_protocol.py index a49c9b30..cf6d5070 100644 --- a/unilabos/compile/filter_protocol.py +++ b/unilabos/compile/filter_protocol.py @@ -1,6 +1,7 @@ from typing import List, Dict, Any, Optional import networkx as nx import logging +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing logger = logging.getLogger(__name__) @@ -68,16 +69,7 @@ def generate_filter_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) debug_print("🌊" * 20) debug_print("🚀 开始生成过滤协议(支持体积运算)✨") diff --git a/unilabos/compile/heatchill_protocol.py b/unilabos/compile/heatchill_protocol.py index 4ed072f0..3165a376 100644 --- a/unilabos/compile/heatchill_protocol.py +++ b/unilabos/compile/heatchill_protocol.py @@ -2,6 +2,7 @@ from typing import List, Dict, Any, Union import networkx as nx import logging import re +from .utils.vessel_parser import get_vessel logger = logging.getLogger(__name__) @@ -217,16 +218,7 @@ def generate_heat_chill_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) debug_print("🌡️" * 20) debug_print("🚀 开始生成加热冷却协议(支持vessel字典)✨") diff --git a/unilabos/compile/hydrogenate_protocol.py b/unilabos/compile/hydrogenate_protocol.py index 6147fe0e..9b65788d 100644 --- a/unilabos/compile/hydrogenate_protocol.py +++ b/unilabos/compile/hydrogenate_protocol.py @@ -1,5 +1,6 @@ import networkx as nx from typing import List, Dict, Any, Optional +from .utils.vessel_parser import get_vessel def parse_temperature(temp_str: str) -> float: @@ -170,16 +171,7 @@ def generate_hydrogenate_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) action_sequence = [] diff --git a/unilabos/compile/recrystallize_protocol.py b/unilabos/compile/recrystallize_protocol.py index 4b64c658..736a9af2 100644 --- a/unilabos/compile/recrystallize_protocol.py +++ b/unilabos/compile/recrystallize_protocol.py @@ -2,6 +2,7 @@ import networkx as nx import re import logging from typing import List, Dict, Any, Tuple, Union +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing logger = logging.getLogger(__name__) @@ -287,16 +288,7 @@ def generate_recrystallize_protocol( """ # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} + vessel_id, vessel_data = get_vessel(vessel) action_sequence = [] diff --git a/unilabos/compile/separate_protocol.py b/unilabos/compile/separate_protocol.py index f50f978a..cdd8862d 100644 --- a/unilabos/compile/separate_protocol.py +++ b/unilabos/compile/separate_protocol.py @@ -3,6 +3,7 @@ import re import logging import sys from typing import List, Dict, Any, Union +from .utils.vessel_parser import get_vessel from .pump_protocol import generate_pump_protocol_with_rinsing logger = logging.getLogger(__name__) @@ -63,6 +64,461 @@ def create_action_log(message: str, emoji: str = "📝") -> Dict[str, Any]: } } + +def generate_separate_protocol( + G: nx.DiGraph, + # 🔧 基础参数,支持XDL的vessel参数 + vessel: dict = None, # 🔧 修改:从字符串改为字典类型 + purpose: str = "separate", # 分离目的 + product_phase: str = "top", # 产物相 + # 🔧 可选的详细参数 + from_vessel: Union[str, dict] = "", # 源容器(通常在separate前已经transfer了) + separation_vessel: Union[str, dict] = "", # 分离容器(与vessel同义) + to_vessel: Union[str, dict] = "", # 目标容器(可选) + waste_phase_to_vessel: Union[str, dict] = "", # 废相目标容器 + product_vessel: Union[str, dict] = "", # XDL: 产物容器(与to_vessel同义) + waste_vessel: Union[str, dict] = "", # XDL: 废液容器(与waste_phase_to_vessel同义) + # 🔧 溶剂相关参数 + solvent: str = "", # 溶剂名称 + solvent_volume: Union[str, float] = 0.0, # 溶剂体积 + volume: Union[str, float] = 0.0, # XDL: 体积(与solvent_volume同义) + # 🔧 操作参数 + through: str = "", # 通过材料 + repeats: int = 1, # 重复次数 + stir_time: float = 30.0, # 搅拌时间(秒) + stir_speed: float = 300.0, # 搅拌速度 + settling_time: float = 300.0, # 沉降时间(秒) + **kwargs +) -> List[Dict[str, Any]]: + """ + 生成分离操作的协议序列 - 支持vessel字典和体积运算 + + 支持XDL参数格式: + - vessel: 分离容器字典(必需) + - purpose: "wash", "extract", "separate" + - product_phase: "top", "bottom" + - product_vessel: 产物收集容器 + - waste_vessel: 废液收集容器 + - solvent: 溶剂名称 + - volume: "200 mL", "?" 或数值 + - repeats: 重复次数 + + 分离流程: + 1. (可选)添加溶剂到分离容器 + 2. 搅拌混合 + 3. 静置分层 + 4. 收集指定相到目标容器 + 5. 重复指定次数 + """ + + # 🔧 核心修改:vessel参数兼容处理 + if vessel is None: + if isinstance(separation_vessel, dict): + vessel = separation_vessel + else: + raise ValueError("必须提供vessel字典参数") + + # 🔧 核心修改:从字典中提取容器ID + vessel_id, vessel_data = get_vessel(vessel) + + debug_print("🌀" * 20) + debug_print("🚀 开始生成分离协议(支持vessel字典和体积运算)✨") + debug_print(f"📝 输入参数:") + debug_print(f" 🥽 vessel: {vessel} (ID: {vessel_id})") + debug_print(f" 🎯 分离目的: '{purpose}'") + debug_print(f" 📊 产物相: '{product_phase}'") + debug_print(f" 💧 溶剂: '{solvent}'") + debug_print(f" 📏 体积: {volume} (类型: {type(volume)})") + debug_print(f" 🔄 重复次数: {repeats}") + debug_print(f" 🎯 产物容器: '{product_vessel}'") + debug_print(f" 🗑️ 废液容器: '{waste_vessel}'") + debug_print(f" 📦 其他参数: {kwargs}") + debug_print("🌀" * 20) + + action_sequence = [] + + # 🔧 新增:记录分离前的容器状态 + debug_print("🔍 记录分离前容器状态...") + original_liquid_volume = get_vessel_liquid_volume(vessel) + debug_print(f"📊 分离前液体体积: {original_liquid_volume:.2f}mL") + + # === 参数验证和标准化 === + debug_print("🔍 步骤1: 参数验证和标准化...") + action_sequence.append(create_action_log(f"开始分离操作 - 容器: {vessel_id}", "🎬")) + action_sequence.append(create_action_log(f"分离目的: {purpose}", "🧪")) + action_sequence.append(create_action_log(f"产物相: {product_phase}", "📊")) + + # 统一容器参数 - 支持字典和字符串 + def extract_vessel_id(vessel_param): + if isinstance(vessel_param, dict): + return vessel_param.get("id", "") + elif isinstance(vessel_param, str): + return vessel_param + else: + return "" + + final_vessel_id, _ = vessel_id + final_to_vessel_id, _ = get_vessel(to_vessel) or get_vessel(product_vessel) + final_waste_vessel_id, _ = get_vessel(waste_phase_to_vessel) or get_vessel(waste_vessel) + + # 统一体积参数 + final_volume = parse_volume_input(volume or solvent_volume) + + # 🔧 修复:确保repeats至少为1 + if repeats <= 0: + repeats = 1 + debug_print(f"⚠️ 重复次数参数 <= 0,自动设置为 1") + + debug_print(f"🔧 标准化后的参数:") + debug_print(f" 🥼 分离容器: '{final_vessel_id}'") + debug_print(f" 🎯 产物容器: '{final_to_vessel_id}'") + debug_print(f" 🗑️ 废液容器: '{final_waste_vessel_id}'") + debug_print(f" 📏 溶剂体积: {final_volume}mL") + debug_print(f" 🔄 重复次数: {repeats}") + + action_sequence.append(create_action_log(f"分离容器: {final_vessel_id}", "🧪")) + action_sequence.append(create_action_log(f"溶剂体积: {final_volume}mL", "📏")) + action_sequence.append(create_action_log(f"重复次数: {repeats}", "🔄")) + + # 验证必需参数 + if not purpose: + purpose = "separate" + if not product_phase: + product_phase = "top" + if purpose not in ["wash", "extract", "separate"]: + debug_print(f"⚠️ 未知的分离目的 '{purpose}',使用默认值 'separate'") + purpose = "separate" + action_sequence.append(create_action_log(f"未知目的,使用: {purpose}", "⚠️")) + if product_phase not in ["top", "bottom"]: + debug_print(f"⚠️ 未知的产物相 '{product_phase}',使用默认值 'top'") + product_phase = "top" + action_sequence.append(create_action_log(f"未知相别,使用: {product_phase}", "⚠️")) + + debug_print("✅ 参数验证通过") + action_sequence.append(create_action_log("参数验证通过", "✅")) + + # === 查找设备 === + debug_print("🔍 步骤2: 查找设备...") + action_sequence.append(create_action_log("正在查找相关设备...", "🔍")) + + # 查找分离器设备 + separator_device = find_separator_device(G, final_vessel_id) # 🔧 使用 final_vessel_id + if separator_device: + action_sequence.append(create_action_log(f"找到分离器设备: {separator_device}", "🧪")) + else: + debug_print("⚠️ 未找到分离器设备,可能无法执行分离") + action_sequence.append(create_action_log("未找到分离器设备", "⚠️")) + + # 查找搅拌器 + stirrer_device = find_connected_stirrer(G, final_vessel_id) # 🔧 使用 final_vessel_id + if stirrer_device: + action_sequence.append(create_action_log(f"找到搅拌器: {stirrer_device}", "🌪️")) + else: + action_sequence.append(create_action_log("未找到搅拌器", "⚠️")) + + # 查找溶剂容器(如果需要) + solvent_vessel = "" + if solvent and solvent.strip(): + solvent_vessel = find_solvent_vessel(G, solvent) + if solvent_vessel: + action_sequence.append(create_action_log(f"找到溶剂容器: {solvent_vessel}", "💧")) + else: + action_sequence.append(create_action_log(f"未找到溶剂容器: {solvent}", "⚠️")) + + debug_print(f"📊 设备配置:") + debug_print(f" 🧪 分离器设备: '{separator_device}'") + debug_print(f" 🌪️ 搅拌器设备: '{stirrer_device}'") + debug_print(f" 💧 溶剂容器: '{solvent_vessel}'") + + # === 执行分离流程 === + debug_print("🔍 步骤3: 执行分离流程...") + action_sequence.append(create_action_log("开始分离工作流程", "🎯")) + + # 🔧 新增:体积变化跟踪变量 + current_volume = original_liquid_volume + + try: + for repeat_idx in range(repeats): + cycle_num = repeat_idx + 1 + debug_print(f"🔄 第{cycle_num}轮: 开始分离循环 {cycle_num}/{repeats}") + action_sequence.append(create_action_log(f"分离循环 {cycle_num}/{repeats} 开始", "🔄")) + + # 步骤3.1: 添加溶剂(如果需要) + if solvent_vessel and final_volume > 0: + debug_print(f"🔄 第{cycle_num}轮 步骤1: 添加溶剂 {solvent} ({final_volume}mL)") + action_sequence.append(create_action_log(f"向分离容器添加 {final_volume}mL {solvent}", "💧")) + + try: + # 使用pump protocol添加溶剂 + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=solvent_vessel, + to_vessel=final_vessel_id, # 🔧 使用 final_vessel_id + volume=final_volume, + amount="", + time=0.0, + viscous=False, + rinsing_solvent="", + rinsing_volume=0.0, + rinsing_repeats=0, + solid=False, + flowrate=2.5, + transfer_flowrate=0.5, + rate_spec="", + event="", + through="", + **kwargs + ) + action_sequence.extend(pump_actions) + debug_print(f"✅ 溶剂添加完成,添加了 {len(pump_actions)} 个动作") + action_sequence.append(create_action_log(f"溶剂转移完成 ({len(pump_actions)} 个操作)", "✅")) + + # 🔧 新增:更新体积 - 添加溶剂后 + current_volume += final_volume + update_vessel_volume(vessel, G, current_volume, f"添加{final_volume}mL {solvent}后") + + except Exception as e: + debug_print(f"❌ 溶剂添加失败: {str(e)}") + action_sequence.append(create_action_log(f"溶剂添加失败: {str(e)}", "❌")) + else: + debug_print(f"🔄 第{cycle_num}轮 步骤1: 无需添加溶剂") + action_sequence.append(create_action_log("无需添加溶剂", "⏭️")) + + # 步骤3.2: 启动搅拌(如果有搅拌器) + if stirrer_device and stir_time > 0: + debug_print(f"🔄 第{cycle_num}轮 步骤2: 开始搅拌 ({stir_speed}rpm,持续 {stir_time}s)") + action_sequence.append(create_action_log(f"开始搅拌: {stir_speed}rpm,持续 {stir_time}s", "🌪️")) + + action_sequence.append({ + "device_id": stirrer_device, + "action_name": "start_stir", + "action_kwargs": { + "vessel": final_vessel_id, # 🔧 使用 final_vessel_id + "stir_speed": stir_speed, + "purpose": f"分离混合 - {purpose}" + } + }) + + # 搅拌等待 + stir_minutes = stir_time / 60 + action_sequence.append(create_action_log(f"搅拌中,持续 {stir_minutes:.1f} 分钟", "⏱️")) + action_sequence.append({ + "action_name": "wait", + "action_kwargs": {"time": stir_time} + }) + + # 停止搅拌 + action_sequence.append(create_action_log("停止搅拌器", "🛑")) + action_sequence.append({ + "device_id": stirrer_device, + "action_name": "stop_stir", + "action_kwargs": {"vessel": final_vessel_id} # 🔧 使用 final_vessel_id + }) + + else: + debug_print(f"🔄 第{cycle_num}轮 步骤2: 无需搅拌") + action_sequence.append(create_action_log("无需搅拌", "⏭️")) + + # 步骤3.3: 静置分层 + if settling_time > 0: + debug_print(f"🔄 第{cycle_num}轮 步骤3: 静置分层 ({settling_time}s)") + settling_minutes = settling_time / 60 + action_sequence.append(create_action_log(f"静置分层 ({settling_minutes:.1f} 分钟)", "⚖️")) + action_sequence.append({ + "action_name": "wait", + "action_kwargs": {"time": settling_time} + }) + else: + debug_print(f"🔄 第{cycle_num}轮 步骤3: 未指定静置时间") + action_sequence.append(create_action_log("未指定静置时间", "⏭️")) + + # 步骤3.4: 执行分离操作 + if separator_device: + debug_print(f"🔄 第{cycle_num}轮 步骤4: 执行分离操作") + action_sequence.append(create_action_log(f"执行分离: 收集{product_phase}相", "🧪")) + + # 🔧 替换为具体的分离操作逻辑(基于old版本) + + # 首先进行分液判断(电导突跃) + action_sequence.append({ + "device_id": separator_device, + "action_name": "valve_open", + "action_kwargs": { + "command": "delta > 0.05" + } + }) + + # 估算每相的体积(假设大致平分) + phase_volume = current_volume / 2 + + # 智能查找分离容器底部 + separation_vessel_bottom = find_separation_vessel_bottom(G, final_vessel_id) # ✅ + + if product_phase == "bottom": + debug_print(f"🔄 收集底相产物到 {final_to_vessel_id}") + action_sequence.append(create_action_log("收集底相产物", "📦")) + + # 产物转移到目标瓶 + if final_to_vessel_id: + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=separation_vessel_bottom, + to_vessel=final_to_vessel_id, + volume=current_volume, + flowrate=2.5, + **kwargs + ) + action_sequence.extend(pump_actions) + + # 放出上面那一相,60秒后关阀门 + action_sequence.append({ + "device_id": separator_device, + "action_name": "valve_open", + "action_kwargs": { + "command": "time > 60" + } + }) + + # 弃去上面那一相进废液 + if final_waste_vessel_id: + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=separation_vessel_bottom, + to_vessel=final_waste_vessel_id, + volume=current_volume, + flowrate=2.5, + **kwargs + ) + action_sequence.extend(pump_actions) + + elif product_phase == "top": + debug_print(f"🔄 收集上相产物到 {final_to_vessel_id}") + action_sequence.append(create_action_log("收集上相产物", "📦")) + + # 弃去下面那一相进废液 + if final_waste_vessel_id: + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=separation_vessel_bottom, + to_vessel=final_waste_vessel_id, + volume=phase_volume, + flowrate=2.5, + **kwargs + ) + action_sequence.extend(pump_actions) + + # 放出上面那一相,60秒后关阀门 + action_sequence.append({ + "device_id": separator_device, + "action_name": "valve_open", + "action_kwargs": { + "command": "time > 60" + } + }) + + # 产物转移到目标瓶 + if final_to_vessel_id: + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=separation_vessel_bottom, + to_vessel=final_to_vessel_id, + volume=phase_volume, + flowrate=2.5, + **kwargs + ) + action_sequence.extend(pump_actions) + + debug_print(f"✅ 分离操作已完成") + action_sequence.append(create_action_log("分离操作完成", "✅")) + + # 🔧 新增:分离后体积估算 + separated_volume = phase_volume * 0.95 # 假设5%损失,只保留产物相体积 + update_vessel_volume(vessel, G, separated_volume, f"分离操作后(第{cycle_num}轮)") + current_volume = separated_volume + + # 收集结果 + if final_to_vessel_id: + action_sequence.append( + create_action_log(f"产物 ({product_phase}相) 收集到: {final_to_vessel_id}", "📦")) + if final_waste_vessel_id: + action_sequence.append(create_action_log(f"废相收集到: {final_waste_vessel_id}", "🗑️")) + + else: + debug_print(f"🔄 第{cycle_num}轮 步骤4: 无分离器设备,跳过分离") + action_sequence.append(create_action_log("无分离器设备可用", "❌")) + # 添加等待时间模拟分离 + action_sequence.append({ + "action_name": "wait", + "action_kwargs": {"time": 10.0} + }) + + # 🔧 新增:如果不是最后一次,从中转瓶转移回分液漏斗(基于old版本逻辑) + if repeat_idx < repeats - 1 and final_to_vessel_id and final_to_vessel_id != final_vessel_id: + debug_print(f"🔄 第{cycle_num}轮: 产物转移回分离容器准备下一轮") + action_sequence.append(create_action_log("产物转回分离容器,准备下一轮", "🔄")) + + pump_actions = generate_pump_protocol_with_rinsing( + G=G, + from_vessel=final_to_vessel_id, + to_vessel=final_vessel_id, + volume=current_volume, + flowrate=2.5, + **kwargs + ) + action_sequence.extend(pump_actions) + + # 更新体积回到分离容器 + update_vessel_volume(vessel, G, current_volume, f"产物转回分离容器(第{cycle_num}轮后)") + + # 循环间等待(除了最后一次) + if repeat_idx < repeats - 1: + debug_print(f"🔄 第{cycle_num}轮: 等待下一次循环...") + action_sequence.append(create_action_log("等待下一次循环...", "⏳")) + action_sequence.append({ + "action_name": "wait", + "action_kwargs": {"time": 5} + }) + else: + action_sequence.append(create_action_log(f"分离循环 {cycle_num}/{repeats} 完成", "🌟")) + + except Exception as e: + debug_print(f"❌ 分离工作流程执行失败: {str(e)}") + action_sequence.append(create_action_log(f"分离工作流程失败: {str(e)}", "❌")) + + # 🔧 新增:分离完成后的最终状态报告 + final_liquid_volume = get_vessel_liquid_volume(vessel) + + # === 最终结果 === + total_time = (stir_time + settling_time + 15) * repeats # 估算总时间 + + debug_print("🌀" * 20) + debug_print(f"🎉 分离协议生成完成") + debug_print(f"📊 协议统计:") + debug_print(f" 📋 总动作数: {len(action_sequence)}") + debug_print(f" ⏱️ 预计总时间: {total_time:.0f}s ({total_time / 60:.1f} 分钟)") + debug_print(f" 🥼 分离容器: {final_vessel_id}") + debug_print(f" 🎯 分离目的: {purpose}") + debug_print(f" 📊 产物相: {product_phase}") + debug_print(f" 🔄 重复次数: {repeats}") + debug_print(f"💧 体积变化统计:") + debug_print(f" - 分离前体积: {original_liquid_volume:.2f}mL") + debug_print(f" - 分离后体积: {final_liquid_volume:.2f}mL") + if solvent: + debug_print(f" 💧 溶剂: {solvent} ({final_volume}mL × {repeats}轮 = {final_volume * repeats:.2f}mL)") + if final_to_vessel_id: + debug_print(f" 🎯 产物容器: {final_to_vessel_id}") + if final_waste_vessel_id: + debug_print(f" 🗑️ 废液容器: {final_waste_vessel_id}") + debug_print("🌀" * 20) + + # 添加完成日志 + summary_msg = f"分离协议完成: {final_vessel_id} ({purpose},{repeats} 次循环)" + if solvent: + summary_msg += f",使用 {final_volume * repeats:.2f}mL {solvent}" + action_sequence.append(create_action_log(summary_msg, "🎉")) + + return action_sequence + def parse_volume_input(volume_input: Union[str, float]) -> float: """ 解析体积输入,支持带单位的字符串 @@ -364,386 +820,54 @@ def update_vessel_volume(vessel: dict, G: nx.DiGraph, new_volume: float, descrip debug_print(f"📊 容器 '{vessel_id}' 体积已更新为: {new_volume:.2f}mL") -def generate_separate_protocol( - G: nx.DiGraph, - # 🔧 基础参数,支持XDL的vessel参数 - vessel: dict = None, # 🔧 修改:从字符串改为字典类型 - purpose: str = "separate", # 分离目的 - product_phase: str = "top", # 产物相 - # 🔧 可选的详细参数 - from_vessel: Union[str, dict] = "", # 源容器(通常在separate前已经transfer了) - separation_vessel: Union[str, dict] = "", # 分离容器(与vessel同义) - to_vessel: Union[str, dict] = "", # 目标容器(可选) - waste_phase_to_vessel: Union[str, dict] = "", # 废相目标容器 - product_vessel: Union[str, dict] = "", # XDL: 产物容器(与to_vessel同义) - waste_vessel: Union[str, dict] = "", # XDL: 废液容器(与waste_phase_to_vessel同义) - # 🔧 溶剂相关参数 - solvent: str = "", # 溶剂名称 - solvent_volume: Union[str, float] = 0.0, # 溶剂体积 - volume: Union[str, float] = 0.0, # XDL: 体积(与solvent_volume同义) - # 🔧 操作参数 - through: str = "", # 通过材料 - repeats: int = 1, # 重复次数 - stir_time: float = 30.0, # 搅拌时间(秒) - stir_speed: float = 300.0, # 搅拌速度 - settling_time: float = 300.0, # 沉降时间(秒) - **kwargs -) -> List[Dict[str, Any]]: - """ - 生成分离操作的协议序列 - 支持vessel字典和体积运算 - - 支持XDL参数格式: - - vessel: 分离容器字典(必需) - - purpose: "wash", "extract", "separate" - - product_phase: "top", "bottom" - - product_vessel: 产物收集容器 - - waste_vessel: 废液收集容器 - - solvent: 溶剂名称 - - volume: "200 mL", "?" 或数值 - - repeats: 重复次数 - - 分离流程: - 1. (可选)添加溶剂到分离容器 - 2. 搅拌混合 - 3. 静置分层 - 4. 收集指定相到目标容器 - 5. 重复指定次数 - """ - - # 🔧 核心修改:vessel参数兼容处理 - if vessel is None: - if isinstance(separation_vessel, dict): - vessel = separation_vessel - else: - raise ValueError("必须提供vessel字典参数") - - # 🔧 核心修改:从字典中提取容器ID - # 统一处理vessel参数 - if isinstance(vessel, dict): - if "id" not in vessel: - vessel_id = list(vessel.values())[0].get("id", "") - else: - vessel_id = vessel.get("id", "") - vessel_data = vessel.get("data", {}) - else: - vessel_id = str(vessel) - vessel_data = G.nodes[vessel_id].get("data", {}) if vessel_id in G.nodes() else {} - - debug_print("🌀" * 20) - debug_print("🚀 开始生成分离协议(支持vessel字典和体积运算)✨") - debug_print(f"📝 输入参数:") - debug_print(f" 🥽 vessel: {vessel} (ID: {vessel_id})") - debug_print(f" 🎯 分离目的: '{purpose}'") - debug_print(f" 📊 产物相: '{product_phase}'") - debug_print(f" 💧 溶剂: '{solvent}'") - debug_print(f" 📏 体积: {volume} (类型: {type(volume)})") - debug_print(f" 🔄 重复次数: {repeats}") - debug_print(f" 🎯 产物容器: '{product_vessel}'") - debug_print(f" 🗑️ 废液容器: '{waste_vessel}'") - debug_print(f" 📦 其他参数: {kwargs}") - debug_print("🌀" * 20) - - action_sequence = [] - - # 🔧 新增:记录分离前的容器状态 - debug_print("🔍 记录分离前容器状态...") - original_liquid_volume = get_vessel_liquid_volume(vessel) - debug_print(f"📊 分离前液体体积: {original_liquid_volume:.2f}mL") - - # === 参数验证和标准化 === - debug_print("🔍 步骤1: 参数验证和标准化...") - action_sequence.append(create_action_log(f"开始分离操作 - 容器: {vessel_id}", "🎬")) - action_sequence.append(create_action_log(f"分离目的: {purpose}", "🧪")) - action_sequence.append(create_action_log(f"产物相: {product_phase}", "📊")) - - # 统一容器参数 - 支持字典和字符串 - def extract_vessel_id(vessel_param): - if isinstance(vessel_param, dict): - return vessel_param.get("id", "") - elif isinstance(vessel_param, str): - return vessel_param - else: - return "" - - final_vessel_id = vessel_id - final_to_vessel_id = extract_vessel_id(to_vessel) or extract_vessel_id(product_vessel) - final_waste_vessel_id = extract_vessel_id(waste_phase_to_vessel) or extract_vessel_id(waste_vessel) - - # 统一体积参数 - final_volume = parse_volume_input(volume or solvent_volume) - - # 🔧 修复:确保repeats至少为1 - if repeats <= 0: - repeats = 1 - debug_print(f"⚠️ 重复次数参数 <= 0,自动设置为 1") - - debug_print(f"🔧 标准化后的参数:") - debug_print(f" 🥼 分离容器: '{final_vessel_id}'") - debug_print(f" 🎯 产物容器: '{final_to_vessel_id}'") - debug_print(f" 🗑️ 废液容器: '{final_waste_vessel_id}'") - debug_print(f" 📏 溶剂体积: {final_volume}mL") - debug_print(f" 🔄 重复次数: {repeats}") - - action_sequence.append(create_action_log(f"分离容器: {final_vessel_id}", "🧪")) - action_sequence.append(create_action_log(f"溶剂体积: {final_volume}mL", "📏")) - action_sequence.append(create_action_log(f"重复次数: {repeats}", "🔄")) - - # 验证必需参数 - if not purpose: - purpose = "separate" - if not product_phase: - product_phase = "top" - if purpose not in ["wash", "extract", "separate"]: - debug_print(f"⚠️ 未知的分离目的 '{purpose}',使用默认值 'separate'") - purpose = "separate" - action_sequence.append(create_action_log(f"未知目的,使用: {purpose}", "⚠️")) - if product_phase not in ["top", "bottom"]: - debug_print(f"⚠️ 未知的产物相 '{product_phase}',使用默认值 'top'") - product_phase = "top" - action_sequence.append(create_action_log(f"未知相别,使用: {product_phase}", "⚠️")) - - debug_print("✅ 参数验证通过") - action_sequence.append(create_action_log("参数验证通过", "✅")) - - # === 查找设备 === - debug_print("🔍 步骤2: 查找设备...") - action_sequence.append(create_action_log("正在查找相关设备...", "🔍")) - - # 查找分离器设备 - separator_device = find_separator_device(G, final_vessel_id) # 🔧 使用 final_vessel_id - if separator_device: - action_sequence.append(create_action_log(f"找到分离器设备: {separator_device}", "🧪")) - else: - debug_print("⚠️ 未找到分离器设备,可能无法执行分离") - action_sequence.append(create_action_log("未找到分离器设备", "⚠️")) - - # 查找搅拌器 - stirrer_device = find_connected_stirrer(G, final_vessel_id) # 🔧 使用 final_vessel_id - if stirrer_device: - action_sequence.append(create_action_log(f"找到搅拌器: {stirrer_device}", "🌪️")) - else: - action_sequence.append(create_action_log("未找到搅拌器", "⚠️")) - - # 查找溶剂容器(如果需要) - solvent_vessel = "" - if solvent and solvent.strip(): - solvent_vessel = find_solvent_vessel(G, solvent) - if solvent_vessel: - action_sequence.append(create_action_log(f"找到溶剂容器: {solvent_vessel}", "💧")) - else: - action_sequence.append(create_action_log(f"未找到溶剂容器: {solvent}", "⚠️")) - - debug_print(f"📊 设备配置:") - debug_print(f" 🧪 分离器设备: '{separator_device}'") - debug_print(f" 🌪️ 搅拌器设备: '{stirrer_device}'") - debug_print(f" 💧 溶剂容器: '{solvent_vessel}'") - - # === 执行分离流程 === - debug_print("🔍 步骤3: 执行分离流程...") - action_sequence.append(create_action_log("开始分离工作流程", "🎯")) - - # 🔧 新增:体积变化跟踪变量 - current_volume = original_liquid_volume - - try: - for repeat_idx in range(repeats): - cycle_num = repeat_idx + 1 - debug_print(f"🔄 第{cycle_num}轮: 开始分离循环 {cycle_num}/{repeats}") - action_sequence.append(create_action_log(f"分离循环 {cycle_num}/{repeats} 开始", "🔄")) - - # 步骤3.1: 添加溶剂(如果需要) - if solvent_vessel and final_volume > 0: - debug_print(f"🔄 第{cycle_num}轮 步骤1: 添加溶剂 {solvent} ({final_volume}mL)") - action_sequence.append(create_action_log(f"向分离容器添加 {final_volume}mL {solvent}", "💧")) - - try: - # 使用pump protocol添加溶剂 - pump_actions = generate_pump_protocol_with_rinsing( - G=G, - from_vessel=solvent_vessel, - to_vessel=final_vessel_id, # 🔧 使用 final_vessel_id - volume=final_volume, - amount="", - time=0.0, - viscous=False, - rinsing_solvent="", - rinsing_volume=0.0, - rinsing_repeats=0, - solid=False, - flowrate=2.5, - transfer_flowrate=0.5, - rate_spec="", - event="", - through="", - **kwargs - ) - action_sequence.extend(pump_actions) - debug_print(f"✅ 溶剂添加完成,添加了 {len(pump_actions)} 个动作") - action_sequence.append(create_action_log(f"溶剂转移完成 ({len(pump_actions)} 个操作)", "✅")) - - # 🔧 新增:更新体积 - 添加溶剂后 - current_volume += final_volume - update_vessel_volume(vessel, G, current_volume, f"添加{final_volume}mL {solvent}后") - - except Exception as e: - debug_print(f"❌ 溶剂添加失败: {str(e)}") - action_sequence.append(create_action_log(f"溶剂添加失败: {str(e)}", "❌")) - else: - debug_print(f"🔄 第{cycle_num}轮 步骤1: 无需添加溶剂") - action_sequence.append(create_action_log("无需添加溶剂", "⏭️")) - - # 步骤3.2: 启动搅拌(如果有搅拌器) - if stirrer_device and stir_time > 0: - debug_print(f"🔄 第{cycle_num}轮 步骤2: 开始搅拌 ({stir_speed}rpm,持续 {stir_time}s)") - action_sequence.append(create_action_log(f"开始搅拌: {stir_speed}rpm,持续 {stir_time}s", "🌪️")) - - action_sequence.append({ - "device_id": stirrer_device, - "action_name": "start_stir", - "action_kwargs": { - "vessel": final_vessel_id, # 🔧 使用 final_vessel_id - "stir_speed": stir_speed, - "purpose": f"分离混合 - {purpose}" - } - }) - - # 搅拌等待 - stir_minutes = stir_time / 60 - action_sequence.append(create_action_log(f"搅拌中,持续 {stir_minutes:.1f} 分钟", "⏱️")) - action_sequence.append({ - "action_name": "wait", - "action_kwargs": {"time": stir_time} - }) - - # 停止搅拌 - action_sequence.append(create_action_log("停止搅拌器", "🛑")) - action_sequence.append({ - "device_id": stirrer_device, - "action_name": "stop_stir", - "action_kwargs": {"vessel": final_vessel_id} # 🔧 使用 final_vessel_id - }) - - else: - debug_print(f"🔄 第{cycle_num}轮 步骤2: 无需搅拌") - action_sequence.append(create_action_log("无需搅拌", "⏭️")) - - # 步骤3.3: 静置分层 - if settling_time > 0: - debug_print(f"🔄 第{cycle_num}轮 步骤3: 静置分层 ({settling_time}s)") - settling_minutes = settling_time / 60 - action_sequence.append(create_action_log(f"静置分层 ({settling_minutes:.1f} 分钟)", "⚖️")) - action_sequence.append({ - "action_name": "wait", - "action_kwargs": {"time": settling_time} - }) - else: - debug_print(f"🔄 第{cycle_num}轮 步骤3: 未指定静置时间") - action_sequence.append(create_action_log("未指定静置时间", "⏭️")) - - # 步骤3.4: 执行分离操作 - if separator_device: - debug_print(f"🔄 第{cycle_num}轮 步骤4: 执行分离操作") - action_sequence.append(create_action_log(f"执行分离: 收集{product_phase}相", "🧪")) - - # 调用分离器设备的separate方法 - separate_action = { - "device_id": separator_device, - "action_name": "separate", - "action_kwargs": { - "purpose": purpose, - "product_phase": product_phase, - "from_vessel": extract_vessel_id(from_vessel) or final_vessel_id, # 🔧 使用vessel_id - "separation_vessel": final_vessel_id, # 🔧 使用 final_vessel_id - "to_vessel": final_to_vessel_id or final_vessel_id, # 🔧 使用vessel_id - "waste_phase_to_vessel": final_waste_vessel_id or final_vessel_id, # 🔧 使用vessel_id - "solvent": solvent, - "solvent_volume": final_volume, - "through": through, - "repeats": 1, # 每次调用只做一次分离 - "stir_time": 0, # 已经在上面完成 - "stir_speed": stir_speed, - "settling_time": 0 # 已经在上面完成 - } - } - action_sequence.append(separate_action) - debug_print(f"✅ 分离操作已添加") - action_sequence.append(create_action_log("分离操作完成", "✅")) - - # 🔧 新增:分离后体积估算(分离通常不改变总体积,但会重新分配) - # 假设分离后保持体积(实际情况可能有少量损失) - separated_volume = current_volume * 0.95 # 假设5%损失 - update_vessel_volume(vessel, G, separated_volume, f"分离操作后(第{cycle_num}轮)") - current_volume = separated_volume - - # 收集结果 - if final_to_vessel_id: - action_sequence.append(create_action_log(f"产物 ({product_phase}相) 收集到: {final_to_vessel_id}", "📦")) - if final_waste_vessel_id: - action_sequence.append(create_action_log(f"废相收集到: {final_waste_vessel_id}", "🗑️")) - - else: - debug_print(f"🔄 第{cycle_num}轮 步骤4: 无分离器设备,跳过分离") - action_sequence.append(create_action_log("无分离器设备可用", "❌")) - # 添加等待时间模拟分离 - action_sequence.append({ - "action_name": "wait", - "action_kwargs": {"time": 10.0} - }) - - # 循环间等待(除了最后一次) - if repeat_idx < repeats - 1: - debug_print(f"🔄 第{cycle_num}轮: 等待下一次循环...") - action_sequence.append(create_action_log("等待下一次循环...", "⏳")) - action_sequence.append({ - "action_name": "wait", - "action_kwargs": {"time": 5} - }) - else: - action_sequence.append(create_action_log(f"分离循环 {cycle_num}/{repeats} 完成", "🌟")) - - except Exception as e: - debug_print(f"❌ 分离工作流程执行失败: {str(e)}") - action_sequence.append(create_action_log(f"分离工作流程失败: {str(e)}", "❌")) - # 添加错误日志 - action_sequence.append({ - "device_id": "system", - "action_name": "log_message", - "action_kwargs": { - "message": f"分离操作失败: {str(e)}" - } - }) - - # 🔧 新增:分离完成后的最终状态报告 - final_liquid_volume = get_vessel_liquid_volume(vessel) - - # === 最终结果 === - total_time = (stir_time + settling_time + 15) * repeats # 估算总时间 - - debug_print("🌀" * 20) - debug_print(f"🎉 分离协议生成完成") - debug_print(f"📊 协议统计:") - debug_print(f" 📋 总动作数: {len(action_sequence)}") - debug_print(f" ⏱️ 预计总时间: {total_time:.0f}s ({total_time/60:.1f} 分钟)") - debug_print(f" 🥼 分离容器: {final_vessel_id}") - debug_print(f" 🎯 分离目的: {purpose}") - debug_print(f" 📊 产物相: {product_phase}") - debug_print(f" 🔄 重复次数: {repeats}") - debug_print(f"💧 体积变化统计:") - debug_print(f" - 分离前体积: {original_liquid_volume:.2f}mL") - debug_print(f" - 分离后体积: {final_liquid_volume:.2f}mL") - if solvent: - debug_print(f" 💧 溶剂: {solvent} ({final_volume}mL × {repeats}轮 = {final_volume * repeats:.2f}mL)") - if final_to_vessel_id: - debug_print(f" 🎯 产物容器: {final_to_vessel_id}") - if final_waste_vessel_id: - debug_print(f" 🗑️ 废液容器: {final_waste_vessel_id}") - debug_print("🌀" * 20) - - # 添加完成日志 - summary_msg = f"分离协议完成: {final_vessel_id} ({purpose},{repeats} 次循环)" - if solvent: - summary_msg += f",使用 {final_volume * repeats:.2f}mL {solvent}" - action_sequence.append(create_action_log(summary_msg, "🎉")) - - return action_sequence + +def find_separation_vessel_bottom(G: nx.DiGraph, vessel_id: str) -> str: + """ + 智能查找分离容器的底部容器(假设为flask或vessel类型) + + Args: + G: 网络图 + vessel_id: 分离容器ID + + Returns: + str: 底部容器ID + """ + debug_print(f"🔍 查找分离容器 {vessel_id} 的底部容器...") + + # 方法1:根据命名规则推测 + possible_bottoms = [ + f"{vessel_id}_bottom", + f"flask_{vessel_id}", + f"vessel_{vessel_id}", + f"{vessel_id}_flask", + f"{vessel_id}_vessel" + ] + + debug_print(f"📋 尝试的底部容器名称: {possible_bottoms}") + + for bottom_id in possible_bottoms: + if bottom_id in G.nodes(): + node_type = G.nodes[bottom_id].get('type', '') + if node_type == 'container': + debug_print(f"✅ 通过命名规则找到底部容器: {bottom_id}") + return bottom_id + + # 方法2:查找与分离器相连的容器(假设底部容器会与分离器相连) + debug_print(f"📋 方法2: 查找连接的容器...") + for node in G.nodes(): + node_data = G.nodes[node] + node_class = node_data.get('class', '') or '' + + if 'separator' in node_class.lower(): + # 检查分离器的输入端 + if G.has_edge(node, vessel_id): + for neighbor in G.neighbors(node): + if neighbor != vessel_id: + neighbor_type = G.nodes[neighbor].get('type', '') + if neighbor_type == 'container': + debug_print(f"✅ 通过连接找到底部容器: {neighbor}") + return neighbor + + debug_print(f"❌ 无法找到分离容器 {vessel_id} 的底部容器") + return "" diff --git a/unilabos/devices/mock/__init__.py b/unilabos/compile/utils/__init__.py similarity index 100% rename from unilabos/devices/mock/__init__.py rename to unilabos/compile/utils/__init__.py diff --git a/unilabos/compile/utils/vessel_parser.py b/unilabos/compile/utils/vessel_parser.py new file mode 100644 index 00000000..01275816 --- /dev/null +++ b/unilabos/compile/utils/vessel_parser.py @@ -0,0 +1,20 @@ +def get_vessel(vessel): + """ + 统一处理vessel参数,返回vessel_id和vessel_data。 + + Args: + vessel: 可以是一个字典或字符串,表示vessel的ID或数据。 + + Returns: + tuple: 包含vessel_id和vessel_data。 + """ + if isinstance(vessel, dict): + if "id" not in vessel: + vessel_id = list(vessel.values())[0].get("id", "") + else: + vessel_id = vessel.get("id", "") + vessel_data = vessel.get("data", {}) + else: + vessel_id = str(vessel) + vessel_data = {} + return vessel_id, vessel_data diff --git a/unilabos/devices/mock/mock_chiller.py b/unilabos/devices/mock/mock_chiller.py deleted file mode 100644 index fbb823c9..00000000 --- a/unilabos/devices/mock/mock_chiller.py +++ /dev/null @@ -1,177 +0,0 @@ -import time -import threading - - -class MockChiller: - def __init__(self, port: str = "MOCK"): - self.port = port - self._current_temperature: float = 25.0 # 室温开始 - self._target_temperature: float = 25.0 - self._status: str = "Idle" - self._is_cooling: bool = False - self._is_heating: bool = False - self._vessel = "Unknown" - self._purpose = "Unknown" - - # 模拟温度变化的线程 - self._temperature_thread = None - self._running = True - self._temperature_thread = threading.Thread(target=self._temperature_control_loop) - self._temperature_thread.daemon = True - self._temperature_thread.start() - - @property - def current_temperature(self) -> float: - """当前温度 - 会被自动识别的设备属性""" - return self._current_temperature - - @property - def target_temperature(self) -> float: - """目标温度""" - return self._target_temperature - - @property - def status(self) -> str: - """设备状态 - 会被自动识别的设备属性""" - return self._status - - @property - def is_cooling(self) -> bool: - """是否正在冷却""" - return self._is_cooling - - @property - def is_heating(self) -> bool: - """是否正在加热""" - return self._is_heating - - @property - def vessel(self) -> str: - """当前操作的容器名称""" - return self._vessel - - @property - def purpose(self) -> str: - """当前操作目的""" - return self._purpose - - def heat_chill_start(self, vessel: str, temp: float, purpose: str): - """设置目标温度并记录容器和目的""" - self._vessel = str(vessel) - self._purpose = str(purpose) - self._target_temperature = float(temp) - - diff = self._target_temperature - self._current_temperature - if abs(diff) < 0.1: - self._status = "At Target Temperature" - self._is_cooling = False - self._is_heating = False - elif diff < 0: - self._status = "Cooling" - self._is_cooling = True - self._is_heating = False - else: - self._status = "Heating" - self._is_heating = True - self._is_cooling = False - - self._start_temperature_control() - return True - - def heat_chill_stop(self, vessel: str): - """停止加热/制冷""" - if vessel != self._vessel: - return {"success": False, "status": f"Wrong vessel: expected {self._vessel}, got {vessel}"} - - # 停止温度控制线程,锁定当前温度 - self._stop_temperature_control() - - # 更新状态 - self._status = "Stopped" - self._is_cooling = False - self._is_heating = False - - # 重新启动线程但保持温度 - self._running = True - self._temperature_thread = threading.Thread(target=self._temperature_control_loop) - self._temperature_thread.daemon = True - self._temperature_thread.start() - - return {"success": True, "status": self._status} - - def _start_temperature_control(self): - """启动温度控制线程""" - self._running = True - if self._temperature_thread is None or not self._temperature_thread.is_alive(): - self._temperature_thread = threading.Thread(target=self._temperature_control_loop) - self._temperature_thread.daemon = True - self._temperature_thread.start() - - def _stop_temperature_control(self): - """停止温度控制""" - self._running = False - if self._temperature_thread: - self._temperature_thread.join(timeout=1.0) - - def _temperature_control_loop(self): - """温度控制循环 - 模拟真实冷却器的温度变化""" - while self._running: - # 如果状态是 Stopped,不改变温度 - if self._status == "Stopped": - time.sleep(1.0) - continue - - temp_diff = self._target_temperature - self._current_temperature - - if abs(temp_diff) < 0.1: - self._status = "At Target Temperature" - self._is_cooling = False - self._is_heating = False - elif temp_diff < 0: - self._status = "Cooling" - self._is_cooling = True - self._is_heating = False - self._current_temperature -= 0.5 - else: - self._status = "Heating" - self._is_heating = True - self._is_cooling = False - self._current_temperature += 0.3 - - time.sleep(1.0) - - def emergency_stop(self): - """紧急停止""" - self._status = "Emergency Stop" - self._stop_temperature_control() - self._is_cooling = False - self._is_heating = False - - def get_status_info(self) -> dict: - """获取完整状态信息""" - return { - "current_temperature": self._current_temperature, - "target_temperature": self._target_temperature, - "status": self._status, - "is_cooling": self._is_cooling, - "is_heating": self._is_heating, - "vessel": self._vessel, - "purpose": self._purpose, - } - - -# 用于测试的主函数 -if __name__ == "__main__": - chiller = MockChiller() - - # 测试基本功能 - print("启动冷却器测试...") - print(f"初始状态: {chiller.get_status_info()}") - - # 模拟运行10秒 - for i in range(10): - time.sleep(1) - print(f"第{i+1}秒: 当前温度={chiller.current_temperature:.1f}°C, 状态={chiller.status}") - - chiller.emergency_stop() - print("测试完成") diff --git a/unilabos/devices/mock/mock_filter.py b/unilabos/devices/mock/mock_filter.py deleted file mode 100644 index f54e41ed..00000000 --- a/unilabos/devices/mock/mock_filter.py +++ /dev/null @@ -1,235 +0,0 @@ -import time -import threading - - -class MockFilter: - def __init__(self, port: str = "MOCK"): - # 基本参数初始化 - self.port = port - self._status: str = "Idle" - self._is_filtering: bool = False - - # 过滤性能参数 - self._flow_rate: float = 1.0 # 流速(L/min) - self._pressure_drop: float = 0.0 # 压降(Pa) - self._filter_life: float = 100.0 # 滤芯寿命(%) - - # 过滤操作参数 - self._vessel: str = "" # 源容器 - self._filtrate_vessel: str = "" # 目标容器 - self._stir: bool = False # 是否搅拌 - self._stir_speed: float = 0.0 # 搅拌速度 - self._temperature: float = 25.0 # 温度(℃) - self._continue_heatchill: bool = False # 是否继续加热/制冷 - self._target_volume: float = 0.0 # 目标过滤体积(L) - self._filtered_volume: float = 0.0 # 已过滤体积(L) - self._progress: float = 0.0 # 过滤进度(%) - - # 线程控制 - self._filter_thread = None - self._running = False - - @property - def status(self) -> str: - return self._status - - @property - def is_filtering(self) -> bool: - return self._is_filtering - - @property - def flow_rate(self) -> float: - return self._flow_rate - - @property - def pressure_drop(self) -> float: - return self._pressure_drop - - @property - def filter_life(self) -> float: - return self._filter_life - # 新增 property - @property - def vessel(self) -> str: - return self._vessel - - @property - def filtrate_vessel(self) -> str: - return self._filtrate_vessel - - @property - def filtered_volume(self) -> float: - return self._filtered_volume - - @property - def progress(self) -> float: - return self._progress - - @property - def stir(self) -> bool: - return self._stir - - @property - def stir_speed(self) -> float: - return self._stir_speed - - @property - def temperature(self) -> float: - return self._temperature - - @property - def continue_heatchill(self) -> bool: - return self._continue_heatchill - - @property - def target_volume(self) -> float: - return self._target_volume - - def filter(self, vessel: str, filtrate_vessel: str, stir: bool = False, stir_speed: float = 0.0, temp: float = 25.0, continue_heatchill: bool = False, volume: float = 0.0) -> dict: - """新的过滤操作""" - # 停止任何正在进行的过滤 - if self._is_filtering: - self.stop_filtering() - # 验证参数 - if volume <= 0: - return {"success": False, "message": "Target volume must be greater than 0"} - # 设置新的过滤参数 - self._vessel = vessel - self._filtrate_vessel = filtrate_vessel - self._stir = stir - self._stir_speed = stir_speed - self._temperature = temp - self._continue_heatchill = continue_heatchill - self._target_volume = volume - # 重置过滤状态 - self._filtered_volume = 0.0 - self._progress = 0.0 - self._status = "Starting Filter" - # 启动过滤过程 - self._flow_rate = 1.0 # 设置默认流速 - self._start_filter_process() - - return {"success": True, "message": "Filter started"} - - def stop_filtering(self): - """停止过滤""" - self._status = "Stopping Filter" - self._stop_filter_process() - self._flow_rate = 0.0 - self._is_filtering = False - self._status = "Stopped" - return True - - def replace_filter(self): - """更换滤芯""" - self._filter_life = 100.0 - self._status = "Filter Replaced" - return True - - def _start_filter_process(self): - """启动过滤过程线程""" - if not self._running: - self._running = True - self._is_filtering = True - self._filter_thread = threading.Thread(target=self._filter_loop) - self._filter_thread.daemon = True - self._filter_thread.start() - - def _stop_filter_process(self): - """停止过滤过程""" - self._running = False - if self._filter_thread: - self._filter_thread.join(timeout=1.0) - - def _filter_loop(self): - """过滤进程主循环""" - update_interval = 1.0 # 更新间隔(秒) - - while self._running and self._is_filtering: - try: - self._status = "Filtering" - - # 计算这一秒过滤的体积 (L/min -> L/s) - volume_increment = (self._flow_rate / 60.0) * update_interval - - # 更新已过滤体积 - self._filtered_volume += volume_increment - - # 更新进度 (避免除零错误) - if self._target_volume > 0: - self._progress = min(100.0, (self._filtered_volume / self._target_volume) * 100.0) - - # 更新滤芯寿命 (每过滤1L减少0.5%寿命) - self._filter_life = max(0.0, self._filter_life - (volume_increment * 0.5)) - - # 更新压降 (根据滤芯寿命和流速动态计算) - life_factor = self._filter_life / 100.0 # 将寿命转换为0-1的因子 - flow_factor = self._flow_rate / 2.0 # 将流速标准化(假设2L/min是标准流速) - base_pressure = 100.0 # 基础压降 - # 压降随滤芯寿命降低而增加,随流速增加而增加 - self._pressure_drop = base_pressure * (2 - life_factor) * flow_factor - - # 检查是否完成目标体积 - if self._target_volume > 0 and self._filtered_volume >= self._target_volume: - self._status = "Completed" - self._progress = 100.0 - self.stop_filtering() - break - - # 检查滤芯寿命 - if self._filter_life <= 10.0: - self._status = "Filter Needs Replacement" - - time.sleep(update_interval) - - except Exception as e: - print(f"Error in filter loop: {e}") - self.emergency_stop() - break - - def emergency_stop(self): - """紧急停止""" - self._status = "Emergency Stop" - self._stop_filter_process() - self._is_filtering = False - self._flow_rate = 0.0 - - def get_status_info(self) -> dict: - """扩展的状态信息""" - return { - "status": self._status, - "is_filtering": self._is_filtering, - "flow_rate": self._flow_rate, - "pressure_drop": self._pressure_drop, - "filter_life": self._filter_life, - "vessel": self._vessel, - "filtrate_vessel": self._filtrate_vessel, - "filtered_volume": self._filtered_volume, - "target_volume": self._target_volume, - "progress": self._progress, - "temperature": self._temperature, - "stir": self._stir, - "stir_speed": self._stir_speed - } - - -# 用于测试的主函数 -if __name__ == "__main__": - filter_device = MockFilter() - - # 测试基本功能 - print("启动过滤器测试...") - print(f"初始状态: {filter_device.get_status_info()}") - - - - # 模拟运行10秒 - for i in range(10): - time.sleep(1) - print( - f"第{i+1}秒: " - f"寿命={filter_device.filter_life:.1f}%, 状态={filter_device.status}" - ) - - filter_device.emergency_stop() - print("测试完成") diff --git a/unilabos/devices/mock/mock_heater.py b/unilabos/devices/mock/mock_heater.py deleted file mode 100644 index 47dd8d85..00000000 --- a/unilabos/devices/mock/mock_heater.py +++ /dev/null @@ -1,247 +0,0 @@ -import time -import threading - -class MockHeater: - def __init__(self, port: str = "MOCK"): - self.port = port - self._current_temperature: float = 25.0 # 室温开始 - self._target_temperature: float = 25.0 - self._status: str = "Idle" - self._is_heating: bool = False - self._heating_power: float = 0.0 # 加热功率百分比 0-100 - self._max_temperature: float = 300.0 # 最大加热温度 - - # 新增加的属性 - self._vessel: str = "Unknown" - self._purpose: str = "Unknown" - self._stir: bool = False - self._stir_speed: float = 0.0 - - # 模拟加热过程的线程 - self._heating_thread = None - self._running = True - self._heating_thread = threading.Thread(target=self._heating_control_loop) - self._heating_thread.daemon = True - self._heating_thread.start() - - @property - def current_temperature(self) -> float: - """当前温度 - 会被自动识别的设备属性""" - return self._current_temperature - - @property - def target_temperature(self) -> float: - """目标温度""" - return self._target_temperature - - @property - def status(self) -> str: - """设备状态 - 会被自动识别的设备属性""" - return self._status - - @property - def is_heating(self) -> bool: - """是否正在加热""" - return self._is_heating - - @property - def heating_power(self) -> float: - """加热功率百分比""" - return self._heating_power - - @property - def max_temperature(self) -> float: - """最大加热温度""" - return self._max_temperature - - @property - def vessel(self) -> str: - """当前操作的容器名称""" - return self._vessel - - @property - def purpose(self) -> str: - """操作目的""" - return self._purpose - - @property - def stir(self) -> bool: - """是否搅拌""" - return self._stir - - @property - def stir_speed(self) -> float: - """搅拌速度""" - return self._stir_speed - - def heat_chill_start(self, vessel: str, temp: float, purpose: str) -> dict: - """开始加热/制冷过程""" - self._vessel = str(vessel) - self._purpose = str(purpose) - self._target_temperature = float(temp) - - diff = self._target_temperature - self._current_temperature - if abs(diff) < 0.1: - self._status = "At Target Temperature" - self._is_heating = False - elif diff > 0: - self._status = "Heating" - self._is_heating = True - else: - self._status = "Cooling Down" - self._is_heating = False - - return {"success": True, "status": self._status} - - def heat_chill_stop(self, vessel: str) -> dict: - """停止加热/制冷""" - if vessel != self._vessel: - return {"success": False, "status": f"Wrong vessel: expected {self._vessel}, got {vessel}"} - - self._status = "Stopped" - self._is_heating = False - self._heating_power = 0.0 - - return {"success": True, "status": self._status} - - def heat_chill(self, vessel: str, temp: float, time: float, - stir: bool = False, stir_speed: float = 0.0, - purpose: str = "Unknown") -> dict: - """完整的加热/制冷控制""" - self._vessel = str(vessel) - self._target_temperature = float(temp) - self._purpose = str(purpose) - self._stir = stir - self._stir_speed = stir_speed - - diff = self._target_temperature - self._current_temperature - if abs(diff) < 0.1: - self._status = "At Target Temperature" - self._is_heating = False - elif diff > 0: - self._status = "Heating" - self._is_heating = True - else: - self._status = "Cooling Down" - self._is_heating = False - - return {"success": True, "status": self._status} - - def set_temperature(self, temperature: float): - """设置目标温度 - 需要在注册表添加的设备动作""" - try: - temperature = float(temperature) - except ValueError: - self._status = "Error: Invalid temperature value" - return False - - if temperature > self._max_temperature: - self._status = f"Error: Temperature exceeds maximum ({self._max_temperature}°C)" - return False - - self._target_temperature = temperature - self._status = "Setting Temperature" - - # 启动加热控制 - self._start_heating_control() - return True - - def set_heating_power(self, power: float): - """设置加热功率""" - try: - power = float(power) - except ValueError: - self._status = "Error: Invalid power value" - return False - - self._heating_power = max(0.0, min(100.0, power)) # 限制在0-100% - return True - - def _start_heating_control(self): - """启动加热控制线程""" - if not self._running: - self._running = True - self._heating_thread = threading.Thread(target=self._heating_control_loop) - self._heating_thread.daemon = True - self._heating_thread.start() - - def _stop_heating_control(self): - """停止加热控制""" - self._running = False - if self._heating_thread: - self._heating_thread.join(timeout=1.0) - - def _heating_control_loop(self): - """加热控制循环""" - while self._running: - # 如果状态是 Stopped,不改变温度 - if self._status == "Stopped": - time.sleep(1.0) - continue - - temp_diff = self._target_temperature - self._current_temperature - - if abs(temp_diff) < 0.1: - self._status = "At Target Temperature" - self._is_heating = False - self._heating_power = 10.0 - elif temp_diff > 0: - self._status = "Heating" - self._is_heating = True - self._heating_power = min(100.0, abs(temp_diff) * 2) - self._current_temperature += 0.5 - else: - self._status = "Cooling Down" - self._is_heating = False - self._heating_power = 0.0 - self._current_temperature -= 0.2 - - time.sleep(1.0) - - def emergency_stop(self): - """紧急停止""" - self._status = "Emergency Stop" - self._stop_heating_control() - self._is_heating = False - self._heating_power = 0.0 - - def get_status_info(self) -> dict: - """获取完整状态信息""" - return { - "current_temperature": self._current_temperature, - "target_temperature": self._target_temperature, - "status": self._status, - "is_heating": self._is_heating, - "heating_power": self._heating_power, - "max_temperature": self._max_temperature, - "vessel": self._vessel, - "purpose": self._purpose, - "stir": self._stir, - "stir_speed": self._stir_speed - } - -# 用于测试的主函数 -if __name__ == "__main__": - heater = MockHeater() - - print("启动加热器测试...") - print(f"初始状态: {heater.get_status_info()}") - - # 设置目标温度为80度 - heater.set_temperature(80.0) - - # 模拟运行15秒 - try: - for i in range(15): - time.sleep(1) - status = heater.get_status_info() - print( - f"\r温度: {status['current_temperature']:.1f}°C / {status['target_temperature']:.1f}°C | " - f"功率: {status['heating_power']:.1f}% | 状态: {status['status']}", - end="" - ) - except KeyboardInterrupt: - heater.emergency_stop() - print("\n测试被手动停止") - - print("\n测试完成") \ No newline at end of file diff --git a/unilabos/devices/mock/mock_pump.py b/unilabos/devices/mock/mock_pump.py deleted file mode 100644 index 43cbf007..00000000 --- a/unilabos/devices/mock/mock_pump.py +++ /dev/null @@ -1,360 +0,0 @@ -import time -import threading -from datetime import datetime, timedelta - -class MockPump: - def __init__(self, port: str = "MOCK"): - self.port = port - - # 设备基本状态属性 - self._current_device = "MockPump1" # 设备标识符 - self._status: str = "Idle" # 设备状态:Idle, Running, Error, Stopped - self._pump_state: str = "Stopped" # 泵运行状态:Running, Stopped, Paused - - # 流量相关属性 - self._flow_rate: float = 0.0 # 当前流速 (mL/min) - self._target_flow_rate: float = 0.0 # 目标流速 (mL/min) - self._max_flow_rate: float = 100.0 # 最大流速 (mL/min) - self._total_volume: float = 0.0 # 累计流量 (mL) - - # 压力相关属性 - self._pressure: float = 0.0 # 当前压力 (bar) - self._max_pressure: float = 10.0 # 最大压力 (bar) - - # 运行控制线程 - self._pump_thread = None - self._running = False - self._thread_lock = threading.Lock() - - # 新增 PumpTransfer 相关属性 - self._from_vessel: str = "" - self._to_vessel: str = "" - self._transfer_volume: float = 0.0 - self._amount: str = "" - self._transfer_time: float = 0.0 - self._is_viscous: bool = False - self._rinsing_solvent: str = "" - self._rinsing_volume: float = 0.0 - self._rinsing_repeats: int = 0 - self._is_solid: bool = False - - # 时间追踪 - self._start_time: datetime = None - self._time_spent: timedelta = timedelta() - self._time_remaining: timedelta = timedelta() - - # ==================== 状态属性 ==================== - # 这些属性会被Uni-Lab系统自动识别并定时对外广播 - - @property - def status(self) -> str: - return self._status - - @property - def current_device(self) -> str: - """当前设备标识符""" - return self._current_device - - @property - def pump_state(self) -> str: - return self._pump_state - - @property - def flow_rate(self) -> float: - return self._flow_rate - - @property - def target_flow_rate(self) -> float: - return self._target_flow_rate - - @property - def pressure(self) -> float: - return self._pressure - - @property - def total_volume(self) -> float: - return self._total_volume - - @property - def max_flow_rate(self) -> float: - return self._max_flow_rate - - @property - def max_pressure(self) -> float: - return self._max_pressure - - # 添加新的属性访问器 - @property - def from_vessel(self) -> str: - return self._from_vessel - - @property - def to_vessel(self) -> str: - return self._to_vessel - - @property - def transfer_volume(self) -> float: - return self._transfer_volume - - @property - def amount(self) -> str: - return self._amount - - @property - def transfer_time(self) -> float: - return self._transfer_time - - @property - def is_viscous(self) -> bool: - return self._is_viscous - - @property - def rinsing_solvent(self) -> str: - return self._rinsing_solvent - - @property - def rinsing_volume(self) -> float: - return self._rinsing_volume - - @property - def rinsing_repeats(self) -> int: - return self._rinsing_repeats - - @property - def is_solid(self) -> bool: - return self._is_solid - - # 修改这两个属性装饰器 - @property - def time_spent(self) -> float: - """已用时间(秒)""" - if isinstance(self._time_spent, timedelta): - return self._time_spent.total_seconds() - return float(self._time_spent) - - @property - def time_remaining(self) -> float: - """剩余时间(秒)""" - if isinstance(self._time_remaining, timedelta): - return self._time_remaining.total_seconds() - return float(self._time_remaining) - - # ==================== 设备控制方法 ==================== - # 这些方法需要在注册表中添加,会作为ActionServer接受控制指令 - def pump_transfer(self, from_vessel: str, to_vessel: str, volume: float, - amount: str = "", time: float = 0.0, viscous: bool = False, - rinsing_solvent: str = "", rinsing_volume: float = 0.0, - rinsing_repeats: int = 0, solid: bool = False) -> dict: - """Execute pump transfer operation""" - # Stop any existing operation first - self._stop_pump_operation() - - # Set transfer parameters - self._from_vessel = from_vessel - self._to_vessel = to_vessel - self._transfer_volume = float(volume) - self._amount = amount - self._transfer_time = float(time) - self._is_viscous = viscous - self._rinsing_solvent = rinsing_solvent - self._rinsing_volume = float(rinsing_volume) - self._rinsing_repeats = int(rinsing_repeats) - self._is_solid = solid - - # Calculate flow rate - if self._transfer_time > 0 and self._transfer_volume > 0: - self._target_flow_rate = (self._transfer_volume / self._transfer_time) * 60.0 - else: - self._target_flow_rate = 10.0 if not self._is_viscous else 5.0 - - # Reset timers and counters - self._start_time = datetime.now() - self._time_spent = timedelta() - self._time_remaining = timedelta(seconds=self._transfer_time) - self._total_volume = 0.0 - self._flow_rate = 0.0 - - # Start pump operation - self._pump_state = "Running" - self._status = "Starting Transfer" - self._running = True - - # Start pump operation thread - self._pump_thread = threading.Thread(target=self._pump_operation_loop) - self._pump_thread.daemon = True - self._pump_thread.start() - - # Wait briefly to ensure thread starts - time.sleep(0.1) - - return { - "success": True, - "status": self._status, - "current_device": self._current_device, - "time_spent": 0.0, - "time_remaining": float(self._transfer_time) - } - - def pause_pump(self) -> str: - - if self._pump_state != "Running": - self._status = "Error: Pump not running" - return "Error" - - self._pump_state = "Paused" - self._status = "Pump Paused" - self._stop_pump_operation() - - return "Success" - - def resume_pump(self) -> str: - - if self._pump_state != "Paused": - self._status = "Error: Pump not paused" - return "Error" - - self._pump_state = "Running" - self._status = "Resuming Pump" - self._start_pump_operation() - - return "Success" - - def reset_volume_counter(self) -> str: - self._total_volume = 0.0 - self._status = "Volume counter reset" - return "Success" - - def emergency_stop(self) -> str: - self._status = "Emergency Stop" - self._pump_state = "Stopped" - self._stop_pump_operation() - self._flow_rate = 0.0 - self._pressure = 0.0 - self._target_flow_rate = 0.0 - - return "Success" - - # ==================== 内部控制方法 ==================== - - def _start_pump_operation(self): - with self._thread_lock: - if not self._running: - self._running = True - self._pump_thread = threading.Thread(target=self._pump_operation_loop) - self._pump_thread.daemon = True - self._pump_thread.start() - - def _stop_pump_operation(self): - with self._thread_lock: - self._running = False - if self._pump_thread and self._pump_thread.is_alive(): - self._pump_thread.join(timeout=2.0) - - def _pump_operation_loop(self): - """泵运行主循环""" - print("Pump operation loop started") # Debug print - - while self._running and self._pump_state == "Running": - try: - # Calculate flow rate adjustment - flow_diff = self._target_flow_rate - self._flow_rate - - # Adjust flow rate more aggressively (50% of difference) - adjustment = flow_diff * 0.5 - self._flow_rate += adjustment - - # Ensure flow rate is within bounds - self._flow_rate = max(0.1, min(self._max_flow_rate, self._flow_rate)) - - # Update status based on flow rate - if abs(flow_diff) < 0.1: - self._status = "Running at Target Flow Rate" - else: - self._status = "Adjusting Flow Rate" - - # Calculate volume increment - volume_increment = (self._flow_rate / 60.0) # mL/s - self._total_volume += volume_increment - - # Update time tracking - self._time_spent = datetime.now() - self._start_time - if self._transfer_time > 0: - remaining = self._transfer_time - self._time_spent.total_seconds() - self._time_remaining = timedelta(seconds=max(0, remaining)) - - # Check completion - if self._total_volume >= self._transfer_volume: - self._status = "Transfer Completed" - self._pump_state = "Stopped" - self._running = False - break - - # Update pressure - self._pressure = (self._flow_rate / self._max_flow_rate) * self._max_pressure - - print(f"Debug - Flow: {self._flow_rate:.1f}, Volume: {self._total_volume:.1f}") # Debug print - - time.sleep(1.0) - - except Exception as e: - print(f"Error in pump operation: {str(e)}") - self._status = "Error in pump operation" - self._pump_state = "Stopped" - self._running = False - break - - def get_status_info(self) -> dict: - """ - 获取完整的设备状态信息 - - Returns: - dict: 包含所有设备状态的字典 - """ - return { - "status": self._status, - "pump_state": self._pump_state, - "flow_rate": self._flow_rate, - "target_flow_rate": self._target_flow_rate, - "pressure": self._pressure, - "total_volume": self._total_volume, - "max_flow_rate": self._max_flow_rate, - "max_pressure": self._max_pressure, - "current_device": self._current_device, - "from_vessel": self._from_vessel, - "to_vessel": self._to_vessel, - "transfer_volume": self._transfer_volume, - "amount": self._amount, - "transfer_time": self._transfer_time, - "is_viscous": self._is_viscous, - "rinsing_solvent": self._rinsing_solvent, - "rinsing_volume": self._rinsing_volume, - "rinsing_repeats": self._rinsing_repeats, - "is_solid": self._is_solid, - "time_spent": self._time_spent.total_seconds(), - "time_remaining": self._time_remaining.total_seconds() - } - - -# 用于测试的主函数 -if __name__ == "__main__": - pump = MockPump() - - # 测试基本功能 - print("启动泵设备测试...") - print(f"初始状态: {pump.get_status_info()}") - - # 设置流速并启动 - pump.set_flow_rate(50.0) - pump.start_pump() - - # 模拟运行10秒 - for i in range(10): - time.sleep(1) - print(f"第{i+1}秒: 流速={pump.flow_rate:.1f}mL/min, 压力={pump.pressure:.2f}bar, 状态={pump.status}") - - # 测试方向切换 - print("切换泵方向...") - - - pump.emergency_stop() - print("测试完成") diff --git a/unilabos/devices/mock/mock_rotavap.py b/unilabos/devices/mock/mock_rotavap.py deleted file mode 100644 index 9b2ea914..00000000 --- a/unilabos/devices/mock/mock_rotavap.py +++ /dev/null @@ -1,390 +0,0 @@ -import time -import threading -import json - - -class MockRotavap: - """ - 模拟旋转蒸发器设备类 - - 这个类模拟了一个实验室旋转蒸发器的行为,包括旋转控制、 - 真空泵控制、温度控制等功能。参考了现有的 RotavapOne 实现。 - """ - - def __init__(self, port: str = "MOCK"): - """ - 初始化MockRotavap实例 - - Args: - port (str): 设备端口,默认为"MOCK"表示模拟设备 - """ - self.port = port - - # 设备基本状态属性 - self._status: str = "Idle" # 设备状态:Idle, Running, Error, Stopped - - # 旋转相关属性 - self._rotate_state: str = "Stopped" # 旋转状态:Running, Stopped - self._rotate_time: float = 0.0 # 旋转剩余时间 (秒) - self._rotate_speed: float = 0.0 # 旋转速度 (rpm) - self._max_rotate_speed: float = 300.0 # 最大旋转速度 (rpm) - - # 真空泵相关属性 - self._pump_state: str = "Stopped" # 泵状态:Running, Stopped - self._pump_time: float = 0.0 # 泵剩余时间 (秒) - self._vacuum_level: float = 0.0 # 真空度 (mbar) - self._target_vacuum: float = 50.0 # 目标真空度 (mbar) - - # 温度相关属性 - self._temperature: float = 25.0 # 水浴温度 (°C) - self._target_temperature: float = 25.0 # 目标温度 (°C) - self._max_temperature: float = 180.0 # 最大温度 (°C) - - # 运行控制线程 - self._operation_thread = None - self._running = False - self._thread_lock = threading.Lock() - - # 操作成功标志 - self.success: str = "True" # 使用字符串而不是布尔值 - - # ==================== 状态属性 ==================== - # 这些属性会被Uni-Lab系统自动识别并定时对外广播 - - @property - def status(self) -> str: - return self._status - - @property - def rotate_state(self) -> str: - return self._rotate_state - - @property - def rotate_time(self) -> float: - return self._rotate_time - - @property - def rotate_speed(self) -> float: - return self._rotate_speed - - @property - def pump_state(self) -> str: - return self._pump_state - - @property - def pump_time(self) -> float: - return self._pump_time - - @property - def vacuum_level(self) -> float: - return self._vacuum_level - - @property - def temperature(self) -> float: - return self._temperature - - @property - def target_temperature(self) -> float: - return self._target_temperature - - # ==================== 设备控制方法 ==================== - # 这些方法需要在注册表中添加,会作为ActionServer接受控制指令 - - def set_timer(self, command: str) -> str: - """ - 设置定时器 - 兼容现有RotavapOne接口 - - Args: - command (str): JSON格式的命令字符串,包含rotate_time和pump_time - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - try: - timer = json.loads(command) - rotate_time = timer.get("rotate_time", 0) - pump_time = timer.get("pump_time", 0) - - self.success = "False" - self._rotate_time = float(rotate_time) - self._pump_time = float(pump_time) - self.success = "True" - - self._status = "Timer Set" - return "Success" - - except (json.JSONDecodeError, ValueError, KeyError) as e: - self._status = f"Error: Invalid command format - {str(e)}" - self.success = "False" - return "Error" - - def set_rotate_time(self, time_seconds: float) -> str: - """ - 设置旋转时间 - - Args: - time_seconds (float): 旋转时间 (秒) - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - self.success = "False" - self._rotate_time = max(0.0, float(time_seconds)) - self.success = "True" - self._status = "Rotate time set" - return "Success" - - def set_pump_time(self, time_seconds: float) -> str: - """ - 设置泵时间 - - Args: - time_seconds (float): 泵时间 (秒) - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - self.success = "False" - self._pump_time = max(0.0, float(time_seconds)) - self.success = "True" - self._status = "Pump time set" - return "Success" - - def set_rotate_speed(self, speed: float) -> str: - """ - 设置旋转速度 - - Args: - speed (float): 旋转速度 (rpm) - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - if speed < 0 or speed > self._max_rotate_speed: - self._status = f"Error: Speed out of range (0-{self._max_rotate_speed})" - return "Error" - - self._rotate_speed = speed - self._status = "Rotate speed set" - return "Success" - - def set_temperature(self, temperature: float) -> str: - """ - 设置水浴温度 - - Args: - temperature (float): 目标温度 (°C) - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - if temperature < 0 or temperature > self._max_temperature: - self._status = f"Error: Temperature out of range (0-{self._max_temperature})" - return "Error" - - self._target_temperature = temperature - self._status = "Temperature set" - - # 启动操作线程以开始温度控制 - self._start_operation() - - return "Success" - - def start_rotation(self) -> str: - """ - 启动旋转 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - if self._rotate_time <= 0: - self._status = "Error: No rotate time set" - return "Error" - - self._rotate_state = "Running" - self._status = "Rotation started" - return "Success" - - def start_pump(self) -> str: - """ - 启动真空泵 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - - if self._pump_time <= 0: - self._status = "Error: No pump time set" - return "Error" - - self._pump_state = "Running" - self._status = "Pump started" - return "Success" - - def stop_all_operations(self) -> str: - """ - 停止所有操作 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._rotate_state = "Stopped" - self._pump_state = "Stopped" - self._stop_operation() - self._rotate_time = 0.0 - self._pump_time = 0.0 - self._vacuum_level = 0.0 - self._status = "All operations stopped" - return "Success" - - def emergency_stop(self) -> str: - """ - 紧急停止 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._status = "Emergency Stop" - self.stop_all_operations() - return "Success" - - # ==================== 内部控制方法 ==================== - - def _start_operation(self): - """ - 启动操作线程 - - 这个方法启动一个后台线程来模拟旋蒸的实际运行过程。 - """ - with self._thread_lock: - if not self._running: - self._running = True - self._operation_thread = threading.Thread(target=self._operation_loop) - self._operation_thread.daemon = True - self._operation_thread.start() - - def _stop_operation(self): - """ - 停止操作线程 - - 安全地停止后台运行线程并等待其完成。 - """ - with self._thread_lock: - self._running = False - if self._operation_thread and self._operation_thread.is_alive(): - self._operation_thread.join(timeout=2.0) - - def _operation_loop(self): - """ - 操作主循环 - - 这个方法在后台线程中运行,模拟真实旋蒸的工作过程: - 1. 时间倒计时 - 2. 温度控制 - 3. 真空度控制 - 4. 状态更新 - """ - while self._running: - try: - # 处理旋转时间倒计时 - if self._rotate_time > 0: - self._rotate_state = "Running" - self._rotate_time = max(0.0, self._rotate_time - 1.0) - else: - self._rotate_state = "Stopped" - - # 处理泵时间倒计时 - if self._pump_time > 0: - self._pump_state = "Running" - self._pump_time = max(0.0, self._pump_time - 1.0) - # 模拟真空度变化 - if self._vacuum_level > self._target_vacuum: - self._vacuum_level = max(self._target_vacuum, self._vacuum_level - 5.0) - else: - self._pump_state = "Stopped" - # 真空度逐渐回升 - self._vacuum_level = min(1013.25, self._vacuum_level + 2.0) - - # 模拟温度控制 - temp_diff = self._target_temperature - self._temperature - if abs(temp_diff) > 0.5: - if temp_diff > 0: - self._temperature += min(1.0, temp_diff * 0.1) - else: - self._temperature += max(-1.0, temp_diff * 0.1) - - # 更新整体状态 - if self._rotate_state == "Running" or self._pump_state == "Running": - self._status = "Operating" - elif self._rotate_time > 0 or self._pump_time > 0: - self._status = "Ready" - else: - self._status = "Idle" - - # 等待1秒后继续下一次循环 - time.sleep(1.0) - - except Exception as e: - self._status = f"Error in operation: {str(e)}" - break - - # 循环结束时的清理工作 - self._status = "Idle" - - def get_status_info(self) -> dict: - """ - 获取完整的设备状态信息 - - Returns: - dict: 包含所有设备状态的字典 - """ - return { - "status": self._status, - "rotate_state": self._rotate_state, - "rotate_time": self._rotate_time, - "rotate_speed": self._rotate_speed, - "pump_state": self._pump_state, - "pump_time": self._pump_time, - "vacuum_level": self._vacuum_level, - "temperature": self._temperature, - "target_temperature": self._target_temperature, - "success": self.success, - } - - -# 用于测试的主函数 -if __name__ == "__main__": - rotavap = MockRotavap() - - # 测试基本功能 - print("启动旋转蒸发器测试...") - print(f"初始状态: {rotavap.get_status_info()}") - - # 设置定时器 - timer_command = '{"rotate_time": 300, "pump_time": 600}' - rotavap.set_timer(timer_command) - - # 设置温度和转速 - rotavap.set_temperature(60.0) - rotavap.set_rotate_speed(120.0) - - # 启动操作 - rotavap.start_rotation() - rotavap.start_pump() - - # 模拟运行10秒 - for i in range(10): - time.sleep(1) - print( - f"第{i+1}秒: 旋转={rotavap.rotate_time:.0f}s, 泵={rotavap.pump_time:.0f}s, " - f"温度={rotavap.temperature:.1f}°C, 真空={rotavap.vacuum_level:.1f}mbar" - ) - - rotavap.emergency_stop() - print("测试完成") diff --git a/unilabos/devices/mock/mock_separator.py b/unilabos/devices/mock/mock_separator.py deleted file mode 100644 index 222cb2ed..00000000 --- a/unilabos/devices/mock/mock_separator.py +++ /dev/null @@ -1,399 +0,0 @@ -import time -import threading -from datetime import datetime, timedelta - -class MockSeparator: - def __init__(self, port: str = "MOCK"): - self.port = port - - # 基本状态属性 - self._status: str = "Idle" # 当前总体状态 - self._valve_state: str = "Closed" # 阀门状态:Open 或 Closed - self._settling_time: float = 0.0 # 静置时间(秒) - - # 搅拌相关属性 - self._shake_time: float = 0.0 # 剩余摇摆时间(秒) - self._shake_status: str = "Not Shaking" # 摇摆状态 - - # 用于后台模拟 shake 动作 - self._operation_thread = None - self._thread_lock = threading.Lock() - self._running = False - - # Separate action 相关属性 - self._current_device: str = "MockSeparator1" - self._purpose: str = "" # wash or extract - self._product_phase: str = "" # top or bottom - self._from_vessel: str = "" - self._separation_vessel: str = "" - self._to_vessel: str = "" - self._waste_phase_to_vessel: str = "" - self._solvent: str = "" - self._solvent_volume: float = 0.0 - self._through: str = "" - self._repeats: int = 1 - self._stir_time: float = 0.0 - self._stir_speed: float = 0.0 - self._time_spent = timedelta() - self._time_remaining = timedelta() - self._start_time = datetime.now() # 添加这一行 - - @property - def current_device(self) -> str: - return self._current_device - - @property - def purpose(self) -> str: - return self._purpose - - @property - def valve_state(self) -> str: - return self._valve_state - - @property - def settling_time(self) -> float: - return self._settling_time - - @property - def status(self) -> str: - return self._status - - @property - def shake_time(self) -> float: - with self._thread_lock: - return self._shake_time - - @property - def shake_status(self) -> str: - with self._thread_lock: - return self._shake_status - - @property - def product_phase(self) -> str: - return self._product_phase - - @property - def from_vessel(self) -> str: - return self._from_vessel - - @property - def separation_vessel(self) -> str: - return self._separation_vessel - - @property - def to_vessel(self) -> str: - return self._to_vessel - - @property - def waste_phase_to_vessel(self) -> str: - return self._waste_phase_to_vessel - - @property - def solvent(self) -> str: - return self._solvent - - @property - def solvent_volume(self) -> float: - return self._solvent_volume - - @property - def through(self) -> str: - return self._through - - @property - def repeats(self) -> int: - return self._repeats - - @property - def stir_time(self) -> float: - return self._stir_time - - @property - def stir_speed(self) -> float: - return self._stir_speed - - @property - def time_spent(self) -> float: - if self._running: - self._time_spent = datetime.now() - self._start_time - return self._time_spent.total_seconds() - - @property - def time_remaining(self) -> float: - if self._running: - elapsed = (datetime.now() - self._start_time).total_seconds() - total_time = (self._stir_time + self._settling_time + 10) * self._repeats - remain = max(0, total_time - elapsed) - self._time_remaining = timedelta(seconds=remain) - return self._time_remaining.total_seconds() - - def separate(self, purpose: str, product_phase: str, from_vessel: str, - separation_vessel: str, to_vessel: str, waste_phase_to_vessel: str = "", - solvent: str = "", solvent_volume: float = 0.0, through: str = "", - repeats: int = 1, stir_time: float = 0.0, stir_speed: float = 0.0, - settling_time: float = 60.0) -> dict: - """ - 执行分离操作 - """ - with self._thread_lock: - # 检查是否已经在运行 - if self._running: - return { - "success": False, - "status": "Error: Operation already in progress" - } - # 必填参数验证 - if not all([from_vessel, separation_vessel, to_vessel]): - self._status = "Error: Missing required vessel parameters" - return {"success": False} - # 验证参数 - if purpose not in ["wash", "extract"]: - self._status = "Error: Invalid purpose" - return {"success": False} - - if product_phase not in ["top", "bottom"]: - self._status = "Error: Invalid product phase" - return {"success": False} - # 数值参数验证 - try: - solvent_volume = float(solvent_volume) - repeats = int(repeats) - stir_time = float(stir_time) - stir_speed = float(stir_speed) - settling_time = float(settling_time) - except ValueError: - self._status = "Error: Invalid numeric parameters" - return {"success": False} - - # 设置参数 - self._purpose = purpose - self._product_phase = product_phase - self._from_vessel = from_vessel - self._separation_vessel = separation_vessel - self._to_vessel = to_vessel - self._waste_phase_to_vessel = waste_phase_to_vessel - self._solvent = solvent - self._solvent_volume = float(solvent_volume) - self._through = through - self._repeats = int(repeats) - self._stir_time = float(stir_time) - self._stir_speed = float(stir_speed) - self._settling_time = float(settling_time) - - # 重置计时器 - self._start_time = datetime.now() - self._time_spent = timedelta() - total_time = (self._stir_time + self._settling_time + 10) * self._repeats - self._time_remaining = timedelta(seconds=total_time) - - # 启动分离操作 - self._status = "Starting Separation" - self._running = True - - # 在锁内创建和启动线程 - self._operation_thread = threading.Thread(target=self._operation_loop) - self._operation_thread.daemon = True - self._operation_thread.start() - - # 等待确认操作已经开始 - time.sleep(0.1) # 短暂等待确保操作线程已启动 - - return { - "success": True, - "status": self._status, - "current_device": self._current_device, - "time_spent": self._time_spent.total_seconds(), - "time_remaining": self._time_remaining.total_seconds() - } - - def shake(self, shake_time: float) -> str: - """ - 模拟 shake(搅拌)操作: - - 进入 "Shaking" 状态,倒计时 shake_time 秒 - - shake 结束后,进入 "Settling" 状态,静置时间固定为 5 秒 - - 最后恢复为 Idle - """ - try: - shake_time = float(shake_time) - except ValueError: - self._status = "Error: Invalid shake time" - return "Error" - - with self._thread_lock: - self._status = "Shaking" - self._settling_time = 0.0 - self._shake_time = shake_time - self._shake_status = "Shaking" - - def _run_shake(): - remaining = shake_time - while remaining > 0: - time.sleep(1) - remaining -= 1 - with self._thread_lock: - self._shake_time = remaining - with self._thread_lock: - self._status = "Settling" - self._settling_time = 60.0 # 固定静置时间为60秒 - self._shake_status = "Settling" - while True: - with self._thread_lock: - if self._settling_time <= 0: - self._status = "Idle" - self._shake_status = "Idle" - break - time.sleep(1) - with self._thread_lock: - self._settling_time = max(0.0, self._settling_time - 1) - - self._operation_thread = threading.Thread(target=_run_shake) - self._operation_thread.daemon = True - self._operation_thread.start() - return "Success" - - def set_valve(self, command: str) -> str: - """ - 阀门控制命令:传入 "open" 或 "close" - """ - - command = command.lower() - if command == "open": - self._valve_state = "Open" - self._status = "Valve Opened" - elif command == "close": - self._valve_state = "Closed" - self._status = "Valve Closed" - else: - self._status = "Error: Invalid valve command" - return "Error" - return "Success" - - def _operation_loop(self): - """分离操作主循环""" - try: - current_repeat = 1 - - # 立即更新状态,确保不会停留在Starting Separation - with self._thread_lock: - self._status = f"Separation Cycle {current_repeat}/{self._repeats}" - - while self._running and current_repeat <= self._repeats: - # 第一步:搅拌 - if self._stir_time > 0: - with self._thread_lock: - self._status = f"Stirring (Repeat {current_repeat}/{self._repeats})" - remaining_stir = self._stir_time - while remaining_stir > 0 and self._running: - time.sleep(1) - remaining_stir -= 1 - - # 第二步:静置 - if self._settling_time > 0: - with self._thread_lock: - self._status = f"Settling (Repeat {current_repeat}/{self._repeats})" - remaining_settle = self._settling_time - while remaining_settle > 0 and self._running: - time.sleep(1) - remaining_settle -= 1 - - # 第三步:打开阀门排出 - with self._thread_lock: - self._valve_state = "Open" - self._status = f"Draining (Repeat {current_repeat}/{self._repeats})" - - # 模拟排出时间(5秒) - time.sleep(10) - - # 关闭阀门 - with self._thread_lock: - self._valve_state = "Closed" - - # 检查是否继续下一次重复 - if current_repeat < self._repeats: - current_repeat += 1 - else: - with self._thread_lock: - self._status = "Separation Complete" - break - - except Exception as e: - with self._thread_lock: - self._status = f"Error in separation: {str(e)}" - finally: - with self._thread_lock: - self._running = False - self._valve_state = "Closed" - if self._status == "Starting Separation": - self._status = "Error: Operation failed to start" - elif self._status != "Separation Complete": - self._status = "Stopped" - - def stop_operations(self) -> str: - """停止任何正在执行的操作""" - with self._thread_lock: - self._running = False - if self._operation_thread and self._operation_thread.is_alive(): - self._operation_thread.join(timeout=1.0) - self._operation_thread = None - self._settling_time = 0.0 - self._status = "Idle" - self._shake_status = "Idle" - self._shake_time = 0.0 - self._time_remaining = timedelta() - return "Success" - - def get_status_info(self) -> dict: - """获取当前设备状态信息""" - with self._thread_lock: - current_time = datetime.now() - if self._start_time: - self._time_spent = current_time - self._start_time - - return { - "status": self._status, - "valve_state": self._valve_state, - "settling_time": self._settling_time, - "shake_time": self._shake_time, - "shake_status": self._shake_status, - "current_device": self._current_device, - "purpose": self._purpose, - "product_phase": self._product_phase, - "from_vessel": self._from_vessel, - "separation_vessel": self._separation_vessel, - "to_vessel": self._to_vessel, - "waste_phase_to_vessel": self._waste_phase_to_vessel, - "solvent": self._solvent, - "solvent_volume": self._solvent_volume, - "through": self._through, - "repeats": self._repeats, - "stir_time": self._stir_time, - "stir_speed": self._stir_speed, - "time_spent": self._time_spent.total_seconds(), - "time_remaining": self._time_remaining.total_seconds() - } - - -# 主函数用于测试 -if __name__ == "__main__": - separator = MockSeparator() - - print("启动简单版分离器测试...") - print("初始状态:", separator.get_status_info()) - - # 触发 shake 操作,模拟 10 秒的搅拌 - print("执行 shake 操作...") - print(separator.shake(10.0)) - - # 循环显示状态变化 - for i in range(20): - time.sleep(1) - info = separator.get_status_info() - print( - f"第{i+1}秒: 状态={info['status']}, 静置时间={info['settling_time']:.1f}秒, " - f"阀门状态={info['valve_state']}, shake_time={info['shake_time']:.1f}, " - f"shake_status={info['shake_status']}" - ) - - # 模拟打开阀门 - print("打开阀门...", separator.set_valve("open")) - print("最终状态:", separator.get_status_info()) diff --git a/unilabos/devices/mock/mock_solenoid_valve.py b/unilabos/devices/mock/mock_solenoid_valve.py deleted file mode 100644 index 0f0fbe55..00000000 --- a/unilabos/devices/mock/mock_solenoid_valve.py +++ /dev/null @@ -1,89 +0,0 @@ -import time - - -class MockSolenoidValve: - """ - 模拟电磁阀设备类 - 简化版本 - - 这个类提供了电磁阀的基本功能:开启、关闭和状态查询 - """ - - def __init__(self, port: str = "MOCK"): - """ - 初始化MockSolenoidValve实例 - - Args: - port (str): 设备端口,默认为"MOCK"表示模拟设备 - """ - self.port = port - self._status: str = "Idle" - self._valve_status: str = "Closed" # 阀门位置:Open, Closed - - @property - def status(self) -> str: - """设备状态 - 会被自动识别的设备属性""" - return self._status - - @property - def valve_status(self) -> str: - """阀门状态""" - return self._valve_status - - def set_valve_status(self, status: str) -> str: - """ - 设置阀门位置 - - Args: - position (str): 阀门位置,可选值:"Open", "Closed" - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - if status not in ["Open", "Closed"]: - self._status = "Error: Invalid position" - return "Error" - - self._status = "Moving" - time.sleep(1) # 模拟阀门动作时间 - - self._valve_status = status - self._status = "Idle" - return "Success" - - def open_valve(self) -> str: - """打开阀门""" - return self.set_valve_status("Open") - - def close_valve(self) -> str: - """关闭阀门""" - return self.set_valve_status("Closed") - - def get_valve_status(self) -> str: - """获取阀门位置""" - return self._valve_status - - def is_open(self) -> bool: - """检查阀门是否打开""" - return self._valve_status == "Open" - - def is_closed(self) -> bool: - """检查阀门是否关闭""" - return self._valve_status == "Closed" - - -# 用于测试的主函数 -if __name__ == "__main__": - valve = MockSolenoidValve() - - print("启动电磁阀测试...") - print(f"初始状态: 位置={valve.valve_status}, 状态={valve.status}") - - # 测试开启阀门 - valve.open_valve() - print(f"开启后: 位置={valve.valve_status}, 状态={valve.status}") - - # 测试关闭阀门 - valve.close_valve() - print(f"关闭后: 位置={valve.valve_status}, 状态={valve.status}") - - print("测试完成") diff --git a/unilabos/devices/mock/mock_stirrer.py b/unilabos/devices/mock/mock_stirrer.py deleted file mode 100644 index a1f2c51d..00000000 --- a/unilabos/devices/mock/mock_stirrer.py +++ /dev/null @@ -1,307 +0,0 @@ -import time -import threading - - -class MockStirrer: - def __init__(self, port: str = "MOCK"): - self.port = port - - # 设备基本状态属性 - self._status: str = "Idle" # 设备状态:Idle, Running, Error, Stopped - - # 搅拌相关属性 - self._stir_speed: float = 0.0 # 当前搅拌速度 (rpm) - self._target_stir_speed: float = 0.0 # 目标搅拌速度 (rpm) - self._max_stir_speed: float = 2000.0 # 最大搅拌速度 (rpm) - self._stir_state: str = "Stopped" # 搅拌状态:Running, Stopped - - # 温度相关属性 - self._temperature: float = 25.0 # 当前温度 (°C) - self._target_temperature: float = 25.0 # 目标温度 (°C) - self._max_temperature: float = 300.0 # 最大温度 (°C) - self._heating_state: str = "Off" # 加热状态:On, Off - self._heating_power: float = 0.0 # 加热功率百分比 0-100 - - # 运行控制线程 - self._operation_thread = None - self._running = False - self._thread_lock = threading.Lock() - - # ==================== 状态属性 ==================== - # 这些属性会被Uni-Lab系统自动识别并定时对外广播 - - @property - def status(self) -> str: - return self._status - - @property - def stir_speed(self) -> float: - return self._stir_speed - - @property - def target_stir_speed(self) -> float: - return self._target_stir_speed - - @property - def stir_state(self) -> str: - return self._stir_state - - @property - def temperature(self) -> float: - """ - 当前温度 - - Returns: - float: 当前温度 (°C) - """ - return self._temperature - - @property - def target_temperature(self) -> float: - """ - 目标温度 - - Returns: - float: 目标温度 (°C) - """ - return self._target_temperature - - @property - def heating_state(self) -> str: - return self._heating_state - - @property - def heating_power(self) -> float: - return self._heating_power - - @property - def max_stir_speed(self) -> float: - return self._max_stir_speed - - @property - def max_temperature(self) -> float: - return self._max_temperature - - # ==================== 设备控制方法 ==================== - # 这些方法需要在注册表中添加,会作为ActionServer接受控制指令 - - def set_stir_speed(self, speed: float) -> str: - - speed = float(speed) # 确保传入的速度是浮点数 - - if speed < 0 or speed > self._max_stir_speed: - self._status = f"Error: Speed out of range (0-{self._max_stir_speed})" - return "Error" - - self._target_stir_speed = speed - self._status = "Setting Stir Speed" - - # 如果设置了非零速度,启动搅拌 - if speed > 0: - self._stir_state = "Running" - else: - self._stir_state = "Stopped" - - return "Success" - - def set_temperature(self, temperature: float) -> str: - temperature = float(temperature) # 确保传入的温度是浮点数 - - if temperature < 0 or temperature > self._max_temperature: - self._status = f"Error: Temperature out of range (0-{self._max_temperature})" - return "Error" - - self._target_temperature = temperature - self._status = "Setting Temperature" - - return "Success" - - def start_stirring(self) -> str: - - if self._target_stir_speed <= 0: - self._status = "Error: No target speed set" - return "Error" - - self._stir_state = "Running" - self._status = "Stirring Started" - return "Success" - - def stop_stirring(self) -> str: - self._stir_state = "Stopped" - self._target_stir_speed = 0.0 - self._status = "Stirring Stopped" - return "Success" - - def heating_control(self, heating_state: str = "On") -> str: - - if heating_state not in ["On", "Off"]: - self._status = "Error: Invalid heating state" - return "Error" - - self._heating_state = heating_state - - if heating_state == "On": - self._status = "Heating On" - else: - self._status = "Heating Off" - self._heating_power = 0.0 - - return "Success" - - def stop_all_operations(self) -> str: - self._stir_state = "Stopped" - self._heating_state = "Off" - self._stop_operation() - self._stir_speed = 0.0 - self._target_stir_speed = 0.0 - self._heating_power = 0.0 - self._status = "All operations stopped" - return "Success" - - def emergency_stop(self) -> str: - """ - 紧急停止 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._status = "Emergency Stop" - self.stop_all_operations() - return "Success" - - # ==================== 内部控制方法 ==================== - - def _start_operation(self): - with self._thread_lock: - if not self._running: - self._running = True - self._operation_thread = threading.Thread(target=self._operation_loop) - self._operation_thread.daemon = True - self._operation_thread.start() - - def _stop_operation(self): - """ - 停止操作线程 - - 安全地停止后台运行线程并等待其完成。 - """ - with self._thread_lock: - self._running = False - if self._operation_thread and self._operation_thread.is_alive(): - self._operation_thread.join(timeout=2.0) - - def _operation_loop(self): - while self._running: - try: - # 处理搅拌速度控制 - if self._stir_state == "Running": - speed_diff = self._target_stir_speed - self._stir_speed - - if abs(speed_diff) < 1.0: # 速度接近目标值 - self._stir_speed = self._target_stir_speed - if self._stir_speed > 0: - self._status = "Stirring at Target Speed" - else: - # 模拟速度调节,每秒调整10%的差值 - adjustment = speed_diff * 0.1 - self._stir_speed += adjustment - self._status = "Adjusting Stir Speed" - - # 确保速度在合理范围内 - self._stir_speed = max(0.0, min(self._max_stir_speed, self._stir_speed)) - else: - # 搅拌停止时,速度逐渐降为0 - if self._stir_speed > 0: - self._stir_speed = max(0.0, self._stir_speed - 50.0) # 每秒减少50rpm - - # 处理温度控制 - if self._heating_state == "On": - temp_diff = self._target_temperature - self._temperature - - if abs(temp_diff) < 0.5: # 温度接近目标值 - self._heating_power = 20.0 # 维持温度的最小功率 - elif temp_diff > 0: # 需要加热 - # 根据温差调整加热功率 - if temp_diff > 50: - self._heating_power = 100.0 - elif temp_diff > 20: - self._heating_power = 80.0 - elif temp_diff > 10: - self._heating_power = 60.0 - else: - self._heating_power = 40.0 - - # 模拟加热过程 - heating_rate = self._heating_power / 100.0 * 1.5 # 最大每秒升温1.5度 - self._temperature += heating_rate - else: # 目标温度低于当前温度 - self._heating_power = 0.0 - # 自然冷却 - self._temperature -= 0.1 - else: - self._heating_power = 0.0 - # 自然冷却到室温 - if self._temperature > 25.0: - self._temperature -= 0.2 - - # 限制温度范围 - self._temperature = max(20.0, min(self._max_temperature, self._temperature)) - - # 更新整体状态 - if self._stir_state == "Running" and self._heating_state == "On": - self._status = "Stirring and Heating" - elif self._stir_state == "Running": - self._status = "Stirring Only" - elif self._heating_state == "On": - self._status = "Heating Only" - else: - self._status = "Idle" - - # 等待1秒后继续下一次循环 - time.sleep(1.0) - - except Exception as e: - self._status = f"Error in operation: {str(e)}" - break - - # 循环结束时的清理工作 - self._status = "Idle" - - def get_status_info(self) -> dict: - return { - "status": self._status, - "stir_speed": self._stir_speed, - "target_stir_speed": self._target_stir_speed, - "stir_state": self._stir_state, - "temperature": self._temperature, - "target_temperature": self._target_temperature, - "heating_state": self._heating_state, - "heating_power": self._heating_power, - "max_stir_speed": self._max_stir_speed, - "max_temperature": self._max_temperature, - } - - -# 用于测试的主函数 -if __name__ == "__main__": - stirrer = MockStirrer() - - # 测试基本功能 - print("启动搅拌器测试...") - print(f"初始状态: {stirrer.get_status_info()}") - - # 设置搅拌速度和温度 - stirrer.set_stir_speed(800.0) - stirrer.set_temperature(60.0) - stirrer.heating_control("On") - - # 模拟运行15秒 - for i in range(15): - time.sleep(1) - print( - f"第{i+1}秒: 速度={stirrer.stir_speed:.0f}rpm, 温度={stirrer.temperature:.1f}°C, " - f"功率={stirrer.heating_power:.1f}%, 状态={stirrer.status}" - ) - - stirrer.emergency_stop() - print("测试完成") diff --git a/unilabos/devices/mock/mock_stirrer_new.py b/unilabos/devices/mock/mock_stirrer_new.py deleted file mode 100644 index ac429db5..00000000 --- a/unilabos/devices/mock/mock_stirrer_new.py +++ /dev/null @@ -1,229 +0,0 @@ -import time -import threading -from datetime import datetime, timedelta - -class MockStirrer_new: - def __init__(self, port: str = "MOCK"): - self.port = port - - # 基本状态属性 - self._status: str = "Idle" - self._vessel: str = "" - self._purpose: str = "" - - # 搅拌相关属性 - self._stir_speed: float = 0.0 - self._target_stir_speed: float = 0.0 - self._max_stir_speed: float = 2000.0 - self._stir_state: str = "Stopped" - - # 计时相关 - self._stir_time: float = 0.0 - self._settling_time: float = 0.0 - self._start_time = datetime.now() - self._time_remaining = timedelta() - - # 运行控制 - self._operation_thread = None - self._running = False - self._thread_lock = threading.Lock() - - # 创建操作线程 - self._operation_thread = threading.Thread(target=self._operation_loop) - self._operation_thread.daemon = True - self._operation_thread.start() - - # ==================== 状态属性 ==================== - @property - def status(self) -> str: - return self._status - - @property - def stir_speed(self) -> float: - return self._stir_speed - - @property - def target_stir_speed(self) -> float: - return self._target_stir_speed - - @property - def stir_state(self) -> str: - return self._stir_state - - @property - def vessel(self) -> str: - return self._vessel - - @property - def purpose(self) -> str: - return self._purpose - - @property - def stir_time(self) -> float: - return self._stir_time - - @property - def settling_time(self) -> float: - return self._settling_time - - @property - def max_stir_speed(self) -> float: - return self._max_stir_speed - - @property - def progress(self) -> float: - """返回当前操作的进度(0-100)""" - if not self._running: - return 0.0 - elapsed = (datetime.now() - self._start_time).total_seconds() - total_time = self._stir_time + self._settling_time - if total_time <= 0: - return 100.0 - return min(100.0, (elapsed / total_time) * 100) - - # ==================== Action Server 方法 ==================== - def start_stir(self, vessel: str, stir_speed: float = 0.0, purpose: str = "") -> dict: - """ - StartStir.action 对应的方法 - """ - with self._thread_lock: - if self._running: - return { - "success": False, - "message": "Operation already in progress" - } - - try: - # 重置所有参数 - self._vessel = vessel - self._purpose = purpose - self._stir_time = 0.0 # 连续搅拌模式下不设置搅拌时间 - self._settling_time = 0.0 - self._start_time = datetime.now() # 重置开始时间 - - if stir_speed > 0: - self._target_stir_speed = min(stir_speed, self._max_stir_speed) - - self._stir_state = "Running" - self._status = "Stirring Started" - self._running = True - - return { - "success": True, - "message": "Stirring started successfully" - } - - except Exception as e: - return { - "success": False, - "message": f"Error: {str(e)}" - } - - def stir(self, stir_time: float, stir_speed: float, settling_time: float) -> dict: - """ - Stir.action 对应的方法 - """ - with self._thread_lock: - try: - # 如果已经在运行,先停止当前操作 - if self._running: - self._running = False - self._stir_state = "Stopped" - self._target_stir_speed = 0.0 - time.sleep(0.1) # 给一个短暂的停止时间 - - - # 重置所有参数 - self._stir_time = float(stir_time) - self._settling_time = float(settling_time) - self._target_stir_speed = min(float(stir_speed), self._max_stir_speed) - self._start_time = datetime.now() # 重置开始时间 - self._stir_state = "Running" - self._status = "Stirring" - self._running = True - - return {"success": True} - - except ValueError: - self._status = "Error: Invalid parameters" - return {"success": False} - - def stop_stir(self, vessel: str) -> dict: - """ - StopStir.action 对应的方法 - """ - with self._thread_lock: - if vessel != self._vessel: - return { - "success": False, - "message": "Vessel mismatch" - } - - self._running = False - self._stir_state = "Stopped" - self._target_stir_speed = 0.0 - self._status = "Stirring Stopped" - - return { - "success": True, - "message": "Stirring stopped successfully" - } - - # ==================== 内部控制方法 ==================== - - def _operation_loop(self): - """操作主循环""" - while True: - try: - current_time = datetime.now() - - with self._thread_lock: # 添加锁保护 - if self._stir_state == "Running": - # 实际搅拌逻辑 - speed_diff = self._target_stir_speed - self._stir_speed - if abs(speed_diff) > 0.1: - adjustment = speed_diff * 0.1 - self._stir_speed += adjustment - else: - self._stir_speed = self._target_stir_speed - - # 更新进度 - if self._running: - if self._stir_time > 0: # 定时搅拌模式 - elapsed = (current_time - self._start_time).total_seconds() - if elapsed >= self._stir_time + self._settling_time: - self._running = False - self._stir_state = "Stopped" - self._target_stir_speed = 0.0 - self._stir_speed = 0.0 - self._status = "Stirring Complete" - elif elapsed >= self._stir_time: - self._status = "Settling" - else: # 连续搅拌模式 - self._status = "Stirring" - else: - # 停止状态下慢慢降低速度 - if self._stir_speed > 0: - self._stir_speed = max(0, self._stir_speed - 20.0) - - time.sleep(0.1) - - except Exception as e: - print(f"Error in operation loop: {str(e)}") # 添加错误输出 - self._status = f"Error: {str(e)}" - time.sleep(1.0) # 错误发生时等待较长时间 - - def get_status_info(self) -> dict: - """获取设备状态信息""" - return { - "status": self._status, - "vessel": self._vessel, - "purpose": self._purpose, - "stir_speed": self._stir_speed, - "target_stir_speed": self._target_stir_speed, - "stir_state": self._stir_state, - "stir_time": self._stir_time, # 添加 - "settling_time": self._settling_time, # 添加 - "progress": self.progress, - "max_stir_speed": self._max_stir_speed - } \ No newline at end of file diff --git a/unilabos/devices/mock/mock_vacuum.py b/unilabos/devices/mock/mock_vacuum.py deleted file mode 100644 index 9e368a90..00000000 --- a/unilabos/devices/mock/mock_vacuum.py +++ /dev/null @@ -1,410 +0,0 @@ -import time -import threading - - -class MockVacuum: - """ - 模拟真空泵设备类 - - 这个类模拟了一个实验室真空泵的行为,包括真空度控制、 - 压力监测、运行状态管理等功能。参考了现有的 VacuumPumpMock 实现。 - """ - - def __init__(self, port: str = "MOCK"): - """ - 初始化MockVacuum实例 - - Args: - port (str): 设备端口,默认为"MOCK"表示模拟设备 - """ - self.port = port - - # 设备基本状态属性 - self._status: str = "Idle" # 设备状态:Idle, Running, Error, Stopped - self._power_state: str = "Off" # 电源状态:On, Off - self._pump_state: str = "Stopped" # 泵运行状态:Running, Stopped, Paused - - # 真空相关属性 - self._vacuum_level: float = 1013.25 # 当前真空度 (mbar) - 大气压开始 - self._target_vacuum: float = 50.0 # 目标真空度 (mbar) - self._min_vacuum: float = 1.0 # 最小真空度 (mbar) - self._max_vacuum: float = 1013.25 # 最大真空度 (mbar) - 大气压 - - # 泵性能相关属性 - self._pump_speed: float = 0.0 # 泵速 (L/s) - self._max_pump_speed: float = 100.0 # 最大泵速 (L/s) - self._pump_efficiency: float = 95.0 # 泵效率百分比 - - # 运行控制线程 - self._vacuum_thread = None - self._running = False - self._thread_lock = threading.Lock() - - # ==================== 状态属性 ==================== - # 这些属性会被Uni-Lab系统自动识别并定时对外广播 - - @property - def status(self) -> str: - """ - 设备状态 - 会被自动识别的设备属性 - - Returns: - str: 当前设备状态 (Idle, Running, Error, Stopped) - """ - return self._status - - @property - def power_state(self) -> str: - """ - 电源状态 - - Returns: - str: 电源状态 (On, Off) - """ - return self._power_state - - @property - def pump_state(self) -> str: - """ - 泵运行状态 - - Returns: - str: 泵状态 (Running, Stopped, Paused) - """ - return self._pump_state - - @property - def vacuum_level(self) -> float: - """ - 当前真空度 - - Returns: - float: 当前真空度 (mbar) - """ - return self._vacuum_level - - @property - def target_vacuum(self) -> float: - """ - 目标真空度 - - Returns: - float: 目标真空度 (mbar) - """ - return self._target_vacuum - - @property - def pump_speed(self) -> float: - """ - 泵速 - - Returns: - float: 泵速 (L/s) - """ - return self._pump_speed - - @property - def pump_efficiency(self) -> float: - """ - 泵效率 - - Returns: - float: 泵效率百分比 - """ - return self._pump_efficiency - - @property - def max_pump_speed(self) -> float: - """ - 最大泵速 - - Returns: - float: 最大泵速 (L/s) - """ - return self._max_pump_speed - - # ==================== 设备控制方法 ==================== - # 这些方法需要在注册表中添加,会作为ActionServer接受控制指令 - - def power_control(self, power_state: str = "On") -> str: - """ - 电源控制方法 - - Args: - power_state (str): 电源状态,可选值:"On", "Off" - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - if power_state not in ["On", "Off"]: - self._status = "Error: Invalid power state" - return "Error" - - self._power_state = power_state - - if power_state == "On": - self._status = "Power On" - self._start_vacuum_operation() - else: - self._status = "Power Off" - self.stop_vacuum() - - return "Success" - - def set_vacuum_level(self, vacuum_level: float) -> str: - """ - 设置目标真空度 - - Args: - vacuum_level (float): 目标真空度 (mbar) - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - try: - vacuum_level = float(vacuum_level) - except ValueError: - self._status = "Error: Invalid vacuum level" - return "Error" - if self._power_state != "On": - self._status = "Error: Power Off" - return "Error" - - if vacuum_level < self._min_vacuum or vacuum_level > self._max_vacuum: - self._status = f"Error: Vacuum level out of range ({self._min_vacuum}-{self._max_vacuum})" - return "Error" - - self._target_vacuum = vacuum_level - self._status = "Setting Vacuum Level" - - return "Success" - - def start_vacuum(self) -> str: - """ - 启动真空泵 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - if self._power_state != "On": - self._status = "Error: Power Off" - return "Error" - - self._pump_state = "Running" - self._status = "Starting Vacuum Pump" - self._start_vacuum_operation() - - return "Success" - - def stop_vacuum(self) -> str: - """ - 停止真空泵 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._pump_state = "Stopped" - self._status = "Stopping Vacuum Pump" - self._stop_vacuum_operation() - self._pump_speed = 0.0 - - return "Success" - - def pause_vacuum(self) -> str: - """ - 暂停真空泵 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - if self._pump_state != "Running": - self._status = "Error: Pump not running" - return "Error" - - self._pump_state = "Paused" - self._status = "Vacuum Pump Paused" - self._stop_vacuum_operation() - - return "Success" - - def resume_vacuum(self) -> str: - """ - 恢复真空泵运行 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - if self._pump_state != "Paused": - self._status = "Error: Pump not paused" - return "Error" - - if self._power_state != "On": - self._status = "Error: Power Off" - return "Error" - - self._pump_state = "Running" - self._status = "Resuming Vacuum Pump" - self._start_vacuum_operation() - - return "Success" - - def vent_to_atmosphere(self) -> str: - """ - 通大气 - 将真空度恢复到大气压 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._target_vacuum = self._max_vacuum # 设置为大气压 - self._status = "Venting to Atmosphere" - return "Success" - - def emergency_stop(self) -> str: - """ - 紧急停止 - - Returns: - str: 操作结果状态 ("Success", "Error") - """ - self._status = "Emergency Stop" - self._pump_state = "Stopped" - self._stop_vacuum_operation() - self._pump_speed = 0.0 - - return "Success" - - # ==================== 内部控制方法 ==================== - - def _start_vacuum_operation(self): - """ - 启动真空操作线程 - - 这个方法启动一个后台线程来模拟真空泵的实际运行过程。 - """ - with self._thread_lock: - if not self._running and self._power_state == "On": - self._running = True - self._vacuum_thread = threading.Thread(target=self._vacuum_operation_loop) - self._vacuum_thread.daemon = True - self._vacuum_thread.start() - - def _stop_vacuum_operation(self): - """ - 停止真空操作线程 - - 安全地停止后台运行线程并等待其完成。 - """ - with self._thread_lock: - self._running = False - if self._vacuum_thread and self._vacuum_thread.is_alive(): - self._vacuum_thread.join(timeout=2.0) - - def _vacuum_operation_loop(self): - """ - 真空操作主循环 - - 这个方法在后台线程中运行,模拟真空泵的工作过程: - 1. 检查电源状态和运行状态 - 2. 如果泵状态为 "Running",根据目标真空调整泵速和真空度 - 3. 否则等待 - """ - while self._running and self._power_state == "On": - try: - with self._thread_lock: - # 只有泵状态为 Running 时才进行更新 - if self._pump_state == "Running": - vacuum_diff = self._vacuum_level - self._target_vacuum - - if abs(vacuum_diff) < 1.0: # 真空度接近目标值 - self._status = "At Target Vacuum" - self._pump_speed = self._max_pump_speed * 0.2 # 维持真空的最小泵速 - elif vacuum_diff > 0: # 需要抽真空(降低压力) - self._status = "Pumping Down" - if vacuum_diff > 500: - self._pump_speed = self._max_pump_speed - elif vacuum_diff > 100: - self._pump_speed = self._max_pump_speed * 0.8 - elif vacuum_diff > 50: - self._pump_speed = self._max_pump_speed * 0.6 - else: - self._pump_speed = self._max_pump_speed * 0.4 - - # 根据泵速和效率计算真空降幅 - pump_rate = (self._pump_speed / self._max_pump_speed) * self._pump_efficiency / 100.0 - vacuum_reduction = pump_rate * 10.0 # 每秒最大降低10 mbar - self._vacuum_level = max(self._target_vacuum, self._vacuum_level - vacuum_reduction) - else: # 目标真空度高于当前值,需要通气 - self._status = "Venting" - self._pump_speed = 0.0 - self._vacuum_level = min(self._target_vacuum, self._vacuum_level + 5.0) - - # 限制真空度范围 - self._vacuum_level = max(self._min_vacuum, min(self._max_vacuum, self._vacuum_level)) - else: - # 当泵状态不是 Running 时,可保持原状态 - self._status = "Vacuum Pump Not Running" - # 释放锁后等待1秒钟 - time.sleep(1.0) - except Exception as e: - with self._thread_lock: - self._status = f"Error in vacuum operation: {str(e)}" - break - - # 循环结束后的清理工作 - if self._pump_state == "Running": - self._status = "Idle" - # 停止泵后,真空度逐渐回升到大气压 - while self._vacuum_level < self._max_vacuum * 0.9: - with self._thread_lock: - self._vacuum_level += 2.0 - time.sleep(0.1) - - def get_status_info(self) -> dict: - """ - 获取完整的设备状态信息 - - Returns: - dict: 包含所有设备状态的字典 - """ - return { - "status": self._status, - "power_state": self._power_state, - "pump_state": self._pump_state, - "vacuum_level": self._vacuum_level, - "target_vacuum": self._target_vacuum, - "pump_speed": self._pump_speed, - "pump_efficiency": self._pump_efficiency, - "max_pump_speed": self._max_pump_speed, - } - - -# 用于测试的主函数 -if __name__ == "__main__": - vacuum = MockVacuum() - - # 测试基本功能 - print("启动真空泵测试...") - vacuum.power_control("On") - print(f"初始状态: {vacuum.get_status_info()}") - - # 设置目标真空度并启动 - vacuum.set_vacuum_level(10.0) # 设置为10mbar - vacuum.start_vacuum() - - # 模拟运行15秒 - for i in range(15): - time.sleep(1) - print( - f"第{i+1}秒: 真空度={vacuum.vacuum_level:.1f}mbar, 泵速={vacuum.pump_speed:.1f}L/s, 状态={vacuum.status}" - ) - # 测试通大气 - print("测试通大气...") - vacuum.vent_to_atmosphere() - - # 继续运行5秒观察通大气过程 - for i in range(5): - time.sleep(1) - print(f"通大气第{i+1}秒: 真空度={vacuum.vacuum_level:.1f}mbar, 状态={vacuum.status}") - - vacuum.emergency_stop() - print("测试完成") diff --git a/unilabos/registry/device_comms/serial.yaml b/unilabos/registry/device_comms/communication_devices.yaml similarity index 98% rename from unilabos/registry/device_comms/serial.yaml rename to unilabos/registry/device_comms/communication_devices.yaml index 3bf2b023..4b49cc99 100644 --- a/unilabos/registry/device_comms/serial.yaml +++ b/unilabos/registry/device_comms/communication_devices.yaml @@ -1,6 +1,6 @@ serial: category: - - serial + - communication_devices class: action_value_mappings: auto-handle_serial_request: diff --git a/unilabos/registry/devices/camera.yaml b/unilabos/registry/devices/camera.yaml index ea5337e8..5f5b24bc 100644 --- a/unilabos/registry/devices/camera.yaml +++ b/unilabos/registry/devices/camera.yaml @@ -1,4 +1,4 @@ -camera: +camera.USB: category: - camera class: diff --git a/unilabos/registry/devices/characterization_chromatic.yaml b/unilabos/registry/devices/characterization_chromatic.yaml new file mode 100644 index 00000000..7132b4fb --- /dev/null +++ b/unilabos/registry/devices/characterization_chromatic.yaml @@ -0,0 +1,404 @@ +hplc.agilent: + category: + - characterization_chromatic + class: + action_value_mappings: + auto-check_status: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: 检查安捷伦HPLC设备状态的函数。用于监控设备的运行状态、连接状态、错误信息等关键指标。该函数定期查询设备状态,确保系统稳定运行,及时发现和报告设备异常。适用于自动化流程中的设备监控、故障诊断、系统维护等场景。 + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: check_status参数 + type: object + type: UniLabJsonCommand + auto-extract_data_from_txt: + feedback: {} + goal: {} + goal_default: + file_path: null + handles: [] + result: {} + schema: + description: 从文本文件中提取分析数据的函数。用于解析安捷伦HPLC生成的结果文件,提取峰面积、保留时间、浓度等关键分析数据。支持多种文件格式的自动识别和数据结构化处理,为后续数据分析和报告生成提供标准化的数据格式。适用于批量数据处理、结果验证、质量控制等分析工作流程。 + properties: + feedback: {} + goal: + properties: + file_path: + type: string + required: + - file_path + type: object + result: {} + required: + - goal + title: extract_data_from_txt参数 + type: object + type: UniLabJsonCommand + auto-start_sequence: + feedback: {} + goal: {} + goal_default: + params: null + resource: null + wf_name: null + handles: [] + result: {} + schema: + description: 启动安捷伦HPLC分析序列的函数。用于执行预定义的分析方法序列,包括样品进样、色谱分离、检测等完整的分析流程。支持参数配置、资源分配、工作流程管理等功能,实现全自动的样品分析。适用于批量样品处理、标准化分析、质量检测等需要连续自动分析的应用场景。 + properties: + feedback: {} + goal: + properties: + params: + type: string + resource: + type: object + wf_name: + type: string + required: + - wf_name + type: object + result: {} + required: + - goal + title: start_sequence参数 + type: object + type: UniLabJsonCommand + auto-try_close_sub_device: + feedback: {} + goal: {} + goal_default: + device_name: null + handles: [] + result: {} + schema: + description: 尝试关闭HPLC子设备的函数。用于安全地关闭泵、检测器、进样器等各个子模块,确保设备正常断开连接并保护硬件安全。该函数提供错误处理和状态确认机制,避免强制关闭可能造成的设备损坏。适用于设备维护、系统重启、紧急停机等需要安全关闭设备的场景。 + properties: + feedback: {} + goal: + properties: + device_name: + type: string + required: [] + type: object + result: {} + required: + - goal + title: try_close_sub_device参数 + type: object + type: UniLabJsonCommand + auto-try_open_sub_device: + feedback: {} + goal: {} + goal_default: + device_name: null + handles: [] + result: {} + schema: + description: 尝试打开HPLC子设备的函数。用于初始化和连接泵、检测器、进样器等各个子模块,建立设备通信并进行自检。该函数提供连接验证和错误恢复机制,确保子设备正常启动并准备就绪。适用于设备初始化、系统启动、设备重连等需要建立设备连接的场景。 + properties: + feedback: {} + goal: + properties: + device_name: + type: string + required: [] + type: object + result: {} + required: + - goal + title: try_open_sub_device参数 + type: object + type: UniLabJsonCommand + execute_command_from_outer: + feedback: {} + goal: + command: command + goal_default: + command: '' + handles: [] + result: + success: success + schema: + description: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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.hplc.AgilentHPLC:HPLCDriver + status_types: + could_run: bool + data_file: list + device_status: str + driver_init_ok: bool + finish_status: str + is_running: bool + status_text: str + success: bool + type: python + config_info: [] + description: 安捷伦高效液相色谱(HPLC)分析设备,用于复杂化合物的分离、检测和定量分析。该设备通过UI自动化技术控制安捷伦ChemStation软件,实现全自动的样品分析流程。具备序列启动、设备状态监控、数据文件提取、结果处理等功能。支持多样品批量处理和实时状态反馈,适用于药物分析、环境检测、食品安全、化学研究等需要高精度色谱分析的实验室应用。 + handles: [] + icon: '' + init_param_schema: + config: + properties: + driver_debug: + default: false + type: string + required: [] + type: object + data: + properties: + could_run: + type: boolean + data_file: + type: array + device_status: + type: string + driver_init_ok: + type: boolean + finish_status: + type: string + is_running: + type: boolean + status_text: + type: string + success: + type: boolean + required: + - status_text + - device_status + - could_run + - driver_init_ok + - is_running + - success + - finish_status + - data_file + type: object + version: 1.0.0 +hplc.agilent-zhida: + category: + - characterization_chromatic + class: + action_value_mappings: + abort: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: '' + properties: + feedback: + properties: {} + required: [] + title: EmptyIn_Feedback + type: object + goal: + properties: {} + required: [] + title: EmptyIn_Goal + type: object + result: + properties: + return_info: + type: string + required: + - return_info + title: EmptyIn_Result + type: object + required: + - goal + title: EmptyIn + type: object + type: EmptyIn + auto-close: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: HPLC设备连接关闭函数。安全地断开与智达HPLC设备的TCP socket连接,释放网络资源。该函数确保连接的正确关闭,避免网络资源泄露。通常在设备使用完毕或系统关闭时调用。 + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: close参数 + type: object + type: UniLabJsonCommand + auto-connect: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: HPLC设备连接建立函数。与智达HPLC设备建立TCP socket通信连接,配置通信超时参数。该函数是设备使用前的必要步骤,建立成功后可进行状态查询、方法获取、任务启动等操作。连接失败时会抛出异常。 + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: connect参数 + type: object + type: UniLabJsonCommand + get_methods: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: '' + properties: + feedback: + properties: {} + required: [] + title: EmptyIn_Feedback + type: object + goal: + properties: {} + required: [] + title: EmptyIn_Goal + type: object + result: + properties: + return_info: + type: string + required: + - return_info + title: EmptyIn_Result + type: object + required: + - goal + title: EmptyIn + type: object + type: EmptyIn + start: + feedback: {} + goal: + string: string + goal_default: + string: '' + handles: [] + result: {} + schema: + description: '' + properties: + feedback: + properties: {} + required: [] + title: StrSingleInput_Feedback + type: object + goal: + properties: + string: + type: string + required: + - string + title: StrSingleInput_Goal + type: object + result: + 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: + methods: dict + status: dict + type: python + config_info: [] + description: 智达高效液相色谱(HPLC)分析设备,用于实验室样品的分离、检测和定量分析。该设备通过TCP socket与HPLC控制系统通信,支持远程控制和状态监控。具备自动进样、梯度洗脱、多检测器数据采集等功能,可执行复杂的色谱分析方法。适用于化学分析、药物检测、环境监测、生物样品分析等需要高精度分离分析的实验室应用场景。 + handles: [] + icon: '' + init_param_schema: + config: + properties: + host: + default: 192.168.1.47 + type: string + port: + default: 5792 + type: string + timeout: + default: 10.0 + type: string + required: [] + type: object + data: + properties: + methods: + type: object + status: + type: object + required: + - status + - methods + type: object + version: 1.0.0 diff --git a/unilabos/registry/devices/characterization_optic.yaml b/unilabos/registry/devices/characterization_optic.yaml index 5fef8552..6ebdcbd3 100644 --- a/unilabos/registry/devices/characterization_optic.yaml +++ b/unilabos/registry/devices/characterization_optic.yaml @@ -1,225 +1,4 @@ -hplc.agilent: - category: - - characterization_optic - class: - action_value_mappings: - auto-check_status: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: 检查安捷伦HPLC设备状态的函数。用于监控设备的运行状态、连接状态、错误信息等关键指标。该函数定期查询设备状态,确保系统稳定运行,及时发现和报告设备异常。适用于自动化流程中的设备监控、故障诊断、系统维护等场景。 - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: check_status参数 - type: object - type: UniLabJsonCommand - auto-extract_data_from_txt: - feedback: {} - goal: {} - goal_default: - file_path: null - handles: [] - result: {} - schema: - description: 从文本文件中提取分析数据的函数。用于解析安捷伦HPLC生成的结果文件,提取峰面积、保留时间、浓度等关键分析数据。支持多种文件格式的自动识别和数据结构化处理,为后续数据分析和报告生成提供标准化的数据格式。适用于批量数据处理、结果验证、质量控制等分析工作流程。 - properties: - feedback: {} - goal: - properties: - file_path: - type: string - required: - - file_path - type: object - result: {} - required: - - goal - title: extract_data_from_txt参数 - type: object - type: UniLabJsonCommand - auto-start_sequence: - feedback: {} - goal: {} - goal_default: - params: null - resource: null - wf_name: null - handles: [] - result: {} - schema: - description: 启动安捷伦HPLC分析序列的函数。用于执行预定义的分析方法序列,包括样品进样、色谱分离、检测等完整的分析流程。支持参数配置、资源分配、工作流程管理等功能,实现全自动的样品分析。适用于批量样品处理、标准化分析、质量检测等需要连续自动分析的应用场景。 - properties: - feedback: {} - goal: - properties: - params: - type: string - resource: - type: object - wf_name: - type: string - required: - - wf_name - type: object - result: {} - required: - - goal - title: start_sequence参数 - type: object - type: UniLabJsonCommand - auto-try_close_sub_device: - feedback: {} - goal: {} - goal_default: - device_name: null - handles: [] - result: {} - schema: - description: 尝试关闭HPLC子设备的函数。用于安全地关闭泵、检测器、进样器等各个子模块,确保设备正常断开连接并保护硬件安全。该函数提供错误处理和状态确认机制,避免强制关闭可能造成的设备损坏。适用于设备维护、系统重启、紧急停机等需要安全关闭设备的场景。 - properties: - feedback: {} - goal: - properties: - device_name: - type: string - required: [] - type: object - result: {} - required: - - goal - title: try_close_sub_device参数 - type: object - type: UniLabJsonCommand - auto-try_open_sub_device: - feedback: {} - goal: {} - goal_default: - device_name: null - handles: [] - result: {} - schema: - description: 尝试打开HPLC子设备的函数。用于初始化和连接泵、检测器、进样器等各个子模块,建立设备通信并进行自检。该函数提供连接验证和错误恢复机制,确保子设备正常启动并准备就绪。适用于设备初始化、系统启动、设备重连等需要建立设备连接的场景。 - properties: - feedback: {} - goal: - properties: - device_name: - type: string - required: [] - type: object - result: {} - required: - - goal - title: try_open_sub_device参数 - type: object - type: UniLabJsonCommand - execute_command_from_outer: - feedback: {} - goal: - command: command - goal_default: - command: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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.hplc.AgilentHPLC:HPLCDriver - status_types: - could_run: bool - data_file: list - device_status: str - driver_init_ok: bool - finish_status: str - is_running: bool - status_text: str - success: bool - type: python - config_info: [] - description: 安捷伦高效液相色谱(HPLC)分析设备,用于复杂化合物的分离、检测和定量分析。该设备通过UI自动化技术控制安捷伦ChemStation软件,实现全自动的样品分析流程。具备序列启动、设备状态监控、数据文件提取、结果处理等功能。支持多样品批量处理和实时状态反馈,适用于药物分析、环境检测、食品安全、化学研究等需要高精度色谱分析的实验室应用。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - driver_debug: - default: false - type: string - required: [] - type: object - data: - properties: - could_run: - type: boolean - data_file: - type: array - device_status: - type: string - driver_init_ok: - type: boolean - finish_status: - type: string - is_running: - type: boolean - status_text: - type: string - success: - type: boolean - required: - - status_text - - device_status - - could_run - - driver_init_ok - - is_running - - success - - finish_status - - data_file - type: object - version: 1.0.0 -raman_home_made: +raman.home_made: category: - characterization_optic class: diff --git a/unilabos/registry/devices/vacuum_and_purge.yaml b/unilabos/registry/devices/gas_handler.yaml similarity index 99% rename from unilabos/registry/devices/vacuum_and_purge.yaml rename to unilabos/registry/devices/gas_handler.yaml index a127a086..944675b1 100644 --- a/unilabos/registry/devices/vacuum_and_purge.yaml +++ b/unilabos/registry/devices/gas_handler.yaml @@ -1,6 +1,6 @@ gas_source.mock: category: - - vacuum_and_purge + - gas_handler class: action_value_mappings: auto-is_closed: @@ -180,6 +180,7 @@ gas_source.mock: vacuum_pump.mock: category: - vacuum_and_purge + - gas_handler class: action_value_mappings: auto-is_closed: diff --git a/unilabos/registry/devices/mock_devices.yaml b/unilabos/registry/devices/mock_devices.yaml deleted file mode 100644 index ec629868..00000000 --- a/unilabos/registry/devices/mock_devices.yaml +++ /dev/null @@ -1,4685 +0,0 @@ -mock_chiller: - category: - - mock_devices - class: - action_value_mappings: - emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - heat_chill_start: - feedback: {} - goal: - purpose: purpose - temp: temp - vessel: vessel - goal_default: - purpose: '' - temp: 0.0 - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - status: status - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: HeatChillStart_Feedback - type: object - goal: - properties: - purpose: - type: string - temp: - type: number - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - temp - - purpose - title: HeatChillStart_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: HeatChillStart_Result - type: object - required: - - goal - title: HeatChillStart - type: object - type: HeatChillStart - heat_chill_stop: - feedback: {} - goal: - vessel: vessel - goal_default: - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - status: status - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: HeatChillStop_Feedback - type: object - goal: - properties: - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - title: HeatChillStop_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: HeatChillStop_Result - type: object - required: - - goal - title: HeatChillStop - type: object - type: HeatChillStop - module: unilabos.devices.mock.mock_chiller:MockChiller - status_types: - current_temperature: float - is_cooling: bool - is_heating: bool - purpose: str - status: str - status_info: dict - target_temperature: float - vessel: str - type: python - config_info: [] - description: Mock Chiller Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - current_temperature: - type: number - is_cooling: - type: boolean - is_heating: - type: boolean - purpose: - type: string - status: - type: string - status_info: - type: object - target_temperature: - type: number - vessel: - type: string - required: - - current_temperature - - target_temperature - - status - - is_cooling - - is_heating - - vessel - - purpose - - status_info - type: object - version: 1.0.0 -mock_filter: - category: - - mock_devices - class: - action_value_mappings: - auto-emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: emergency_stop的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: emergency_stop参数 - type: object - type: UniLabJsonCommand - filter: - feedback: - current_status: current_status - current_temp: current_temp - filtered_volume: filtered_volume - progress: progress - goal: - continue_heatchill: continue_heatchill - filtrate_vessel: filtrate_vessel - stir: stir - stir_speed: stir_speed - temp: temp - vessel: vessel - volume: volume - goal_default: - continue_heatchill: false - filtrate_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - stir: false - stir_speed: 0.0 - temp: 0.0 - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - volume: 0.0 - handles: [] - result: - message: message - success: success - schema: - description: '' - properties: - feedback: - properties: - current_status: - type: string - current_temp: - type: number - filtered_volume: - type: number - progress: - type: number - required: - - progress - - current_temp - - filtered_volume - - current_status - title: Filter_Feedback - type: object - goal: - properties: - continue_heatchill: - type: boolean - filtrate_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - stir: - type: boolean - stir_speed: - type: number - temp: - type: number - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - volume: - type: number - required: - - vessel - - filtrate_vessel - - stir - - stir_speed - - temp - - continue_heatchill - - volume - title: Filter_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: Filter_Result - type: object - required: - - goal - title: Filter - type: object - type: Filter - replace_filter: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - stop_filtering: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_filter:MockFilter - status_types: - continue_heatchill: bool - filter_life: float - filtered_volume: float - filtrate_vessel: str - flow_rate: float - is_filtering: bool - pressure_drop: float - progress: float - status: str - status_info: dict - stir: bool - stir_speed: float - target_volume: float - temperature: float - vessel: str - type: python - config_info: [] - description: Mock Filter Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - continue_heatchill: - type: boolean - filter_life: - type: number - filtered_volume: - type: number - filtrate_vessel: - type: string - flow_rate: - type: number - is_filtering: - type: boolean - pressure_drop: - type: number - progress: - type: number - status: - type: string - status_info: - type: object - stir: - type: boolean - stir_speed: - type: number - target_volume: - type: number - temperature: - type: number - vessel: - type: string - required: - - status - - is_filtering - - flow_rate - - pressure_drop - - filter_life - - vessel - - filtrate_vessel - - filtered_volume - - progress - - stir - - stir_speed - - temperature - - continue_heatchill - - target_volume - - status_info - type: object - version: 1.0.0 -mock_heater: - category: - - mock_devices - class: - action_value_mappings: - auto-set_heating_power: - feedback: {} - goal: {} - goal_default: - power: null - handles: [] - result: {} - schema: - description: set_heating_power的参数schema - properties: - feedback: {} - goal: - properties: - power: - type: number - required: - - power - type: object - result: {} - required: - - goal - title: set_heating_power参数 - type: object - type: UniLabJsonCommand - auto-set_temperature: - feedback: {} - goal: {} - goal_default: - temperature: null - handles: [] - result: {} - schema: - description: set_temperature的参数schema - properties: - feedback: {} - goal: - properties: - temperature: - type: number - required: - - temperature - type: object - result: {} - required: - - goal - title: set_temperature参数 - type: object - type: UniLabJsonCommand - emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - heat_chill: - feedback: - status: status - goal: - purpose: purpose - stir: stir - stir_speed: stir_speed - temp: temp - time: time - vessel: vessel - goal_default: - pressure: '' - purpose: '' - reflux_solvent: '' - stir: false - stir_speed: 0.0 - temp: 0.0 - temp_spec: '' - time: '' - time_spec: '' - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: HeatChill_Feedback - type: object - goal: - properties: - pressure: - type: string - purpose: - type: string - reflux_solvent: - type: string - stir: - type: boolean - stir_speed: - type: number - temp: - type: number - temp_spec: - type: string - time: - type: string - time_spec: - type: string - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - temp - - time - - temp_spec - - time_spec - - pressure - - reflux_solvent - - stir - - stir_speed - - purpose - title: HeatChill_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: HeatChill_Result - type: object - required: - - goal - title: HeatChill - type: object - type: HeatChill - heat_chill_start: - feedback: - status: status - goal: - purpose: purpose - temp: temp - vessel: vessel - goal_default: - purpose: '' - temp: 0.0 - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: HeatChillStart_Feedback - type: object - goal: - properties: - purpose: - type: string - temp: - type: number - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - temp - - purpose - title: HeatChillStart_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: HeatChillStart_Result - type: object - required: - - goal - title: HeatChillStart - type: object - type: HeatChillStart - heat_chill_stop: - feedback: - status: status - goal: - vessel: vessel - goal_default: - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: HeatChillStop_Feedback - type: object - goal: - properties: - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - title: HeatChillStop_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: HeatChillStop_Result - type: object - required: - - goal - title: HeatChillStop - type: object - type: HeatChillStop - module: unilabos.devices.mock.mock_heater:MockHeater - status_types: - current_temperature: float - heating_power: float - is_heating: bool - max_temperature: float - purpose: str - status: str - status_info: dict - stir: bool - stir_speed: float - target_temperature: float - vessel: str - type: python - config_info: [] - description: Mock Heater Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - current_temperature: - type: number - heating_power: - type: number - is_heating: - type: boolean - max_temperature: - type: number - purpose: - type: string - status: - type: string - status_info: - type: object - stir: - type: boolean - stir_speed: - type: number - target_temperature: - type: number - vessel: - type: string - required: - - current_temperature - - target_temperature - - status - - is_heating - - heating_power - - max_temperature - - vessel - - purpose - - stir - - stir_speed - - status_info - type: object - version: 1.0.0 -mock_pump: - category: - - mock_devices - class: - action_value_mappings: - auto-emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: emergency_stop的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: emergency_stop参数 - type: object - type: UniLabJsonCommand - pause_pump: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - pump_transfer: - feedback: - current_device: current_device - status: status - time_remaining: time_remaining - time_spent: time_spent - goal: - amount: amount - from_vessel: from_vessel - rinsing_repeats: rinsing_repeats - rinsing_solvent: rinsing_solvent - rinsing_volume: rinsing_volume - solid: solid - time: time - to_vessel: to_vessel - viscous: viscous - volume: volume - goal_default: - amount: '' - event: '' - flowrate: 0.0 - from_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - rate_spec: '' - rinsing_repeats: 0 - rinsing_solvent: '' - rinsing_volume: 0.0 - solid: false - through: '' - time: 0.0 - to_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - transfer_flowrate: 0.0 - viscous: false - volume: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - current_device: - type: string - status: - type: string - time_remaining: - properties: - nanosec: - maximum: 4294967295 - minimum: 0 - type: integer - sec: - maximum: 2147483647 - minimum: -2147483648 - type: integer - required: - - sec - - nanosec - title: Duration - type: object - time_spent: - properties: - nanosec: - maximum: 4294967295 - minimum: 0 - type: integer - sec: - maximum: 2147483647 - minimum: -2147483648 - type: integer - required: - - sec - - nanosec - title: Duration - type: object - required: - - status - - current_device - - time_spent - - time_remaining - title: PumpTransfer_Feedback - type: object - goal: - properties: - amount: - type: string - event: - type: string - flowrate: - type: number - from_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - rate_spec: - type: string - rinsing_repeats: - maximum: 2147483647 - minimum: -2147483648 - type: integer - rinsing_solvent: - type: string - rinsing_volume: - type: number - solid: - type: boolean - through: - type: string - time: - type: number - to_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - transfer_flowrate: - type: number - viscous: - type: boolean - volume: - type: number - required: - - from_vessel - - to_vessel - - volume - - amount - - time - - viscous - - rinsing_solvent - - rinsing_volume - - rinsing_repeats - - solid - - flowrate - - transfer_flowrate - - rate_spec - - event - - through - title: PumpTransfer_Goal - type: object - result: - properties: - return_info: - type: string - success: - type: boolean - required: - - return_info - - success - title: PumpTransfer_Result - type: object - required: - - goal - title: PumpTransfer - type: object - type: PumpTransfer - reset_volume_counter: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - resume_pump: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_pump:MockPump - status_types: - amount: str - current_device: str - flow_rate: float - from_vessel: str - is_solid: bool - is_viscous: bool - max_flow_rate: float - max_pressure: float - pressure: float - pump_state: str - rinsing_repeats: int - rinsing_solvent: str - rinsing_volume: float - status: str - status_info: dict - target_flow_rate: float - time_remaining: float - time_spent: float - to_vessel: str - total_volume: float - transfer_time: float - transfer_volume: float - type: python - config_info: [] - description: Mock Pump Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - amount: - type: string - current_device: - type: string - flow_rate: - type: number - from_vessel: - type: string - is_solid: - type: boolean - is_viscous: - type: boolean - max_flow_rate: - type: number - max_pressure: - type: number - pressure: - type: number - pump_state: - type: string - rinsing_repeats: - type: integer - rinsing_solvent: - type: string - rinsing_volume: - type: number - status: - type: string - status_info: - type: object - target_flow_rate: - type: number - time_remaining: - type: number - time_spent: - type: number - to_vessel: - type: string - total_volume: - type: number - transfer_time: - type: number - transfer_volume: - type: number - required: - - status - - current_device - - pump_state - - flow_rate - - target_flow_rate - - pressure - - total_volume - - max_flow_rate - - max_pressure - - from_vessel - - to_vessel - - transfer_volume - - amount - - transfer_time - - is_viscous - - rinsing_solvent - - rinsing_volume - - rinsing_repeats - - is_solid - - time_spent - - time_remaining - - status_info - type: object - version: 1.0.0 -mock_rotavap: - category: - - mock_devices - class: - action_value_mappings: - auto-emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: emergency_stop的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: emergency_stop参数 - type: object - type: UniLabJsonCommand - auto-stop_all_operations: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: stop_all_operations的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: stop_all_operations参数 - type: object - type: UniLabJsonCommand - set_pump_time: - feedback: {} - goal: - float_in: time_seconds - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - set_rotate_speed: - feedback: {} - goal: - float_in: speed - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - set_rotate_time: - feedback: {} - goal: - float_in: time_seconds - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - set_temperature: - feedback: {} - goal: - float_in: temperature - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - set_timer: - feedback: {} - goal: - string: command - goal_default: - string: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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 - start_pump: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - start_rotation: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_rotavap:MockRotavap - status_types: - pump_state: str - pump_time: float - rotate_speed: float - rotate_state: str - rotate_time: float - status: str - status_info: dict - target_temperature: float - temperature: float - vacuum_level: float - type: python - config_info: [] - description: Mock Rotavap Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - pump_state: - type: string - pump_time: - type: number - rotate_speed: - type: number - rotate_state: - type: string - rotate_time: - type: number - status: - type: string - status_info: - type: object - target_temperature: - type: number - temperature: - type: number - vacuum_level: - type: number - required: - - status - - rotate_state - - rotate_time - - rotate_speed - - pump_state - - pump_time - - vacuum_level - - temperature - - target_temperature - - status_info - type: object - version: 1.0.0 -mock_separator: - category: - - mock_devices - class: - action_value_mappings: - separate: - feedback: - current_device: current_device - status: status - time_remaining: time_remaining - time_spent: time_spent - goal: - from_vessel: from_vessel - product_phase: product_phase - purpose: purpose - repeats: repeats - separation_vessel: separation_vessel - settling_time: settling_time - solvent: solvent - solvent_volume: solvent_volume - stir_speed: stir_speed - stir_time: stir_time - through: through - to_vessel: to_vessel - waste_phase_to_vessel: waste_phase_to_vessel - goal_default: - from_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - product_phase: '' - product_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - purpose: '' - repeats: 0 - separation_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - settling_time: 0.0 - solvent: '' - solvent_volume: '' - stir_speed: 0.0 - stir_time: 0.0 - through: '' - to_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - volume: '' - waste_phase_to_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - waste_vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - progress: - type: number - status: - type: string - required: - - status - - progress - title: Separate_Feedback - type: object - goal: - properties: - from_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - product_phase: - type: string - product_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - purpose: - type: string - repeats: - maximum: 2147483647 - minimum: -2147483648 - type: integer - separation_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - settling_time: - type: number - solvent: - type: string - solvent_volume: - type: string - stir_speed: - type: number - stir_time: - type: number - through: - type: string - to_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - volume: - type: string - waste_phase_to_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - waste_vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - purpose - - product_phase - - from_vessel - - separation_vessel - - to_vessel - - waste_phase_to_vessel - - product_vessel - - waste_vessel - - solvent - - solvent_volume - - volume - - through - - repeats - - stir_time - - stir_speed - - settling_time - title: Separate_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: Separate_Result - type: object - required: - - goal - title: Separate - type: object - type: Separate - set_valve: - feedback: {} - goal: - string: command - goal_default: - string: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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 - shake: - feedback: - status: status - goal: - float_in: shake_time - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - stop_operations: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_separator:MockSeparator - status_types: - current_device: str - from_vessel: str - product_phase: str - purpose: str - repeats: int - separation_vessel: str - settling_time: float - shake_status: str - shake_time: float - solvent: str - solvent_volume: float - status: str - status_info: dict - stir_speed: float - stir_time: float - through: str - time_remaining: float - time_spent: float - to_vessel: str - valve_state: str - waste_phase_to_vessel: str - type: python - config_info: [] - description: Simplified Mock Separator Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - current_device: - type: string - from_vessel: - type: string - product_phase: - type: string - purpose: - type: string - repeats: - type: integer - separation_vessel: - type: string - settling_time: - type: number - shake_status: - type: string - shake_time: - type: number - solvent: - type: string - solvent_volume: - type: number - status: - type: string - status_info: - type: object - stir_speed: - type: number - stir_time: - type: number - through: - type: string - time_remaining: - type: number - time_spent: - type: number - to_vessel: - type: string - valve_state: - type: string - waste_phase_to_vessel: - type: string - required: - - current_device - - purpose - - valve_state - - settling_time - - status - - shake_time - - shake_status - - product_phase - - from_vessel - - separation_vessel - - to_vessel - - waste_phase_to_vessel - - solvent - - solvent_volume - - through - - repeats - - stir_time - - stir_speed - - time_spent - - time_remaining - - status_info - type: object - version: 1.0.0 -mock_solenoid_valve: - category: - - mock_devices - class: - action_value_mappings: - auto-is_closed: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: is_closed的参数schema - properties: - feedback: {} - goal: - 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: is_open的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: is_open参数 - type: object - type: UniLabJsonCommand - close_valve: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - open_valve: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - set_valve_status: - feedback: {} - goal: - string: status - goal_default: - string: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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.mock.mock_solenoid_valve:MockSolenoidValve - status_types: - status: str - valve_status: str - type: python - config_info: [] - description: Mock Solenoid Valve Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - status: - type: string - valve_status: - type: string - required: - - status - - valve_status - type: object - version: 1.0.0 -mock_stirrer: - category: - - mock_devices - class: - action_value_mappings: - auto-emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: emergency_stop的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: emergency_stop参数 - type: object - type: UniLabJsonCommand - auto-stop_all_operations: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: stop_all_operations的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: stop_all_operations参数 - type: object - type: UniLabJsonCommand - heating_control: - feedback: {} - goal: - string: heating_state - goal_default: - string: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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 - set_stir_speed: - feedback: {} - goal: - float_in: speed - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - set_temperature: - feedback: {} - goal: - float_in: temperature - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - start_stirring: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - stop_stirring: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_stirrer:MockStirrer - status_types: - heating_power: float - heating_state: str - max_stir_speed: float - max_temperature: float - status: str - status_info: dict - stir_speed: float - stir_state: str - target_stir_speed: float - target_temperature: float - temperature: float - type: python - config_info: [] - description: Mock Stirrer Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - heating_power: - type: number - heating_state: - type: string - max_stir_speed: - type: number - max_temperature: - type: number - status: - type: string - status_info: - type: object - stir_speed: - type: number - stir_state: - type: string - target_stir_speed: - type: number - target_temperature: - type: number - temperature: - type: number - required: - - status - - stir_speed - - target_stir_speed - - stir_state - - temperature - - target_temperature - - heating_state - - heating_power - - max_stir_speed - - max_temperature - - status_info - type: object - version: 1.0.0 -mock_stirrer_new: - category: - - mock_devices - class: - action_value_mappings: - start_stir: - feedback: - current_speed: stir_speed - current_status: status - progress: progress - goal: - purpose: purpose - stir_speed: stir_speed - vessel: vessel - goal_default: - purpose: '' - stir_speed: 0.0 - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - message: message - success: success - schema: - description: '' - properties: - feedback: - properties: - current_speed: - type: number - current_status: - type: string - progress: - type: number - required: - - progress - - current_speed - - current_status - title: StartStir_Feedback - type: object - goal: - properties: - purpose: - type: string - stir_speed: - type: number - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - stir_speed - - purpose - title: StartStir_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: StartStir_Result - type: object - required: - - goal - title: StartStir - type: object - type: StartStir - stir: - feedback: - status: status - goal: - settling_time: settling_time - stir_speed: stir_speed - stir_time: stir_time - goal_default: - event: '' - settling_time: '' - stir_speed: 0.0 - stir_time: 0.0 - time: '' - time_spec: '' - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: Stir_Feedback - type: object - goal: - properties: - event: - type: string - settling_time: - type: string - stir_speed: - type: number - stir_time: - type: number - time: - type: string - time_spec: - type: string - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - - time - - event - - time_spec - - stir_time - - stir_speed - - settling_time - title: Stir_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: Stir_Result - type: object - required: - - goal - title: Stir - type: object - type: Stir - stop_stir: - feedback: - current_status: status - progress: progress - goal: - vessel: vessel - goal_default: - vessel: - category: '' - children: [] - config: '' - data: '' - id: '' - name: '' - parent: '' - pose: - orientation: - w: 1.0 - x: 0.0 - y: 0.0 - z: 0.0 - position: - x: 0.0 - y: 0.0 - z: 0.0 - sample_id: '' - type: '' - handles: [] - result: - message: message - success: success - schema: - description: '' - properties: - feedback: - properties: - current_status: - type: string - progress: - type: number - required: - - progress - - current_status - title: StopStir_Feedback - type: object - goal: - properties: - vessel: - properties: - category: - type: string - children: - items: - type: string - type: array - config: - type: string - data: - type: string - id: - type: string - name: - type: string - parent: - type: string - 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 - sample_id: - type: string - type: - type: string - required: - - id - - name - - sample_id - - children - - parent - - type - - category - - pose - - config - - data - title: Resource - type: object - required: - - vessel - title: StopStir_Goal - type: object - result: - properties: - message: - type: string - return_info: - type: string - success: - type: boolean - required: - - success - - message - - return_info - title: StopStir_Result - type: object - required: - - goal - title: StopStir - type: object - type: StopStir - module: unilabos.devices.mock.mock_stirrer_new:MockStirrer_new - status_types: - max_stir_speed: float - progress: float - purpose: str - settling_time: float - status: str - status_info: dict - stir_speed: float - stir_state: str - stir_time: float - target_stir_speed: float - vessel: str - type: python - config_info: [] - description: Mock Stirrer Device (Copy Version) - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - max_stir_speed: - type: number - progress: - type: number - purpose: - type: string - settling_time: - type: number - status: - type: string - status_info: - type: object - stir_speed: - type: number - stir_state: - type: string - stir_time: - type: number - target_stir_speed: - type: number - vessel: - type: string - required: - - status - - stir_speed - - target_stir_speed - - stir_state - - vessel - - purpose - - stir_time - - settling_time - - max_stir_speed - - progress - - status_info - type: object - version: 1.0.0 -mock_vacuum: - category: - - mock_devices - class: - action_value_mappings: - auto-emergency_stop: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: emergency_stop的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: emergency_stop参数 - type: object - type: UniLabJsonCommand - pause_vacuum: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - power_control: - feedback: {} - goal: - string: power_state - goal_default: - string: '' - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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 - resume_vacuum: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - set_vacuum_level: - feedback: {} - goal: - float_in: vacuum_level - goal_default: - float_in: 0.0 - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: FloatSingleInput_Feedback - type: object - goal: - properties: - float_in: - type: number - required: - - float_in - title: FloatSingleInput_Goal - type: object - result: - 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 - start_vacuum: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - stop_vacuum: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - vent_to_atmosphere: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: - success: success - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - module: unilabos.devices.mock.mock_vacuum:MockVacuum - status_types: - max_pump_speed: float - power_state: str - pump_efficiency: float - pump_speed: float - pump_state: str - status: str - status_info: dict - target_vacuum: float - vacuum_level: float - type: python - config_info: [] - description: Mock Vacuum Pump Device - handles: [] - icon: '' - init_param_schema: - config: - properties: - port: - default: MOCK - type: string - required: [] - type: object - data: - properties: - max_pump_speed: - type: number - power_state: - type: string - pump_efficiency: - type: number - pump_speed: - type: number - pump_state: - type: string - status: - type: string - status_info: - type: object - target_vacuum: - type: number - vacuum_level: - type: number - required: - - status - - power_state - - pump_state - - vacuum_level - - target_vacuum - - pump_speed - - pump_efficiency - - max_pump_speed - - status_info - type: object - version: 1.0.0 diff --git a/unilabos/registry/devices/moveit_config.yaml b/unilabos/registry/devices/moveit_config.yaml deleted file mode 100644 index eafa5229..00000000 --- a/unilabos/registry/devices/moveit_config.yaml +++ /dev/null @@ -1,704 +0,0 @@ -moveit.arm_slider: - category: - - moveit_config - class: - action_value_mappings: - auto-check_tf_update_actions: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: check_tf_update_actions的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: check_tf_update_actions参数 - type: object - type: UniLabJsonCommand - auto-moveit_joint_task: - feedback: {} - goal: {} - goal_default: - joint_names: null - joint_positions: null - move_group: null - retry: 10 - speed: 1 - handles: [] - result: {} - schema: - description: moveit_joint_task的参数schema - properties: - feedback: {} - goal: - properties: - joint_names: - type: string - joint_positions: - type: string - move_group: - type: string - retry: - default: 10 - type: string - speed: - default: 1 - type: string - required: - - move_group - - joint_positions - type: object - result: {} - required: - - goal - title: moveit_joint_task参数 - type: object - type: UniLabJsonCommand - auto-moveit_task: - feedback: {} - goal: {} - goal_default: - cartesian: false - move_group: null - offsets: - - 0 - - 0 - - 0 - position: null - quaternion: null - retry: 10 - speed: 1 - target_link: null - handles: [] - result: {} - schema: - description: moveit_task的参数schema - properties: - feedback: {} - goal: - properties: - cartesian: - default: false - type: string - move_group: - type: string - offsets: - default: - - 0 - - 0 - - 0 - type: string - position: - type: string - quaternion: - type: string - retry: - default: 10 - type: string - speed: - default: 1 - type: string - target_link: - type: string - required: - - move_group - - position - - quaternion - type: object - result: {} - required: - - goal - title: moveit_task参数 - type: object - type: UniLabJsonCommand - auto-post_init: - feedback: {} - goal: {} - goal_default: - ros_node: null - handles: [] - result: {} - schema: - description: post_init的参数schema - properties: - feedback: {} - goal: - properties: - ros_node: - type: string - required: - - ros_node - type: object - result: {} - required: - - goal - title: post_init参数 - type: object - type: UniLabJsonCommand - auto-resource_manager: - feedback: {} - goal: {} - goal_default: - parent_link: null - resource: null - handles: [] - result: {} - schema: - description: resource_manager的参数schema - properties: - feedback: {} - goal: - properties: - parent_link: - type: string - resource: - type: string - required: - - resource - - parent_link - type: object - result: {} - required: - - goal - title: resource_manager参数 - type: object - type: UniLabJsonCommand - auto-wait_for_resource_action: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: wait_for_resource_action的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: wait_for_resource_action参数 - type: object - type: UniLabJsonCommand - pick_and_place: - feedback: {} - goal: - command: command - goal_default: - command: '' - handles: [] - result: {} - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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 - config_info: [] - description: 机械臂与滑块运动系统,基于MoveIt2运动规划框架的多自由度机械臂控制设备。该系统集成机械臂和线性滑块,通过ROS2和MoveIt2实现精确的轨迹规划和协调运动控制。支持笛卡尔空间和关节空间的运动规划、碰撞检测、逆运动学求解等功能。适用于复杂的pick-and-place操作、精密装配、多工位协作等需要高精度多轴协调运动的实验室自动化应用。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - device_config: - type: string - joint_poses: - type: string - moveit_type: - type: string - rotation: - type: string - required: - - moveit_type - - joint_poses - type: object - data: - properties: {} - required: [] - type: object - model: - mesh: arm_slider - type: device - version: 1.0.0 -moveit.toyo_xyz: - category: - - moveit_config - class: - action_value_mappings: - auto-check_tf_update_actions: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: check_tf_update_actions的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: check_tf_update_actions参数 - type: object - type: UniLabJsonCommand - auto-moveit_joint_task: - feedback: {} - goal: {} - goal_default: - joint_names: null - joint_positions: null - move_group: null - retry: 10 - speed: 1 - handles: [] - result: {} - schema: - description: moveit_joint_task的参数schema - properties: - feedback: {} - goal: - properties: - joint_names: - type: string - joint_positions: - type: string - move_group: - type: string - retry: - default: 10 - type: string - speed: - default: 1 - type: string - required: - - move_group - - joint_positions - type: object - result: {} - required: - - goal - title: moveit_joint_task参数 - type: object - type: UniLabJsonCommand - auto-moveit_task: - feedback: {} - goal: {} - goal_default: - cartesian: false - move_group: null - offsets: - - 0 - - 0 - - 0 - position: null - quaternion: null - retry: 10 - speed: 1 - target_link: null - handles: [] - result: {} - schema: - description: moveit_task的参数schema - properties: - feedback: {} - goal: - properties: - cartesian: - default: false - type: string - move_group: - type: string - offsets: - default: - - 0 - - 0 - - 0 - type: string - position: - type: string - quaternion: - type: string - retry: - default: 10 - type: string - speed: - default: 1 - type: string - target_link: - type: string - required: - - move_group - - position - - quaternion - type: object - result: {} - required: - - goal - title: moveit_task参数 - type: object - type: UniLabJsonCommand - auto-post_init: - feedback: {} - goal: {} - goal_default: - ros_node: null - handles: [] - result: {} - schema: - description: post_init的参数schema - properties: - feedback: {} - goal: - properties: - ros_node: - type: string - required: - - ros_node - type: object - result: {} - required: - - goal - title: post_init参数 - type: object - type: UniLabJsonCommand - auto-resource_manager: - feedback: {} - goal: {} - goal_default: - parent_link: null - resource: null - handles: [] - result: {} - schema: - description: resource_manager的参数schema - properties: - feedback: {} - goal: - properties: - parent_link: - type: string - resource: - type: string - required: - - resource - - parent_link - type: object - result: {} - required: - - goal - title: resource_manager参数 - type: object - type: UniLabJsonCommand - auto-wait_for_resource_action: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: wait_for_resource_action的参数schema - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: wait_for_resource_action参数 - type: object - type: UniLabJsonCommand - pick_and_place: - feedback: {} - goal: - command: command - goal_default: - command: '' - handles: [] - result: {} - schema: - description: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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: '' - properties: - feedback: - properties: - status: - type: string - required: - - status - title: SendCmd_Feedback - type: object - goal: - properties: - command: - type: string - required: - - command - title: SendCmd_Goal - type: object - result: - 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 - config_info: [] - description: 东洋XYZ三轴运动平台,基于MoveIt2运动规划框架的精密定位设备。该设备通过ROS2和MoveIt2实现三维空间的精确运动控制,支持复杂轨迹规划、多点定位、速度控制等功能。具备高精度定位、平稳运动、实时轨迹监控等特性。适用于精密加工、样品定位、检测扫描、自动化装配等需要高精度三维运动控制的实验室和工业应用场景。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - device_config: - type: string - joint_poses: - type: string - moveit_type: - type: string - rotation: - type: string - required: - - moveit_type - - joint_poses - type: object - data: - properties: {} - required: [] - type: object - model: - mesh: toyo_xyz - type: device - version: 1.0.0 diff --git a/unilabos/registry/devices/robot_arm.yaml b/unilabos/registry/devices/robot_arm.yaml index 64b7344f..61803d17 100644 --- a/unilabos/registry/devices/robot_arm.yaml +++ b/unilabos/registry/devices/robot_arm.yaml @@ -1,3 +1,355 @@ +robotic_arm.SCARA_with_slider.virtual: + category: + - robot_arm + class: + action_value_mappings: + auto-check_tf_update_actions: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: check_tf_update_actions的参数schema + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: check_tf_update_actions参数 + type: object + type: UniLabJsonCommand + auto-moveit_joint_task: + feedback: {} + goal: {} + goal_default: + joint_names: null + joint_positions: null + move_group: null + retry: 10 + speed: 1 + handles: [] + result: {} + schema: + description: moveit_joint_task的参数schema + properties: + feedback: {} + goal: + properties: + joint_names: + type: string + joint_positions: + type: string + move_group: + type: string + retry: + default: 10 + type: string + speed: + default: 1 + type: string + required: + - move_group + - joint_positions + type: object + result: {} + required: + - goal + title: moveit_joint_task参数 + type: object + type: UniLabJsonCommand + auto-moveit_task: + feedback: {} + goal: {} + goal_default: + cartesian: false + move_group: null + offsets: + - 0 + - 0 + - 0 + position: null + quaternion: null + retry: 10 + speed: 1 + target_link: null + handles: [] + result: {} + schema: + description: moveit_task的参数schema + properties: + feedback: {} + goal: + properties: + cartesian: + default: false + type: string + move_group: + type: string + offsets: + default: + - 0 + - 0 + - 0 + type: string + position: + type: string + quaternion: + type: string + retry: + default: 10 + type: string + speed: + default: 1 + type: string + target_link: + type: string + required: + - move_group + - position + - quaternion + type: object + result: {} + required: + - goal + title: moveit_task参数 + type: object + type: UniLabJsonCommand + auto-post_init: + feedback: {} + goal: {} + goal_default: + ros_node: null + handles: [] + result: {} + schema: + description: post_init的参数schema + properties: + feedback: {} + goal: + properties: + ros_node: + type: string + required: + - ros_node + type: object + result: {} + required: + - goal + title: post_init参数 + type: object + type: UniLabJsonCommand + auto-resource_manager: + feedback: {} + goal: {} + goal_default: + parent_link: null + resource: null + handles: [] + result: {} + schema: + description: resource_manager的参数schema + properties: + feedback: {} + goal: + properties: + parent_link: + type: string + resource: + type: string + required: + - resource + - parent_link + type: object + result: {} + required: + - goal + title: resource_manager参数 + type: object + type: UniLabJsonCommand + auto-wait_for_resource_action: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: wait_for_resource_action的参数schema + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: wait_for_resource_action参数 + type: object + type: UniLabJsonCommand + pick_and_place: + feedback: {} + goal: + command: command + goal_default: + command: '' + handles: [] + result: {} + schema: + description: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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 + config_info: [] + description: 机械臂与滑块运动系统,基于MoveIt2运动规划框架的多自由度机械臂控制设备。该系统集成机械臂和线性滑块,通过ROS2和MoveIt2实现精确的轨迹规划和协调运动控制。支持笛卡尔空间和关节空间的运动规划、碰撞检测、逆运动学求解等功能。适用于复杂的pick-and-place操作、精密装配、多工位协作等需要高精度多轴协调运动的实验室自动化应用。 + handles: [] + icon: '' + init_param_schema: + config: + properties: + device_config: + type: string + joint_poses: + type: string + moveit_type: + type: string + rotation: + type: string + required: + - moveit_type + - joint_poses + type: object + data: + properties: {} + required: [] + type: object + model: + mesh: arm_slider + type: device + version: 1.0.0 robotic_arm.UR: category: - robot_arm diff --git a/unilabos/registry/devices/robot_linear_motion.yaml b/unilabos/registry/devices/robot_linear_motion.yaml index 3ca4e9ad..70885351 100644 --- a/unilabos/registry/devices/robot_linear_motion.yaml +++ b/unilabos/registry/devices/robot_linear_motion.yaml @@ -470,6 +470,358 @@ linear_motion.grbl: - spindle_speed type: object version: 1.0.0 +linear_motion.toyo_xyz.sim: + category: + - robot_linear_motion + class: + action_value_mappings: + auto-check_tf_update_actions: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: check_tf_update_actions的参数schema + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: check_tf_update_actions参数 + type: object + type: UniLabJsonCommand + auto-moveit_joint_task: + feedback: {} + goal: {} + goal_default: + joint_names: null + joint_positions: null + move_group: null + retry: 10 + speed: 1 + handles: [] + result: {} + schema: + description: moveit_joint_task的参数schema + properties: + feedback: {} + goal: + properties: + joint_names: + type: string + joint_positions: + type: string + move_group: + type: string + retry: + default: 10 + type: string + speed: + default: 1 + type: string + required: + - move_group + - joint_positions + type: object + result: {} + required: + - goal + title: moveit_joint_task参数 + type: object + type: UniLabJsonCommand + auto-moveit_task: + feedback: {} + goal: {} + goal_default: + cartesian: false + move_group: null + offsets: + - 0 + - 0 + - 0 + position: null + quaternion: null + retry: 10 + speed: 1 + target_link: null + handles: [] + result: {} + schema: + description: moveit_task的参数schema + properties: + feedback: {} + goal: + properties: + cartesian: + default: false + type: string + move_group: + type: string + offsets: + default: + - 0 + - 0 + - 0 + type: string + position: + type: string + quaternion: + type: string + retry: + default: 10 + type: string + speed: + default: 1 + type: string + target_link: + type: string + required: + - move_group + - position + - quaternion + type: object + result: {} + required: + - goal + title: moveit_task参数 + type: object + type: UniLabJsonCommand + auto-post_init: + feedback: {} + goal: {} + goal_default: + ros_node: null + handles: [] + result: {} + schema: + description: post_init的参数schema + properties: + feedback: {} + goal: + properties: + ros_node: + type: string + required: + - ros_node + type: object + result: {} + required: + - goal + title: post_init参数 + type: object + type: UniLabJsonCommand + auto-resource_manager: + feedback: {} + goal: {} + goal_default: + parent_link: null + resource: null + handles: [] + result: {} + schema: + description: resource_manager的参数schema + properties: + feedback: {} + goal: + properties: + parent_link: + type: string + resource: + type: string + required: + - resource + - parent_link + type: object + result: {} + required: + - goal + title: resource_manager参数 + type: object + type: UniLabJsonCommand + auto-wait_for_resource_action: + feedback: {} + goal: {} + goal_default: {} + handles: [] + result: {} + schema: + description: wait_for_resource_action的参数schema + properties: + feedback: {} + goal: + properties: {} + required: [] + type: object + result: {} + required: + - goal + title: wait_for_resource_action参数 + type: object + type: UniLabJsonCommand + pick_and_place: + feedback: {} + goal: + command: command + goal_default: + command: '' + handles: [] + result: {} + schema: + description: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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: '' + properties: + feedback: + properties: + status: + type: string + required: + - status + title: SendCmd_Feedback + type: object + goal: + properties: + command: + type: string + required: + - command + title: SendCmd_Goal + type: object + result: + 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 + config_info: [] + description: 东洋XYZ三轴运动平台,基于MoveIt2运动规划框架的精密定位设备。该设备通过ROS2和MoveIt2实现三维空间的精确运动控制,支持复杂轨迹规划、多点定位、速度控制等功能。具备高精度定位、平稳运动、实时轨迹监控等特性。适用于精密加工、样品定位、检测扫描、自动化装配等需要高精度三维运动控制的实验室和工业应用场景。 + handles: [] + icon: '' + init_param_schema: + config: + properties: + device_config: + type: string + joint_poses: + type: string + moveit_type: + type: string + rotation: + type: string + required: + - moveit_type + - joint_poses + type: object + data: + properties: {} + required: [] + type: object + model: + mesh: toyo_xyz + type: device + version: 1.0.0 motor.iCL42: category: - robot_linear_motion diff --git a/unilabos/registry/devices/sim_nodes.yaml b/unilabos/registry/devices/sim_nodes.yaml deleted file mode 100644 index f07966b4..00000000 --- a/unilabos/registry/devices/sim_nodes.yaml +++ /dev/null @@ -1,315 +0,0 @@ -lh_joint_publisher: - category: - - sim_nodes - class: - action_value_mappings: - auto-check_tf_update_actions: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: check_tf_update_actions的参数schema - properties: - feedback: {} - goal: - 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: find_resource_parent的参数schema - properties: - feedback: {} - goal: - properties: - 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: inverse_kinematics的参数schema - properties: - feedback: {} - goal: - properties: - parent_id: - type: string - x: - type: string - x_joint: - type: object - y: - type: string - y_joint: - type: object - z: - type: string - 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: lh_joint_action_callback的参数schema - properties: - feedback: {} - goal: - properties: - 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: lh_joint_pub_callback的参数schema - properties: - feedback: {} - goal: - 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: move_joints的参数schema - properties: - feedback: {} - goal: - properties: - option: - type: string - resource_names: - type: string - speed: - default: 0.1 - type: string - x: - type: string - x_joint: - type: string - y: - type: string - y_joint: - type: string - z: - type: string - 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: move_to的参数schema - properties: - feedback: {} - goal: - properties: - joint_positions: - type: string - parent_id: - type: string - 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: resource_move的参数schema - properties: - feedback: {} - goal: - properties: - channels: - type: array - link_name: - type: string - 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: send_resource_action的参数schema - properties: - feedback: {} - goal: - properties: - link_name: - type: string - resource_id_list: - type: array - 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 - status_types: {} - type: ros2 - config_info: [] - description: 液体处理器关节发布器,用于ROS2仿真系统中的液体处理设备运动控制。该节点通过发布关节状态驱动仿真模型中的机械臂运动,支持三维坐标到关节空间的逆运动学转换、多关节协调控制、资源跟踪和TF变换。具备精确的位置控制、速度调节、pick-and-place操作等功能。适用于液体处理系统的虚拟仿真、运动规划验证、系统集成测试等应用场景。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - device_id: - default: lh_joint_publisher - type: string - rate: - default: 50 - type: string - resource_tracker: - type: string - resources_config: - type: array - required: - - resources_config - - resource_tracker - type: object - data: - properties: {} - required: [] - type: object - version: 1.0.0 diff --git a/unilabos/registry/devices/laiyu_add_solid.yaml b/unilabos/registry/devices/solid_dispenser.yaml similarity index 99% rename from unilabos/registry/devices/laiyu_add_solid.yaml rename to unilabos/registry/devices/solid_dispenser.yaml index fbb654db..9c8cafb5 100644 --- a/unilabos/registry/devices/laiyu_add_solid.yaml +++ b/unilabos/registry/devices/solid_dispenser.yaml @@ -1,6 +1,6 @@ -laiyu_add_solid: +solid_dispenser.laiyu: category: - - laiyu_add_solid + - solid_dispenser class: action_value_mappings: add_powder_tube: diff --git a/unilabos/registry/devices/virtual_device.yaml b/unilabos/registry/devices/virtual_device.yaml index fa4d057c..55859f9c 100644 --- a/unilabos/registry/devices/virtual_device.yaml +++ b/unilabos/registry/devices/virtual_device.yaml @@ -2239,6 +2239,14 @@ virtual_multiway_valve: io_type: source label: '7' side: WEST + - data_key: fluid_port_8 + data_source: executor + data_type: fluid + description: 八通阀门端口8-特殊输入 + handler_key: '8' + io_type: target + label: '8' + side: WEST - data_key: fluid_port_8 data_source: executor data_type: fluid @@ -3983,14 +3991,6 @@ virtual_separator: io_type: source label: bottom_phase_out side: SOUTH - - data_key: top_outlet - data_source: executor - data_type: fluid - description: 上相(轻相)液体输出口 - handler_key: topphaseout - io_type: source - label: top_phase_out - side: EAST - data_key: mechanical_port data_source: handle data_type: mechanical diff --git a/unilabos/registry/devices/work_station.yaml b/unilabos/registry/devices/work_station.yaml index c1cc5aa4..097ff77e 100644 --- a/unilabos/registry/devices/work_station.yaml +++ b/unilabos/registry/devices/work_station.yaml @@ -1262,6 +1262,11 @@ workstation: data_type: resource handler_key: solvent label: Solvent + - data_key: reagent + data_source: handle + data_type: resource + handler_key: reagent + label: Reagent output: - data_key: vessel data_source: executor diff --git a/unilabos/registry/devices/zhida_hplc.yaml b/unilabos/registry/devices/zhida_hplc.yaml deleted file mode 100644 index ade1c0ff..00000000 --- a/unilabos/registry/devices/zhida_hplc.yaml +++ /dev/null @@ -1,183 +0,0 @@ -zhida_hplc: - category: - - zhida_hplc - class: - action_value_mappings: - abort: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - auto-close: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: HPLC设备连接关闭函数。安全地断开与智达HPLC设备的TCP socket连接,释放网络资源。该函数确保连接的正确关闭,避免网络资源泄露。通常在设备使用完毕或系统关闭时调用。 - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: close参数 - type: object - type: UniLabJsonCommand - auto-connect: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: HPLC设备连接建立函数。与智达HPLC设备建立TCP socket通信连接,配置通信超时参数。该函数是设备使用前的必要步骤,建立成功后可进行状态查询、方法获取、任务启动等操作。连接失败时会抛出异常。 - properties: - feedback: {} - goal: - properties: {} - required: [] - type: object - result: {} - required: - - goal - title: connect参数 - type: object - type: UniLabJsonCommand - get_methods: - feedback: {} - goal: {} - goal_default: {} - handles: [] - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: EmptyIn_Feedback - type: object - goal: - properties: {} - required: [] - title: EmptyIn_Goal - type: object - result: - properties: - return_info: - type: string - required: - - return_info - title: EmptyIn_Result - type: object - required: - - goal - title: EmptyIn - type: object - type: EmptyIn - start: - feedback: {} - goal: - string: string - goal_default: - string: '' - handles: [] - result: {} - schema: - description: '' - properties: - feedback: - properties: {} - required: [] - title: StrSingleInput_Feedback - type: object - goal: - properties: - string: - type: string - required: - - string - title: StrSingleInput_Goal - type: object - result: - 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: - methods: dict - status: dict - type: python - config_info: [] - description: 智达高效液相色谱(HPLC)分析设备,用于实验室样品的分离、检测和定量分析。该设备通过TCP socket与HPLC控制系统通信,支持远程控制和状态监控。具备自动进样、梯度洗脱、多检测器数据采集等功能,可执行复杂的色谱分析方法。适用于化学分析、药物检测、环境监测、生物样品分析等需要高精度分离分析的实验室应用场景。 - handles: [] - icon: '' - init_param_schema: - config: - properties: - host: - default: 192.168.1.47 - type: string - port: - default: 5792 - type: string - timeout: - default: 10.0 - type: string - required: [] - type: object - data: - properties: - methods: - type: object - status: - type: object - required: - - status - - methods - type: object - version: 1.0.0 diff --git a/unilabos/registry/resources/organic/container.yaml b/unilabos/registry/resources/organic/container.yaml index 28600987..66af5b92 100644 --- a/unilabos/registry/resources/organic/container.yaml +++ b/unilabos/registry/resources/organic/container.yaml @@ -28,7 +28,7 @@ container: handler_key: bind io_type: target label: bind - side: SOUTH + side: WEST icon: Flask.webp init_param_schema: {} registry_type: resource