gnmarino@andrew.cmu.edu – Intro to Physical Computing: Student Work Fall 2022 https://courses.ideate.cmu.edu/60-223/f2022/work Intro to Physical Computing: Student Work Sun, 18 Dec 2022 12:55:42 +0000 en-US hourly 1 https://wordpress.org/?v=6.0.8 Back-up Alarm by Team Fornax: Final Documentation https://courses.ideate.cmu.edu/60-223/f2022/work/back-up-alarm-by-team-fornax-final-documentation/ Sun, 18 Dec 2022 05:11:51 +0000 https://courses.ideate.cmu.edu/60-223/f2022/work/?p=16847 For this project, we worked in teams of three to design a device that would be useful for a person living with a disability. Each team worked alongside a client from Community Living and Support Services (CLASS) to create something what would be relevant and useful in their lives. Our client was Jeff Owens, an individual with a mobile disability. Through the course of this project we would conduct an interview with Jeff and incorporate his feedback into the final product. To read more about our interview with Jeff, click here.

What We Built

Our end product for Jeff was a device that he could strap onto the bottom of his wheelchair using Velcro strips. This device would help ensure that he would not back up into/onto the objects behind him. Jeff gets in the range of an object behind him the device would beep until he is a reasonable distance away from the object. In additional, the device includes lights that would flash on and off at the same time. Jeff has total control of this device, he has the ability to turn off the device entirely or just the beeping. Similarly, Jeff can adjust the range in which the device starts beeping at.

This is the main photo of the device with all its parts. All the velcro is unstrapped in this photo and there is a loose LED strip in the middle that is connected to the control panel.

This is the control panel close up. It contains a switch that turns off sound (it has sound labeled underneath), and it has a switch that turns off lights and sound (has lights labeled underneath). The switches are like this because we wanted Jeff to have the ability to stop lights and sounds up at the control panel where he can reach. The blue knob is a potentiometer for adjusting the distance the sensor scans for.

This is one of our ultra sonic sensors that is suppose to be strapped to the behind lower part of wheelchair with its one other counterpart. As you can see, you mount this by strapping the velcro tightly around the wheelchair rods.

This is a picture showing what the back of everything looks like, and it’s suppose to show you how you would strap the velcro if it was on the wheelchair.

This is the device on Jeff’s wheelchair at the critique. We didn’t get much time with it but we found it mostly worked except for attaching the underneath box with the Arduino. We must have incorrectly measured on prototype day because the velcro straps were not quite long enough. Otherwise it was kinda successful!

 

Narrative Sketch

After recording another album review for this YouTube, Jeff decides to take a quick nap in his wheelchair. Unknowingly to Jeff at the same time as he begins to drift away his two-year old nephew decided to take out all his toys and begin to play with them all around Jeff. Very quickly Jeff’s nephew gets bored of playing inside and decides to go outside, leaving all his toys still on the ground around Jeff.

After Jeff wakes up from his nap, he realizes that he is surrounded by all his nephew’s toys. Jeff turns on the back-up alarm. Jeff waits and does not hear a beep. He now knows that there is a safe path behind him that he can take to get out of the living room. Jeff has saved himself from getting hurt from accidentally tipping over and has saved himself from hurting his nephew’s feelings by accidentally breaking one of this toys.

How We Got Here

Prototype

The prototype we created was designed to answer the question: How can we help Jeff move safely from Point A to Point B?

Our prototype was more on the simpler side as we wanted to gauge Jeff’s opinion on our approach. The prototype took the shape of a rectangular cardboard box with optical proximity sensors poking out of the frontside. In addition, we mocked up a control panel on paper for Jeff to take a look at. When we showed our prototype, we focused a lot of explaining how device would interact upon certain actions.

This is us testing which sensors to use for our project. We ended up going with the ultrasonic sensor because it had a larger range it detected which would help minimize problems later we suspected. We brought this set up to the prototype critique but the design and wizard of oz prototypes ended up helping us communicate better with Jeff.

This was the underneath box prototype, we talked about how the sensors may end up on the side of this box and be put on the lower half of the wheelchair, however, after looking at Jeff’s wheelchair we decided this wasn’t going to happen.

This is the paper control panel mockups. We had Jeff put his finger on the imaginary buttons to see what was big enough. We also held it next to his arm rest and asked which size was most legible. We found the biggest one was the only viable option after these two tests.

Wizard of Ozzing of the LED Strip

This is what the serial monitor looked like when we were testing the distance sensors before the prototype session.

Here you can see us ideating after Jeff’s interview, trying to get an idea for the prototype critique. We struggled with this because we found Jeff didn’t have any complaints about his daily life. So we tried fleshing out/expanding all three of our ideas and talked to Zach about it. We ended up telling Jeff the problem space we picked but let him decided if he liked this route or not.

The main helpful info we got from the prototype session other than a solid direction for our project was a lot of measurements. This is the main page of notes that documented our measurements through a picture and writing. We ended up referencing this image a lot in the process.

In our mind, our device would mount underneath Jeff’s wheelchair and help detect objects in front of him. From the Prototype Critique, we gained valuable feedback that helped patch up holes from our initial interview with Jeff. Moreover, the Prototype Critique redefined the purpose of our device. Instead of detecting objects in front of Jeff, that he can already see, we learned that it was much more helpful if the device could detect objects behind Jeff as he backs up. This led us to separate the optical proximity sensor from being embedded within the device. We decided to move these sensors to these two metal rods already pointing from the back of Jeff’s wheelchair because these rods were already at an angle.

At the end of the Prototype Critique, we decided to acknowledge and include all the feedback we received from Jeff and the other CLASS clients. As people who do not have much experience with wheelchairs, we believed it was in the best interest to consider all the information we were given as our client knows himself the best. Furthermore, we are making this device for Jeff, hence his opinion would help us finalize our ideas for the final iteration. The main problem we encountered while prototyping was we found that getting the distance sensor accurate was pretty difficult because of angle and the sensor moving around, thus explaining why we wizard of oz the prototype instead.

Process

This is the original code flow chart. This was used to help organize the code initially and figure out how we wanted the information to flow through the device.

This was all our wiring before soldering. This was definitely a lot to tackle and difficult to read when initially soldering.

Results from calibration. This is what we documented when testing the potentiometer. We needed to figure out the highest the calibration should go.

This was the first prototype of the control panel. We ended up deciding the velcro should only strap underneath, because this was extremely unstable and wouldn’t really stay up. We also decided not to do a second potentiometer, and decided to enlarge the hole to a square so the potentiometer was easier to pinch.

This was us testing the ultrasonic sensor holder. We found it to be a little wide and we decided we want a hole to embed the sensor instead of have it sit on top or the wood.

