mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2026-02-05 14:05:12 +00:00
修改了add protocol
This commit is contained in:
@@ -4,58 +4,83 @@
|
|||||||
"id": "AddTestStation",
|
"id": "AddTestStation",
|
||||||
"name": "添加试剂测试工作站",
|
"name": "添加试剂测试工作站",
|
||||||
"children": [
|
"children": [
|
||||||
"pump_add",
|
"transfer_pump",
|
||||||
"flask_1",
|
"multiway_valve",
|
||||||
"flask_2",
|
|
||||||
"flask_3",
|
|
||||||
"flask_4",
|
|
||||||
"reactor",
|
|
||||||
"stirrer",
|
"stirrer",
|
||||||
"flask_air"
|
"flask_reagent1",
|
||||||
|
"flask_reagent2",
|
||||||
|
"flask_reagent3",
|
||||||
|
"flask_reagent4",
|
||||||
|
"reactor",
|
||||||
|
"flask_waste",
|
||||||
|
"flask_rinsing",
|
||||||
|
"flask_buffer"
|
||||||
],
|
],
|
||||||
"parent": null,
|
"parent": null,
|
||||||
"type": "device",
|
"type": "device",
|
||||||
"class": "workstation",
|
"class": "workstation",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 620.6111111111111,
|
"x": 620,
|
||||||
"y": 171,
|
"y": 171,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"protocol_type": ["AddProtocol", "PumpTransferProtocol", "CleanProtocol"]
|
"protocol_type": ["AddProtocol", "TransferProtocol", "StirProtocol", "StartStirProtocol", "StopStirProtocol"]
|
||||||
},
|
},
|
||||||
"data": {}
|
"data": {}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "pump_add",
|
"id": "transfer_pump",
|
||||||
"name": "pump_add",
|
"name": "注射器泵",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "device",
|
"type": "device",
|
||||||
"class": "virtual_pump",
|
"class": "virtual_transfer_pump",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 520.6111111111111,
|
"x": 520,
|
||||||
"y": 300,
|
"y": 300,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"port": "VIRTUAL",
|
"port": "VIRTUAL",
|
||||||
"max_volume": 25.0
|
"max_volume": 50.0,
|
||||||
|
"transfer_rate": 5.0
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"status": "Idle"
|
"status": "Idle"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "multiway_valve",
|
||||||
|
"name": "八通阀门",
|
||||||
|
"children": [],
|
||||||
|
"parent": "AddTestStation",
|
||||||
|
"type": "device",
|
||||||
|
"class": "virtual_multiway_valve",
|
||||||
|
"position": {
|
||||||
|
"x": 420,
|
||||||
|
"y": 300,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"port": "VIRTUAL",
|
||||||
|
"positions": 8
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"status": "Idle",
|
||||||
|
"current_position": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "stirrer",
|
"id": "stirrer",
|
||||||
"name": "stirrer",
|
"name": "搅拌器",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "device",
|
"type": "device",
|
||||||
"class": "virtual_stirrer",
|
"class": "virtual_stirrer",
|
||||||
"position": {
|
"position": {
|
||||||
"x": 698.1111111111111,
|
"x": 720,
|
||||||
"y": 478,
|
"y": 450,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@@ -68,110 +93,115 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flask_1",
|
"id": "flask_reagent1",
|
||||||
"name": "通用试剂瓶1",
|
"name": "试剂瓶1 (甲醇)",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"class": null,
|
"class": null,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 100,
|
"x": 100,
|
||||||
"y": 428,
|
"y": 400,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"max_volume": 2000.0
|
"max_volume": 1000.0
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"liquid": []
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "甲醇",
|
||||||
|
"volume": 800.0,
|
||||||
|
"concentration": "99.9%"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flask_2",
|
"id": "flask_reagent2",
|
||||||
"name": "通用试剂瓶2",
|
"name": "试剂瓶2 (乙醇)",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"class": null,
|
"class": null,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 250,
|
"x": 180,
|
||||||
"y": 428,
|
"y": 400,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"max_volume": 2000.0
|
"max_volume": 1000.0
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"liquid": []
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "乙醇",
|
||||||
|
"volume": 750.0,
|
||||||
|
"concentration": "95%"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flask_3",
|
"id": "flask_reagent3",
|
||||||
"name": "通用试剂瓶3",
|
"name": "试剂瓶3 (丙酮)",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"class": null,
|
"class": null,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 400,
|
"x": 260,
|
||||||
"y": 428,
|
"y": 400,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"max_volume": 2000.0
|
"max_volume": 1000.0
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"liquid": []
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "丙酮",
|
||||||
|
"volume": 900.0,
|
||||||
|
"concentration": "99.5%"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "flask_4",
|
"id": "flask_reagent4",
|
||||||
"name": "通用试剂瓶4",
|
"name": "试剂瓶4 (二氯甲烷)",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"class": null,
|
"class": null,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 550,
|
"x": 340,
|
||||||
"y": 428,
|
"y": 400,
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"max_volume": 2000.0
|
"max_volume": 1000.0
|
||||||
},
|
},
|
||||||
"data": {
|
"data": {
|
||||||
"liquid": []
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "二氯甲烷",
|
||||||
|
"volume": 850.0,
|
||||||
|
"concentration": "99.8%"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "reactor",
|
"id": "reactor",
|
||||||
"name": "reactor",
|
"name": "反应器",
|
||||||
"children": [],
|
"children": [],
|
||||||
"parent": "AddTestStation",
|
"parent": "AddTestStation",
|
||||||
"type": "container",
|
"type": "container",
|
||||||
"class": null,
|
"class": null,
|
||||||
"position": {
|
"position": {
|
||||||
"x": 698.1111111111111,
|
"x": 720,
|
||||||
"y": 428,
|
"y": 400,
|
||||||
"z": 0
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"max_volume": 5000.0
|
|
||||||
},
|
|
||||||
"data": {
|
|
||||||
"liquid": []
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": "flask_air",
|
|
||||||
"name": "flask_air",
|
|
||||||
"children": [],
|
|
||||||
"parent": "AddTestStation",
|
|
||||||
"type": "container",
|
|
||||||
"class": null,
|
|
||||||
"position": {
|
|
||||||
"x": 800,
|
|
||||||
"y": 300,
|
|
||||||
"z": 0
|
"z": 0
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
@@ -180,70 +210,166 @@
|
|||||||
"data": {
|
"data": {
|
||||||
"liquid": []
|
"liquid": []
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "flask_waste",
|
||||||
|
"name": "废液瓶",
|
||||||
|
"children": [],
|
||||||
|
"parent": "AddTestStation",
|
||||||
|
"type": "container",
|
||||||
|
"class": null,
|
||||||
|
"position": {
|
||||||
|
"x": 850,
|
||||||
|
"y": 400,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"max_volume": 3000.0
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"liquid": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "flask_rinsing",
|
||||||
|
"name": "冲洗液瓶",
|
||||||
|
"children": [],
|
||||||
|
"parent": "AddTestStation",
|
||||||
|
"type": "container",
|
||||||
|
"class": null,
|
||||||
|
"position": {
|
||||||
|
"x": 950,
|
||||||
|
"y": 300,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"max_volume": 1000.0
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "去离子水",
|
||||||
|
"volume": 800.0,
|
||||||
|
"concentration": "纯净"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "flask_buffer",
|
||||||
|
"name": "缓冲液瓶",
|
||||||
|
"children": [],
|
||||||
|
"parent": "AddTestStation",
|
||||||
|
"type": "container",
|
||||||
|
"class": null,
|
||||||
|
"position": {
|
||||||
|
"x": 950,
|
||||||
|
"y": 400,
|
||||||
|
"z": 0
|
||||||
|
},
|
||||||
|
"config": {
|
||||||
|
"max_volume": 1000.0
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"liquid": [
|
||||||
|
{
|
||||||
|
"name": "磷酸盐缓冲液",
|
||||||
|
"volume": 700.0,
|
||||||
|
"concentration": "0.1M, pH 7.4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"links": [
|
"links": [
|
||||||
{
|
{
|
||||||
"source": "stirrer",
|
"source": "transfer_pump",
|
||||||
|
"target": "multiway_valve",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"transfer_pump": "syringe-port",
|
||||||
|
"multiway_valve": "multiway-valve-inlet"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_reagent1",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-1",
|
||||||
|
"flask_reagent1": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_reagent2",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-2",
|
||||||
|
"flask_reagent2": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_reagent3",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-3",
|
||||||
|
"flask_reagent3": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_reagent4",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-4",
|
||||||
|
"flask_reagent4": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
"target": "reactor",
|
"target": "reactor",
|
||||||
"type": "physical",
|
"type": "physical",
|
||||||
"port": {
|
"port": {
|
||||||
"stirrer": "top",
|
"multiway_valve": "multiway-valve-port-5",
|
||||||
"reactor": "bottom"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "pump_add",
|
|
||||||
"target": "flask_1",
|
|
||||||
"type": "physical",
|
|
||||||
"port": {
|
|
||||||
"pump_add": "outlet",
|
|
||||||
"flask_1": "top"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "pump_add",
|
|
||||||
"target": "flask_2",
|
|
||||||
"type": "physical",
|
|
||||||
"port": {
|
|
||||||
"pump_add": "inlet",
|
|
||||||
"flask_2": "top"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "pump_add",
|
|
||||||
"target": "flask_3",
|
|
||||||
"type": "physical",
|
|
||||||
"port": {
|
|
||||||
"pump_add": "inlet",
|
|
||||||
"flask_3": "top"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "pump_add",
|
|
||||||
"target": "flask_4",
|
|
||||||
"type": "physical",
|
|
||||||
"port": {
|
|
||||||
"pump_add": "inlet",
|
|
||||||
"flask_4": "top"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"source": "pump_add",
|
|
||||||
"target": "reactor",
|
|
||||||
"type": "physical",
|
|
||||||
"port": {
|
|
||||||
"pump_add": "outlet",
|
|
||||||
"reactor": "top"
|
"reactor": "top"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"source": "pump_add",
|
"source": "multiway_valve",
|
||||||
"target": "flask_air",
|
"target": "flask_waste",
|
||||||
"type": "physical",
|
"type": "physical",
|
||||||
"port": {
|
"port": {
|
||||||
"pump_add": "inlet",
|
"multiway_valve": "multiway-valve-port-6",
|
||||||
"flask_air": "top"
|
"flask_waste": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_rinsing",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-7",
|
||||||
|
"flask_rinsing": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "multiway_valve",
|
||||||
|
"target": "flask_buffer",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"multiway_valve": "multiway-valve-port-8",
|
||||||
|
"flask_buffer": "top"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"source": "stirrer",
|
||||||
|
"target": "reactor",
|
||||||
|
"type": "physical",
|
||||||
|
"port": {
|
||||||
|
"stirrer": "stirrer-vessel",
|
||||||
|
"reactor": "bottom"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -15,46 +15,116 @@ def generate_add_protocol(
|
|||||||
purpose: str
|
purpose: str
|
||||||
) -> List[Dict[str, Any]]:
|
) -> List[Dict[str, Any]]:
|
||||||
"""
|
"""
|
||||||
生成添加试剂的协议序列 - 严格按照 Add.action
|
生成添加试剂的协议序列
|
||||||
|
|
||||||
|
流程:
|
||||||
|
1. 找到包含目标试剂的试剂瓶
|
||||||
|
2. 配置八通阀门到试剂瓶位置
|
||||||
|
3. 使用注射器泵吸取试剂
|
||||||
|
4. 配置八通阀门到反应器位置
|
||||||
|
5. 使用注射器泵推送试剂到反应器
|
||||||
|
6. 如果需要,启动搅拌
|
||||||
"""
|
"""
|
||||||
action_sequence = []
|
action_sequence = []
|
||||||
|
|
||||||
|
# 验证目标容器存在
|
||||||
|
if vessel not in G.nodes():
|
||||||
|
raise ValueError(f"目标容器 {vessel} 不存在")
|
||||||
|
|
||||||
# 如果指定了体积,执行液体转移
|
# 如果指定了体积,执行液体转移
|
||||||
if volume > 0:
|
if volume > 0:
|
||||||
# 查找可用的试剂瓶
|
# 1. 查找注射器泵 (transfer pump)
|
||||||
|
transfer_pump_nodes = [node for node in G.nodes()
|
||||||
|
if G.nodes[node].get('class') == 'virtual_transfer_pump']
|
||||||
|
|
||||||
|
if not transfer_pump_nodes:
|
||||||
|
raise ValueError("没有找到可用的注射器泵 (virtual_transfer_pump)")
|
||||||
|
|
||||||
|
transfer_pump_id = transfer_pump_nodes[0]
|
||||||
|
|
||||||
|
# 2. 查找八通阀门
|
||||||
|
multiway_valve_nodes = [node for node in G.nodes()
|
||||||
|
if G.nodes[node].get('class') == 'virtual_multiway_valve']
|
||||||
|
|
||||||
|
if not multiway_valve_nodes:
|
||||||
|
raise ValueError("没有找到可用的八通阀门 (virtual_multiway_valve)")
|
||||||
|
|
||||||
|
valve_id = multiway_valve_nodes[0]
|
||||||
|
|
||||||
|
# 3. 查找包含指定试剂的试剂瓶
|
||||||
|
reagent_vessel = None
|
||||||
available_flasks = [node for node in G.nodes()
|
available_flasks = [node for node in G.nodes()
|
||||||
if node.startswith('flask_')
|
if node.startswith('flask_')
|
||||||
and G.nodes[node].get('type') == 'container']
|
and G.nodes[node].get('type') == 'container']
|
||||||
|
|
||||||
if not available_flasks:
|
# 简化:使用第一个可用的试剂瓶,实际应该根据试剂名称匹配
|
||||||
|
if available_flasks:
|
||||||
|
reagent_vessel = available_flasks[0]
|
||||||
|
else:
|
||||||
raise ValueError("没有找到可用的试剂容器")
|
raise ValueError("没有找到可用的试剂容器")
|
||||||
|
|
||||||
reagent_vessel = available_flasks[0]
|
|
||||||
|
|
||||||
# 查找泵设备
|
# 4. 获取试剂瓶和反应器对应的阀门位置
|
||||||
pump_nodes = [node for node in G.nodes()
|
# 这需要根据实际连接图来确定,这里假设:
|
||||||
if G.nodes[node].get('class') == 'virtual_pump']
|
reagent_valve_position = 1 # 试剂瓶连接到阀门位置1
|
||||||
|
reactor_valve_position = 2 # 反应器连接到阀门位置2
|
||||||
|
|
||||||
if pump_nodes:
|
# 5. 执行添加操作序列
|
||||||
pump_id = pump_nodes[0]
|
|
||||||
action_sequence.append({
|
# 5.1 设置阀门到试剂瓶位置
|
||||||
"device_id": pump_id,
|
action_sequence.append({
|
||||||
"action_name": "transfer",
|
"device_id": valve_id,
|
||||||
"action_kwargs": {
|
"action_name": "set_position",
|
||||||
"from_vessel": reagent_vessel,
|
"action_kwargs": {
|
||||||
"to_vessel": vessel,
|
"position": reagent_valve_position
|
||||||
"volume": volume,
|
}
|
||||||
"amount": amount,
|
})
|
||||||
"time": time,
|
|
||||||
"viscous": viscous,
|
# 5.2 使用注射器泵从试剂瓶吸取液体
|
||||||
"rinsing_solvent": "",
|
action_sequence.append({
|
||||||
"rinsing_volume": 0.0,
|
"device_id": transfer_pump_id,
|
||||||
"rinsing_repeats": 0,
|
"action_name": "transfer",
|
||||||
"solid": False
|
"action_kwargs": {
|
||||||
}
|
"from_vessel": reagent_vessel,
|
||||||
})
|
"to_vessel": transfer_pump_id, # 吸入到注射器
|
||||||
|
"volume": volume,
|
||||||
|
"amount": amount,
|
||||||
|
"time": time / 2, # 吸取时间为总时间的一半
|
||||||
|
"viscous": viscous,
|
||||||
|
"rinsing_solvent": "",
|
||||||
|
"rinsing_volume": 0.0,
|
||||||
|
"rinsing_repeats": 0,
|
||||||
|
"solid": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# 5.3 设置阀门到反应器位置
|
||||||
|
action_sequence.append({
|
||||||
|
"device_id": valve_id,
|
||||||
|
"action_name": "set_position",
|
||||||
|
"action_kwargs": {
|
||||||
|
"position": reactor_valve_position
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
# 5.4 使用注射器泵将液体推送到反应器
|
||||||
|
action_sequence.append({
|
||||||
|
"device_id": transfer_pump_id,
|
||||||
|
"action_name": "transfer",
|
||||||
|
"action_kwargs": {
|
||||||
|
"from_vessel": transfer_pump_id, # 从注射器推出
|
||||||
|
"to_vessel": vessel,
|
||||||
|
"volume": volume,
|
||||||
|
"amount": amount,
|
||||||
|
"time": time / 2, # 推送时间为总时间的一半
|
||||||
|
"viscous": viscous,
|
||||||
|
"rinsing_solvent": "",
|
||||||
|
"rinsing_volume": 0.0,
|
||||||
|
"rinsing_repeats": 0,
|
||||||
|
"solid": False
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
# 如果需要搅拌,使用 StartStir 而不是 Stir
|
# 6. 如果需要搅拌,启动搅拌器
|
||||||
if stir:
|
if stir:
|
||||||
stirrer_nodes = [node for node in G.nodes()
|
stirrer_nodes = [node for node in G.nodes()
|
||||||
if G.nodes[node].get('class') == 'virtual_stirrer']
|
if G.nodes[node].get('class') == 'virtual_stirrer']
|
||||||
@@ -63,12 +133,156 @@ def generate_add_protocol(
|
|||||||
stirrer_id = stirrer_nodes[0]
|
stirrer_id = stirrer_nodes[0]
|
||||||
action_sequence.append({
|
action_sequence.append({
|
||||||
"device_id": stirrer_id,
|
"device_id": stirrer_id,
|
||||||
"action_name": "start_stir", # 使用 start_stir 而不是 stir
|
"action_name": "start_stir",
|
||||||
"action_kwargs": {
|
"action_kwargs": {
|
||||||
"vessel": vessel,
|
"vessel": vessel,
|
||||||
"stir_speed": stir_speed,
|
"stir_speed": stir_speed,
|
||||||
"purpose": f"添加 {reagent} 后搅拌"
|
"purpose": f"添加 {reagent} 后搅拌混合"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
else:
|
||||||
|
print("警告:需要搅拌但未找到搅拌设备")
|
||||||
|
|
||||||
|
return action_sequence
|
||||||
|
|
||||||
|
|
||||||
|
def find_valve_position_for_vessel(G: nx.DiGraph, valve_id: str, vessel_id: str) -> int:
|
||||||
|
"""
|
||||||
|
根据连接图找到容器对应的阀门位置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
G: 网络图
|
||||||
|
valve_id: 阀门设备ID
|
||||||
|
vessel_id: 容器ID
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 阀门位置编号 (1-8)
|
||||||
|
"""
|
||||||
|
# 查找阀门到容器的连接
|
||||||
|
edges = G.edges(data=True)
|
||||||
|
|
||||||
|
for source, target, data in edges:
|
||||||
|
if source == valve_id and target == vessel_id:
|
||||||
|
# 从连接数据中提取端口信息
|
||||||
|
port_info = data.get('port', {})
|
||||||
|
valve_port = port_info.get(valve_id, '')
|
||||||
|
|
||||||
|
# 解析端口名称获取位置编号
|
||||||
|
if valve_port.startswith('multiway-valve-port-'):
|
||||||
|
position = valve_port.split('-')[-1]
|
||||||
|
return int(position)
|
||||||
|
|
||||||
|
# 默认返回位置1
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
def generate_add_with_autodiscovery(
|
||||||
|
G: nx.DiGraph,
|
||||||
|
vessel: str,
|
||||||
|
reagent: str,
|
||||||
|
volume: float,
|
||||||
|
**kwargs
|
||||||
|
) -> List[Dict[str, Any]]:
|
||||||
|
"""
|
||||||
|
智能添加协议生成器 - 自动发现设备连接关系
|
||||||
|
"""
|
||||||
|
action_sequence = []
|
||||||
|
|
||||||
|
# 查找必需的设备
|
||||||
|
devices = {
|
||||||
|
'transfer_pump': None,
|
||||||
|
'multiway_valve': None,
|
||||||
|
'stirrer': None
|
||||||
|
}
|
||||||
|
|
||||||
|
for node in G.nodes():
|
||||||
|
node_class = G.nodes[node].get('class')
|
||||||
|
if node_class == 'virtual_transfer_pump':
|
||||||
|
devices['transfer_pump'] = node
|
||||||
|
elif node_class == 'virtual_multiway_valve':
|
||||||
|
devices['multiway_valve'] = node
|
||||||
|
elif node_class == 'virtual_stirrer':
|
||||||
|
devices['stirrer'] = node
|
||||||
|
|
||||||
|
# 验证必需设备
|
||||||
|
if not devices['transfer_pump']:
|
||||||
|
raise ValueError("缺少注射器泵设备")
|
||||||
|
if not devices['multiway_valve']:
|
||||||
|
raise ValueError("缺少八通阀门设备")
|
||||||
|
|
||||||
|
# 查找试剂容器
|
||||||
|
reagent_vessels = [node for node in G.nodes()
|
||||||
|
if node.startswith('flask_')
|
||||||
|
and G.nodes[node].get('type') == 'container']
|
||||||
|
|
||||||
|
if not reagent_vessels:
|
||||||
|
raise ValueError("没有找到试剂容器")
|
||||||
|
|
||||||
|
# 执行添加流程
|
||||||
|
reagent_vessel = reagent_vessels[0]
|
||||||
|
reagent_pos = find_valve_position_for_vessel(G, devices['multiway_valve'], reagent_vessel)
|
||||||
|
reactor_pos = find_valve_position_for_vessel(G, devices['multiway_valve'], vessel)
|
||||||
|
|
||||||
|
# 生成操作序列
|
||||||
|
action_sequence.extend([
|
||||||
|
# 切换到试剂瓶
|
||||||
|
{
|
||||||
|
"device_id": devices['multiway_valve'],
|
||||||
|
"action_name": "set_position",
|
||||||
|
"action_kwargs": {"position": reagent_pos}
|
||||||
|
},
|
||||||
|
# 吸取试剂
|
||||||
|
{
|
||||||
|
"device_id": devices['transfer_pump'],
|
||||||
|
"action_name": "transfer",
|
||||||
|
"action_kwargs": {
|
||||||
|
"from_vessel": reagent_vessel,
|
||||||
|
"to_vessel": devices['transfer_pump'],
|
||||||
|
"volume": volume,
|
||||||
|
"amount": kwargs.get('amount', ''),
|
||||||
|
"time": kwargs.get('time', 10.0) / 2,
|
||||||
|
"viscous": kwargs.get('viscous', False),
|
||||||
|
"rinsing_solvent": "",
|
||||||
|
"rinsing_volume": 0.0,
|
||||||
|
"rinsing_repeats": 0,
|
||||||
|
"solid": False
|
||||||
|
}
|
||||||
|
},
|
||||||
|
# 切换到反应器
|
||||||
|
{
|
||||||
|
"device_id": devices['multiway_valve'],
|
||||||
|
"action_name": "set_position",
|
||||||
|
"action_kwargs": {"position": reactor_pos}
|
||||||
|
},
|
||||||
|
# 推送到反应器
|
||||||
|
{
|
||||||
|
"device_id": devices['transfer_pump'],
|
||||||
|
"action_name": "transfer",
|
||||||
|
"action_kwargs": {
|
||||||
|
"from_vessel": devices['transfer_pump'],
|
||||||
|
"to_vessel": vessel,
|
||||||
|
"volume": volume,
|
||||||
|
"amount": kwargs.get('amount', ''),
|
||||||
|
"time": kwargs.get('time', 10.0) / 2,
|
||||||
|
"viscous": kwargs.get('viscous', False),
|
||||||
|
"rinsing_solvent": "",
|
||||||
|
"rinsing_volume": 0.0,
|
||||||
|
"rinsing_repeats": 0,
|
||||||
|
"solid": False
|
||||||
|
}
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
# 如果需要搅拌
|
||||||
|
if kwargs.get('stir', False) and devices['stirrer']:
|
||||||
|
action_sequence.append({
|
||||||
|
"device_id": devices['stirrer'],
|
||||||
|
"action_name": "start_stir",
|
||||||
|
"action_kwargs": {
|
||||||
|
"vessel": vessel,
|
||||||
|
"stir_speed": kwargs.get('stir_speed', 300.0),
|
||||||
|
"purpose": f"添加 {reagent} 后混合"
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
return action_sequence
|
return action_sequence
|
||||||
Reference in New Issue
Block a user