rolandog@andrew.cmu.edu – Intro to Physical Computing: Student Work https://courses.ideate.cmu.edu/60-223/f2018/work Intro to Physical Computing: Student Work Sun, 16 Dec 2018 16:38:47 +0000 en-US hourly 1 https://wordpress.org/?v=4.9.25 Paper Organizer by Team MARYa: Final Documentation https://courses.ideate.cmu.edu/60-223/f2018/work/paper-organizer-by-team-marya-final-documentation/ https://courses.ideate.cmu.edu/60-223/f2018/work/paper-organizer-by-team-marya-final-documentation/#respond Fri, 14 Dec 2018 22:51:00 +0000 https://courses.ideate.cmu.edu/60-223/f2018/work/?p=5359 Introduction:

We are Team MARYa, (Mohan, Andrea, Roly, Yingyang) a group of four Carnegie Mellon University students taking an Introduction to Physical Computing course. For our final project, we were given the task of pairing up with an older person, Maria and creating a useful device for her that implements an Arduino and other physical computing elements. At our initial meeting, we discovered Maria had a habit of throwing papers on the floor instead of organizing them. Keeping this in mind, we created a prototype  for a shelf that would sort your papers for you. Be warned, our prototype is very different from our final product which is documented here. Due to some constraints, we had to take our project in a different direction.

What We Built:

This shelf is helping Maria to easily organise her documents in her home working space. Each section on the shelf has a category with a number and match to the button. The shelf section will be blink by pressing the button. It will be stopped blinking by receiving the document in the right shelf section.

 

Overall

 

Botton Layouts

 

Shelf Construction

 

OLYMPUS DIGITAL CAMERA

 

Maria is busy working in her home office. She wants to quickly organise her documents on her messy desk. After reading her latest bank invoice, she presses the button “3”, which identifies as “Finance” section. She saw the section 3 on the shelf starts to blink so she put the letter into the right section. All the action takes Maria less than 2 secs. Maria is so happy that she can quickly organise her document without thinking where is the “Finance” section. Maria starts to like to organise her documents and she can finally find her documents in the right category in her shelf!

 

How We Got Here:

As was previously mentioned, our project took a sudden turn near the end of the process. We realized that the mechanical aspects of our filing cabinet (including a small elevator to place papers in shelves) were proving far too finicky to finish on time.

Roly here is removing the old supports for the elevator mechanism after trying to solve mechanical issues.

Due to the nature of timing belts and how precise they need to be to produce the motion desired, the elevator was experiencing problems with keeping the belts tensioned enough. These belts were essential to the elevator’s movement since they provided the force that spun the lead screws, which in turn lifted or lowered the tray.

With this big change, the team needed to decide on an alternative option that kept the spirit of the idea. The first idea came almost right away. We wanted to help Maria make sure her papers got filed, but we opted to make it a device to help modify behavior rather than perform the task itself.

This was taken moments after we decided that we had to change our idea. Written on the table were some notes on the logistics of the new idea.

These LED’s became a central part of our new idea.

This is a sensor similar to the one we used to detect when paper was placed in a shelf. The clear bulb emits infrared light, and when an object bounces it back to the black bulb, the sensor knows how far the object is.

Our device was changed slightly to include LED lights on the side of the shelves. These lights would illuminate the shelf where Maria was supposed to put a piece of paper (she would first pick the filing category with a button). Inside of the shelf, some device would sense that she put the paper there and turn off the light. This version of the device was now more focused on reinforcing good habits of paper filing. By having Maria file her papers immediately, we were trying to break the habit of simply leaving it for later. But one problem was left: how to incentivize this.

This was our inspiration for an incentive: a gumball machine. Maria had wanted some sort of candy dispenser before, so we figured we could bring it back in a similar form to this.

Based on one of our first meetings with Maria, we decided to use candy as the incentive for filing. Maria had initially proposed that we make her an automatic candy dispenser, but we decided upon our current project since it seemed more useful to her. By bringing back the candy idea, we added a little inside humor between us and created a reward system for filing.

First test of the lighting and paper detection!

Once we got the shelf lighting and paper detection system working, we began designing the reward system. It was going to be a simple box on top of the shelf that contained a mechanism to dispense candy. Unfortunately, when we were going to laser cut the box, the USB that its file was on got corrupted and we lost it permanently.

In the end, we were only able to get the lighting and paper detection system working, and it was very finicky. We were slightly disappointed to the project turn out like this, but we simply did not have time to fix our ranging technical issues by the day of the presentation.

The final circuit board for the shelving unit. It was somewhat cramped, but it worked (mostly).

Throughout this process, we learned a lot about working on teams with vastly different skill sets. One of our members was an architect, one was a costume designer, and the other two were Information Systems students. We had to be very thorough in our meetings to ensure that this very widespread team was always on the same page. We also had to learn to keep frustrations in check, seeing as we were working hard and late up until the last minute.

Patience was key throughout this whole process. We were working very hard and had to make sure not to clash heads.

Overall, this project was a semi-success in that we were able to finish something for Maria. We would have been disappointed to not have anything at all to present to her or the class. However, through diligence and taking responsibility for our own sections of work, we pushed through to the end.

