Project 2 – Intro to Physical Computing: Student Work Fall 2020 https://courses.ideate.cmu.edu/60-223/f2020/work Intro to Physical Computing: Student Work Wed, 23 Dec 2020 02:36:10 +0000 en-US hourly 1 https://wordpress.org/?v=5.4.15 Project 2 – Applause Alarm Clock https://courses.ideate.cmu.edu/60-223/f2020/work/project-2-applause-alarm-clock/ Wed, 04 Nov 2020 04:02:10 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11836 Applause Alarm Clock

Using lights, a proximity diffuse, and canned applause, this alarm clock is a stubbornly encouraging way to wake up.

coming in at about 16″ x 6″ x 5.5″, this bad boy has presence and a punch

the top of the box opens for access to the internal electrical components. A gap is left along its hinge, leaving room for wires to power sources and the external motion sensor.

theres something very Ark of the Covenant about servicing this device through its top hatch

Process

I spent a bit of time fitting the piece of acrylic into a wooden “U” shape. In the beginning of this project, I wanted to be able to switch out what the message displayed would be. This fitting process to a long time, and ultimately I had to cut that idea short and commit to figuring out the “APPLAUSE” text the best way I could.

In my first attempt at creating the text, I handdrew the lettering on a piece of fitted tracing paper. However, I wasn’t happy with how the light revealed all of the pen strokes. Knowing that a most onlooker attention would be drawn to the letters, I discarded this draft.

After sleeping on it, I dug around the things I had accumulated during college and was reminded of an old Christmas gift my sister gave me. Pulling letters from a novelty marquee, I couldn’t believe I hadn’t thought of this sooner.

Discussion

I think in my own reflection, I have mixed feelings about how this project turned out. I definitely experienced the warning around budgeting time for nonlinear progress in the project. By the time I thought I would be halfway done, it became evident that I had 80% more to go. Still, I impressed myself that I was able to make a project that was this functional, as I’ve struggled in the past with projects that had less components. Still, my ideal vision for this project would probably require one or two more work sessions to polish the form for a full mount to the ceiling. Additionally, I would want to spend some more time creating acrylic slides.

I do like the rough quality to my current iteration. I had one of my favorite artists, Tom Sachs, in mind as I was working. Sachs’ process is transparent, in that materiality isn’t hidden and pencil marks aren’t erased. A challenge I gave myself was to grab all of the materials I was using from what was left behind by past tenants in my apartment. This limitation yielded interesting final aesthetic, with old layers of paint on my wood collaged back into a new life.

Reading other’s feedback was great. I especially liked the suggestion that “having an internal timer where the applause turns into booing if you don’t get up after a certain amount of time could be funny.” Such a missed initial opportunity! If I revisit this project, I will definitely find a way to map the time to a shift from applause to booing. It’s interesting to see some of my initial reflection surface in others’ suggestions as well. Someone wrote “I loved the end result/aesthetic of the product! Simple yet with a great concept. It would be cool if people could customize sounds + text later on if the idea is built.” I am ecstatic that the simple and honest aesthetic vision came through to others. That was an element I was getting a lot of pushback on from my peers in design. It wasn’t the kind of project intended to fall neatly into functional nor novelty.  The suggestion to customize sounds is also a great blindspot to recognize. I remember when presenting live someone suggested incorporating an LED screen to adjust the wakeup time. I think this would be a great place to scroll through sounds to vary morning to morning. I am curious what alternatives there are to uploading custom sounds via SD card. 

Schematic

Code

/*
 * Applause Alarm Clock
 * Connor McGaffin (cmcgaffi)
 * 
 * Description: The code below controls an alarm clock in the form of an live-show applause sign. 
 * At a designated time, a real time clock module triggers two LED panels to illuminate frosted acrylic with 
 * "APPLAUSE" written across it in black. This is accompanied by a looping canned track of studio
 * audience applause, which can be turned off in tandem with the lights by input on a motion sensor intended 
 * to be installed outside of one's bedroom. 
 * 
 * Pin mapping:
 * 
 * pin   | mode   | description
 * ------|--------|------------
 * 7      input     pir pin  
 * 8      output    led panel
 * 9      output    led panel
 * 10     output    dfplayer tx
 * 11     input     dfplayer rx
 * SCL    output    rtc serial clock
 * SDA    input     rtc serial data
 * 
 * CREDIT: i couldn't have done this without
 * DFRobotDFPlayerMini Library - written by Angelo quiao
 * https://github.com/DFRobot/DFRobotDFPlayerMini
 * DS3231 Library - written by A. Wickert, E. Ayars, J. C. Wippler
 * https://github.com/NorthernWidget/DS3231
 * 
 */

#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <DS3231.h>
#include <Wire.h>

DS3231 rtc(SDA, SCL);
Time t;

int Hor;
int Min;
int Sec;

SoftwareSerial mySoftwareSerial(10, 11); // RX, TX
DFRobotDFPlayerMini myDFPlayer;

const int LEDPIN1 = 9;
const int LEDPIN2 = 8;
const int PIRPIN = 7;
int val = 0;

void setup()
{
  mySoftwareSerial.begin(9600);
  Serial.begin(9600);  
  Serial.println();
  pinMode(LEDPIN1, OUTPUT);
  pinMode(LEDPIN2, OUTPUT);
  pinMode(PIRPIN, INPUT);
  Wire.begin();
  rtc.begin ();
  rtc.setTime(00,00,0); //set time
  if (!myDFPlayer.begin(mySoftwareSerial)) {      // use softwareSerial to communicate with mp3.
    while(true);
  }
  myDFPlayer.volume(20);                          // volume set out of 30
}

void loop()
{
  t = rtc.getTime();
  Hor = t.hour;
  Min = t.min;
  Sec = t.sec;
  val = digitalRead(PIRPIN);                       // read sensor input 
  
  if( Hor == 8 &&  (Min == 30 || Min == 31)){      // if the current time matches the alarm time 
     if (val == LOW) {                             //if sensor input is LOW
        static unsigned long timer = millis();
        if (millis() - timer > 25000) {
          timer = millis();
          myDFPlayer.play(1);                      // Play the first mp3 again every 25 seconds (length of file)   
          }
        digitalWrite(LEDPIN1, HIGH);               // LED is on   
        digitalWrite(LEDPIN2, HIGH);
      } else {                                     // if sensor input is HIGH
        digitalWrite(LEDPIN1, LOW);                // LED turns off
        digitalWrite(LEDPIN2, LOW);                      
        myDFPlayer.stop();                         // stops playing applause
        delay(60000);                              // runs out clock on rest of alarmed minute
    }    
  }
}

// vvv MP3 PLAYER SERIAL STATUS CODE vvv //

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }

}
]]>
Project 2: Thought Keyboard, Buffer and Printer https://courses.ideate.cmu.edu/60-223/f2020/work/project-2-thought-keyboard-buffer-and-printer/ Tue, 03 Nov 2020 15:18:36 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11701 Overview

This project is a handmade mechanical keyboard wired to an Arduino, which is further connected to a receipt printer. The goal of the project was to make a temporary vessel for transient thoughts that I don’t have the time to give proper mind to.

The finished project, for scale/ visual comprehension.

 

View of top panel the the – regrettably – bare keys.

Process Images

While developing this project, there were myriad decisions to make. Of these, a rather subtle choice that I made was to make the base key panels into modular things that can be wired into a system separately. All that they really are in the end are button arrays, and will certainly have utility in later projects. By setting the modules up to be reusable, it was possible later to restart designing without having to redo a lot of work. Another big point where things changed was when I realized that my original design did not work as-is. This was because I was down a large number of diodes. As a result, I needed to rethink the whole system, but this was arguably a good thing since it forced me to simplify my project significantly.

Each of these keyboard panels is designed to simply carry current out to the appropriate wire when a given button is pressed (provided that the red power lines are receiving power). These were crucial to make early, as the buttons used were not breadboard compatible. Each had to be soldered to

In this image, I’ve bundled all of the cables that go together so that management for wiring would be tractable (never mend tolerable). It might not be super clear, but the wires are individually bundled per color with tape, with all of the sub-bundles further bundled into one.

 

This image shows the beginning of wiring of the keyboard submodules to their corresponding selectors on the arduino. After doing some power flow testing, I realized that I had made a fatal flaw in my wiring – I was about 102 diodes short of making the board actually work.

 

This image highlights the moment that I was prepared to take the original board apart and restart with the simpler design.

 

The moment where I bound the lighter-weight key interfaces to a cardboard case to make the shell for the keyboard.

I like this image, mostly because of the deep blue aura around the LED has me thinking a bit more critically about how light reflects in air. This image shows the light indicating that the keyboard is being used turning on as a result of, well, the keyboard being activated.

Discussion

Looking over this project in hindsight, I feel that I learned a  lot of lessons both big and small. Chief among them is that, no matter how long you think something will take to do in the world of complex projects with many small parts like this, your estimate WILL be wrong. I ended up sinking an entire weekend (October 24-26… 3 days I’ll never forget) into solely wiring the system and still couldn’t finish it due to unforeseen technical difficulties. That last bit stings the most, but I can’t say that it wasn’t my fault that this was the outcome – I should have thought more about the wiring before just jumping in and grinding it out. This is more evidence to me that, in order to really excel at a project with a seriously involved technical component, one should plan rigorously, and make sure to iron out all of the fine details before jumping in.

Considering the previous, I’m not totally satisfied with how the project itself turned out, but this is immaterial to me. More important than the product, I’ve gained a newfound appreciation for the process of developing custom electronics, and given that my system did (sort of) work in the end, I’m confident that in a future project or personal endeavor, given I plan effectively ahead of time, the outcome will be something much more exciting. There is still that looming notion of poor planning, and I think this is what allowed for such a languid final product.

All of the written peer critique that I received was rather positive. One states,

I could tell you obviously put in a whole lot of effort! It’s a shame that you ran into so many wiring troubles, but cool idea overall.

It’s certainly reassuring that the idea of the project wasn’t strangled out in the tangle of spaghetti-wiring!

Another reads,

The idea was really cool! I can emphasize [sic] with having many ideas that I don’t know what to do with.”

Being such a scatterbrain myself, it feels good to know that the idea of trying to effectively reign the mind in is something that is appealing to others. As someone who’s lived their life with ADHD and OCD, often times my mind is inherently incapable of regulating its own direction and flow without manual intervention, but often this leads me to lose out on some really interesting streams of consciousness that will, well, never exist again. While I reckon that among the many preexisting methods for maintaining and logging thoughts what I’ve created here is not so novel, it would be nice to explore more novel methods to this end. There is something to be said about making something to solve your own problems as opposed to buying into a solution designed for an abstracted, generalized market.

Going forward, I think I’ll take more of my own time to create. I’ve always enjoyed visual arts and creative program, but the idea that I can essentially fold all of the power of a (tiny) computer into actual, physical projects is mind blowing. I feel a newfound fire in the engine that drives my work, and I want to ensure that it doesn’t burn out before I really carve out new ground. I now have a bunch of wired button arrays to use and a mountain of other electrical components that I feel more comfortable with beyond what I can learn from an ECE textbook. Alas, I can say all I like about what I could do, but this won’t matter until I actually do something.

While I’m not planning to iterate on this design (by the time you read it much of the project has likely been broken down for components), if I were to, there are two direction’s I’d take it. First, I’d dial back to the first circuit idea that I had – first, I’d strictly plan everything out and acquire every last required component to make the design, and do rigorous electrical testing throughout. This way, I wouldn’t be 80% of the way done only to learn that the rest of the non-cosmetic work is impossible to finish. The other, more likely direction I would take this would be to drop the arduino altogether and learn how to interface with a USB, as in a keyboard. This way, I could make a genuine physical keyboard out of the modules that I have. This would in all honesty probably be similar process-wise to the prior, but the end result, if constructed well enough, would be something that I’d be able to use in a variety of other situations.

Technical Portion

/* Arduino Receipt Printer and Keyboard Driver
 * by Evan Tipping
 * 
 * The following code is used to drive an otherwise entirely mechanical keyboard,
 * store the input and print it out via a receipt printer.
 * 
 * NOTE: This code requires and arduino Mega to work
 * 
 * PINOUT:
 * A0 : Pin linked to print button
 * A1 : Pin linked to starting and stopping keyboard
 * A3 : Pin linked to space button
 * 
 * 6 : TX Digital serial transmission to receipt printer
 * 5 : RX Digital serial reception from receipt printer
 * 
 * start_pin to start_pin + 36 : Corresponds to a key in the keyboard
 * 
 * Credit to https://github.com/pjreddie/darknet/blob/master/LICENSE.v1 for the idea of 
 * writing a useless liscense :D
 * 
 * Liscense Information:
 * lol what's the point of liscensing code that's not being used in security-critical
 * applications? our modern legal system already failed and mostly serves to protect
 * those in a position of power and even if this code had a different liscense it's
 * not like I could afford a lawyer to defend myself. basically go nuts!
 */

#include <EEPROM.h>
#include "Adafruit_Thermal.h"
#include "SoftwareSerial.h"

const int MEM_LIM = 4096; // Length of EEPROM, board dependant
int mem_start;
int start_pin = 18;

bool typing = false;

const int PIN_PRINT = A0;
const int PIN_WRITE = A1;
const int PIN_SPACE = A3;
int TX_PIN = 6; // Arduino transmit  YELLOW WIRE  labeled RX on printer
int RX_PIN = 5; // Arduino receive   GREEN WIRE   labeled TX on printer

// Needed to operate keyboard
const char key_array[36] = {'0', '1', '2', '3', '4', '5', 
                            '6', '7', '8', '9', 'a', 'b', 
                            'c', 'd', 'e', 'f', 'g', 'h',
                            'i', 'j', 'k', 'l', 'm', 'n',
                            'o', 'p', 'q', 'r', 's', 't',
                            'u', 'v', 'w', 'x', 'y', 'z'};



SoftwareSerial mySerial(RX_PIN, TX_PIN); // Declare SoftwareSerial obj first
Adafruit_Thermal printer(&mySerial);     // Pass addr to printer constructor

// Establish the top 36 inputs in the MEGA to be keys
void set_key_pins() {
  for (int i = start_pin; i < start_pin + 36; i++) {
    pinMode(i, INPUT_PULLUP); // Use for button
  }
}

char get_char_pressed() {
  for (int i = start_pin; i < start_pin + 36 - 10; i++) {
    if (!digitalRead(i)) { // Extra check accounting for.. hardware failure..
      return key_array[i]; // Otherwise use regular key indexing
    }
  }
  if (false){//digitalRead(PIN_SPACE)) {
    return ' '; // If the space key is pressed, return a space character
  }
  return '\0';
}

void print_msg(char* msg_buf) {
  printer.boldOn();
  printer.println(msg_buf);
  printer.boldOff();
}

void print_mem() {
  char str_msg[MEM_LIM];
  for (int i = 0; i < mem_start; i++) {
    int j = 0; // Index in message
    char chr_msg;
    while ((chr_msg = EEPROM.read(i)) != '\0') { // While not at end of string
      str_msg[j] = chr_msg;
      i++;
      j++;
    }
    str_msg[j+1] = '\0';
    Serial.println(str_msg);
    print_msg(str_msg);
  }
}