This was us realizing two things. We made a mistake wiring the switches, and the bread board was not fitting in the control panel neatly. This lead us to a lot of re-soldering.

Through this project, we ran into several roadblocks. Firstly, after we had decided on the project, we struggled with deciding exactly how we wanted to go about the user feedback. We had to make some executive decisions on using lights and a buzzer and forgoing vibration. We then had some issues getting our buttons wired, but we then figured out how to get them to work because we found that we accidentally wired the incorrect holes in the soldering board. Afterwards, we then ran into some issues with exactly how we were going to mount the ultrasonic distance sensors on the wheelchair. We realized that the sensors could have easily been bumped, throwing off the distances. We then had to add a potentiometer, though we already had a working setup and working code. After, we ran into several issues with soldering, with the solder on the LEDs easily falling off. This caused several issues, but at the end of the day, we ended up with a working product.

A lot of the issues we ran into were found the night before. This was because we diverged a bit with our projected Gantt chart. We spent the class period before the project’s due date still working, since we had no sense of urgency, and put in little time outside of class. Instead of soldering and assembling the product, which is where we ran into the majority of our problems, we continued trying to refine our code and hardware. If we had dedicated that class period to assembling, we would have had more time to debug, and more time to dedicate to details.

Planned Gantt Chart

Conclusions and Lessons Learned

Our group had a great time with this project and we were happy with the product we produced during the final critique day. That being said, there is always room for improvement, and we received a lot of helpful feedback that we could have implemented, feedback that could have improved our project. 

For example, we received multiple critiques on our non-shrink-wrapped wires, such as “exposed wiring needs shrink wrap,” and “The wires […] would benefit from more protective covering as well”. We thought this was a good critique, as it was one way that our project could have been elevated to the next level. During the final build stage, we were considering adding the shrink wrap to our project, but we ultimately ran out of time. Another critique was that a stable mounting system would have helped a lot with our project, and I am very inclined to agree. The problem that we encountered was that we didn’t have access to Jeff’s wheelchair, and a more complicated mounting system would have taken up a lot of time, and been very difficult to create in the scope of our class. We ended up using velcro for mounting, since it was the simplest option, but I do agree that with a more stable mounting system we would have been able to make the product a lot more effective. 

There was also feedback that complimented our use of the wheelchair, and considering the situation that Jeff himself was in. “[T]he group did a nice job figuring out how to make the device fit on his chair best”. The idea of personalization vs. generalization was a critique that was discussed a lot in person as well. We tried to make it very clear that the goal of this project was not to make a manufacturable product, but to make a project for Jeff himself. That being said, I think some of our guests were excited about the possibility that our product had if we were able to generalize it a bit. I think they appreciated how many people our product might have been able to help, which is a critique that is easy to accept. Another positive critique that we received was that the user feedback options that we had were good choices. We got multiple compliments on the visibility and clarity of the lights, but then one guest commented that for the visually impaired, the idea of the buzzer for sound feedback was also a good option. We appreciated this critique because it took us a while to decide what might be the most effective method of user feedback.  

Working with a client with a disability was a good experience for us. We had to be careful about how we worded interview questions, and it was a bit hard to communicate with Jeff, but we managed to find aspects of his life that we could improve and build our project on. In order to do that, we had to dive fairly deeply into what a day in his life looked like. I don’t think there was anything we would have done differently. We tried to be as open as we could when it came to communication with our client, and I think we did a fairly good job, even though our client was not as responsive as we might have hoped. 

I think all of our group members had a good time with this project. The diversity of backgrounds and skills that we brought into this project helped it run smoothly. We learned how to make things, not just for ourselves or for this class, but for other people. Something that really stuck with me was the impact that our work had on so many people. There were multiple clients talking about how important and life-changing the work we were doing was. Though we’ve only been through one semester of this class, we were able to see the applications of our knowledge in a way that was very fulfilling and meaningful.

Technical Details

Electronic Schematic and Block Diagram

Electronic Schematic

 

Block Diagram

Code

/**
 * @title Back-up Alarm
 * @brief A useful device designed for Jeff
 * 
 * 60-223: Introduction to Physical Computing
 *
 * The following code initializes two optical proximity that serve
 * as eyes of the back of Jeff's wheelchair. If Jeff backs within
 * a certain distance of object, the led strip will light up and
 * the buzzer will buzz. The code also gives Jeff the freedom to
 * adjust the upperbound distance using a potentiometer. 
 *
 * @authors Ethan Lu <ethanl2@andrew.cmu.edu>
 *          Frances Adiwijaya <fda@andrew.cmu.edu>
 *          Gia Marino <gnmarino@andrew.cmu.edu>
 *
 * @mapping
 *  Arduino Pin |   Role   |   Description   
 *  ------------|----------|-----------------
 *      A0         INPUT    Potentiometer
 *      3          INPUT    Buzzer Control Button
 *      4          INPUT    Device Control Button
 *      5          OUTPUT   Buzzer
 *      9          INPUT    ECHO Pin for Right Sensor
 *      10         INPUT    TRIGGER Pin for Right Sensor
 *      11         INPUT    ECHO Pin for Left Sensor
 *      12         INPUT    TRIGGER Pin for Left Sensor
 *      13         OUTPUT   LED Strip
 */

/** @brief Import libraries */
#include <NewPing.h>
#include <PololuLedStrip.h>
#include <assert.h>

/** @brief Declare constants */
#define POTENTIOMETER_PIN         A0

#define BUZZER_CONTROL_PIN        3
#define CONTROL_BUTTON_PIN        4
#define BUZZER_PIN                5
#define RIGHT_ECHO_PIN            9
#define RIGHT_TRIGGER_PIN         10
#define LEFT_ECHO_PIN             11
#define LEFT_TRIGGER_PIN          12

#define LED_COUNT     60
#define MAX_DISTANCE 200
#define MAX_BUZZ       8

/** @brief Debugging macros */
#define requires(expr) assert(expr)
#define ensures(expr)  assert(expr)

PololuLedStrip<13> led_strip;
NewPing sonar_left(LEFT_TRIGGER_PIN, LEFT_ECHO_PIN, MAX_DISTANCE);
NewPing sonar_right(RIGHT_TRIGGER_PIN, RIGHT_ECHO_PIN, MAX_DISTANCE);
rgb_color colors[LED_COUNT];

unsigned lowerbound = 10;
unsigned upperbound =  0;

void fill(uint8_t r, uint8_t g, uint8_t b);

/**
 * @brief Declare pin modes
 */
void setup() {
  pinMode(RIGHT_ECHO_PIN, INPUT);
  pinMode(RIGHT_TRIGGER_PIN, INPUT);
  pinMode(LEFT_ECHO_PIN, INPUT);
  pinMode(LEFT_TRIGGER_PIN, INPUT);

  pinMode(CONTROL_BUTTON_PIN, INPUT);
  pinMode(BUZZER_CONTROL_PIN, INPUT);
  pinMode(POTENTIOMETER_PIN, INPUT);

  pinMode(BUZZER_PIN, OUTPUT);
}

