qiyuanz@andrew.cmu.edu – Intro to Physical Computing: Student Work Spring 2023 https://courses.ideate.cmu.edu/60-223/s2023/work Intro to Physical Computing: Student Work Thu, 04 May 2023 00:16:47 +0000 en-US hourly 1 https://wordpress.org/?v=6.1.6 Mood Communicator by Team Guava: Final Documentation https://courses.ideate.cmu.edu/60-223/s2023/work/mood-communicator-by-team-guava-final-documentation/ Thu, 04 May 2023 00:05:27 +0000 https://courses.ideate.cmu.edu/60-223/s2023/work/?p=18157 0. Project Introduction

We are Team Guava, and our client is Shaude.

Over the weeks, we talked to and interacted with Shaude to get to know her better and to understand what she does. From those conversations, we were able to find and target aspects of her life that we could help to improve, such as picking fallen things up, helping her paint, and assisting her in communicating, especially in the morning.

Link to previous post: https://courses.ideate.cmu.edu/60-223/s2023/work/interview-with-shaude-team-guava/

1. What We Built

By having two boxes that can communicate with each other at a distance, we can give our client, Shaude, the ability to communicate with someone in her home much easier than a smartphone. In particular, we had one device for the client’s bedside that could send up to six predetermined messages for specific needs and two adjustable gradient indicators for both general mood and health to another device that could be placed anywhere in the home for the ease of the caretaker. We also made it so both devices run based on a wall outlet, removing the need to change batteries in the product.

 

Controller (left) and Display (Right)Button 1: Can you help me get up? Button 2: I can't wait for breakfast! Button 3: Could you get me some water? Button 4: Please be patient with me today. Button 5: I want to get outside today. Button 6: Can I have some time to myself? Two sliders below the buttons that control the display for heath and mood via LEDs.

Controller (left) and Display (Right)

Controller - Custom Slider Cap, Arcade Buttons, Sticker Papers

Controller – Custom Slider Cap, Arcade Buttons, Sticker Papers

Controller - Internal Wiring

Controller – Internal Wiring

Display - LCD

Display – LCD

Display - Internal Wiring

Display – Internal Wiring

By having two boxes that can communicate with each other at a distance, we can give our client, Shaude, the ability to communicate with someone in her home much easier than a smartphone. In particular, we had one device for the client’s bedside that could send up to six predetermined messages for specific needs and two adjustable gradient indicators for both general mood and health to another device that could be placed anywhere in the home for the ease of the caretaker. We also made it so both devices run based on a wall outlet, removing the need to change batteries in the product.

Video of Our Devices Working as Intended.

Narrative sketch of how device works

Narrative sketch of how our product works

2. Prototypes and Processes

Our first prototypes were built in order to answer the following questions: 

  • What inputs and outputs we wanted to use?
    • Such as how should Shaude enter her emotions and how should they be shown
  • What colors and gradients made the most sense for out purpose 
    • Should we use light color or brightness?
  • What scale should the device be at
  • What should be the layout of the device 

We made a lot of prototypes testing the hardware that we would be using, such as the radio, the potentiometers and the Neo pixel bulbs. These were practical prototypes to see how the coding and functionality would look like. We also printed prototypes of the housing so we would be able to better address scale. Some prototypes were simple drawings exploring how different aspects of the outputs might be, such as drawing of different light gradients or LED configurations.

prototype sketches

These sketches show our thought process behind our questions, and some things we wanted to explore in our prototyping.

Neopixel bulb light up for the first time connected to Arduino

Neopixel bulb light up for the first time (emotional)

This was our first version of slider to lights. This simple setup controlled the red blue and green value on the Neopixel. You can see that they all run to the same bulb and effect each other. The position on the slider effects the brightness of each color in the bulb. We were happy with this experiment because it was much like mixing paint, but with light, and it was fun to play with.

Above is second iteration of the potentiometer to lights. We tested mapping specific gradients to the lights. Here you can green to red as well as red to blue. You may notice the weird jump from blue to red in the lights. This was a coding issue we needed to battle and happens because the red value is much stronger than the blue.

LED strip alternative to neopixel attempt

LED strip alternative to neopixel attempt

This idea correlated to a sketch seen above, where the amount of mood or health corelates to a number of bulbs illuminated on the LED strip. This idea was scraped because it seemed a little confusing and added a layer of complexity that was unnecessary. This porotype was never brought to a fully functional level.

Above you can see a video of us testing the connection between two Arduinos using Arduino. The input is the press of a button and the output is a message displaying on an LCD screen.

a set of 3D printed objects. two panels with holes for buttons and sliders and then three button caps

physical prototypes

To test how big we wanted to control panel to be we printed a few panel to show to Shaude for layout and scale. We also wanted to test using button caps to make the buttons differentiated and easier to press. These caps did not end up working because they attached onto the tops of the buttons and were not deep enough to create a snug fit.

