Change of tune

Problem:
There are many factors that have to be considered in managing risk of contagion during the pandemic. One particularly difficult element to get a good gauge on and keep continuous track of is is how well ventilated the air around you is at any given time.

This is crucial and can counterbalance whether it is safe to remain where you are at any given point of time. It can significantly overcome the risk odds of being less than 6ft away from people, both indoors and outdoors.

Without ventilation, aerosols remain suspended in the air, becoming increasingly concentrated as time goes by. (Source)

Solution:
A concealed wind sensor housed in a lapel pin that gives you audio feedback about the air ventilation around you. Ideally, this would be able to connect to your phone or audio device wirelessly so that you can check on this discretely whenever needed.
To engage, push a button on the pin and the reading will be sent to your audio device.
Visual indicators:
For demo purposes, I have added LEDs to help visualize the invisible elements present in the solution.
White LED: visual feedback of wind sensor values changing
Green/yellow/red LED: indicator of what range of ventilation is safe or not.
Audio feedback:
I chose 3 different tunes for the 3 risk levels:
High risk – morse code for SOS
Medium risk – tense, suspenseful tune
Low risk – major key arpeggio as a simple, positive sounding indicator.
Demo:

At the start, the wind sensor reads a low level of ventilation, and starts playing the SOS tune. As the ventilation increases, it switches to the low risk tune of a major arpeggio. As that value falls slightly, it starts playing the suspenseful tune before reverting back to the major arpeggio as the values increase again.

Components:

  • 1x RGB Diffused Common Cathode
  • 3x LED (Red, Green, Yellow)
  • 1x button
  • 7x Resistor 220 ohm
  • Wind Sensor Rev. C
  • 35CSB speaker

Schematic:

Code:

/*************************************************
* Sound Sensor
*************************************************/
#define analogPinForRV    1   // blue jumper wire
#define analogPinForTMP   0   // yellow jumper wire

// to calibrate your sensor, put a glass over it, but the sensor should not be
// touching the desktop surface however.
// adjust the zeroWindAdjustment until your sensor reads about zero with the glass over it. 

const float zeroWindAdjustment =  .2; // negative numbers yield smaller wind speeds and vice versa.

int TMP_Therm_ADunits;  //temp termistor value from wind sensor
float RV_Wind_ADunits;    //RV output from wind sensor 
float RV_Wind_Volts;
unsigned long lastMillis;
int TempCtimes100;
float zeroWind_ADunits;
float zeroWind_volts;
float WindSpeed_MPH;

//LED Feedback
int redPin = 9; //Pin for the red RGB led pin
int greenPin = 10; //Pin for the green RGB led pin
int bluePin = 11; //Pin for the blue RGB led pin 

int writeValue_red; //declare variable to send to the red LED
int writeValue_green; //declare variable to send to the green LED
int writeValue_blue; //declare variable to send to the blue LED



/*************************************************
* Interrupt Button
*************************************************/
static const int togglePin = 5;
bool buttonState = false;
const bool isInterrupt = true;

/*************************************************
* Melodies
*************************************************/
#include "pitches.h"
int speakerPin = 8;

// notes in the major melody (9 notes):
int majorMelody[] = {
NOTE_C4, NOTE_D4,NOTE_G4, NOTE_C5, 0, NOTE_C4, NOTE_D4, NOTE_G4, NOTE_C5};

// note durations: 4 = quarter note, 8 = eighth note, etc.:
int majorNoteDurations[] = {
   4, 4, 4, 4, 4, 4, 4, 4, 4
};

// notes in the minor melody (9 notes):
int minorMelody[] = {
NOTE_FS4, NOTE_FS4, NOTE_FS4, NOTE_DS4, 0, NOTE_E4, NOTE_E4, NOTE_E4, NOTE_CS4};
// note durations: 4 = quarter note, 8 = eighth note, etc.:

int minorNoteDurations[] = {
   8, 8, 8, 2, 4, 8, 8, 8, 2
};

// notes in morse code (11 notes):
int SOS[] = {
  NOTE_GS5, NOTE_GS5, NOTE_GS5, 0, NOTE_GS5, NOTE_GS5, NOTE_GS5, 0, NOTE_GS5, NOTE_GS5, NOTE_GS5
};

int SOSDurations[] = {
  8, 8, 8, 4, 2, 2, 2, 4, 8, 8, 8
};


/*************************************************
 * 
 * SETUP
 * 
*************************************************/

//void SwitchPressed(){
//  buttonState =! buttonState;
//}