int find_mem_start() {
  int eeprom_end = 0;
  while (EEPROM.read(eeprom_end) != '\0' && eeprom_end < MEM_LIM) {
    Serial.println(eeprom_end);
    eeprom_end++;
  }
  if (eeprom_end != 0) {
    eeprom_end++; // Skip over the null terminator if we aren't at start of memory
  }
  return eeprom_end;
}


bool mem_full() {
  return mem_start >= MEM_LIM - 1; // This is to ensure that there is a '\0' at end of eeprom 
}

void write_to_mem(char key_pressed) {
    EEPROM.write(mem_start, key_pressed);
    mem_start++;
    EEPROM.write(mem_start, '\0');
}


void clear_eeprom() {
  for (int i = 0; i < mem_start; i++) {
    EEPROM.write(i, 0);
  }
}

/*
 * SETUP SYSTEM
 */
void setup() {
  set_key_pins();
  mem_start = find_mem_start();

  pinMode(PIN_PRINT, INPUT_PULLUP);
  pinMode(PIN_WRITE, INPUT_PULLUP);
  pinMode(PIN_SPACE, INPUT_PULLUP);

  // Find end of EEPROM string
  Serial.begin(9600);

  mySerial.begin(19200);  // Initialize SoftwareSerial
  printer.begin();        // Init printer (same regardless of serial type)
  printer.justify('C');
}

/*
 * LOOP TO DRIVE THE BOARD
 */
void loop() {
  digitalWrite(A2, LOW);
  if (typing) {
    int old_start = mem_start;
    char key_pressed = get_char_pressed();
    if (key_pressed != '\0') {
      char dbg_buf[2];
      dbg_buf[1] = '\0';
      dbg_buf[0] = key_pressed;
      digitalWrite(A2, HIGH);
      write_to_mem(key_pressed);
    }
    if (!digitalRead(PIN_WRITE) || mem_full()) { 
      typing = false; // Cancel typing early as there's no room left in memory or the user pressed the keyboard controller
      if (!mem_full() && !(old_start == mem_start)) mem_start++; // Skip null terminator from prior string
    }
  } else {
    if (!digitalRead(PIN_WRITE)) {
      typing = true;
    }
    else if (!digitalRead(PIN_PRINT)) {
        digitalWrite(A2, HIGH);
        print_mem();
        clear_eeprom();
      }
    }
  delay(300);
}

Electrical schematic for this project.

]]>
Simple Management Rotary Tool (SMRT) https://courses.ideate.cmu.edu/60-223/f2020/work/simple-management-rotary-tool-smrt/ Tue, 03 Nov 2020 14:02:18 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11819 The Simple Management Rotary Tool (SMRT) is a compact way to keep track of all your daily tasks for the day. Powered by an Arduino Uno, this device only has 3 other components to it: a rotary encoder, a 20×4 LCD I2C, and a single button. The making of this was not extremely challenging, but more difficult than I had originally planned.

The first step I took was putting my initial thoughts into electronics. I had wired a standard 16×2 LCD with a couple buttons, that I would eventually turn into one button and a rotary encoder.

This worked out great. It was simple, and it did exactly what I wanted. The issue I had was this was all hard coded. I was manually counting out the number of letters in order to fit into the screen. My thought to this was to change the code, but this is where things got a little dicey. Trying to cut off strings at certain points and such was challenging. I tried going through and using character operations and different string operations, but no luck. I knew what I wanted the function to do, but I didn’t know of a command to do it. I was essentially trying to reinvent the wheel.

Before picture with all of the complex wiring.

This is the after picture with a clean slate of wiring.

The next iteration was much cleaner. I switched from the standard 16×2 LCD to using the 20×4 LCD I2C that came with a handy backpack to simplify the wiring. Then I installed the rotary encoder and a button with a pull up resistor and that was everything to it. The wiring went from cramped to clean in mere seconds.

 

Important point, this all took place in the first week of development. This is where I got confident. This is also the point in which I tried to simplify the design, but in doing so, made it all the more complicated. My plan was going to be to make a “custom PCB” that would fit all of my needs. I really like PCBs because they are compact and you do not have to worry about faulty wiring within the breadboards (I had experienced this issue with some buttons before the change). This was done with a perfboard that I had soldered some wires to.

This is the front side of the perfboard.

This is the backside of the perfboard. There are a couple wires that were soldered onto the pins after realizing they were not soldered on.

After all of this work, the code finally was updated, and everything was going well. This is of course until I remembered that I had to laser cut the box and it was 10pm (TechSpark closes at 11pm).
This problem was made much nicer because I realized that the CAD files I had made with Inventor were not loading properly the .dwg files that I would use to laser cut the box parts. I had to set out to redesign and remake the entire box from scratch, which took a while, but ended up with a nice looking design!

This is the Solidworks version of the final assembly that would be laser cut.

 

Again, there were more issues with the sizings of everything, and when it was all said and done, the final product looked like this:

This is the front view of the final product for the project 2.

 

 

Discussion:

Quote: “Cool idea! I think the simplicity of a knob and a button makes the system really simple to use, plus it has a sort of arcade cabinet aesthetic that I can’t help but love.”

Response: I agree! The simplicity is what makes this enjoyable from my perspective. The arcade cabinet was also by design! Just to make things fun for the user. There is a scenario in which this has a small game tied to finishing each task and there’s a fun LED display to go along with it!

 

Quote: “I can see that the digital solution might be an improvement on paper both by narrowing your focus and by providing a physical affordance you might come to associate solely with productivity. You might consider how to improve the rewards you receive if the gamification was also important.” 

Response: One thing I would love to do with it would be to design a custom game with LCD I2C using custom characters and such, however that was outside the time that I wanted to spend on the physical completion of this project.

 

Self Critique:

Overall, I am not pleased with the final outcome. The coding took a lot longer than I thought it would, simply because I do not have a great understanding for the language yet. It took a long time to just understand how the different variables were going to interact and finding a means that loops properly with the LCD. The actual construction of everything took 30 minutes, but I wish I would have spent that time maybe three to four days before the due date so that I could properly redesign and plan for what errors might have occurred. If you looked at the box from the outside, the wires were pretty well hidden, and there was some soldering – unnecessary because I was unable to work with the Arduino Promicro (Leonardo) – that made the project look like a lot less work went into it than actually did. I did have fun learning and working on this, and it is something that I think I want to continue to work on and finish throughout my free time. 

 

What I Learned:

The biggest thing I learned was to not underestimate a project. I definitely went into this knowing what I wanted the device to do, but not quite realizing how difficult the coding was going to be. Specifically the parts that were more confusing for me were the various string operations and working with arrays. These are things that I have used extensively in MATLAB, but how they work varies from language to language. My advice to the past Carl would likely be to find someone who can explain it all to me sooner. I went to a buddy of mine for help because he is seen as the coding master in my friend group and he was able to walk me through the steps and we figured out something together.

 

Next Steps:

The next ideal steps in this project would be to redesign the box that it was put into and add LEDs/ a fun game to the code. Really start to dive further into this idea that it looks like an arcade cabinet. Maybe then I could design a quick bit for the outside of the wooden box and make it look nice. This way it would be pleasing to look at, compact in design, and functions like a game piece to hopefully be more efficient when working.

 

Technical Information:

Schematic–

This is the schemativ for the design.

 

Code–

/*  Project 2
 *   Carl Young (cryoung)
 *   Time: 12 hours
 *  
 *   Collaborations:
 *   Ryan Bates for debugging
 *   Aidan Smith for debugging and ideation with
 *    regards to the String functions.
 *     
 *   Challenges:
 *   Biggest thing was the string displays and 
 *    getting the right length of strings to display.
 *  
 *   Next Time:
 *   Do more of this upfront. 80% of it was done, but
 *    that definitely was not enough. I should have
 *    just finished it.
 *  
 *   Pin Mapping:
 *  
 *   pin    / mode    / description
 *   -------/---------/------------
 *   13       input     completion button
 *   10       output    LED blue
 *   9        output    LED green
 *   8        output    LED red
 *   4        input     rotary encoder SW
 *   3        input     rotary encoder DT
 *   2        input     rotary encoder CLK
 *   A4       input     LCD I2C SDA
 *   A5       input     LCD I2C SCL
 */

// -----===== Varibales =====-----
// Component Pins
#define inputCLK 2
#define inputDT 3
#define inputSW 4
#define redLED 8        // not used
#define greenLED 9      // not used
#define blueLED 10      // not used
#define completeSW 13

// -----===== Libraries =====-----
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <Encoder.h>

LiquidCrystal_I2C lcd(0x27,20,4);
Encoder rencoder(inputCLK,inputDT);

// Task Variables
unsigned int taskNum = 1;
unsigned int taskTotal = 3;
int taskTotalOG = taskTotal;
String taskDisplay = ((String)taskTotal);
String taskOne = "Complete all homework.";
String taskTwo = "Shower before going to bed.";
String taskThree = "Play Overwatch.";
String taskFinish = "ALL DONE!";
String taskList[] = {taskOne,taskTwo,taskThree,taskFinish};
String splitString[2];
String space = "                                       ";

// Completing Tasks
int completeButtonState = 0;
int lastCompleteState = 1;
bool completedTasks[] = {0,0,0};

// Encoder Variables
int currentStateCLK;
int previousStateCLK;
long positionEncoder = 0;
bool lock = false;
String encdir = "";
int lockButtonState = 0;
int lastLockState = 1;
unsigned int lockCount = 0;

// -----===== SetUp =====-----
void setup(){
  // Initialize LCD
  lcd.init();
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);

  // Task Printing
  overallDisplay();
  lcd.setCursor(0,1);
  lcd.print("--------------------");

  // Initialize Pins
  pinMode(inputCLK,INPUT);
  pinMode(inputDT,INPUT);
  pinMode(inputSW,INPUT_PULLUP);
  pinMode(completeSW,INPUT_PULLUP);
  pinMode(redLED,OUTPUT);
  pinMode(greenLED,OUTPUT);
  pinMode(blueLED,OUTPUT);
  Serial.begin(9600);
  previousStateCLK = digitalRead(inputCLK);
}

// -----===== Loop =====-----
void loop(){
  if(taskTotal != taskTotalOG){
    overallDisplay();
    taskTotalOG = taskTotal;
  }
  displayCurrentTask(taskNum);
  int lockSwitch = digitalRead(inputSW);
  int completeSwitch = digitalRead(completeSW);
  currentStateCLK = digitalRead(inputCLK);
  lockDetection();
  Serial.println(lock);
  while(lock == true){
    digitalWrite(redLED,HIGH);
    digitalWrite(greenLED,LOW);
    digitalWrite(blueLED,LOW);
    lockDetection();
    checkComplete();
  }
  if(completedTasks[taskNum-1] == true){
    taskNum++;
  }
  encoderMovement();
  
  while(completedTasks[0] == 1 && completedTasks[1] == 1 && completedTasks[2] == 1){
    displayCurrentTask(4);
    celebrationLoop();
  }
  
  delay(10);
}

// -----===== Functions =====-----
// Wraps text if too long
void textWrap(String temp){
  String supportingText = "-";
  if(temp.length() < 38){
    if(temp.length() < 18){
      supportingText = " ";
    } else {
      supportingText = "-";
    }
    int diff = 36-temp.length();
    temp = temp + space.substring(0,diff);
  }
  if(temp.length() > 17){
    splitString[0] = temp.substring(0,17)+supportingText;
    splitString[1] = temp.substring(17);
  } else {
    splitString[0] = temp.substring(0);
    splitString[1] = "";
  }
}

// Displays the task associated with taskNum
void displayCurrentTask(unsigned int number){
  textWrap(taskList[taskNum-1]);
  lcd.setCursor(0,2);  
  lcd.print((String)taskNum+":"+splitString[0]);
  lcd.setCursor(0,3);
  lcd.print(splitString[1]);
}

// Encoder position code - GOOD
void encoderMovement(){
  long newPos = rencoder.read()/4;
  if(newPos != positionEncoder && newPos > positionEncoder){
    positionEncoder = newPos;
    taskNum--;
    if(taskNum < 1){
      taskNum = taskTotal;
    }
  }
  if(newPos != positionEncoder && newPos < positionEncoder){
    positionEncoder = newPos;
    taskNum++;
    if(taskNum > taskTotal){
      taskNum = 1;
    }
  }
}

// Adjusts the lock state and checks status of lock via lockCount
void lockDetection(){
  lockButtonState = digitalRead(inputSW);
  if(lockButtonState != lastLockState){
    if(lockButtonState == 0 && lock == false){
      lockCount++;
    }
    delay(50);
    lastLockState = lockButtonState;
    if(lockCount%2 != 0){
      lock = true;
    } else {
      lock = false;
    }
  }
}

// Simple button change for complete that also changes the state of the
//  task complete list and the lock
void checkComplete(){
  completeButtonState = digitalRead(completeSW);
  if(completeButtonState != lastCompleteState){
    if(completeButtonState == 0){
      // if button is pushed
      if(lock == true){
        lock == false;
        lockCount++;
      }
      completedTasks[taskNum-1] = true;
      taskTotal--;
      //Serial.println((String)"taskNum: "+taskNum);
      //Serial.println((String)"taskTotal: "+taskTotal);
      //Serial.println((String)"completedTask?: "+completedTasks[taskNum-1]);
    }
    delay(50);
    lastCompleteState = completeButtonState;\
    digitalWrite(blueLED,HIGH);
    delay(250);
    digitalWrite(blueLED,LOW);
  }
}

void overallDisplay(){
  if(taskTotal < 10 && taskTotal >= 0){
    taskDisplay = ((String)"00"+taskTotal);
  } else if(taskTotal > 9 && taskTotal < 100){
    taskDisplay = ((String)"0"+taskTotal);
  }
  lcd.setCursor(0,0);
  lcd.print("Tasks remaining: " + taskDisplay);
}

void celebrationLoop(){
  digitalWrite(blueLED,HIGH);
  digitalWrite(greenLED,LOW);
  digitalWrite(redLED,LOW);
  delay(250);
  digitalWrite(blueLED,LOW);
  digitalWrite(greenLED,HIGH);
  delay(250);
  digitalWrite(greenLED,LOW);
  digitalWrite(redLED,HIGH);
  delay(250);
  digitalWrite(redLED,LOW);
}

 

]]>
Alarm Clock with color puzzles https://courses.ideate.cmu.edu/60-223/f2020/work/alarm-clock-with-color-puzzles/ Tue, 03 Nov 2020 08:55:43 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11722 Overview

This project was designed to make an alarm clock that stops the alarm by matching a random color puzzle.

Final Project Product

Wires and other electrical parts inside the box

Powerline for the alarm clock

*For clear demonstration, I used a flat-plain type alarm clock video instead of a shoebox type.

Process images and review

Decision 1: Decide to test all components and check whether my idea will work.

During the prototype check day, I had a lot of problems with my gadgets. Therefore, I decided to test each gadget I brainstormed to see how it works and change if it does not work correctly.

Check 1: Turning off the alarm by changing the color of the led.

Here, there were two problems in total.

The first problem came up LCD becoming dull by having too many signals in a short amount of time. I solved this issue by adding a delay command on the Arduino.