We learned the most from our prototypes after discussing the outcomes with Shaude. After showing her the scale of the models we learned that she needed much bigger buttons, and a big display box for her to see what the options on the box were. She also noted that she preferred a flat down view of the box rather than a slanted one. She enjoyed the potentiometers and the feedback of the lights. We talked to her about what colors she connected with different expressions and moods. We were then able to use this information to decide on our final color gradients that would be most descriptive and helpful to her. The range of these colors were red to blue for agitated to calm and green to red for health to ill. We also discussed her favorite colors and such so we could design the box to be most pleasing to her later on. Her favorite colors by the way are purple and pink, and she really likes dogs. 

During our prototyping process we were surprised by how the neopixel colors values are not all equal. The power and brightness of the red really overpowered the blue and we had difficulty mapping the values to get a noticeable gradient from blue to red. If we had more time to prototype we would have liked to explore other visual methods and hardware for showing the gradients and values of colors. We had one drawn idea of utilizing strip LEDs to use both color and value to show mood and health (see above), but it seemed to add a layer of confusion, especially with calm and agitation. We chose to continue with the Neopixel bulbs because they were simple to read and true to our original intent. Overall going further with our design we took the work from our prototypes and simply made them better suited for Shaude.

3. Conclusions and Reflections

Overall, our group thought that our product successfully fulfilled our client’s identified needs. Through interview and iteration, we were able to come up with a device that allowed the communication of both specific desires and more general moods in a concise and effective way. However, the process did involve challenges, not the least of which was working with our client. Working in an environment like CMU, we are often surrounded by people of similar dispositions who know what we can accomplish. This project allowed us to work with someone with a disability who had none of these attributes. In particular, we often found it hard when speaking or working with Shaude to get actionable feedback or find specific problems that were within our skills to address. This unexpected difficulty forced us to change how we interacted with Shaude in our second interview. Instead of open-ended questions where we expected her to give us actionable answers, we provided her with a list of possible options or user interfaces. This narrowed the scope of choices and discussion, allowing her to point out any general issues in all the possibilities. For instance, when we were giving her options on how the buttons were laid out, she expressed that even the most prominent option we had was too small. This informed us of a significant issue we must be aware of. Next time, I would like to schedule periodic meetings with Shaude at the beginning of the project to increase her involvement in our process and interview her caretaker to get a feel for their opinion on the output device.

The final crit was an informative and valuable process. Our team felt that those present gave good feedback on what we did well and what we could have done better as a final project. In particular, the one we felt was most true was regarding the layout of the mood and health potentiometers, “The ‘mood’ light felt backward, and the red/blue color scheme was hard to decipher any middle ground.” This was a comment that a couple of people gave us because the mood and health sliders went opposite directions to increase/decrease, which needed to be clarified, and the spectrum for the mood light (red to blue) was hard to see any interim values. With more time, we would fix this by flipping one of the potentiometers so that both are the same and choosing better colors to the spectrum between. Another comment we got was to improve the “Robustness of the device. Add texture or images to buttons, which is something we would want to do. We were considering making our buttons at one time, which could have allowed us to do this. Making it even easier by allowing buttons to be differentiated by feel or image instead of just clarifying what each does by text. Another useful feedback was about having a message on the receiving device for too long. This could be addressed by “adding some kind of ‘acknowledge’ button to the remote receiver, which would then silence the message and blank out the screen.” This is something that we should have considered and is a problem. Because it teaches the recipient that messages are not current, decreasing the device’s effectiveness. We did have difficulties with the radio, and getting two-way communication instead of one-way would be a challenge that we felt would have taken more time than we had. Finally, someone commented, “Bedside table space can be limited, so a slightly smaller bedside device” would be better. We agree and think that its height might also become an issue. If we could do it again, the solution would be to cut the arcade buttons in half, which would have worked because the buttons’ electrical and physical components could be separated. The buttons took up the majority of the space inside the input box.

To sum up, this device solves a real problem in Shaude’s life. Hopefully, it gets used, and no issues pop up over long periods of use, but we don’t think they will. It was an exciting experience that Team Guava was happy to be a part of.

 

Shaude and team Guava at final Crit

Final project, Shaude, and Team Guava at final Critique

4. Technical Details

Block Diagrams:

 

 

Block Diagram of Input device for mood communicator

Block diagram showing input and output flow for Shaude’s portion of communicator

Output Device Block Diagram

block diagram showing inputs as radio signals and outputs such as lights and LSD screen

Receiver block diagram

 

Electrical Schematics:

 

Electrical Schematic of Input device for Mood communicator

 

wiring diagram for Shaude's receiver.

Receiver Wiring diagram

Code:

/*
 * Mood Communicator, input code, final project 
 * By: Andres Montemayor, Evette Lacomb, Dunn Zhang

 Description: The code below takes in inputs from buttons, and sliding potentiometers
 then, displays a gradient from red to blue and red to green based on the pot values
 it also transmits those values over a NRF24L01 radio to another arduino

 Pin Map:
  POTPIN1     | input    | potentiometer: sets mood gradient
  POTPIN2     | input    | potentiometer: sets health gradient
  BUTTON1     | input    | reads when message 1 button pressed, sets integer for radio to send
  BUTTON2    | input        | reads when message 2 button pressed, sets integer for radio to send
  BUTTON3    | input        | reads when message 3 button pressed, sets integer for radio to send
  BUTTON4    | input        | reads when message 4 button pressed, sets integer for radio to send
  BUTTON5    | input        | reads when message 5 button pressed, sets integer for radio to send
  BUTTON6    | input        | reads when message 6 button pressed, sets integer for radio to send
  moodLed   | output        | outputs rgb value to neopixel to show potentiometer value on spectrum(red->blue)
  healthLed | output       | outputs rgb value to neopixel to show potentiometer value on spectrum(red->green)

NRF24L01 pin map can be seen below 
 * 
 * radio pin    Arduino Uno/Nano pin    Arduino Micro pin
 * VCC          3.3V                    3.3V
 * GND          GND                     GND
 * CE           7                       7
 * CSN          8                       8
 * MOSI         11                      MO
 * MISO         12                      MI
 * SCK          13                      SCK

 * modified from code by: Alton Olson, Vicky Zhou, Seema Kamath, Robert Zacharias, Andres Montemayor, Evette Lacomb
 Credit:
 Used example libraries from relevant libraries for relevant sections
 for radio code, it was provided by Robert Zacharias and then later adjusted by team to better fulfill project
 parameters.
 * 
 */

//Libraries in use in this code
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <PololuLedStrip.h>
// numbers in <> are pin numbers for the leds to display mood and health, reference for what is transmitted
PololuLedStrip<2> moodLed;
PololuLedStrip<4> healthLed;

//LED initialize count. We use a single neopixel so only one, if use a strip would be more
#define LED_COUNT 1
rgb_color moodcolors[1];
rgb_color healthcolors[1];

//define integers for colors map from sliding potentiometer
int red;
int red2;
int blue;
int green;

// Initialize the pins for the buttons, potentiometer, radio, single 
const int BUTTON1 = 3;
const int BUTTON2 = 5;
const int BUTTON3 = 6;
const int BUTTON4 = A2;
const int BUTTON5 = A3;
const int BUTTON6 = A4;

const int POTPIN1 = A0;
const int POTPIN2 = A1;

const int RADIO_CE = 7;
const int RADIO_CSN = 8;

int button = 0;
int POT1 = -1;
int POT2 = -1;
int send[] = {0,0,0};

//initiallize and name radio, address needs to be 6 digit and same on recieve and transmit
RF24 radio(RADIO_CE, RADIO_CSN);
const byte address[6] = "00001";

void setup() {
  // radio startup
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_HIGH);
  radio.stopListening();
  Wire.begin();
  // Set the pins for the potentiometers & buttons
  pinMode(BUTTON1, INPUT);
  pinMode(BUTTON2, INPUT);
  pinMode(BUTTON3, INPUT);
  pinMode(BUTTON4, INPUT);
  pinMode(BUTTON5, INPUT);
  pinMode(BUTTON6, INPUT);

  pinMode(POTPIN1, INPUT);
  pinMode(POTPIN2,INPUT);
}

void loop() {
  // read analog values from sliding pots
  POT1 = map(analogRead(POTPIN1),0,1023,0,255);
  POT2 = map(analogRead(POTPIN2),0,1023,0,255);

  //map sliding pots to colors for leds
  red = map(POT1, 0, 255, 7, 255);
  blue = map(POT1, 0, 255, 10, 0);

  red2 = map(POT2, 0, 255, 0, 255);
  green = map(POT2, 0, 255, 255, 0);

  //display color
  moodcolors[0] = rgb_color(0, red, blue);
  healthcolors[0] = rgb_color(green, red2, 0);

  moodLed.write(moodcolors, 1);
  healthLed.write(healthcolors, 1);
  // check which button is pressed to see what integer should be transmitted over radio
  if (digitalRead(BUTTON1) == LOW) {
    button = 1;
  }
  if (digitalRead(BUTTON2) == LOW) {
    button = 2;
  }
  if (digitalRead(BUTTON3) == LOW) {
    button = 3;
  }
  if (digitalRead(BUTTON4) == LOW) {
    button = 4;
  }
  if (digitalRead(BUTTON5) == LOW) {
    button = 5;
  }
  if (digitalRead(BUTTON6) == LOW) {
    button = 6;
  }
  //redefine arrey before sending based on inputs 
  send[0]=POT1;
  send[1]=POT2;
  send[2]=button;

  // transmit values
  radio.write(send, sizeof(send));
  //delay so time to update led correctly
  delay(50);
}

//PROJECT 3 GUAVAS: OUTPUT CODE
//Dunn Zhang, Andres Montemayor, Evette LaComb
//SHAUDE's mood box RECEIVE code - takes the radio signal from another box and displays the inputs through screen and lights  