void setup() {

  Serial.begin(57600);   // faster printing to get a bit better throughput on extended info
  // remember to change your serial monitor

  Serial.println("start");
  // put your setup code here, to run once:

  //   Uncomment the three lines below to reset the analog pins A2 & A3
  //   This is code from the Modern Device temp sensor (not required)
  pinMode(A2, INPUT);        // GND pin      
  pinMode(A3, INPUT);        // VCC pin
  digitalWrite(A3, LOW);     // turn off pullups

  //initialize button pin as input
//  pinMode(buttonPin, INPUT_PULLUP);

  //Risk feedback state
  int greenLED = 2;
  int yellowLED = 3;
  int redLED = 4;
  pinMode(greenLED, OUTPUT);
  pinMode(yellowLED, OUTPUT);
  pinMode(redLED, OUTPUT);

//  if (isInterrupt){
//      attachInterrupt(digitalPinToInterrupt(togglePin), SwitchPressed, RISING);    
//  }
  
}

void loop() {
  
/*************************************************
* Reading Wind Sensor
*************************************************/
  if (millis() - lastMillis > 200){      // read every 200 ms - printing slows this down further
    
    TMP_Therm_ADunits = analogRead(analogPinForTMP);
    RV_Wind_ADunits = analogRead(analogPinForRV);
    RV_Wind_Volts = (RV_Wind_ADunits *  0.0048828125);

    // these are all derived from regressions from raw data as such they depend on a lot of experimental factors
    // such as accuracy of temp sensors, and voltage at the actual wind sensor, (wire losses) which were unaccouted for.
    TempCtimes100 = (0.005 *((float)TMP_Therm_ADunits * (float)TMP_Therm_ADunits)) - (16.862 * (float)TMP_Therm_ADunits) + 9075.4;  

    zeroWind_ADunits = -0.0006*((float)TMP_Therm_ADunits * (float)TMP_Therm_ADunits) + 1.0727 * (float)TMP_Therm_ADunits + 47.172;  //  13.0C  553  482.39

    zeroWind_volts = (zeroWind_ADunits * 0.0048828125) - zeroWindAdjustment;  

    // This from a regression from data in the form of 
    // Vraw = V0 + b * WindSpeed ^ c
    // V0 is zero wind at a particular temperature
    // The constants b and c were determined by some Excel wrangling with the solver.
    
   WindSpeed_MPH =  pow(((RV_Wind_Volts - zeroWind_volts) /.2300) , 2.7265);   
   
//    Serial.print("  TMP volts ");
//    Serial.print(TMP_Therm_ADunits * 0.0048828125);
//    
//    Serial.print(" RV volts ");
//    Serial.print((float)RV_Wind_Volts);
//
//    Serial.print("\t  TempC*100 ");
//    Serial.print(TempCtimes100 );
//
//    Serial.print("   ZeroWind volts ");
//    Serial.print(zeroWind_volts);

    Serial.print("   WindSpeed MPH ");
    Serial.println((float)WindSpeed_MPH);

    lastMillis = millis();
  }

/*************************************************
* Wind sensor LED feedback
*************************************************/

  writeValue_red = (255./10.)*WindSpeed_MPH; //Calculate the value to write on the red LED (add point to change to float point)
  writeValue_green = (255./10.)*WindSpeed_MPH; //Calculate the value to write on the green LED
  writeValue_blue = (255./10.)*WindSpeed_MPH; ///Calculate the value to write on the blue LED
  
  analogWrite(redPin,writeValue_red); //write value to set the brightness of the red LED
  analogWrite(greenPin,writeValue_green); //write value to set the brightness of the green LED
  analogWrite(bluePin,writeValue_blue); //write value to set the brightness of the blue LED



/*************************************************
* State + Sound
*************************************************/

//if (buttonState == true){
//  

    if(WindSpeed_MPH <= 2){
    // turn red LED on:
    digitalWrite(4, HIGH);
    // turn the rest off:
    digitalWrite(2, LOW);
    digitalWrite(3, LOW);

    // play SOS melody:
     for (int thisNote = 0; thisNote < 11; thisNote++) {
      int noteDuration = 1000/SOSDurations[thisNote];
      tone(8, SOS[thisNote],noteDuration);
      //pause for the note's duration plus 30 ms:
      delay(noteDuration +30);
      noTone(8);
    }
  }

    else if (WindSpeed_MPH >7) {
      //turn green LED on:
      digitalWrite(2, HIGH);
      // turn the rest off:
      digitalWrite(4, LOW);
      digitalWrite(3, LOW);

      //play major melody:
      for (int thisNote = 0; thisNote < 9; thisNote++) {
      int noteDuration = 1000/majorNoteDurations[thisNote];
      tone(8, majorMelody[thisNote],noteDuration);
      //pause for the note's duration plus 30 ms:
      delay(noteDuration +30);
      noTone(8);
    }
   }

    else {
      //turn yellow LED on:
      digitalWrite(3, HIGH);
      // turn the rest off:
      digitalWrite(2, LOW);
      digitalWrite(4, LOW);

      //play minor melody:
      for (int thisNote = 0; thisNote < 9; thisNote++) {
      int noteDuration = 1000/minorNoteDurations[thisNote];
      tone(8, minorMelody[thisNote],noteDuration);
      //pause for the note's duration plus 30 ms:
      delay(noteDuration +30);
      noTone(8);
      
    }
    }
//    }
//    else {
//      noTone(8);
//      //turn all LEDs off:
//      digitalWrite(3, LOW);
//      digitalWrite(2, LOW);
//      digitalWrite(4, LOW);
//    }
/*************************************************
* Wind sensor LED feedback on button press
*************************************************/
//buttonState = digitalRead(buttonPin);
//
//if (buttonState == HIGH){
//
//  if (flag == 0){
//    //light up white LED
//    analogWrite(redPin,writeValue_red); //write value to set the brightness of the red LED
//    analogWrite(greenPin,writeValue_green); //write value to set the brightness of the green LED
//    analogWrite(bluePin,writeValue_blue); //write value to set the brightness of the blue LED
//  flag = 1;
//  }
//
//  if (flag == 1){
//    //turn off white LED
//    analogWrite(redPin,0); //write value to set the brightness of the red LED
//    analogWrite(greenPin,0); //write value to set the brightness of the green LED
//    analogWrite(bluePin,0); //write value to set the brightness of the blue LED
//    flag = 0;
//  }
//}
//
//if (buttonState == HIGH){
//    //light up white LED
//    analogWrite(redPin,writeValue_red); //write value to set the brightness of the red LED
//    analogWrite(greenPin,writeValue_green); //write value to set the brightness of the green LED
//    analogWrite(bluePin,writeValue_blue); //write value to set the brightness of the blue LED
//}
//
//else if (buttonState == LOW){
//    //turn off white LED
//    analogWrite(redPin,0); //write value to set the brightness of the red LED
//    analogWrite(greenPin,0); //write value to set the brightness of the green LED
//    analogWrite(bluePin,0); //write value to set the brightness of the blue LED
//}

}