The second problem came up with the neo-pixel strip. I tried to use the neo-pixel strip for this project but there were connection issues with the wire. Therefore, I decided to use a simpler RGB LED. (Unfortunately no photo)

Check 2: Learn how to use the other two new components

Fortunately, there were no big issues with testing these new modules.

Testing how the real-time clock module works

Adding Piezo Speaker to Arduino and tested with the Real-Time Clock module.

Adding all components into one circuit

Decision 2: For better design, I looked for a box where I can put components.

Decided to use a shoebox instead of just planting a bunch of circuits on top of the board

By this point, I thought the alarm clock will be a good design-wise but…

Final Product

the box was too big for a small alarm clock. D:

Discussion

I got the question, “[Is] there a function for accessibility for those who are color blind.” I never thought of this question before I build this device. For this project, there is no function that is accessible for color blinds. However, I can allow users to select a color pool when they set up the alarm. For example, if someone is green color blind, I build a push-button function that can exclude the green color type answer from the puzzle.  The second feedback I got was “you’re using a finite number of predefined colors, is there any reason to use a potentiometer as opposed to toggle switches?” In this case, yes. We can use the switch button to select those colors. However, I used a potentiometer because it gives more flexibility in the color pool. For instance, if I use a potentiometer I can use Violet(R:128 G:0 B:255) and Rose(R:255 G:0 B:128) for the color problem.

Overall, I was happy with my project function-wise. My project worked on how I intended. There were little mechanical wiring issues with LCDs but I was able to fix it after trying out several times. However, I was not satisfied with design-wise. In the beginning, I was thought using a shoebox would give a good and organized design aesthetic outfit because I saw other projects made with a shoebox. However, my LCD screen was too small compared to the size of the box creating an ugly shape.

During this project, I learned that sending too many signals in a short amount of time can create an error in Arduino. For example, as I mentioned in the process check 1 section, I had a problem with LCD being dull when I renewed the LCD screen every 1 millisecond. It did not create a problem when I used LCD only, but it generated dull letters when I turned my LCDs. I was able to solve this problem by adding a delay command on Arduino.

If I have a second chance to rebuild this project, I will add several new functions to my alarm clock. First, I want to add a push-button function so that I can modify the time without connecting the computer. Currently, I am resetting my time based on the computer and codes. So, if I need to change alarm time or clock time, I need to turn on the computer and re-upload code when I need to change those settings. Also, I want to customize the size of the box to improve aesthetic value.

 

Technical information

Schematic:

Code:

/*
* Alarm Clock with color puzzles
* Daniel Moon (seonghym)
*
*
* Description: This code takes the time from the computer and computes the time
* on LCD screen by using the Real Time Clock Module. Then, if it reaches a certain time,
* the speaker starts to ring. To turn off the speaker, we need to match the random color
* specified on the LCD screen with LED attached to the circuit by turning three potentiometers.
*
*Credit: 
*   -Real Time Clock Module
*   https://forum.arduino.cc/index.php?topic=128928.0
*   
*   -Sample Speaker Code in Arduino website
*   https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody
*
* Pin mapping:
*
* pin   | mode   | description
* ------|--------|------------
  8      output   Speaker
  7      output   LCD pin(B)
  6      output   LCD pin(G)
  5      output   LCD pin(R)
  A2     input    Potentiometer for Red Color
  A3     input    Potentiometer for Green Color
  A4     input    Potentiometer for Blue Color
  3      ouput    LCD rs
  4      output   LCD enable
  10     output   LCD d4
  11     output   LCD d5
  12     output   LCD d6
  13     output   LCD d7
*/

#include <LiquidCrystal.h>
#include <RTClib.h>
#include <Wire.h>
RTC_DS1307 RTC;

//LCD set
LiquidCrystal lcd(3,4,10,11,12,13);//LCD

//Sets pin for LED change
#define redPotPin A2
#define bluePotPin A3
#define greenPotPin A4

//For timer counts
unsigned long timeVal=0;

//Sets alarm time
int alarmHour = 22;
int alarmminute = 47;

//Sets puzzle value
//Total 7 different color types.
String colour[] = {"white","blue","green","red","yellow","purple","cyan"};
int randVal = 0;

//Sets pin numbers
int speakerPin=8;
int redLedPin = 5;
int greenLedPin = 6;
int blueLedPin = 7;

//Sets Color of LED
int color_value[3] = {0,0,0};
int target_color_value[3] = {1,1,1};

//Check whether day passed
bool timePassed = true;
//Check whether alarm clock is ringing
boolwakeVal = false;

void setup() {
randomSeed(analogRead(0));
Serial.begin(9600);  

//Adjust Real Time Clock with PC
Wire.begin();
RTC.begin();
RTC.adjust(DateTime(__DATE__,__TIME__));
//Adjust LCD
lcd.begin(16,2);
lcd.clear();

//sets a random value for puzzle
randVal = random(0, 6);
//Serial.println(randVal);

//Sets outputs for RGB LED
 pinMode(redLedPin, OUTPUT);
 pinMode(greenLedPin, OUTPUT);
 pinMode(blueLedPin, OUTPUT);
}

void loop() {
DateTime now=RTC.now();
//only executes every 1 seconds
if(millis()-timeVal>=1000){
  //Sets LCD with correct time
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print((String)now.month() + "/" + now.day()+ " " + now.hour()+":"+now.minute()+":"+now.second());
  if(wakeVal){
    //Operates the color puzzle
    lcd.setCursor(0,1);
    lcd.print(colour[randVal]);
  }
  timeVal=millis();
}
if(now.hour() == 24){
  //Resets the alarm activation
  timePassed = true;
}
if((wakeVal || now.hour() == alarmHour && now.minute() == alarmminute) && timePassed){
  wakeVal = true;
  //Serial.println("Made it 1");
  //Rings the alarm
  tone(speakerPin, 262, 250);
  //Sets the puzzle
  ColortoNum(colour[randVal]);
  //Changes LED color
  color_value[0] = analogRead(redPotPin)/4; //(0~1023 => 1024/4=256)
  color_value[1] = analogRead(bluePotPin)/4;
  color_value[2] = analogRead(greenPotPin)/4;
  ColorVal(color_value[0],color_value[1],color_value[2]);
}
//Chekc whether the puzzle is correct
if(timePassed && color_value[0] == target_color_value[0]&&color_value[1] == target_color_value[1]&&color_value[2] == target_color_value[2]){
  if(wakeVal){
    timePassed = false;
  }
  //Turns the puzzle and alarm off
  wakeVal = false;
  randVal = random(0, 6);
  Serial.println(randVal);
  //ColortoNum(colour[randVal]);
  Serial.println("Made it 2");
  noTone(speakerPin);
  ColorVal(0,0,0);
}
}

//Sets LED color
void ColorVal(int red, int green, int blue)
{
  analogWrite(redLedPin, red);
  analogWrite(greenLedPin, green);
  analogWrite(blueLedPin, blue);
}

//Check Whether LED shows correct color
void ColortoNum(String colour){
  if (colour == "white"){
    target_color_value[0] = 255;
    target_color_value[1] = 255;
    target_color_value[2] = 255;
  }
  else if (colour == "blue"){
    target_color_value[0] = 0;
    target_color_value[1] = 0;
    target_color_value[2] = 255;
  }
  else if (colour == "red"){
    target_color_value[0] = 255;
    target_color_value[1] = 0;
    target_color_value[2] = 0;
  }
  else if (colour == "green"){
    target_color_value[0] = 0;
    target_color_value[1] = 255;
    target_color_value[2] = 0;
  }
  else if (colour == "yellow"){
    target_color_value[0] = 255;
    target_color_value[1] = 255;
    target_color_value[2] = 0;
  }
  else if (colour == "purple"){
    target_color_value[0] = 255;
    target_color_value[1] = 0;
    target_color_value[2] = 255;
  }
  else if (colour == "cyan"){
    target_color_value[0] = 0;
    target_color_value[1] = 255;
    target_color_value[2] = 255;
  }
}

 

]]>
Project 2: Blood Circulation Sensor https://courses.ideate.cmu.edu/60-223/f2020/work/project-2-blood-circulation-sensor/ Tue, 03 Nov 2020 08:46:43 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11638 A footstool that uses a temperature sensor to alarm users when their feet are getting colder so they are able to get up and move around to help their blood flow!

Ever since I was younger, I have always had cold hands and feet. It is typically due to not moving around and sitting all day. Due to classes being remote, it has gotten worse. At my worst, my feet get so cold that they are numb. So, for this project, I wanted to create an anklet sensor that would alarm me when my temperature starts to drop before getting to the lowest degree. However, due to my incompetence, I was unable to follow through but shift it into a footstool.

The video above is exemplifies what happens when the device is in the trigger state and the button is pushed. When the push-button is pressed while in the trigger state, then the device will wait 5 minutes (in the video it is 5 seconds due to time) for the users to move around to raise their tempt. In the meantime, the vibration will turn off, but to make sure the users understands what state the device is in, the LED continues to stay on. Once the time is up, the device will check the user’s temperature again and if it is not at the resting state, then it continues the triggers until it goes up. 

The “Device Overview” video shows a user actually using the device. The first part of the clip is when the feet are at the resting state. The second part of the clip exemplifies what happens when the feet are at the trigger state. 

Here is a diagram of the parts of the device!

Process

Before getting to the final concept of making a foot stool, I wanted to create an ankle bracelet that have the same purpose but for only one foot and it is wearable. I started off with mood boarding and doing feet studies on how I could create a device that is wearable, comfortable, and effective.

Here is the mood-board that I created.

Here is one of the foot studies that I did.

 

 

 

 

 

 

These are quick iterations of what the device could have looked like when I was still doing a wearable device.

Before starting on the code in TinkerCad, I struggled to grasp all the components of my device, because I kept overcomplicating it. So, I went to Zach for advice and he suggested creating a state map, which was extremely helpful in organizing my idea!

Here is my state map to help me organize what components are needed for my device and what they do.

However, after starting with TinkerCad to get the software aspect of my device working, I realized that I was not competent enough to learn how to use an ATTiny 85. It was difficult for me to code as that type of component does not have a serial monitor for me to check my data. Due to that constraint, I decided to pivot to make a foot stool so that I could use the Arduino Uno. I made the decision to switch because I felt much more comfortable with using the Arduino because of my previous experience. Once I was able to get that all decided, I went to TinkerCad to get that all set up, because I am the most weak with coding.

This is the TinkerCad prototype to help me first understand the software aspect of how to create this device. Press on the image to go to the actual TinkerCad Link!

At first, when the temp went into the resting that, there would be weird buffer and then the triggers would turn off. I thought it was a code error at first and went through, but after discussing with Zach, the order of my code was incorrect. To make the code properly articulate what I want the Arduino to do, I need to order it based on sense, decide, do, and then report. After fixing that issue, I had no issues with the TinkerCad!

Here is the half of the first day that I did with tracking!

Before fabricating, I wanted to get some data about my personal blood circulation and its correlation with temperature. In order to do so, I tracked the temperature of my feet for a little less than 5 days. I measured my right arm, heels of both feet, bottom of both feet, and big toes of both feet. It was interesting to see the correlation and difference of what I had thought and what was actually true.

One thing that I noticed was that my left foot was always slightly warmer than my right. It was not drastic, but a few degrees. In addition, when the temperature of my feet started to hit around 24 C, then the temperature would continue to drop drastically. Because of that finding, I made my code have anything less than or equal to 24 C as the trigger state. I had fun tracking! I hypothesized that the bottom of my feet and my toes would be the coldest and the heels wouldn’t matter, but as I tracked, it was interesting to see that the heels get cold and sometimes are the coldest areas of my feet.

Throughout this project, I used the thermometer that my mom gave me. This was the most I had ever used it!

Now to fabrication! Before I went into the physical building, I wanted to make sure I had an idea of what the foot stool would look like, so I made quick sketches. In addition, I used boxes that I had and used them as bases and pieces.

Here are some quick sketches that I made about the design of the foot stool.

At first, I wanted to use as little breadboards as possible, because I thought that would make the process easier. However, I was completely wrong. Limiting myself made it much more difficult when fabricating.

This was my first iteration and I was being ambitious and trying to only use the small breadboard. However, because I had so many components, it would not work.

Here is the second trial where I tried only using two bread boards.

 

 

 

After getting most of the components to work with the Arduino, I started to design the foot stool. I used an old smoothie box that I had. For this design, I used my own feet for the sizes. Unfortunately, I was unable to go with this prototype because it would squish the wires, causing poor circuits which I will explain later on.

Here is an image of me testing the size of the foot compartment of the stool.

This is an image of the cutout from the front to see the compartments. The box was much taller than I expected so I added a layer on the bottom to make my foot stand slightly higher.

In order for the foot to rest, I made a separate part with the TMP sticking out!

Here is what the wiring looked like from the inside.

Here is another view of how the LED was placed in this box.

Here is what the hanging metal looked like.

When using this design, it was difficult to use. Before adding my parts into this box, it wasn’t having any major issues, but after I squished it in, then the components were all messed up. There were many issues to why this happened. The main issue was that there were a lot of hanging metal which would touch each other due to the tight space of the box.

This is what it would have looked like from a birds eye view if I continued on with this design.

Here is another angle of what the footstool would have looked like in this design.

 

Here is the quick vector sketch of the newest design.

So, after realizing the major issues the previous design had, I wanted to add more breadboards so that there is less potential touching with wires and them getting squished. In addition, I wanted the design to become more flexible so that the wires would not be contained to produce the best circuits. I tried sketching an iteration. Below, you can see how the white parts of the device open and close. Those sections will contain the main breadboards and circuits. It is able to open and close incase there are any issues with the wiring, so that if a user wants to fix it, it is easy to look through.

This was the previous circuit where it was only using two breadboards, which was not as effective.

This is the final connections that I made. These circuits were the most effective. I am glad that I used 4 breadboards as it made it much easier to keep track of all the wires as well as keeping them plugged in properly and not squished.

Here is the final product.

Discussion

This project was extremely fun, even though there were a lot of problems in between. Since this was the biggest and most complicated circuit I had built in this class, my process was very all over the place, but I appreciate that. Because of the obstacles, I genuinely feel happy with how far I was able to come with this project. The ideation was definitely not easy, but it really helped me grow overall with my coding, electrical, and mechanical skills. It was not easy, but the problems and solutions that I was able to go through will definitely prepare me for future projects that may be more complex.

How can we use biosignals to create an experience! Temperature and its correlation with blood circulation is a smart way to think! Look into pinching/massaging with bettering the circulation.

This was one of the feedback that stood out to me. I had not thought about ways to better the circulation due to the lack of knowledge with how to help. During the first class check-in, I recall that someone asked if the vibration motor would be used as a way to help circulation, but because it is so light with the shaking it has no affect. Adding on, vibration does not help with increasing heat but rubbing and or massaging does. I think it would be interesting to see what are massage techniques to help blood circulation and then transferring them into motions through motors. I am not sure of how effective and possible that will be in the mechanical side, but it would be extremely interesting to look into in the future. On the other hand, I am not sure if adding this component would take away from the overall purpose of this device being a blood circulation alarm for those who get very busy during the day and forget to move around.

The application seems very relevant.  I think the unanswered question for me is how well actual temperature correlates with perceived temperature.

