Belay on!

Problem:

In rock climbing, when ascending a natural rock face, rock climbers use a technique called lead climbing. This is different from toprope climbing, where the rope is already tethered to the top of the route. Here, the lead climber brings the rope up the rock surface with them.

(Source)

More details about lead climbing can be found here.

Due to the physical position of the belayer, it is incredibly tiring for them to continuously keep a lookout on the climber. Sometimes, this is even impossible if there are outcrops of rock that occludes the belayer’s line of sight.

There are some tools today such as belay glasses that try to relieve the neck strain of belayers, but it is still a tiring job and it’s incredibly easy to make a mistake, when you take your eyes off of the climber or look down for a break.

In fact, it is so tedious and strenuous that lots of pro climbers get into accidents and falls often while lead climbing. How can we provide visual feedback to help reduce incidence of accidents and injury?

Solution:

Creating a system of visual feedback where there’s an indicator signaling how high or low the tension is in the rope. Compared to regular toprope, there is little physical feedback on the belayer on how taut the lead climber’s rope actually is. By introducing more indicators on the belay device, the belayer will be more aware of the rope tension as this feedback will be visible within their line of sight, and on the belay device.

(Source)

Part 1: Preventing falling

(Source)

One of the greatest causes of accidents is slow or absent braking when the lead climber falls. At all times, except when letting in more rope, the belayer should apply friction to the right side of the belay device to act as an emergency brake. In this visual feedback system, if there is insufficient tension applied, a red light will start blinking. Once it is pulled taut enough to withstand a fall from the lead climber, it will stop blinking.

Part 2: Slack awareness

One of the other most important factors in lead climbing is providing the lead climber with the appropriate amount of slack. If it’s too little, they can’t stretch or move far enough to progress. If it’s too much, they run the risk of a highly injurious fall if they do end up slipping. By introducing a color indicator of the range of rope tension, we enable belayers to better monitor this more closely and make adjustments more quickly. As the tension moves low to high, the range is indicated on the row of lights.

Side view, for better view of colors in visual feedback:

Front view demo of the whole system:

Schematic:

Code:

#define belayLeft   1 //left pot
#define belayRight  0 //right pot

//to store tension on upward and downard tension on belay device
int upwardPull = 0;
int downwardPull = 0;

//LED pins in a row, left
int Blue1 = 3;
int Blue2 = 4;
int Green1 = 5;
int Green2 = 6;
int Yellow1 = 7;
int Yellow2 = 8;

//Blinking LED, right
int R1 = 9;

void setup() {
  Serial.begin(9600);

  pinMode(Blue1, OUTPUT);
  pinMode(Blue2, OUTPUT);
  pinMode(Green1, OUTPUT);
  pinMode(Green2, OUTPUT);
  pinMode(Yellow1, OUTPUT);
  pinMode(Yellow2, OUTPUT);
  pinMode(R1, OUTPUT);

  // put your setup code here, to run once:
  
}

void loop() {
  // read tension on both sides of belay device
  upwardPull = analogRead(belayLeft);
  downwardPull = analogRead(belayRight);

  //show range of tension in upwards belay
  if (upwardPull <= 50){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, LOW);
    digitalWrite(Green1, LOW);
    digitalWrite(Green2, LOW);
    digitalWrite(Yellow1, LOW);
    digitalWrite(Yellow2, LOW);
  }

  else if (upwardPull > 50 && upwardPull <= 100){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, HIGH);
    digitalWrite(Green1, LOW);
    digitalWrite(Green2, LOW);
    digitalWrite(Yellow1, LOW);
    digitalWrite(Yellow2, LOW);
  }

  else if (upwardPull > 100 && upwardPull <= 150){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, HIGH);
    digitalWrite(Green1, HIGH);
    digitalWrite(Green2, LOW);
    digitalWrite(Yellow1, LOW);
    digitalWrite(Yellow2, LOW);
  }

  else if (upwardPull > 150 && upwardPull <= 200){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, HIGH);
    digitalWrite(Green1, HIGH);
    digitalWrite(Green2, HIGH);
    digitalWrite(Yellow1, LOW);
    digitalWrite(Yellow2, LOW);
  }

  else if (upwardPull > 200 && upwardPull <= 220){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, HIGH);
    digitalWrite(Green1, HIGH);
    digitalWrite(Green2, HIGH);
    digitalWrite(Yellow1, HIGH);
    digitalWrite(Yellow2, LOW);
  }

  else if (upwardPull > 220){
    digitalWrite(Blue1, HIGH);
    digitalWrite(Blue2, HIGH);
    digitalWrite(Green1, HIGH);
    digitalWrite(Green2, HIGH);
    digitalWrite(Yellow1, HIGH);
    digitalWrite(Yellow2, HIGH);
  }


   //Red LED blinks if safety is not 'on'
   if (downwardPull < 100){
    digitalWrite(R1, HIGH);
    delay(100);
    digitalWrite(R1, LOW);
    delay(100);
   }else{
    digitalWrite(R1, LOW);
  }

  // debugging