//Pinmap:
/*  pin       mode         description      
    4         output       mood Led 
    3         output       health Led           
    SDA       output       LCD screen 
    SCL       output       LCD screen 
    7         CE           radio
    8         CSN          radio
    11        MOSI         radio
    12        MISO         radio
    13        SCK          radio

NRF24L01 pinmap can be seen below 
  radio pin    Arduino Uno/Nano pin    Arduino Micro pin
  VCC          3.3V                    3.3V
  GND          GND                     GND
  CE           7                       7
  CSN          8                       8
  MOSI         11                      MO
  MISO         12                      MI
  SCK          13                      SCK
 
 * modified from code by: Alton Olson, Vicky Zhou, Seema Kamath
 * Robert Zacharias 5-23

*/

//USE THIS CODE FOR RECIEVE
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
/// lights vvv 

#include <PololuLedStrip.h>
PololuLedStrip<4> moodLed;
PololuLedStrip<3> healthLed;

#define LED_COUNT 1
rgb_color moodcolors[1];
rgb_color healthcolors[1];

int red;
int red2;
int blue;
int green;
//lights ^^^

//Initialize the LCD library with the I2C address, number of columns and rows. call it lcd
LiquidCrystal_I2C lcd(0x27, 20, 4);

const int RADIO_CE_PIN = 7;
const int RADIO_CSN_PIN = 8;

int POT1;
int POT2;
int button;
int message = -1;

RF24 radio(RADIO_CE_PIN, RADIO_CSN_PIN);
const byte address[6] = "00001";

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

  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_HIGH);
  radio.startListening();
  lcd.init();
  lcd.backlight();
}

void loop() {
  // get radio input from transmitter
  if (radio.available()) {
    int readVal[3];  
    radio.read(&readVal, sizeof(readVal));

    POT1 = readVal[0];
    POT2 = readVal[1];
    button = readVal[2];
    Serial.println(POT1);
    
    //depending on the button signal show message 
    if (readVal[2] == 5 && message != 5) {
      message = 5;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Can you help me");
      lcd.setCursor(0, 1);
      lcd.print("get up?");
    }
    if (readVal[2] == 2 && message != 2) {
      message = 2;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Can I have some");
      lcd.setCursor(0, 1);
      lcd.print("time to myself?");
    }
    if (readVal[2] == 3 && message != 3) {
      message = 3;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("I want to get");
      lcd.setCursor(0, 1);
      lcd.print("outside today.");
    }
    if (readVal[2] == 6 && message != 6) {
      message = 6;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Could you get");
      lcd.setCursor(0, 1);
      lcd.print("me some water?");
    }
    if (readVal[2] == 4 && message != 4) {
      message = 4;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("I can't wait");
      lcd.setCursor(0, 1);
      lcd.print("for breakfast!");
    }
    if (readVal[2] == 1 && message != 1) {
      message = 1;
      lcd.clear();
      lcd.setCursor(0, 0);
      lcd.print("Please be patient");
      lcd.setCursor(0, 1);
      lcd.print("with me today.");
    }
    //colored LEDs:
    int red = map(POT1, 0, 255, 7, 255);
    int blue = map(POT1, 0, 255, 10, 0);

    int red2 = map(POT2, 0, 255, 0, 255);
    int green = map(POT2, 0, 255, 255, 0);

    moodcolors[0] = rgb_color(0, red, blue);
    healthcolors[0] = rgb_color(green, red2, 0);

    moodLed.write(moodcolors, 1);
    healthLed.write(healthcolors, 1);

    delay(150);

  }
}

 

]]>
Focus Box https://courses.ideate.cmu.edu/60-223/s2023/work/focus-box/ Tue, 14 Mar 2023 22:26:11 +0000 https://courses.ideate.cmu.edu/60-223/s2023/work/?p=17764 Part.0 Overview

An assistive device that helps the user to focus on the task at hand rather than his or her phone by mechanically retracting the phone inside.

 

Technical Demostration: 

Orange Tape Acting as Phone to Trick the IR Sensor

 

Overall Photo:

Overall Dimension (8″x8″x8″)

Internal Wiring & Layout

 

Detailed Photos:

Protoboards Connections: Motor Driver & UI Systems

UI – Front

UI – Back

 

In Use:

Timer Counting Down

 

Part.1 Process Images & Review

Using a Ambient Light Sensor Instead of an IR Sensor

In the very beginning, I decided to use an ambient light sensor as the sensor for detecting the phone on the stand. I also thought about using the same laser range finder I used for the project 1. There were some significant issues with the ambient light sensor, however. It was way too sensitive, and the code had to be tweaked everytime the overhead lighting condition was changed. I also should have considered that there would eventually be a roof covering much of the sensor input, making the ambiance differences between phone on and phone off very difficult to distinguish. Instead, Zach recommended an IR sensor, which was much easier to code and more reliable in its data output. Also, its compact size allowed for more versatility.