Reminder: include pitches.h for code to work

 

Don’t trip on what’s in front of you!

Problem:

People often trip over small objects that are in their path that they may not be expecting, especially if the object isn’t very tall. This is because the object is well below their sight line unless they are looking towards the ground. If someone’s on their phone, they are also more likely to trip over a small object. Blind people also of course have to be able to navigate around things that they cannot see. While they have a cane that will help them to know if something is in front of them by it hitting it, but sounds to notify something within a stride could be helpful.

Proposed Solution:

To help people with this problem, I propose a small wearable device strapped to the ankle that will buzz at different intervals based on how far an object is. This device is made up of a servo motor, ultrasonic distance sensor, accelerometer, and pancake vibration motor. The servo, distance sensor, and accelerometer are all attached. The servo moves such that the accelerometer is level so that the distance sensor is pointed straight ahead. This is important because as you walk, your leg is at various angles and doesn’t stay vertical. The buzzing from the vibration motor is a good way to know how far you are from something because the sound is pretty distinctive and has the added bonus of being able to feel it on your leg. For an actual version of this, I would package this smaller so that it could be actually something small attached to your leg that isn’t cumbersome.  This would go on both ankles so that you’d know if something was in your path for sure and not just on one side. I’d also use a bigger vibration motor so that the sound is a bit louder; with this, I could feel it and hear it fine, but if the house was louder, it would’ve been harder to hear. I also wish that I had soldered the leads of the vibration motor while I was in A10 because the wire kept coming loose while trying to take videos of me walking and I’d have to bend down to fix it and then when I stood up, it would come loose again; along the same vein, I wish I had been recording the whole time because a really good example while walking with the all different buzzing intervals happened when I forgot to restart it.

Proof of Concept:

Schematic
//changed smoothing example from https://www.arduino.cc/en/Tutorial/BuiltInExamples/Smoothing

#include <Servo.h>

Servo myLittleMotor;
const int servoPin = 11;
int servoPosition = 120;

#include <NewPing.h>
const int triggerPin = 8;
const int echoPin = 9;
int maxDistance = 400;
NewPing sonar(triggerPin, echoPin, maxDistance);
const int footSize = 25.4;//cm
int distance;

const int numReadings = 10;
int DISTreadings[numReadings];      // the readings from the analog input
int readIndex = 0;              // the index of the current reading
int DISTtotal = 0;                  // the running total
int DISTaverage = 0;                // the average

const int yPin = A4;
int yVal;

const int pancakePin = 6;

void setup() {
  myLittleMotor.attach(servoPin);


  pinMode(yPin, INPUT);


  pinMode(pancakePin, OUTPUT);

  Serial.begin(9600);
  myLittleMotor.write(servoPosition);
  for (int thisReading = 0; thisReading < numReadings; thisReading++) {
    DISTreadings[thisReading] = 0;
  }

}