/**
 * @brief Main routine
 */
void loop() {
  delay(100);
  upperbound = map(analogRead(POTENTIOMETER_PIN), 0, 1023, 60, 150);

  cleanup();
  if (digitalRead(CONTROL_BUTTON_PIN) == HIGH) {
    unsigned int left_distance = (sonar_left.ping() / US_ROUNDTRIP_CM);
    unsigned int right_distance = (sonar_right.ping() / US_ROUNDTRIP_CM);

    /** Too close to an object */
    while ((lowerbound < left_distance && left_distance < upperbound) || (lowerbound < right_distance && right_distance < upperbound)) {
      fill(255, 0, 0);
      if (digitalRead(BUZZER_CONTROL_PIN) == HIGH) {
        buzz(min(left_distance, right_distance));
      }
      left_distance  = (sonar_left.ping() / US_ROUNDTRIP_CM);
      right_distance = (sonar_right.ping() / US_ROUNDTRIP_CM);
    }
  }
}

/**
 * @brief     Assigns a new rgb value to every element in the color array
 * @param[in] r Amount of red
 * @param[in] g Amount of green
 * @param[in] b Amount of blue
 */
void fill(uint8_t r, uint8_t g, uint8_t b) {
  for (uint16_t i = 0; i < LED_COUNT; i++) {
     colors[i] = rgb_color(r, g, b);
  }
  led_strip.write(colors, LED_COUNT);
}

/**
 * @brief     Activate the buzzer
 * @param[in] distance
 * @pre       `distance` is non-negative
 * @pre       `distance` is less than `MAX_DISTANCE`
 */
void buzz(unsigned long distance) {
  requires(distance < MAX_DISTANCE);
  int x = MAX_BUZZ - int_log2(distance);

  warn(x);
}

/**
 * @brief     Calculate log2 of an integer
 * @param[in] x
 * @return    log2(`x`)
 * @pre       `x` is non-negative
 */
int int_log2(int x) {
  requires(-1 < x);

  int c = 0;
  if (x == 0) return 1; 
  while ((x >>= 1)) { c++; }
  return c;
}

/**
 * @brief     Run the buzzer a number of times
 * @param[in] x The number of times
 * @pre       `x` is non-negative
 * @pre       `x` is less than or equal to 7
 */
void warn(int x) {
  requires(-1 < x);

  for (int i = 0; i < x; i++) {
    digitalWrite(BUZZER_PIN, HIGH);
    delay(50);
    digitalWrite(BUZZER_PIN, LOW);
    delay(50);
  }
  delay(500);
}

/**
 * @brief Turns the buzzer and led strip off
 */
void cleanup() {
  digitalWrite(BUZZER_PIN, LOW);
  fill(0, 0, 0);
}

Design File

Rhino file that was used to laser cut all the pieces of this device.

]]>
Team Fornax: Interview with Jeff https://courses.ideate.cmu.edu/60-223/f2022/work/team-fornax-interview-with-jeff/ Tue, 08 Nov 2022 13:26:23 +0000 https://courses.ideate.cmu.edu/60-223/f2022/work/?p=16757 Introduction:

This interview was conducted by team Fornax, which includes Ethan, Frances, and Gia. We interviewed Jeff on Tuesday November 1st, at 6pm. Our team went into the meeting with the intention of learning about Jeff’s daily struggles effected by his disability, and what he wants to add in his life. However, we also wanted to let Jeff know our intentions and limitations, and make sure he didn’t have any questions. Our hope was that after the meeting we would have a few ideas on how what kind of assistive gadget we could create to make Jeff’s life better or more convenient.

Agenda:

Before the interview we wrote out a bunch of questions and follow up questions that we planned to run through. We didn’t plan to use it as an exact format where we went down the list. It was more so just to make sure we had enough questions to get a solid interview. I think we went through almost every question.

We also wrote up an outline for an introduction to make things clear with Jeff so he knows where we are coming from. It was mostly based on the outline Zach gave us.

Here were the list of questions:

Say: our names – our backgrounds

Ask client to introduce themselves: name, interest in participating in this

Say project goals:

  • Trying to build prototype useful devices (making a convenience machine/ gadget)
  • Engaging in an iterative design process, including gathering formative feedback around the midpoint of the process
  • Taking about seven weeks to go from this meeting to a reasonably high-fidelity final product (explain timeline)

We are not

  • Professional technologists who are experienced in making polished products
  • Planning to build something that will be sold commercially
  • Constrained by any practicality outside of usefulness to the person we’re designing for
  • Likely to invent a totally novel piece of electronics (say limits of Arduino)

Ask client if they have questions about process

Interview Questions (follow up questions in bullet points)

Are there any Daily life activities that are frustrating/difficult? You can list it or go into detail about a few?

  • Can you group your problems into a couple big categories
  • Can you demonstrate it?
  • What makes it difficult?
  • Is there a product you think that can help mediate this?

Is there something you use to enjoy doing that has become harder over time?

    • Is there any creative ideas you have to help this issue
    • Is there a way to make it somewhat easier again
    • What would encourage you to do this activity again?

Could you narrate or draw your daily life?

      • What’s the typical routine?
      • Common emotions throughout the day?
      • What do you look forward too?
      • What do you not look forward too?

What do you care about?

  • Why is it important to you?
  • How would you want to implement it more into your life?
  • What ways can you think of that would bring this into your life more?

What do you need that maybe you don’t always get?

  • What hinders you from this

How would you improve your resources and tools now?

  • Ways to add on or subtract?
  • Is a completely new device needed? Or add on to what you have now?

Tell us some story about inconveniences that come up in your life?

Meeting Summary and Major Takeaways:

Before we could design a unique device for Jeff, it was important for us to understand Jeff’s hobbies and interests. The meeting started with us asking Jeff about his daily routine. Jeff highlighted that his favorite parts of the day are playing video games with his best friend, recording and watching YouTube, and sitting on back porch. Jeff informed us that he decided to participate in this project because he: “likes the invention of new technology”. After getting to know Jeff a bit more, we then began to explore possible avenues in which a device could assist Jeff in his daily life.

At an earlier point, Jeff mentioned that he works as a receptionist at CLASS for a couple days of a week. We asked if there were any little annoyances that he may experience due to being in a wheelchair. Jeff told us his only pet peeve is wh

