Rick Rogers
Published © MIT

Heatblock for COVID-19 Testing

A flexible, extensible platform for COVID-19 testing - quick and easy detection and tracing in the developing world using CRISPR tests.

IntermediateFull instructions provided8 hours5,254
Heatblock for COVID-19 Testing

Things used in this project

Hardware components

Arduino Nano Every
Arduino Nano Every
Can be any Arduino, or a custom PC board.
×1
SparkFun LED RGB - Generic
×2
SparkFun SPST mini pushbutton
Any SPST pushbutton will do
×2
TDK Corporation NTC Themistor
10K at 25C
×2
Delete me piezo speaker
Any generic piezo speaker
×1
ICStation Heater strip
×2
Power supply 12V 2A
Optional generic 12V power supply (can just run from a car battery instead...)
×1
Custom enclosure
Literally any enclosure - the submission uses a custom 3D printed enclosure (with .STL file provided), but a sardine can would do.
×1
Heater controllers
LED controllers were used in the submission (because they are cheap), but all that is needed is a simple MOSFET if a custom board is being created.
×1

Software apps and online services

Arduino IDE
Arduino IDE
Fritzing

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)
Soldering iron (generic)
Soldering iron (generic)
Drill / Driver, Cordless
Drill / Driver, Cordless

Story

Read more

Custom parts and enclosures

Covid-19 Precision Heatblock for CRISPR Diagnostic Testing

An STL file for a custom enclosure for a dual precision heatblock. The enclosure can be 3D printed, and provides mounting for an Arduino Nano and power MOSFET controllers. It also has appropriate openings for a 12V power connector and the Arduino microUSB.

Lid for Heatblock Custom Enclosure

An STL file for a lid for the custom enclosure that includes holes for heatblocks, LEDs, switches and a piezo speaker.

Faceplate Artwork for Covid-19 Precision Heatblock

An SVG file (created with Affinity Designer) for the faceplate of the heatblock. It includes appropriate labels and a guide to the meaning of the LED colors. In practice it would be easy to change languages, for example, or change the layout for heatblocks with a different geometry.

Faceplate Artwork as Affinity Designer file

Same as the other faceplate file, but the Affinity Designer version, for easier editing.

Schematics

Covid-19 Precision Heatblock for CRISPR Diagnostic Testing

A Fritzing dataset that implements an Arduino based dual precision heatblock for developing countries. Only the schematic portion of the dataset is valid - the breadboard and PC sections should not be used.

Code

Covid-19 Precision Heatblock for CRISPR Diagnostic Testing

Arduino
Arduino code to implement a precision dual heatblock for use with CRISPR based Covid-19 point of care tests.
// Heatblock sketch
// 
// Used to heat and hold temperature of two custom heatblocks.
// Temperatures are set as TempRT and TempCR.
// Timer values are TimeRT and TimeCR

// Author: Rick Rogers
// 
//Copyright (c) 2020 Rick Rogers
//
//Permission is hereby granted, free of charge, to any person obtaining a copy
//of this software and associated documentation files (the "Software"), to deal
//in the Software without restriction, including without limitation the rights
//to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//copies of the Software, and to permit persons to whom the Software is
//furnished to do so, subject to the following conditions:
//
//The above copyright notice and this permission notice shall be included in all
//copies or substantial portions of the Software.
//
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
//SOFTWARE.


#include <PID_v1.h>
#include <NTC_Thermistor.h>
#include <Thermistor.h>
#include <SmoothThermistor.h>
#include <jled.h>



// pin assignments
#define HeatRTpin 9 // heater for RT block (thru MOSFET)
#define HeatCRpin 10 // heater for CRISPR block (thru MOSFET)

#define RedRTpin 14 // Red LED for RT
#define GrnRTpin 8  // Green LED for RT
#define BluRTpin 7  // Blue LED for RT

#define RedCRpin 15  // Red LED for CRISPR
#define GrnCRpin 6  // Green LED for CRISPR
#define BluCRpin 5  // Blue LED for CRISPR

#define TempRTpin A3  // Temperature of RT
#define TempCRpin A4  // Temperature of CRISPR
#define tempScale 1 // Temperature scaling - temp to analog value

#define SwTimerRTpin 19 // Timer pushbutton for RT
#define SwTimerCRpin 20 // Timer pushbutton for CRISPR

#define SPKRpin 21 // Piezo speaker

// PID variables
double TempSPRT = 37.0; // Setpoint temperature for RT-LAMP reaction in degrees C
double TempSPCR = 42.0; // Setpoint temperature for CRISPR reaction om degrees C
double TempRT, TempCR, OutRT, OutCR;

// Timer constants
long TimeRTDur = 60*25; // seconds - RT timer duration
long TimeCRDur = 60*30; // seconds - CRISPR timer duration
bool TimeRTRun = false;
bool TimeCRRun = false;
long TimeRTBase;
long TimeCRBase;

// Initialize PID controllers
double Kp = 10.0;
double Ki = 0.25;
double Kd = 0;
PID RTPID(&TempRT, &OutRT, &TempSPRT, Kp,Ki,Kd, DIRECT);
PID CRPID(&TempCR, &OutCR, &TempSPCR, Kp,Ki,Kd, DIRECT);

// Initialize thermistor inputs
Thermistor* thermistorRT = new SmoothThermistor(
  new NTC_Thermistor(
    TempRTpin, 10000, 10000, 25.0, 3988), 5);