//    Serial.print("   left side of belay device ");
    Serial.println(upwardPull);
//    Serial.print("   right side of belay device");
//    Serial.println(downwardPull);

}

 

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

 

Are you prepared for the next couple hours weather?

Problem

With quarantine, I have not been leaving the house all that much, so I seem to have lost my intuition about temperature and my habit of always checking the weather in the morning. This has led me to be surprised by how hot/cold it gets if I’ve gone on a long walk or gone grocery shopping as well as when it starts raining before I’ve gotten home. I’ve found myself really cold in just a sweatshirt in the evening, hot when I wore thick sweatpants on a day that became unusually warm, and caught in the rain unprepared in the infrequent times I’ve been outside for an hour or two this semester.  This led me to the idea of a system that when I leave the house, would let me know about weather changes in the 2 following hours without bothering me.

Proposed Solution

To solve this problem, I propose a small device that can be placed on the wall near the front door that will detect when you leave the house and give notifications appropriate to the current weather and the changes. The opening of the door is detected with a magnetic reed switch.  Whether you are entering or exiting the house is decided based on if the PIR motion sensor detects motion right before the door opens. If you are entering the house, motion will be detected. Notifications will only be given when you are leaving the house, so when no motion is detected. This device uses an esp32 board (I chose the Adafruit Huzzah32) to get the current and hourly weather from the OpenWeather API over WiFi. The current temperature and weather condition as well as that of the next 2 hours are taken from the fetched information. If it will rain or snow, and it isn’t already raining or snowing, the buzzer will play a specific tone sequence 3 times as the door is opening. I chose a sequence that sounds to me a bit like “oh hooray” when it will snow because I love snow. If it will rain, I chose a more warning sound alert because it’s usually not fun to get caught in the rain. The main reason I chose to not give an alert if it will snow/rain when it already is is because you can clearly see what’s happening and should be prepared for it to keep raining/snowing. The buzzer was chosen rather than a speaker because it was loud enough to catch my attention easily, but unlike the speaker it isn’t loud enough to be annoying. I chose to have the LED strip light up to let you know it will be colder or hotter by 5 or more degrees Fahrenheit as that’s when the temperature change bothers me. Red corresponds to hotter and blue to colder. The LED strip will flash for 2 seconds once the door closes to get your attention and then for another 5 seconds it will stay that color so that you can still see the alert but not get annoyed by it as you are leaving. In the next section, you can see demo videos of the cases for this device.

Proof of Concept

Outside videos showing operation when set up:

Demo while leaving the house showing the snow and colder notifications.

Demo while entering the house, showing how there’s no notifications even though the temperature gets colder enough and it will snow.

Videos taken inside to show the different cases:

Demo showing how there are no notifications when temperature doesn’t change enough and it won’t snow or rain.

Demo showing when it just gets colder.

Demo showing when it just gets hotter.

Demo showing when it just will rain.

Demo showing when it just will snow.

Demo showing when it just will rain and is currently raining.

Changes for real implementation

Currently, my device is easily seen and looks bad especially because I had to use so much duct tape for things to stick. To fix this, I would use command strips instead of duct tape to attach everything to the door and wall. The wires for the magnetic reed switch would be all white to blend more. The main board part would be soldered together and put into a box then place under the decorative wreath.

