Example data demonstrating the PCR works
Green channel was plotted to compare. Heat conditions:
Samples
Note: after 30 cycles signal was visable
Steps for building a mini thermocycler
Custom Parts:thermoblock_holder_1inch_half.stl
1. Milling thermoblock. It costs $100 to make this. thermoblock_holder_1inch_half.stl | |
2. Lid with 2 3mm set screws drillblock_1inch_lid_half.stl | |
3. Block holder hermoblock_holder_1inch_half.stl | |
4. Extrusion connects tslot_hinge_thermalblock.stl | |
5. Brd base thermocycle_brd.stl | |
6. PCB board pcbs_thermominiblock.zip Parts: gerberfiles_parts.zip | |
7. Single tip imager singletip_imager.stl |
Off the shelf ($43) + assembled brd is around $20 a unit + pipetters $20:
1. Power supply | |
2. Peltier cooling system | |
3. Mosfets | |
4. Diodes | |
5. Heater/Thermistors | |
6. Arduino Nano |
import time,datetime,os from datetime import datetime import json,re import serial import subprocess def timestamp(gg): now = datetime.now() # current date and time date_time = now.strftime("%m/%d/%Y, %H:%M:%S") print("date and time:",date_time) gg.write("date and time: " + date_time) def openport(prt): try: ser = serial.Serial(prt, 115200, timeout=0.2) time.sleep(2) except: print("its not connecting") return ser def whatstheports(): try: output = subprocess.check_output("python3 -m serial.tools.list_ports -v", shell=True).decode() b = re.split("\n", output) if len(b)>1: for i in b: if re.match('^ ', i): pass else: try: dada = (re.sub(' .*', '',i)) if re.match('^.*AMA0.*$', dada): pass else: #ser = serial.Serial('/dev/ttyUSB0', 115200, timeout=0.2) ser = serial.Serial(dada, 115200, timeout=0.2) time.sleep(2) ser.write(b'info\n') time.sleep(0.2) resp = (ser.readlines()[0].decode()) ser.close() if re.match('^tempcontrol.*', resp): return dada except: pass else: print("You need to plug in the device") except: print("please plug the device in") def read(): port = whatstheports() ser = openport(port) ser.write(b'readlevel\n') b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(temp) def incubate(stemp): print("Beginning to incubate at this temp "+stemp) print("To stop, ^c to kill the program") port = whatstheports() ser = openport(port) ser.write(b'settemp '+stemp.encode()+b'\n') ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) a = 1 while a >0: ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(temp) def coolon(): print("cooling ... ") port = whatstheports() ser = openport(port) ser.write(b'fanon\n') time.sleep(0.5) ser.write(b'coolon\n') time.sleep(0.5) ser.write(b'settemp 0\n') a = 1 while a > 0: ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(temp) def flashon(): port = whatstheports() ser = openport(port) ser.write(b'strobmic\n') return ser def flashoff(ser): ser.write(b'off\n') ser.close() def runcycle(dtemp,dtemptm,etemp,etemptm,cy): print(int(cy)) ccy = int(cy) gg = open("log.txt", "w") timestamp(gg) gg.write("Thermcycler denature "+dtemp+"C time "+dtemptm+" extend "+etemp+" time "+etemptm+" cycle "+cy+"\n") print("Thermcycler denature "+dtemp+"C time "+dtemptm+" extend "+etemp+" time "+etemptm+" cycle "+cy) print("To stop, ^c to kill the program\n") port = whatstheports() ser = openport(port) time.sleep(1) #ser.write(b'setp 300\n') for i in range(0,ccy): print("cycle "+str(i)) gg.write("cycle "+str(i)+"\n") cycle(dtemp,dtemptm,etemp,etemptm,cy,ser,i,gg) print("finished thermocycling") timestamp(gg) gg.write("finished thermocycling\n") gg.close() def cycle(dtemp,dtemptm,etemp,etemptm,cy,ser,cycle,gg): print("Cycle "+str(cycle)) print("Setting denaturing temperature to "+str(dtemp)+"C") gg.write("Cycle "+str(cycle)+"\n") gg.write("Setting denaturing temperature to "+str(dtemp)+"C\n") ser.write(b'settemp '+dtemp.encode()+b'\n') ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) while temp < (int(dtemp)+1): ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(temp) gg.write(str(temp)+"\n") if temp == (int(dtemp)): break time.sleep(int(dtemptm)) ser.write(b'settemp 0\n') print("Setting extend temperature to "+str(etemp)+"C") print("Cooling ... ") gg.write("Setting extend temperature to "+str(etemp)+"C\n") gg.write("Cooling ... \n") ser.write(b'fanon\n') time.sleep(0.3) ser.write(b'coolon\n') time.sleep(0.3) ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) while temp > (int(etemp)+1): ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(str(cycle) + ' ' + str(temp)) gg.write(str(cycle) + ' ' + str(temp)+'\n') if temp == (int(etemp)): break ser.write(b'fanoff\n') time.sleep(0.3) ser.write(b'cooloff\n') time.sleep(0.3) print("extend temperature begins") gg.write("extending \n") time.sleep(0.3) ser.write(b'settemp '+etemp.encode()+b'\n') while temp > (int(etemp)+1): ser.write(b'readlevel\n') time.sleep(0.2) b = (ser.readlines()) temp = float(b[0].decode().rstrip()) print(temp) gg.write(str(temp)+"\n") gg.write("incubating at extend temperaure\n") print("incubating at extend temperaure\n") time.sleep(int(etemptm)) input_var = input("Thermobock controller [help|h, about|a, incubate|i, cycle|c], read|r, cool, flashon: ") if re.match("help|h", input_var): print("This controller the thermocycler. Here are the available commands") print("\thelp[h] - Provides the options") print("\tabout[a] - About the program, the product its used for and the developer") print("\tincubate[i] - Incubate at specific temperate. The command goes like this -incubate[i]_[your temperature]. So something like this 'i_55' or 'incubate_55' for incubating at 55C") print("\tread[r] - Read temperature sensor, it reports in Celcius") print("\tcycle - Cycling conditions. Argument goes like this -cycle[c] extent_time_denature_time_cycles. Like cycle_94_30_55_180_40 for 55C for 30 seconds then 55 for 180 seconds") print("\tflashon - Turns on LED") elif re.match("port", input_var): whatstheports() elif re.match("read|r", input_var): read() elif re.match("cool", input_var): coolon() elif re.match("incubate_.*|i_.*", input_var): [arg, temp] = re.split('_', input_var) incubate(temp) elif re.match("cycle_.*|c_.*", input_var): [arg, dtemp,dtemptm,etemp,etemptm,cy] = re.split('_', input_var) runcycle(dtemp,dtemptm,etemp,etemptm,cy) elif re.match("flashon", input_var): ser = flashon() floff = input("Press [enter] to turn off") flashoff(ser) else: print("command not recognized")
#include <Servo.h> #include <PID_v1.h> //#include <FastPID.h> Servo myservo; // create servo object to control a servo #include <Wire.h> #include <SoftwareSerial.h> #define THERMISTOR_PIN A7 #define TEMPCONTROL 3 #define FANPIN 5 #define THERMOELECTRIC_COOL 6 #define LED 9 //Define the aggressive and conservative Tuning Parameters double aggKp=150, aggKi=0.5, aggKd=0; int thermoelectricval = 255; int ledval = 255; int tempcontrol = 3; String command; float currpos; int celsius; int levelstreamon; double settemp = 0; double Setpoint, Input, Output; int tme = 250; //Specify the links and initial tuning parameters //PID myPID(&Input, &Output, &Setpoint, consKp, consKi, consKd, DIRECT); PID myPID(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, DIRECT); #define NUMTEMPS 20 short temptable[NUMTEMPS][2] = { {1, 841}, {54, 255}, {107, 209}, {160, 184}, {213, 166}, {266, 153}, {319, 142}, {372, 132}, {425, 124}, {478, 116}, {531, 108}, {584, 101}, {637, 93}, {690, 86}, {743, 78}, {796, 70}, {849, 61}, {902, 50}, {955, 34}, {1008, 3} }; void setup() { // put your setup code here, to run once: Serial.begin(115200); analogWrite(TEMPCONTROL, 0); analogWrite(FANPIN, 0); Setpoint = settemp; //turn the PID on myPID.SetMode(AUTOMATIC); analogWrite(THERMOELECTRIC_COOL,0); analogWrite(LED,0); } void loop() { Input = read_temp(); double gap = abs(Setpoint-Input); //distance away from setpoint myPID.SetTunings(aggKp, aggKi, aggKd); myPID.Compute(); analogWrite(TEMPCONTROL,Output); int rawvalue = analogRead(THERMISTOR_PIN); float celsius = read_temp(); int fahrenheit = (((celsius * 9) / 5) + 32); if (levelstreamon == 1) { Serial.println(celsius); delay(500); } if(Serial.available()) { char c = Serial.read(); if (c== '\n') { parseCommand(command); command = ""; } else { command +=c; } } delay(1); } float parseCommand(String com) { if(com.equalsIgnoreCase("info")){ Serial.println("tempcontrol"); } else if(com.equalsIgnoreCase("levelstreamon")){ levelstreamon = 1; } else if(com.equalsIgnoreCase("defaultpid")){ double aggKp=19.56, aggKi=0.71, aggKd=134.26; } else if (com.substring(0,4) == "setp") { aggKp = com.substring(5).toDouble(); } else if (com.substring(0,4) == "seti") { aggKi = com.substring(5).toDouble(); } else if (com.substring(0,4) == "setd") { aggKd = com.substring(5).toDouble(); } else if(com.equalsIgnoreCase("coolon")){ analogWrite(THERMOELECTRIC_COOL,thermoelectricval); } else if(com.equalsIgnoreCase("cooloff")){ analogWrite(THERMOELECTRIC_COOL,0); } else if (com.substring(0,10) == "setledval") { ledval = com.substring(11).toInt(); } else if(com.equalsIgnoreCase("levelstreamoff")){ levelstreamon = 0; } else if(com.equalsIgnoreCase("fanon")){ analogWrite(FANPIN, 255); } else if(com.equalsIgnoreCase("fanoff")){ analogWrite(FANPIN, 0); } else if(com.equalsIgnoreCase("readlevel")){ int rawvalue = analogRead(THERMISTOR_PIN); float celsius = read_temp(); Serial.println(celsius); } else if (com.substring(0,12) == "setthermoval") { //Serial.println("setting temperature"); thermoelectricval = com.substring(13).toInt(); //Serial.println(settemp); } else if (com.substring(0,7) == "settemp") { //Serial.println("setting temperature"); settemp = com.substring(8).toInt(); //Serial.println(settemp); Setpoint = settemp; } else if(com.equalsIgnoreCase("strobmic")){ strobingmic(ledval, tme); delay(10); } } float read_temp() { int rawtemp = analogRead(THERMISTOR_PIN); float current_celsius = 0; byte i; for (i=1; i<NUMTEMPS; i++) { if (temptable[i][0] > rawtemp) { float realtemp = temptable[i-1][1] + (rawtemp - temptable[i-1][0]) * (temptable[i][1] - temptable[i-1][1]) / (temptable[i][0] - temptable[i-1][0]); if (realtemp > 255) realtemp = 255; current_celsius = realtemp; break; } } // Overflow: We just clamp to 0 degrees celsius if (i == NUMTEMPS) current_celsius = 0; return current_celsius; } void strobingmic(int ledval, int tme){ int strobtimer = 1; while (strobtimer > 0 && Serial.available() == 0){ analogWrite(LED, ledval); delayMicroseconds(tme); analogWrite(LED, 0); delayMicroseconds(tme); strobtimer++; } analogWrite(LED, 0); }