Dedicated 9V Power Breadboard (Ignore my disgusting hand)

This decision did not necessarily change the outcome of my project, but it was critical in keeping everything safe and secure. Mixing 5V and 9V on the same breadboard is asking for a disater. Therefore, I opted for a dedicated breadboard and, later, a protoboard to hold all the components that required 9V power. This way, I would always have the opportunity to get everything right.

 

Red Buttons

Before knowing these red buttons existed, I planned to use the tiny four-legged push buttons. That would not have made a massive difference in the wiring. However, I was planning to solder the legs, which would have been annoying. These red buttons are big and eye-catching, much more user-friendly than the legged push buttons.

Part.2 Discussion

 

Overall, I am satisfied with the final result of my assistive device, even though I had to make changes to reduce complexity. However, the project was challenging, and I am content that everything worked during the technical demonstration.

One of the comments I received from the final critique that stood out to me was, “I like how it doesn’t completely lock your phone away— there’s definitely less anxiety associated with it and I think i would be pretty likely to use it!” I thought this was quite interesting. I saw the lack of securing your phone inside as a failure since a focus box should take away your access to your phone over the countdown. However, now reflecting on this quote again, it is intriguing to see others’ perspectives, as it seems to encourage the user to use the device more and make it less intimidating.

Though I was pleased with the final results, as I mentioned before, there were places where I had to cut corners and features to reduce the project’s completion timeline and complexity. First, the box was supposed to function as a toaster, in which the phone would be placed on top of the box, and some mechanical motion would retract the phone inside the box, locking it away until the timer ran out or the release was hit. However, the ratio of extension to overall length could have been better on the linear actuator, which means I would have a massive box if I were to implement a vertical operation. Another idea I had to overcome this issue was to design a DC Motor-driven contraption, maybe pulling on a string or rubber band. However, I had yet to learn how to create a system as such in the time frame given. I also did not do an excellent job designing in Rhino. I have done plenty of detailed, beautiful physical models for my architecture studios; nevertheless, this was my first time creating something involving moving parts and wiring. I ran into issues of pieces not fitting, usually due to inaccuracies in measuring component dimensions and assuming things that may not be true.
Besides learning how the components involved in my project worked, as stated previously, I also learned that working to build a shell for the internal wiring logic in Rhino, or any other CAD software, should be taken seriously and with great care and certainty. I should be more detailed in my component sizing documentation. That way, I would have produced a cut with no adjustment later. I also learned that a linear actuator is hard to use, especially when you want it to push an object parallel to the adjacent walls. I was extremely frustrated when it got stuck on a piece of glue and debris and broke the whole box. Besides that, I decided to use as much soldering as possible in this project to reduce the number of times my hands accidentally bumped into stuff and unplugged wires. I also ensured that everything running on 9V power was separated and placed on their dedicated protoboard to avoid catastrophe.

I was thrilled that the project worked thoroughly during the final critique. However, as stated before, there were places where features had to be cut to save time and ground the project within my capabilities. One of the features includes a trap door, which may be manual or controlled, to close when the phone is retracted and open when the phone is out. I also wanted to implement a way where a notification on your phone may prompt the box to reject it via specific sensors, such as a microphone or photoresistor. If given more time or to approach the project again, I will try my best to implement those forgotten ideas.

 

Part.3 Technical Information

 

Block Diagram:

 

 

Schematics:

 

Code:

// Focus Box: 
// Assistive Device for myself, Project 2, Physical Computing

// Description: 
// The code below will retract the linear actuator if the timer 
// starter button is pressed when a phone is detector via an IR 
// sensor. And when in the retracted state, the code will extend
// the linear actuator if the IR sensor no longer detects a phone, 
// or the release button is hit.


// Credits:
// Used example code for millis() from https://courses.ideate.cmu.edu/60-223/s2023/tutorials/code-bites
// Used and edited example code for countdown timer from https://projecthub.arduino.cc/tylerpeppy/86bb3eef-23ec-4873-ad3b-86c7c277142f

#include <Wire.h>
#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C screen(0x27, 16, 2);

const int actuatorPinA = 12;      // linear actuator pinA, driven by a motor driver
const int actuatorPinB = 13;      // linear actuator pinB, driven by a motor driver
const int minutePin = A1;         // potentiometer input, adjust the timer
const int buttonPinRelease = 4;   // release
const int buttonPinTimer = 2;     // start timer
const int irPin = A0;             // IR Sensor pin, detects the phone

int prevReleaseState;
int currReleaseState;
int prevTimerState;
int currTimerState;
int countdown_time = 0;
int tempPotInput;

unsigned long quarterTimer = 0;

bool timerCounting;