This was the second response that really stuck with me, because the correlation with the actual temperature and perceived temperature is something that I wanted to look more into for next steps. Because the TMP36 is small, it does not accurately get the correct temperature all the time, so I was thinking about having multiple TMP36s all around each foot and then averaging the temperatures to get the most accurate data.

Overall, I think I did a good job and I am happy with the final product. The device works the way that I intended which is what really excites me. In the beginning, I definitely lacked a lot of confidence due to my lack of expertise, but as I worked, I realized that I should not feel that way. This class is meant for me to make mistakes and play around so that I can grow. It was difficult for me to code and do the wirings, but as I kept trying and looking at other projects, I felt really excited cause I would get closer and closer each time. Furthermore, the design of the stool was much harder than I thought it would be. I did not consider that squishing the wires would mess up circulations. From this, I learned how to deal with cutting metal to fit the breadboard without sticking out.

The biggest takeaways from this project was that HANGING WIRES ARE A NO NO. I never knew about hanging metals so I thought that it was normal to have metal in a female/male wire. But through this project, I learned about how wrong that is. In addition, TinkerCAD is not always simulating the circuits properly, so I should try to work on the physical building as soon as possible. Adding on, be gentle with the wires! While I was trying to get the metal from the pancake vibration motor, I accidentally pulled the wire too much and broke it. Lastly, be ready for the unexpected by having back-up plans. No matter how well-planned your project is, there can be obstacles that occur due to anything. I think this project really helped me grow to work smarter. With the previous project and assignments, I struggled to fully get the connections with code, electronics, and mechanics, but with this project, I feel confident with my ability. 

For next steps, I would want to try learning how to use the ATTiny to create the anklet version. Also, I would want to reiterate on my final stool design because I used paper for this version which was not as clean as I want. In addition, I want to continue to research how to accurately get data from the TMP36. I say this because I tested out the device while doing homework for an hour. I had not considered some factors that would disrupt my data. One factor is that I shake my right leg when I am sitting down, which made it difficult for the device to accurately get my temperature properly. Adding on, there would be times that I would check the temperature with the thermometer and then the TMP36 and the data would be different. I want to look more into why they are different to make my device get more accurate information.

In the end, I am proud with the overall finish of the project! I was really able to push my comfort level and skills through this project. I think that I am glad that I tried to be ambitious as it was a great way for me to learn more about physical computing on my own and learn how to problem-solve through my comprehension skills and other resources. I am so thankful for everyone who had helped me with this device. 

Schematic

Here is my schematic drawing!

/* 
 * Project 2: An Assistive Device for someone you know well
 * Jina Lee (jinal2)
 *
 * Collaboration: For this project, I used various resources
 * to help me get to the final state! Due to my lack of
 * experience with everything (software, electrical, and 
 * fabrication), it was extremely helpful for me to do
 * research and see what other people have done.
 *
 * I worked closely with my professor, Zach, to get a better 
 * understanding of how to use a ULN2803A, properly order my 
 * code, plug in wires without metals touching each other on 
 * the breadboard, and use multiple breadboards. Without the 
 * help of Zach, my project would not have been able to be at 
 * the final state, because he drastically aided me in fully 
 * understanding software and electrical concepts which I 
 * struggled a lot with!
 *
 * https://www.tinkercad.com/things/7KlkHaxx20c-
 * tmp36-temperature-sensor-with-arduino
 * zhtuhin4: For learning what formulas are needed to find the
 * temperature from the voltage that the TMP is getting.
 * 
 * https://learn.adafruit.com/tmp36-temperature-sensor/
 * using-a-temp-sensor
 * This link was used to help me learn how to properly use the 
 * temperature sensor. Because of my inexperience, looking at 
 * the formulas and various types of way to approach the software
 * was extremely helpful. 
 *
 * https://bc-robotics.com/tutorials/using-a-tmp36-temperature-
 * sensor-with-arduino/
 * This link helped me by going step by step on how to use the 
 * TMP36 sensor with the Arduino by showing images and code to 
 * explain the steps. The way this website explained to me was 
 * the most effective in getting me to fully understand what 
 * to do!
 *
 * https://dothemath.ucsd.edu/2012/04/heat-those-feet/
 * This article is about cold feet and how to treat them. This 
 * reading was helpful to me so that I have a strong understanding 
 * of how I can correlate the temperature of my feet to blood 
 * circulation. 
 *
 * https://pubmed.ncbi.nlm.nih.gov/20660876/
 * This paper is about how foot temperature can also be affected 
 * by age. It was interesting to see the correlation about peoples'
 * feet temperatures while sleeping. My feet are usually extremely 
 * cold when I am about to go to sleep, but when I wake up, they 
 * are warm.
 * 
 * Sue Lee: Former student in this class, helped me when I had 
 * trouble with fabrication. There was an issue with the TMP36 
 * getting negative degrees and she suggested to change the GND and 
 * 5V to switch the current, which is what works with motors. 
 * However, after trying that, thankfully the arduino and all my 
 * components were completely fine, but the TMP36 heat up really 
 * quickly, so I had to not touch my stuff for a few minutes.
 *
 * Description: 
 * The code below uses the temperature sensors to detect the blood 
 * circulation in user's feet. When the trigger tempt is detected 
 * (anything less than 29 C), then the LEDs and Vibration motors 
 * will turn on. In that trigger state, if the push button is pressed, 
 * then the TMP36 that is connected to it will take a five minute 
 * wait, giving the person time to move around to raise their tempt. 
 * During the wait time, the LED stays on while the vibration stops. 
 * After the wait time is up, then the temperature will detect again 
 * and if it is in the resting state, the device will stop all 
 * triggers. However, if it is the opposite, both triggers will 
 * start again.
 *
 * Pin mapping: 
 * pin | mode | description 
 * ----|------|------------
 * A1  |INPUT | TMP36 Sensor
 * A2  |INPUT | TMP36 Sensor
 * 2   |OUTPUT| LED
 * 3   |OUTPUT| Pancake Vibration Motor
 * 4   |INPUT | Pushbutton
 * 5   |OUTPUT| Pancake Vibration Motor
 * 6   |INPUT | Pushbutton
 * 8   |OUTPUT| LED
 */

const int lefttemperaturePin = A1;
const int righttemperaturePin = A2;
const int leftLED = 2;
const int rightLED = 8;
const int leftMOTOR = 3;
const int rightMOTOR = 5;
const int leftBUTTON = 4;
const int rightBUTTON = 6;


void setup()
{
  pinMode(lefttemperaturePin, INPUT);
  pinMode(righttemperaturePin, INPUT);
  pinMode(leftBUTTON, INPUT);
  pinMode(rightBUTTON, INPUT);
  pinMode(leftLED, OUTPUT);
  pinMode(rightLED, OUTPUT);
  pinMode(leftMOTOR, OUTPUT);
  pinMode(rightMOTOR, OUTPUT);
  Serial.begin(9600);
}


void loop()
{
  float lvoltage, ldegreesC, ldegreesF;
  float rvoltage, rdegreesC, rdegreesF;
  int leftbuttonState = digitalRead(leftBUTTON);
  int rightbuttonState = digitalRead(rightBUTTON);
  
  //Measure left foot voltage
  lvoltage = getVoltage(lefttemperaturePin);
  //Convert left voltage to degrees Celsius
  ldegreesC = (lvoltage - 0.5) * 100.0;
  //Convert left Celsius to Fahrenheit
  ldegreesF = ldegreesC * (9.0/5.0) + 32.0;
  
  //Measure right foot voltage 
  rvoltage = getVoltage(righttemperaturePin);
  //Convert right voltage to degrees Celsius
  rdegreesC = (rvoltage - 0.5) * 100.0;
  //Convert right Celsius to Fahrenheit
  rdegreesF = rdegreesC * (9.0/5.0) + 32.0;
  
  //When the left temp is lower than the resting state
  //and the button is pushed,
  //then there is a five minute pause.
  //The vibration turns off, but the LED is still 
  //on to notify users what state it is in.
  //Afterwards, the left temp is checked again.
  //If it is still lower than the resting state,
  //then the trigger starts until left temp moves up
  if ((leftbuttonState == HIGH)) {
    digitalWrite(leftLED, HIGH);
    digitalWrite(leftMOTOR, LOW);
    //Wait for the user to move around (right now
    //using a faster time to display the task)
    delay(5000);
    //Measure left foot voltage again when 
    //button is pushed
  	lvoltage = getVoltage(lefttemperaturePin);
  	ldegreesC = (lvoltage - 0.5) * 100.0;
  	ldegreesF = ldegreesC * (9.0/5.0) + 32.0;
    if (ldegreesC > 29) {
      //Measure left foot voltage after the delay
  	  lvoltage = getVoltage(lefttemperaturePin);
      ldegreesC = (lvoltage - 0.5) * 100.0;
      ldegreesF = ldegreesC * (9.0/5.0) + 32.0;
      //If tempt is in resting state,
      //then the triggers turn off
      digitalWrite(leftLED, LOW);
      digitalWrite(leftMOTOR, LOW);
      delay(10);
    } else {
      //If tempt is still in trigger state,
      //then the triggers continue
      digitalWrite(leftLED, HIGH);
      digitalWrite(leftMOTOR, HIGH);
      delay(10);
    }
  }
  
  //When left temp is lower than the resting state
  //the tiggers start
  if (ldegreesC < 29) {
    digitalWrite(leftLED, HIGH);
    digitalWrite(leftMOTOR, HIGH);
    delay(10);
  } else {
    //When left temp is in resting state, 
    //the triggers end
    digitalWrite(leftLED, LOW);
    digitalWrite(leftMOTOR, LOW);
    delay(10);
  }
  
  //WHen the tight temp is lower than the resting state
  //and the button is pushed,
  //then there is a five minute pause.
  //Afterwards, right temp is checked again.
  //If it is still lower than the resting state,
  //then the trigger starts until it moves up
  if ((rightbuttonState == HIGH)) {
    digitalWrite(rightLED, HIGH);
    digitalWrite(rightMOTOR, LOW);
    delay(5000);
    //Measure right foot voltage again 
    //when button is pushed
    rvoltage = getVoltage(righttemperaturePin);
    rdegreesC = (rvoltage - 0.5) * 100.0;
    rdegreesF = rdegreesC * (9.0/5.0) + 32.0;
    if (rdegreesC > 29) {
      //Measure right foot voltage after the delay
  	  rvoltage = getVoltage(righttemperaturePin);
      rdegreesC = (rvoltage - 0.5) * 100.0;
      rdegreesF = rdegreesC * (9.0/5.0) + 32.0;
      //If tempt is in resting state,
      //then the triggers turn off
      digitalWrite(rightLED, LOW);
      digitalWrite(rightMOTOR, LOW);
    } else {
      //If tempt is still in trigger state,
      //then the triggers continue
      digitalWrite(rightLED, HIGH);
      digitalWrite(rightMOTOR, HIGH);
    }
  }
  
  //When right temp is lower than the resting state
  //then the tiggers start
  if (rdegreesC < 29) {
    digitalWrite(rightLED, HIGH);
    digitalWrite(rightMOTOR, HIGH);
    delay(10);
  } else {
        //When right temp is in resting state, 
        //the triggers end
    	digitalWrite(rightLED, LOW);
    	digitalWrite(rightMOTOR, LOW);
    	delay(10);
  }
  
  //Serial port to double check left foot data
  Serial.print("  left deg C: ");
  Serial.print(ldegreesC);
  Serial.print("  left deg F: ");
  Serial.println(ldegreesF);
  delay(1000);
  
  //Serial port to double check the right foot data
  Serial.print("  right deg C: ");
  Serial.print(rdegreesC);
  Serial.print("  right deg F: ");
  Serial.println(rdegreesF);
  delay(1000);
}


float getVoltage(int pin)
{
  return (analogRead(pin) * 0.004882814);
}

 

]]>
Drink up! https://courses.ideate.cmu.edu/60-223/f2020/work/drink-up/ Tue, 03 Nov 2020 05:15:17 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11720 Your water drinking water reminder and monitor!

Time-lapse of drinking a water bottle – Sorry the video quality is bad, I had to compress it a lot to upload it

 

The overall image of the project

 

This is an image of the LCD displaying the amount of water drank

 

The project in action!

 

Decision points:

  • Creating a laser cut box for the exterior of my project. This was a big decision point for me as I was debating on just using a cardboard box but realized the need for a sturdy box to use the load cell. Hence, I decided laser cut the box
  • I wanted to make my device to reset the number of bottles drunk every day, but I was unable to make the clock part work with my device and so decided it was not as important as working on the rest

Process Pictures

Load cell assembly – Load cell is placed between two wooden planks and attached to each of the planks on opposite sides of the cell to allow for bending when a wait is applied.

Image of the circuit inside the box

Clamps being used to hold the wooden box together waiting for the wood glue to dry up

 

Responses to other’s feedback

Your end product looked really nice and was a great idea. Like someone said it would be nice if this was a coaster that you could bring with you “

“I think your project is super helpful (as someone who doesn’t drink water either haha) – It could be interesting to see it as an attachment to a water bottle, like an attachable base, or have it be incorporated into your primary work desk so it’s almost indetectable.”

Since all my critique was essentially the same, I will respond to all of them at once. The reason I chose the topic, as it was pointed out in my critique, is because I need to force myself to drink more water regularly, and I am really glad that there are people other than me who think this is helpful and a good idea. The common feedback that I got from the critique as well as during the presentation was that the project would be better if I could make it smaller and more portable. I definitely like the idea of a coaster or an attachable base. However, the idea of embedding it into my work desk is something new that I never thought of but I really like. It is definitely something I would like to explore as a next step.

 

Self critique:

Overall, I think I am quite happy with the way my project turned out. I am specifically very happy with how the exterior of my project, the laser cut box, looks. This is because design and presentation is something I am very new to, and I did not expect it to turn out the way it did. In addition, it took me quite a bit of time to figure out how to make the design for the laser cutting. 

The one part I am not as happy with is that I was unable to get the LCD to reflect the exact volume of water that was consumed. This was one of the goals I was very excited about, but I was unable to figure out exactly what the conversion from load cell readings to volume in ml was.

 

What I learned:

There were a lot of different skills and concepts I learned through this project. Like I mentioned before, how to create laser cutting designs, how to make precise measurements for the drawings as well as how laser cutting works is one of the big learnings I had from this project. In addition, just thinking about the project not just in a technical way, as I have been doing all along, but as a product is a completely new lens I adopted through this project.

I also found the code for the project more challenging than normal, especially the part where I had to calculate the volume of water drank. This was quite difficult because I had to account for cases where the bottle was no longer on the load cell, when the volume of water decreased, as well as when the volume increased (when the bottle is refilled). In order to account for all of this, I had a lot of variables that I needed to keep track of which got very confusing at first. Later, however, I created a flowchart of how the code should work in each of the cases listed above, after which the coding process got a lot smoother.

In addition, I also had a little bit of trouble soldering my wires together. For some reason, the tip of my solder would not heat up, but the areas just below the tip would heat up just fine. It took me a while of thinking I didn’t know how to solder and thinking the solder wasn’t hot enough to realize this behavior, after which the process was easier, though it was still harder to use the thicker part of the solder rather than the tip.

 

Next Steps:

My next steps would be to build a more compact and portable version of the project, as well as better calculate the volume of water drank.

 

Schematic:

/********************************
 * Project: Drink up!
 * By Sruti Srinidhi
 * 
 * The code below takes a load cell reading and 
 * outputs the volume of water drank, lights
 * up LEDs indicating the number of bottles
 * completed as well as sounds an alarm 
 * if water has not been drank for a while
 * 
 * pin   | mode   | description
 * ------|--------|------------
 * 7      output     LED indicating bottle drank   
 * 8      output     LED indicating bottle drank 
 * 9      output     LED indicating bottle drank
 * 11     input      Push button switch for calibration 
 * A1     input      Load Cell Pin
 * A0     input      Load Cell Pin
 * 3      output     Speaker Pin
 * 
 * 2      output     LCD BD7 Pin 
 * 4      output     LCD DB6 Pin
 * 5      output     LCD DB5 Pin 
 * 6      output     LCD DB4 Pin 
 * 10     output     LCD Enable Pin
 * 12     output     LCD Register select Pin
 * 
 * HX711 module by Rob Tillaart
 */

#include "HX711.h"
#include <LiquidCrystal.h>

const int BOTTLE1LEDPIN = 7;
const int BOTTLE2LEDPIN = 8;
const int BOTTLE3LEDPIN = 9;
const int CALIBRATEPIN = 11;
const int LOADCELLPIN1 = A1;
const int LOADCELLPIN2 = A0;
const int SPEAKERPIN = 3;

int bottleCount = -1;
int emptyWeight = 0;
bool calibrated = false;
bool increasing = false;
unsigned long timer;
bool drinking = false;
int volumeDrank = 0;
int weightReading = 0;
long lastWeight;
long LoadCellInput = 0;

HX711 cell;
LiquidCrystal lcd(12, 10, 6, 5, 4, 2);

void setup() {
  pinMode(3, OUTPUT);
  // put your setup code here, to run once:
  pinMode(BOTTLE1LEDPIN,OUTPUT);
  pinMode(BOTTLE2LEDPIN,OUTPUT);
  pinMode(BOTTLE3LEDPIN,OUTPUT);
  pinMode(CALIBRATEPIN, INPUT);
  lcd.begin(16, 2);
  cell.begin(A1,A0);

}


void loop() {
  lcd.setCursor(0, 0);
  //Ask to calibrate if it is uncalibrated
  if (!calibrated){
    lcd.print("calibrate");
  }
  else {
    // Show volume drank on lCD
    lcd.print("Volume drank:");
    lcd.setCursor(0, 1);
    lcd.print(volumeDrank);
    lcd.setCursor(6,1);
    lcd.print("ml");
  }
  LoadCellInput = cell.read()/1000;
  //Water drank if the bottle is lifted off the load cell
  if (LoadCellInput < emptyWeight){
    timer = millis();
  }
  else{
    //Srinking water
    if (LoadCellInput < lastWeight){
      increasing = false;
      if (calibrated){
        volumeDrank = volumeDrank + lastWeight - LoadCellInput;
      }
     }
    
    //Bottle is being replaced
    else if (LoadCellInput > (lastWeight + 300)){
        increasing = true;
        bottleCount++;
      }
    
    lastWeight = LoadCellInput;
  }
  
  
  //Sound alarm if water has not been drank in a while
  if ((millis() - timer) > 900000){
    tone(SPEAKERPIN,200);
  }
  else {
    noTone(SPEAKERPIN);
  }
  
  //Calibrate
  int calibrate = digitalRead(CALIBRATEPIN);
  if (calibrate == HIGH){
    calibrated = true;
    emptyWeight = LoadCellInput;
    bottleCount = -1;
    volumeDrank = 0;
    digitalWrite(BOTTLE1LEDPIN,LOW);
    digitalWrite(BOTTLE2LEDPIN,LOW);
    digitalWrite(BOTTLE3LEDPIN,LOW);
  }else{
    //Turn on LED to show bottle count
    if (bottleCount >= 1){
      digitalWrite(BOTTLE1LEDPIN,HIGH);
    }
    if (bottleCount >= 2){
      digitalWrite(BOTTLE2LEDPIN,HIGH);
    }
    if (bottleCount >= 3){
      digitalWrite(BOTTLE3LEDPIN,HIGH);
    }
  }
  
  weightReading = LoadCellInput - emptyWeight;
}

 

 

]]>
Task Management Visualizer https://courses.ideate.cmu.edu/60-223/f2020/work/task-management-visualizer/ Tue, 03 Nov 2020 01:33:04 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11688 Overview

It’s a device that could help and motivate you to finish your tasks and also work as a nice decorative material for your bleak walls – complete all your tasks for today and find out what constellation you got at the end!

 

Final Model Showing Big Dipper. Notice the LCD screen showing ‘BIG DIPPER’ and the LED indicating that you have seven tasks is on. (From left to right each LED represents 4, 5, 6, 7, 8, 9, 10 tasks-to-do respectively) The final device is battery-run.

Device showing another constellation (Leo)

 

IR Remote sticking from the bottom (Works best when there’s nothing blocking it so I took it out of the casing)

IR remote with a new casing

What each button indicates

 

Process

After some consideration, I came up with an idea to make something that would help me keep track of my tasks – but also something that would motivate me to do so. And since it had to be placed somewhere noticeable in my room, I wanted it to be aesthetically pleasing and work as a decorative material too. At the end, I came up with task-tracker that uses constellations to visualize for your processes.

Initial Ideation

I wanted it to have an element of surprise with what constellation I would get at the end, which would require me to input a variety of constellations with a different number of stars. All these constellations have different positions for stars and I thought it would be appropriate to use an addressable LED strip instead of individual LEDs. Working with the LED strip was pretty easy since there were a lot of tutorials for how to program it. For this specific project I used the WS2811 addressable LED strip and the FastLED library.

I began prototyping by testing how I could input the fact that I have finished off a task and how that could translate to an LED being lit up. For this I used a bush button and a state-change code to light up the LED every time I pressed the button as shown in the video below.

However I thought it would be somewhat inconvenient for me to get up every time I finish a task to go find the device (that’s hanging on the wall on the opposite side of the room) and press the button, I thought it would be better if I could control it remotely. So I began looking into how to use the IR remote and receiver and the IRremote library. The library translates the signal received from the remote to a certain code and also includes a function that allows you to command what action would happen when you press a certain button on the remote. At first it wasn’t working. I wasn’t able to figure out if there was a problem in the remote, the receiver, or the library – but it worked fine after I switched to another Arduino board. The video below shows me turning the LED on and off using the IR remote.

 

After figuring out how to work the individual components – it was time to write the code! I made arrays for seven groups of three constellations (that have 4, 5, 6, 7, 8, 9, 10 stars) and wrote the code to store each star’s location on a 10 x 10 matrix of LED lights. And then I wrote the code to turn one star (LED) at a time using the up/down button on the remote as well as the one to turn off all the lights and reset the device using the IR remote.

After the electronics came the mechanics. I laser-cut some wood to make a casing and also a board to hold the LEDs. Each of these holes are a bit offset so that the constellations would appear more organic. I made some holes on the bottom to hold the LCD panel and the green LED lights that indicate how many tasks you have at the moment. (from left to right: 4, 5, 6, 7, 8, 9, 10) Then I put the diffusing material on top to cover up the LED’s (ended up putting two layers), connected the Arduino to a battery, placed everything in the bottom space and covered it up with another piece of wooden board.

Fitting in the LED strip into the laser-cut parts.

Putting the diffusing material on top

Space on the bottom where all the electronics will go into

At the beginning and every time you press the reset button the LCD panel will say: HOW MANY TASKS DO YOU HAVE?

Discussion

I am pretty satisfied with the outcome of this project even though the initial concept may have lacked practicality. I was able to solve all the problems I faced and make it work exactly how I wanted it. However there were some points that were brought up during crit which I completely agree with: the diffusing material is white which is not what the night sky looks like exactly, and sometimes it is hard to even remember to turn on the light every time you finish the task. And you may want to keep up with your tasks NOT exactly because it is motivational, but because it is fun to play with (which is the reason why it would work so great with kids). I also enjoyed learning to control the LED strip and IR remote for the first time during this project. I think both of them are going to be useful tools in the future electronics project. Making the casing was also fun and I am glad that it turned out nicely at the end despite the lack of proper tools and materials (wood glue, wood finish, black fabric that I intended to use as a diffusing material at first).

There was one thing that bothered me and that is how long the code was. After completing I tried tweaking it to make it shorter but it just didn’t work the same way I wanted it to. It might be because I do not have sufficient knowledge about it. I think this a skill though that I can develop over time as I familiarize myself with coding.

As a next iteration, I was thinking about adding the IoT component to it to automate the task-tracking component and make it easier too. With the Particle Board and IFTTT I think it would be possible to link it to either your reminder app or the calendar app on your phone to update the number of tasks and keep track of them automatically even when you’re far away from the device.

 

Schematic

/*
 * Project 2: Assistive Technology
 * Claire Koh
 * 
 * Collaboration: FastLED tutorial (https://www.instructables.com/Basic-of-FastLED/)
 * IR Remote Control tutorial (https://www.circuitbasics.com/arduino-ir-remote-receiver-tutorial/)
 * 
 * Challenge: Learning how to work the IR remote and the LED strip using respective libraries
 * that were both new to me. 
 * 
 * Next Time: I would change the diffusing material to black so it would have more of the 'night sky' feeling.
 * Also I hope once I learn more about coding I could figure out how to shorten this code.. which is very very long.
 * 
 * 
 * Description: It helps you keep track of the tasks you have finished and also motivates you to do so
 * by making a complete constellation at the end. 
 * First you start by inputting the number of tasks you have - you can do that by clicking the corresponding
 * button on the IR remote (4,5,6,7,8,9,10)
 * Then Arduino will pick a random constellation whose number of stars matches the input number of tasks.
 * Every time you finish a task you press the up button and a star will light up. You can press the down button
 * to take it back if you've pressed the up button by accident.
 * Once you've completed all the tasks the constellation will be complete - and it will do a little animation.
 * You can go to sleep by looking at the constellation you've completed and feeling accomplished.
 * It could also work as a general wall art.
 * 
 * Pin Mapping:
 * 
 * pin | mode | description
 * ----|------|-------------
 * 2    OUTPUT  Task indicator LED (10)
 * 3    OUTPUT  Task indicator LED (9)
 * 4    OUTPUT  Task indicator LED (8)
 * 5    OUTPUT  Task indicator LED (7)
 * 6    OUTPUT  Task indicator LED (6)
 * 7    OUTPUT  Task indicator LED (5)
 * 8    OUTPUT  To program the LED strip
 * 9    OUTPUT  Task indicator LED (4)
 * 10   OUTPUT  LCD Panel (EPIN)
 * 11   INPUT   IR remote signal receiver
 * 12   OUTPUT  LCD Panel (RSPIN)
 * A0   INPUT   To get a random number
 * A1   OUTPUT  LCD Panel (D7PIN)
 * A2   OUTPUT  LCD Panel (D6PIN)
 * A3   OUTPUT  LCD Panel (D5PIN)
 * A4   OUTPUT  LCD Panel (D4PIN)
 */


#include <IRremote.h>
#include <FastLED.h>
#include <LiquidCrystal.h>


// Signal Pin of IR receiver to Arduino Digital Pin 11
const int receiver = 11; 

// LED's to indicate how many tasks you have to do.
const int FOURLED = 9;
const int FIVELED = 7;
const int SIXLED = 6;
const int SEVENLED = 5;
const int EIGHTLED = 4;
const int NINELED = 3;
const int TENLED = 2;

// Parameters for the LED strip
const int NUM_LEDS = 100;
const int DATA_PIN = 8;

// For the LCD screen
const int RSPIN = 12;
const int EPIN = 10;
const int D4PIN = A4;
const int D5PIN = A3;
const int D6PIN = A2;
const int D7PIN = A1;

// Integer to store how many tasks you've done.
int plusCount = -1;

// Integers used to indicate which function is on at the moment.
// At the beginning of a function one of these would be set to 1 and the rest would be 0.
int booleancaelum = 0;
int booleancrux = 0;
int booleansagitta = 0;
int booleanaries = 0;
int booleancassiopeia = 0;
int booleancorvus = 0;
int booleancancer = 0;
int booleanlyra = 0;
int booleanauriga = 0;
int booleanbigdipper = 0;
int booleancepheus = 0;
int booleancygnus = 0;
int booleanorion = 0;
int booleanlynx = 0;
int booleanlibra = 0;
int booleanleo = 0;
int booleancapricorn = 0;
int booleanbootes = 0;
int booleangemini = 0;
int booleancanismajor = 0;
int booleanvirgo = 0;

int LEDstate = LOW;

// Arrays to store the position of leds that correspond to the position of the stars in each constellation
int caelumArray[] = {82, 73, 45, 26};
int cruxArray[] = {56, 72, 84, 26};
int sagittaArray[] = {98, 54, 12, 30};

int ariesArray[] = {60, 83, 32, 12, 6};
int cassiopeiaArray[] = {79, 96, 55, 47, 8};
int corvusArray[] = {27, 47, 37, 96, 86};

int cancerArray[] = {94, 65, 54, 23, 27, 8};
int lyraArray[] = {75, 38, 23, 73, 87, 71};
int aurigaArray[] = {23, 32, 51, 87, 83, 58};

int bigdipperArray[] = {19, 2, 24, 43, 64, 86, 89};
int cepheusArray[] = {48, 47, 74, 82, 57, 23, 24};
int cygnusArray[] = {83, 64, 33, 27, 41, 72, 88};

int orionArray[] = {2, 43, 82, 94, 73, 54, 13, 44};
int lynxArray[] = {1, 18, 37, 35, 54, 53, 87, 90};
int libraArray[] = {59, 57, 63, 95, 88, 48, 26, 13};

int leoArray[] = {48, 16, 1, 22, 53, 55, 63, 84, 94};
int capricornArray[] = {33, 26, 37, 60, 61, 63, 65, 71, 88};
int bootesArray[] = {29, 31, 26, 54, 84, 97, 78, 43, 5};

int geminiArray[] = {80, 61, 75, 85, 89, 69, 35, 22, 18, 2};
int canismajorArray[] = {20, 38, 22, 3, 25, 55, 73, 84, 93, 69};
int virgoArray[] = {42, 75, 53, 34, 15, 40, 1, 96, 68, 90};

// Pin to get a random value. Will be used to assign a random constellation.
const int RANDOMPIN = A0;

IRrecv irrecv(receiver); // create instance of 'irrecv'
decode_results results; // create instance of 'decode_results'
CRGB leds[NUM_LEDS];
LiquidCrystal lcd(RSPIN,EPIN,D4PIN,D5PIN,D6PIN,D7PIN);



void setup() {
  pinMode(FOURLED, OUTPUT);
  pinMode(FIVELED, OUTPUT);
  pinMode(SIXLED, OUTPUT);
  pinMode(SEVENLED, OUTPUT);
  pinMode(EIGHTLED, OUTPUT);
  pinMode(NINELED, OUTPUT);
  pinMode(TENLED, OUTPUT);
  pinMode(RANDOMPIN, INPUT);
  randomSeed(analogRead(RANDOMPIN));
  
  FastLED.addLeds<WS2811, DATA_PIN, RGB>(leds, NUM_LEDS); // Start the LED strip
  irrecv.enableIRIn(); // Start the receiver
  Serial.begin(9600);
  allOff();
}


