Project in progress
DNA-Dave, the Transcription Translation Robot Educator

DNA-Dave, the Transcription Translation Robot Educator © MIT

DNA-Dave is striving to be the best tool to teach kids molecular biology concepts. The key word is "striving."

  • 1,541 views
  • 0 comments
  • 6 respects

Components and supplies

Apps and online services

About this project

In the spirit of Simone Giertz, we embarked on a journey to make a fun robot. The goal was to help kids understand basic biology. DNA-Dave has a nucleus for a head, mRNA for hair, DNA complementary strands for eyes and lips. in his belly, there is a ribosome: the protein complex that is responsible for translating RNA to protein. By interacting with Dave, a child is immersed in a completely new world, where "transcription" and "translation" are the ideas it needs to understand to get to the goal: a working protein, dispensed by Dave!

Here we will present how Dave works, how kids interact with him, his quirks and features, and then document his transition from an Arduino board to a micro:bit. We will also present microDaves, little working DNA translators that kids will be making using micro:bits and LED strips, at a workshop designed to teach how you get from DNA to protein, the universal genetic code, and how folding of RNA and protein can happen due to the sequence of the molecular chain.

In the first iteration of DNA-Dave we used an Arduino Uno as the microcontroller to drive the various components. You can find the schematics, pictures of the build and Arduino code below:

Interacting with Dave
Late night coding session with Dave

We made a simpler version of the DNA Dave software to work with the BBC micro:bit microcontroller. We then made the wiring of Dave to be easily accessible for a micro:bit using a breakout board (octopus:bit) and a small breadboard. Due to the small number of PINs available without crosstalk with other functions of the microbit, we changed the LEDs of Dave to be individually addressable strings of LEDs, and used the microbit code we attach here to drive him. A full breakdown of microbit-Dave will be writen here shortly.

miniDaves:

Big Dave, in his quest to teach kids the core concepts of biology, needs little helpers. They come in the form of miniDaves, the DNA translators! We use a micro:bit connected to a string of individually addressable LEDs to write and visualise arbitrary DNA sequences, then translate them and visualise their corresponding amino-acid sequences. The setup is as follows:

There are two versions of the code for miniDaves. The first version is the simple case where we want to write a "DNA sequence" using the two buttons of the microbit, tilting the microbit to the left to write A and Ts and to the right to write C and Gs. If we press both buttons at the same time we delete the sequence. We then light up the LEDs, each light representing with a color a nucleotide. We would like this code to be as easy as possible, so that kids can write it and modify it with us during a workshop. The kids will also learn how DNA or RNA, due to complementarity in is sequence, forms loops and folds into shapes, that sometimes has functional significance.

The second version of miniDaves is a fully working DNA translator. Additional code makes the microbit able to "transcribe" the DNA sequence by triplets to a corresponding amino-acid, using the Universal Genetic Code. We access this function-state by shaking the microbit: we have added this second state in the main loop of the program, and when in that state, the miniDave will light up the LEDs and represent the peptide chain that this DNA sequence corresponds to. We used the RasMol amino color scheme for amino-acid chains that makes polar residues appear bright in color, and non-polar be more dull. We hope that we can then make apparent how proteins fold due to their sequence. In a workshop setting, the kids can lookup online using BLAST what the sequence they came up with might be actually be doing, by looking up what proteins-DNA have this sequence. We hope that by working with this miniDave DNA translator kids can be exposed to the wonder of the Universal Genetic Code, transcription, translation, the basic molecular chains of life, and concepts like the transition from sequence to structure.

miniDave in action. Could work as a DNA-Protein nightlight!


Code