void loop() {
  myLittleMotor.write(servoPosition);
  yVal = analogRead(yPin);

  distance = sonar.ping_cm();
  // subtract the last reading:
  DISTtotal = DISTtotal - DISTreadings[readIndex];
  // read from the sensor:
  DISTreadings[readIndex] = distance;
  // add the reading to the total:
  DISTtotal = DISTtotal + DISTreadings[readIndex];
  // advance to the next position in the array:
  readIndex = readIndex + 1;

  // if we're at the end of the array...
  if (readIndex >= numReadings) {
    // ...wrap around to the beginning:
    readIndex = 0;
  }

  // calculate the average:
  DISTaverage = DISTtotal / numReadings;
  // send it to the computer as ASCII digits
  //Serial.println(Yaverage);
  if (yVal > 352 && servoPosition > 0) {
    servoPosition -= 1;
  }
  else if (yVal < 348 && servoPosition < 180) {
    servoPosition += 1;
  }
  if (DISTaverage < (1.5 * footSize)) { //1 footSize past your foot
    static int start = millis();
    //Serial.println("closest");
    if ((millis() - start) < 200) {
      //digitalWrite(speakerPin,HIGH);
      digitalWrite(pancakePin, HIGH);
    }
    else if ((millis() - start) < 400) {
      digitalWrite(pancakePin, LOW);
    }
    else {
      start = millis();
    }
  }
  else if (DISTaverage < (1.5 * footSize + footSize)) {
    static int start2 = millis();
    if ((millis() - start2) < 200) {
      digitalWrite(pancakePin, HIGH);
    }
    else if ((millis() - start2) < 600) {
      digitalWrite(pancakePin, LOW);
    }
    else {
      start2 = millis();
    }
  }
  else if (DISTaverage < (1.5 * footSize + 2 * footSize)) {
    static int start3 = millis();
    if ((millis() - start3) < 200) {

      digitalWrite(pancakePin, HIGH);
    }
    else if ((millis() - start3) < 1000) {
      digitalWrite(pancakePin, LOW);
    }
    else {
      start3 = millis();
    }
  }
  else {
    //noTone(speakerPin);
    digitalWrite(pancakePin, LOW);
  }
  Serial.print(yVal);
  Serial.print('\t');
  Serial.println(DISTaverage);
  delay(25);
  //38.1
  //63.1
  //88.9
}

 

Audible Cooking Thermometer

Problem

I always find tracking the internal temperature of the things being cooked tedious . Sometimes I have to stop what I am doing to check on it, sometimes I have to look at it the whole time if the food can easily be overcooked. If I forget to check, there is a risk of overcooking and therefore bad texture and taste.

Solution

A device that actively tracks the internal temperature of the food and reminds the user when needed can solve this problem. The device is composed of a temperature sensor, a transducer speaker, and a screen. The temperature sensor of the device will be stuck into the middle of the meat or broth to measure the rate of rise in temperature.

The components of the device

If the rising rate is too large that might lead to overcooking, the device plays “Mi Re Do” to remind the user to turn down the gas. Text will be displayed on the screen if the user needs further information. In the same fashion, if the rising rate is too small, the device plays “Do Re Mi”. The user can stop the sound by pressing the device. In addition, specific instructions can be set for different foods. For the demo, an reminder to flip the fish for stir-frying salmon comes up when the temperature reaches a specific value. The device will play a melody when the food is cooked when the temperature reaches its ideal value. However, the device will only be successful if the algorithm of the cooking temperature for different foods is well developed.

Proof of Logic

Because I am not sure if the sensor can be used on real meat, and because it will take a longer time, I changed the rate of temperature rise in each cooking stage and did a demonstration with my hand instead. I stimulate the cooking process by holding the temperature sensor and raises its temperature from room temperature (about 23 Celcius) to 32 Celcius.

Overall setup of the prototype
Schematics
//libary
#include <OneWire.h>
#include <DallasTemperature.h>
#include "pitches.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>


//definition
#define ONE_WIRE_BUS 5
#define SPEAKER 7
#define CONFIRM_BUTTON 2

//Attachment
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
LiquidCrystal_I2C screen(0x27, 16, 2);



//Global variable
float Celcius = 0;
float Fahrenheit = 0;
float room_temp = 0;
int start_time = 0;

const bool isInterrupt = true;
bool confirmbuttonState = false;
bool isDone = false;

static const float salmon_flip_over_temp = 28;  //This is the default temperature for flipping salmon
static const float done_temp = 32;  //This is the temperature when the salmon is "cooked".
bool flip = false;

float last_read = 0;
float current_read = 0;
float rise_over_time = 0;


//Varibles for the timer of recording data, record data every 2 seconds
unsigned long clock_data = 0; // variable for timing
const int INTERVAL1 = 2000; // milliseconds between updates

//Functions
void read_temperature() {
  sensors.requestTemperatures();
  Celcius = sensors.getTempCByIndex(0);
  Fahrenheit = sensors.toFahrenheit(Celcius);
  Serial.print(" C  ");
  Serial.print(Celcius);
  Serial.print(" F  ");
  Serial.println(Fahrenheit);
}

void ConfirmButtonPressed()
{
  if (digitalRead(CONFIRM_BUTTON) == LOW) {
   confirmbuttonState = true;
  }
}



