Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ conda env update --file unilabos-[YOUR_OS].yml -n environment_name

# Currently, you need to install the `unilabos_msgs` package
# You can download the system-specific package from the Release page
conda install ros-humble-unilabos-msgs-0.9.10-xxxxx.tar.bz2
conda install ros-humble-unilabos-msgs-0.9.12-xxxxx.tar.bz2

# Install PyLabRobot and other prerequisites
git clone https://github.com/PyLabRobot/pylabrobot plr_repo
Expand Down
2 changes: 1 addition & 1 deletion README_zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ conda env update --file unilabos-[YOUR_OS].yml -n 环境名

# 现阶段,需要安装 `unilabos_msgs` 包
# 可以前往 Release 页面下载系统对应的包进行安装
conda install ros-humble-unilabos-msgs-0.9.11-xxxxx.tar.bz2
conda install ros-humble-unilabos-msgs-0.9.12-xxxxx.tar.bz2

# 安装PyLabRobot等前置
git clone https://github.com/PyLabRobot/pylabrobot plr_repo
Expand Down
2 changes: 1 addition & 1 deletion recipes/ros-humble-unilabos-msgs/recipe.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package:
name: ros-humble-unilabos-msgs
version: 0.9.11
version: 0.9.12
source:
path: ../../unilabos_msgs
folder: ros-humble-unilabos-msgs/src/work
Expand Down
2 changes: 1 addition & 1 deletion recipes/unilabos/recipe.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package:
name: unilabos
version: "0.9.11"
version: "0.9.12"

source:
path: ../..
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