en the receptionist working the previous shift doesn’t cleanup after themselves. We decides as a group, that this in an avenue we don’t want to further explore. Naturally we then talked more about Jeff’s life at home. We learned that Jeff has a two-year old nephew, who occasionally leaves their toys out on the floor. We asked Jeff he deals with this situation, he told us that he would always get someone else to clean the toys up. This striked us as a possible avenue that we could explore. We also learned that Jeff sits on his back porch because his front porch is at a slight angle. Jeff emphasized to us that he is always nervous about being on the front porch without someone behind him. He said if he would feel more comfortable if he knew that he would be okay by himself.

Quick sketch of wedges elevating a wheelchair

Towards the end of the hour, we talked to Jeff about his YouTube channel. We learned that Jeff likes to make reviews about music albums. We asked Jeff about how he records his videos. We discovered that his setup was very minimalist, he simply records only using his computer in one take.

 

Quick sketch of the Toy Sweeper

Thinking of ways to create the toy sweeper

Post Interview Thoughts: 

Our interview did not quite go how we expected. Jeff was quite satisfied with how his life functioned and it was a bit difficult for us to ideate some ideas for how to improve his experience. It was difficult to get the conversation started, but slowly but surely, we discovered more and more about Jeff’s life. The agenda we had come up with was definitely not adhered to, as we came up with a lot of follow up questions that we didn’t ever get to. 

I think part of the reason that our interview was not quite as successful as we wanted it to be was that we came into the interview assuming that Jeff would have suggestions on what he thought might be a good gadget. Though he was very receptive with ideas that we suggested, it was difficult to get him to complain about his own life. 

In hindsight, our team wished that we asked a little more about the details of the wheelchair itself, as a lot of our ideas were built on improving the wheelchair. We could have asked about the dimensions or the braking system, which might have been good jumping off points for possible ideas. The ideas that we came up with were quite mechanical, and were grasps on the parts of Jeff’s life that we thought we could ease even more, but not necessarily the most achievable and reasonable ideas. 

That being said, I think our interview served its purpose. We got to learn more about the life of Jeff, and we came up with several possible project ideas that we can build on. 

]]>
Do Not Disturb Toaster https://courses.ideate.cmu.edu/60-223/f2022/work/do-not-disturb-toaster/ Thu, 27 Oct 2022 11:16:27 +0000 https://courses.ideate.cmu.edu/60-223/f2022/work/?p=16623 This device is intended to let everyone around you know when you are working or not so that you are able to stay on task.

This is the toaster switching from free time mode to work mode. You see once work mode is on, the lights starts to flash which is from the noise in the room. The linear actuator has to complete its’ movement before the mode properly switches.

Main Photo For Scale: The toaster has a “Do Not Disturb” sign and a “Free To Talk” sign at the top. 10 LEDs on the top. An LCD that says “Break Time!” or “Work Time!”. A switch to start timer and sound sensor are in the back.

Detail Shot: This gives a good view of the top so you can see the whole top and all the LEDs. Also in this photo you can see the button, sound sensor, and the hole for all the cords, which is located on the back of the toaster. When the button is clicked it starts the Pomodoro timer.

Detail Photo: This is the inside of the toaster. The wiring is pretty intense because of the 10 LEDs. I had to tape/puddy some connections so they wouldn’t come undone. I taped down/glued two bread boards inside so they stayed stable in the box to avoid loose connections, and so the switch would be available on the outside of the box.

Action Photo: When the “Free To Talk” sign is up that means it is break time according to the Pomodoro timer. The timer will constantly switch between 25 minutes and 5 minutes because it is based off the Pomodoro technique for most efficient work. Work time is suppose to be 25 minutes long and break time is 5 minutes long.

When the “Do Not Disturb” sign is up that means it is work time. The lights will flash if you start talking and if you talk loud enough they will blink red for 1 second to alert you that you are distracting the user from being productive. When the “Do Not Disturb” sign lowers then the toaster will stop flashing the LEDs.

Action Photo: There is an LCD screen that is for the user to look at so they can know if it’s break time or work time. It is also there as another reminder to stay focused.

Action Photo: The sound sensor does not send signals to the lights when the “Free To Talk” sign is up. If there is minimal noise the lights will not light up. The toaster needs to detect “disturbing levels of noise” to flash lights. This makes it so the toaster can be used in a public area and notify people when they are being too disturbing so that the user doesn’t need to do it themselves.

Process

The first big decision in my process was deciding how the sound detector was going to identify it’s signals. I originally organized my sounds into quiet, moderate, and loud. After Zach helped me get a more reliable sound detection, I started messing with the sensitivity. I was adjusting what the Arduino identified as quiet and loud, and at this point I made the decision on what the toaster is going to react too. I decided that first of all there was going to be some wiggle room so that a loud room does not trigger the toaster. Then I made the decision that moderate and loud would have different response. I decided here that the toaster should get “more angry” when it detects loud noise, which would cause it to flash the red light longer. I think this thinking and decision making really effected the logic of my code and how I approached it. This decision came pretty earlier on and I think that is made obvious by how I coded the whole device. It overall had a heavy influence on the design.

The second big decision came much later in the process. When I was deciding how the toaster was going to look, I also considered how it was going to act and be interacted with. I made a couple last minute decisions when designing the outer look and experience. There were two things that I felt like were feeling unclear in my design. First, I was concerned it wouldn’t be obvious enough when the toaster would detect loud sounds. This made me realize I am going to need an LED strip or lots of LEDs. I decided that the design would look kinda pretty and less tacky if used little LEDs and had them dotted around the top, plus it would be hard to miss many LEDs flashing at you, especially 10. Secondly, I realize for some it may not be fully clear when it is break time or work time, so that is when I decided the LED screen was necessary, because it wasn’t always planned to be in the design. Thus, when I was designing the lasercut box I put in a rectangle hole for the LCD, however there was then an even more last minute switch up. Last minute I realized I made a switch for my box and that needs to be easily accessible on the outside. So, I ended up using the LCD hole as a place to put the breadboard with the switch in it so I didn’t have to open the box to start it. In the picture you can see the lasercut box before it’s fully assembled, and at this moment is when I realized I need to move the switch off my big breadboard and onto a tiny one.

 

This is the first sketch of my device. What’s interesting is in the beginning of ideating I wasn’t thinking about the code as much, so in this drawing I have a knob that you can turn to the amount of time you want to work. I quickly realized after I moved out of ideating that this could be difficult and would potentially be a lot of coding, so I later opted for a button which is a simple on/off mechanism rather than the user being able to select a time.

This is my setup to test the sound detector to light signal. So this helped me visualize how sensitive the sound detector is and also if the LED would actually light up when I wanted too. I did a lot of clap and talking and yelling with this simple set up when trying to calibrate my sensor properly.

 

