Uncategorized – Intro to Physical Computing: Student Work Spring 2021 https://courses.ideate.cmu.edu/60-223/s2021/work Intro to Physical Computing: Student Work Fri, 16 Apr 2021 17:52:04 +0000 en-US hourly 1 https://wordpress.org/?v=5.6.13 Gestural Midi Controller https://courses.ideate.cmu.edu/60-223/s2021/work/gestural-midi-controller/ Fri, 09 Apr 2021 21:47:59 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12814

At last, a way to produce electronic music with physical gestures. Rotate your hand and wiggle a joystick to manipulate sound in four distinct ways.

Overview

At last, a way to produce electronic music with physical gestures. Rotate your hand and wiggle a joystick to manipulate sound in four distinct ways.

Relative proportion of Gesture Controller

Relative proportion of Joystick Controller

 

Graphical user interface and midi translator between Arduino and Logic Pro

Process Images and Review

The Controller was going to have two modes: Performance Mode and Wand Mode

In Performance Mode, all 3 axes of the accelerometer would control 3 different parameters. Side to side for Pitch Bend and vibrato, front and back for Modulation, and up and down for Expression.

In Wand Mode, a single parameter would react to the overall motion.

In both modes, the joystick would control two parameters with the X and Y axes, but they would control slightly different parameters depending on the mode.

I had two major problems. In the first one, I had to calculate the velocity and position based on the acceleration readings, for all 3 axes.

Code from the old physics suite: getDeltTime(), noiseGated(), and getRestingState()

The problem is that accelerometer readings are noisy and give data even when not moving. This random data was accumulating in the velocity calculations and causing my variables to overflow, and thus the position calculations were even worse.

I tried noise gating the data when the accelerometer was not moving (i.e. when the readings were at 0), and only letting the data through when above a certain threshold. But above that threshold, the readings were still noisy and inaccurate.

I scrapped almost all of that code.

Demonstrating the new gestures the controller will respond to. (Far left) Printing accelerometer rotation readings.

Instead, I decided to make only one Mode, one that uses only the acceleration readings form the Y and Z axes. For this purpose, the acceleration readings were accurate enough, and I already had plenty of success using it.

The second problem was this. In both of the old modes and the new one, the joystick’s click function was going to turn Arduino’s output on and off. This would have let me choose when my motion was intended for performance and when to have the computer ignore it.

(Left) Joystick detects several clicks at a time (bouncing). (Right) Solution: apply a minimum delay that I measured with a stopwatch.

First, I the joystick was reading several button-downs and button-ups with one single click (called bouncing). My solution was for the Arduino, as soon as it read a button press, to wait 5 milliseconds before it read anything else. I measured the fastest I could possibly double-click button by using my watch’s stopwatch, and found that was around 8 milliseconds.

Successful debounce and communication with Max.

Once I successfully debounced the button, I also successfully made Max register the button-down as distinct from the button-up. I even got Max to freeze and unfreeze the joystick’s output based on if the button was pressed not.

Unfortunately, for some reason, putting the joystick and accelerometer together, I was only able to unfreeze the Arduino’s output with a click-down command, but never freeze it again with a click-up. I never knew why, and scrapped that feature, too.

Discussion

Students’ Critique

This was one student’s response to my project, in particular, to my presentation.

It would be good to get a background about the project before diving right into the demo because I wasn’t sure what we were looking at initially.

I couldn’t agree more with this. The demonstration was just Logic playing back a synthesize chord, and my motion changing the sound in bizarre and uninteresting ways. I do like giving the audience a sense of discovery, but since I didn’t verbally give context, and my performance didn’t fill that gap either, my cues didn’t help the audience grasp the device’s usefulness.

Later I was playing around with my device, improvising a performance, and realized how easy and compelling it would’ve been to do that performance for my presentation. Rip.

I absolutely love this:

Is there a way to preset chords such that as you rotate your wrist, it plays a simple song forwards or backwards?

What comes to my mind is called an arpeggiator. This is a really good idea, and possibly an easy one to implement. I could do it in Max and have it generate MIDI notes there. Logic also has MIDI plugin that lets you program in JavaScript any MIDI effect; maybe I could do it there.

This critique was my favorite.

Maybe have some sort of way to set it while inside the bathroom and display outside

Go ahead and let that simmer :=)

Lessons Learned.

My absolute greatest success in this project was making the simplest tests I could come up with. Even before I typed a single line of code, I chopped up the entire project into these tests, and scheduled out when I was going to make them, weeks in advance. This also included making schematics for each sub-circuit I had to test.

I ran tests as simple as printing the accelerometer axes on the Arduino. I made the Arduino, by itself, talk to Max with hard-coded numbers. I made Max, by itself, talk to Logic. Then I put all of those together and made the accelerometer talk to Max, and later, to Logic. And thus I scaffolded from very simple examples like that to the entire finished build.

This made it extremely easy to isolate the unique bugs of each subsystem and not let issues from other systems bleed over. Not only did I learn how to solve these issues, I mostly only had to solve them once! Because then I could take that success with me for the entire rest of the build!

I did find that each test was way less trivial than I thought at first. I would have way more problems than I expected, and the seemingly really long time cushions I would allocate for myself, I would spend all of it, or more, trying to solve those problems. It made me all the more grateful to have made “small” tests, and also to have scheduled such long cushions.

I will definitely keep these very good project management habits.

Next Steps

In the next iteration, I will definitely keep in mind that fantastic idea of arpeggiation. Maybe the angle of my wrist could correspond to playback speed, or I could build upon that idea in different ways.

I will also make a much sturdier, reusable, plug-and-play version setup. One that I don’t have to rip everything up every time I need the parts for something else. One that lets me just plug in the Arduino, the joystick, the accelerometer, and all of the cables.

Dissembling (actually destroying) the device

It would also be fantastic to have a drop-down menu in Max that lets me select what MIDI parameter I want each accelerometer and joystick axis to affect, and through what MIDI channel. Right now those things are hard-coded, and I need to unlock the patch and change the code to change the mapping.

Technical Information

Functional Block Diagrams and schematics for final build, as well as sub-systems

/* Gestural Midi Controller
 *
 * Carlos Ortega (carlosor)
 * 
 * Reads data from all axes of an accelerometer and a joystick,
 * converts the data into a usable range for MIDI,
 * formats the data to be interpretted in Max/MSP,
 * and sends to Max.
 * 
 * Pin Mapping:
 * 
 * Accel x      A0
 * Accel y      A1
 * Accel z      A2
 * 
 * Joy x        A3
 * Joy y        A4
 * 
 * Joy Switch   2
 * 
 */

typedef int pin_t;
// Accelerometer pin mappings
pin_t ACCEL_X_PIN = A0;
pin_t ACCEL_Y_PIN = A1;
pin_t ACCEL_Z_PIN = A2;

// Joystick pin mappings
pin_t JOY_X_PIN = A3;
pin_t JOY_Y_PIN = A4;
pin_t JOY_SW_PIN = 2;

// Axis indices
typedef byte axis_t;
axis_t AXIS_X = 0;
axis_t AXIS_Y = 1;
axis_t AXIS_Z = 2;

axis_t JOY_SW = 255;

// Device type
typedef String device_t;
device_t DEV_ACCEL = "accel";
device_t DEV_JOY = "joy";

typedef String clickstate_t;
clickstate_t CLK = "clk";
clickstate_t UNCLK = "unclk";
clickstate_t NO_CHANGE = "no_change";