Conclusions and Lessons Learned:

Assemble process

From the problems we as a team encountered at final assblem stage, we learn a important lesson that for the problem we never worked before, there should be enough time set aside for it, different parts could be delivered late, for example the belt we had at last minute won’t fit the mechanism we already had. Also building a quick prototype from what we have might be a good idea to identify problems need to be resolved. If time constrain is a issue, different scenarios could be developed in advance.

Final Presentation feedback

We get a lot of useful feedback during crit that would help us identify problems and know better about outside opinion, overall people like the project. Although we change our idea at last minute, it is actually from the rewarding system idea we had long time ago. In terms of helping Maria on her habit, reminding system would potentially help her more on change her habbits, as she wrote in comment, it’s more a human/motivation issue than a mechanical issue, how we address it is very interesting, and how the client would use it is a very important post-evaluation part too. There are advice from students suggesting that visual reminder(blinking LED)might be substitued by audio which is more “annoying” and some people feel like bliking LED is not very comfortable to them, therefore this is a debating point which might need to discuss with our “client”. Right now the shelf is not painted and LED stripe is exposed, both need to be worked on in future.

Overall, our team learned a lot from this project. We worked closely with Maria trying to identify her needs in daily life that herself might even not aware of. We tried to start from the point of “organizing paper work” and develop a system/mechanism that would work to help her better on it. We stumbled on some issues and succeed on other issues, both are good lessons we learned.

 

Technical Details:

/*
 * Lighted Paper Shelf by Andrea Chung
 * 
 * When a button is pushed, its corresponding shelf section will
 * light up and blink until a photocell sensor reads that something 
 * has been inserted into that shelf.
 * 
 * The circuit:
 *  - 6 photocell sensors attached to pins A0-A5
 *  - 6 corresponding buttons attached to pins 2-7
 *  - LED strip attached to pin 8
 */

//photocell sensor pins
int sensor1 = A0; 
int sensor2 = A1;
int sensor3 = A2;
int sensor4 = A3;
int sensor5 = A4;
int sensor6 = A5;
//button pins
const int BUT1 = 2;
const int BUT2 = 3;
const int BUT3 = 4;
const int BUT4 = 5;
const int BUT5 = 6;
const int BUT6 = 7;
//filtering values for the sensor readings
float avgVal = 0;  // this variable, of type float (decimal), holds the filtered sensor value
const float PREV_WEIGHT = 0.8; // this variable, of type float (decimal), determines the previously filtered value's weight.
const float CUR_WEIGHT = 1 - PREV_WEIGHT; 
const float threshold = 5.0;
//timer setup for blinking LEDs
unsigned long previousMillis = 0;
const long interval = 1000;
//indicattors for light on or off
bool on1 = false;
bool on2 = false;
bool on3 = false;
bool on4 = false;
bool on5 = false;
bool on6 = false;

//LED strip setup
#include <PololuLedStrip.h>

PololuLedStrip<8> ledStrip; 
// set up how many LEDs on the strip you would like to control
#define LED_COUNT 48
rgb_color colors[LED_COUNT];

void setup() {
  //setup sensor pins as input
  pinMode(sensor1, INPUT);
  pinMode(sensor2, INPUT);
  pinMode(sensor3, INPUT);
  pinMode(sensor4, INPUT);
  pinMode(sensor5, INPUT);
  pinMode(sensor6, INPUT);
  //setup button pins as pullup 
  pinMode(BUT1, INPUT_PULLUP);
  pinMode(BUT2, INPUT_PULLUP);
  pinMode(BUT3, INPUT_PULLUP);
  pinMode(BUT4, INPUT_PULLUP);
  pinMode(BUT5, INPUT_PULLUP);
  pinMode(BUT6, INPUT_PULLUP);
  Serial.begin(9600); // starts serial communication at 9,600 baud (the rate)
}