During the whole coding process I constantly had many Arduino files open. That is for a couple reasons. First reason is because I was looking at example code and trying new things out, so if I wanted to try a new approach I just made a new sketch and attempted in the new sketch (hence in this picture why I have two LCD sketches). Secondly, some sketch files were more for testing sensors or outputs. I had one sketch file that would reset the linear actuators for me. I also had a sketch file that would test the sound detector. I had another sketch file that would print the timer on the LCD screen for me. All of this helped me debug my code. Lastly, I was scared of messing up whatever I made work successfully, so I had each part of the system in it’s own sketch. Thus, I had an LCD sketch, Timer sketch, Sound Sensor + LED sketch, and a linear actuator sketch. So at the end of coding I had to compile all my sketches together carefully and neatly.

This is me wiring the button. I never wired a button before I had to kinda look it up and guess, but it ended up successfully and coded the button after wiring it.

I had a lot of trouble with making the linear actuator fit into the code properly with my timer code I made. The main reason is because linear actuators aren’t told to go a distance, they are just told to go and stop. The example code I referenced used delays to make the linear actuator go the distance it wanted, so it was really difficult to fit that into code that was all based around millis(). It took a lot of experimenting with the linear actuators just sat on the table until I was able to figure out the code. It was also difficult because I have a break time mode and a work time mode in my code, so at first I had no idea where which linear actuator should be extended or retracted. That took a little bit of guessing and thinking through.

Discussion

I am overall pretty happy with my project. I think it does exactly what I intended it to do. It detects sound levels decently well and the linear actuators actually work perfectly how I intended them too. I think if anything I wish I could add in more of my fun ideas. For example, I wish I could add more stimuli to happen when the noise levels get loud. I think that would make the project even more fun and interesting. I also wish I did put more time into the design of the project just because I am a design major and I think it would enhance the interaction of this device.

 

Overall, I did fumble a lot along the way. I think I still don’t fully understand the sparkfun sound detector. I tried to calibrate it exactly how I wanted, but I only had so much time and I never got back around to it. Yet, the hardest part was actually making the timer and switching the modes between work and break. I am used to coding in functions, so for me, it is hard to code into a loop. A couple times I forgot that the program is constantly looping, which caused bugs. It took me a while to figure out ways around it (aka I made variables that acted as switches), but it was hard to figure out how to make my initial logic work. Then after that I had to add in the linear actuator code which was challenging because I couldn’t remember where break mode and work mode was being turned off and on. So, I think overall, my code could’ve been much cleaner because it started to confuse me. I think there’s too many switches on and off and there must be a way to simplify and make the variable names clearer.

The critiques brought up some great points and I actually ended up listening to one of them. The first one that stood out said “Maybe add double sided signs and have the signs disappear all the way into the toaster”. I strongly agreed with them and I ended up remaking my signs to be double sided and sturdier, however, the linear actuators are too tall to actually get the signs all the way in, but I would’ve loved to also incorporate that into my design. The second critique said “I would say if, theoretically, you were trying to use this device in a library, or somewhere quiet, then the sound of the linear actuators might be a bit loud and counterintuitive for its purpose”. I honestly don’t have a solution for that currently, but I thought this was an interesting thing to point out. I kinda agree that the sound could end up being distracting, yet my limitations were partially due to what was available.

If I were to make a whole new iteration, I would definitely clean up the wiring and code, since those both caused me lots of extra time. However, I also think there’s so many ways to expand on this idea like adding a more advanced timer, or adding more interactions that help keep you on task, thus I think this would be a really good project to iterate on because of the endless possibilities.

Technical Information

/* The Do Not Disturb Toaster
  By: Gia Marino

  My code has a switch that tells when the program should start.
  Then the program takes a start time and starts calculating time passed.
  If currentTime hits 25 mins and the program is not in break mode
  then it will switch over to break mode and move the linear actuator to
  indicate this. If it is in break mode and the currentTime hits 5 minutes
  then the program will switch into break mode and moves linear actuator
  accordingly. If in workmode the program will take inputs from the sound
  detector and send signals to the LED pin if detects moderate or loud noise.
  It continuously switches inbetween these modes unless stopped.


  Arduino pin | role   | description
  ------------|--------|-------------
  A0            input    enevelope pin on sound detector
  2             output   gate pin on sound detector
  6             output   LED pin
  4             input    button pin
  7             output   DO NOT Disturb linear actuator
  8             output   DO NOT Disturb linear actuator
  11            output   FREE to talk linear actuator
  12            output   FREE to talk linear actuator
  SDA           output   LCD serial pin
  SCL           input    LCD clock pin
  GND           input    ground
  5V            output   5v

  My linear actuator code was inspired by
  https://www.firgelliauto.com/blogs/tutorials/how-do-you-control-a-linear-actuator-with-an-arduino.
  I used this code to start and ended up breaking it up into two parts and putting that into my if
  statements. Secondly, my sound detector code was copied from
  https://learn.adafruit.com/adafruit-microphone-amplifier-breakout/measuring-sound-levels. I basically
  left most of it the same since it worked well for my application and I labeled it as the sound detector code.
  Additionally, I used https://learn.sparkfun.com/tutorials/sound-detector-hookup-guide/all#software-example
  as a launchpad to creating my sound detector code. I ended up not following it for my main code, but my code
  may be slightly inspired by this source. To understand button wiring and coding, I referenced https://youtu.be/TIBa_RQB3Ek.
  Lastly, we copied the LCD tutorial code and worked off of that, so our code for the LCD display
  is also heavily influenced by this tutorial: https://courses.ideate.cmu.edu/60-223/f2022/tutorials/I2C-lcd
*/


//LCD set up
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C screen(0x27, 16, 2);

#define BUTTON_PIN 4    //button pin
#define PIN_GATE_IN 2   //sound detector
#define PIN_LED_OUT 6   // all LEDs are hooked up to pin 6
#define PIN_ANALOG_IN A0    //sound detector

// sound detector variables
const int sampleWindow = 50; // Sample window width in mS (50 mS = 20Hz)
unsigned int sample;

bool workTimerSwitch; //tells the program it is work mode
bool breakTimerSwitch;  //tells the program it is break mode
//this tells program whether it is break time mode (when 1) or work time mode (when 0)
bool breakTimerON;

unsigned long startTime; // when the timer starts
unsigned long currentTime = 0; // how long the timer has been going

bool DEMO_MODE = 1; // Demo mode is turned on if 1
bool startToaster = 0;  // variable that indicates that button turned on toaster
bool TURN_MIC_ON = 0; // lets the program know whether the LEDs should flash if theres sound