// Used for checking the moment 
// when the joystick switch was clickedf
clickstate_t last_clck_state = UNCLK;
unsigned long clickTimer = 0;

// Returns pin number for device at axis
pin_t getAxisPin(axis_t axis, device_t device)
{
  pin_t pin = 0;
  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X) pin = ACCEL_X_PIN;
    else if (axis == AXIS_Y) pin = ACCEL_Y_PIN;
    else if (axis == AXIS_Z) pin = ACCEL_Z_PIN;
  }
  else if (device.equals(DEV_JOY))
  {
    if (axis == AXIS_X) pin = JOY_X_PIN;
    else if (axis == AXIS_Y) pin = JOY_Y_PIN;
    else if (axis == JOY_SW) pin = JOY_SW_PIN;
  }
  return pin;
}

int getData(axis_t axis, device_t device)
{
  pin_t pin = getAxisPin(axis, device);
  if (axis == JOY_SW) return digitalRead(pin);
  return analogRead(pin);
}

// Have 5 millis passed since last switch?
bool clickWaitOver()
{
  return millis() - clickTimer > 5;
}

void updateClickTimer()
{
  clickTimer = millis();
}

// Determine if button was just now clicked, unclicked, or no change.
clickstate_t getSetClickState()
{
  clickstate_t clickState = last_clck_state;
  if (clickWaitOver())
  {
    // clickTimer = 0; // Reset timer
    
    bool clickedThen = last_clck_state.equals(CLK);
    // Input pullup makes for inverted button pressed state
    bool clickedNow = getData(JOY_SW, DEV_JOY) == LOW;

    if (!clickedThen && clickedNow) clickState = CLK;
    else if (clickedThen && !clickedNow) clickState = UNCLK;
  }
  updateClickTimer();
  if (last_clck_state == clickState) return NO_CHANGE;

  last_clck_state = clickState;
  return clickState;
}

bool clicked()
{
  return (getSetClickState()).equals(CLK);
}

bool unclicked()
{
  return (getSetClickState()).equals(UNCLK);
}

// Read from given pin for given device, and convert to MIDI.
byte getMidi(axis_t axis, device_t device)
{
  int data = getData(axis, device);
  int MIDI_LO = 0;
  int MIDI_HI = 127;

  // For joystick, no change needed for the following initialized values.
  int dataLo = 0;
  int dataHi = 1023;

  byte midi = 255;

  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X)
    {
      dataLo = 278;
      dataHi = 413;
    }
    else if (axis == AXIS_Y)
    {
      dataLo = 260;
      dataHi = 408;
    }
    else if (axis == AXIS_Z)
    {
      dataLo = 270;
      dataHi = 412;
    }
  }
  // If checking Joystick only change midi if not checking switch.
  if (axis != JOY_SW) midi = map(data, dataLo, dataHi, MIDI_LO, MIDI_HI);
  return midi;
}

// Print MIDI data formatted to be read in Max.
void sendMidi(axis_t axis, device_t device)
{
  String prefix = "";
  if (device.equals(DEV_ACCEL))
  {
    if (axis == AXIS_X) prefix = "X"; // Ascii 88
    else if (axis == AXIS_Y) prefix = "Y"; // Ascii 89
    else if (axis == AXIS_Z) prefix = "Z"; // Ascii 90
  }

  else if (device.equals(DEV_JOY))
  {
    if (axis == AXIS_X) prefix = "x"; // Ascii 120
    else if (axis == AXIS_Y) prefix = "y"; // Ascii 121
    else if (axis == JOY_SW)
    {
      if (clicked()) prefix = "+\n"; // Ascii 43
      else if (unclicked()) prefix = "-\n"; // ascii 45
    }
  }
  byte midi = getMidi(axis, device);
  Serial.print(prefix);
  // 255 reserved for click. Only print midi if not for click.
  if (midi < 255) Serial.println(midi);
}

// Run initilization for Accelerometer
void setupAccel()
{
  pinMode(getAxisPin(AXIS_X, DEV_ACCEL), INPUT);
  pinMode(getAxisPin(AXIS_Y, DEV_ACCEL), INPUT);
  pinMode(getAxisPin(AXIS_Z, DEV_ACCEL), INPUT);
}

// Run initilization for Joystick
void setupJoy()
{
  pinMode(getAxisPin(AXIS_X, DEV_JOY), INPUT);
  pinMode(getAxisPin(AXIS_Y, DEV_JOY), INPUT);
  pinMode(getAxisPin(JOY_SW, DEV_JOY), INPUT_PULLUP);
}

void setup()
{
  Serial.begin(9600);
  setupAccel();
  setupJoy();
}

void loop()
{
  sendMidi(AXIS_X, DEV_ACCEL);
  sendMidi(AXIS_Y, DEV_ACCEL);
  sendMidi(AXIS_Z, DEV_ACCEL);

  sendMidi(AXIS_X, DEV_JOY);
  sendMidi(AXIS_Y, DEV_JOY);
  sendMidi(JOY_SW, DEV_JOY);
  delay(10);
}

Code in the Max patch and subpatches

]]>
Ultradian Rhythm Visualizer https://courses.ideate.cmu.edu/60-223/s2021/work/ultradian-rhythm-visualizer/ Fri, 09 Apr 2021 20:53:01 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12892 Overview

This clock-adjacent object visualizes my current energy level estimated by the ultradian rhythm.

 

 

Process

Rotating Cam Visualization of Sine Wave

Linear Visualization of Sine Wave

 

There are a few main components to my assembly – the shaft with offset cams, the dowels that sit on top of the cams, the stepper motor mount, and the housing for the entire assembly. Below I will show my process for working on each one.

 

The Cam Shaft

I used a drill press to cut out 9 circles from a piece of plywood. I used a hand drill to drill a hole in each one so I could align them on the wooden dowel. Using glue, I arranged each circle to be offset from the one previous by about 1cm.

 

 

I tried making a smaller one, but found the distance between each cam was not enough to show the sine wave clearly.

The Rods and Rod Holders

Next, I had to figure out how to align the plastic rods above the circles. I rummaged around in the parts drawers at Products Studio and tried out many different arrangements of small metal pieces until I found something that I could space the dowels apart with. I considered using sewing bobbins (pictured left) but eventually settle on using a combination of square nuts and screw plates that I carefully arranged side by side to create the correct spacing for the plastic rods.

The Stepper Motor Mount and Gear Connection

Using Calipers and Bisecting Curves, I figured out the dimensions of the box and screw plate.

This part was very difficult, since if the gear is slightly off, the whole mechanism does not work. I tried many different to hold the stepper motor in place. First, I tried a simple angle bracket, but this was not secure enough. Next, I tried using the drill press to create a face plate but the measurements were just ever so slightly off. Finally, I created two laser-cut pieces of 1/8″ plywood stacked on top of eachother to allow for a counter-bore so the screw can sit flush. Instead of holes, I used ovals with a 1/4″ of wiggle room to allow for precision alignment and adjustment to ensure the gear sits perfectly in place.

The Housing

The housing was the least complicated and simply consisted of a 5 board box made of plywood. I used the tablesaw and a nail gun to assemble this.

Discussion

Response to In-Class Critique

Response to comments gathered during the in-class crit. Quote (verbatim) from at least two written critiques that you received (positive, negative, or otherwise) from the in-class crit, and respond to them. (You may agree or disagree—in either case, explain your position.)

 