void loop() {
  //read button values
  int but1Val = digitalRead(BUT1);
  int but2Val = digitalRead(BUT2);
  int but3Val = digitalRead(BUT3);
  int but4Val = digitalRead(BUT4);
  int but5Val = digitalRead(BUT5);
  int but6Val = digitalRead(BUT6);

  rgb_color color;

  //current time passed
  unsigned long currentMillis = millis();

  //if button 1 pressed set as on and read sensor value
  if (but1Val == LOW) {
    on1 = true;
    avgVal = (float)analogRead(sensor1);
    Serial.println("button1");
  }

  //if LED is set as on make light blink until the sensor
  //reading average changes suddenly
  if (on1 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.red > 0) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 255;
        color.green = 0;
        color.blue = 0;
      }
      for (uint16_t i = 0; i < 8; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    //equations taken from Phys Comp course website credit to Joseph Paetz
    float cur_reading = (float)analogRead(sensor1);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading);
    //turn LED off and set as off if the reading changes over a set threshold
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 0; i < 8; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on1 = false;
    }
  }

  //if button 2 pressed set as on and read sensor value
  if (but2Val == LOW) {
    on2 = true;
    avgVal = analogRead(sensor2);
    Serial.println("button2");
  }
  
  if (on2 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.red == 255) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 255;
        color.green = 255;
        color.blue = 0;
      }
      for (uint16_t i = 8; i < 16; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    float cur_reading = (float)analogRead(sensor2);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading);
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 8; i < 16; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on2 = false;
    }
  }

  //if button 3 pressed set as on and read sensor value
  if (but3Val == LOW) {
    on3 = true;
    avgVal = analogRead(sensor3);
    Serial.println("button3");
  }

  if (on3 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.red == 255) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 255;
        color.green = 255;
        color.blue = 0;
      }
      for (uint16_t i = 16; i < 24; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    float cur_reading = (float)analogRead(sensor3);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading*10);
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 16; i < 24; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on3 = false;
    }
  }

  //if button 4 pressed set as on and read sensor value
  if (but4Val == LOW) {
    on4 = true;
    avgVal = analogRead(sensor4);
    Serial.println("button4");
  }

  if (on4 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.blue == 255) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 0;
        color.green = 0;
        color.blue = 255;
      }
      for (uint16_t i = 24; i < 32; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    float cur_reading = (float)analogRead(sensor4);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading);
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 24; i < 32; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on4 = false;
    }
  }

  //if button 5 pressed set as on and read sensor value
  if (but5Val == LOW) {
    on5 = true;
    avgVal = analogRead(sensor5);
    Serial.println("button5");
  }

  if (on5 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.blue == 255) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 0;
        color.green = 0;
        color.blue = 255;
      }
      for (uint16_t i = 32; i < 40; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    float cur_reading = (float)analogRead(sensor5);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading);
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 32; i < 40; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on5 = false;
    }
  }

  //if button 6 pressed set as on and read sensor value
  if(but6Val == LOW) {
    on6 = true;
    avgVal = analogRead(sensor6);
    Serial.println("button6");
  }
  
  if (on6 == true){
    //make led blink
    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;
  
      // if the LED is off turn it on and vice-versa:
      if (color.blue == 255) {
        color.red = 0;
        color.green = 0;
        color.blue = 0;
      } 
      else {
        color.red = 0;
        color.green = 0;
        color.blue = 255;
      }
      for (uint16_t i = 40; i < 48; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
    }
    float cur_reading = (float)analogRead(sensor6);
    avgVal = avgVal * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
    Serial.println(cur_reading);
    if (abs(avgVal - cur_reading) > threshold){
      color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 40; i < 48  ; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
      on6 = false;
    }
  }
  else{
    color.red = 0;
      color.green = 0;
      color.blue = 0;
      for (uint16_t i = 40; i < 48  ; i++)
      {
        colors[i] = color;
      }
      ledStrip.write(colors, LED_COUNT);
  }
}

 

Schematic

]]>
https://courses.ideate.cmu.edu/60-223/f2018/work/paper-organizer-by-team-marya-final-documentation/feed/ 0
Team MARY(a) Prototype Documentation https://courses.ideate.cmu.edu/60-223/f2018/work/team-marya-prototype-documentation/ https://courses.ideate.cmu.edu/60-223/f2018/work/team-marya-prototype-documentation/#respond Tue, 20 Nov 2018 19:09:31 +0000 https://courses.ideate.cmu.edu/60-223/f2018/work/?p=5092 Introduction:

Our prototype of the Automatic Filing Machine! It is made of laser-cut cardboard and wooden dowels. The tray holding the paper is intended to move up and down to the correct shelf for filing.

A close-up of our paper tray. We did not have time to make the real-life representation of it, but the papers would have a conveyor belt underneath to move the papers off of the tray and into the shelf.

A very simple representation of our user interface: a button panel. Each button would be labeled with the shelf that it goes to, and maybe color coded to aid visual recognition.

We are team MARYa (Mohan, Andrea, Roly, and Yingyang), four students at Carnegie Mellon University that are assigned with the task to create a useful implement for our older friend, Maria. Previously, we had documented our meeting with Maria to find out what could be useful for her. In this stage, we took our idea and turned it into a prototype for Maria to see and critique at our next meeting with her, which was on November 13th. We found in our initial meeting with Maria that she needed was throwing her papers on the floor instead of filing them, so we tried to come up with a product that would organize her papers for her.

Product: An Automatic Filing Cabinet

Our prototype demonstrates a cabinet that files itself. Although it is completely a “behaves-like” prototype (it has no code yet), it does represent what our team envisioned for the product.

We want Maria to be able to put papers that she needs filed onto the tray of our product, press a button, and let the machine do the rest. The machine will determine where the papers go based on the button pressed, which corresponds to a shelf. The tray will move to that shelf, and a small conveyor-belt-like mechanism will push the papers onto the shelf. The tray would then return to the top of the machine, waiting for more papers. The buttons are located on top of the machine for easy access, and the front of the shelves are open to allow the user to take the papers they need out.

Process:

The origin of our idea: Maria’s very populated filing cabinets. She has a publishing business, and thus has massive amounts of paperwork.

A visual inspiration for the proportions and materials of our shelf. We like wood as a main material, since it would fit in well with Maria’s home. We also like the strength and customizability of it.