void setup() {

  Serial.begin(9600);
  pinMode(BUTTON_PIN, INPUT);
  pinMode(PIN_LED_OUT, OUTPUT);

  //LCD
  // initialize the screen (only need to do this once)
  screen.init();
  // turn on the backlight to start
  screen.backlight();
  screen.clear();

  //break time actuator
  pinMode(7, OUTPUT); // Configure pin 7 as an Output
  pinMode(8, OUTPUT); // Configure pin 8 as an Output

  digitalWrite(7, HIGH); // Initialize pin 7 as Low
  digitalWrite(8, HIGH); // Initialize pin 7 as Low

  //work time actuator
  pinMode(11, OUTPUT); // Configure pin 11 as an Output
  pinMode(12, OUTPUT); // Configure pin 12 as an Output

  digitalWrite(11, HIGH); // Initialize pin 11 as Low
  digitalWrite(12, HIGH); // Initialize pin 12 as Low


}

void loop() {

  unsigned long globalTime = millis(); // the global time

  //this variable stores whether button was pressed
  int ON = digitalRead(BUTTON_PIN);

  // if button is pressed then this if statement swtiches the startToaster
  //variable on HIGH which will start the program
  if (ON == 1) {
    startToaster = 1;
  }

  if (startToaster == 1) {
    currentTime = globalTime - startTime; // calculates currentTime
  }

  if (currentTime >= 1500000) { // work timer reached 25 mins
    Serial.println("25 mins!");

    // Retracts Linear Actuator
    digitalWrite(11, HIGH);
    digitalWrite(12, LOW);
    delay(2000); // 2 seconds
    // Stop Actuator
    digitalWrite(11, HIGH);
    digitalWrite(12, HIGH);

    // extends breaktime linear actuator
    digitalWrite(7, LOW);
    digitalWrite(8, HIGH);
    delay(2000); // 2 seconds
    digitalWrite(7, HIGH);
    digitalWrite(8, HIGH);

    // it is break mode so sound does not need to activate LED
    TURN_MIC_ON = 0;

    //LCD
    screen.home();
    screen.print(String ("Break Time!"));

    startTime = globalTime; // reset
    breakTimerSwitch = 1; // turns on break time mode
  }

  // this is so the program doesn't continue to loop in the workTimer statment
  // b/c otherwise it would continue to reset startTime which would make currentTime zero
  // hence why the variable is labeled as a switch
  if (workTimerSwitch == 1) {
    startTime = globalTime;
    workTimerSwitch = 0;
  }

  if (breakTimerSwitch == 1) { // break timer switched on
    breakTimerON = 1;
    startTime = globalTime; // reset
    breakTimerSwitch = 0; // switch is turned off so program doesn't loop in statement
  }

  if (breakTimerON == 1) {
    if (currentTime >= 300000) { // 5 mins
      Serial.println("5 mins!");

      // Retracts break time Linear Actuator
      digitalWrite(7, HIGH);
      digitalWrite(8, LOW);
      delay(2000); // 2 seconds

      // Stop Actuator
      digitalWrite(7, HIGH);
      digitalWrite(8, HIGH);

      // Extend Linear Actuator
      digitalWrite(11, LOW);
      digitalWrite(12, HIGH);

      delay(2000); // 2 seconds

      // Stops Actuator
      digitalWrite(11, HIGH);
      digitalWrite(12, HIGH);

      // sound detection should now activate LEDs since in work mode
      TURN_MIC_ON = 1;

      // LCD
      screen.home();
      screen.print(String ("Work Time!"));

      startTime = globalTime; // reset
      breakTimerON = 0; // will make program exit this if statement
      workTimerSwitch = 1; // switch into work mode
    }
  }

  // SOUND DETECTOR CODE
  if (TURN_MIC_ON == 1) {
    unsigned long startMillis = millis(); // Start of sample window
    unsigned int peakToPeak = 0;   // peak-to-peak level
    unsigned int signalMax = 0;
    unsigned int signalMin = 1024;

    // collect data for 50 mS
    while (millis() - startMillis < sampleWindow)
    {
      sample = analogRead(PIN_ANALOG_IN);
      if (sample < 1024)  // toss out spurious readings
      {
        if (sample > signalMax)
        {
          signalMax = sample;  // save just the max levels
        }
        else if (sample < signalMin)
        {
          signalMin = sample;  // save just the min levels
        }
      }
    }

    peakToPeak = signalMax - signalMin;  // max - min = peak-peak amplitude
    double volts = (peakToPeak * 5.0) / 1024;  // convert to volts

    if (volts <= 0.10) // quiet noise levels
    {
      Serial.println("Quiet.");
      digitalWrite(PIN_LED_OUT, 0);
    }
    else if ( (volts > 0.10) && ( volts <= 0.30) )
    {
      Serial.println("Moderate.");    // moderate noise levels
      digitalWrite(PIN_LED_OUT, 50);
    }
    else if (volts > 0.30)
    {
      Serial.println("Loud.");     // loud noise levels
      digitalWrite(PIN_LED_OUT, 200);
    }
  }

  // DEMO MODE

  if (DEMO_MODE == 1) { // DEMO MODE is turned on
    if (currentTime >= 6000) { // 1 min

      // Retracts Linear Actuator
      digitalWrite(11, HIGH);
      digitalWrite(12, LOW);
      delay(2000); // 2 seconds
      // Stop Actuator
      digitalWrite(11, HIGH);
      digitalWrite(12, HIGH);

      // extends breaktime linear actuator
      digitalWrite(7, LOW);
      digitalWrite(8, HIGH);
      delay(2000); // 2 seconds
      digitalWrite(7, HIGH);
      digitalWrite(8, HIGH);

      // it is break mode so sound does not need to activate LED
      TURN_MIC_ON = 0;

      //LCD
      screen.home();
      screen.print(String ("Break Time!"));

      startTime = globalTime; // reset
      breakTimerSwitch = 1; // turns on break time mode
    }
    if (breakTimerON == 1) {
      if (currentTime >= 6000) { // 1 min

        // Retracts break time Linear Actuator
        digitalWrite(7, HIGH);
        digitalWrite(8, LOW);
        delay(2000); // 2 seconds

        // Stop Actuator
        digitalWrite(7, HIGH);
        digitalWrite(8, HIGH);

        // Extend Linear Actuator
        digitalWrite(11, LOW);
        digitalWrite(12, HIGH);

        delay(2000); // 2 seconds

        // Stops Actuator
        digitalWrite(11, HIGH);
        digitalWrite(12, HIGH);

        // sound detection should now activate LEDs since in work mode
        TURN_MIC_ON = 1;

        // LCD
        screen.home();
        screen.print(String ("Work Time!"));

        startTime = globalTime; // reset
        breakTimerON = 0; // will make program exit this if statement
        workTimerSwitch = 1; // switch into work mode
      }
    }
  }
}

 

]]>
Double Transducer: RPM to Light to Magnetism https://courses.ideate.cmu.edu/60-223/f2022/work/double-transducer-rpm-to-light-to-magnetism/ Thu, 29 Sep 2022 05:35:21 +0000 https://courses.ideate.cmu.edu/60-223/f2022/work/?p=16294 by Gia Marino and Freda Su