void setup() {
  Serial.begin(115200);
  Wire.begin();

  // Linear Actuation
  pinMode(actuatorPinA, OUTPUT);
  pinMode(actuatorPinB, OUTPUT);
  pinMode(buttonPinRelease, INPUT_PULLUP);
  pinMode(buttonPinTimer, INPUT_PULLUP);
  pinMode(irPin, INPUT);

  currReleaseState = digitalRead(buttonPinRelease);
  currTimerState = digitalRead(buttonPinTimer);

  digitalWrite(actuatorPinA, HIGH);
  digitalWrite(actuatorPinB, HIGH);

  // Potentiometer
  pinMode(minutePin, INPUT);



  screen.init();
  screen.backlight();
  screen.home();
  screen.setCursor(0, 1);

  // Serial.print(hourInput);
}

void loop() {

  int luxThreshold = 100;
  int second = 0;
  int potInputA = map(analogRead(minutePin), 0, 1023, 1, 61);
  long countdown_time;


  // Serial.println(analogRead(irPin));
  int dist;
  dist = analogRead(irPin);
  Serial.println(dist);

  // timer start

  prevTimerState = currTimerState;
  currTimerState = digitalRead(buttonPinTimer);
  if (prevTimerState == HIGH && currTimerState == LOW) {  // when retracted
    if (dist > luxThreshold) {
      timerCounting = true;
      countdown_time = potInputA * 60;
      screen.clear();
    }
  }

  prevReleaseState = currReleaseState;
  currReleaseState = digitalRead(buttonPinRelease);

  if (prevReleaseState == HIGH && currReleaseState == LOW) {
    Serial.println("release");
  }

  if (timerCounting) {
    // when timer is counting down

    long countdown_minute = countdown_time / 60;

    long countdown_sec = countdown_time % 60;

    screen.setCursor(0, 1);

    // count down every second
    if ((millis() - quarterTimer) >= 1000) {
      Serial.println("1 Second Has Passed");
      countdown_time -= 1;
      Serial.println(countdown_time);
      quarterTimer = millis();
    }

    if (countdown_minute < 10) {
      screen.print("0");
    }
    screen.print(countdown_minute);
    screen.print(":");
    if (countdown_sec < 10) {
      screen.print("0");
    }
    screen.print(countdown_sec);
  } else {
    screen.setCursor(0, 1);
    // adjustable timer display (not counting down)
    tempPotInput = map(analogRead(minutePin), 0, 1023, 1, 61);
    long totalSec = tempPotInput * 60;
    long tempMin = totalSec / 60;
    long tempSec = totalSec % 60;
    if (tempMin < 10) {
      screen.print("0");
    }
    screen.print(tempMin);
    screen.print(":");
    if (tempSec < 10) {
      screen.print("0");
    }
    screen.print(tempSec);
  }

  if ((tempPotInput > 0) && (dist < luxThreshold)) {
    screen.setCursor(0, 0);
    screen.print("Stand By............");
  } else {
    screen.setCursor(0, 0);
    screen.print("Phone Detected....");
  }

  if ((countdown_time > 0)) {  
    // if counter is still going
    if (prevReleaseState == HIGH && currReleaseState == LOW) {  
      // release
      digitalWrite(actuatorPinA, LOW);
      digitalWrite(actuatorPinB, HIGH);
      timerCounting = false;
    } else {
      if (dist > luxThreshold) {  
        // retract
        screen.setCursor(0, 0);
        screen.print("Phone Detected....");
        if (timerCounting) {
          digitalWrite(actuatorPinA, HIGH);
          digitalWrite(actuatorPinB, LOW);
        }
      } else {  
        // the phone will be on top of the sensor
        screen.setCursor(0, 0);
        screen.print("Stand By........");
      }
    }
  } else {  
    // time is up
    digitalWrite(actuatorPinA, LOW);
    digitalWrite(actuatorPinB, HIGH);
    timerCounting = false;
  }
  if (dist < luxThreshold) {
    digitalWrite(actuatorPinA, LOW);
    digitalWrite(actuatorPinB, HIGH);
    timerCounting = false;
  }
}

 

]]>
Double Transducer: Linear Position to Transparency https://courses.ideate.cmu.edu/60-223/s2023/work/double-transducer-linear-position-to-transparency/ Mon, 13 Feb 2023 21:06:03 +0000 https://courses.ideate.cmu.edu/60-223/s2023/work/?p=17248 Part 1. Overall Images of the Final Product

Dunn’s double transducer
(Position -> Sound -> Transparency)

Bhairavi’s Double Transducer (position –> frequency –> transparency)

 

Part 2. Details

Figuring out how to use a MOSFET for the 12V power needed for the fan. (Mo)

Accidentally plugging the light valve (purple) into a non-PWM pin. (Bhairavi)

 

Part 3. Demonstration

Dunn’s project in action.

 

Mo’s project in action.

 

Bhairavi’s project in action.

Part 4. Narrative 

A sensor reads the distance of an object in front of it, then converts that data to transparency through the use of a light valve. Our team had some different approaches to the middle step of the device. Mo used wind speed as the middle step, while Dunn and Bhairavi used sound. Mo’s project uses a fan that blows into a wind sensor for the middle step, while Dunn and Bhairavi’s projects use a buzzer and a microphone.