One of our most important meetings before the critique. Here Roly is explaining his vision of the mechanism for raising and lowering the paper tray.

One of the mechanism inspirations we found during image research. We will be using a stepper motor to spin a big threaded rod, but this required attaching the stepper to it using a belt. This image shows how we will do that.

A quick drawing that we used to determine how big our shelves should be. We needed to strike a balance between accessibility for Maria and accessibility for the Machine itself.

Maria’s first glimpses of the prototype! She was very intrigued with how it would work and gave some valuable input on the materials we should use and how our interface should be positioned.

The machine in action at our prototype meeting! Maria is testing the height of our paper tray and the reachability of the buttons.

Discussion

Our first meeting with Maria was much later than the other groups’, so we were a bit behind everyone else. While the rest of the class was working on the third in-class session for their prototype, our group was meeting Maria for the first time. Because of this, we only had around 4 days to meet up and work on a prototype. We couldn’t add any of the actual motorized or mechanical features of the prototype, but we did get a full-scale cardboard version of the prototype.

The crit on November 13th was pretty useful to our group. We met with Maria, and showed her our prototype. She gave us some useful feedback that we will want to incorporate into our final product.

She asked us to put wheels under it so that it could be moved easily, which I thought was pretty useful because none of us had thought about that. We asked her feedback on the placement of the buttons, and she gave us useful feedback for that as well, saying if we put the buttons on top of the shelf she wouldn’t be tempted to put things on top of it. She also asked us to number the shelves instead of writing labels on it so that she can label them herself and change the labels if she wants to, which I thought was something we should definitely consider.

For our next steps, we have a ton of work to do. We have to order our parts, figure out the mechanical and software aspects of this, finalize our design, cut the shelf itself out, and basically everything else. It will be quite a challenge to do this in 2 weeks especially with Thanksgiving break coming up, but hopefully we will pull it off.

]]>
https://courses.ideate.cmu.edu/60-223/f2018/work/team-marya-prototype-documentation/feed/ 0
How do you solve a problem like Maria? https://courses.ideate.cmu.edu/60-223/f2018/work/how-do-you-solve-a-problem-like-maria/ https://courses.ideate.cmu.edu/60-223/f2018/work/how-do-you-solve-a-problem-like-maria/#respond Thu, 15 Nov 2018 19:26:43 +0000 https://courses.ideate.cmu.edu/60-223/f2018/work/?p=4925

Background

We are team MARY (Mohan, Andrea, Roly, and Yingyang) and we are currently taking an Introduction to Physical Computing course at Carnegie Mellon University. For the final project, our team was paired up with Maria, an older person who we were assigned to create a useful implement for. In order to come up with an idea for a useful implement for Maria, we first needed to talk with her face to face to face to identify areas in her life where she could use help. Unfortunately, on the week we were supposed to conduct our initial interviews, Maria was on a cruise, which provided some complications for us. We tried to conduct a FaceTime interview with her on October 30th, but that wasn’t very fruitful, especially since we couldn’t get FaceTime to work so we had to do a phone call instead. When she got back, we were able to go visit her house on November 8th and talk to her in person, which was a little more helpful than the first interview.

Meeting Agenda

(Note: the agenda below is for our first meeting over the phone)

Goal: Get to know Maria, let Maria get to know us, ask about what her life is like and how we could help her

Introductions:

  • Talk about ourselves, our skills, what we want to accomplish for the project and the meeting, then ask her to do the same- what does she expect from us?

Questions:

Personal Life

  • What is your daily routine like?
  • What do you like doing for fun?
  • Who do you live with and where?
  • Frustrations in your life?

Career

  • What is your job?
  • What does that involve?
  • If you don’t have a job, do you miss having a job?
  • Do you have anything you think replaces the role of your previous job?

Hobbies

  • Do you have any major hobbies/time-consuming activities?
  • Is there anything you used to do, but is harder to do now?

Closing:

  • Summary of what we talked about, and tell her what we plan to do until the next time we meet

Meeting Summary

Our First “Meeting”, Over the Phone

The first meeting was held over the phone because Maria was on some Arctic Cruise, and we were unable to get FaceTime to work, which I don’t think would have helped that much.

We began the meeting by introducing each of our team members and talking about some of our interests and skills. We hoped that this would give Maria a good idea of what we were able to do. We then tried to let the conversation flow into talking more about Maria’s daily life and routine to perhaps find a problem ourselves. We let the answers to each question guide us, attempting to hit major points such as her job, hobbies, and other activities.

We learned Maria writes and publishes for her publishing company, she likes to play bridge and garden, she has a son who loves Godzilla, and that she lives with her husband in Churchill.

Maria seemed to be attached to a few ideas of “gadgets” (as she called them) that she had come up with on her own beforehand, instead of letting us find a solution while she talked about her problems. She talked about how her husband leaves their kitchen cabinets open and it frustrates her, but that problem is not necessarily an electronics/Arduino problem. She also discussed her and her friends losing at bridge against her husband, and how a dispenser of chocolate can be made for them, but this is again not a very substantial problem to solve. It was very hard to get her to stray from these ideas.