In the final version, a rechargeable 9V battery would be stepped down to 5V would power the LED strip and PIR motion sensor rather than my uno plugged into my laptop which I used because my 9V battery was drained. Using a usb wall plug, I would power the esp32 board rather than my laptop’s port. The outlet my laptop is plugged into would be used for this.

I would run the LED strip wires across the roof of the porch and put the LED strip where the green circle is. This way, it would be where you face while leaving the house and is in the line of sight for going down the porch stairs.

Schematic:

Code:

Note: You will have to enter in your own WiFi information as well as API key- I don’t want to just broadcast that.

//used this tutorial for getting weather: https://techtutorialsx.com/2018/03/17/esp32-arduino-getting-weather-data-from-api/
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "YOUR WIFI NAME";
const char* password =  "YOUR WIFI PASSWORD";

const String endpoint = "https://api.openweathermap.org/data/2.5/onecall?lat=40.445227&lon=-79.934243&exclude=minutely,daily,alerts&units=imperial&appid=";//CHANGE TO LOCATION YOU WANT DATA FROM
const String key = "YOUR UNIQUE KEY";

const int doorSwitchPin = 14;
int justOpened = 0;
int foundWeather = 0;
//const int LEDpin=12;
#include <NeoPixelBus.h>
const int LEDstripPin = 12;
const int numLEDs = 10;
NeoPixelBus<NeoGrbFeature, Neo800KbpsMethod> strip(numLEDs, LEDstripPin);
long startTime;

int hotter = 0;
int colder = 0;
int currentlyRaining = 0;
int currentlySnowing = 0;
int willRain = 0;
int willSnow = 0;
int rainWarning = 0;
int snowWarning = 0;
int maskWarning = 0;
int haveMask = 0;
String content;
#include <Tone32.h>

#define BUZZER_PIN A0
#define BUZZER_CHANNEL 0


const int PIRpin = 27;
int pirVal;

void pirISR() {
  pirVal = digitalRead(PIRpin);
}

//RFID stuff mainly from this tutorial https://randomnerdtutorials.com/security-access-using-mfrc522-rfid-reader-with-arduino/
//#include <SPI.h>
//#include <MFRC522.h>
//
//#define SS_PIN 23
//#define RST_PIN 15
//MFRC522 mfrc522(SS_PIN, RST_PIN);   // Create MFRC522 instance.

void setup() {

  Serial.begin(115200);
  //  SPI.begin();      // Initiate  SPI bus
  //  mfrc522.PCD_Init();   // Initiate MFRC522
  pinMode(doorSwitchPin, INPUT);
  pinMode(PIRpin, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIRpin), pirISR, CHANGE);
  //pinMode(LEDpin, OUTPUT);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");
  // this resets all the neopixels to an off state
  strip.Begin();
  strip.Show();
}