void loop()
{
  if (irrecv.decode(&results)) { // Have we received an IR signal?
    translateIR(); // Then translate the signal to the corresponding code.
    irrecv.resume(); // And then receive the next value
    FastLED.show(); 
  } 
}


// Takes action based on IR code received
// Describing Remote IR codes 
void translateIR() {
  int randomnumber;
  switch(results.value) {

  case 0xFF18E7: // Will be used as "4" Button
  allOff();
  digitalWrite(FOURLED, HIGH); 
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    caelum();
  }
  if (randomnumber == 1) {
    crux();
  }
  if (randomnumber == 2) {
    sagitta();
  }
  FastLED.show();
  break;
  

  case 0xFF10EF: Serial.println("4"); // Will be used as "5" Button
  allOff();
  digitalWrite(FIVELED, HIGH); 
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    aries();
  }
  if (randomnumber == 1) {
    cassiopeia();
  }
  if (randomnumber == 2) {
    corvus();
  }
  FastLED.show();
  break;
  
  case 0xFF38C7: Serial.println("5"); // Will be used as "6" Button
  allOff();
  digitalWrite(SIXLED, HIGH); 
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    cancer();
  }
  if (randomnumber == 1) {
    lyra();
  }
  if (randomnumber == 2) {
    auriga();
  }
  FastLED.show();
  break;

  case 0xFF5AA5: Serial.println("6"); // Will be used as "7" Button
  allOff();
  digitalWrite(SEVENLED, HIGH);
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    bigdipper();
  }
  if (randomnumber == 1) {
    cepheus();
  }
  if (randomnumber == 2) {
    cygnus();
  }
  FastLED.show();
  break;
  
  case 0xFF42BD: Serial.println("7"); // Will be used as "8" Button
  allOff();
  digitalWrite(EIGHTLED, HIGH);
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    orion();
  }
  if (randomnumber == 1) {
    lynx();
  }
  if (randomnumber == 2) {
    libra();
  }
  FastLED.show();
  break;
  
  case 0xFF4AB5: Serial.println("8"); // Will be used as "9" Button
  allOff();
  digitalWrite(NINELED, HIGH); 
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    leo();
  }
  if (randomnumber == 1) {
    capricorn();
  }
  if (randomnumber == 2) {
    bootes();
  }
  FastLED.show();
  break;
  
  case 0xFF52AD: Serial.println("9"); // Will be used as "10" Button
  allOff();
  digitalWrite(TENLED, HIGH); 
  LEDstate = HIGH;
  randomnumber = random(0,3);
  if (randomnumber == 0) {
    gemini();
  }
  if (randomnumber == 1) {
    canismajor();
  }
  if (randomnumber == 2) {
    virgo();
  }
  FastLED.show();
  break;
  
  case 0xFF629D: Serial.println("VOL+"); // Would be used as a reset button
  allOff();
  digitalWrite(FOURLED, LOW);
  digitalWrite(FIVELED, LOW);   
  digitalWrite(SIXLED, LOW);
  digitalWrite(SEVENLED, LOW);
  digitalWrite(EIGHTLED, LOW);   
  digitalWrite(NINELED, LOW);
  digitalWrite(TENLED, LOW);

  plusCount = -1;
  Serial.println("reset");
  Serial.println(plusCount);
  break;


  // Following case is used as an up button
  // It will light up one LED at a time for the called function
  case 0xFF906F: Serial.println("UP");
    plusCount ++;
    Serial.println(plusCount);
  
    if (booleancaelum == 1) {
      leds[caelumArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      caelum();
    }
  
    if (booleancrux== 1) {
      leds[cruxArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      crux();
    }
  
    if (booleansagitta == 1) {
      leds[sagittaArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      sagitta();
    }
  
    if (booleanaries == 1) {
      leds[ariesArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      aries();
    }
  
    if (booleancassiopeia == 1) {
      leds[cassiopeiaArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      cassiopeia();
    }
  
    if (booleancorvus == 1) {
      leds[corvusArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      corvus();
    }
  
    if (booleancancer == 1) {
      leds[cancerArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      cancer();
    }
  
    if (booleanlyra == 1) {
      leds[lyraArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      lyra();
    }
  
    if (booleanauriga == 1) {
      leds[aurigaArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      auriga();
    }
  
    if (booleanbigdipper == 1) {
      leds[bigdipperArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      bigdipper();
    }
  
    if (booleancepheus == 1) {
      leds[cepheusArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      cepheus();
    }
  
    if (booleancygnus == 1) {
      leds[cygnusArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      cygnus();
    }
  
    if (booleanorion == 1) {
      leds[orionArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      orion();
    }
  
    if (booleanlynx == 1) {
      leds[lynxArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      lynx();
    }
  
    if (booleanlibra == 1) {
      leds[libraArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      libra();
    }
  
    if (booleanleo == 1) {
      leds[leoArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      leo();
    }
  
    if (booleancapricorn == 1) {
      leds[capricornArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      capricorn();
    }
  
    if (booleanbootes == 1) {
      leds[bootesArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      bootes();
    }
  
    if (booleangemini== 1) {
      leds[geminiArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      gemini();
    }
  
    if (booleancanismajor == 1) {
      leds[canismajorArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      canismajor();
    }
  
    if (booleanvirgo== 1) {
      leds[virgoArray[plusCount]] = CRGB(255,255,255);
      FastLED.show();
      virgo();
    }
  break;

  // Does the opposite of the UP button
  case 0xFFE01F: Serial.println("DOWN");   
  if (booleancaelum == 1) {
    leds[caelumArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    caelum();
  }

  if (booleancrux == 1) {
    leds[cruxArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    crux();
  }

  if (booleansagitta == 1) {
    leds[sagittaArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    sagitta();
  }

  if (booleanaries == 1) {
    leds[ariesArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    aries();
  }

  if (booleancassiopeia == 1) {
    leds[cassiopeiaArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    cassiopeia();
  }

  if (booleancorvus == 1) {
    leds[corvusArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    corvus();
  }

  if (booleancancer == 1) {
    leds[cancerArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    cancer();
  }

  if (booleanlyra == 1) {
    leds[lyraArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    lyra();
  }

  if (booleanauriga == 1) {
    leds[aurigaArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    auriga();
  }

  if (booleanbigdipper == 1) {
    leds[bigdipperArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    bigdipper();
  }

  if (booleancepheus == 1) {
    leds[cepheusArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    cepheus();
  }

  if (booleancygnus == 1) {
    leds[cygnusArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    cygnus();
  }

  if (booleanorion == 1) {
    leds[orionArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    orion();
  }

  if (booleanlynx == 1) {
    leds[lynxArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    lynx();
  }

  if (booleanlibra == 1) {
    leds[libraArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    libra();
  }

  if (booleanleo == 1) {
    leds[leoArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    leo();
  }
  
  if (booleancapricorn == 1) {
    leds[capricornArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    capricorn();
  }

  if (booleanbootes == 1) {
    leds[bootesArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    bootes();
  }

  if (booleangemini == 1) {
    leds[geminiArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    gemini();
  }

  if (booleancanismajor == 1) {
    leds[canismajorArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    canismajor();
  }

  if (booleanvirgo == 1) {
    leds[virgoArray[plusCount]] = CRGB(0,0,0);
    FastLED.show();
    plusCount = plusCount -1;
    virgo();
  }
  
  break;
  }
  
  delay(200); // Do not get immediate repeat
  FastLED.show();
} //END translateIR


// Function to turn off all LED's and reset the count numbers to -1
void allOff() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("HOW MANY TASKS");
  lcd.setCursor(0,2);
  lcd.print("DO YOU HAVE?");
  plusCount = -1;
  for (int i = 0; i <=NUM_LEDS; i++) {
    leds[i] = CRGB(0,0,0);
  }
  digitalWrite(FOURLED, LOW);
  digitalWrite(FIVELED, LOW);   
  digitalWrite(SIXLED, LOW);
  digitalWrite(SEVENLED, LOW);
  digitalWrite(EIGHTLED, LOW);   
  digitalWrite(NINELED, LOW);
  digitalWrite(TENLED, LOW);
  FastLED.show();
}



// From here will be functions to store the constellations
void caelum() {
  booleancaelum = 1; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==3) {
    leds[caelumArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    caelumComplete();
    FastLED.show();
  }
}

void caelumComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CAELUM");

  for (int i = 0; i<=3; i++) {
    leds[caelumArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[caelumArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }  
}

void crux() {
  booleancaelum = 0; booleancrux = 1; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==3) {
    leds[cruxArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    cruxComplete();
    FastLED.show();
  }
}

void cruxComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CRUX");

  for (int i = 0; i<=3; i++) {
    leds[cruxArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[cruxArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void sagitta() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 1;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==3) {
    leds[sagittaArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    sagittaComplete();
    FastLED.show();
  }
}

void sagittaComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("SAGITTA");
  
  for (int i = 0; i<=3; i++) {
    leds[sagittaArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[sagittaArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void aries() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 1; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==4) {
    leds[ariesArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    ariesComplete();
    FastLED.show();
  }
}

void ariesComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("ARIES");
  
  for (int i = 0; i<=4; i++) {
    leds[ariesArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[ariesArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void cassiopeia() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 1; booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==4) {
    leds[cassiopeiaArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    cassiopeiaComplete();
    FastLED.show();
  }
}

void cassiopeiaComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CASSIOPEIA");
  
  for (int i = 0; i<=4; i++) {
    leds[cassiopeiaArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[cassiopeiaArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void corvus() {
  booleancaelum =0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 1;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==4) {
    leds[corvusArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    corvusComplete();
    FastLED.show();
  }
}

void corvusComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CORVUS");
  
  for (int i = 0; i<=4; i++) {
    leds[corvusArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[corvusArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}


void cancer() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 1; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==5) {
    leds[cancerArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    cancerComplete();
    FastLED.show();
  }
}

void cancerComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CANCER");
  
  for (int i = 0; i<=5; i++) {
    leds[cancerArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[cancerArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void lyra() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 1; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==5) {
    leds[lyraArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    lyraComplete();
    FastLED.show();
  }
}

void lyraComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("LYRA");
  
  for (int i = 0; i<=5; i++) {
    leds[lyraArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[lyraArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void auriga() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 1;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==5) {
    leds[aurigaArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    aurigaComplete();
    FastLED.show();
  }
}

void aurigaComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("AURIGA");
  
  for (int i = 0; i<=5; i++) {
    leds[aurigaArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[aurigaArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}


void bigdipper() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 1; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==6) {
    leds[bigdipperArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    bigdipperComplete();
    FastLED.show();
  }
}

void bigdipperComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("BIG DIPPER");
  
    for (int i = 0; i<=6; i++) {
    leds[bigdipperArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[bigdipperArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}


void cepheus() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 1; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==6) {
    leds[cepheusArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    cepheusComplete();
    FastLED.show();
  }
}

void cepheusComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CEPHEUS");
  
  for (int i = 0; i<=6; i++) {
    leds[cepheusArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[cepheusArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void cygnus() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 1;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==6) {
    leds[cygnusArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    cygnusComplete();
    FastLED.show();
  }
}

void cygnusComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CYGNUS");
  
  for (int i = 0; i<=6; i++) {
    leds[cygnusArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[cygnusArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void orion() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 1; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==7) {
    leds[orionArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    orionComplete();
    FastLED.show();
  }
}

void orionComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("ORION");
  
  for (int i = 0; i<=7; i++) {
    leds[orionArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[orionArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void lynx() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 1; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==7) {
    leds[lynxArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    lynxComplete();
    FastLED.show();
  }
}

void lynxComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("LIBRA");
  
  for (int i = 0; i<=7; i++) {
    leds[lynxArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[lynxArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void libra() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 1;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==7) {
    leds[libraArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    libraComplete();
    FastLED.show();
  }
}

void libraComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("LIBRA");
  
  for (int i = 0; i<=7; i++) {
    leds[libraArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[libraArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void leo() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 1; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==8) {
    leds[leoArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    leoComplete();
    FastLED.show();
  }
}

void leoComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("LEO");
  
  for (int i = 0; i<=8; i++) {
    leds[leoArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[leoArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void capricorn() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 1; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==8) {
    leds[capricornArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    capricornComplete();
    FastLED.show();
  }
}

void capricornComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CAPRICORN");
  
  for (int i = 0; i<=8; i++) {
    leds[capricornArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[capricornArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void bootes() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 1;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==8) {
    leds[bootesArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    bootesComplete();
    FastLED.show();
  }
}

void bootesComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("BOOTES");
  
  for (int i = 0; i<=8; i++) {
    leds[bootesArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[bootesArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void gemini() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 1; booleancanismajor = 0; booleanvirgo = 0;

  if (plusCount ==9) {
    leds[geminiArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    geminiComplete();
    FastLED.show();
  }
}

void geminiComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("GEMINI");
  
  for (int i = 0; i<=9; i++) {
    leds[geminiArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[geminiArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void canismajor() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 1; booleanvirgo = 0;

  if (plusCount ==9) {
    leds[canismajorArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    canismajorComplete();
    FastLED.show();
  }
}

void canismajorComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("CANIS MAJOR");

  for (int i = 0; i<=9; i++) {
    leds[canismajorArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[canismajorArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

void virgo() {
  booleancaelum = 0; booleancrux = 0; booleansagitta = 0;
  booleanaries = 0; booleancassiopeia = 0;booleancorvus = 0;
  booleancancer = 0; booleanlyra = 0; booleanauriga = 0;
  booleanbigdipper = 0; booleancepheus = 0; booleancygnus = 0;
  booleanorion = 0; booleanlynx = 0; booleanlibra = 0;
  booleanleo = 0; booleancapricorn = 0; booleanbootes = 0;
  booleangemini = 0; booleancanismajor = 0; booleanvirgo = 1;

  if (plusCount ==9) {
    leds[virgoArray[plusCount]] = CRGB(255,255,255);
    plusCount = -1;
    FastLED.show();
    delay(1000);
    virgoComplete();
    FastLED.show();
  }
}

void virgoComplete() {
  lcd.begin(16,2);
  lcd.setCursor(0,0);
  lcd.print("VIRGO");
  
  for (int i = 0; i<=9; i++) {
    leds[virgoArray[i]] = CRGB(0,0,0);
    FastLED.show();
    delay(100);
    leds[virgoArray[i]] = CRGB(255,255,255);
    delay(100);
    FastLED.show();
  }
}

 

]]>
Project 2: Laundry Tracker https://courses.ideate.cmu.edu/60-223/f2020/work/project-2-laundry-tracker/ Mon, 02 Nov 2020 23:00:35 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11610 The laundry tracker displays when the washer and dryer are not in use or how long they have been on for when a button is pressed.

The overall view of the laundry tracker display box.

 

 

When the button is pushed the LCD displays the desired text

The laundry tracker is plugged into a 5V source through an opening in the back of the box.

Process :

Decision 1: Add a push button

When the button was pushed the LCD displayed the text about the washer and the dryer. I decided to add this feature so that the screen was not constantly displaying the text. Leaving the display on permanently would have been annoying because this box is only needed when I am looking to do laundry, which is on the order of twice a week.

The push button is wired to the arduino to control the LCD display.

Decision 2: Display the amount of time the washer/ dryer was on

Originally the LCD was going to start a count down timer when the washer or dryer were determined to be on. For example, when the washer was determined to be on a 30 minute timer was going to be started that the LCD would have displayed. I decided to change this to a timer that counted up from zero like a stop watch. I made this decision because the washer and the dryer do not always run for a set time. The run times are determined by the who ever is doing laundry. There was no way for me to determine this using accelerometers so I decided to count up time instead. The information displayed on the LCD would more accuracy describe the state the washer and the dryer were in.

 

Illustrates how the button and the LCD were arranged on the inside of the display box so that the wires were all hidden and the outside of the box looked neat.

The signal values the accelerometer was reading when the washer was off (left) and when the washer was off (right). The y-axis is the signal reading and the x-axis is index of the signal value. This was use to figure out when the washer (and with other graphs, the dryer) was on or off.

The process of making the wires neat and organized for the electronics that went in the basement with the washer and dryer.

Discussion:

The only piece of written feedback I got said in part, “I think with a higher sampling rate and some digital signal processing this could be generalized to detect all sort of mechanical processes.  You could even attempt human activity recognition by measuring the floor vibration and collecting data on the characteristic signals of daily life.” I disagree with the second part of this statement. I disagree because of the data I recorded from testing the accelerometers on my washer and dryer. When I sampled at the fastest rate over an extended period of time it was barely able to determine whether the washer or dryer was on. I don’t believe the accelerometers, at least how they were arranged for my project, are sensitive to measure something like the vibrations produced from people walking. 

In this project I think that overall I did a good job and I am happy with the final product. My project worked how I intended. It was able to sense when the washer or dryer was on and send that information to an LCD to display how long each machine was on for at that moment. Making everything look nice was hard because that is not one of my strengths and I focused a lot on making all the electronics and code work properly. However it was also really enjoyable to make a presentable box from things I found around my house and a really good learning experience. Furthermore, processing the data from the accelerometer proved to be much harder than I thought it would be. The problem was that the signals from when the machines were on and off were similar. I had to take a range of values and compute the deviation to determine if the machines were on or off. From this I learned how to deal and process signals from sensors in a way to get out the desired information.  

Given that I made the display box out of cardboard I found in my house, I think that it looks pretty neat and put together. For the next iteration I would like to laser cut the display box to make it neater and more presentable. I would also use stronger radio modules because when the display box was in my room it could not pick up the radio signal from the washer and dryer. The display box could pick up the signal down the hall from my room but the cutoff was before my room. It would be nice to be able to leave the box in my room where my laundry bag is rather than in the hallway. 

Schematic:

Emitter

Electronic schematic for the transmitter setup that was placed with the washer and the dryer.

Receiver

Electronic schematic that depicts the electronics that received the data and was housed in the display box.

Code:

Emitter

/*
Title: Laundry Tracker
(emitter)
By: Mimi Marino

Description: This code takes readings from an 
accelerometer attached to a washer and an
accelerometer attached to a dryer. 100 readings are 
taken at a time for both the washer and the dryer and
the max and min values are determined. If the range of
the max min values is large enough it is deteremined 
that particular machine is on. The radio module then 
sends out a signal that indicates if both, only the 
washer, only the dryer or neither is on. 

Pin Mapping:

 pin   | mode   | description
 ------|--------|------------
  7      output   Radio - CE
  8      output   Radio - CSN
  11     output   Radio - MOSI
  12     output   Radio - MISO
  13     output   Radio - SCK
  A0     input    Accelerometer_W
  A1     input    Accelerometer_W
  A2     input    Accelerometer_W
  A3     input    Accelerometer_D
  A4     input    Accelerometer_D
  A5     input    Accelerometer_D

Credit:
-starter code for NRF24L01 radio transmitter
https://github.com/robzach/Empathy_Machine/blob/master/development/transmit_analog_read/transmit_analog_read.ino

-How to wire NRF24L01 radio module
//https://howtomechatronics.com/tutorials/arduino/arduino-wireless-communication-//nrf24l01-tutorial/


*/
#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>

const int XPIN_W = A0;
const int YPIN_W = A1;
const int ZPIN_W = A2;

const int XPIN_D = A3;
const int YPIN_D = A4;
const int ZPIN_D = A5;

const int RADIO_CE = 7;
const int RADIO_CSN = 8;
RF24 radio(RADIO_CE, RADIO_CSN);
const byte address[6] = "00001";

void setup() {
  // set up radio
  Serial.begin(9600);
  radio.begin();
  radio.openWritingPipe(address);
  radio.setPALevel(RF24_PA_HIGH);
  radio.stopListening();

  pinMode(XPIN_W, INPUT);
  pinMode(YPIN_W, INPUT);
  pinMode(ZPIN_W, INPUT);
  pinMode(XPIN_D, INPUT);
  pinMode(YPIN_D, INPUT);
  pinMode(ZPIN_D, INPUT);
}


void loop() {
  int on=0;
  int count=0;
  int maxValueW=0;
  int minValueW=1023;
  int maxValueD=0;
  int minValueD=1023;

  //will hold current sensor reading
  int currentWasher;
  int currentDryer;

  //takes 100 reading from both the washer and dryer
  //sensors and finds the max/ min of the 100 values
  while (count<100){
    //avg of the X, Y and Z readings
    currentWasher = (analogRead(XPIN_W) + analogRead(YPIN_W) + analogRead(ZPIN_W))/3;
    currentDryer = (analogRead(XPIN_D) + analogRead(YPIN_D) + analogRead(ZPIN_D))/3;
    if (currentWasher<minValueW){
      minValueW=currentWasher;
    }
    if (currentWasher>maxValueW){
      maxValueW=currentWasher;
    }
    if (currentDryer<minValueD){
      minValueD=currentDryer;
    }
    if (currentDryer>maxValueD){
      maxValueD=currentDryer;
    }
    count++;
  }

  //when the range btw max and min is greater than 2
  //the machine is determined to beon
  if ((maxValueW-minValueW >2) and (maxValueD-minValueD >2)){
    //both washer and dryer are on
    on=6;
  }
  else{
    if (maxValueW-minValueW >2){
      //just washer is on
      on=3;
    }
    else if (maxValueD-minValueD >2){
      //just dryer is on
      on=2;
    }
    else {
      //neither is on
      on=5;
    }
  }
  // transmit values
  radio.write(&on, sizeof(on));
}

Receiver

/*
Title: Laundry Tracker
(reciever)
By: Mimi Marino

Description: I this code we recieve information from 
another radio module. That information says if the 
washer, or dryer are on or off. With that information 
this code calculates how long each has been on for. 
When a button is pressed the LCD displays this 
information in a easy to read way so the user knows
if the washer and dryer are being used and and how 
long they have been on for so far.

Pin Mapping:

 pin   | mode   | description
 ------|--------|------------
  7      output   Radio - CE
  8      output   Radio - CSN
  11     output   Radio - MOSI
  12     output   Radio - MISO
  13     output   Radio - SCK
  3      output   LCD - rs
  4      output   LCD - enable
  10     output   LCD -db4
  2      output   LCD -db5
  5      output   LCD - db6 
  6      output   LCD - db7
  9      input    button 

Credit:
-starter code for NRF24L01 radio reciever 
https://github.com/robzach/Empathy_Machine/blob/master/development/read_radio_signal/read_radio_signal.ino

//-How to wire NRF24L01 radio module
//https://howtomechatronics.com/tutorials/arduino/arduino-wireless-communication-//nrf24l01-tutorial/
*/

#include <SPI.h>
#include <nRF24L01.h>
#include <RF24.h>
#include <LiquidCrystal.h>
//LiquidCrystal(rs, enable, db4, db5, db6, db7) 
LiquidCrystal lcd(3, 4, 10, 2, 5, 6);

const int BUTTON_PIN = 9;
const int RADIO_CE_PIN = 7;
const int RADIO_CSN_PIN = 8;
RF24 radio(RADIO_CE_PIN, RADIO_CSN_PIN);
const byte address[6] = "00001";
unsigned long timer = 0;
int displayClockW=0;
int displayClockD=0;

void setup() {
  Serial.begin(9600);
  lcd.begin(16, 2);
  radio.begin();
  radio.openReadingPipe(0, address);
  radio.setPALevel(RF24_PA_HIGH);
  radio.startListening();
  //initiliazes the button pin as a pullup pin
  pinMode(BUTTON_PIN,INPUT_PULLUP);
}

void loop() {
  //get radio input from transmitter
  if (radio.available()) {
    int readVal;
    radio.read(&readVal, sizeof(readVal));
    //only executes every minute
      if (millis() -timer >= 60000){
        lcd.setCursor(0,0);
        //readVal=6 if the washer and dryer are on
        //readVal=3 if just the washer is on
        //readVal=2 if just the dryer is on
        //readVal=5 if neither are on

        //updates the washer clock 
        if (readVal%3==0){
          displayClockW +=1;
        }
        else{
          displayClockW=0;
        }
        
        //updates the dryer clock
        if (readVal%2==0){
          displayClockD +=1;
        }
        else {
          displayClockD=0;
        }
       timer= millis();
       }
    }
    //When the button is pushed, LCD is updated
    //with acurrate information about the washer 
    //and dryer 
    //when button is not pushed the LCD displays nothing
    
    //digitalRead(BUTTON_PIN)==0 is true when 
    //the button is being pressed
    if (digitalRead(BUTTON_PIN)==0){
      lcd.setCursor(0,0); 
      //when the washer is off
      if (displayClockW==0){
        lcd.print((String)"Washer: Free!");
      }
      //when the washer is on
      else{
        lcd.print((String)"Washer: "+displayClockW);
      }
      lcd.setCursor(0,1);
      //when the dryer is off
      if (displayClockD ==0){
        lcd.print((String)"Dryer:  Free!");
      }
      //when the dryer is on
      else{
        lcd.print((String)"Dryer:  "+displayClockD);
      }
    }
    else{
      lcd.clear();
    }
  }

 

 

]]>
Posture Corrector https://courses.ideate.cmu.edu/60-223/f2020/work/posture-corrector/ Mon, 02 Nov 2020 03:20:17 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11671 This assistive device uses spine position detection and tension sensing to detect slouching in order to remind you and ensure your torso is always held in a correct and healthy posture.

Final Product

The above video shows the posture corrector in action, where my hand movements simulate a person slouching, and the faint vibrating noise being the alert for the wearer to correct their posture.

Posture Corrector in action being worn on my back

Clearer picture of the overall finished product

Closeup of the accelerometer used for position detection, the conductive thread interweaved with the middle strap for tension detection, and the pancake motor for a vibration alert

Process

A lot of thought went into how exactly to detect slouching for my assistive device. I ended up with trying two different measures, separated into version 1 (V1) and version 2 (V2) based on their complexity of implementation. V1 was a simple accelerometer to detect the angle of my spine, and V2 involved somehow using tension to detect when my shoulders were slumped forward. The idea that developed was that having either method of measurement would be acceptable for the device, but having both would be nice.

Beginning stages of my ideation for the posture corrector – a sketch

In my ideation sketch, I purposely left the tension sensor area of the sketch vague and blank because I was unsure how to approach this, as it was the most complex part of my assistive device. After looking into load cells and other related sensors, I was directed to a homemade version using conductive thread that changed resistance depending on how stretched out it was. This significantly increased the complexity of the sensor, which later affected the effectiveness of my final outcome.

The initial stages of building – the general shape structure is there and I began wiring/testing code for the electronics to mount

Wiring up all the other parts and completing V1 was very straightforward, however when actually implementing the tension sensor as a V2 feature, several complication and design decisions changed as a result. I was going to use an elastic band originally to connect the two platform pieces, but the need for the conductive thread to be interwoven in convoluted loops resulted in me using finger knitting as the final process to create all the straps to accommodate the homemade sensor design.

A shot of the device almost completely assembled and mounted – only the tension thread was left to wire up completely

Discussion

Upon reflect on my overall project and the process through which I arrived at the final end result, I was definitely challenged in various aspects along the way. From the initial ideation stage to actually building the device on my own, given the amount of creativity and freedom we were given with the project, I realized the actual difficulty in translating an idea into a solid implementation plan and actually building it according to the plan.

While I am proud of the fact that I was able to build almost everything according to the original idea after I finalized my sketch, especially in terms of functionality, I was very dissatisfied with my general ability to build something sleek and elegant. My end product functioned properly and matched my sketch in terms of the components, with the only shortcoming being the complex tension sensor working unreliably at times, but I feel the general aesthetic was clunky and looked like it was an inconvenience. Coding and wiring came easily to me, but this made it apparent that a significant limitation of mine was designing.

In fact, the comments I received as critique both concerned the aesthetics of the product. Someone suggested that “this could be awesome integrated into a jacket or some type of clothing for more discrete wearing,” which I recognized as a potential solution to help improve the appearance of the product and make it more pleasing to view. Another person asked me “Any ideas for organizing the wires in your project? Is there any danger of getting disconnected while you are moving around?,” which prompted me to think about the fact that wiring placement was definitely a detail I would pay more attention to in the future for general design considerations for the user.

Other than these specific suggestions, looking back, I definitely would have spent more time in the planning stage on all the miniscule details concerning design decisions specifically, and put more effort and importance into the prototype, especially for the base structure that would hold everything together.

Technical Information

Schematic:

Schematic diagram for posture corrector

Code:

/*
 * Project 2: Assistive Technology
 * Arleen Liu
 * 
 * Collaboration: Plusea, for the tension sensor idea using
 * conductive yarn.
 * 
 * Challenge: Figuring out how to implement the tension sensor in
 * a stable and consistent manner to maximize its effectiveness
 * 
 * Next Time: For projects with many components, test each 
 * individual part more thoroughly to make the assembly portion
 * of the building process more smooth.
 * 
 * Description: An accelerometer detects the angle of the spine 
 * and a tension sensor built from conductive thread uses the 
 * difference in resistance to detect shoulder slumping, and if 
 * either measurement goes beyond a certain tuned threshold, the
 * pancake motor vibrates to give an alert.
 * 
 * Pin mapping: 
 * 
 * pin | mode | description
 * ----|------|------------
 * 6    OUTPUT pancake motor
 * A0   INPUT  accelerometer 
 * A1   INPUT  accelerometer 
 * A2   INPUT  accelerometer 
 * A3   INPUT  tension sensor
*/ 

const int X_PIN = A2;
const int Y_PIN = A1;
const int Z_PIN = A0;
const int YARN_PIN = A3;
const int MOTOR_PIN = 6;

// Volts per G-Force
const float sensitivity = 0.206;
const float threshold = -3.92;
const int threshold2 = 700;

void setup() {
  //Initializing pins
  pinMode(MOTOR_PIN, OUTPUT);
  //analogReference(EXTERNAL);
  pinMode(X_PIN, INPUT);
  pinMode(Y_PIN, INPUT);
  pinMode(Z_PIN, INPUT);
  pinMode(YARN_PIN, INPUT);
  
  //Initializing other elements   
  Serial.begin(9600);
}

void loop() {

  float x;
  float y;
  float z;
  
  // Read acceleration pins and handle sensitivity
  x = (analogRead(X_PIN) - 512) * 3.3 / (sensitivity * 1023);
  y = (analogRead(Y_PIN) - 512) * 3.3 / (sensitivity * 1023);
  z = (analogRead(Z_PIN) - 512) * 3.3 / (sensitivity * 1023);
  Serial.print("x: ");
  Serial.print(x);
  Serial.print(", y: ");
  Serial.print(y);
  Serial.print(", z: ");
  Serial.println(z);
  Serial.println(analogRead(YARN_PIN));

  int aDist = sqrt(pow(x, 2) + pow(y, 2) + pow(z, 2));

  if (y > threshold || analogRead(YARN_PIN) > threshold2) {
    digitalWrite(MOTOR_PIN, HIGH);
  } else {
    digitalWrite(MOTOR_PIN, LOW);
  }

  delay(10);
}

 

]]>
A Bossy Box https://courses.ideate.cmu.edu/60-223/f2020/work/a-bossy-box/ Sun, 01 Nov 2020 21:44:37 +0000 https://courses.ideate.cmu.edu/60-223/f2020/work/?p=11605

Final Bossy Box with a front-facing display featuring an LCD screen and two buttons to control the interior circuit

OVERVIEW

The Bossy Box is a personal assistive device that helps the user (in this case, me) to decide on what activities to do once work is done. The box allows you to choose between several categories of activity types by turning the knob on the left and then once you press the button on the right, the box will give you a random activity to do within that activity type!

Toggle through the Main Categories by turning the right knob

Get a random Activity from your selected category by pushing the left button

A more legible video of what happens on the LCD screen as you interact with the box

The final Bossy Box – its size is about 7×4 inches

The Bossy Box was designed to take visual cues from classic arcade consoles, with their distinct color blocking and large buttons. I wanted to bring a more playful aesthetic into this device to drive home its more game-like nature

PROCESS

My work on this project began like most design projects do, with a brainstorm and sketch session meant to generate as many ideas as possible! At the end of this, I decided to go with an Activity Box concept for my final device, as I am indecisive and never know what to do with my free time once I have it.

Concept sketches of my top two ideas – I went with the Activity Box option which then became the Bossy Box

From here, I started by trying to figure out the software needed to get this project to operate. This was because I have a background in physical fabrication and am fairly comfortable with hardware wiring, but writing the software is a skill that I need to improve upon a lot. As I expected, I encountered several challenges when trying to get my software to work in the way in which I wanted.

I started my process by putting together my circuit hardware to code. I opted to do this over just creating a TinkerCAD simulation and coding on there as it would at least give me a chance to get a bit more ahead with my project and wouldn’t put me that behind in terms of my timeframe to complete my software code by. I’ll touch upon this a bit more later, but this circuit was made to test the functionality of the software only, and so the placement of the wires and input components wasn’t taken into account and would have to be reworked later.

When I started the code, the first issue that I encountered was related to arrays. Because I wanted to print full phrases on the LCD screen I was using String Array types, however, these didn’t print the way I wanted to on the LCD screen. My serial feedback for debugging was showing that the Arduino was properly incrementing through the array with the potentiometer input, but the LCD wasn’t showing that. The video below shows one example of how the display was showing me the output.

After talking to our professor, Zach, I learned that String Array types are a bit tricky in C at times, and so many people opt for Character Arrays instead. With some collaboration with him and my own research into these arrays, I changed my code to use Char data types instead and this began to work fairly smoothly. At this point, I was able to toggle through the Main Arrays and retrieve a value from the Sub-Arrays by pressing the button. However, this value wasn’t a truly random one and I would retrieve the same output each time I pressed the button.

The working circuit at its prototype phase

My next challenge was to work through the randomSeed function, which enables the Arduino to actually give you a more random output. To get this to work properly, I worked with our professor who explained how you can get the Arduino to analogRead an inactive analog pin to get a generally random value between 0-1023 which would essentially provide a wide enough range of seed values to have my box output a different Sub-Array value each time I pressed the button. This had some issues at first, where my screen would just print multiple random array items at once making the output illegible. I had to code in a hard stop (which you can see as my last line of code in the code section of this documentation) which wasn’t the most elegant solution in the world, but with the way that I structured my code as an if-else sequence, it was the simplest solution. Looking forward, I want to work with Switch-cases or some other type of logic structure which will allow me to create a more clean code that doesn’t require this type of solution. Perhaps, as a next step, I will work on re-writing my code to follow such logic and then upload that into my box instead.

Moving onto my process of physical construction and circuit integration, I had a lot of fun creating the box and trying to get the circuit to work with the user interacting with non-circuit components! I began by refining my concept for how I wanted this device to look; opting for a color-blocked style reminiscent of the arcade consoles I played with as a kid. Part of why I wanted to make this activity box is to turn the action of selecting an activity into a game itself and bring some playful elements into an every-day device. Therefore, I thought that this semi-retro design direction was fitting of my intent.

Sketches to further consider methods of physical construction and aesthetic style

Based on the materials I had access to, I decided to use two different types of acrylic to create my box. I implemented some box joints into each part, laser cut them, and began to construct!

Begining construction of my laser-cut parts

Once I began to implement my circuit into the physical box itself, I ran into a wiring issue. Not only was it proving difficult to fit all of the wires within the box dimensions that I had chosen, but the actual wiring of my still prototype circuit was not conducive to the interactions that I wanted to create (the button was still in the middle of a breadboard and all of the wires were tangled together making it harder to move the components around). At this point, I essentially took apart my circuit and rewired it so that each input component was on its own tiny breadboard and the wires were all neatly arranged in a way that allowed me to bend them into place without worrying too much about them getting unplugged or damaged.

Begining to incorporate my circuit into my physical box. I had to attach two smaller breadboards to the circuit and rearrange all of the wires to allow for optimal interaction and fit.

Once I did that, it was just a matter of taping the electronics into place and then using a little bit of hot glue to attach the potentiometer to the acrylic knob (which had a measured hole in it to house the potentiometer’s included knob) and a spring to the circuit button so that the exterior acrylic button could successfully press this circuit component.

I kept the back panel unglued so that way I can reuse the Arduino or change the battery at my leisure (but the box joints fit snugly enough that this back panel doesn’t pop out of place without you wanting it to).

DISCUSSION

This project was a lot of fun to create overall, despite having some set-backs and snafus along the way. I believe that this project was, in many ways, successful; however, it was only so because I designed it within what I deemed to be my own capabilities without the need for too much assistance along the way. By this, I mean that I wanted to give myself a reasonable challenge, where I would learn some new software skills along with gaining more functional hardware knowledge along the way, but not create a challenge to the point of where I would be unsure if I would be able to complete the project/have it function totally properly.  Therefore, ultimately, I do wish I pushed the concept a bit further and increased its complexity. 

Some of the comments on this project that I received delved into that aspect of increasing the complexity a bit, which I appreciated. One student within my cohort noted that “…I can imagine this at a more complex scale with multiple sub-arrays that would make it feel even more random and fun!”.  I think that this would be a great way of making selecting an activity into an activity in-and-of-itself (which was part of the purpose of creating this as a physical device rather than an app – being able to play with buttons and interact with an arcade-console-inspired device is part of the fun!) by making more subarrays under each category that you can explore. Perhaps there could be a series of subcategories that you can choose from underneath the main categories and then after a few levels of these category-based selections, you could then get your more specific random output (like a tree of arrays). This would certainly be more complex, but 

Another student said that perhaps size could be another way to iterate upon this concept in the future “…I can definitely emphasize with not knowing what to do and having this device would help a lot. I am curious if it would be possible to have a smaller device for me to carry around during the day in my bag and using every day…”. I think that having this on multiple scales going as small as a keychain, or at least making it more portable than an acrylic box, could be an interesting concept for this device. Perhaps if it was portable and readily programmable, you could take it with you and set the types of activities to chose from to be more context-specific. For instance, if you were going on a camping trip, you could change the activities to be relevant to that trip rather than having them be the general, mostly indoor, activities that I currently have loaded into the device. I think that trying to get all of the components to fit within a keychain-sized piece might be a bit too complicated for my current capabilities, but I can see making a snap-fit 3D printed housing that’s about 4×4 inches with all of the components being feasible! If I have more time in the upcoming semester while I still have access to high-resolution 3D printers, I would like to see try this out as an iteration of my current project because I can see myself using this when doing outdoor activities with friends ( post-Covid, of course). 

Looking back at my project process and final device, I am very happy with the overall look of it and am glad to say that I have used it a handful of times in the past week since it’s completion, which makes it a success in terms of it being useful. Throughout the project process, I learned a lot about different types of arrays and other forms of logic that I had not been exposed to, but am excited to implement into future projects! I think that despite this project perhaps not being the most ambitious out of the bunch, it was a great way for me to explore this realm of physical computing by myself and improve my problem-solving skills, as things didn’t go to plan quite a few times.

FURTHER TECHNICAL INFORMATION

Circuit Schematic Diagram

PROJECT CODE
/*
 *Project 2: An Assistive Device for someone you know well
* Dani Delgado (ddelgad1) 

* Collaboration: To complete this project, I had to collaborate closely with my professor Zach to gain a better understanding of 
* character arrays and generating random outputs from these said arrays. Specifically, the random seed portion of generating these
* outputs. I also used online refrences in order to learn more about randomness in code and arrays on my own. These sources are:
* https://programmersheaven.com/discussion/57997/how-do-you-choose-a-random-item-from-an-array - For learning about randomness
* https://warwick.ac.uk/fac/cross_fac/complexity/newstudents/intro/introtocomputing3.pdf - For learning about randomness logic
* https://www.arduino.cc/reference/en/language/variables/data-types/array/ - For learning more about array syntax
*
* Description: The code below combines a potentiometer and button input to change a LCD display. The potentiometer input allows one to
* scroll through different array options by incrementing through the "main category" array and then having the LCD print each array item 
* (which are strings of characters, for this project) as you do so. Then, you can get a random activity strings out of each of these larger categories
* if you press a button. These activity category arrays contain between 9 and 11 array items (strings) that are printed on the LCD at random when you press 
* the button while on a category item from the "Main category" array. 
* 
* 
*Pin mapping:
* pin | mode | description
* ----|------|------------
* A5  |INPUT | Potentiometer pin with an analog input 
* 8   |INPUT | Button digital input 
 */

#include <LiquidCrystal.h>
#include <stdlib.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

//pin inputs
int POTPIN = A5;
int BUTTONPIN = 8;

//Create the overall category Array
char category[][17] =
{"Self Care", "Create", "Learn Something", "What's Cookin'?", "Qs Love to Watch", "Boolin"};

//Create arrays for the different categories
char selfCare[][17] =
{ "Yoga Flow", "Get ur face BEAT", "Go on a walk!", "Facemask + puff", "Pilates Calendar", "Make tea",
  "FM Sweat Sesh", "Paint nails", "strength workout"
}; //selfCare has 0-8 items

char create[][17] =
{ "Greeting Cards", "Fairy Garden", "Fingerpaint", "Draw a Comic", "BIG Painting", "Draw a Portrait", "Jounral", "FunProductDrawin",
  "Foam Carving"
}; //create has 0-8 items

char learnSomething[][17] =
{"Vocab Unit", "Read 4 pleasure", "Wiki rabbithole", "Play guitar", "Duolingo", "Math Speed Test!"}; // learnSomething has 0-5 items

char whatsCooking[][17] =
{ "Bake Cookies", "Banana Bread", "Vegan Muffins", "Make a Mug Cake", "Eloborate Pasta", "Bake Fish&Veg", "Bake a CrazyCake",
  "Scone Time!", "Quiche or fritta", "BROtien Smoothie"
}; //whatsCooking has 0-9 items

char watchQueen[][17] =
{ "Vine Comp", "Anime u weeb", "Phone List Movie", "Harry Potter", "Stand-up", "80s Spoof Movie", "Horror Movie", "Binge-Worthy TV", "Dani's HS faves",
  "Trixie Mattel", "Oscar Film ", "Unsolved Mystery", "TotalDramaIsland"
}; //watchQueen has 0-12 items

void setup() {

  pinMode(POTPIN, INPUT);
  pinMode(BUTTONPIN, INPUT);

  lcd.begin(16, 2);
  Serial.begin(9600);

  //generate the randomSeed
  //this is an analogRead value in order for the Arduino to use any number between 0-1023 as the seed value, creating a different random output with each button press
 
  long int randVal = analogRead(A1); 
  randomSeed(randVal);
}


void loop() {

  int potVal = analogRead(POTPIN);
  int toggle = map(potVal, 0, 1023, 0, 6); //map the value of the potentiometer inputs to the total amount of array values within the Main Catergory arry
 
  String catVal = category[toggle]; //allow the Arduino to access the mapped value in order to increment through the array by turning the potentiometer 
  
  //Serial feedback for debugging
  Serial.println(toggle);
  Serial.println(catVal);

  bool buttonState = digitalRead(BUTTONPIN); //when button is pressed, the code should give you a random string from the corresponding array

  if (buttonState != true) {
    // If the button has not been pressed, have the LCD print a value for the Main Category array
    lcd.setCursor(0, 0);
    lcd.clear();
    lcd.print(catVal);
  
    Serial.println("Button state is false"); // serial feedback for debugging 
  }
  else if (toggle == 0) {
    //get a random number from the selfCare Subcateroy Array when the potentiometer is accessing the first Main Category array item 
    int careSize = 9;
    int randCare = random(0, careSize);
    Serial.println(randCare);

    lcd.clear();
    lcd.print(selfCare[randCare]);

  }
  else if (toggle == 1) {
    //get a random item from the Create Subcategory Array when the potentiometer is accessing the second Main Category array item 
    int createSize = 9;
    int randCreate = random(0, createSize);
  
    lcd.clear();
    lcd.print(create[randCreate]);

  }
  else if (toggle == 2) {
    //get a random item from the Learn Somethin' Subcategory Array when the potentiometer is accessing the third Main Category array item
    int learnSize = 6;
    int randLearn = random(0, learnSize);

    lcd.clear();
    lcd.print(learnSomething[randLearn]);

  }
  else if (toggle == 3) {
    //get a random item from the What's Cookin' Subcategory Array when the potentiometer is accessing the fourth Main Category array item
    int cookSize = 10;
    int randCook = random(0, cookSize);

    lcd.clear();
    lcd.print(whatsCooking[randCook]);
   
  }
  else if (toggle == 4) {
    //get a random item from the Queen's Who Love to Watch Subcategory Array when the potentiometer is accessing the fifth Main Category array item
    int queenSize = 13;
    int randQueen = random(0, queenSize);
    Serial.println(watchQueen[randQueen]); 
    lcd.clear();
    lcd.print(watchQueen[randQueen]);
    }
    
  //Force stop the LCD printing from displaying multiple random items at once
  while (digitalRead(BUTTONPIN)) {
  }
}

 

 

 

]]>