Overall, this meeting was not extremely conducive to ideation, since the team was not able to get an idea to work off of. 

A photo of us struggling to get FaceTime to work for our first “meeting” with Maria

 

Meeting Maria in Person and Going to Her House

When Maria returned to Pittsburgh from her cruise, we were able to set up a date for her to drive us to her home (November 8th). This meeting was critical because we had come up with absolutely nothing from the first meeting.

Maria first drove us to her new home, which was still being built. We did not find this particularly interesting or helpful, but Maria was pretty set on showing us her new home. We were more interested in her current living situation to see how she lives and goes about her day; so after a lot of insistence on our part to go to her current home, she finally took us there.

This meeting was more fruitful than the first, but we still couldn’t identify major problem points that we could solve with an Arduino that wasn’t a product that already exists. We also got to see her husband leaving the cabinet doors open, which was fun.

We got to see Maria’s workspace, and it was quite cluttered. There was paper everywhere and in piles. Maria has a publishing company, so this was understandable. However, we learned that Maria has a habit of throwing her papers on the floor and not filing or sorting them, which makes it hard for her to remember what papers she put where. It is important to keep track of where she puts things because she has so many papers to deal with, and throwing them on the floor also makes them hard to reach. Maria has a file cabinet and those desktop paper organizers with the different sections, but she still throws them on the floor anyways.

Although this is more of a laziness/bad habit problem instead of something she is physically unable or difficult to do, it gave us at least something to work with.

Maria driving us to her house

Maria showing us her new home that is being built

Maria’s very cluttered desktop

Finally getting where we want to go

So much paperwork and clutter

She doesn’t remember where she filed her papers away

Maria making some hand gestures

Giving us a tour of her space

Reflection

The first meeting was kind of terrible since it provided no material for us to work with, but the second one provided us with at least something.

For our first conversation, we were frustrated that Maria kept pushing ideas for “gadgets” that she’d come up with instead of letting us get to know her and the difficulties she faces in her daily life. Perhaps we had asked the wrong questions. We thought they were generic enough, but it is difficult when she had already planned out what she wanted to talk about, instead of letting our questions guide her.

It was also difficult for us to get her to understand that we wanted to see her current home, not her new one. When we are faced with a blank space that she doesn’t live in yet, we are unable to see what she is like at home, how she goes about her life, and interacts with her environment.

]]>
https://courses.ideate.cmu.edu/60-223/f2018/work/how-do-you-solve-a-problem-like-maria/feed/ 0
Super Pulando Entertainment System (SPES) https://courses.ideate.cmu.edu/60-223/f2018/work/super-pulando-entertainment-system-spes/ https://courses.ideate.cmu.edu/60-223/f2018/work/super-pulando-entertainment-system-spes/#respond Thu, 25 Oct 2018 17:45:09 +0000 https://courses.ideate.cmu.edu/60-223/f2018/work/?p=4595  

DescriptionA fidget device to help me focus by giving my hands a mindless task to do.

Process:

Image result for snes controller

My visual inspiration: a Super Nintendo Entertainment System controller

Some of the original sketches that detailed some of the form issues I would have to solve.

Designing this project was mostly a pain because of how many electronics had to be fit into such a small space. I consistently had to change the dimensions of the SPES to fit in new components like a power switch or an LED ring.

This is the ATTiny84A, a microcontroller small enough to control the SPES!

The original print of the SPES case. It is very small, and I had to make a hole in the back for a set of batteries.

 

 

 

 

 

 

 

The project was very difficult to power effectively since I was using a NeoPixel LED Ring, which uses a lot of current. My solution was to simply push the electronics as close to the front of the SPES as possible, and sneak two AA batteries in behind them.

In terms of software, I did not experience any real challenges except implementing an event-loop system to make the SPES able to change modes very quickly and reliably, as well as flash its LED’s consistently while switching game modes.

An extremely short video of the first time the event loop for flashing the LED ring worked!

The SPES in its normal place on my desk. It fits in quite well amongst the other pieces.

Discussion:

Some feedback from my classmates included:

“Some light sequences seem a bit jarring.”
I agree with this feedback, in regards to other users. However, I do not find them jarring personally, and this is a very personalized device. If I were to market this kind of product to others, I would certainly dim down any extreme color shifts and perhaps make a more cohesive user interface.

“…it would be cool to have labels.”
I also agree with this. The original plan was to have colorful buttons with letters on them, much like a Super Nintendo console controller, but acquiring the buttons would have been expensive relative to the rest of the project. I could have 3D-printed them, but their quality may have been questionable.

Overall, I am very happy with how this project turned out. It was hard work to manufacture the case for my electronics, but it looks as polished as I would have liked. The software works as was intended, but my color-blending “game” is very hard since my concept of color comes from pigmented colors like paint and colored pencils, not mixing light together. This is somewhat annoying, but helps my mind stay occupied when I am not trying to focus on something else.