“It’s soooo hard to build complex mechanical devices like this—congrats on even attempting it, but in a two-week project, I’m not surprised that you faced some real challenges completing this to your satisfaction.”

To this point, I would like to say that this was probably the biggest challenge I faced during this project. I think that this project taught me a lot about the role of mechanisms in ideation development. It is really difficult to bring a complex mechanical concept into reality since mechanisms require every aspect of an idea to be thought out, yet iteration is essential to the design process. It was really difficult for me to know what I should focus on next since everything seemed dependent on another part or piece of code. If I were to approach this project again, I would make sure that I had a functional mechanical prototype with all of the pieces that I wanted to have before moving forward. Since I continued to develop the mechanism while trying to tackle the code and the aesthetics, this project became very unwieldy. I am glad to have a better sense now of the significance of isolating mechanisms from the computation and design. 

 

“I really like the idea of functional poetry; to make this poetic and functional at the same time. It brings art into practicality, which as an artist myself, I really appreciate. Now that you just now mention it, the fiber optic lighting would have been dope. Also, this inspired me to write a program to trace my own energy level.”

This comment felt really great to hear since I was really trying to negotiate between poetry and function with my object and I am glad that someone else resonated with that. Additionally, I am so happy to think I inspired someone else! It is a great reminder to me that a project does not need to be perfect to communicate with or even inspire another person. This is hard to remember in the face of many mechanical failures, so I really appreciate this comment. 

 

“Maybe you could try out a simpler mechanical output that doesn’t require so many components. It will still be very beautiful just to simply have something moving linearly or something”

I think that this person definitely has a point, if I were to go back I think I would try to omit the pegs. That being said, my main mechanical output is really just the stepper motor. I think it was important for me that my visualization of this concept had some volume to it and I was not satisfied with simply linear depictions of these values. I would certainly revisit this idea and work to consider alternate representations of energy levels. 

 

Self-Critique

 

 Are you happy with how the project came out? Did it satisfy your own goals? This should not simply be a recital of your process, but rather a meaningful reflection.**

While I am happy with my explorations during the process of this project, I am not satisfied with where the final project stands. Despite warnings about pursuing physical mechanisms, I had no idea how ambitious my undertaking was actually going to be. I spent so much of the project time trying to simply give my idea a physical form, let alone develop the technology to where it needed to be. A huge hurdle was simply getting the components I needed in a timely manner since I didn’t even know what parts I needed until I played around with the mechanisms for a few hours, googled issues I came into, and learned about new parts. I learned so much from this tinkering though – for example, I now know what a coupler does, the affordances of a D-shaft, and that there are different standards of screw sizes! 

I plan to continue developing this project further since I have learned so much and feel that with more time, I will be able to create something I feel more satisfied with. 

 

What you learned about your own abilities and/or limitations through the process of working on this project.

I confirmed some more things I already knew about my process – I tend to embrace a non-linear process, which is very difficult to make significant progress forward with. As I was warned about, I struggled with the mechanical aspect of this project. I have put significant time towards this project, both independently and in working one-on-one with not just Zach, but many hours with my studio shop advisor as well. Despite this, my project remains incomplete. I cannot help but feel a little disappointed that I did not get further with this project, but there were simply so many unfamiliar variables present. 

In the last project, I took time to intentionally segment off short lo-fi prototyped versions of my idea (i.e. I made a simple version of my graphite resistor before trying to make it more complex). This helped significantly in reducing the number of variables I was working with. I think with this project, I didn’t quite know how to do a similar segmenting of the work which had a significant impact on my ability to complete the project. 

Moving forward, I will make an even greater effort to segment the parts of my project and consult with knowledgeable advisors early on in the process, especially when involving mechanisms. After trying to jimmy-rig so many aspects of the project and then finally finding the right parts, I feel I have a better appreciation of precision tools. I will make greater efforts to attain these tools early on too. 

 

Next-Steps

Next steps. Do you expect to build another iteration of this project?

I am currently working on another iteration of this project. I have already made a lot of progress with refining the mechanism by taking the time to carefully measure all of the interlocking parts. This is in an attempt to get some closure on this rendition of my idea. I would certainly consider other visualizations of energy tracking and time. I also learned that I am fascinated by cam mechanisms and I would love to explore those further. 

Technical Information

 

 

]]>
Automated Medicine Dispenser https://courses.ideate.cmu.edu/60-223/s2021/work/automated-medicine-dispenser/ Fri, 09 Apr 2021 19:40:59 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12875

Overall image of the Automated Medicine Dispenser on my nightstand

The Automated Medicine Dispenser incorporates a wireless charger and phone stand into a single device that allows the user to dispense their medicine bottle upon stopping an alarm.

Overview

Opening Sequence

 

Closing Sequence

Overall Photo

Overall photo showing the scale of the device relative to an iPhone.

 

Detail Photos

Image of the internal wiring of the Automated Medicine Dispenser.

 

Depiction of the inside of the medicine holder. The cutouts help position the medicine bottle in the center of the holder in order to improve consistency in the optical proximity sensor readings.

 

Mounting position of the optical proximity sensor in the side wall of the medicine holder box. Electrical tape was used to protect the sensor housing and prevent unwanted wire crossings.

Use of the Device

Shown above is the photoresistor actuated by the phone flashlight. The image above was taken in the phone’s resting position on the stand.

 

Depiction of the rainbow lights and servo actuation during the dispensing sequence.

Process Images and Review

Tilt Mechanism Troubles

The first major change from my original plan involved the tilting mechanism for the medicine bottle holder. In my original design, the medicine bottle holder incorporated a servo at the axis of rotation in order to complete the tilting motion (Note: original design shown below). This mechanism, however, proved to be infeasible because of the design requirements  involving form factor. Since I wanted to have a flush front surface of the outer housing, the servo needed to be positioned further back requiring a different type of actuation mechanism. In addition to form factor, this original design also created the added challenge of aligning an axle on the other side of the holder with the center of rotation of the servo.

The original tilt mechanism actuated at the axis of rotation of the medicine bottle holder.

Upon reaching these previous conclusions about my original design, I switched to a linkage mechanism for the actuation of the tilt motion. This new design also came with its own challenges, mainly changing the original outer housing design to incorporate enough room for the servo in back  and figuring out a reliable way to connect the linkage to the bottle holder. As shown below, the final mechanism incorporated popsicle sticks as the links and a needle for the pin joint with electrical tape forming the connections to the servo and bottle holder.

Linkage mechanism for the updated tilting mechanism.

Wireless Charger Surface Exposure

Moving on to the surface of the wireless charger, the original design intended for this part to be hidden by a flat top piece that would allow the charging signal to penetrate through and reach the phone. In addition, this cover would also allow the light from the phone flashlight to penetrate and reach the photoresistor. A version of this design is pictured below using a relatively thicker paper that still allowed light to pass through.

Image of the original charger covering idea that was later removed.

While this design was more aesthetically pleasing, the final version did not include this covering and instead left the wireless charger exposed. The first reason contributing to this decision was the uneven bump that resulted from too small of a cutout for the charger (Note: bump pictured below). As a result of this bump, the covering was not able to be completely flat. In addition to this unevenness, the paper also reduced the ability to see the inner workings of the device which I felt was important to this prototype. Seeing the inner workings, as was confirmed by some in the critique, allowed for a better understanding of the complexity and resulted in a more robust looking device.