setup(
name=package_name,
version='0.9.11',
version='0.9.12',
packages=find_packages(),
include_package_data=True,
install_requires=['setuptools'],
Expand Down
65 changes: 40 additions & 25 deletions unilabos/compile/add_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ def create_action_log(message: str, emoji: str = "📝") -> Dict[str, Any]:

def generate_add_protocol(
G: nx.DiGraph,
vessel: str,
vessel: dict, # 🔧 修改:现在接收字典类型的 vessel
reagent: str,
# 🔧 修复:所有参数都用 Union 类型,支持字符串和数值
volume: Union[str, float] = 0.0,
Expand All @@ -334,6 +334,7 @@ def generate_add_protocol(
生成添加试剂协议 - 修复版

支持所有XDL参数和单位:
- vessel: Resource类型字典,包含id字段
- volume: "2.7 mL", "2.67 mL", "?" 或数值
- mass: "19.3 g", "4.5 g" 或数值
- time: "1 h", "20 min" 或数值(秒)
Expand All @@ -343,11 +344,19 @@ def generate_add_protocol(
- equiv: "1.1"
- ratio: "?", "1:1"
"""

# 🔧 核心修改:从字典中提取容器ID
vessel_id = vessel["id"]

# 🔧 修改:更新容器的液体体积(假设有 liquid_volume 字段)
if "data" in vessel and "liquid_volume" in vessel["data"]:
if isinstance(vessel["data"]["liquid_volume"], list) and len(vessel["data"]["liquid_volume"]) > 0:
vessel["data"]["liquid_volume"][0] -= parse_volume_input(volume)

debug_print("=" * 60)
debug_print("🚀 开始生成添加试剂协议")
debug_print(f"📋 原始参数:")
debug_print(f" 🥼 vessel: '{vessel}'")
debug_print(f" 🥼 vessel: {vessel} (ID: {vessel_id})")
debug_print(f" 🧪 reagent: '{reagent}'")
debug_print(f" 📏 volume: {volume} (类型: {type(volume)})")
debug_print(f" ⚖️ mass: {mass} (类型: {type(mass)})")
Expand All @@ -363,18 +372,18 @@ def generate_add_protocol(

# === 参数验证 ===
debug_print("🔍 步骤1: 参数验证...")
action_sequence.append(create_action_log(f"开始添加试剂 '{reagent}' 到容器 '{vessel}'", "🎬"))
action_sequence.append(create_action_log(f"开始添加试剂 '{reagent}' 到容器 '{vessel_id}'", "🎬"))

if not vessel:
if not vessel or not vessel_id:
debug_print("❌ vessel 参数不能为空")
raise ValueError("vessel 参数不能为空")
if not reagent:
debug_print("❌ reagent 参数不能为空")
raise ValueError("reagent 参数不能为空")

if vessel not in G.nodes():
debug_print(f"❌ 容器 '{vessel}' 不存在于系统中")
raise ValueError(f"容器 '{vessel}' 不存在于系统中")
if vessel_id not in G.nodes():
debug_print(f"❌ 容器 '{vessel_id}' 不存在于系统中")
raise ValueError(f"容器 '{vessel_id}' 不存在于系统中")

debug_print("✅ 基本参数验证通过")

Expand Down Expand Up @@ -432,15 +441,15 @@ def generate_add_protocol(
debug_print("🌪️ 准备启动搅拌...")
action_sequence.append(create_action_log("准备启动搅拌器", "🌪️"))

stirrer_id = find_connected_stirrer(G, vessel)
stirrer_id = find_connected_stirrer(G, vessel_id) # 🔧 使用 vessel_id
if stirrer_id:
action_sequence.append(create_action_log(f"启动搅拌器 {stirrer_id} (速度: {stir_speed} rpm)", "🔄"))

action_sequence.append({
"device_id": stirrer_id,
"action_name": "start_stir",
"action_kwargs": {
"vessel": vessel,
"vessel": vessel_id, # 🔧 使用 vessel_id
"stir_speed": stir_speed,
"purpose": f"准备添加固体 {reagent}"
}
Expand All @@ -454,7 +463,7 @@ def generate_add_protocol(

# 固体加样
add_kwargs = {
"vessel": vessel,
"vessel": vessel_id, # 🔧 使用 vessel_id
"reagent": reagent,
"purpose": purpose,
"event": event,
Expand Down Expand Up @@ -509,15 +518,15 @@ def generate_add_protocol(
debug_print("🌪️ 准备启动搅拌...")
action_sequence.append(create_action_log("准备启动搅拌器", "🌪️"))

stirrer_id = find_connected_stirrer(G, vessel)
stirrer_id = find_connected_stirrer(G, vessel_id) # 🔧 使用 vessel_id
if stirrer_id:
action_sequence.append(create_action_log(f"启动搅拌器 {stirrer_id} (速度: {stir_speed} rpm)", "🔄"))

action_sequence.append({
"device_id": stirrer_id,
"action_name": "start_stir",
"action_kwargs": {
"vessel": vessel,
"vessel": vessel_id, # 🔧 使用 vessel_id
"stir_speed": stir_speed,
"purpose": f"准备添加液体 {reagent}"
}
Expand Down Expand Up @@ -555,7 +564,7 @@ def generate_add_protocol(
pump_actions = generate_pump_protocol_with_rinsing(
G=G,
from_vessel=reagent_vessel,
to_vessel=vessel,
to_vessel=vessel_id, # 🔧 使用 vessel_id
volume=final_volume,
amount=amount,
time=final_time,
Expand Down Expand Up @@ -594,7 +603,7 @@ def generate_add_protocol(
debug_print(f"📋 处理总结:")
debug_print(f" 🧪 试剂: {reagent}")
debug_print(f" {add_emoji} 添加类型: {add_type}")
debug_print(f" 🥼 目标容器: {vessel}")
debug_print(f" 🥼 目标容器: {vessel_id}")
if is_liquid:
debug_print(f" 📏 体积: {final_volume}mL")
if is_solid:
Expand All @@ -603,7 +612,7 @@ def generate_add_protocol(
debug_print("=" * 60)

# 添加完成日志
summary_msg = f"试剂添加协议完成: {reagent} → {vessel}"
summary_msg = f"试剂添加协议完成: {reagent} → {vessel_id}"
if is_liquid:
summary_msg += f" ({final_volume}mL)"
if is_solid:
Expand All @@ -614,42 +623,47 @@ def generate_add_protocol(
return action_sequence

# === 便捷函数 ===
# 🔧 修改便捷函数的参数类型

def add_liquid_volume(G: nx.DiGraph, vessel: str, reagent: str, volume: Union[str, float],
def add_liquid_volume(G: nx.DiGraph, vessel: dict, reagent: str, volume: Union[str, float],
time: Union[str, float] = 0.0, rate_spec: str = "") -> List[Dict[str, Any]]:
"""添加指定体积的液体试剂"""
debug_print(f"💧 快速添加液体: {reagent} ({volume}) → {vessel}")
vessel_id = vessel["id"]
debug_print(f"💧 快速添加液体: {reagent} ({volume}) → {vessel_id}")
return generate_add_protocol(
G, vessel, reagent,
volume=volume,
time=time,
rate_spec=rate_spec
)

def add_solid_mass(G: nx.DiGraph, vessel: str, reagent: str, mass: Union[str, float],
def add_solid_mass(G: nx.DiGraph, vessel: dict, reagent: str, mass: Union[str, float],
event: str = "") -> List[Dict[str, Any]]:
"""添加指定质量的固体试剂"""
debug_print(f"🧂 快速添加固体: {reagent} ({mass}) → {vessel}")
vessel_id = vessel["id"]
debug_print(f"🧂 快速添加固体: {reagent} ({mass}) → {vessel_id}")
return generate_add_protocol(
G, vessel, reagent,
mass=mass,
event=event
)

def add_solid_moles(G: nx.DiGraph, vessel: str, reagent: str, mol: str,
def add_solid_moles(G: nx.DiGraph, vessel: dict, reagent: str, mol: str,
event: str = "") -> List[Dict[str, Any]]:
"""按摩尔数添加固体试剂"""
debug_print(f"🧬 按摩尔数添加固体: {reagent} ({mol}) → {vessel}")
vessel_id = vessel["id"]
debug_print(f"🧬 按摩尔数添加固体: {reagent} ({mol}) → {vessel_id}")
return generate_add_protocol(
G, vessel, reagent,
mol=mol,
event=event
)

def add_dropwise_liquid(G: nx.DiGraph, vessel: str, reagent: str, volume: Union[str, float],
def add_dropwise_liquid(G: nx.DiGraph, vessel: dict, reagent: str, volume: Union[str, float],
time: Union[str, float] = "20 min", event: str = "") -> List[Dict[str, Any]]:
"""滴加液体试剂"""
debug_print(f"💧 滴加液体: {reagent} ({volume}) → {vessel} (用时: {time})")
vessel_id = vessel["id"]
debug_print(f"💧 滴加液体: {reagent} ({volume}) → {vessel_id} (用时: {time})")
return generate_add_protocol(
G, vessel, reagent,
volume=volume,
Expand All @@ -658,10 +672,11 @@ def add_dropwise_liquid(G: nx.DiGraph, vessel: str, reagent: str, volume: Union[
event=event
)

def add_portionwise_solid(G: nx.DiGraph, vessel: str, reagent: str, mass: Union[str, float],
def add_portionwise_solid(G: nx.DiGraph, vessel: dict, reagent: str, mass: Union[str, float],
time: Union[str, float] = "1 h", event: str = "") -> List[Dict[str, Any]]:
"""分批添加固体试剂"""
debug_print(f"🧂 分批添加固体: {reagent} ({mass}) → {vessel} (用时: {time})")
vessel_id = vessel["id"]
debug_print(f"🧂 分批添加固体: {reagent} ({mass}) → {vessel_id} (用时: {time})")
return generate_add_protocol(
G, vessel, reagent,
mass=mass,
Expand Down
Loading
Loading