I certainly did not enjoy spending all night building that case, so I learned to always start (no matter what other progress I have made) building the container earlier. I am very sensitive to the amount of sleep I get, and the day after finishing the case was absolutely terrible. The case was 3D-printed, but I ran out of material and had to remake it, which taught me to always have material handy.

The project certainly sparked a fun train of thought while I was implementing the color-blending mode. My original idea was to somehow make a different, more “traditional” game out the LED ring, but I changed it relatively late in the process. I got the idea from a game on my iPhone called Blendoku, and simply implemented its logic in a simpler format.

I would like to rebuild the SPES with a prettier body (e.g. not white) and I would like to solder the electronics absolutely perfectly so that I do have to worry about breaking hard-to-detect connections.

Schematic:

This schematic has many pushbuttons with pull-down resistors.

Code:

/*============================================================= 
 * SUPER PULANDO ENTERTAINMENT SYSTEM (SPES)
 *
 * By: Rolando Garcia III
 * 
 * This code controls the SPES, a small handheld fidget device
 * inspired by a Super Nintendo Entertainment System controller.
 *
 * There are two "game" modes:
 *
 * • Fun with LED's - Just play around with mixing colors
 *                    and making a light move around!
 *
 * • Blendoku - You are given two colors and you must mix them properly to
 *              win!
 =============================================================*/

/*============================================================= 
 * PIN MAPPING:
 *
 * • A button - 2
 * • B button - 3
 * • X button - 4
 * • Y button - 5
 * • Select button - 6
 * • Start button - 7
 * • NeoPixel Ring - 8
 * • Joystick switch - 9
 * • Joystick X - A0
 * • Joystick Y - A1
 *
 =============================================================*/

#include <Adafruit_NeoPixel.h>
#define APIN 2
#define BPIN 3
#define XPIN 4
#define YPIN 5
#define SELECT 6
#define START 7
#define LEDS 8
#define STICKSW 9 //MUST BE PULLED UP TO WORK PROPERLY
#define STICKX A0
#define STICKY A1


//Flashing event loop variables
uint32_t lastTimeLightsOn;
uint32_t lastTimeLightsOff;
const int flashInterval = 250; //How long to flash on or off

/*=============================================================
 * INPUTS:
 * • Joystick
 * • Joystick switch
 * • Start Button
 * • Select Button
 * • A
 * • B
 * • X
 * • Y
  =============================================================*/
//Struct to hold a button and its properties, including debouncing properties
struct button {

  int pin; //Pin mapping of button
  int lastState; //Previous state of button
  int buttonState; //Current state of button
  unsigned long lastBounceTime; //Last bounce time of button

};

//Initialize buttons
struct button A = { APIN, LOW, LOW, millis() };
struct button B = { BPIN, LOW, LOW, millis() };
struct button X = { XPIN, LOW, LOW, millis() };
struct button Y = { YPIN, LOW, LOW, millis() };
struct button Select = { SELECT, LOW, LOW, millis() };
struct button Start = { START, LOW, LOW, millis() };
struct button StickSwitch = { STICKSW, HIGH, HIGH, millis() };

//Button debounce function
int debounce(struct button *b) {

  //Get the current reading
  int buttonReading = digitalRead(b->pin);
  bool result = HIGH;

  //If the buttonState has changed
  if (buttonReading != b->lastState) {
    //Reset the bounce timer
    b->lastBounceTime = millis();
  }

  //If enough time has passed, check if the state is the same
  if ( (millis() - (b->lastBounceTime)) > 10 ) {

    if (buttonReading != b->buttonState) {

      b->buttonState = buttonReading;


      // only toggle the LED if the new button state is HIGH
      if (b->buttonState == LOW) {
        result = !result;
      }
    }

  }

  b->lastState = buttonReading;

  return result;

}

//=============================================================
//OUTPUT: NeoPixel Ring (16 LEDs)
//=============================================================
//Initialize the ring
Adafruit_NeoPixel ring = Adafruit_NeoPixel(16, LEDS, NEO_RGBW + NEO_KHZ800);

//Function to clear the lights of all their color
void clearLights(){

  //Loop through all the pixels and set their RGBW values to all 0's
  for(int i = 0; i < 16; i++){
    ring.setPixelColor(i, 0, 0, 0, 0);
  }
  //Then show them so that the change is reflected
  ring.show();
  
}

/*=============================================================
 * GAME MODES:
 *  true = Fun with LEDs
 *  false = Blendoku
  =============================================================*/
//Game state variables
bool gameMode = true;
bool lastMode = false;

//Hue changing variables
int color = 0; //Color being changed
int red = 1; //Value of red
int green = 1; //Value of green
int blue = 1; //Value of blue
const int change = 10; //Amount of change in color during increases or decreases

//Increase the saturation of a certain color with no rollover
void increaseColor() {
  //Determine which color is being changed
  //and ensure that it is not already maxed out
  if(color == 0 && red+change <= 255){
    red += change;
  } else if(color == 1 && green+change <= 255) {
    green += change;
  } else if(color == 2 && blue+change <= 255) {
    blue += change;
  }
}