void loop() {
  if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status
    HTTPClient http;
    if (digitalRead(doorSwitchPin) == 0) {//door opened
      //added measure so lights off when the door is opened, will immediately turn of lights if you open it while they are on
      for (int i = 0; i < numLEDs; i = i + 1) {
        strip.SetPixelColor(i, RgbColor(0, 0, 0));
      }
      strip.Show();
      if (pirVal == 0) { //no motion detected at door near knob outside, so ur opening from inside
        //        if (haveMask == 0) { // Look for new cards
        //          if ( ! mfrc522.PICC_IsNewCardPresent())
        //          {
        //            //return;
        //          }
        //          // Select one of the cards
        //          if ( ! mfrc522.PICC_ReadCardSerial())
        //          {
        //            //return;
        //          }
        //        }
        //        //Show UID on serial monitor
        //        // Serial.print("UID tag :");
        //        content = "";
        //        byte letter;
        //        for (byte i = 0; i < mfrc522.uid.size; i++)
        //        {
        //          //          Serial.print(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " ");
        //          //          Serial.print(mfrc522.uid.uidByte[i], HEX);
        //          content.concat(String(mfrc522.uid.uidByte[i] < 0x10 ? " 0" : " "));
        //          content.concat(String(mfrc522.uid.uidByte[i], HEX));
        //        }
        //        content.toUpperCase();
        //
        //        if (content.substring(1) == "ED E4 86 B9" || content.substring(1) ==  "9D 65 7D B9" ) {//change here the UID of the card/cards that you want to give access
        //          int haveMask = 1;
        //        }
        //        else { //dont have mask
        //          if (maskWarning == 0) {
        //            for (int count = 0; count < 4; count++) {
        //              tone(BUZZER_PIN, NOTE_D4, 500, BUZZER_CHANNEL);
        //  noTone(BUZZER_PIN, BUZZER_CHANNEL);
        //  tone(BUZZER_PIN, NOTE_C4, 500, BUZZER_CHANNEL);
        //  noTone(BUZZER_PIN, BUZZER_CHANNEL);
        //            }
        //            maskWarning = 1; //been warned
        //          }
        //        }
        if (foundWeather == 0) {//havent calculated the weather for this opening yet
          // Serial.println("calculating");
          http.begin(endpoint + key); //Specify the URL
          int httpCode = http.GET();  //Make the request

          if (httpCode > 0) { //Check for the returning code

            String payload = http.getString();
            int first1 = payload.indexOf("temp");//gives index of the t
            int start1 = first1 + 6;//add indexso that I'm at the number
            int end1 = payload.indexOf(',', start1);
            Serial.println(payload);
            //Serial.println(start1);
            float currentTemp = payload.substring(start1, end1).toFloat();//making string into float so that I can do math with it

            int first2 = payload.indexOf("temp", end1);
            int start2 = first2 + 6;
            int end2 = payload.indexOf(',', start2);
            float hrOneTemp = payload.substring(start2, end2).toFloat();

            int first3 = payload.indexOf("temp", end2);
            int start3 = first3 + 6;
            int end3 = payload.indexOf(',', start3);
            float hrTwoTemp = payload.substring(start3, end3).toFloat();

            Serial.print("Current temp: ");
            Serial.print(currentTemp);
            Serial.print("\t");
            Serial.print("Temp in 1 hr: ");
            Serial.print(hrOneTemp);
            Serial.print("\t");
            Serial.print("Temp in 2 hrs: ");
            Serial.println(hrTwoTemp);
            if (((hrOneTemp - currentTemp) > 5) || ((hrTwoTemp - currentTemp) > 5)) { //would've been 5 but not fluctuating much at all recently
              hotter = 1;
            }
            else {
              hotter = 0;
            }
            if (((currentTemp - hrOneTemp) > 5) || ((currentTemp - hrTwoTemp) > 5)) { //would've been 5 but not fluctuating much at all recently
              colder = 1;
            }
            else {
              colder = 0;
            }
            int first4 = payload.indexOf("temp", end3);//just using to know around where hour 3 is
            int checkRain = payload.indexOf("Rain");
            if (checkRain != -1) { //means doesn't rain at all in huge data set
              if (checkRain < first2) {
                currentlyRaining = 1;
                willRain = 0; //dont care if it rains later as can already see it's raining
              }//don't bother finding index of another rain bc if it's already raining don't need to see if it'll rain in next 2 hours
              else if (checkRain < first3) {
                willRain = 1; //will rain in an hr
              }
              else if (checkRain < first4) {
                willRain = 1; //will rain in 2 hours
              }
            }
            else {
              willRain = 0;
            }
            int checkSnow = payload.indexOf("Snow");
            if (checkSnow != -1) {
              if (checkSnow < first2) {
                currentlySnowing = 1;
                willSnow = 0;
              }
              else if (checkSnow < first3) {
                willSnow = 1;
              }
              else if (checkSnow < first4) {
                willSnow = 1;
              }
            }
            else {
              willSnow = 0;
            }
            willRain = 1;
            Serial.print("Currently raining: ");
            Serial.print(currentlyRaining);
            Serial.print("\t");
            Serial.print("Will rain: ");
            Serial.println(willRain);
            Serial.print("Currently snowing: ");
            Serial.print(currentlySnowing);
            Serial.print("\t");
            Serial.print("Will snow: ");
            Serial.println(willSnow);
            if (willRain) {
              if (rainWarning == 0) {
                for (int count = 0; count < 4; count++) {//play sequence 3x while door is being closed/your just stepping outside
                  tone(BUZZER_PIN, NOTE_C4, 100, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                  tone(BUZZER_PIN, NOTE_A4, 200, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                  tone(BUZZER_PIN, NOTE_B4, 200, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                }
                rainWarning = 1;//so warning doesn't just keep playing if door is open
              }
            }
            if (willSnow) {
              if (snowWarning == 0) {
                for (int count = 0; count < 4; count++) {
                  tone(BUZZER_PIN, NOTE_D4, 100, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                  tone(BUZZER_PIN, NOTE_E4, 500, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                  tone(BUZZER_PIN, NOTE_C4, 300, BUZZER_CHANNEL);
                  noTone(BUZZER_PIN, BUZZER_CHANNEL);
                }
                snowWarning = 1;
              }
            }
          }

          else {
            Serial.println("Error on HTTP request");
          }

          http.end(); //Free the resources
          foundWeather = 1;
        }
      }
    }
    //}
    else {//door closed again
      if (foundWeather == 1) {
        startTime = millis();
        //resetting the variables above
        rainWarning = 0;
        snowWarning = 0;
        maskWarning = 0;
        haveMask = 0;
        content = "";
      }
      foundWeather = 0;


      if (hotter) {
        if (millis() - startTime < 2000) { //flash to get attention
          static int blinkStart = millis();
          for (uint16_t i = 0; i < numLEDs; i++) {//this rotates through each LED on the strip so that each one will be red
            byte x = millis() - 20 * i;
            strip.SetPixelColor(i, RgbColor(255 - x, 0, 0));
          }
          strip.Show();
          if (millis() - blinkStart >= 10) {
            for (uint16_t i = 0; i < numLEDs; i++) {
              strip.SetPixelColor(i, RgbColor(0, 0, 0));
            }
            strip.Show();
            blinkStart = millis();
          }
        }
        else if (millis() - startTime < 7000) {//stays on just lights as attention probably already caught and dont want to annoy
          for (uint16_t i = 0; i < numLEDs; i++) {
            byte x = millis() - 20 * i;
            strip.SetPixelColor(i, RgbColor(255 - x, 0, 0));
          }
        }
        else {
          for (int i = 0; i < numLEDs; i = i + 1) {
            strip.SetPixelColor(i, RgbColor(0, 0, 0));
          }
          strip.Show();
        }
      }
      else if (colder) {
        if (millis() - startTime < 2000) { 
          static int blinkStart = millis();
          for (uint16_t i = 0; i < numLEDs; i++) {
            byte x = millis() - 20 * i;
            strip.SetPixelColor(i, RgbColor(0, 0, 255 - x));
          }
          strip.Show();
          if (millis() - blinkStart >= 10) {
            for (uint16_t i = 0; i < numLEDs; i++) {
              strip.SetPixelColor(i, RgbColor(0, 0, 0));
            }
            strip.Show();
            blinkStart = millis();
          }
        }
        else if (millis() - startTime < 7000) {
          for (uint16_t i = 0; i < numLEDs; i++) {
            byte x = millis() - 20 * i;
            strip.SetPixelColor(i, RgbColor(0, 0, 255 - x));
          }
        }
        else {
          for (int i = 0; i < numLEDs; i = i + 1) {
            strip.SetPixelColor(i, RgbColor(0, 0, 0));
          }
          strip.Show();
        }
      }
    }
  }
}

Notes on taking project further and functioning that was decided against

  • The idea of having an RFID scanner so that notifications are only given when you aren’t prepared is really interesting and would add great functionality, but doesn’t work well with this project. The RFID scanner I have took too long to read the card and held up the entire system; it took long enough that you could already make it to the stairs before a notification was given. Additionally, the card/tag had to be touching the scanner which isn’t realistic for someone leaving the house to do. Finally, it can’t read multiple cards right next to each other. The first of these problems could be fixed with better equipment, but I don’t think the other two would get solved. If someone fixed these issues and wanted to make my project, especially more commercial, the add-ons would be that the clothes and items that pertain to certain type of weather (ie sweatshirt, raincoat, boots, gloves, etc) could be scanned on the way out. Multiple tags can be used for the same category and the tags could be small and machine washable. Similar to this, in the age of covid, masks could be checked for and if you don’t have one, be warned with an alarm sound. Moreover, our school cards are RFID cards, so I could have set it to react according to who is leaving the house or even only just for me. To really expand, a To-do list could be linked via the internet and if you leave close to the time of grocery shopping, you could get a notification if you don’t have reusable bags.
  • Instead of specific sound sequences, I tried to use the TTS esp library with a speaker and amplifier circuit. This is loud enough with the amplifier circuit, however, it isn’t very understandable. I wanted it to say, rain, snow, and mask (with the RFID implemented but again it didn’t work fast enough). Even changing the text given to try and make it sound better by spelling more like pronunciation didn’t help much.
  • Something relatively easy to do with IFTTT is to send a text message when certain criteria are met. I could have had a text message to me if it was going to be colder, hotter, rain, or snow. I decided against this because it would only really make sense if who was leaving was detected and free accounts only have 3 applets included so I didn’t want to use another on this especially since for me I probably wouldn’t even look at or notice that notification until I’m pretty far away.

Notes about using the esp32 board

In general, it takes much longer to compile and upload to the board than it did for the uno.

Certain libraries that work with the uno don’t work with this and you need to download different ones in general or the same ones modified to work with esp32s.

  • I needed to use the Tone32 library instead of regular one.
  • The PololuLedStrip library is incompatible and so I instead used NeoPixelBus.
  • Not for this project, but for the other one I’m working on, I needed to use download an esp servo library and still included Servo.h like usual.

Interactive Restaurant Menu — Still in paper form!

Inspired by the LED bookmarks, I thought of how circuits could be integrated into traditionally paper like things. Restaurants menus have been evolving quite a lot, and I experience this culture shock every time I come back to China: they went from paper menu, to ordering from tablets/ipads, to having customers scanning a QR code to order and pay from their phone in the last few years. As much as I appreciate the convenience, I really enjoy the feeling of flipping through a paper menu.

LED bookmark

I understand many pros of having a digital ordering system for the customer end:

    • saves time for servers & the number of servers needed
    • avoid ordering mistakes
    • the order directly goes from customers to the kitchen without going through the servers
    • customers can see how much they will be spending right away

Adapting such system is costly, but the wide adoption indicates that the productivity beats the cost. However, in the US, we don’t really see restaurants that uses digital ordering system for the customers.

Some AR applications are used for restaurant menus, and there is a restaurant in London named Inamo that has interactive table tops. BUT I’m proposing a interactive menu that is still in the traditional paper form but takes advantage of the digital ordering system. 

Say when the customers presses on a dish on the paper menu, the dish he/she want to order lights up. The menu can display how much the customer will be paying. And when the customer finish ordering, he/she hits submit, and the order goes directly to the kitchen. The waiter can then collect the menu away, and the menu will be ready for the next customer to order.

As for components, I think I will need:

    • conductive tape
    • leds (either those flat/sewable leds or some fancier way of lighting things up while maintaining the overall paper like texture)
    • digit display/lcd to display price
    • a “submit” button
    • to select a dish, things that could work: tactile button, switch button, or even faking a button using tape

 

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
}

 

Class notes, 29 October, 2020

Non-instrument sounds used in music

M.I.A: https://www.youtube.com/watch?v=ewRjZoRtu0Y

Kraftwerk:
Tour de France, use of bicycle/human sounds as part of a song:  https://www.youtube.com/watch?v=rTe7U92ecX8
Autobahn, which I talked about but we didn’t listen:  https://www.youtube.com/watch?v=1DO-Ddqbqgs

Art of Noise is another band that used sampling to bring non-instrument noises to music:
Another song using the orchestral hit, Close (To the Edit):  https://www.youtube.com/watch?v=-sFK0-lcjGU

German industrial band Einstürzende Neubauten uses found objects for percussion and background tambre: https://www.youtube.com/watch?v=KrfOahWNT_A

Cultural conflation

M.I.A. has western/asian drifter culture as part of a video shot in Morrocco in support of a movement to let women legally drive cars. https://www.youtube.com/watch?v=3Yuqxl284cg

Environmental sound

why is this machine so quiet?

what is all the computation happening in this machine?
how is this different from a Trader Joe’s microwave-meal-box?

Colorblind simulator

Maria asked a question about how to express color as sound.  One place to start this sort of research is a colorblind simulator:  https://www.color-blindness.com/coblis-color-blindness-simulator

Mini Assignment 9

  1. nut allergy: Co-living with people who just met you, makes it difficult to always remember about your food allergies. If not properly cleaned, some of the ingredients you are allergic to, may have come into contact with surfaces. Sound production when nuts have touched specific areas.
  2. When you are stressed, house should automatically produce calm sounds or light condition, that could help you calm down and force you into short breaks from studying.
  3. Never been locked out by your flatmates. Notify if everybody is home/returned, so that people know when to lock the door.

Mini assignment 9

  • Elevators in my tall apartment building (22 floors) can take a long time to arrive because we’re limited to 1 household per elevator trip. If there are multiple people waiting for elevators during ‘rush hour’ (and yes there is still rush hour during covid times, many people walk their dogs at the same time) it’d be good if a chirping sound was made before I’m about to leave the house.
  • The recycling area in my apartment building is usually overflowing; I wish that a sound would be made if it’s empty so I can immediately bring my recyclables over.
  • It can be hard to stay on top of perishables in the fridge, both stocking what I need (e.g. eggs, bananas, milk etc.) and making sure that I consume food in an orderly manner (First in, First out) so if the fridge could make a sound to remind me if I need to replenish something or if I need to consume something soon.
  • My white whale in cooking is making toast in my oven. Unlike boiling / frying, there is little sensory feedback (smell, sound, sight, etc.) on how hot the burner is and I often end up burning my bread. I wish that the oven would tell me once it was done.
  • I have a humidifier and air purifier – I wish they would let me know when their filters needed changing.
  • When my keys are not in their appropriate storage place, I wish that they would make a sound to remind me to place them back.
  • If I wake up and we might have a few hours of sunshine that day, I wish my home would encourage me to go outside by playing a spritely tune when I get out of bed in the morning.
  • If I haven’t meditated that day, I wish my meditation chair could make a sound to call this to my attention when my roommate isn’t on work calls.

Mini assignment 9

What sounds would you add to your house to make it more accessible?

  • Pretty much every gadgets in my house talk/play sound when something happens (even the cat feeder..or the toilet..) but one thing I wish is my studio room!! As you can tell from my past projects I have many issues with my studio regarding my health! Wouldn’t it be nice for my studio room to have a detector that tells me how toxic the air level is right now..
  • Or I want some sound that tells me how the water temperature is just right when I shower. Like when the water’s temperature reaches the user’s set temperature, it makes a sound.
  • My dad tends to fall asleep while he is boiling something on the stove, and it sometimes overflows. He says that he wishes that the sound could tell him that the stove is overheating.

Mini Assignment 9

One sound that would be really helpful for our house is a certain song playing as a notification if all our garbage/recycling cans aren’t in their spots on our driveway at 5:30 PM on Wednesdays. This would be a great reminder to take them off the curb so we don’t get in trouble with Pittsburgh.

Another helpful sound inspired by Jet’s weather example is a tone that would be played as we are leaving the house if it’s late afternoon/ early evening and the temperature is supposed to drop by 10 or more degrees. This could be a useful reminder to get a(nother) jacket if you aren’t already prepared for the temperature change. This is more important with everyone spending so much time inside.

Finally, a last helpful sound I thought of is if a package is delivered to have the doorbell ring if the delivery person had not done so. It seems that this year it is up in the air whether there is a notification that a package has arrived.