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 common machine used in biological laboratories to amplify or extend fragments of DNA to be used in subsequent experiments. This tool is especially relevant to iGEM and SynBio labs who pave the way to vaster applications of We began this project with the vision to create a machine that would be
Our first design for a DIY PCR machine was modeled after a more conventional PCR machine. This first prototype relied on two Peltier units stacked on top of each other to heat a customized aluminum block that held the PCR tubes. In order for the system to have feedback, we embedded a temperature sensor in the aluminum block to measure the temperature of the PCR tube wells. The sensor then reported back to an Arduino UNO, which then regulated the energy flow to the Peltier units, thereby regulating the temperature of the block and tubes. However, after much testing, this design proved to be unoriginal, expensive, and inefficient. While the conventionality of the design itself did not pose an issue, we realized that the parts used to assemble it were not as well-known or easily accessible to the general public, which we felt would take away from the possible applications of this machine. In addition, although the price of this first prototype was relatively inexpensive in contrast to laboratory grade PCR machines, the price still ranged in the hundreds of dollars. Finally, the greatest issue with our design 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℃. After considering all of these factors, we began a redesign of our machine to better suit the needs of the DIY market.
The idea for our current thermocycler design first came into form when we found that our original prototype was not ramping up to the desired temperatures fast enough. We thus looked into other options such as the heating element in a hair dryer. We found that the hair dryer was able to reach very high temperatures—much higher than the desired maximum of 95℃ for PCR—in a matter of seconds. We then made a decision to suspend construction on the Peltier-centered thermocycler in order to see how successful we could be with making a rapid PCR machine out of a hair dryer. Before this decision, we took into consideration the danger of working with a hair dryer, failure due to uncertainty that the machine could be effectively controlled, and, on top of that, having less time to work on it. 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 a lot of 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 heating of the device to maintain our desired setpoints. We were able to regulate the heat of the machine in order to 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 tried PCR once more and still found that the reaction did not occur. We assumed that the heat sensor might have been an issue,; the sensor was exposed to the moving air and was relaying information about the air temperature instead of the temperature inside of the PCR tubes. This meant that our feedback system was not accurately responding and controlling the temperature inside of the PCR tubes. Assuming the temperatures inside the machine were not representative of the temperatures inside the PCR tubes, 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, ran the products on a gel and saw a large band of the correct size, indicating that our machine had worked.
Click to hide
Hardware
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 a lot of 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 heating of the device to maintain our desired setpoints. We were able to regulate the heat of the machine in order to 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 tried PCR once more and still found that the reaction did not occur. We assumed that the heat sensor might have been an issue,; the sensor was exposed to the moving air and was relaying information about the air temperature instead of the temperature inside of the PCR tubes. This meant that our feedback system was not accurately responding and controlling the temperature inside of the PCR tubes. Assuming the temperatures inside the machine were not representative of the temperatures inside the PCR tubes, 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, ran the products on a gel and saw 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 here to read about the parts used for our thermocycler.
The electronics of the machine are mainly comprised of two relays, an Arduino micro-controller and a lm35 temperature sensor.
Actuation
The relays convert the low wattage outputs of the Arduino into a high wattage output needed to power the hairdryer. The relays are switches that can be triggered by the milliwatt output of the Arduino and can handle the 1.8 kilowatt power of the hairdryer.
Sensing
The lm35 temperature sensor is used to provide the Arduino controller with input on the current temperature of the machine.
Software
Closing the loop
With both the temperature sensor and the relays we are able to provide the micro-controller with the ability to regulate and cycle the machine at various temperatures. To allow for tight temperature regulation within the machine a proportional integral derivative control scheme was adopted. This scheme enabled the controller to take temperature readings and calculate rate at which the temperature is increasing, the constant error of the machine found through the integral term, and the proportional error which compares current temperature to a set point. The way our code is designed and implemented utilizes three setpoints, 95,70, and 50 degrees C, all of these are variable and able to be adjusted but for convince we will define the three with these set of temperature values. A any given time only one of these setpoints is active, and the PID control scheme regulates temperature at that specific value. Since the machine needs to cycle and hit at least 3 different temperatures our code also logs time after each setpoint is hit, thus allowing us to define a time interval after which the setpoint is altered. What this means is that if we define the first setpoint to be 95 degrees C that our code will execute and tell the machine to heat to 95 and once that temperature is reached it will trigger a timing function which after a defined period will reset the setpoint to 50 degrees which will then force the machine to cool down to the new setpoint.
Click to hide
Problems and Current issues
Click to show
We have had one successful amplification with our machine however we understand that repeatability is a vital component of all lab work and currently we are attempting to make our device repeatable. From our early days of testing we found that peltier units were not powerful enough to enable PCR tube to reach 95 degrees. On the other hand, the fan and heating element of a cheap hairdryer provide a control scheme that enables for rapid cycling of temperature. We have found that developing a housing for the PCR tubes and enabling even heat distribution is challenging. We often have found that our temperature sensor and the pcr reaction tube are not at the same temperature and degree of difference is a delta 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 ambition is that this will enable 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 }