//Decrease the saturation of a certain color with no rollover
void decreaseColor() {
  //Determine which color is being changed
  //and ensure that it is not already minimized
  if(color == 0 && red-change >= 0){
    red -= change;
  } else if(color == 1 && green-change >= 0) {
    green -= change;
  } else if(color == 2 && blue-change >= 0) {
    blue -= change;
  }
}

//Function to randomize a passed-in hue
void randomizeColors(int *redVal, int *greenVal, int *blueVal){

  *redVal = random(0,255);
  *greenVal = random(0,255);
  *blueVal = random(0,255);
  
}

//Resets all user's hue variables
void resetColors(){
  red = 0;
  green = 0;
  blue = 0;
}

//Flash the center lights to alert the user of the game mode
void flashLights(bool currentMode) {

  //For the funwithLEDs mode, simply flash white lights
  if (currentMode == true) {

    if(millis() - lastTimeLightsOff >= flashInterval){
      clearLights();
      lastTimeLightsOff = millis();
    }

    if(millis() - lastTimeLightsOn >= flashInterval*2){
      for (int j = 0; j < 16; j++) {
  
        ring.setPixelColor(j, 0, 0, 0, 255);
  
      }
      ring.show();
      lastTimeLightsOn = millis();
    }

  } else { //For the blendoku mode, flash colorful lights

    if(millis() - lastTimeLightsOff >= flashInterval){
      clearLights();
      lastTimeLightsOff = millis();
    }
    
    if(millis() - lastTimeLightsOn >= flashInterval*2){
      //For the blendoku game mode, flash colorful lights
      for (int j = 0; j < 16; j++) {
  
        ring.setPixelColor(j, random(0,255), random(0,255), random(0,255), 0);
  
      }
      ring.show();
      lastTimeLightsOn = millis();
    }

  }

}

//=============================================================
//VARIABLES/FUNCTIONS FOR BLENDOKU MODE
//=============================================================
//Random Color 1
int red1;
int green1;
int blue1;
//Random Color 2;
int red2;
int green2;
int blue2;

//New blendoku game flag variable
bool newBlendoku = true;

//Randomizes the colors that the person has to blend
void pick2RandomColors() {

  //Use the randomizeColors() function to do the work for you
  randomizeColors(&red1, &green1, &blue1);
  randomizeColors(&red2, &green2, &blue2);
  
}

//Shows player the two colors of the game
void showPlayerProblem(){

  //Flash the first color
  for (int i = 0; i < 16; i++) {

    ring.setPixelColor(i, green1, red1, blue1, 0);

  }
  ring.show();
  delay(500);

  clearLights();
  delay(500);

  //Flash the second color
  for (int i = 0; i < 16; i++) {

    ring.setPixelColor(i, green2, red2, blue2, 0);

  }
  ring.show();
  delay(500);

  clearLights();
  delay(500);
  
}

//Function to show player's current color combination
void showPlayerColors() {

  for (int i = 0; i < 16; i++) {

    ring.setPixelColor(i, green, red, blue, 0);

  }
  ring.show();
  
}

//Checks the user's solution 
bool checkBlendoku(){

  //Set the threshold for verifying two colors
  const int threshold = 200;

  //Determine the solution
  int solveRed = min(red2,red1) + (int)(abs(red1-red2)/2);
  int solveGreen = min(green2,green1) + (int)(abs(green1-green2)/2);
  int solveBlue = min(blue2,blue1) + (int)(abs(blue1-blue2)/2);
  
  //If the RGB value is between those of the random colors, they solved it
  if( (sq(red-solveRed) + sq(green-solveGreen) + sq(blue-solveBlue)) <= sq(threshold) ) {
    return true;
  }
  
  return false;
  
}

//Flash a green circle when a player solves a blendoku
void success(){

  for(int j = 0; j < 2; j++){
    for (int i = 0; i < 16; i++) {
  
      ring.setPixelColor(i, 255, 0, 0, 0);
  
    }
    ring.show();
    delay(500);
  
    clearLights();
    delay(500);
  }
  
}

//Flash a red circle for a failure
void failure(){

  for(int j = 0; j < 2; j++){
    for (int i = 0; i < 16; i++) {
  
      ring.setPixelColor(i, 0, 255, 0, 0);
  
    }
    ring.show();
    delay(500);
  
    clearLights();
    delay(500);
  }
  
}

//Game mode where the player must blend two colors
void blendoku() {

  //If a new game is initiated, pick two new colors and show them
  if(newBlendoku || debounce(&Start) == LOW){
    clearLights();
    pick2RandomColors();
    resetColors();
    showPlayerProblem();
    newBlendoku = false;
  }

  //Allow the user to recheck the colors they were given
  //by moving the stick up or down
  if(analogRead(STICKY) >= 900 || analogRead(STICKY) <= 100){
    showPlayerProblem();
  }

  //Allow the user to switch the hue they are changing
  if(debounce(&StickSwitch) == LOW){
    color += 1;
    color %= 3;
  }

  if(debounce(&X) == LOW){
    increaseColor();
  }

  if(debounce(&B) == LOW){
    decreaseColor();
  }

  //Also allow them to reset their color selections and start over
  if(debounce(&Y) == LOW){
    resetColors();
  }

  showPlayerColors();

  //If the user confirms their solution, check it and start a new game
  if(debounce(&A) == LOW){
    
    if(checkBlendoku() == true){
      success();
    } else {
      failure();
    }
    newBlendoku = true;
    
  }


}