Part 5. Processes

Dunn’s process:

I wanted to ensure the laser was working correctly before proceeding with the other components. The laser range finder required solder before attachment. This component is a much better alternative to the ultrasonic ranger, which has a shorter range and wider scanning cone.

After resolving the laser issue, all other components came together fairly easily and quickly. However, I wanted to ensure everything worked before anchoring the components to the chipboard to avoid potential hardware issues.

 

 

 

 

 

 

 

 

 

 

Almost-final iteration. Most components are secured in their locations.

Mo’s Process:

Starting out by individually testing each component. This picture is the laser distance sensor – I found an example sketch on the Adafruit website which I used to  learn how the VL530X works. (Bhairavi)

Last thing to change: accidentally plugging the light valve (purple) into a non-PWM pin, meaning that the transparency couldn’t be changed easily. (Bhairavi)

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Part 6. Discussion

Overall, this project was an excellent introduction to physical computing: how everything works and comes together. Though our team had different solutions and approaches, they were equally unique and valid. We learned the hard lesson that the product might not work as you intended on the presentation day, and there are always issues to be resolved. It was interesting to see how our teammates approached the project prompt – each of us faced different constraints, leading us to end up with different middle steps for our transducers.

Since there was only one fan present in the classroom, both Dunn and Bhairavi chose to use buzzers generating sound for their middle steps. Dunn chose to control the volume of the buzzer for the middle step, since he found this easier than controlling the frequency. However, Bhairavi had trouble accurately detecting the volume of the buzzer and decided to hone in on the small range of frequencies in which the microphone could detect a linear increase in frequency.

Another difference between our projects was that the sensitivity of the transparency to movement was significantly different. Both Dunn and Bhairavi found it necessary to significantly limit the range in which the laser could detect movement due to range limitations in their middle step, while Mo was able to detect and express a larger range of movement.

 

Part 7. Functional Block Diagram and Schematic

Part 8. Code Submission

/*
 File/Sketch Name: transducer_test

 Version No.: v2.0 Created Feb 14 2023 Bhairavi Chandersekhar
 
 Description:  This code works to run an Arduino Uno powered double transducer. The transducer converts distance to transparency. 
 The double transducer uses a VL53L0X 'Time of Flight' Laser distance
 sensor to input distance (must be between 40 and 220 mm). The distance signal is then converted by the Arduino to a frequency between
 290 and 335 Hz. which is then sent to a passive piezo buzzer. An electret microphone picks up the signal from the passive buzzer and 
 uses the frequency to control the transparency of a light valve. 
 Input, intermediate, and output values are displayed on an LCD screen. 

 Notes: 
 - all frequencies between 290 and 355 Hz are not able to be used. Frequencies from 300-315 Hz are very frequently not picked up
 accurately by the microphone. This is why much of the code is split up using if statements; frequencies in two different nonadjacent
 ranges are generated, and the frequencies picked up are also present in two nonadjacent ranges. Frequencies above, below, or between these
 ranges are disregarded as noise. 
 - Specific ranges in which the microphone is able to detect the frequency accurately depend on the specific choice 
 of buzzer and microphone, as well as the ambient noise in the room. 

 Pin Mappings: 
 5        one lead of the piezo buzzer (other lead to ground)
 10       one lead of the light valve (other lead to ground)
 A0       electret microphone input
 3.3 V    runs to electret microphone and laser distance sensor
 5V       runs to LCD display. 
 SCL/SDA  connects to both the LCD display and to the laser distance sensor
 
 
 FFT code based on AudioFrequencyDetector code written by Clyde A. Lettsome, PhD, PE, MEM
 For more information visit https://clydelettsome.com/blog/2019/12/18/my-weekend-project-audio-frequency-detector-using-an-arduino/

*/

#include "arduinoFFT.h"
#include <Wire.h>
#include <VL53L0X.h>
#include <LiquidCrystal_I2C.h>
 
#define SAMPLES 128             //SAMPLES-pt FFT. Must be a base 2 number. Max 128 for Arduino Uno.
#define SAMPLING_FREQUENCY 3000 //Ts = Based on Nyquist, must be 2 times the highest expected frequency.
#define PIEZO_PIN  5      // Pin connected to the piezo buzzer.
#define LIGHTVALVE 10             // digital pin connected to the light valve 
 
VL53L0X sensor;
LiquidCrystal_I2C screen(0x27, 16, 2);
arduinoFFT FFT = arduinoFFT();
 
unsigned int samplingPeriod;
unsigned long microSeconds;
unsigned long previousMillis;
 
double vReal[SAMPLES]; //create vector of size SAMPLES to hold real values
double vImag[SAMPLES]; //create vector of size SAMPLES to hold imaginary values

int peak; 
int LCD_peak; 
 