Side view of the surface bump on top of the phone stand.

Discussion

During the critique of the project, there were many amazing points brought up about the overall design and aesthetic of my prototype. One critique about the placement of the proximity sensor stood out to me as it was something that I spent a lot of time thinking about. This person critiquing wrote that I should “Put the prox[imity] sensor under the pill bottle to sense when pill bottle has been removed/replaced.” This is something that I briefly considered while designing this mechanism but never really gave much thought to because it would interfere with the tilting mechanism and how far it could retract. Looking back on this decision, however, this would’ve been a much more accurate way of detecting whether the bottle had been taken because there is more variance in the sensor reading. When initially testing the final sensing mechanism, I had trouble getting the sensor to read a consistent change in the distance when the medicine bottle was taken which could have easily been solved by this new mounting point. In addition to this critique, another person also questioned “from a form factor perspective … [how] the two separate housings could be integrated into a single form.” Again, the housing form was something that I gave a lot of thought to during the ideation phase of this project and is something that I am very satisfied with about the final result. While it would look nice to have everything in a single form factor, I like the placement of the phone slightly below the top of the medicine dispenser section because it provides for a more natural feeling phone stand aesthetic. I felt that having the phone placed too high would result in an awkward looking final product.

Looking back on the process of this project, while the end result did not work out in exactly the way I had hoped in terms of reliability and overall aesthetic appeal, I was very satisfied with the functionality and proof of concept. From a reliability standpoint, the tilting mechanism did not meet the standards I was hoping to achieve due to the last minute changes to the entire design. In addition, I encountered a lot of trouble trying to time the retraction of the bottle holder in such a manner that didn’t break the flimsy pin joint constructed from a sewing needle.

Putting this project in perspective with my technical abilities, the biggest thing I learned is that mechanical aspects of a device are much more deceiving than they might seem. In beginning this project, I had a very clear image of the final product in my mind which didn’t change much throughout the process except in regards to the mechanical components. Upon getting further into the actual assembly of the final prototype I encountered many issues with the tilting mechanism that could have been solved much earlier on with a bit more thought on their design. Paying close attention to the mechanical aspects of the project is something that I would definitely change if I were to redesign this device in a future version.

While I do not plan on building another version of this project in the near future, the first thing I would do differently if I did build this project again would be to figure out a better system for dispensing the medicine. While my tilting idea is nifty, the physical constraints of the tilting action resulted in the final product falling out of line with my original idea.

Technical Information

Block Diagram

Functional block diagram of the Automated Medicine Dispenser

Schematic

Full electrical schematic of the Automated Medicine Dispenser

Code

/*
   Medicine Dispenser
   Judson Kyle (judsonk)

   Collaboration and sources:
   1) https://forum.arduino.cc/index.php?topic=8498.0 for rainbow blinking

   2) https://courses.ideate.cmu.edu/16-223/f2020/text/exercises/electronics/photointerruptor/photointerruptor.html
      was consulted for the wiring of the proximity sensor

   Description: This device allows the user to dispense their medicine by utilizing the shortcuts on the iPhone
                to flash the flashlight for 1 second upon stopping their alarm. When the photoresistor detects
                this action, the servo pushes out the medicine holder while simultaneously flashing rainbow lights.
                The proximity snesor inside the medicine holder detects when the medicine bottle has been taken out
                and then placed back. Upon placing the medicine bottle back, the servo retracts the holder while
                simultaneously turning off the LED's. After all of this happens, the cycle is reset.

   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   3             output    Red LED
   5             output    Green LED
   6             output    Blue LED
   11            output    Servo
   A0            input     Photoresistor
   A1            input     Optical Proximity Sensor

*/
#include <Servo.h>

const int OPTPIN = A1;
const int RED = 3, GREEN = 5, BLUE = 6;
const int PHOTOPIN = A0;
const int SERVOPIN = 11;

//Thresholds
int distThresh = 800, lightThresh = 600;

int optVal = 0, photoVal = 0;
int counter = 0;
bool medicineTaken = false, bottleTaken = false;
bool alarmSnoozed = false, dispenseMedicine = false, prev_bottleTakenState = false;

//warningLights variables
int timerVal = 3000;
unsigned long waitingVal = 0;

//Servo Variables
Servo medicineTilter;
bool tiltServo = false;
int tiltAngle = 180;


// Number of colors used for animating, higher = smoother and slower animation)
int numColors = 255;

// The combination of numColors and animationDelay determines the
// animation speed, I recommend a higher number of colors if you want
// to slow down the animation. Higher number of colors = smoother color changing.
int animationDelay = 5; // number milliseconds before RGB LED changes to next color

void setup() {

  //Output pins
  pinMode(RED, OUTPUT);
  pinMode(GREEN, OUTPUT);
  pinMode(BLUE, OUTPUT);

  //Input pins
  pinMode(OPTPIN, INPUT);
  pinMode(PHOTOPIN, INPUT);

  //Servo Intialization
  medicineTilter.attach(SERVOPIN);
  medicineTilter.write(0);

  Serial.begin(9600);
}

//Code to loop through
void loop() {
  //Read sensor data
  optVal = analogRead(OPTPIN);
  photoVal = analogRead(PHOTOPIN);

  //Determine whether bottle has been taken or not
  if (optVal > distThresh) {
    bottleTaken = true;   //If taken --> bottleTaken = true
  } else if (optVal <= distThresh) {
    bottleTaken = false;  //If sensed in the holder --> bottleTaken = false
  }

  //Check for alarm snoozing action
  if (photoVal > lightThresh && alarmSnoozed == false) {

    alarmSnoozed = true;

    //Dispense medicine upon alarm snooze
    dispenseMedicine = true;//Dispense medicine upon alarm snooze
    medicineTilter.write(tiltAngle);
  }

  //Actions that follow detection of an alarm snoozed event
  if (dispenseMedicine == true) {

    // This part takes care of displaying the
    // color changing in reverse by counting backwards if counter
    // is above the number of available colors
    float colorNumber = counter > numColors ? counter - numColors : counter;

    // Play with the saturation and brightness values
    // to see what they do
    float saturation = 1; // Between 0 and 1 (0 = gray, 1 = full color)
    float brightness = 0.8; // Between 0 and 1 (0 = dark, 1 is full brightness)
    float hue = (colorNumber / float(numColors)) * 360; // Number between 0 and 360
    long color = HSBtoRGB(hue, saturation, brightness);

    // Get the red, blue and green parts from generated color
    int red = color >> 16 & 255;
    int green = color >> 8 & 255;
    int blue = color & 255;

    setColor(red, green, blue);

    // Counter can never be greater then 2 times the number of available colors
    // the colorNumber = line above takes care of counting backwards (nicely looping animation)
    // when counter is larger then the number of available colors
    counter = (counter + 1) % (numColors * 2);

    // If you uncomment this line the color changing starts from the
    // beginning when it reaches the end (animation only plays forward)
    // counter = (counter + 1) % (numColors);

    delay(animationDelay);

    //Track when the bottle has been put back after taking the medicine
    if (prev_bottleTakenState == true && bottleTaken == false) {
      medicineTaken = true;
      waitingVal = millis();
    }

    if (medicineTaken == true) {
      
      //Delay the reset to allow for safe return of medicine bottle without breaking linkage
      if (millis() - waitingVal > timerVal) {
        resetSystem(); //reset for next cycle
      }
    }
  }

  prev_bottleTakenState = bottleTaken; //Update previous bottleTaken state boolean

}