void temp_rise(float rise_over_time, float lowerbound, float upperbound) {
  if (rise_over_time > upperbound) {
    screen.clear();
    screen.setCursor(3, 0);
    screen.print("Turn Down");
    while (confirmbuttonState == false) {
      tone(SPEAKER, NOTE_E4, 200);
      delay(350);
      tone(SPEAKER, NOTE_D4, 200);
      delay(350);
      tone(SPEAKER, NOTE_C4, 200);
      delay(1000);

    }

    confirmbuttonState = false;
    screen.clear();
  }

  if (rise_over_time < lowerbound) {
    screen.clear();
    screen.setCursor(4, 0);
    screen.print("Turn Up");
    while (confirmbuttonState == false) {
      tone(SPEAKER, NOTE_C4, 200);
      delay(350);
      tone(SPEAKER, NOTE_D4, 200);
      delay(350);
      tone(SPEAKER, NOTE_E4, 200);
      delay(1000);

    }

    confirmbuttonState = false;
    screen.clear();
  }
}

//The song to play when cooking is finished
void fly_me_to_the_moon() {
  tone(SPEAKER, NOTE_C5);
  delay(500);
  tone(SPEAKER, NOTE_B4);
  delay(500);
  tone(SPEAKER, NOTE_A4);
  delay(500);
  tone(SPEAKER, NOTE_G4);
  delay(250);
  tone(SPEAKER, NOTE_F4);
  delay(1000);
  tone(SPEAKER, NOTE_G4);
  delay(250);
  tone(SPEAKER, NOTE_A4);
  delay(500);
  tone(SPEAKER, NOTE_C5);
  delay(500);
  tone(SPEAKER, NOTE_B4);
  delay(500);
  tone(SPEAKER, NOTE_A4);
  delay(500);
  tone(SPEAKER, NOTE_G4);
  delay(500);
  tone(SPEAKER, NOTE_F4);
  delay(250);
  tone(SPEAKER, NOTE_E4);
  delay(1250);
  if (confirmbuttonState == true){
    return;
  }
  
  noTone(SPEAKER);
  delay(250);
  tone(SPEAKER, NOTE_A4);
  delay(250);
  tone(SPEAKER, NOTE_G4);
  delay(500);
  tone(SPEAKER, NOTE_F4);
  delay(500);
  tone(SPEAKER, NOTE_E4);
  delay(250);
  tone(SPEAKER, NOTE_D4);
  delay(1000);
  tone(SPEAKER, NOTE_E4);
  delay(250);
  tone(SPEAKER, NOTE_F4);
  delay(500);
  tone(SPEAKER, NOTE_A4);
  delay(250);
  tone(SPEAKER, NOTE_F4);
  delay(250);
  tone(SPEAKER, NOTE_GS4);
  delay(750);
  tone(SPEAKER, NOTE_F4);
  delay(500);
  tone(SPEAKER, NOTE_E4);
  delay(500);
  tone(SPEAKER, NOTE_D4);
  delay(250);
  tone(SPEAKER, NOTE_C4);
  delay(1750);


  noTone(SPEAKER);
  delay(1000);
}

//This function is called when the "salmon" option is selected
void stirfry_salmon() {
  //check the rate of temperature rise every 2 seconds
  if (millis() >=  clock_data) {
    sensors.requestTemperatures();
    Celcius = sensors.getTempCByIndex(0);
   

    current_read = Celcius;
    rise_over_time = (current_read - last_read) / 2;

    //Print information onto the lcd screen
    int minute = (millis() - start_time) / 60000;
    int second = (millis() - 60000 * minute) / 1000;

    //Serial.print(minute);
    //Serial.println(second);


    screen.setCursor(0, 0);
    screen.print("Salmon");
    screen.setCursor(0, 1);
    screen.print((String)"Temp:" + current_read + "C");
    screen.setCursor(7, 0);
    screen.print((String)"Time:" + minute + ":" + second);




    //Check whether it is time to flip the fish
    if (current_read >= salmon_flip_over_temp && flip == false) {
      screen.clear();
      screen.setCursor(6, 0);
      screen.print("Flip");
      screen.setCursor(7, 1);
      screen.print("it");
      while (confirmbuttonState == false) {
        tone(SPEAKER, NOTE_C5, 200);
        delay(350);
        tone(SPEAKER, NOTE_B4, 200);
        delay(350);
        tone(SPEAKER, NOTE_A4, 200);
        delay(350);
        tone(SPEAKER, NOTE_G4, 200);
        delay(350);
        tone(SPEAKER, NOTE_A4, 200);
        delay(350);
        tone(SPEAKER, NOTE_B4, 200);
        delay(350);
        tone(SPEAKER, NOTE_C5, 200);
        delay(1000);
      }

      confirmbuttonState = false;
      screen.clear();
      flip = true;
    }

    //Checked if the fish is already cooked
    if (current_read >= done_temp) {
      screen.clear();
      screen.setCursor(5, 0);
      screen.print("Cooked");
      while (confirmbuttonState == false) {
        fly_me_to_the_moon();
      }

      confirmbuttonState = false;
      screen.clear();
      isDone = true;
      return;
    }

    //Every cooking stage has a different "standard" rate of temperature rise
    //0-10s The first stage of cooking
    if (millis() - start_time <= 10000) {
      temp_rise(rise_over_time, 0.12, 0.7);
    }

    //10-16s The second stage of cooking
    if (millis() - start_time > 10000 && millis() - start_time <= 16000 ) {
      temp_rise(rise_over_time, 0.12, 0.19);
    }

    //16-24s The third stage of cooking
    if (millis() - start_time > 16000 && millis() - start_time <= 24000 ) {
      temp_rise(rise_over_time, 0.6, 0.9);
    }

    //>24s The fourth stage of cooking
    if (millis() - start_time > 10000 && millis() - start_time <= 16000 ) {
      temp_rise(rise_over_time, 0, 0.3);
    }



    last_read = current_read;
    clock_data = millis() + INTERVAL1 ;
    //Serial.print(Celcius);
    //Serial.print("     ");
    Serial.print(current_read);
    Serial.print("     ");
    Serial.println(rise_over_time);
  }
}