void setup() 
{
  // FFT setup
  Serial.begin(115200); //Baud rate for the Serial Monitor
  samplingPeriod = round(1000000*(1.0/SAMPLING_FREQUENCY)); //Period in microseconds 
  
  // TOF distance sensor setup
  delay(100);
  Wire.begin();

  screen.init();
  screen.backlight();
  screen.home();

  sensor.setTimeout(500);
  if (!sensor.init())
  {
    Serial.println("Failed to detect and initialize sensor!");
    while (1) {}
  }
  // Start continuous back-to-back mode (take readings as
  // fast as possible).  To use continuous timed mode
  // instead, provide a desired inter-measurement period in
  // ms (e.g. sensor.startContinuous(100)).
  sensor.startContinuous();

  previousMillis = millis();

  peak = 0; 
  LCD_peak = 0; 
    
}

double fft() 
{
  /*Sample SAMPLES times*/
    for(int i=0; i<SAMPLES; i++)
    {
        microSeconds = micros();    //Returns the number of microseconds since the Arduino board began running the current script. 
     
        vReal[i] = analogRead(0); //Reads the value from analog pin 0 (A0), quantize it and save it as a real term.
        vImag[i] = 0; //Makes imaginary term 0 always

        /*remaining wait time between samples if necessary*/
        while(micros() < (microSeconds + samplingPeriod))
        {
          //do nothing
        }
    }
 
    /*Perform FFT on samples*/
    FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD);
    FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD);
    FFT.ComplexToMagnitude(vReal, vImag, SAMPLES);

    /*Find peak frequency and print peak*/
    double new_peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY);
    long transparency; 
    
    // print detected frequency to LCD screen. 
    if (new_peak < 1000) {
      peak = new_peak; 
      LCD_peak = map(peak, 865, 955, 0, 17); 
      LCD_peak = constrain(LCD_peak, 0, 17);
      transparency = map(peak, 865, 955, 0, 17);
      //transparency = constrain(transparency, 0, 17);
    } else if (new_peak > 1190 && new_peak < 1410) {
      peak = new_peak; 
      LCD_peak = map(peak, 1190, 1410, 17, 99); 
      LCD_peak = constrain(LCD_peak, 17, 99);
      transparency = map(peak, 1190, 1410, 17, 99); 
      //transparency = constrain(transparency, 17, 99);
    }
    /* 
    int LCD_peak = map(peak, 850, 1500, 0, 99);
    LCD_peak = constrain(LCD_peak, 0, 99); */ 
    screen.setCursor(6, 1);
    screen.print(LCD_peak);
    if (transparency < 0) {
      transparency = 0;
    }
    analogWrite(LIGHTVALVE, transparency);

    int LCD_transparency = map(transparency, 0, 120, 0, 99);
    LCD_transparency = constrain(LCD_transparency, 0, 99);
    screen.setCursor(12, 1);
    screen.print(LCD_peak);
    Serial.print("peak frequency: ");
    Serial.println(peak);     //Print out the most dominant frequency.
    Serial.print("transparency: ");
    Serial.println(transparency);
}

void buzz()
{
  // detect distance
  int distance = sensor.readRangeContinuousMillimeters();

  // print to LCD screen
  screen.home();
  screen.print("i:");
  // map distance from 0-100
  long LCD_distance = map(distance, 40, 210, 0, 99);
  LCD_distance = constrain(LCD_distance, 0, 99);
  screen.print(LCD_distance);
  

  //calculate piezo freq. based on distance
  int frequency; 
  if (distance < 85) {
    frequency = map(distance, 40, 85, 290, 295);
    frequency = constrain(frequency, 290, 295);  
  } else {
    frequency = map(distance, 85, 220, 315, 335);
    frequency = constrain(frequency, 315, 335); 
  }
  tone(PIEZO_PIN, frequency);

  //print to LCD screen, column 6 row 0
  screen.setCursor(6, 0);
  screen.print("m:");

  // map frequency from 0 - 99;
  int LCD_frequency; 
  if (frequency <= 295) {
    LCD_frequency = map(frequency, 290, 295, 0, 17);
    LCD_frequency = constrain(LCD_frequency, 0, 17);
  } else {
    LCD_frequency = map(frequency, 315, 335, 17, 99);
    LCD_frequency = constrain(LCD_frequency, 17, 99);
  }
  screen.print(LCD_frequency);
  if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); }
}
void loop() 
{  
  // first generate a sound 
  buzz();
  // then read in the frequency 
  fft(); 

  // refresh the screen every half a second. 
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > 500) {
    screen.clear(); 
    previousMillis = currentMillis;
  }
}

 

]]>
Protected: Double Transducer: Varying Light Valve Transparency https://courses.ideate.cmu.edu/60-223/s2023/work/dunns-double-transducer/ Mon, 13 Feb 2023 02:43:59 +0000 https://courses.ideate.cmu.edu/60-223/s2023/work/?p=17115

This content is password protected. To view it please enter your password below:

]]>