def __init__ (self, title, set_target): self.title = title self.target = Property(title = self.title + " Target Temperature", type = int, unit = "C", min = -1000, max = 250, setter = set_target) self.mode = Property(title = self.title + " Mode", type = str) self.power = Stream(title = self.title + " Power", type = int, unit = "W") self.temp = Stream(title = self.title + " Temperature", type = float, unit = "C")
def setup(self, syringe_diameter): @defer.inlineCallbacks def set_rate(rate): # Get the current rate try: state, result = yield self.protocol.command("RAT") except CommandError as e: raise # Cannot set rate if the pump is running - stop the pump. if state in ("I", "W", "A"): try: yield self.protocol.command("STP") except CommandError as e: if e.type is not CommandError.NOT_APPLICABLE: pass # Set the rate yield self.protocol.command("RAT{:.3f}".format( rate / _rate_unit_factors[self._rate_unit])[:8] + self._rate_unit) # Only start if the rate > 0 if rate > 0: state, result = yield self.protocol.command("RUN") if state in ("I", "W"): defer.returnValue("OK") else: raise Error("Could not start pump") else: defer.returnValue("OK") def set_direction(direction): direction = "WDR" if direction == "withdraw" else "INF" return self.protocol.command("DIR" + direction) # setup variables self.status = Property(title="Status", type=str) self.rate = Property(title="Flow rate", type=float, unit="uL/min", setter=set_rate) self.direction = Property(title="Direction", type=str, options=("infuse", "withdraw"), setter=set_direction) self.dispensed = Stream(title="Volume dispensed", type=float, unit="mL") self.withdrawn = Stream(title="Volume withdrawn", type=float, unit="mL") self._syringe_diameter = syringe_diameter self._vol_unit = "UL" self._rate_unit = "MM" self.ui = ui(properties=[self.rate])
def setup (self): # setup variables self.power = Property(title = "Power", type = str, options = ("on", "off"), setter = _set_power(self)) self.setpoint = Property(title = "Stirrer setpoint", type = float, unit = "rpm", setter = _set_setpoint(self)) self.rpm = Stream(title = "Stirrer Speed", type = float, unit = "rpm") self.torque = Stream(title = "Torque", type = float, unit = "Ncm")
def __init__ (self, title, set_target, set_input): self.title = title self.target = Property(title = self.title + " Target Flow Rate", type = int, unit = "uL/min", min = 0, max = 99999, setter = set_target) self.input = Property(title = self.title + " Input", type = str, options = ("solvent", "reagent"), setter = set_input) self.rate = Stream(title = self.title + " Flow Rate", type = int, unit = "uL/min") self.pressure = Stream(title = self.title + " Pressure", type = int, unit = "mbar") self.airlock = Stream(title = self.title + " Airlock", type = int)
def setup (self): # setup variables self.heater_power = Property(title = "Heater On", type = str, options = ("on", "off"), setter = _set_heater_power(self)) self.stirrer_power = Property(title = "Stirrer On", type = str, options = ("on", "off"), setter = _set_stirrer_power(self)) self.stirrer_setpoint = Property(title = "Stirrer setpoint", type = float, unit = "rpm", setter = _set_stirrer_setpoint(self)) self.heater_setpoint = Property(title = "Heater setpoint", type = float, unit = "rpm", setter = _set_heater_setpoint(self)) self.external_temperature = Stream(title = "External Temperature", type = float, unit = "C") self.hotplate_temperature = Stream(title = "Hotplate Temperature", type = float, unit = "C") self.stirrer_speed = Stream(title = "Stirrer Speed", type = float, unit = "rpm") self.viscosity = Stream(title = "Viscosity", type = float, unit = "%")
def setup(self): # setup variables self.power = Property(title="Power", type=str, options=("on", "off"), setter=_set_power_s(self)) self.target = Property(title="Target flowrate", type=float, unit="mL/min", setter=_set_setpoint_s(self)) self.flowrate = Stream(title="Flow rate", type=float, unit="mL/min") self.pressure = Stream(title="Pressure", type=float, unit="bar")
class CGQ(Machine): """ Control class for a Aquila CGQ, via the CGQuant software. The software connects via a Named Pipe at \\.\pipe\CGQuantDataPipe """ protocolFactory = Factory.forProtocol(CGQuantLineReceiver) name = "CGQuant" def setup(self): # setup variables self.backscatter = Stream(title="Backscatter", type=float, unit="au") self.temperature = Stream(title="Temperature", type=float, unit="C") self.shakingspeed = Stream(title="Shaking speed", type=float, unit="rpm") self.growthrate = Stream(title="Growth rate", type=float, unit="1/h") def start(self): def receive_packet(packet: CGQuantDataPacket): self.backscatter._push(packet.backscatter) self.temperature._push(packet.temperature) self.shakingspeed._push(packet.shakingspeed) self.growthrate._push(packet.growthrate) self.protocol.setListener(receive_packet) def stop(self): self.protocol.setListener(None)
def setup(self): # setup variables self.power = Property(title="Power", type=str, options=("on", "off"), setter=_set_power(self)) self.setpoint = Property(title="Setpoint", type=int, unit="C", setter=_set_setpoint(self)) self.bath_temp = Stream(title="Bath Temperature", type=float, unit="C") self.external_temp = Stream(title="External Temperature", type=float, unit="C")
def setup(self): # setup variables self.backscatter = Stream(title="Backscatter", type=float, unit="au") self.temperature = Stream(title="Temperature", type=float, unit="C") self.shakingspeed = Stream(title="Shaking speed", type=float, unit="rpm") self.growthrate = Stream(title="Growth rate", type=float, unit="1/h")
def setup (self, **kwargs): # setup variables self.status = Property(title = "Status", type = str) self.power = Property(title = "System Power", type = str, options = ("on", "off"), setter = _set_power(self)) self.pressure = Stream(title = "System Pressure", type = int, unit = "mbar") self.pressure_limit = Property(title = "System Pressure Limit", type = int, unit = "mbar", min = 1000, max = 50000, setter = _set_pressure_limit(self)) self.output = Property(title = "Output", type = str, options = ("waste", "collect"), setter = _set_output(self)) self.pump1 = R2Pump("Pump A", _set_pump_target(self, 0), _set_pump_input(self, 0)) self.pump2 = R2Pump("Pump B", _set_pump_target(self, 1), _set_pump_input(self, 1)) self.loop1 = Property(title = "Loop A Position", type = str, options = ("load", "inject"), setter = _set_loop(self, 0)) self.loop2 = Property(title = "Loop B Position", type = str, options = ("load", "inject"), setter = _set_loop(self, 1)) self.heater1 = R4Heater("Heater A", _set_heater_target(self, 0)) self.heater2 = R4Heater("Heater B", _set_heater_target(self, 1)) self.heater3 = R4Heater("Heater C", _set_heater_target(self, 2)) self.heater4 = R4Heater("Heater D", _set_heater_target(self, 3)) self.ui = ui( traces = [{ "title": "Pressure", "unit": self.pressure.unit, "traces": [self.pressure, self.pump1.pressure, self.pump2.pressure], "colours": ["#0c4", "#F70", "#50a"] }, { "title": "Temperature", "unit": self.heater1.temp.unit, "traces": [self.heater1.temp, self.heater2.temp, self.heater3.temp, self.heater4.temp], "colours": ["#0c4", "#F70", "#50a", "#921"] }], properties = [ self.pressure, self.pump1.pressure, self.pump2.pressure, self.pump1.rate, self.pump2.rate, self.pump1.input, self.pump2.input, self.heater1.temp, self.heater2.temp, self.heater3.temp, self.heater4.temp ] )
class Sartorious(Machine): protocolFactory = Factory.forProtocol(QueuedLineReceiver) name = "Sartorious Balance" def setup(self): # setup variables self.weight = Stream(title="Weight", type=float, unit="g") def start(self): def interpret_weight(result: str) -> float: result_value = float((result[-14:-4]).replace(" ", "")) self.weight._push(result_value) to_monitor = [] def addMonitor(command, fn, variable: Stream): def interpret(result): variable._push(fn(result), now()) to_monitor.append((command, interpret)) addMonitor("P", interpret_weight, self.weight) def monitor(): for cmd, fn in to_monitor: self.protocol.write(cmd).addCallback(fn) self._monitor = self._tick(monitor, 1) def stop(self): self._stopTicks() def reset(self): return defer.succeed('OK') def tare(self): return self.protocol.write("T", expectReply=False, wait=5)
def setup(self): # setup variables self.power = Property(title="Power", type=str, options=("on", "off"), setter=_set_power(self)) self.percentage_setpoint = Property( title="Setpoint", type=float, unit="%", setter=_set_percentage_setpoint(self)) self.pressure_setpoint = Property(title="Setpoint", type=float, unit="bar", setter=_set_pressure_setpoint(self)) self.percentage_pressure = Stream(title="Flow rate", type=float, unit="%") self.pressure = Stream(title="Flow rate", type=float, unit="bar")
def setup(self): # setup variables self.power = Property(title="Power", type=str, options=("on", "off"), setter=_set_power_l(self)) self.target = Property(title="Target speed", type=float, unit="1/min", setter=_set_setpoint_l(self)) self.speed = Stream(title="Speed", type=float, unit="1/min")
class Aladdin(Machine): protocolFactory = protocol.Factory.forProtocol(SinglePumpReceiver) name = "World Precision Instruments Aladdin Syringe Pump" def setup(self, syringe_diameter): @defer.inlineCallbacks def set_rate(rate): # Get the current rate try: state, result = yield self.protocol.command("RAT") except CommandError as e: raise # Cannot set rate if the pump is running - stop the pump. if state in ("I", "W", "A"): try: yield self.protocol.command("STP") except CommandError as e: if e.type is not CommandError.NOT_APPLICABLE: pass # Set the rate yield self.protocol.command("RAT{:.3f}".format( rate / _rate_unit_factors[self._rate_unit])[:8] + self._rate_unit) # Only start if the rate > 0 if rate > 0: state, result = yield self.protocol.command("RUN") if state in ("I", "W"): defer.returnValue("OK") else: raise Error("Could not start pump") else: defer.returnValue("OK") def set_direction(direction): direction = "WDR" if direction == "withdraw" else "INF" return self.protocol.command("DIR" + direction) # setup variables self.status = Property(title="Status", type=str) self.rate = Property(title="Flow rate", type=float, unit="uL/min", setter=set_rate) self.direction = Property(title="Direction", type=str, options=("infuse", "withdraw"), setter=set_direction) self.dispensed = Stream(title="Volume dispensed", type=float, unit="mL") self.withdrawn = Stream(title="Volume withdrawn", type=float, unit="mL") self._syringe_diameter = syringe_diameter self._vol_unit = "UL" self._rate_unit = "MM" self.ui = ui(properties=[self.rate]) def start(self): ## To set: # SAF50 # VER = version # DIA = syringe diameter (only not during program) ## To call # VOL = volume to be dispensed (only not during program) # CLD = clear dispensed volume (only not during program) ## To monitor: # DIR = pumping direction (INF/WDR/REV) # DIS = volume dispensed # RAT = pumping rate (stored if not during program) ## Phase Programming... todo? # RUN = run pumping program # STP = stop pumping program # LOC = keyboard lockout (only during program) # ... # Setup monitor on a tick to update variables def interpretDispensed(result): if result is None: return status, result = result self.status._push(_aladdin_status[status]) vol_unit = result[12:14] unit = _vol_unit_factors[vol_unit] self._vol_unit = vol_unit self.dispensed._push(unit * float(result[1:6])) self.withdrawn._push(unit * float(result[7:12])) def interpretRate(result): if result is None: return status, result = result rate_unit = result[5:7] unit = _rate_unit_factors[rate_unit] self._rate_unit = rate_unit self.rate._push(unit * float(result[0:5])) def interpretDirection(result): if result is None: return self.direction._push("infuse" if result[1] == "INF" else "withdraw") def monitor(): return defer.gatherResults([ self.protocol.command("DIS").addCallback( interpretDispensed).addErrback(lambda f: self.log.failure( "While getting dispensed volume", f)), self.protocol.command("RAT").addCallback( interpretRate).addErrback( lambda f: self.log.failure("While getting rate", f)), self.protocol.command("DIR").addCallback( interpretDirection).addErrback(lambda f: self.log.failure( "While getting direction", f)) ]) def setMonitor(result): self._tick(monitor, 1) return defer.gatherResults([ self.protocol.command("STP").addErrback( lambda f: self.log.failure("While stopping pump", f)), self.protocol.command("SAF50"), self.protocol.command("VER"), self.protocol.command("DIA{:.3f}".format( self._syringe_diameter)[:8]), monitor().addCallback(setMonitor) ]) def stop(self): # Disable safe mode to prevent timeout error. self._stopTicks() self.protocol.command("SAF0") def reset(self): # Setup a single program phase with unlimited volume # Default to stopped (0 rate) and infuse direction. return defer.gatherResults([ self.protocol.command("STP").addErrback( lambda f: self.log.failure("While stopping pump", f)), self.protocol.command("PHN01"), self.protocol.command("FUNRAT"), self.protocol.command("VOL0"), self.protocol.command("RAT0"), self.protocol.command("DIRINF") ]) def pause(self): self._pauseState = self.rate.value return self.rate.set(0) def resume(self): try: return self.rate.set(self._pauseState) except AttributeError: return defer.succeed()
class R2R4 (Machine): title = "Vapourtec R2+/R4" protocolFactory = R2ProtocolFactory() def setup (self, **kwargs): # setup variables self.status = Property(title = "Status", type = str) self.power = Property(title = "System Power", type = str, options = ("on", "off"), setter = _set_power(self)) self.pressure = Stream(title = "System Pressure", type = int, unit = "mbar") self.pressure_limit = Property(title = "System Pressure Limit", type = int, unit = "mbar", min = 1000, max = 50000, setter = _set_pressure_limit(self)) self.output = Property(title = "Output", type = str, options = ("waste", "collect"), setter = _set_output(self)) self.pump1 = R2Pump("Pump A", _set_pump_target(self, 0), _set_pump_input(self, 0)) self.pump2 = R2Pump("Pump B", _set_pump_target(self, 1), _set_pump_input(self, 1)) self.loop1 = Property(title = "Loop A Position", type = str, options = ("load", "inject"), setter = _set_loop(self, 0)) self.loop2 = Property(title = "Loop B Position", type = str, options = ("load", "inject"), setter = _set_loop(self, 1)) self.heater1 = R4Heater("Heater A", _set_heater_target(self, 0)) self.heater2 = R4Heater("Heater B", _set_heater_target(self, 1)) self.heater3 = R4Heater("Heater C", _set_heater_target(self, 2)) self.heater4 = R4Heater("Heater D", _set_heater_target(self, 3)) self.ui = ui( traces = [{ "title": "Pressure", "unit": self.pressure.unit, "traces": [self.pressure, self.pump1.pressure, self.pump2.pressure], "colours": ["#0c4", "#F70", "#50a"] }, { "title": "Temperature", "unit": self.heater1.temp.unit, "traces": [self.heater1.temp, self.heater2.temp, self.heater3.temp, self.heater4.temp], "colours": ["#0c4", "#F70", "#50a", "#921"] }], properties = [ self.pressure, self.pump1.pressure, self.pump2.pressure, self.pump1.rate, self.pump2.rate, self.pump1.input, self.pump2.input, self.heater1.temp, self.heater2.temp, self.heater3.temp, self.heater4.temp ] ) def gsioc (self, id): d = defer.Deferred() def interpret (response): if response[:13] == 'GSIOC reply: ': return response[13:] if response == 'GSIOC command failed' or response == 'GSIOC timed out': raise GSIOCNoDevice(id) if response == 'GSIOC command OK': return True def immediate_command (line): return self.protocol.write( "TG i %d %s" % (id, line) ).addCallback(interpret) def buffered_command (line): return self.protocol.write( "TG b %d %s" % (id, line) ).addCallback(interpret) def r (result): d.callback(GSIOCSlave( immediate_command, buffered_command, name = "%s(GSIOC:%s)" % ( self.protocol.connection_name, id ) )) return result self.ready.addCallback(r) return d def start (self): # setup monitor on a tick to update variables self._timeZero = now() # in seconds def handleClearHistory (result): if result == 'OK': self._timeZero = now() def clearHistory (): return self.protocol.write("HR").addCallback(handleClearHistory) heaterMode = { "U": "off", "C": "cooling", "H": "heating", "S": "stable unheated", "F": "stable heated" } status = ( "off", "running", "system overpressure", "pump 1 overpressure", "pump 2 overpressure", "system underpressure", "pump 1 underpressure", "pump 2 underpressure" ) def heaterTemp (input): if input == "-1000": return 0 else: return float(input) / 10 def interpretPressure (result, sendTime): if result == "OK": return result = [x.split(",") for x in result.split("&")] # Compensate for difference between clocks. # # Expect the last time returned to have some delay: # At least 0.1s (frequency of collection) # + 1/2 round-trip communication time # # Any other difference is due to slow/fast clock, # which can be re-zeroed from time to time. # # Algorithm: # lastTime = self._timeZero + (float(result[-1][0]) / 10) # roundTripTime = now() - sendTime # expectedDiff = 0.1 + (roundTripTime / 2) # timeDiff = (lastTime - now()) - expectedDiff timeDiff = self._timeZero + (float(result[-1][0]) * 0.1) - 0.1 - (now() * 1.5) + (sendTime * 0.5) if timeDiff < -0.05: self._timeZero -= timeDiff for v in result: if len(v) < 4: return time = self._timeZero + (float(v[0]) / 10) self.pressure._push(int(v[1]) * 10, time) self.pump1.pressure._push(int(v[2]) * 10, time) self.pump2.pressure._push(int(v[3]) * 10, time) def interpretHistory (result): if result == "OK": return for type, parts in [x.split("{") for x in result[:-1].split("}")]: data = [x.split(",") for x in parts.split("&")] if type == "T": for v in data: if len(v) < 9: continue time = self._timeZero + (float(v[0]) / 10) self.heater1.mode._push(heaterMode[v[1]], time) self.heater1.temp._push(heaterTemp(v[2]), time) self.heater2.mode._push(heaterMode[v[3]], time) self.heater2.temp._push(heaterTemp(v[4]), time) self.heater3.mode._push(heaterMode[v[5]], time) self.heater3.temp._push(heaterTemp(v[6]), time) self.heater4.mode._push(heaterMode[v[7]], time) self.heater4.temp._push(heaterTemp(v[8]), time) if type == "W": for v in data: if len(v) < 5: continue time = self._timeZero + (float(v[0]) / 10) self.heater1.power._push(int(v[1]), time) self.heater2.power._push(int(v[2]), time) self.heater3.power._push(int(v[3]), time) self.heater4.power._push(int(v[4]), time) if type == "F": for v in data: if len(v) < 3: continue time = self._timeZero + (float(v[0]) / 10) self.pump1.rate._push(int(v[1]), time) self.pump2.rate._push(int(v[2]), time) if type == "V": for v in data: if len(v) < 2: continue time = self._timeZero + (float(v[0]) / 10) v = int(v[1]) self.pump1.input._push("reagent" if v & 1 else "solvent", time) self.pump2.input._push("reagent" if v & 2 else "solvent", time) self.loop1._push("inject" if v & 4 else "load", time) self.loop2._push("inject" if v & 8 else "load", time) self.output._push("collect" if v & 16 else "waste", time) # Reset the R2's internal clock before it runs out # of numbers for timing (v[0] ~ 2**15 ?) if now() > self._timeZero + 2500: clearHistory() def interpretStatus (result): v = result.split(" ") if len(v) < 11: return time = now() self.power._push("on" if v[0] == "1" else "off", time) self.status._push(status[int(v[0])], time) self.pump1.target._push(int(v[1]), time) self.pump2.target._push(int(v[2]), time) self.pump1.airlock._push(int(v[3]), time) self.pump2.airlock._push(int(v[4]), time) self.pressure_limit._push(float(v[5]) / 100, time) self.heater1.target._push(int(v[7]), time) self.heater2.target._push(int(v[8]), time) self.heater3.target._push(int(v[9]), time) self.heater4.target._push(int(v[10]), time) def monitorPressure (): self.protocol.write("HP").addCallback(interpretPressure, now()) def monitorStatus (): self.protocol.write("HH").addCallback(interpretHistory) self.protocol.write("GA").addCallback(interpretStatus) def startMonitors (result): self._tick(monitorPressure, 0.1) self._tick(monitorStatus, 1) clearHistory().addCallback(startMonitors) def stop (self): self._stopTicks() def reset (self): return defer.gatherResults([ self.power.set("off"), self.pressure_limit.set(15000), self.output.set("waste"), self.loop1.set("load"), self.loop2.set("load"), self.pump1.input.set("solvent"), self.pump2.input.set("solvent"), self.pump1.target.set(0), self.pump2.target.set(0), self.heater1.target.set(-1000), self.heater2.target.set(-1000), self.heater3.target.set(-1000), self.heater4.target.set(-1000) ]) def pause (self): self._pauseState = self.power.value return self.power.set("off") def resume (self): return self.power.set(self._pauseState)
def setup(self): # setup variables self.weight = Stream(title="Weight", type=float, unit="g")