Overall Photos

The whole transducer.

The whole double transducer.

Pictures of Each Part and Videos

Electromagnet. It creates a magnetic field when power runs through it’s coils

RC circuit and transistor circuit. Smoothes out and amplifies current.

Soldered LED and photo-resistor circuit. The photo-resistor detects the brightness of the LED

The rotary encoder wiring on a separate bread board. Reads RPM

Videos:

 

Simple Narrative Description

The knob measures how fast it’s spinning. This controls how bright the blue light will be, which is then measured by a light detector. The amount of light measured is used to determine how strong the magnet will be.

Process

Ideation

Or ideation for our double transducer

We had a few ideas for different energy forms, such as light, sound, and heat, as well as moving a magnet different distances. Some things, such as the sound and heat, would be hard to detect accurately, so we eliminated those ideas. Zach said the electromagnet might be a bit tricky but feasible and creative. He also recommended the simpler light transmission/detector system for the middle step, so we get more time to focus on the hard stuff.

Rotary Encoder

Getting rotary encoder to work

serial print screen equations

First, we learned about the Encoder library by Paul Stroffogen. We found a pin diagram online and ran the Basic code given with the library, and watched how the numbers in the Serial monitor changed as we twisted the knob. The numbers increase for rotating in one direction and decrease for the other direction, which is why you see the negative sign in the picture. We originally calculated angular velocity to convert to RPM but then switched to doing the math based on the ticks.

 

The fun part was obviously the math for figuring out how these numbers relate to calculating the RPM.

  1. Count the number of ticks it takes to complete 1 rotation: assuming the ticks are evenly spaced, then we can figure out how much of a rotation has happened by looking at the difference of two ticks.

    For our rotary encoder, there were 80 ticks per rotation, which means [latex]\frac{1 rotation}{80 ticks}[/latex] so each tick is [latex]\frac{1}{80}[/latex]th of a rotation.
  2. Time frame of measurement: counting ticks for a minute would be too slow, so it’s better to measure over a small portion of time and extrapolate the “instantaneous” RPM. We decided to measure over 1ms, since we have the millis() function in Arduino built in. Using dimensional analysis:

    (x ticks/ms) * (1 rotation/80 ticks) * (60000ms/min) ends up with units of RPM.

The LED

Brighter LED

Dimmer LED

We used analogWrite to send different voltages to the LED to give it different brightness. We also used the lowest resistor and tried different colors to see what could give us the brightest LED so that the change in brightness would be most drastic. The Serial monitor shows the brightness detected by the photoresistor, which helped us find the photoresistor range also.

Electromagnet

RC circuit Zach helped us simulate

Electromagnets with different coil size and wrapping

Testing the magnetic field

https://drive.google.com/file/d/1RH2CfyKH7a7ctSiBseOcUsEurZxuO4Pa/view video of capacitor resistor circuit reacting to changing voltages 
(too big to upload)

 

  1. We need to make sure the electromagnet works by itself, so we wrapped copper wire around a metal screw and drove current through it. At first, it wouldn’t pick up any paper clips at all:
    1. First, we added a lot more coils to make the magnet stronger.
    2. When that still didn’t work, we sanded the ends for a better connection with the 9V power supply we were using.
    3. That still wasn’t quite strong enough because it turns out the wire itself interfered with the magnetic field, so we had to sand off the outside layer. As you can see in the comparison between the 2 screws, the wire on the top (unsanded) is a stronger bronze color than the bottom screw (sanded), where you can see a lighter, more sandy/dusty brown where it was successfully sanded.
    4. We experimented with 2 different wire thicknesses for the coils and discovered that the thicker wire became a stronger magnet for about the same amount of coils. In addition, the thinner wire would break a lot more often when trying to sand the ends, so we like the thicker wire better.
  2. We learned that Arduino’s analog output isn’t truly a constant voltage, but more of a rapid cycle between the amount of time it sends 5V and 0V such that the “average voltage” is somewhere in between (Pulse Width Modulation). However, the electromagnet wouldn’t like the sudden changes between 5V and 0V, so we need to smooth out the voltage with a RC (resistor capacitor) circuit so it would become some close to “constant” voltage between 5V and 0V, turning it into a true analog voltage.
    1. This website simulates how the duty cycle turns into a smooth line: https://falstad.com/circuit/circuitjs.html?ctz=CQAgjCAMB0l5YCcyWrQDhAZjDA7HuugKwBMW6iYeFALNgGwjHOTMCmAtGGAFADyIWnHAM2xMKVFsZvAOZCRpIorZZSMqLwBOIUsOmrDbUht4BjI2DFHlmGbAQhu0WsmLoshPJH1IsWFCOfABKegbWbNRMkVB6VpoOtKS8APZx6nHCiJgsMPCQiHgMxAykeeC8FEIgAGIQFbhs3CAAIgCuAC4AngA6AM4Awt3mADbsvAAW2PFYvEA
  3. We also needed a transistor (IRLB8721PbF) in order to give the electromagnet enough current, since the Arduino doesn’t have much. The transistor takes in a voltage at the Gate terminal (output of RC circuit) and amplifies the output to the electromagnet. The value of transistors is that a small change in the Gate voltage would result in a much larger difference in the current, which would thus change the magnetic field strength.
    1. We started with trying the default parameters given in the website, because why not. Those values turned out to work well, so we kept those.
    2. We also added a heat sink to the transistor because it became hot quickly.

Discussion

While the project seemed pretty straightforward at first, there were details that we didn’t really consider that took more time than it should have. For example, even with simple parts of the system, such as the LED, we had to try different colors of LEDs/resistor combinations, because it turns out that they glow with different brightness when they all have the same amount of current. We wanted to use the brightest LED in order to give the photoresistor the widest range of values possible, since every LED can be dimmed to the same level, but not every LED can be brightened to the same level. Other small things that took longer than it should have included needing to sand all the wire used around the electromagnet, since we didn’t realize that the coating could interfere with the magnetic field until we tested it. Another problem we ran into was that the LCD would flash in order to refresh the correct values, and we tried for a while to get rid of the flashing at first, but couldn’t. So we realized it was probably just a necessary quirk of the system. Also we realized that we should’ve put more time into figuring out the LCD because ours didn’t end up working properly and it was most likely a little mapping issue we missed.

 

Secondly, for some reason one of the circuits that was working normally before suddenly decides to shut off whenever the rotary encoder spins. Not sure why that happens, and Zach wasn’t able to figure it out either. Another team suggested later that it could be that the other components use too much power, causing the Arduino to shut off. Of course, there could be other issues such as poor connections as well, but we double checked those, and again, it was working before without modifying anything.

 

