bump version to 0.9.7 新增一个测试PumpTransferProtocol的teststation,亲测可以运行,将八通阀们和转移泵与pump_protocol适配

This commit is contained in:
KCFeng425
2025-06-17 16:56:49 +08:00
parent 18c4eb3e4d
commit f6f9244ff1
11 changed files with 464 additions and 76 deletions

View File

@@ -11,23 +11,39 @@ class VirtualPumpMode(Enum):
AccuratePosVel = 2
class VirtualPump:
"""虚拟泵类 - 模拟泵的基本功能,无需实际硬件"""
class VirtualTransferPump:
"""虚拟转移泵类 - 模拟泵的基本功能,无需实际硬件"""
def __init__(self, device_id: str = None, max_volume: float = 25.0, mode: VirtualPumpMode = VirtualPumpMode.Normal, transfer_rate=0):
self.device_id = device_id or "virtual_pump"
self.max_volume = max_volume
self._transfer_rate = transfer_rate
self.mode = mode
def __init__(self, device_id: str = None, config: dict = None, **kwargs):
"""
初始化虚拟转移泵
# 状态变量
Args:
device_id: 设备ID
config: 配置字典包含max_volume, port等参数
**kwargs: 其他参数,确保兼容性
"""
self.device_id = device_id or "virtual_transfer_pump"
# 从config或kwargs中获取参数确保类型正确
if config:
self.max_volume = float(config.get('max_volume', 25.0))
self.port = config.get('port', 'VIRTUAL')
else:
self.max_volume = float(kwargs.get('max_volume', 25.0))
self.port = kwargs.get('port', 'VIRTUAL')
self._transfer_rate = float(kwargs.get('transfer_rate', 0))
self.mode = kwargs.get('mode', VirtualPumpMode.Normal)
# 状态变量 - 确保都是正确类型
self._status = "Idle"
self._position = 0.0 # 当前柱塞位置 (ml)
self._max_velocity = 5.0 # 默认最大速度 (ml/s)
self._current_volume = 0.0 # 当前注射器中的体积
self._position = 0.0 # float
self._max_velocity = 5.0 # float
self._current_volume = 0.0 # float
self.logger = logging.getLogger(f"VirtualPump.{self.device_id}")
self.logger = logging.getLogger(f"VirtualTransferPump.{self.device_id}")
async def initialize(self) -> bool:
"""初始化虚拟泵"""
self.logger.info(f"Initializing virtual pump {self.device_id}")
@@ -86,30 +102,73 @@ class VirtualPump:
velocity = self._max_velocity
return abs(volume) / velocity
# 基本泵操
async def set_position(self, position: float, velocity: float = None):
# 新的set_position方法 - 专门用于SetPumpPosition动
async def set_position(self, position: float, max_velocity: float = None):
"""
移动到绝对位置
移动到绝对位置 - 专门用于SetPumpPosition动作
Args:
position (float): 目标位置 (ml)
velocity (float): 移动速度 (ml/s)
max_velocity (float): 移动速度 (ml/s)
Returns:
dict: 符合SetPumpPosition.action定义的结果
"""
position = max(0, min(self.max_volume, position)) # 限制在有效范围内
try:
# 验证并转换参数
target_position = float(position)
velocity = float(max_velocity) if max_velocity is not None else self._max_velocity
# 限制位置在有效范围内
target_position = max(0.0, min(float(self.max_volume), target_position))
# 计算移动距离和时间
volume_to_move = abs(target_position - self._position)
duration = self._calculate_duration(volume_to_move, velocity)
self.logger.info(f"SET_POSITION: Moving to {target_position} ml (current: {self._position} ml), velocity: {velocity} ml/s")
# 模拟移动过程
start_position = self._position
steps = 10 if duration > 0.1 else 1 # 如果移动距离很小只用1步
step_duration = duration / steps if steps > 1 else duration
for i in range(steps + 1):
# 计算当前位置和进度
progress = (i / steps) * 100 if steps > 0 else 100
current_pos = start_position + (target_position - start_position) * (i / steps) if steps > 0 else target_position
# 更新状态
self._status = "Moving" if i < steps else "Idle"
self._position = current_pos
self._current_volume = current_pos
# 等待一小步时间
if i < steps and step_duration > 0:
await asyncio.sleep(step_duration)
volume_to_move = abs(position - self._position)
duration = self._calculate_duration(volume_to_move, velocity)
self.logger.info(f"Moving to position {position} ml (current: {self._position} ml)")
# 模拟移动过程
await self._simulate_operation(duration)
self._position = position
self._current_volume = position # 假设位置等于体积
self.logger.info(f"Reached position {self._position} ml")
# 确保最终位置准确
self._position = target_position
self._current_volume = target_position
self._status = "Idle"
self.logger.info(f"SET_POSITION: Reached position {self._position} ml, current volume: {self._current_volume} ml")
# 返回符合action定义的结果
return {
"success": True,
"message": f"Successfully moved to position {self._position} ml"
}
except Exception as e:
error_msg = f"Failed to set position: {str(e)}"
self.logger.error(error_msg)
return {
"success": False,
"message": error_msg
}
# 其他泵操作方法
async def pull_plunger(self, volume: float, velocity: float = None):
"""
拉取柱塞(吸液)
@@ -135,7 +194,7 @@ class VirtualPump:
self._current_volume = new_position
self.logger.info(f"Pulled {actual_volume} ml, current volume: {self._current_volume} ml")
async def push_plunger(self, volume: float, velocity: float = None):
"""
推出柱塞(排液)
@@ -161,37 +220,18 @@ class VirtualPump:
self._current_volume = new_position
self.logger.info(f"Pushed {actual_volume} ml, current volume: {self._current_volume} ml")
# 便捷操作方法
async def aspirate(self, volume: float, velocity: float = None):
"""
吸液操作
Args:
volume (float): 吸液体积 (ml)
velocity (float): 吸液速度 (ml/s)
"""
"""吸液操作"""
await self.pull_plunger(volume, velocity)
async def dispense(self, volume: float, velocity: float = None):
"""
排液操作
Args:
volume (float): 排液体积 (ml)
velocity (float): 排液速度 (ml/s)
"""
"""排液操作"""
await self.push_plunger(volume, velocity)
async def transfer(self, volume: float, aspirate_velocity: float = None, dispense_velocity: float = None):
"""
转移操作(先吸后排)
Args:
volume (float): 转移体积 (ml)
aspirate_velocity (float): 吸液速度 (ml/s)
dispense_velocity (float): 排液速度 (ml/s)
"""
"""转移操作(先吸后排)"""
# 吸液
await self.aspirate(volume, aspirate_velocity)
@@ -252,7 +292,7 @@ class VirtualPump:
}
def __str__(self):
return f"VirtualPump({self.device_id}: {self._current_volume:.2f}/{self.max_volume} ml, {self._status})"
return f"VirtualTransferPump({self.device_id}: {self._current_volume:.2f}/{self.max_volume} ml, {self._status})"
def __repr__(self):
return self.__str__()
@@ -261,30 +301,28 @@ class VirtualPump:
# 使用示例
async def demo():
"""虚拟泵使用示例"""
pump = VirtualPump("demo_pump", max_volume=50.0)
pump = VirtualTransferPump("demo_pump", {"max_volume": 50.0})
await pump.initialize()
print(f"Initial state: {pump}")
# 测试set_position方法
result = await pump.set_position(10.0, max_velocity=2.0)
print(f"Set position result: {result}")
print(f"After setting position to 10ml: {pump}")
# 吸液测试
await pump.aspirate(10.0, velocity=2.0)
print(f"After aspirating 10ml: {pump}")
# 排液测试
await pump.dispense(5.0, velocity=3.0)
print(f"After dispensing 5ml: {pump}")
# 转移测试
await pump.transfer(3.0)
print(f"After transfer 3ml: {pump}")
await pump.aspirate(5.0, velocity=2.0)
print(f"After aspirating 5ml: {pump}")
# 清空测试
await pump.empty_syringe()
result = await pump.set_position(0.0)
print(f"Empty result: {result}")
print(f"After emptying: {pump}")
print("\nPump info:", pump.get_pump_info())
if __name__ == "__main__":
asyncio.run(demo())
asyncio.run(demo())