Thermistor* thermistorCR = new SmoothThermistor(
  new NTC_Thermistor(
    TempCRpin, 10000, 10000, 25.0, 3988), 5);

JLed LedRedRT = JLed(RedRTpin).Off();
JLed LedRedCR = JLed(RedCRpin).Off();
JLed LedBlueRT = JLed(BluRTpin).On();
JLed LedBlueCR = JLed(BluCRpin).On();
JLed LedGreenRT = JLed(GrnRTpin).Off();
JLed LedGreenCR = JLed(GrnCRpin).Off();

void setup() {
  Serial.begin(9600); // open the serial port at 9600 bps:
  
  // setup pin uses
  pinMode(HeatRTpin, OUTPUT);
  pinMode(HeatCRpin, OUTPUT);
  pinMode(RedRTpin, OUTPUT);
 // pinMode(GrnRTpin, OUTPUT);
 // pinMode(BluRTpin, OUTPUT);
  pinMode(RedCRpin, OUTPUT);
  //pinMode(GrnCRpin, OUTPUT);
  //pinMode(BluCRpin, OUTPUT);
  pinMode(SwTimerRTpin, INPUT_PULLUP);
  pinMode(SwTimerCRpin, INPUT_PULLUP);
  pinMode(SPKRpin, OUTPUT);

  // Start the PID loops
  TempRT = analogRead(TempRTpin);
  TempCR = analogRead(TempCRpin);

  RTPID.SetMode(AUTOMATIC);
  CRPID.SetMode(AUTOMATIC);

  TimeCRBase = millis()/1000.0;
  Serial.print("Kp="); Serial.print(Kp);
  Serial.print(" Ki="); Serial.print(Ki);
  Serial.print(" Kd="); Serial.print(Kd);
  Serial.print(" TempScale="); Serial.println(tempScale);
  Serial.println("Sec,TempRT,TempCR,OutRT,OutCR");

}

void loop() {
  // PID loops
  TempRT = thermistorRT->readCelsius();
  TempCR = thermistorCR->readCelsius();
  if (millis()%1000 < 3){
    Serial.print(millis()/1000 - TimeCRBase);
    Serial.print(",");
    Serial.print(TempRT);
    Serial.print(",");
    Serial.print(TempCR);
    Serial.print(",");
    Serial.print(OutRT);
    Serial.print(",");
    Serial.println(OutCR);
  }
  
  if (millis()%5000 < 3){
    // Once every 5 seconds, reset LED blink rates
    SetLEDColor(LedRedRT, LedBlueRT, LedGreenRT, TempRT, TempSPRT, 25.0);
    SetLEDColor(LedRedCR, LedBlueCR, LedGreenCR, TempCR, TempSPCR, 25.0);
  }
  // Update LEDs
  LedRedRT.Update();
  LedBlueRT.Update();
  LedGreenRT.Update();
  LedRedCR.Update();
  LedBlueCR.Update();
  LedGreenCR.Update();

  // Update PID loops
  CRPID.Compute();
  RTPID.Compute();
  analogWrite(HeatRTpin, (int)OutRT/tempScale);
  analogWrite(HeatCRpin, (int)OutCR/tempScale);

  
  // Timers
  // If a timer is running, increment time and see if time's up
  if (TimeRTRun) {
    // RT timer is running
    // Tick once a second
    if (millis()%1000 < 5){
      tone(SPKRpin, 500,50);
    }
    float TimeRTVal = millis()/1000.0;
    if (TimeRTVal > TimeRTBase+TimeRTDur) {
      // Time's up - sound beeper and clear timer
      tone(SPKRpin, 1000, 2000);
      TimeRTRun = false;
    }
  } else {
    // RT timer is not running - see if user wants to start
    if (!digitalRead(SwTimerRTpin)) {
      TimeRTRun = true;
      TimeRTBase = millis()/1000.0;
    }  
  }
  
  if (TimeCRRun) {
    // Tick once a second
    // CR Timer is running
    if (millis()%1000 < 5){
      tone(SPKRpin, 500,50);
    }
    float TimeCRVal = millis()/1000.0;
    if (TimeCRVal > TimeCRBase+TimeCRDur) {
      // Time's up - sound beeper and clear timer
      tone(SPKRpin, 500, 2000);
      TimeCRRun = false;
    }
  } else {
    // CR timer is not running - see if user wants to start
    if (!digitalRead(SwTimerCRpin)) {
      TimeCRRun = true;
      TimeCRBase = millis()/1000.0;
    }  
  }

}

void SetLEDColor(JLed &LedRed, JLed &LedBlue, JLed &LedGreen, double Temp, double TempSP, double TempRoom){
  double TempDiff = TempSP - Temp;
  if (abs(TempDiff) < double(4.0)){
    LedGreen.On();
    LedRed.Off();
    LedBlue.Off();
  }
  if (TempDiff > double(4.0)){
    LedBlue.Blink(500,500*(TempSP-Temp)/(TempSP-TempRoom)).Forever();
    LedRed.Off();
    LedGreen.Off();
  }
  if (TempDiff < double (-4.0)){
    LedRed.Blink(500,500*(TempSP-Temp)/(TempSP-TempRoom)).Forever();
    LedBlue.Off();
    LedGreen.Off();
  }
  LedRed.Update();
  LedBlue.Update();
  LedGreen.Update();
}

Credits

Rick Rogers

Rick Rogers

1 project • 2 followers
Veteran hardware and software developer, with Master's Degrees in EE and Biomedical Engineering.

Comments