//---------Helper Functions-----------------------

//Turn all LED's off
void clearLEDs() {
  //Turn all LED's off
  digitalWrite(RED, LOW);
  digitalWrite(GREEN, LOW);
  digitalWrite(BLUE, LOW);

}

//Reset the system
void resetSystem() {
  
  medicineTilter.write(0);  //Return bottle holder to rest position
  clearLEDs();              //Turn LED's off

  //Reset state variables
  alarmSnoozed = false;
  dispenseMedicine = false;
  medicineTaken = false;

}

//Rainbow color changing helper functions copied from source 1
void setColor (unsigned char red, unsigned char green, unsigned char blue)
{
  analogWrite(RED, red);
  analogWrite(GREEN, green);
  analogWrite(BLUE, blue);
}

long HSBtoRGB(float _hue, float _sat, float _brightness) {
  float red = 0.0;
  float green = 0.0;
  float blue = 0.0;

  if (_sat == 0.0) {
    red = _brightness;
    green = _brightness;
    blue = _brightness;
  } else {
    if (_hue == 360.0) {
      _hue = 0;
    }

    int slice = _hue / 60.0;
    float hue_frac = (_hue / 60.0) - slice;

    float aa = _brightness * (1.0 - _sat);
    float bb = _brightness * (1.0 - _sat * hue_frac);
    float cc = _brightness * (1.0 - _sat * (1.0 - hue_frac));

    switch (slice) {
      case 0:
        red = _brightness;
        green = cc;
        blue = aa;
        break;
      case 1:
        red = bb;
        green = _brightness;
        blue = aa;
        break;
      case 2:
        red = aa;
        green = _brightness;
        blue = cc;
        break;
      case 3:
        red = aa;
        green = bb;
        blue = _brightness;
        break;
      case 4:
        red = cc;
        green = aa;
        blue = _brightness;
        break;
      case 5:
        red = _brightness;
        green = aa;
        blue = bb;
        break;
      default:
        red = 0.0;
        green = 0.0;
        blue = 0.0;
        break;
    }
  }

  long ired = red * 255.0;
  long igreen = green * 255.0;
  long iblue = blue * 255.0;

  return long((ired << 16) | (igreen << 8) | (iblue));
}

 

]]>
Double Transducer: The Convoluted Potentiometer (Orientation –> Light) https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-the-convoluted-potentiometer-orientation-light/ Wed, 10 Mar 2021 14:07:34 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12644

The most successful Tinkercad circuit we built, for testing and learning the LCD screen and the LiquidCrystal library. See below for our full Tinkercad circuit and why it didn’t work.

To begin this assignment,  we discussed various ideas of how we could transduce orientation to light.  After a couple hours of excited general brainstorming, we found it very helpful to use then maker cards to narrow down our conversation in terms of input and output.  This focus allowed us to see what was necessary in the middle steps of the operation , and what parts may lend themselves well to working together.

An overview of our 3 more refined ideas

Our favorite of the 0ur 3 more refined ideas  was the following:

 

A potentiometer sets the angle for a servo for a stepper motor. A cable sticking out from the motor turns with the motor and glides on a layer of graphite drawn around the motor. A current is always flowing through the graphite, and depending on the position of the cable along the graphite trail, it’ll measure more or less current. Essentially like a homemade potentiometer whose position is determined by a stepper motor. Depending on the current read by the cable, an LED lights up more or less.

 

Jubbies’ concept sketch for our idea

We had gotten some good feedback from  our professor as well, since this idea seemed to be a good balance between exciting and feasible.  To proceed forward,  we broke down our problem into several steps so we could focus on individual components before be assembled them together .  The first step we needed to confirm was working  independently was the one that was most unfamiliar – using a graphite resistor.  To learn how to do this,  Jubbies used YouTube  to find a concise demonstration of this idea.

The following video was very helpful  as it demonstrated  some of the affordances of using graphite circuit .

Using this video as guidance,  Jubbies recreated this graphite circuit with alligator clips in a 9-volt battery.  This demonstration proved successful, although there was not as much variance in the light as was desired. We found that this issue was resolved as we eventually used a longer graphite resistor.

 

Demonstration of the graphite circuit

After proving that the graphite circuit could work,  the next issue to tackle was  controlling the stepper motor accurately with a potentiometer. This pursuit proved to be far more difficult than we first predicted. A huge barrier that we had to figure out how to overcome  Rose  making the  stepper motor turn the correct direction. For some reason the stepper motor seems to only cumulatively turn to the right no matter the direction that the potentiometer was turned.   it was as if the stepper motor turn only two  the amount  that was equivalent to the total value that the potentiometer was turned , regardless of whether that value was left or right.  We tried editing the code and  checking our wiring for hours,  but none of this seemed to help.

 

here’s an example of the potentiometer moving to stepper motor only to the right depsite the direction that the potentiometer turned.

 

It wasn’t until receiving help directly from our professor that we were able to proceed forward.  The thing that fixed this issue  was in the end, simply replacing both the stepper motor and a stepper motor driver.  We have not yet identified what the issue was particularly, but using  the new parts with the same code achieve the results that we had wanted.

finally our stepper motor turned right AND left!!

While this issue was frustrating and strange,  it did allow us to use a stepper motor that was far more robust than the one we were using before.  This helped  with the construction  of our circuit  since we did not have to worry that the arm would not move quick enough.  however  oh, I believe the use of outside power source led to  the following image – Jubbies accidentally blew up an LED while accidentally connecting the power and ground of the LED without the graphite circuit in-between. This was a good lesson, as it reminded her to be very conscientous of these wires not connecting again.

Another strange issue that was not ideal but did not hinder the intended mechanism was an ever present jitter in the stepper motor arm. This jitter was likely due to analog interference and could be resolved in the future with a threshold or other tool to smooth the data recieved by the potentiomenter. I had considered using a rotary encoder mid-project over the potentiometer as I heard that it was less susceptible to analog interference, but I was unable to quickly implement this and ended up just using the potentiometer.

Bonus: I strapped a pen onto the stepper motor arm and found this jitter made for an interesting drawing tool to be explored further in the future – Jubbies

 

Carlos’s progress

My (Carlos’s) Tinkercad code somehow became ridden with invisible special characters \302 and \240, maybe after copying and pasting the code from iMessage. They were nearly impossible to remove without retyping those lines word for word all over again. Because of this, the code wouldn’t compile, and I couldn’t check if the rest of the code was correct.

Tinkercad does not have a stepper motor, so I used the larger, grey DC Motor with Encoder as a mere placeholder, not even connected to anything.

Block Diagram & Schematic:

 

