Lucas Rose
Published © GPL3+

Toothbrush Launcher & Timer

This device ejects your toothbrush at you then times how long you've brushed for, as well as saves the longest recorded brush.

IntermediateFull instructions provided2 hours3
Toothbrush Launcher & Timer

Things used in this project

Hardware components

Limit Switch (Generic)
Any limit switch works as long as they have 2 pins.
×1
KY-037 "Big Sound" Sensor
×1
Photon 2
Particle Photon 2
×1
Photo resistor
Photo resistor
×1
Relay Module (Generic)
×1
DC Motor, Miniature
DC Motor, Miniature
×1
ELEGOO 3PCS 0.96 Inch OLED Display Screen Module Compact Self-Luminous SSD1306 I2C Display Mini Screens
×1
Breadboard (generic)
Breadboard (generic)
×1

Hand tools and fabrication machines

3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

Enclosure

This is the encasing for the breadboard and electrical components. The limit switch should be put at the back of the launch tube. The motor and flywheel should be in the little cutout by the mouth of the launch tube on the base of the thing. The breadboard goes in the main compartment and the lid goes on top. The little block is to shorten the gap between the toothbrush and the limit switch so it doesn't need to be pushed that far back. This block worked for me but you can make your own depending on the length of your brush; or just move the limit switch forward. The sound and photo resistor should be aligned with the big hole in the lid to allow light and sound through. The hole near the mouth of the launch tube is for the OLED display's pins.

Sketchfab still processing.

Schematics

Circuit Diagram

Follow it to connect everything. Adding a bigger motor and a better motor control system than I have currently in place wouldn't hurt.

Code

toothbrushlauncher.ino

C/C++
This is the main code for the device. Load this onto your particle device after installing the Adafruit_SSD1306 library and it should work.
#include <Adafruit_SSD1306.h>
#include "Particle.h"

SYSTEM_MODE(AUTOMATIC);

SerialLogHandler logHandler(LOG_LEVEL_INFO);

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64

Adafruit_SSD1306 screen(-1);
int averageSound = 0;
int count = 0;

void setup() {
    pinMode(2, OUTPUT); // Motor
    pinMode(4, INPUT_PULLUP); // Limit switch
    
    digitalWrite(2, LOW);

    Serial.begin(9600);

    Wire.begin();
    screen.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    screen.clearDisplay();
    
    averageSound = averageAmbientSound();
}

class Display {
public:
    static int longest;
    int current;
    bool newRecord;
    
    Display(int num){
        current = num;
        newRecord = false;
    }
    
    void displayCurrent(){
        screen.clearDisplay();
        screen.setCursor(0, 0);
        screen.setTextSize(4);
        screen.setTextColor(WHITE);
        screen.println((double) current / 100);
        screen.display();
    }
    
    void countCurrent(){
        current += 10;
        
        if (current > longest){
            newRecord = true;
            longest = current;
        }
    }
    
    void displayFinal(){
        screen.clearDisplay();
        screen.setCursor(0, 0);
        screen.setTextSize(2);
        screen.setTextColor(WHITE);
    
        if (newRecord) {
            screen.println("New Record");
            screen.print(longest / 100);
            screen.println(" sec!");
            newRecord = false;
            screen.display();
        } else {
            screen.println("Your time:");
            screen.print(current / 100);
            screen.println(" sec");
            screen.display();
            
            for (int i = 0; i < 300; i++) {
                Particle.process();
                delay(10);
            }
    
            screen.clearDisplay();
            screen.setCursor(0, 0);
            screen.println("Longest:");
            screen.print(longest / 100);
            screen.println(" sec");
            screen.display();
        }
    
        for (int i = 0; i < 300; i++) {
            Particle.process();
            delay(10);
        }
    }
};
int Display::longest = 0;

void loop() {
    screen.clearDisplay();
    screen.setCursor(0, 0);
    screen.setTextSize(5);
    screen.print(":)");
    screen.display();

    Serial.print("Lights on: ");
    Serial.print(analogRead(A0));
    Serial.print(" Clap: ");
    Serial.print(analogRead(A1));
    Serial.print(" Motor Status: ");
    Serial.print(digitalRead(2));
    Serial.print(" Switch Status: ");
    Serial.print(digitalRead(4));
    Serial.print(" Average Sound: ");
    Serial.println(averageSound);
    
    if (detectLight() && detectClap()){
        screen.clearDisplay();
        screen.setCursor(0, 0);
        screen.setTextSize(2);
        screen.print("Activating...");
        screen.display();
        
        delay(2000);
        
        activateMotor();
        Serial.println("IN");
        
        Display display(0);
        
        while (digitalRead(4) == 0){
            display.countCurrent();
            display.displayCurrent();
            delay(10);
        }
        
        display.displayFinal();
    }
    
    Serial.println("OUT");
    delay(10);
    
    if (count == 1000){
        averageSound = averageAmbientSound();
        count = 0;
    }
    
    count++;
}

void activateMotor(){
    digitalWrite(2, HIGH);
    delay(2000);
    digitalWrite(2, LOW);
}


bool detectLight(){
    if (analogRead(A0) < 2500){
        return true;
    } else {
        return false;
    }
}

bool detectClap(){
    if (analogRead(A1) > averageSound + 20){
        return true;
    } else {
        return false;
    }
}

int averageAmbientSound(){
    int sum = 0;
    for (int i = 0; i < 100; i++){
        Particle.process();
        sum += analogRead(A1);
        delay(10);
    }
    
    return sum / 100;
}

Credits

Lucas Rose
1 project • 0 followers

Comments