If we were doing this again, perhaps we could consider doing different strategies for dividing the work. For this project, we both worked on the same part of the system at once. The benefits were that we both learned more deeply about each part of the circuit, and could help each other debug better because of it. However, this may not have been the most time efficient approach, since the output produced would be limited to whatever part of the system we were doing, instead of perhaps being able to make progress on multiple parts at once. But at the same time, by each working on different parts, perhaps we wouldn’t have as deep of an understanding of each step, and thus be less effective at helping each other debug. Perhaps we could take a mixture of these approaches and do the easy parts concurrently, but work on the hard parts together.

Functional block diagram and schematic

 

Code

/* Double Transducer: RPM to Magnetism 
Gia Marino and Freda Su

Our code takes inputs from a rotary encoder and translates them to positions on a 
tiny circle in the encoder. We used these positions to calculate the RPM based on 
the number of ticks that go by. Then we take that number and map RPM into a 
0 to 255 so that the LED can change brightness based on the rotation speed. Then we 
have the photoresistor that reads the brightness of the LED and maps it into a range
of 0 to 255 so it can send a voltage to our electromagnet. Lastly, the code takes the
RPM, LED input value, LED brightness, and input value into the electromagnet and maps
it into a range of 0-99. then prints it on the LCD screen

 Arduino pin | role   | description
 ------------|--------|-------------
 A3            input    photoresistor pin
 9             output   electromagnet pin
 6             output   LED pin
 2             input    rotary encoder pin A
 3             input    rotary encoder pin B
 SDA           output   LCD serial pin
 SCL           input    LCD clock pin
 GND           input    ground
 5V            output   5v

We based our if statement for the rotary encoder around Paul Stoffregen's Encoder
library code: https://github.com/PaulStoffregen/Encoderthe, specifically the "basic" 
example that comes with the library. We had a lot of assistance and influence from Remy's 
code for the LCD display (https://github.com/remyfrank01/Double-Transducer/blob/main/DOUBLE_TRANS.ino).
Lastly, we copied the LCD tutorial code and worked off of that, so our code for the LCD display 
is also heavily influenced by this tutorial: https://courses.ideate.cmu.edu/60-223/f2022/tutorials/I2C-lcd*/



#include <LiquidCrystal_I2C.h>  ////https://courses.ideate.cmu.edu/60-223/f2022/tutorials/I2C-lcd
#include <Wire.h> //LCD display
#include <Encoder.h> //https://www.pjrc.com/teensy/td_libs_Encoder.html

const int PHOTOPIN = A3; // photoresistor pin
const int LEDPIN = 6; // LED pin
const int EMPIN = 9; // electromagnet pin
const int totalTicks = 48; // amount of steps in one full rotation of the rotary encoder
const double anglePerTick = 1.0/totalTicks; // one Rotation/total ticks

/* Create an LCD display object called "lcd" with I2C address 0x27
    which is 16 columns wide and 3 rows tall. You can use any name you'd like. (col, row)
    (0,0) (1,0) (2,0) ... (15,0)
    (0,1) (1,1) (2,1) ... (15,1)*/
LiquidCrystal_I2C lcd(0x27, 16, 2);
Encoder myEnc(2,3); //pins 2 & 3 should have interrupt capablility

void setup() {
  pinMode(PHOTOPIN, INPUT);
  pinMode(LEDPIN, OUTPUT);
  pinMode(EMPIN, OUTPUT);
  Serial.begin(9600);
  Wire.begin();
  
  // initialize the lcd (only need to do this once)
  lcd.init();

  // turn on the backlight to start
  lcd.backlight();
  lcd.clear();

}

unsigned long time0 = millis(); // time since last checked the rotary encoder
unsigned long timerLCD = millis(); // timer used for LCD dispkay
long oldPosition = -999;
float angVel; // anglular velocity
unsigned int brightness = 0; //the input for the LED that controls the brightness
unsigned int photoVal = 0; // the value we get from the photoresistor
unsigned int voltage = 0; // electromagnet voltage
unsigned int rpm = 0; // rotations per min calculated from rotary encoder steps


void loop() {

unsigned long globalTime = millis(); 
  
  long newPosition = myEnc.read();

  // convert ticks to rpm
  if (globalTime - time0 >= 1) { // checks every second
    double countTicks = abs(newPosition - oldPosition); // figures out how many steps passed by 
    oldPosition = newPosition;

    // reset time so when loop runs again we base our math on the most recent last position
    time0 = globalTime; 

    angVel = countTicks * anglePerTick;
    rpm = angVel * 60000; // converts just calculated angular velocity to RPM
  }

    // takes RPM and calculates a mapped output voltage so brightness is affected by rpm speed
    brightness = map(rpm, 0, 60, 0, 255);  //120-360 deg/sec to 0-255 analogWrite
    analogWrite(LEDPIN, brightness);

    //takes photoresistor value and maps an output voltage for the electromagnet so
    // it varies based on the photoresistor values
    photoVal = analogRead(PHOTOPIN);
    voltage = map(photoVal, 0,1023, 0, 255); //adjust photoVal range: 0-1023 photoVal to 0-255 analogWrite
    analogWrite(EMPIN, voltage);

  //LCD display
  
  if (millis() - timerLCD >= 250) {// every 1/4 sec
    timerLCD = millis();  //reset
    lcd.clear();
    // set cursor to home position, i.e. the upper left corner
    lcd.home(); 
    int mappedRPM = map(rpm, 0, 60, 0, 99);
    if (mappedRPM > 99) mappedRPM = 99;
    else if (mappedRPM < 0) mappedRPM = 0;
    lcd.print("i:" + String(mappedRPM));  //convert to rpm

    lcd.setCursor(6,0);  //middle of first row
    int mappedBrightness = map(brightness, 0, 255, 0, 99);
    if (mappedBrightness > 99) mappedBrightness = 99;
    else if (mappedBrightness < 0) mappedBrightness = 0;
    lcd.print("m:" + String(mappedBrightness)); //convert brightness
    // move cursor to column 8, row 1
    
    lcd.setCursor(8, 1);
    int mappedPhotoVal = map(photoVal, 0, 1023, 0, 99);
    if (mappedPhotoVal > 99) mappedPhotoVal = 99;
    else if (mappedPhotoVal < 0) mappedPhotoVal = 0;
    
    lcd.print(String(mappedPhotoVal));
    // move cursor to column 13, row 2
    lcd.setCursor(12, 1);

    int mappedVoltage = map(voltage, 0, 255, 0, 99);
    if (mappedVoltage > 99) mappedVoltage = 99;
    else if (mappedVoltage < 0) mappedVoltage = 0;
    lcd.print("o:" + String(voltage));
  }

  //goes to RC circuit, transistor etc

}

 

]]>