/*
  60-223, Double Transducer: The Convoluted Potentiometer
  Jubbies Steinweh-Adler
  Carlos Ortega

  Collaboration and sources:
  1) I collaborated with Carlos to figure out the order of the code
  2) Referenced heavily Circuit Digest stepper motor with Potentiometer
  https://circuitdigest.com/microcontroller-projects/stepper-motor-control-with-potentiometer-arduino
  3) The maker cards really helped me understand the parts
  https://nsfsmartmakerspaces.github.io/physcomp/parts/4005/#starter-code--connection
  4) I referenced Household Hacker's youtube video about paper and graphite
  circuits to get started with this idea.
  
  5) Tate gave me some advice on how to use the LCD display since I could 
  not figure it out.

  Challenge(s): Remote collaboration was difficult, as was
  working through unknown bugs with the Stepper Motor. The
  stepper motor and driver did not work and simply had to be
  replaced. Additionally, I could not get the LCD working in
  time. 

  Next time: It was extremely helpful to segment the process
  of solving this code, proving that each mechanism works
  independently of the whole rig. I will certainly do this again
  as it really sped things up and made them less stressful.
  In terms of issues, I think I should have given more time
  to the physical assembly of all the parts, since this took
  way longer than I thought. I spent a lot of time trying to
  fashion non-destructive mounts. It was hard to physically arrange
  the parts together in a semi-elegant way. I also want to give
  more time to the small final details, like resolving the
  stepper motor jitter.

  Another thing I want to take forward from this project was using
  a clearly understood visual indicator of the process like the
  graphite semicircle, since I found this helped people make sense
  of this project quickly.

  Description:

  Pin mapping:

  Arduino pin | type       | description
  ------------|------------|-------------
  A0            Input       Potentiometer input
  12            LCD Pin     Used for the LiquidCrystal Library
  11            LCD Pin     Used for the LiquidCrystal Library

  2             Input       Stepper Motor driver
  3             Input       Stepper motor driver, direction

   7            LCD Pin     used for the LCD
   6            LCD Pin     used for the LCD
   5            LCD Pin     used for the LCD
   4            LCD Pin     used for the LCD


*/
//Initialize the LCD
#include <LiquidCrystal.h> //include the LCD library code


// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 12, en = 11, d4 = 7, d5 = 6, d6 = 5, d7 = 4;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);


//Initialize the Stepper

#include <AccelStepper.h> // including the accelstepper library for more control of motor


const int POTPIN = A0; //potentiometer input pin

const int STEP_PIN = 2; // A4988 "STEP" pin wired to Arduino pin 2 (you can change this)
const int DIR_PIN = 3; // A4988 "DIRECTION" pin wired to Arduino pin 3 (you can change this)

int pos = 100; // variable to store motor position instruction, 100 is half rotation

// Modified from:
//https://courses.ideate.cmu.edu/60-223/s2021/tutorials/stepper

AccelStepper stepper(1, STEP_PIN, DIR_PIN);

// Will compare this to currStepMotPos later, inside loop.
int prevStepMotPos = 0;

unsigned long timerVar = 0;
const int WAIT = 200; //does not change

int LCDupdate = 0;

void setup() {
  int BAUD = 9600; //serial comm value
  int maxSpeedVar = 100; //measured in steps per second
  int accel = 500; //measured in steps per second
  Serial.begin(BAUD); //begin serial communication

  //---LCD Setup---
  lcd.begin(16, 2);

  // Modified from:
  // https://nsfsmartmakerspaces.github.io/physcomp/parts/4005/#starter-code--connection

  //---Stepper Motor setup---

  stepper.setMaxSpeed(maxSpeedVar);    // measured in steps per second
  stepper.setAcceleration(accel); // measured in steps per second squared

  // while there is still a distance to go,
  stepper.run(); // make the motor run
  

}


void loop() {
  unsigned long currentTime = millis();
  unsigned long previousTime = 0;

  
  }

  int inLo = 0; //lowest value of potentiometer range
  int inHi = 1023; //max value of potentiometer range
  int outLo = 0; //lowest value of stepper motor range
  int outHi = 100; //200 per rev, so half revolution



  int potPos = analogRead(POTPIN); //potPos assigned position of potentiometer

  //map pot pos range to stepper motor range
  int long currStepMotPos = map(potPos, inHi, inLo, outLo, outHi);


  //Change destination of stepper to potentiometer input
  stepper.moveTo(currStepMotPos); //tell motor to go to new position

  prevStepMotPos = currStepMotPos; //save current value into previous value
  stepper.run();

  //Serial.println(prevStepMotPos); //for debugging

  LCDPotVal = 
  LCDStepperVal = 

//LCD Update 
  /*if (currentTime - timerVar >= WAIT) {
    lcd.clear();
    lcd.home();
    lcd.print("i:");
    lcd.print(LCDPotVal0;
    lcd.setCursor(6, 0);
    lcd.print("m:");
   */
    previousTime = currentTime;
  


}

 

Discussion:

This project was an exciting introduction to many new concepts  such as assembling separate components into one  operation, using  graphite as a resistor,   learning how to debug in context,  soldering,  and collaborating remotely.  Since we were both excited about this idea, it was easier to push through these bugs.   Learning hands-on was a great experience , since somebody can tell you what it’s like to explode an LED, but before you actually do it,  I would argue that it is far less likely to sticks with you.

The biggest barriers we faced had to do with  significant bugs and remote collaboration.  The stepper motor/ stepper motor driver bug , although  circumnavigated, was never resolved. Only with the help of our professors are we able to  move on from that point through replacing our parts.

Additionally, since Carlos is studying remotely and never received his Arduino kit  from customs,  there was simply not an option to collaborate on the hardware issues.  Since the software and hardware are delicately intertwined, this also made it extremely difficult to collaboratively resolve software issues as well.  While on paper, tinkercad seems to be a good option  to ease this situation,  the lack of a stepper motor, stepper motor driver, and  graphite resistor on the platform, as well as the inability to import libraries, made this tool unhelpful.

That being said, we were able to have rewarding discussions about  conceptual development and enjoyed the process of translating our idea to a real tangible thing.

]]>
Double Transducer | Distance -> Pressure https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-distance-pressure/ Wed, 10 Mar 2021 09:02:08 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12315 Feature Image

Distance to pressure double transducer.

 

Double Transducer IRL:

Daniel Zhu:

Sunjana:

 

TinkerCAD:

Final Project Images:

Daniel Zhu:

Featured Image

Distance to Pressure Double Transducer – Daniel Zhu

Sunjana:

Close Up Images

Close up of the method servo used to apply pressure to the paper

Close up of servo in position to press the lever switch intermittently when its shaft is turned programmatically


Simple Narrative Description:

As the distance between the Ultrasonic Distance Sensor and an object decreases, the rate at which a servo motor presses a lever switch increases. As the lever switch registers a faster and faster rate of being triggered, a second servo motor presses a stack of cardboard more closely to the table, applying more pressure. Conversely, as the distance between the Ultrasonic Distance Sensor and an object increases, the rate at which a servo motor presses a lever switch decreases. As the lever switch registers slower rate of being triggered, a second servo motor presses a stack of cardboard less closely to the table, relieving pressure. 

Progress Images:

Daniel Zhu:

Noise in Ultrasonic Distance sensor data.

Sunjana:

Converting rotational motion into pressure

Unsoldered prototype

Discussion:

This project introduced numerous physical, coding, and conceptual difficulties. Conceptually, it was difficult for us to come up with an idea to convert distance into pressure: while we had spent a lot of time working with light as a medium (LEDs) and movement, we hadn’t ever worked with any electrical components that had a specific function of exerting pressure. After speaking with the professor, we learned that in order to exert pressure, we could take inspiration from a crank that used a circular turning motion to push and pull an object. We then decided upon the idea of our second transducer outputting an angle change for a motor so it could turn like a crank and push and pull an object we created. The object in turn would apply pressure to a piece of paper as it was being pushed. 