void setup()
{
  //Initialization
  Serial.begin(9600);
  sensors.begin();
  screen.init();
  screen.backlight();

  //Setting the pinMode
  pinMode(CONFIRM_BUTTON, INPUT_PULLUP);

  //Attach interrupt
  if (isInterrupt) {
    attachInterrupt (digitalPinToInterrupt(CONFIRM_BUTTON), ConfirmButtonPressed, FALLING);
  }


  //Record the room temperature
  sensors.requestTemperatures();
  Celcius = sensors.getTempCByIndex(0);
  room_temp = Celcius;
  last_read = room_temp;

  //test-field
  //tone(SPEAKER, NOTE_A4,200);
  //screen.setCursor(0, 1);
  //screen.print("2nd row text");
  start_time = millis();

 

}

void loop(void)
{
  if (isDone == false) {
  stirfry_salmon();
  }
  
}

 

”欢迎光临“ A motion sensor that welcomes customers

Years ago(when I was a kid) in China, when you walk into most convenience stores and small shops, an accessory by the door will welcome you by saying “welcome”, and it also serves to notify the store owners that they have customers. I remember when I was a kid, I found it really annoying, because it makes the sound not only when you walk in, but also when you walk out. And if you stand by the door, it will keep ‘welcoming’ you. It’s probably because the accessory sensor only detects for distance, and it’s not smart enough to distinguish when not to make the sound.

Nowadays, I don’t hear it as often, and I’m not sure if it’s because the sensing accessory it too annoying, or simply because people associate this sound with ‘low-end’ stores. But I thought if this sensing accessory could become smarter, maybe it’s not a bad idea to bring it back?

So I added 2 features:

    1. only makes the sound when someone walks in, not out;
    2. don’t make the sound if the store owner is already by the door or near the door

I initially wanted to use 2 ultrasonic distance sensors(1 to sense the person walking through the door, and another to sense the store owner being nearby the door), but I only had 1 distance sensor, so I used a button to indicate the event of “the owner is nearby the door”.

Input: Button, Photo-resistor, ultrasonic distance sensors

Output: buzzer speaker

I wasn’t able to get the speaker to play “Welcome” in Chinese, but I tried to mimic the tones of the way “Welcome” sounds with these sensing accessories(shoutout to my musically talented friend Michelle).

I used a photoresistor to detect whether the person is going in or out, but this scheme is far from reliable. A real motion sensor can do a much better job than what I have.

#include<Wire.h>


// PIN INIT
const int SPEAKERPIN = 3;
const int TRIGPIN = 4;
const int ECHOPIN = 5;
const int BUTTONPIN = 7;
const int PHOTOPIN = A0;


// GLOBAL VARS
int distanceThreshold = 4;
int prevPhotoVal = 0;

int get_distance(){
  unsigned long duration;
  int distance;
  digitalWrite(TRIGPIN, HIGH);
  delay(1);
  digitalWrite(TRIGPIN, LOW);
  duration = pulseIn(ECHOPIN, HIGH, 20000);
  distance = duration / 57;  // Divide by round-trip microseconds per cm to get cm
  return distance;
}

void setup() {
  Serial.begin(9600);
  pinMode(SPEAKERPIN, OUTPUT); 
  pinMode(ECHOPIN, INPUT);
  pinMode(TRIGPIN, OUTPUT);
  pinMode(PHOTOPIN, INPUT);
  pinMode(BUTTONPIN, INPUT_PULLUP);
}

void loop() {
  int buttonUp = digitalRead(BUTTONPIN);
  int currPhotoVal = analogRead(PHOTOPIN);
  int distance = get_distance();
  if (distance < distanceThreshold && buttonUp) {
    if(currPhotoVal > prevPhotoVal) {
      tone(SPEAKERPIN , 185, 200);
      delay(200);
      tone(SPEAKERPIN , 146.83, 200);
      delay(200);
      tone(SPEAKERPIN , 185, 200);
      delay(200);
      tone(SPEAKERPIN , 146.83, 400);
      delay(400);
    }
  }
  prevPhotoVal = currPhotoVal;
}

 