miniDave_microbit_DNA_translatorJavaScript
this is Javascript MakeCode code for a microbit connected to a strip of individually addressable LEDs, where you can input and visualise a DNA sequence, then translate it into an amino-acid sequence! Just paste it into the Javascript Window of MakeCode online editor. The AminoAcid color scheme is similar to RasMol amino color scheme, itself similar to Shapely scheme.
function transcribe_and_translate_the_DNA_string () {
    RNA_string = []
    AminoAcid_string = []
    for (let index = 0; index <= DNA_string.length; index++) {
        if (DNA_string[index] == "t") {
            RNA_string.insertAt(index, "u")
        } else {
            RNA_string.insertAt(index, DNA_string[index])
        }
    }
    number_of_triplets = RNA_string.length / 3
    for (let index2 = 0; index2 <= number_of_triplets; index2++) {
        RNA_triplet_position_1 = RNA_string.shift()
        RNA_triplet_position_2 = RNA_string.shift()
        RNA_triplet_position_3 = RNA_string.shift()
        RNA_triplet = "" + RNA_triplet_position_1 + RNA_triplet_position_2 + RNA_triplet_position_3
        AminoAcid = Universal_Genetic_Code_squashed[Universal_Genetic_Code_squashed.indexOf(RNA_triplet) + 1]
        AminoAcid_string.push(AminoAcid)
    }
}
input.onButtonPressed(Button.B, function () {
    if (tilt_state == 1) {
        DNA_string.push("g")
        basic.showLeds(`
            . # # # .
            # . . . .
            # . # # .
            # . . # .
            . # # # .
            `)
    } else {
        DNA_string.push("a")
        basic.showLeds(`
            . # # . .
            # . . # .
            # . . # .
            # # # # .
            # . . # .
            `)
    }
})
input.onButtonPressed(Button.A, function () {
    if (tilt_state == 0) {
        DNA_string.push("t")
        basic.showLeds(`
            # # # # #
            . . # . .
            . . # . .
            . . # . .
            . . # . .
            `)
    } else {
        DNA_string.push("c")
        basic.showLeds(`
            . # # # .
            # . . . .
            # . . . .
            # . . . .
            . # # # .
            `)
    }
})
input.onGesture(Gesture.Shake, function () {
    if (translate_state == 0) {
        translate_state = 1
        strip.clear()
        strip.show()
        basic.showString("Protein")
    } else {
        translate_state = 0
        basic.showString("DNA")
        strip.clear()
        strip.show()
    }
})
input.onGesture(Gesture.TiltRight, function () {
    tilt_state = 1
    basic.showLeds(`
        # # . . .
        # . # # #
        # # # . .
        . . # . #
        . . # # #
        `)
})
input.onButtonPressed(Button.AB, function () {
    DNA_string = []
    basic.showLeds(`
        # . . . #
        . # . # .
        . . # . .
        . # . # .
        # . . . #
        `)
    strip.clear()
})
input.onGesture(Gesture.TiltLeft, function () {
    tilt_state = 0
    basic.showLeds(`
        # # # . .
        . # . # .
        . # # . #
        . . # # #
        . . # . #
        `)
})
let position = 0
let AminoAcid = ""
let RNA_triplet = ""
let RNA_triplet_position_3 = ""
let RNA_triplet_position_2 = ""
let RNA_triplet_position_1 = ""
let number_of_triplets = 0
let RNA_string: string[] = []
let Universal_Genetic_Code_squashed: string[] = []
let AminoAcid_string: string[] = []
let DNA_string: string[] = []
let translate_state = 0
let tilt_state = 0
let strip: neopixel.Strip = null
strip = neopixel.create(DigitalPin.P0, 40, NeoPixelMode.RGB)
tilt_state = 0
translate_state = 0
DNA_string = []
AminoAcid_string = []
basic.showString("DNA!")
Universal_Genetic_Code_squashed = ["uuu", "phe", "uuc", "phe", "uua", "leu", "uug", "leu", "ucu", "ser", "ucc", "ser", "uca", "ser", "ucg", "ser", "uau", "tyr", "uac", "tyr", "uaa", "stop", "uag", "stop", "ugu", "cys", "ugc", "cys", "uga", "stop", "ugg", "trp", "cuu", "leu", "cuc", "leu", "cua", "leu", "cug", "leu", "ccu", "pro", "ccc", "pro", "cca", "pro", "ccg", "pro", "cau", "his", "cac", "his", "caa", "gln", "cag", "gln", "cgu", "arg", "cgc", "arg", "cga", "arg", "cgg", "arg", "auu", "ile", "auc", "ile", "aua", "ile", "aug", "met", "acu", "thr", "acc", "thr", "aca", "thr", "acg", "thr", "aau", "asn", "aac", "asn", "aaa", "lys", "aag", "lys", "agu", "ser", "agc", "ser", "aga", "arg", "agg", "arg", "guu", "val", "guc", "val", "gua", "val", "gug", "val", "gcu", "ala", "gcc", "ala", "gca", "ala", "gcg", "ala", "gau", "asp", "gac", "asp", "gaa", "glu", "gag", "glu", "ggu", "gly", "ggc", "gly", "gga", "gly", "ggg", "gly"]
basic.forever(function () {
    position = -1
    if (translate_state == 0) {
        for (let deoxyribonucleotide of DNA_string) {
            position += 1
            if (deoxyribonucleotide == "a") {
                strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Blue))
            } else if (deoxyribonucleotide == "t") {
                strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Green))
            } else if (deoxyribonucleotide == "c") {
                strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Orange))
            } else if (deoxyribonucleotide == "g") {
                strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Red))
            }
        }
    } else {
        transcribe_and_translate_the_DNA_string()
        for (let AminoAcid2 of AminoAcid_string) {
            position += 1
            if (AminoAcid2 == "ala") {
                strip.setPixelColor(position, neopixel.rgb(10, 10, 10))
            } else if (AminoAcid2 == "arg") {
                strip.setPixelColor(position, neopixel.rgb(40, 10, 235))
            } else if (AminoAcid2 == "asn") {
                strip.setPixelColor(position, neopixel.rgb(0, 150, 255))
            } else if (AminoAcid2 == "asp") {
                strip.setPixelColor(position, neopixel.rgb(255, 0, 0))
            } else if (AminoAcid2 == "cys") {
                strip.setPixelColor(position, neopixel.rgb(255, 200, 0))
            } else if (AminoAcid2 == "glu") {
                strip.setPixelColor(position, neopixel.rgb(230, 10, 10))
            } else if (AminoAcid2 == "gln") {
                strip.setPixelColor(position, neopixel.rgb(0, 255, 150))
            } else if (AminoAcid2 == "gly") {
                strip.setPixelColor(position, neopixel.rgb(235, 235, 235))
            } else if (AminoAcid2 == "his") {
                strip.setPixelColor(position, neopixel.rgb(255, 0, 255))
            } else if (AminoAcid2 == "ile") {
                strip.setPixelColor(position, neopixel.rgb(15, 90, 15))
            } else if (AminoAcid2 == "leu") {
                strip.setPixelColor(position, neopixel.rgb(0, 255, 0))
            } else if (AminoAcid2 == "lys") {
                strip.setPixelColor(position, neopixel.rgb(0, 0, 255))
            } else if (AminoAcid2 == "met") {
                strip.setPixelColor(position, neopixel.rgb(200, 255, 5))
            } else if (AminoAcid2 == "phe") {
                strip.setPixelColor(position, neopixel.rgb(0, 0, 50))
            } else if (AminoAcid2 == "pro") {
                strip.setPixelColor(position, neopixel.rgb(200, 100, 40))
            } else if (AminoAcid2 == "ser") {
                strip.setPixelColor(position, neopixel.rgb(255, 100, 0))
            } else if (AminoAcid2 == "thr") {
                strip.setPixelColor(position, neopixel.rgb(255, 50, 0))
            } else if (AminoAcid2 == "trp") {
                strip.setPixelColor(position, neopixel.rgb(180, 40, 60))
            } else if (AminoAcid2 == "tyr") {
                strip.setPixelColor(position, neopixel.rgb(10, 0, 40))
            } else if (AminoAcid2 == "val") {
                strip.setPixelColor(position, neopixel.rgb(10, 200, 10))
            } else if (AminoAcid2 == "stop") {
                strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Black))
            }
        }
    }
    strip.show()
})
miniDave_microbit_DNA_only_visualiser_simpleJavaScript
This is MakeCode JavaScript code to use with a microbit that is connected to a strip/string of individually addressable LEDs. The user can input a DNA sequence using the microbit and see it in the strip of LEDs! It uses the neopixel extension.
input.onButtonPressed(Button.A, function () {
    if (tilt_state == 0) {
        DNA_string.push("t")
        basic.showLeds(`
            # # # # #
            . . # . .
            . . # . .
            . . # . .
            . . # . .
            `)
    } else {
        DNA_string.push("c")
        basic.showLeds(`
            . # # # .
            # . . . .
            # . . . .
            # . . . .
            . # # # .
            `)
    }
})
input.onButtonPressed(Button.B, function () {
    if (tilt_state == 1) {
        DNA_string.push("g")
        basic.showLeds(`
            . # # # .
            # . . . .
            # . # # .
            # . . # .
            . # # # .
            `)
    } else {
        DNA_string.push("a")
        basic.showLeds(`
            . # # . .
            # . . # .
            # . . # .
            # # # # .
            # . . # .
            `)
    }
})
input.onGesture(Gesture.TiltLeft, function () {
    tilt_state = 0
    basic.showLeds(`
        # # # . .
        . # . # .
        . # # . #
        . . # # #
        . . # . #
        `)
})
input.onGesture(Gesture.TiltRight, function () {
    tilt_state = 1
    basic.showLeds(`
        # # . . .
        # . # # #
        # # # . .
        . . # . #
        . . # # #
        `)
})
input.onButtonPressed(Button.AB, function () {
    DNA_string = []
    basic.showLeds(`
        # . . . #
        . # . # .
        . . # . .
        . # . # .
        # . . . #
        `)
    strip.clear()
})
let position = 0
let DNA_string: string[] = []
let tilt_state = 0
let strip: neopixel.Strip = null
strip = neopixel.create(DigitalPin.P16, 150, NeoPixelMode.RGB)
tilt_state = 0
DNA_string = []
basic.showString("DNA!")
basic.forever(function () {
    position = -1
    for (let deoxyribonucleotide of DNA_string) {
        position += 1
        if (deoxyribonucleotide == "a") {
            strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Red))
        } else if (deoxyribonucleotide == "t") {
            strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Orange))
        } else if (deoxyribonucleotide == "c") {
            strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Blue))
        } else if (deoxyribonucleotide == "g") {
            strip.setPixelColor(position, neopixel.colors(NeoPixelColors.Indigo))
        }
    }
    strip.show()
})
DNA-Dave_microbit_javascriptFromMakeCodeJavaScript
goto Makecode website and paste it into the javascript part of a project
function Glissanto (note1: number, note2: number, rate: number) {
    if (note1 < note2) {
        i = note1
        while (i < note2) {
            music.ringTone(i)
            control.waitMicros(rate)
            i += 2
        }
    } else {
        i = note1
        while (i > note2) {
            music.ringTone(i)
            control.waitMicros(rate)
            i += -2
        }
    }
    music.rest(0)
}
function Tremolo (note: number, length: number, rate: number) {
    note_duration = length / rate
    pauseBetweenNotes = rate * (1 + rate / length)
    for (let index = 0; index <= rate; index++) {
        music.playTone(note, note_duration)
        music.rest(pauseBetweenNotes)
    }
    music.rest(0)
}
input.onButtonPressed(Button.A, function () {
    greenArmpitButtonSound()
    control.waitMicros(1000)
})
input.onButtonPressed(Button.B, function () {
    redArmpitButtonSound()
    control.waitMicros(1000)
})
function success_sound () {
    for (let index2 = 0; index2 <= Math.randomRange(1, 6); index2++) {
        for (let index22 = 0; index22 <= 1000; index22++) {
            music.ringTone(1000 + index22)
            control.waitMicros(300)
        }
    }
    music.rest(music.beat(BeatFraction.Whole))
    music.stopMelody(MelodyStopOptions.All)
}
function angry_Dave_sound () {
    for (let index3 = 0; index3 <= 4; index3++) {
        for (let index23 = 0; index23 <= 1000; index23++) {
            music.ringTone(1000 - index23)
            control.waitMicros(300)
        }
    }
    music.rest(music.beat(BeatFraction.Whole))
    music.stopMelody(MelodyStopOptions.All)
}
function dispense_protein () {
    which_protein = Math.randomRange(0, strip2.length() - 1)
    strip2.setPixelColor(which_protein, neopixel.rgb(Math.randomRange(0, 255), Math.randomRange(0, 255), Math.randomRange(0, 255)))
    strip2.setPixelColor(Math.abs((which_protein - 1) % strip2.length()), neopixel.rgb(Math.randomRange(0, 255), Math.randomRange(0, 255), Math.randomRange(0, 255)))
    strip2.show()
    for (let index4 = 0; index4 <= 9 * strip2.length() - 1; index4++) {
        strip2.rotate(1)
        strip2.show()
        music.ringTone(index4 * index4)
        control.waitMicros(index4 * 7000)
    }
    strip2.clear()
    strip2.setPixelColor(which_protein, neopixel.colors(NeoPixelColors.Green))
    strip2.show()
    success_sound()
    control.waitMicros(6000000)
    strip.clear()
    strip.show()
    control.waitMicros(2000000)
    strip2.clear()
    strip2.show()
}
function redArmpitButtonSound () {
    rand = Math.randomRange(1, 4)
    if (rand == 1) {
        Glissanto(784, 392, 0)
        Glissanto(392, 784, 0)
        control.waitMicros(100000)
        Glissanto(784, 392, 0)
        Glissanto(392, 784, 0)
    }
    if (rand == 2) {
        Glissanto(1400, 1000, 0)
        Glissanto(1200, 800, 0)
        Glissanto(1000, 6000, 0)
        control.waitMicros(300000)
        Tremolo(440, 30, 3)
        control.waitMicros(100000)
        Tremolo(659, 30, 12)
    }
    if (rand > 2) {
        Glissanto(784, 392, 0)
        control.waitMicros(300000)
        Glissanto(784, 392, 0)
        Glissanto(784, 196, 0)
    }
}
function greenArmpitButtonSound () {
    rand = Math.randomRange(1, 5)
    if (rand == 1) {
        Glissanto(784, 392, 0)
        control.waitMicros(300000)
        Glissanto(880, 220, 0)
        control.waitMicros(100000)
        Tremolo(175, 30, 3)
        control.waitMicros(100000)
        Tremolo(131, 30, 3)
        control.waitMicros(100000)
        Glissanto(131, 523, 0)
        Glissanto(988, 392, 0)
    }
    if (rand == 2) {
        Glissanto(500, 2000, 0)
        control.waitMicros(500000)
        Tremolo(800, 30, 3)
        control.waitMicros(100000)
        Tremolo(600, 30, 3)
        control.waitMicros(100000)
        Glissanto(300, 1700, 0)
        Glissanto(600, 3000, 0)
    }
    if (rand == 3) {
        Glissanto(6000, 200, 0)
        control.waitMicros(500000)
        Tremolo(1000, 30, 3)
        control.waitMicros(100000)
        Tremolo(600, 30, 3)
        control.waitMicros(100000)
        Tremolo(800, 30, 3)
        control.waitMicros(100000)
        Tremolo(400, 30, 3)
    }
    if (rand == 4) {
        Glissanto(6000, 5500, 100)
        control.waitMicros(100000)
        Glissanto(6000, 5500, 100)
        control.waitMicros(300000)
        Glissanto(6000, 5500, 100)
        control.waitMicros(100000)
        Tremolo(1000, 30, 3)
        control.waitMicros(10000)
        Tremolo(600, 30, 3)
        control.waitMicros(10000)
        Tremolo(800, 30, 3)
        control.waitMicros(10000)
        Tremolo(400, 30, 3)
    }
    if (rand == 5) {
        Glissanto(294, 2000, 0)
        control.waitMicros(500000)
        Tremolo(1760, 30, 3)
        control.waitMicros(100000)
        Tremolo(1396, 30, 3)
        control.waitMicros(100000)
        Glissanto(5000, 2500, 0)
        Glissanto(5000, 2500, 0)
    }
}
let which_LED = 0
let cog_average_before = 0
let cog_average = 0
let Dave_state = 0
let cog_voltage = 0
let rand = 0
let which_protein = 0
let pauseBetweenNotes = 0
let note_duration = 0
let i = 0
let strip2: neopixel.Strip = null
let strip: neopixel.Strip = null
strip = neopixel.create(DigitalPin.P8, 10, NeoPixelMode.RGB)
strip2 = neopixel.create(DigitalPin.P16, 6, NeoPixelMode.RGB)
let increment = 20
let dispensed_protein = 1
basic.forever(function () {
    cog_voltage = pins.analogReadPin(AnalogPin.P1)
    control.waitMicros(1000)
    if (Dave_state == 0) {
        strip.clear()
        strip.show()
        cog_average = 0
        pins.digitalWritePin(DigitalPin.P2, 1)
        if (cog_voltage < 20) {
            pins.digitalWritePin(DigitalPin.P2, 0)
            strip.clear()
            strip2.clear()
            strip.show()
            strip2.show()
            Dave_state = 1
            cog_average_before = 20
        }
    } else if (Dave_state == 1) {
        cog_average += (cog_voltage - cog_average) * 0.7
        which_LED = Math.round(Math.map(cog_average, 0, 1023, 0, strip.length() + 2))
        for (let index5 = 0; index5 <= which_LED; index5++) {
            strip.setPixelColor(index5, neopixel.rgb(Math.randomRange(0, 255), Math.randomRange(0, 255), Math.randomRange(0, 255)))
        }
        strip.show()
        if (cog_average > cog_average_before + increment) {
            cog_average_before = cog_average
        } else if (cog_average < cog_average_before - increment) {
            Dave_state = 2
        }
        if (cog_average > 740) {
            Dave_state = 3
        }
    } else if (Dave_state == 2) {
        angry_Dave_sound()
        Dave_state = 0
    } else if (Dave_state == 3) {
        success_sound()
        dispense_protein()
        Dave_state = 0
        strip.clear()
        strip.show()
    }
})
DNA-Dave_Arduino
This is the code that runs on the arduino version of DNA-Dave