Physically, our challenge lay in orienting the different components of the machine (i.e. the servos and the button) so that they would form a chain reaction (i.e. a servo pressing a button intermittently, causing the other servo to intermittently apply pressure to a piece of paper). It took some trial and error to figure out which button was most responsive to the servo’s touch, as well as whether a servo or stepper motor was better suited to our task. It became too technically difficult for us to implement the crank with the stepper motor providing the circular turning motion, like we had originally intended, so we ended up going with the servo. In the future, we would want to be able to utilize the stepper motor as it would allow for more creativity in our output, since it turns 360 degrees. 

Coding-wise, our challenge lay in figuring out the relationship between the first servo, the button, and the second servo, and how to pass information through each of these components. Specifically, we had to figure out how to convert the digital intermittent pressing of the button into an analog angle for the second servo. This also took a lot of debugging and trial and error, as we didn’t immediately know which angles of the servo were most optimal for pressing on the paper, and we didn’t know how we could change the angles such that the servo would be intermittently pressing down and intermittently going back up based on the button-pressing speed of the first servo. 

Even though this project was extremely difficult, since we were relative Arduino beginners, we were able to go far out of our comfort zone and learn to put together various moving parts, as well as how to convert an analog signal to a digital signal and back to an analog signal. 

Diagrams:

Block Diagram:

Block Diagram

Block Diagram

Schematic Diagram:

Schematic Diagram

Schematic Diagram

Code:

/*
   60-223, Project 1: Double Transducer
   Daniel Zhu (dszhu)
   time spent: 6+ hrs

   Collaboration and sources:
   1) Code for LCD taken from the course website.
   2) Code for Servo Motor take from course website.

   Challenge(s): A faulty barrel jack charger as well as
   noise in the LCD Display due to it being connected to
   a power source shared by servo motors caused it to display
   egyption hieroglyphics for several hours.

   Description: As the distance between the Ultrasonic Distance Sensor
   and an object decreases, the rate at which a servo motor presses a
   lever switch increases. As the lever switch registers a faster and
   faster rate of being triggered, a second servo motor presses a stack
   of cardboard more closely to the table, applying more pressure.

   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   2             output    LCD Display Coding Pin
   3             output    LCD Display Coding Pin
   4             output    LCD Display Coding Pin
   5             output    LCD Display Coding Pin
   6             output    LCD Display E
   7             input     LCD Display RS
   8             output    Output Servo Motor (Pressure)
   9             output    Middle Servo Motor (Morse)
   10            input     Lever Switch Input
   11            output    TRIGGER_PIN - Ultrasonic Distance Sensor
*/

#include <Servo.h> //Servo Library
#include <NewPing.h> //Ultrasonic Distance Finder Library
#include <LiquidCrystal.h> //LCD Library
#include <Wire.h> //LCD Library

//Ultrasonic Distance Sensor Pins
const int TRIGGER_PIN = 12;  // Arduino pin tied to trigger pin on the ultrasonic sensor.
const int ECHO_PIN = 11;  // Arduino pin tied to echo pin on the ultrasonic sensor.
const int MAX_DISTANCE = 200; // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); //Createing a new Sonar object for use.

const int SDELAY = 50; // Minimum amount of delay between sonar pings
long sTimeSince = 0; // Time since last sonar ping
int dist = sonar.ping_cm(); // Keeps track of object distance from sensor

//Servo Motor Pins
const int BTN = 10; // Lever Switch
const int SERVO_IN = 9; // Middle Servo
const int SERVO_OUT = 8; // Output Servo
Servo Morse;
Servo Pressure;

long mTimeSince = 0; // Time since Middle Servo Triggered
bool mSwitch = false; // Keeps track of whether the servo is in the motion of pressing or returning

long pTimeSince = 0; // Time since Output Servo Triggered
int prsRate = 0; // Lever Switch input press rate

//LCD Display
const int rs = 7, en = 6, d4 = 2, d5 = 3, d6 = 4, d7 = 5;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

long lTimeSince = 0; //Time Since LCD Display was last updated
const int lcdDelay = 250; // Minimum time between LCD updates

void setup() {
  pinMode(BTN, INPUT);
  Morse.attach(SERVO_IN);
  Pressure.attach(SERVO_OUT);
  Serial.begin(115200);
  lcd.begin(16, 2);
}

void loop() {

  if (millis() - sTimeSince > SDELAY) { // Triggering the Ultrasonic Sensor + Finding the Distance
    dist = sonar.ping_cm();
    sTimeSince = millis();
  }

  int pause = map(dist, 0, 50, 500, 1000); // Converts distance into how long the middle servo pauses between presses

  if (int(millis() - mTimeSince) > pause) { //pressing the middle servo motor
    if (mSwitch == false) { // Pressing the Lever Switch
      Morse.write(40);
      mSwitch = true;
    }
    else { // Unpressing the Lever Switch
      Morse.write(45);
      mSwitch = false;
    }

    prsRate -= 10; // Automatically Subtracting from the Pressrate of the Lever Switch
    Serial.print("Delay: ");
    Serial.println(pause);
    mTimeSince = millis();
  }

  if (digitalRead(BTN) == 1) { // Detecting LEvel Switch Input
    prsRate += 20;
  }

  if (prsRate > 100) { // Capping the pressrate before its conversion to angle to prevent servo failure
    prsRate = 100;
  }
  if (prsRate < 0) {
    prsRate = 0;
  }

  int angle = map(prsRate, 0, 100, 30, 20); // Converting the Pressrate of the Lever Switch to an Angle
  if (millis() - pTimeSince > 500) {
    Pressure.write(angle); // Moving the output motor to that angle
  }

  if (int(millis() - lTimeSince) > lcdDelay) { // LCD Display delay

    // Converting Middle values into 0-99 range for LCD
    int input = map(dist, 0, 50, 0, 99);
    int middleA = map(pause, 500, 1000, 0, 99);
    int middleS = map(prsRate, 0, 100, 0, 99);
    int output = map(angle, 20, 30, 0, 99);

    lcd.setCursor(0, 0);
    lcd.print((String)"i:" + input + " m:" + middleA);
    lcd.setCursor(8, 2);
    lcd.print((String)middleS + " o:" + output);

    lTimeSince = millis();
  }
}

 

 

]]>
Double Transducer: Pressure –> Light –> Orientation https://courses.ideate.cmu.edu/60-223/s2021/work/frogs-double-transducer/ Wed, 10 Mar 2021 02:03:40 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12322

Double Transducer

Images

Overall Photos

(Jud)

(Jun)

Detail Photos

                 

Transducers in Action

TinkerCAD Simulation

Narrative Description

The cardboard stand on the left of the transducer has a pressure sensor attached to it which senses how hard it is pressed. Based off of this pressure, a light inside of the cardboard box turns on to a specific brightness. If the pressure sensor is pushed hard, then the light turns on very bright, and if it is pressed lightly, then the light is very dim. Inside of this box is also a light sensor that senses this change in the clear light’s brightness. According to the amount of change that occurs, a servo on the left side of the mechanism turns around. If the amount of light in the box increases, then the servo rotates counter-clockwise to match this amount of change. As all of this is happening, a display at the bottom of the machine shows the numeric values of all of these actions starting with the pressure sensor in the top left and ending with the servo in the bottom right of the screen.

Process

This image shows the soldering of the color sensor that we were originally going to use. The soldering was successfully done, and the device was working, but we decided not to use this sensor.

This image depicts the testing of the color output using three different color LED’s to see what was causing our multi-colored LED issue discussed later on.

This image shows the final step of the soldering process where our switch from color sensing to brightness became permanent.

