Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented fluidics interface for syringe pump. #98

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
59 changes: 59 additions & 0 deletions storm_control/fluidics/default_config_syringe.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<kilroy_configuration num_valves = "3" num_pumps = "1">
<valve_commands>
<valve_cmd name = "Stop Valve">
<valve_pos valve_ID = "1" port_ID = "1"></valve_pos>
</valve_cmd>
<valve_cmd name = "Flow Hybridization">
<valve_pos valve_ID = "1" port_ID = "2"></valve_pos>
</valve_cmd>
<valve_cmd name = "Flow Wash">
<valve_pos valve_ID = "1" port_ID = "3"></valve_pos>
</valve_cmd>
<valve_cmd name = "Flow STORM Buffer">
<valve_pos valve_ID = "1" port_ID = "4"></valve_pos>
</valve_cmd>
<valve_cmd name = "Set Hyb 1">
<valve_pos valve_ID = "2" port_ID = "1"></valve_pos>
</valve_cmd>
<valve_cmd name = "Set Hyb 2">
<valve_pos valve_ID = "2" port_ID = "2"></valve_pos>
</valve_cmd>
<valve_cmd name = "Set Hyb 3">
<valve_pos valve_ID = "2" port_ID = "3"></valve_pos>
</valve_cmd>
<valve_cmd name = "Set Hyb 4">
<valve_pos valve_ID = "2" port_ID = "4"></valve_pos>
</valve_cmd>
</valve_commands>

<pump_commands>
<pump_cmd name = "Flow 2mL">
<pump_config position = "2000" speed = "500"></pump_config>
</pump_cmd>
</pump_commands>

<kilroy_protocols>
<protocol name = "Extra Wash">
<valve duration = "0">Flow Wash</valve>
<pump duration = "200">Normal Flow</pump>
<pump duration = "0">Stop Flow</pump>
</protocol>
<protocol name = "Hybridize 1">
<pump duration = "0">Normal Flow</pump>
<valve duration = "20">Set Hyb 1</valve>
<valve duration = "10">Flow Hybridization</valve>
<valve duration = "10">Flow Wash</valve>
<valve duration = "10">Flow STORM Buffer</valve>
<pump duration = "0">Stop Flow</pump>
</protocol>
<protocol name = "Hybridize 2">
<pump duration = "0">Normal Flow</pump>
<valve duration = "20">Set Hyb 2</valve>
<valve duration = "10">Flow Hybridization</valve>
<valve duration = "10">Flow Wash</valve>
<valve duration = "10">Flow STORM Buffer</valve>
<pump duration = "0">Stop Flow</pump>
</protocol>
</kilroy_protocols>
</kilroy_configuration>
20 changes: 15 additions & 5 deletions storm_control/fluidics/kilroy.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@
import time
from PyQt5 import QtCore, QtGui, QtWidgets
from storm_control.fluidics.valves.valveChain import ValveChain
from storm_control.fluidics.pumps.pumpControl import PumpControl
from storm_control.fluidics.pumps.pumpControl import PeristalticPumpControl
from storm_control.fluidics.pumps.pumpControl import SyringePumpControl
from storm_control.fluidics.kilroyProtocols import KilroyProtocols
from storm_control.sc_library.tcpServer import TCPServer
import storm_control.sc_library.parameters as params
Expand All @@ -34,7 +35,12 @@ def __init__(self, parameters):
self.tcp_port = parameters.get("tcp_port")
self.pump_com_port = parameters.get("pump_com_port")
self.pump_ID = parameters.get("pump_ID")


if not parameters.has("pump_type"):
self.pump_type = 'peristaltic'
else:
self.pump_type = parameters.get('pump_type')

if not parameters.has("num_simulated_valves"):
self.num_simulated_valves = 0
else:
Expand Down Expand Up @@ -70,12 +76,16 @@ def __init__(self, parameters):
verbose = self.verbose)

# Create PumpControl instance
self.pumpControl = PumpControl(parameters = parameters)

if self.pump_type == 'peristaltic':
self.pumpControl = PeristalticPumpControl(parameters=parameters)
elif self.pump_type == 'syringe':
self.pumpControl = SyringePumpControl(parameters=parameters)

# Create KilroyProtocols instance and connect signals
self.kilroyProtocols = KilroyProtocols(protocol_xml_path = self.protocols_file,
command_xml_path = self.commands_file,
verbose = self.verbose)
verbose = self.verbose,
pumpType = self.pump_type)

self.kilroyProtocols.command_ready_signal.connect(self.sendCommand)
self.kilroyProtocols.status_change_signal.connect(self.handleProtocolStatusChange)
Expand Down
9 changes: 7 additions & 2 deletions storm_control/fluidics/kilroyProtocols.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
# Jeff Moffitt
# 2/15/14
# [email protected]
#
# Updated 7/2019 by George Emanuel
# ----------------------------------------------------------------------------------------

# ----------------------------------------------------------------------------------------
Expand All @@ -33,7 +35,8 @@ class KilroyProtocols(QtWidgets.QMainWindow):
def __init__(self,
protocol_xml_path = "default_config.xml",
command_xml_path = "default_config.xml",
verbose = False):
verbose = False,
pumpType='peristaltic'):
super(KilroyProtocols, self).__init__()