I’ll take that as a “Yes”

Have you ever had an experience of not being able to talk for some reason?

For instance, when you took your wisdom teeth out, broke your jaw, someone taking a mold of your face..and so on.

One of the biggest fights that I had with my sister started with when she couldn’t understand my murmurs when I took my wisdom teeth out.

So I decided to make a communicator.

Video demonstration: http://drive.google.com/file/d/1M4TKym7BnJNcziB2OL4j2dgWhBx9dFqx/view?usp=sharing

It comes with two parts: a Joystick and a button. The joystick is for a simple answer, and the button is for inquiries.

The joystick corresponds with one’s positivity in the answer in counterclockwise order, following down (no), right (maybe), up (yes), left (sounds great). The pitch of the sound corresponds as well, from a lower to higher pitch depending on the positivity in the answer.

Down; C
Right; D
Up; E
Left; F

The button shows one’s inquiry in order. The user can change the message as well, but you can assign each note that corresponds with your inquiries.

Default
Pressed once; G
Pressed twice; A
Pressed three times; B
Pressed four times; next octave C

Q&A

What if I am not a perfect pitch?

  • Does the pitch of notes corresponding with your answer help? Does LCD? Please let me know!

Schematics:

//Codes
#include <Wire.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(13, 12, 5, 4, 3, 2);


int speaker = 7;

const int button = 6;
int val;
int counter;
int pressed;


void setup() {
lcd.begin(16,2);

pinMode(speaker, OUTPUT);
pinMode(button, INPUT_PULLUP);

Serial.begin(9600);
lcd.print("Default");

}

void loop() {
val = digitalRead(button);

int sensorReading = analogRead(A2); 
int sensorReading2 = analogRead(A3);

if (sensorReading < 300) {
lcd.setCursor(0,0);
lcd.print("Yes. ");
tone(speaker,659); 
delay(500);
noTone(speaker);
}
if (sensorReading > 800) {
lcd.setCursor(0,0);
lcd.print("No. ");
tone(speaker,(523)); 
delay(500);
noTone(speaker);
}
if (sensorReading2 <300) {
lcd.setCursor(0,0);
lcd.print("Maybe. ");
tone(speaker, 587);
delay(500);
noTone(speaker);
}
if (sensorReading2 > 800) {
lcd.setCursor(0,0);
lcd.print("Sounds great. ");
tone(speaker, 698);
delay(500);
noTone(speaker);
}



if (val == LOW){
pressed=counter ++; 
delay(250);
Serial.println(pressed);

if (pressed == 0){
lcd.setCursor(0,0);
lcd.print("I need water.");
tone(speaker, 784);
delay(500);
noTone(speaker);
}
if (pressed == 1){
lcd.setCursor(0,0);
lcd.print("I want food. ");
tone(speaker, 880);
delay(500);
noTone(speaker);
}
if (pressed == 2){
lcd.setCursor(0,0);
lcd.print("Can you bring");
lcd.setCursor(0,2);
lcd.print("my phone?");
tone(speaker, 988);
delay(500);
noTone(speaker);
}
if (pressed == 3){
lcd.setCursor(0,0);
lcd.print("I need to be ");
lcd.setCursor(0,2);
lcd.print("alone. ");
tone(speaker, 1046);
delay(500);
noTone(speaker);
}

}
}

Hearing the Colors

Context: One of the main contributions of technology is mediation: technology mediates the agency of both disabled and fully enabled humans in the world, rebuilding their relation with the environment.

Problem: For visually impaired people, many applications  have been developed that scan and recognise objects in space for visually impaired people. This way, the user can perceive spatial information without employing touch. The visual information is translated into auditory words, which describe an object or a spatial condition.

This method facilitates the daily life for people with visual impairment. However, it is inadequate when it comes to the perception of art. A  colourful painting cannot be described through a sequence of colour matches that may bear no meaning to people with congenital vision disability.

Solution: ‘Hearing the colours  is a wearable interface that turns the experience of colours and visual art into an audio performance. The wearable prompts the user to move their hand and ‘grasp’ the sounds of the colours in a similar way with that they execute to ‘grasp’ the Braille dots for reading.

The interface plays the role of a sensory substitution device (SSD). After practice, the user learns to stimulate spontaneously the experiential quality of “seeing a color” through a new set of sensoricognitive skills. . This changes the classical definition of sensory modalities and contributes to the emergence of a form of “artificial synaesthesia”.

The interface is designed to transform the static observation of art into an interplay of visuals, sound and body movement. However, hearing the colors through a wearable device should not only be constrained to the spectrum of artwork. It contains the potential to turn the body into a scanning device, that moves and interacts with the space itself, even with other human beings.

Idea
Perceiving the colours in art
Perceiving people through their skin colour