Custom parts and enclosures

DNA Dave CAD drawings
eDrawings file of all of DNA Dave's components. We suggest that you download solidworks eDrawings Viewer (which is free!).
dna_dave_edrawings_assembly_OJk0paVKZJ.easm

Schematics

Build Your Own DNA Dave -Booklet
Download this file to get your complete guide to the project - learn about how proteins are made, how DNA Dave works and learn how to code your own robot.
DNA-Dave_Arduino
fritzing schematic file
dna-dave_arduino_gHiMUAC7Ki.fzz
DNA-Dave_Arduino_png
schematic png file
Dna dave arduino bb ra9qusnykt
DNA-Dave_microbit
fritzing diagram of microbit version of DNA-Dave. simpler wiring and code than the arduino version
dna-dave_microbit_LyDgAhnAqS.fzz
DNA-Dave_microbit_diagram
Dna dave microbit bb ygrzq3mq5v

Comments

Similar projects you might like

Gesture-Controlled Robot

Project tutorial by Youssef El-Gendy and Romina Abachi

  • 5,076 views
  • 0 comments
  • 14 respects

Amazing 6WD Off-Road Robot | Arduino RC Robot

Project tutorial by Jithin Sanal

  • 9,980 views
  • 0 comments
  • 54 respects

Scriba Robot - A Printing Robot

Project in progress by RobinB

  • 2,549 views
  • 0 comments
  • 8 respects

MeArm Robot Arm - Your Robot - V1.0

Project tutorial by Benjamin Gray

  • 29,594 views
  • 4 comments
  • 42 respects

End-Effector and Control Logic for Robot

Project showcase by Team PowerBerry

  • 8,599 views
  • 2 comments
  • 43 respects

Mini Me 1.5 - Adafruit HUZZAH Robot Doll

Project tutorial by Kitty Yeung

  • 6,143 views
  • 2 comments
  • 29 respects
Add projectSign up / Login