# Initialize internal attributes
Expand All @@ -47,6 +50,7 @@ def __init__(self,
self.status = [-1, -1] # Protocol ID, command ID within protocol
self.issued_command = []
self.received_message = None
self.pumpType = pumpType

print("----------------------------------------------------------------------")

Expand All @@ -59,7 +63,8 @@ def __init__(self,

# Create instance of PumpCommands class
self.pumpCommands = PumpCommands(xml_file_path = self.command_xml_path,
verbose = self.verbose)
verbose = self.verbose,
pumpType = pumpType)

# Connect pump commands issue signal
self.pumpCommands.change_command_signal.connect(self.issuePumpCommand)
Expand Down
3 changes: 3 additions & 0 deletions storm_control/fluidics/pumps/gilson_mp3.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ def __init__(self,
self.startFlow(self.speed, self.direction)
self.identification = self.getIdentification()

def pumpType(self):
return 'peristaltic'

def getIdentification(self):
return self.sendImmediate(self.pump_ID, "%")

Expand Down
147 changes: 147 additions & 0 deletions storm_control/fluidics/pumps/hamilton_psd6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/python
# ----------------------------------------------------------------------------------------
# The basic I/O class for a Hamilton syringe pump
# ----------------------------------------------------------------------------------------
# George Emanuel
# 6/28/19
# ----------------------------------------------------------------------------------------

import serial

acknowledge = '\x06'
start = '\x0A'
stop = '\x0D'


# ----------------------------------------------------------------------------------------
# HamiltonPSD6 Syringe Pump Class Definition
# ----------------------------------------------------------------------------------------
class APump():
def __init__(self, parameters=False):

print('Initializing pump')

# Define attributes
self.com_port = parameters.get("pump_com_port", "COM3")
self.pump_ID = parameters.get("pump_ID", 30)
self.verbose = parameters.get("verbose", True)
self.simulate = parameters.get("simulate_pump", True)
self.serial_verbose = parameters.get("serial_verbose", False)
self.flip_flow_direction = parameters.get("flip_flow_direction", False)

# Create serial port
self.serial = serial.Serial(
port=self.com_port, baudrate=9600, timeout=0.1)

# enable h commands
self.sendString('/1h30001R\r')

# TODO Confirm that this initialization only pushes to waste
self.sendString('/1OZ1R\r')

# Define initial pump status
self.flow_status = "Stopped"
self.speed = 1000
self.direction = "Forward"

self.disconnect()
self.setSpeed(self.speed)
self.identification = 'HamiltonSyringe'

def pumpType(self):
return 'syringe'

def getIdentification(self):
return self.sendImmediate(self.pump_ID, "%")

def getPumpPosition(self):
return int(self.sendString('/1?R\r').decode()
.split('`')[1].split('\x03')[0])

def getValvePosition(self):
positionDict = {
0: 'Moving',
1: 'Input',
2: 'Output',
3: 'Wash',
4: 'Return',
5: 'Bypass',
6: 'Extra'
}
return positionDict[int(self.sendString('/1?23000\r').decode()
.split('`')[1].split('\x03')[0])]

def getStatus(self):
return (self.getPumpPosition(), self.getValvePosition())

message = self.readDisplay()

if self.flip_flow_direction:
direction = {" ": "Not Running", "-": "Forward", "+": "Reverse"}. \
get(message[0], "Unknown")
else:
direction = {" ": "Not Running", "+": "Forward", "-": "Reverse"}. \
get(message[0], "Unknown")

status = "Stopped" if direction == "Not Running" else "Flowing"

control = {"K": "Keypad", "R": "Remote"}.get(message[-1], "Unknown")

auto_start = "Disabled"

speed = float(message[1:len(message) - 1])

return (status, self.getPumpPosition(), direction, control, auto_start, "No Error")

def close(self):
pass

def setValvePosition(self, valvePosition):
# valve position is either 'input' or 'output'
if valvePosition == 'Input':
self.sendString('/1IR\r')
elif valvePosition == 'Output':
self.sendString('/1OR\r')

def setSyringePosition(self, position, valvePosition=None, speed=500,
emptyFirst=False):
commandString = '/1'

if emptyFirst:
commandString += 'OV5000A0'

if valvePosition is not None:
if valvePosition == 'Input':
commandString += 'I'
else:
commandString += 'O'

commandString += 'V' + str(int(speed))
commandString += 'A' + str(int(position))

self.sendString(commandString + 'R\r')

def emptySyringe(self):
self.sendString('/1OV5000A0R\r')

def stopSyringe(self):
self.sendString('/1TR\r')

def resetSyringe(self):
self.sendString('/1OZ1R\r')

def setSpeed(self, speed):
if 2 <= speed <= 5800:
self.sendString('/1V%iR\r' % speed)

def stopFlow(self):
self.setSpeed(0.0)
return True

def disconnect(self):
pass
#self.sendAndAcknowledge('\xff')

def sendString(self, string):
self.serial.write(string.encode())
return self.serial.readline()
Loading