Color as a R:G:B and H:S:B code

 

Computational Logic:

Demonstration Demo:

 

Circuit design:

Code: 

#include <Wire.h>
#include "Adafruit_TCS34725.h"

/* Initialise with specific int time (700ms) and gain(1x) values
  Integration time = how often it reads the colors

  Longer integration times can be used for increased sensitivity at low light levels.
  Valid integration times are: 2.4MS, 24MS, 50MS, 101MS, 154MS, 700MS

  Sets the gain of the ADC to control the sensitivity of the sensor.
  Valid gain settings are: 1x(no gain), 4x, 16x, 60x
*/

Adafruit_TCS34725 myRGB = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);

int R = 0;
int G = 0;
int B = 0;
int hsv [3];

const int speaker = 11;
int pitch; int duration; int delayT;

/*********************************************************************************************/

void setup() {

  Serial.begin(9600);

  if (myRGB.begin()) {
    Serial.println("The colorSensor is found");
  } else {
    Serial.println("No colorSensori is found");
    while (1);
  }

  Serial.println("*****************************************************");
  Serial.println();

}
/*********************************************************************************************/

void loop() {
  getRGBValues();
  rgb2Hsv(R, G, B, hsv);
  colors2Sounds();

  tone(speaker, pitch, duration);
  delay(delayT);

} // loop

/*********************************************************************************************/
void colors2Sounds() {

  if (hsv[0] <= 1) {
    pitch = 100;
    duration = 400;
    delayT = 0;
    Serial.println("red");
  } else if (hsv[0] <= 5) {
    pitch = 300;
    duration = 400;
    delayT = 50;
    Serial.println("purple");
  } else if (hsv[0] <= 13) {
    pitch = 500;
    duration = 400;
    delayT = 100;
    Serial.println("orange");
  } else if (hsv[0] <= 17) {
    pitch = 1000;
    duration = 400;
    delayT = 180;
    Serial.println("yellow");
  } else if (hsv[0] <= 25) {
    pitch = 1800;
    duration = 400;
    delayT = 230;
    Serial.println("green");
  } else if (hsv[0] <= 33) {
    pitch = 2400;
    duration = 400;
    delayT = 300;
    Serial.println("greenish blue");
  } else if (hsv[0] <= 55) {
    pitch = 3000;
    duration = 400;
    delayT = 400;
    Serial.println("blue");

  }
}

void getRGBValues() {

  float _red, _green, _blue;
  myRGB.setInterrupt(false);
  delay(60);
  myRGB.getRGB(&_red, &_green, &_blue);
  myRGB.setInterrupt(true);

  //Print RGB values
  /* Serial.print("Red: "); Serial.print(_red); Serial.print(" *** ");
    Serial.print("Green: "); Serial.print(_green); Serial.print(" *** ");
    Serial.print("Blue: "); Serial.print(_blue); Serial.print(" *** ");
    Serial.println(); */

  R = _red;
  G = _green;
  B = _blue;

} // getRGBValues


void rgb2Hsv(byte r, byte g, byte b, int hsv[]) {
  float rd = (float) r / 255;
  float gd = (float) g / 255;
  float bd = (float) b / 255;
  float max = threeway_max(rd, gd, bd), min = threeway_min(rd, gd, bd);
  float h, s, v = max;

  float d = max - min;
  s = max == 0 ? 0 : d / max;

  if (max == min) {
    h = 0; // achromatic
  } else {
    if (max == rd) {
      h = (gd - bd) / d + (gd < bd ? 6 : 0);
    } else if (max == gd) {
      h = (bd - rd) / d + 2;
    } else if (max == bd) {
      h = (rd - gd) / d + 4;
    }
    h /= 6;
  }

  hsv[0] = int(h * 100);
  hsv[1] = int(s * 100);
  hsv[2] = int(v * 100);

  Serial.println((String)"Hue: " + hsv[0] + " Saturation: " + hsv[1] + " Value: " + hsv[2]);
}

float threeway_max(float r, float g, float b) {
  float res;
  res = r;
  if (g > res) {
    res = g;
  }
  if (b > res) {
    res = b;
  }
  return res;
}

float threeway_min(float r, float g, float b) {
  float res;
  res = r;
  if (g < res) {
    res = g;
  }
  if (b < res) {
    res = b;
  }
  return res;
}

Sound Crit

Generate sounds related to an environment that make the environment easier to use for people who might have issue with collecting data via sight or physical capabilities.  This includes data they might not be able to perceive, say “how many people are in the elevator coming to my floor?” or “when will my bus arrive at my bus stop?”

Universal design and accessibility are good starting places.  I work with a lot of heat when I’m in the studio, welding metal or working with glass.  As we usually say (rather loudly) while going to the first-aid box, “hot metal looks just like cold metal” or “hot glass looks just like cold glass”.  I have temperature probes but they require me using both hands while looking at a screen.  How can I get an audible warning that I’m about to touch something dangerously hot?