Team:UMaryland/Design
UMD DIY PCR
How we created a dual purpose PCR machine and incubator out of a hair dryer.
Construction Hazard. Jumping hairdryer safety measures will cause rapid heating of the machine, without proper control the machine may cause fires. Proceed with caution.
Background
Click to show
The PCR machine is a quintessential component of any biological laboratory that needs to amplify or extend fragments of DNA for subsequent experiments. This tool is especially relevant to iGEM and SynBio labs who pave the way to vaster applications of genetic engineering.
Our initial prototype for a DIY PCR machine was modeled in the fashion of most readily available commercial machines, relying on on two Peltier units stacked on top of each other to heat a customized aluminum block in which PCR tubes would sit. In order for the system to be informed by accurate feedback on temperature fluctuations, we embedded a temperature sensor in the aluminum block. The sensor reported the temperature to an Arduino UNO, which responded by regulating the energy flow to the Peltier units, thereby controlling the temperature of the block and tubes.
However, after substantial testing, this design proved to be unoriginal, expensive, and inefficient. We were troubled to realize that the parts used to assemble it were not as easily accessible as we had hoped, which we felt would take away from the possible applications of this machine as well as the philosophy of its construction. In addition, although the price of this first prototype was relatively inexpensive compared to laboratory-grade PCR machines, the price still exceeded our goal, ultimately costing several hundred dollars. Finally, the final straw that led to our eventual redesign was the inefficiency of the hardware: we found that the Peltier units were not able to quickly cycle through the desired temperatures, causing the unit to take 5 to 10 minutes just to rise up to 95℃, where denaturation must occur between each of the 25 or so cycles. After considering this combination of factors, we embarked on a redesign of our machine to better suit the needs of the DIY market.
To combat the unacceptably slow temperature ramp rate, we made a decision to suspend construction on the Peltier-centered thermocycler in order to attempt making a rapid PCR machine out of a hair dryer. Before committing to this effort, we considered the danger of working with a hair dryer and the potential for failure: we were uncertain that the machine could be effectively controlled and had a narrow window of time within which to design and trouble shoot the machine. Nevertheless, we took the risk.
Please continue on to see the design of our machine.
Click to hide
Design
Click to show
We began by working out how to wire the hairdryer so that we could regulate the heating unit and the fan separately.
After significant soldering and reworking the internal safety measures inside the hairdryer, we were able to wire the system so that we could turn the heat on and off while running the fan continuously. Using tape, we secured a sheet of aluminium foil to the top of the heating unit of the hairdryer. The outer casing of the hairdryer had been removed. We placed a heat sensor inside the tin to measure the temperature of the air inside the machine. By wiring the heat sensor to the Arduino, we were able to receive input/feedback from the sensor and adjust the heating of the device to maintain our desired setpoints and produce proper thermocycling.
At this point, we tried to perform our first PCR reaction. Unfortunately, we soon found that we had melted our tube. We learned that the machine had difficulty with evenly distributing the heat. To better distribute the heat, we removed our tinfoil lid and replaced it with with a cut soda can. This can was designed with evenly spaced holes enabling for better heat distribution. Although we did not and still have not modeled the heat transfer of between the can's surface and the convection heating generated by the hair dryer, we were able to experimentally conclude that the heat distribution was more even across the can than the tin foil.
After construction of the can-based cover, we attempted PCR once more and still found that amplification had not occurred. We assumed that the heat sensor might have been an issue; it was exposed to the moving air and as such was relaying information about the air temperature rather than the temperature of the reaction mixture within the PCR tubes. This meant that our feedback system was not accurately responding to or controlling the temperature inside of the PCR tubes. To compensate for this discrepancy, we put the heat sensor inside a PCR tube with mineral oil and placed this inside one of the holes. We ran another PCR reaction, visualized the products on an agarose gel, and witnessed a large band of the correct size, indicating that our machine had worked.
Click to hide
Hardware
Click to show
The working internals of our PCR machine are comprised of hairdryer elements. With the exception of the hairdryers outer housing, the thermal fuse and bimetallic circuit breaker, all other working components remain intact. The thermal fuse and bimetallic circuit breaker were shorted using copper wire in order to reach temperatures up to 95 within our machine. The outer plastic housing of the hairdryer was also removed to enable our machine to stand upright and fit PCR tubes. The hairdryers heating mechanism which utilizes a bank of nichrome wires and fan that distributes the heat remained untouched.
Click to hide
Electronics
Click to show
Click to hide
Problems and Current issues
Click to show
We have had one successful amplification with our machine; however, we still struggle to replicate these results with an updated housing design (essentially, a new soda can with appropriately sized holes). Our trials still suggest that our temperature sensor and the liquid reaction housed within the tube are not at the same temperature, with a discrepancy of over 10 degrees Celsius. We are currently working of milling a block of aluminum with better and more consistent heat transfer properties, and modeling the heat transfer within the can. Our hope is that modeling the heat transfer will facilitate better control of temperature within the device.
Click to hide
CODE
#include <PID_v1.h> #include<math.h> #include <LiquidCrystal.h> //The PID functions by adjusting a certain output in order to // minimize the error between two values, which are the setpoint // and the input. // The PID function itself creates a PID controller and takes // five parameters: // Input: The value that needs to be controlled // Output: The value that the PID will adjust // Setpoint: The value that the input will be maintained at // Kp,Ki,KD: Parameters that will affect how the output is adjusted // Direct: Defines which direction the output will proceed given an error // Define PID varaibles double Setpoint, Input, Output; PID myPID(&Input, &Output, &Setpoint, 1550, 800, 780, DIRECT); //LiquidCrystal lcd( 8, 9, 4, 5, 6, 7 ); //PCR Variables int stepnow = 1; int cycle = 2; int laststep = 0; int count = 1; int startup = 2; // Cycles int cycles = 35; int cyclenum = (cycles-1)*3 +1; //Startup cycle int meltT1 = 96; int pcrT1 = 59; //All cycles int meltT = 96; int pcrT = 59; int extensionT = 73; //End cycle int endextT = 73; int endT = 4; int deathT = 97; int val0; int val1; int val; int tempPin0 = 2; int tempPin1 = 3; int signalr1 = 3; int signalr2 = 5; String pcr = "starting "; boolean cooling = false; //Startup cycle unsigned long Melt1 = 180; unsigned long t1Melt = Melt1*1000; unsigned long PCR1 = 20; unsigned long t1PCR = PCR1*1000; unsigned long extension1 = 20; unsigned long textension1 = extension1*1000; // All cycles unsigned long Melt = 30; unsigned long tMelt = Melt*1000; unsigned long PCR = 30; unsigned long tPCR = PCR*1000; unsigned long extension = 20; unsigned long textension = extension*1000; //End cycle unsigned long extend = 30; unsigned long textend = extend*1000; unsigned long cycleStart; int WindowSize = 500; unsigned long windowStartTime; // Sets up the staring environment and will only run once void setup() { Serial.begin(9600); //lcd.begin(16, 2); windowStartTime = millis(); myPID.SetOutputLimits(0, WindowSize); myPID.SetMode(AUTOMATIC); pinMode(signalr1, OUTPUT); pinMode(signalr2, OUTPUT); Setpoint = meltT1; } void loop() { if (stepnow < cyclenum) { //The following code is only implemented once as the first cycle of the PCR // This allows for the user to set conditions which may be different from the subsequent // cycles. The code, however, works in much the same way as the other cycles // at the most basic level. It divides each cycle into subcycles: activation, pcr and extension // and enters each step based on stepnow(which denotes how many subcyles the program has entered) divisiblity by 3. // The remainder for activation will always be 1, // the remainder for pcr will be 2 and the remainder for extension will be 3 //Begins activation of the PCR by checking that this is the first cycle and that the current subcycle is activation if (((stepnow % 3) == 1) && (cycle == 2)) { // sets the setpoint that the pcr will heat up to as meltT1 Setpoint = meltT1; // prints out the current cycle number and the step it is currenly on Serial.println(pcr + count); // If the setpoint has reached the desired temperature, it will enter this loop if (((Input - meltT1 + 1) > 0) && (laststep != stepnow)) { // Starts the timer and maintains this temperature for the desired amount of time cycleStart = millis(); pcr = "maintaining cycle activation: cycle "; laststep++; } //If the pcr has maintained the setpoint for the desired amount //of time, it will enter this loop and begin cooling if ((millis() > (t1Melt + cycleStart)) && (laststep == stepnow)) { stepnow++; pcr = "cooling to pcr "; cooling = true; } } // Checks that the current step is the subcycle pcr if (((stepnow % 3) == 2) && (cycle == 2)) { // sets the temperature as pcrT1 Setpoint = pcrT1; Serial.println(pcr + count); //checks that the machine has reached the setpoint if (((Input - pcrT1 - 1) < 0) && (laststep != stepnow)) { cooling = false; cycleStart = millis(); pcr = "maintaining cycle pcr: cycle "; laststep++; } //checks if the machine has maintained the temperature for //the desired amount of time, and begins the next step if ((millis() > (t1PCR + cycleStart)) && (laststep == stepnow) && (cycle == 2)) { stepnow++; pcr = "heating to extension "; } } // Checks that the current step is the subcycle extension if ((cycle == 2) && ((stepnow % 3) == 0)) { // sets the temperature as extensionT Setpoint = extensionT; Serial.println(pcr + count); //checks that the machine has reached the setpoint if (((Input - extensionT + 1) > 0) && (laststep != stepnow)) { pcr = "maintaining cycle extension: cycle "; cycleStart = millis(); laststep++; } //checks if the machine has maintained the temperature // for the desired amount of time, and begins the next step if ((millis() > (textension1 + cycleStart)) && (laststep == stepnow)) { pcr = "heating to melt "; stepnow++; cycle++; count++; } } //Begins the intermediate steps which work in an identical manner to the startup cycle //and may differ only in the alloted temperatures and times for each subcycle if (((stepnow % 3) == 1) && (cycle != 2)) { Setpoint = meltT; Serial.println(pcr + count); if (((Input - meltT + 1) > 0) && (laststep != stepnow)) { pcr = "maintaining melt: cycle "; cycleStart = millis(); laststep++; } if ((millis() > (tMelt + cycleStart)) && (laststep == stepnow)) { stepnow++; cooling = true; pcr = "cooling to pcr "; } } if (((stepnow % 3) == 2) && (cycle != 2)) { Setpoint = pcrT; Serial.println(pcr + count); if (((Input - pcrT - 1) < 0) && (laststep != stepnow)) { cooling = false; pcr = "maintaining pcr: cycle "; cycleStart = millis(); laststep++; } if ((millis() > (tPCR + cycleStart)) && (laststep == stepnow) ) { stepnow++; pcr = "heating to extension "; } } if (((stepnow % 3) == 0) && (cycle != 2)) { Setpoint = extensionT; Serial.println(pcr + count); if (((Input - extensionT + 1) > 0) && (laststep != stepnow)) { cycleStart = millis(); pcr = "maintaining extension: cycle "; laststep++; } if ((millis() > (textension + cycleStart)) && (laststep == stepnow)) { stepnow++; count++; pcr = "heating to melt "; } } // Begins the last step, which again works in a similar fashion // to the other steps, but may differ in the final extension temperature } else if ((stepnow >= cyclenum && stepnow <= cyclenum + 2 )) { if (((stepnow % 3) == 1)) { Setpoint = meltT; Serial.println(pcr + count); if (((Input - meltT + 1) > 0) && (laststep != stepnow)) { pcr = "maintaining melt: cycle "; cycleStart = millis(); laststep++; } if ((millis() > (tMelt + cycleStart)) && (laststep == stepnow)) { stepnow++; cooling = true; pcr = "cooling to pcr "; } } if (((stepnow % 3) == 2)) { Setpoint = pcrT; Serial.println(pcr + count); if (((Input - pcrT - 1) < 0) && (laststep != stepnow)) { cooling = false; pcr = "maintaining pcr: cycle "; cycleStart = millis(); laststep++; } if ((millis() > (tPCR + cycleStart)) && (laststep == stepnow) ) { stepnow++; pcr = "heating to extension "; } } if (((stepnow % 3) == 0)) { Setpoint = extensionT; Serial.println(pcr + count); if (((Input - extensionT + 1) > 0) && (laststep != stepnow)) { cycleStart = millis(); pcr = "maintaining extension: cycle "; laststep++; } if ((millis() > (textend + cycleStart)) && (laststep == stepnow)) { stepnow++; count++; pcr = "cooling to end "; } } // Once the last step has been completed, determined by // stepnow being greater than cyclenum+2,the code will tell the // pcr to hold at 4 C. It will continue looping at this step indefinitely // because the conditions will no longer satisfy any of the other if statement } else { int strt = 1; boolean cooldown = true; if (strt == 1) { Setpoint = endT; Serial.println(pcr); } // begins cooldown to 4 if (cooldown) { digitalWrite(signalr1, HIGH); digitalWrite(signalr2, LOW); } //Once the pcr has reached 37 C, the pcr will //print out that the pcr has shutt off if ((Input - 38 + 1) < 0) { digitalWrite(signalr1, HIGH); digitalWrite(signalr2, LOW); pcr = "turn off"; } } // creates the window unsigned long now = millis(); if (now - windowStartTime > WindowSize) { windowStartTime += WindowSize; Input = val; // this function is called once every loop, and contains the pid algorithm myPID.Compute(); } // if cooling is true, it will begin cooling until cool is set to false if (cooling){ digitalWrite(signalr1, HIGH); digitalWrite(signalr2, LOW); Serial.println("COOLING"); // if the pcr machine's temperature reaches 97, cooling will // automatically be initiated and a death message will be displayed }else if ((Input - deathT +1) > 0){ digitalWrite(signalr1, HIGH); digitalWrite(signalr2, LOW ); Serial.println("DEATH"); // these two statements work on the maintaining the temperature, by // controlling heating and cooling when there is overshoot or undershoot // in the temperature } else if (Output > now - windowStartTime - 1) { digitalWrite(signalr1, HIGH); digitalWrite(signalr2, HIGH); } else { digitalWrite(signalr1, HIGH); digitalWrite(signalr2, LOW); } //int reading = analogRead(tempPin); val0 = (((analogRead(tempPin0) / 1024.0) * 5000) / 10); val1 = (((analogRead(tempPin1) / 1024.0) * 5000) / 10); //val = (val0 + val1)/2; val = val1; // determines the value of the current temperature and prints it out Serial.println(val); // loops back to the top of the code, this will occur indefinitely }