//VARIABLES/FUNCTIONS FOR FUNWITHLEDS MODE

//Index of the light that is currently on
int lightOn = 0;

//Function to determine light index from joystick position
float lightIndexFromJoystick(int stickX, int stickY){

  //Arctangent magics!
  float angle = atan2(stickY, stickX);
  int lightIndex = 15 - round((angle/1.57)*15);

  return lightIndex;
}

//Fun mode where the user can simply play with colors on the wheel
void funWithLEDs() {

  clearLights();
  int stickX = analogRead(STICKX);
  int stickY = analogRead(STICKY);

  //Find how far the joystick is from its center
  int xDist = stickX - 512;
  int yDist = stickY - 512;

  double distance = sqrt( (float)xDist*xDist + (float)yDist*yDist );

  //Only change the light that is on if the analog stick is fully pushed
  if(distance > 100){
    ring.setPixelColor(lightOn, 0, 0, 0, 0);
    lightOn = lightIndexFromJoystick( stickX, stickY );
  }

  //Allow the user to switch the hue they are changing
  if(debounce(&A) == LOW){
    color += 1;
    color %= 3;
  }

  if(debounce(&X) == LOW){
    increaseColor();
  }

  if(debounce(&B) == LOW){
    decreaseColor();
  }

  //Also allow them to reset their color selections and start over
  if(debounce(&Y) == LOW){
    randomizeColors(&red, &green, &blue);
  }

  if(debounce(&Start) == LOW){
    resetColors();
  }
  
  ring.setPixelColor(lightOn, green, red, blue, 0);
  ring.show();

}

//Switches game modes when the Select button is pressed
void switchGameMode() {
  //Switch the game mode
  gameMode = !gameMode;

  //Reinitialize blendoku
  if(gameMode == false){
    newBlendoku = true;
  }

  //Blank out the lights and reset the timers
  resetColors();
  lastTimeLightsOff = millis();
  lastTimeLightsOn = millis() + flashInterval;
  delay(10);
}

void setup() {
  // put your setup code here, to run once:
  pinMode(APIN, INPUT);
  pinMode(BPIN, INPUT);
  pinMode(XPIN, INPUT);
  pinMode(YPIN, INPUT);
  pinMode(STICKX, INPUT);
  pinMode(STICKY, INPUT);
  pinMode(STICKSW, INPUT_PULLUP); //Remember to pull up for reliable reading

  ring.setBrightness(30); //Lower the default brightness so as not to 
  ring.begin(); //Initialize the LED ring
  ring.show();

  lastTimeLightsOff = millis();
  lastTimeLightsOn = millis() + flashInterval;
}

void loop() {
  
  //Check the select button
  if (debounce(&Select) == LOW) {
    lastMode = gameMode;
    switchGameMode();
  }

  //If the person has not confirmed the game mode, flash the lights at them
  if(lastMode != gameMode && debounce(&Start) == HIGH ){
    resetColors();
    flashLights(gameMode);
    return;
  } else {
    //Otherwise continue into the gameMode
    lastMode = gameMode;
  }

  //Determine the correct game mode and play it
  if (gameMode == true) {

    funWithLEDs();

  } else {

    blendoku();
    
  }
}








 

]]>
https://courses.ideate.cmu.edu/60-223/f2018/work/super-pulando-entertainment-system-spes/feed/ 0
3D-Printed Roller Coaster Model https://courses.ideate.cmu.edu/60-223/f2018/work/3d-printed-roller-coaster-model/ https://courses.ideate.cmu.edu/60-223/f2018/work/3d-printed-roller-coaster-model/#respond Tue, 28 Aug 2018 23:28:54 +0000 https://courses.ideate.cmu.edu/60-223/f2018/work/?p=3804 Project Title: 3D-Printed Model of “Invertigo” from King’s Island Park

Creator: Matt Schmotzer, Purdue University

This is a roller coaster almost entirely 3D-printed by Matt Schmotzer of Perdue University. It is a working model of “Invertigo” at the King’s Island amusement park, including a control console akin to one actually used on a roller coaster such as this, passenger restraints on the vehicles, and even small gates at the station to allow “guests” on. All of this is powered by an Arduino Mega which I believe is hidden inside of the grey station.

Invertigo Scaled Model Roller Coaster imageInvertigo Scaled Model Roller Coaster imageInvertigo Scaled Model Roller Coaster image

This small, seemingly innocuous model actually boasts the concepts used for building real rides, such as a control console with sensory inputs that allow an operator to see when something is wrong in the system, buttons to close restraints on carts, or station dispatch controls. This seems complex, but it is really simple to imagine the system as having a doorman who decides whether or not people are allowed through a door. For these reasons, this project never ceases to impress me.

]]>
https://courses.ideate.cmu.edu/60-223/f2018/work/3d-printed-roller-coaster-model/feed/ 0