This image shows the process of adding the potentiometer to the LCD in order to adjust its brightness. Initially, the v0 was connected to the ground instead of the potentiometer, and we were not able to adjust its brightness.

 

 

Discussion

The hardest part about this project was understanding how to use each of the components and figure out accurate mapping functions to make sure each component was being used to its full potential. The hardest component accomplish this with was the color sensor because of its 3 inputs. Since the color sensor has red, green, and blue inputs, the Force Sensitive Resistor’s (FSR) single output made connecting these two elements very challenging. In the end, after relentlessly searching for algorithms that would accomplish this goal for us, we decided to pursue an alternative method utilizing brightness instead. Reflecting back on this decision, however, it would’ve been a better idea to start out with trying to understand this conversion process and write our own algorithm as opposed to searching the internet for one we could implement. This could have possibly improved our ability to understand these converting algorithms later on if we needed to use them which may have resulted in the final product including this middle sensor. 

Apart from this color sensing dilemma, we also ran into issues while trying to use the servo library and analogWrite functionality together. During our first testing stages of the different components, we had the multi-colored LED wired in such a way that it would receive PWM signals from pins 6, 9, and 10. Upon plugging everything in and trying to change the color of the LED, only the LED plugged into pin 6 would produce the desired effect. After lots of time spent trying to debug the circuit, we finally figured out that the issue existed with the way that the servo library interacts with the Arduino. In order for the servo library to function, part of the code disables the analogWrite function for pins 9 and 10 making our original circuit diagram invalid. Just switching the input pin placement for these LED’s fixed our problem entirely.

Reflecting back on the creativity of the project, it would’ve been both easier and more exciting/interesting to only use the red and blue LED’s for the middle step of the transducer. This would not only make the code simpler by removing the need to map one input to three values and back, but it would also have a more physical meaning aligning closer to traditional ways of depicting pressure. Adding this element could have made the transducer a little bit more interactive helping to produce a more meaningful interaction than what this final version creates. 

Functional Block Diagram

Electrical Schematic

Code

/*
   60-223, Double Transducer
   Judson Kyle  (judsonk)
   Hyojun Jeong (hyojunj)

   Collaboration and sources:
   1) Used sample from Code Bites page on the 60-223 Intro to Physical 
      Computing website for serial communication to the MQTT bridge application

   Description: This double transducer will convert pressure to light
   to orientation through the use of a Force Sensitive Resistor (FSR),
   a photoresistor, and a servo. The input of the FSR will drive the
   brightness of an LED which is in an enclosed box with the photoresistor.
   The photoresistor will read the LED brghtness and map it to an angle
   which the servo can travel to. This will continuously happen until
   the system is turned off. In addition, the input and output values for
   each sensor and output will be mapped to a value from 0-99 and then
   displayed in an LCD screen with the FSR reading on the top left, the 
   LED birghtness in the middle top, the photoresistor reading in the bottom
   middle, and the servo output in the bottom right.
   
   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   A0            input     Force Sensitive Resistor for sensing pressure
   A1            input     Photoresistor for sensing birhgtness ofLED
   3             output    LED pin for controlling brightness
   4             output    LCD enable pin
   7             output    LCD register select pin
   8             output    LCD pin D4
   9             output    LCD pin D3
   10            output    LCD pin D6
   11            output    Servo pin for control of servo's angle
   12            output    LCD pin D7
*/

//Include Libraries for LCD and Servo Motor
#include <LiquidCrystal.h>
#include <Servo.h>

//FSR pins
const int FSRPIN = A0;

//Photoresistor and LED pins
const int PHOTOPIN = A1, LEDPIN = 3;

//Servo object and variable creation
Servo gauge;              //Create servo object "gauge"
int pos = 0;              //Set pos varible to 0 (stores position of servo)
const int SERVOPIN = 5;   //Variable holding servo pin number

//LCD object creation and pin attachment
const int en = 4, rs = 7, d7 = 12, d6 = 10, d5 = 9, d4 = 8;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

//Prepare timing values to reduce delay of writing to LCD
const int waitingValue = 100; // Time delay between readings
unsigned long lastTime = 0;   // Variable to store the most recent time

//MQTT Variables
const unsigned long WAIT = 250; //25sec
unsigned long timer;

int inVal, outVal;

//Code to run once
void setup() {

  //LCD Initialization
  lcd.begin(16, 2);
  lcd.print("Hello");

  //Define inputs
  pinMode(FSRPIN, INPUT);
  pinMode(PHOTOPIN, INPUT);

  //Define outputs
  pinMode(LEDPIN, OUTPUT);

  //Set gauge object to read from SERVOPIN
  gauge.attach(SERVOPIN);
  
  Serial.begin(115200); // qt_arduino_mqtt_bridge uses this rate
  Serial.setTimeout(50); // wait ≤ 50 milliseconds to parse incoming data

}

//Code to loop through
void loop() {

//  //Recieve input from previous transducer
//  int ledVal = map(inVal, 0, 99, 0, 255);
  
  //Convert pressure into light
  int fsrValue = analogRead(FSRPIN); //Read FSR value and sotre in fsrValue

  int ledVal = map(fsrValue, 0, 1000, 0, 255); //convert pressure to PWM signal
  
  analogWrite(LEDPIN, ledVal); //Display brightness
  //Convert light into servo orientation
  int photoVal = analogRead(PHOTOPIN); //Read photoresistor to get brightness
  int servoAngle = map(photoVal, 0, 750, 0, 180); //Convert brightss to degreeof rotation
 
  //Rotate servo to correct angle and wait for it to get there
  gauge.write(servoAngle);
  delay(15);

  //Output to LCD after every time interval
  if (millis() - lastTime > waitingValue) {
    lcd.clear();
    lcd.print("i:" + String(map(fsrValue, 0, 1000, 0, 99))); //Print FSR input value in 0-99 range
    
    //Set location of next print line to middle of the first row
    lcd.setCursor(6, 0);
    lcd.print("m:" + String(map(ledVal, 0, 255, 0, 99))); // Print LED value in 0-99 range
    
    //Set location of next print to be the bottom middle of the LCD
    lcd.setCursor(6, 1);
    lcd.print(String(map(photoVal, 0, 750, 0, 99))); //color sensor output value in 0-99 range
    
    //Set location of next print to be the bottom right of the LCD
    lcd.setCursor(11, 1);
    lcd.print("o:" + String(map(servoAngle, 0, 170, 0, 99))); // Print servo output value in 0-99 range
    lastTime = millis();
  }

  //Transmit output data to next device
  if (millis() - timer > WAIT){
    outVal = map(servoAngle, 0, 170, 0, 99);
    transmitSerialSignal();
    timer = millis();
  }
}

void serialEvent(){
  /*  You do *not* need to call this function in your loop;
      it is a special function that will run whenever serial
      data flows into the Arduino. */
  
  /*  The function assumes your machine's input value 
      is called "inVal" (change that variable name as needed) */

  // if there is incoming serial data, read it
  while (Serial.available() > 0){
    // interpret incoming digits as integer and save into inVal
    inVal = Serial.read();
  }
}

void transmitSerialSignal(){
  /* You should call this function 2-4 times/second in your
     main loop to transmit information to the next Arduino
     in the transmission chain. */
  
  /* Assumes your machine's outgoing value is called outVal
     (change that variable name as needed) */
  Serial.println(outVal);
}

 

]]>