Project 1 – Intro to Physical Computing: Student Work Spring 2021 https://courses.ideate.cmu.edu/60-223/s2021/work Intro to Physical Computing: Student Work Thu, 11 Mar 2021 01:29:39 +0000 en-US hourly 1 https://wordpress.org/?v=5.6.13 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: Position to Color/Light to Vibration https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-position-to-color-light-to-vibration/ Wed, 10 Mar 2021 14:00:07 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12436 TinkerCad Simulation

This simulation helped us plan our physical project. Here we have a potentiometer as the input, an RGB LED and photo-resistor as our middle step, and a pancake vibration motor as our output.

Dani’s Project

Overview of project

Dani’s final project

Demonstration:

Nish’s Project

Nish’s Final Project image

Demonstration:

Project Images

RGB LED and Color Sensor

The RGB LED and the Color Sensor (purple chip) act as our middle transduction step

The accelerometer is the input to detect position change

Project Description

 

The user holds a position sensor and can move and tilt it in all directions. This will make and LED light up in different colors, depending on the position of the sensor. A color sensor picks up what color the LED is at that moment. The color sensor will then determine how much to vibrate the output based on what color it sees.

 

Progress Images

I thought the power/ground connections went all the way to both sides of the board, but there is a small gap at the bottom. It took me a while to realize I needed to bridge the gap to close the electrical connection.

We were getting negative values on our LCD and we realized it was because we were mapping to incorrect ranges that were causing values outside of the 0-99 range.

I wasn’t able to get the LCD to display correctly for a while. It turned out the wires weren’t matched up exactly to how I had described them in the Arduino code, and the LCD pins were not fully inserted into the breadboard. It was difficult to get the pins to stay in consistently. – Nish

I was having some difficulty soldering because I decided to solder in the RGB LED first. However, this was a bad idea as it made the rest of the board uneven for me to solder the resistors and other components on. Therefore, a lot of the resistors look uneven and like they’re sticking out, as demonstrated in this picture. Also, even though it doesn’t really matter, I was upset that I had soldered upside down on the protoboard. – Nish

Discussion

The easiest parts of this project including the brainstorming and ideation as well as the actual wiring of the parts. We felt there was only a limited number of options for our middle step since it would be difficult to physically modulate anything in our middle step to use something like distance/distance sensor. However, upon seeing what other groups have completed, we realized we could have been more creative in this project by using outputs and motors we do have to create a physical middle step, perhaps something similar to our wind sensor idea but more practical for this class. However, using color as a middle step did invoke some challenges as well that we didn’t think we would run into.

Though the soldering overall was easy, Nish did learn something that should have been intuitive. Although RGB LEDs individually have different current values they need in order to not blow up, if you use different resistors on each one, the intensity of each color will show up differently. She had already soldered in her resistors when she realized this, and this mistake was reflected when the color sensor was not able to sense as much red as should have been outputted in the LED.

Learning how to use the color sensor was an interesting challenge, though not a difficult one. Since we were using a sensor that was not a part of our kit, there wasn’t necessarily a module that described how to wire it and code it, so our team had to use our own research to find our model and other projects that had used the same sensor. Since this is a common sensor it was not that difficult to find Arduino code online that we could model ours after. While we probably don’t understand why it’s coded in the way it is and didn’t fully utilize all the functions, we were able to successfully sense the output of our RGB LED.

The most difficult part of our project was figuring out how to go from three inputs (X, Y, Z orientation) to just one final output, where different combinations of the three inputs would lead to a meaningful differences in the final output. Several different input positions can lead to the same output, as we discovered that the X, Y, Z inputs tend to vary around the same values for the most part (between 200 and 300, though their individual ranges can go between 0 and 500). Therefore, if we mapped the entire 0 to 500 value to a 0-255 range for our RGB values, we would end up with very similar colors no matter what the orientation is, so we chose to map our X, Y, and Z values of only 200-300 to a 0-255 range for later use. However, for some reason when we tried to map to a 0-99 range for our output into the LCD, the Arduino program did not like that and we had to change our range of the X, Y, Z inputs from 200-300 to 0-500, resulting in the LCD representation for our input having a very small range that was not consistent with the rest of the numbers that had been calculated from a 200-300 range mapping. We are still unsure as to why the Arduino program did not let us map from a 200-300 range in this portion, and hope to eventually get more consistent numbers between our four outputs on the LCD.

 

We also ran into a problem where despite using code similar to our previous outputs to the LCD, the representation of the vibration output was coming out negative. Both of us individually solved this in different ways, with one of us using “constrain” from 0 to 99, and the other changing this output from an int to an unsigned int. While we learned different methods to solve the problem, we are still unsure of the root cause of why we got a negative output in the first place, since I don’t believe we caused any overflow and we were only working with positive numbers that had worked fine up until that calculation. Throughout these several issues with mapping, we were able to pick up handy debugging skills, such as using the Serial.print() function for both strings and variables in intermediate steps to see what our numbers were before we mapped them, and to find the appropriate typical range for each of our sensors.

 

We probably could have used more features of the color sensor if we had explored more. Since we were going from three inputs to one output, and our X, Y, Z ideally directly maps to an RGB value, respectively, we perhaps could have utilized the “lux” sensor. Our color sensor was able to sense not only red, green, and blue values, but also the intensity. Looking back, this may have made more sense to use it’s a more direct way of going from the color itself to a single property of the color, rather than trying to arithmetically calculate a single output value for vibration from three values of red, green, and blue. It also would have made our middle step more significant in calculating the final output, rather than just something we had to put in for this project since we definitely could have used a similar formula to directly calculate vibration from the X, Y, Z coordinates.

Functional Block Diagram and Schematic

The Functional Block Diagram for our project shows a high level of the inputs and outputs.

The Schematic of our project presents a more detailed view of how the components are connected to each other.

Code

#include <Wire.h>
#include "Adafruit_TCS34725.h" // for color sensor
#include <LiquidCrystal.h> // for LCD

/*

Daniela Castleburg & Nish Nilakantan

Double Transducer: Orientation to Color to Vibration

This code takes in X, Y, Z coordinates of an input sensor and maps them to RGB values which create a color outputted by the RGB LED, which is then sensed by the color sensor and mapped to a single value that represents the strength of output vibration.


Pin Table: 

pin     |     mode    |   description
--------------------------------------
A0          input         x position
A1          input         y position
A2          input         z position
A4          input         color sensor (SDA)
A5          input         color sensor (SCL)
3           output        pancake vibrator
4           output        d4 LCD
5           output        d5 LCD
6           output        d6 LCD
7           output        d7 LCD
9           output        Blue LED
10          output        Green LED
11          output        Red LED
12          output        EN LCD
13          output        RS LCD


Credits for Color Sensor code: https://learn.adafruit.com/adafruit-color-sensors/arduino-code
*/


// INPUT //
// Accelerometer pins
const int accelXPin = A0; // Analog input pin for X movement
const int accelYPin = A1; // Analog input pin for Y movement
const int accelZPin = A2; // Analog input pin for Z movement

// Variables to keep track of the current positions
int accelXPos = 0;
int accelYPos = 0;
int accelZPos = 0;


// MIDDLE STEP //
// RGB LED pins
const int RED = 11;
const int GREEN = 10;
const int BLUE = 9;

/* Initialise with specific int time and gain values */
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_700MS, TCS34725_GAIN_1X);


// OUTPUT //
const int PANCAKE = 3;

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

// Other variables
const int WAIT = 200;
unsigned long lastTime = 0;


// MQTT
int inVal, outVal;

void setup() {
// begin serial communication
Serial.begin(115200);
Serial.setTimeout(50);

// finding the color sensor
if (tcs.begin()) {
Serial.println("Found sensor");
} else {
Serial.println("No TCS34725 found ... check your connections");
while (1);
}

// RGB LED as output
pinMode(RED, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(BLUE, OUTPUT);

// Setup the accelerometer inputs
pinMode(accelXPin, INPUT);
pinMode(accelYPin, INPUT);
pinMode(accelZPin, INPUT);

// Pancake Vibration Motor as output
pinMode(PANCAKE, OUTPUT);

// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
}


void loop() {

uint16_t r, g, b, c, colorTemp, lux;

// Get the current states of accelerometer
accelXPos = analogRead(accelXPin);
accelYPos = analogRead(accelYPin);
accelZPos = analogRead(accelZPin);
int accelAbs = sqrt(accelXPos ^ 2 + accelYPos ^ 2 + accelZPos ^ 2); // absolute acceleration for LCD

// map acceleration input to LED output
int redVal = map(analogRead(accelXPin), 200, 300, 0, 255);
int greenVal = map(analogRead(accelYPin), 200, 300, 0, 255);
int blueVal = map(analogRead(accelZPin), 200, 300, 0, 255);


// Use mqtt to get input data
// int redVal = map(inVal,0,99,0,255);
// int greenVal = map(inVal,0,99,0,150);
// int blueVal = map(inVal,0,99,0,100);
int LEDAbs = sqrt(redVal ^ 2 + greenVal ^ 2 + blueVal ^ 2); // combination of LED values for LCD

// update LED color based on accelerometer position
analogWrite(RED, redVal);
analogWrite(GREEN, greenVal);
analogWrite(BLUE, blueVal);

// data from color sensor
tcs.getRawData(&r, &g, &b, &c);
int colorSensorAbs = sqrt(r ^ 2 + g ^ 2 + b ^ 2); // combination of color sensor values for LCD

// map color sensor data to pancake input
int pancakeVal = map(colorSensorAbs, 100, 250, 0, 255);

// update pancake vibration motor based on color sensor
analogWrite(PANCAKE, pancakeVal);

// get pancake value
//int normOutput = analogRead(PANCAKE);

// normalize all variables to 0-->99 range
int normInput = map(accelAbs, 0, 500, 0, 99); // Accelerometer
int normMiddleOutput = map(LEDAbs, 0, 255, 0, 99); // RGB LED
int normMiddleInput = map(colorSensorAbs, 0, 500, 0, 99); // Color Sensor
int normOutput = map(pancakeVal,-350,350,0,99); // Pancake Vibration motor

// print information to LCD
if (millis() - lastTime > WAIT) {
lcd.setCursor(0, 0);
lcd.print("i:");
lcd.setCursor(2, 0);
lcd.print(normInput);

lcd.setCursor(6, 0);
lcd.print("m:");
lcd.setCursor(8, 0);
lcd.print(normMiddleOutput);

lcd.setCursor(8, 1);
lcd.print(normMiddleInput);

lcd.setCursor(12, 1);
lcd.print("o:");
lcd.setCursor(14,1);
lcd.print(normOutput);

outVal = normOutput;
transmitSerialSignal();

lastTime = millis(); // update timer variable
}
}


// Mqtt functions
void serialEvent(){
while(Serial.available() > 0){
inVal = Serial.parseInt();
}
}

void transmitSerialSignal(){
Serial.println(outVal);
}

 

]]>
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: Vibration to Movement to Sound https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-vibration-to-movement-to-sound/ Wed, 10 Mar 2021 05:54:59 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12520 Tinkercad Video:

Tinkercad does not have a lot of components that are present in the real life version, so there are some fake data simulation. In real life, our first sensor is an accelerometer, but we simulated it with a potentiometer. The values are mapped to be in between 0-100 to mimic values we could get from our accelerometer. From there, the data is mapped to a value between 130-180 so serve as an angle for the servo motor. In real life, the servo motor would move an object in front of an ultrasonic ranger, but instead, we have to fake the simulation. The distance output from the ultrasonic ranger is then mapped to a value between 100 and 600 to serve as tone for the buzzer.

Photos for Scale:

Shuyu:

Vishnu:

Detail Photos

Initially, getting data from the accelerometer was a little foreign, so it took some thinking on how we would utilize the data.

The accelerometer was a new tool to us, so we had to research on how to wire and write code for it.

Testing everything with a pancake motor at the end.

Building the arm that extend back and forth had its mechanical difficulties. It took a while to troubleshoot how far the arm could extend.

Videos:

Shuyu:

 

Vishnu:

 

Narrative Description:

Our double transducer takes in vibration as an input (via a 3-axis accelerometer), and converts that input to an angle for a servo motor. The servo motor is attached to a popsicle stick “arm” that extends based on the angle. An ultrasonic ranger detects how far the popsicle sticks are from it and the resulting distance (cm) is converted into a tone for an 8-ohm speaker. 

Progress Photos:

Shuyu: This was when I first successfully wired and ran some code through the LCD display. It was super exciting because the wiring was a little intense and something could have easily gone wrong.

Shuyu: Using a transistor to wire a speaker was a new concept and wiring it correctly was a major step in the overall project.

Vishnu: Troubleshooting the popsicle arm and trying to find a good angle range. I ended up building barriers for it.

Vishnu: Wiring the speaker had some challenges because wires were not connected into the right ports.

 

Discussion:

The entire process of brainstorming, planning, and creating the double transducer was filled with its unique set of problems and triumphs. From the beginning, we were not familiar with vibration as an input and we were not sure how ambitious we should be with our middle step. We played around with a couple of ideas, including a basic vibration to light to sound workflow. Excluding the vibration portion, we were confident we could get the “light” middle step (LED + photoresistor) to work and output sound; this would serve as a good backup plan in case a more ambitious setup failed.

The ambitious idea we settled on was a system of vibration to movement to sound. We decided to split the “movement” into two parts: One part performing the movement (a Servo motor with a lever attached), and the other part sensing proximity and outputting a distance value (via an ultrasonic ranger). We found that while the idea was simple enough, the middle step ran into significant challenges. 

Most notably, we had to restrict the servo motor from its total range, in order to constrain it to the board as well as prevent it from ripping out of its supports. This was mainly achieved through trial and error, and each of us had slightly different ranges based on the physical layout of our board and device. 

With help from Zach, we realized that a good stand-in for a vibration sensor was a 3-axis accelerometer. The accelerometer senses the position (X,Y, Z) of the device if it is even slightly shifted. We realized that this could work to our advantage, although we needed to manually manipulate it to achieve the output. We found that because we had to twist the accelerometer around, we had to make sure to bolt the apparatus down through soldering and tape.

This project definitely pushed us to understand the real-world limitations of theoretical concepts. While there were chunks of the project we could neatly resolve in software, there were other parts we simply had to stress-test through empirical trials (such as the servo extension). Overall, we came away with a solid understanding of the relationship between different mediums, as well as the interlocking nature of software and hardware in electronics.

 

Functional Block Diagram:

Schematic:

 

 

Code:

/*
   60-223, Double Transducer : Vibration to Movement to Sound
   Shuyu Zhang, Vishnu Raghavan

   Description: Our doubel transducer takes in vibration as an input.
   The input is measured by a 3-axis accelerometer. The difference between
   the input from the x-axis and y-axis is then mapped to an angle
   for a servo motor (130-180 degrees). In real life, the servo motor is
   attached to a popsicle arm that will extend based on the angle the servo
   motor moves to. An ultrasonic ranger sits in front of the popsicle arm
   and measures how close or far the arm is from it. The data from the
   ultrasonic ranger is then mapped to a tone (100-600) which is the output
   for a speaker.

   Sources:
   1) Heavily referenced the program on the maker cards website when programming the
   accelerometer
   2) Incorporated some of the code of an example from the HCSR04 library in order
   to read distance with the ultrasonic ranger
   3) Referenced the Servo Motor example from class to program the servo motor
   4) Used LCD Display wiring and program from Arudino Website to program the
   LCD Display


   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   12     LCD Pin  Used to initialize the LiquidCrystal Library
   11     LCD Pin  Used to initialize the LiquidCrystal Library
   5      LCD Pin  Used to initialize the LiquidCrystal Library
   4      LCD Pin  Used to initialize the LiquidCrystal Library
   3      LCD Pin  Used to initialize the LiquidCrystal Library
   2      LCD Pin  Used to initialize the LiquidCrystal Library
   9      Output   Servo Motor pin
   6      Output   Buzzer pin
   13     Input    Trigger Pin in the Ultrasonic ranger
   7      Input    Echo Pin in the Unltrasonic ranger
   A0     Input    Analog input pin for X movement
   A1     Input .  Analog input pin for Y movement
   A2     Input    Analog input pin for Z movement

*/

#include <HCSR04.h>
#include <Servo.h>
#include <LiquidCrystal.h>

const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

Servo motor;
byte triggerPin = 13;
byte echoPin = 7;
const int SERVOPIN = 9; //Analog
const int BUZZER = 6; //Analog output in for 8Ω Speaker
const int ACCELXPIN = A0; // Analog input pin for X movement
const int ACCELYPIN = A1; // Analog input pin for Y movement
const int ACCELZPIN = A2; // Analog input pin for Z movement
const int TIMERWAIT = 1000;
const int MOTORWAIT = 200;

// Variables to keep track of the current positions
int accelXPos = 0;
int accelYPos = 0;
int accelZPos = 0;
int dist;
int angle;
int currTone;
int accelData;
unsigned long timer = 0;
unsigned long motorTimer = 0;

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

  //Set up for ultrasonic ranger
  HCSR04.begin(triggerPin, echoPin);

  //Set up for servo motor
  motor.attach(SERVOPIN);

  // Setup the accelerometer inputs
  pinMode(ACCELXPIN, INPUT);
  pinMode(ACCELYPIN, INPUT);
  pinMode(ACCELZPIN, INPUT);

  //Setup for buzzer output
  pinMode(BUZZER, OUTPUT);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
 
}

void loop() {

  // Get the current states
  accelXPos = analogRead(ACCELXPIN);
  accelYPos = analogRead(ACCELYPIN);
  accelZPos = analogRead(ACCELZPIN);

  //declares a variable to read distance for ultrasonic ranger
  double* distances = HCSR04.measureDistanceCm();

  accelData = abs(accelXPos - accelYPos); //Gives range of (0-90)

  //Mapping Accelerometer data to an angle
  angle = map(accelData, 0, 90, 130, 180);


  //Set at a delay of 200 milliseconds
  //c
  if (millis() - motorTimer > MOTORWAIT) {
    motorTimer = millis();

    dist = (int)(distances[0]);
    currTone = map(dist, 0, 30, 100, 600);
    tone(BUZZER, currTone);

    //changes angle based on accelerometer input
    //changes tone based on distance
    motor.write(angle);
    delay(200);
    tone(BUZZER, currTone);
    motor.write(angle);
    delay(200);

  }


  //LCD Display Code
  if (millis() - timer > TIMERWAIT) {
    timer = millis();

    lcd.setCursor(8, 1);
    int midSen = map(dist, 0, 30, 0, 99);
    lcd.print(midSen);
    if (midSen > 100) {
      lcd.clear();
    }

    //First Row on LCD
    lcd.setCursor(0, 0);
    lcd.print("i:");
    int input = map(accelData, 0, 90, 0, 99);
    lcd.print(input);
    lcd.setCursor(7, 0);
    lcd.print("m:");
    int midAct = map(angle, 130, 180, 0, 99);
    lcd.print(midAct);

    //Second Row on LCD
    lcd.setCursor(12, 1);
    lcd.print("o:");
    int output = map(currTone, 200, 600, 0, 99);
    lcd.print(output);
  }


}

 

 

]]>
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);
}

 

]]>
Double Transducer | Light to Orientation https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-light-to-orientation/ Tue, 09 Mar 2021 22:31:31 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12422 Team Members: Kevin Bender, Nicole Yu

Tinkercad:

* the potentiometer on the left is representative of the rotary encoder. The DC motor and driver are representative of the stepper motor and driver

Overall:

Nicole’s final double transducer

Kevin’s Final Double Transducer

 

Detail Photos:

LCD input/output values

Servo motor “dial” (from 0º – 180º)

Close up of the connection between the stepper motor and rotary encoder

Final protoboard wiring

 

 

 

 

 

 

 

 

 

 

 

 

 

Brief Movies:

 

Description:

This device detects the amount of light through a photoresistor, and sends that signal to the stepper motor driver and stepper motor, which turns the rotary encoder at a certain speed. The rotary encoder determines how far it was rotated, and sends that data to the servo motor, which based on the data, turns to a certain angle (orientation).

Progress Images:

Figuring out the connection between the stepper motor and rotary encoder [Nicole]

An LCD that needs to be debugged [Nicole]

LCD setup with “Hello World” starter code from library [Kevin]

In-progress picture of soldering the photoresistor and encoder circuits onto a protoboard [Kevin]

 

 

Testing all the individual components put together for the first time! [Kevin]

Discussion:

I think one of the biggest hurdles for us was dealing with the unknown. We chose to use a rotary encoder, something that we weren’t really familiar with, causing a lot of uncertainty. We also had no idea how we were going to connect the stepper motor and rotary encoder together, so we winged that as well. In hindsight, I think we should’ve fleshed out our plan to the smallest detail before starting rather than going in with a vague idea. That would’ve saved a lot of headaches. However, on the other hand, going in with vague idea was a great way to force one to solidify their idea, since planning can only do so much.

Nicole: Planning first would’ve also helped me with my wiring, since once the LCD Display came along with its 6 more pins, I was just sticking them wherever there was available space. Ideally, if I had planned it out, I would have the pins consecutive with each other.

One of our challenges was that we needed 12 digital pins, meaning that we were either forced to do some challenging wiring to use something like a shift register or sacrifice one of the TX/RX pins. At first neither of us knew exactly what the implications of that would be, but we found out that we could not upload code to the Arduino or use serial communication while using these pins. This ended up being a headache when we were debugging issues with our code and wiring as if we forgot to unplug the TX pin the code failed to upload. The wire ended up breaking inside the pin, although luckily some needle nose pliers saved the day. I will be trying my best to avoid using these pins in the future by using a shift register or investing in an Arduino board with more pins.

Diagrams:

Functional Block Diagram

Functional Block Diagram

Schematic Diagrams

Nicole’s electrical schematic

*a few of Kevin’s pins are slightly different (see code), but the wiring is identical otherwise

 

Code:

Nicole’s Code

/*
   60-223, Project 1: Double Transducer
   Nicole Yu (nvy) Kevin Bender (kbender1)

   Description:
   This device detects the amount of light through a photoresistor, and
   sends that signal to the stepper motor driver and stepper motor,
   which turns the rotary encoder at a certain speed. The rotary encoder
   determines how far it was rotated in the span of 2 seconds, and sends
   that data to the servo motor, which based on the data, turns to a
   certain angle (orientation).

   
   Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   A0            input     photoresistor
   2             input     rotary encoder pin A
   3             input     rotary encoder pin B
   5             output    servo motor
   7             input     stepper motor IN1
   8             input     stepper motor IN2
   9             input     stepper motor IN3
   10            input     stepper motor IN4
   A1            output    LCD RS
   4             output    LCD Enable
   6             output    LCD D4
   11            output    LCD D5
   12            output    LCD D6
   13            output    LCD D7

   Sources:
   1) How to wire and program the LCD from the Elgoo website:
   https://drive.google.com/drive/folders/1BUe40Ibb9Bzi1JwRKywO1PCXBMzkFXm7?usp=sharing
   2) I borrowed heavily from this Stepper motor library
   and code: https://www.arduino.cc/en/Tutorial/LibraryExamples/StepperSpeedControl
   3) I followed this tutorial and borrowed heavily its code:
   https://www.seeedstudio.com/blog/2020/01/19/rotary-encoders-how-it-works-how-to-use-with-arduino/
   4) I referenced the Canvas modules to refresh on how to wire and
   code for a photoresistor and servo
*/

// LIBRARIES
#include <Encoder.h>
#include <Stepper.h>
#include <Servo.h>
#include <LiquidCrystal.h>

// VARIABLES
const int PHOTOPIN = A0; // photoresistor pin
const int DOORMOTORPIN = 5; // servo motor pin
const int stepsPerRevolution = 200; // stepper motor's
const int WAIT = 2000; // 2 seconds
unsigned long timerVariable = 0;
int orientation;
long oldPosition  = -999;

// initialize library code
LiquidCrystal lcd(A1, 4, 6, 11, 12, 13);
Stepper myStepper(stepsPerRevolution, 7, 8, 9, 10);
Encoder myEnc(2, 3);
Servo doorMotor;


void setup() {

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  // servo
  doorMotor.attach(DOORMOTORPIN);

}

void loop() {

  // PHOTORESISTOR
  int photoVal = analogRead(PHOTOPIN);

  // STEPPER MOTOR
  int motorSpeed = map(photoVal, 0, 1023, 0, 100);
  if (motorSpeed > 0) {

    myStepper.setSpeed(motorSpeed);
    myStepper.step(stepsPerRevolution / 100);

    // ROTARY ENCODER
    long newPosition = myEnc.read();

    // SERVO
    int orientation = map(newPosition, 0, 17, 10, 170); // the 17 is a placeholder,
    // I haven't seen the rotary encoder go past 16

    // Sees at 2 seconds how far rotary encoder turned
    if (millis() - timerVariable > WAIT) {

      doorMotor.write(orientation);
      myEnc.write(0); // resets encoder to 0

      // LCD
      // update LCD here
      lcd.setCursor(0, 0);
      lcd.print("i:"); // input
      lcd.print(photoVal);
      lcd.print(" "); // solution to non erasing problem

      lcd.setCursor(8, 0);
      lcd.print("m1:"); // middle step 1
      lcd.print(motorSpeed);
      lcd.print(" ");

      lcd.setCursor(0, 1);
      lcd.print("m2:"); // middle step 2
      lcd.print(newPosition);
      lcd.print("  ");

      lcd.setCursor(8, 1);
      lcd.print("o:"); // output
      lcd.print(orientation);
      lcd.print(" ");


      timerVariable = millis();

    }

    // not > 2 seconds, update the old position
    else {
      if (newPosition != oldPosition) {
        oldPosition = newPosition;
      }

    }
  }
}
/*
 * 60-223, Project 1
 * Kevin Bender (kbender1)
 * time spent: ~8 hours
 *
 * Collaboration and sources: 
 * 1) Nicole Yu and I worked together on the idea and 
 *  electrical design, coded separately (other than tinkercad)
 * 2) I borrowed from the Elegoo starter kit lesson 2.3 for the 
 *    LCD
 * 3) I borrowed from the Encoder library examples
 * 6) I borrowed from the stepper library examples
 * 
 * Challenge(s): This project took a lot of learning and research
 *  as it combined everything we had learned so far about
 *  Arduino and electronics. The challenges came in the form
 *  of trying to figure out how to use the LCD which didn't work
 *  with the manufacturer-recommended wiring of 3.3v and with the 
 *  stepper motor which was much weaker than expected. 
 *  
 * Next time: I will try to learn more about potential inputs/outputs
 * and possibly try them out in advance. A lot of suffering could
 * have been saved by doing this with the stepper motor
 * 
 * Description: Object detects light level, based on how intense light is it would cause a motor to spin fast/slow, 
 * and that speed would then affect the orientation of the servo motor “dial” (from encoder)
 * 
 * Pin mapping:
 * 
 * Arduino pin | type   | description
 * ------------|--------|-------------
 * A0            input     Photoresistor as initial input
 * 1             input     rotary encoder pin A for middle step input
 * 13            input     rotary encoder pin B
 * 2             output    Stepper motor driver pin A as middle step output
 * 3             output    Stepper motor driver pin B 
 * 4             output    Stepper motor driver pin C 
 * 5             output    Stepper motor driver pin D 
 * 6             output    servo motor for final output
 * 7             input     pushbutton to activate lights
 * 8             output    LCD pin A
 * 9             output    LCD pin B
 * 10             output    LCD pin C
 * 11             output    LCD pin D     
 * 12             output    LCD pin E
 */

// include the library code:
#include <LiquidCrystal.h>
#include <Encoder.h>
#include <Stepper.h>
#include <Servo.h>

const int stepsPerRevolution = 200;

const int ENC1 = 1;
const int ENC2 = 13;

const int LCD1 = 7;
const int LCD2 = 8;
const int LCD3 = 9;
const int LCD4 = 10;
const int LCD5 = 11;
const int LCD6 = 12;

const int STEP1 = 2;
const int STEP2 = 3;
const int STEP3 = 4;
const int STEP4 = 5;

const int SERVOPIN = 6;

const int PHOTORESISTOR = A0;
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(LCD1, LCD2, LCD3, LCD4, LCD5, LCD6);
Encoder myEnc(ENC1, ENC2);
Stepper myStepper(stepsPerRevolution, STEP1, STEP2, STEP3, STEP4);
Servo myservo; 

void setup() {
  myservo.attach(SERVOPIN);
  // put your setup code here, to run once:
  lcd.begin(16, 2);
  // Print a message to the LCD.
  pinMode(PHOTORESISTOR, INPUT);

}


void loop() {
  long t0 = millis();
  long speed = 0;
  long lastPos = myEnc.read();
  while (true) {
    long t = millis();
    myEnc.read();
     int motorSpeed = map(analogRead(PHOTORESISTOR), 0, 1023, 0, 100);
    // set the motor speed:
    if (motorSpeed > 0) {
    myStepper.setSpeed(motorSpeed);
    // step 1/100 of a revolution:
    myStepper.step(stepsPerRevolution / 100);
  }
    if (t - t0 > 1000) {
      long curPos = myEnc.read();
      speed = abs(curPos-lastPos);
      long pos = map(speed,0,15,0,180);
      myservo.write(pos);
      lastPos = curPos;
      lcd.setCursor(0, 0);
      lcd.print( "i: " + String(map(analogRead(PHOTORESISTOR), 0, 1023, 0, 99)) + " m: "+String(motorSpeed));
      lcd.setCursor(0, 1);

      lcd.print("  " + String(speed)+ "  o: " +  String(map(pos,0,180,0,99)));
      // print the number of seconds since reset:
      t0 = t;
    }
  }

}

 

]]>
Double Transducer: Ultrasonic to Rotation to Light Output https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-ultrasonic-to-rotation-to-light-output/ Tue, 09 Mar 2021 01:13:27 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12348

Initial Sketches and Block Diagram:

For the middle step on our transducer, we were deciding between having a servo drive a potentiometer, having a servo drive a platform with an accelerometer, and having a speaker output measured by a microphone. We ended up deciding on the servo – accelerometer pair, but also made a servo – potentiometer prototype as an initial version to test various components on.

TinkerCAD Exploration

Ultrasonic to Potentiometer to LED

Erica’s Version

This was the initial double transducer design we had. My project was barely held together. I had to tape the micro servo to the Maker Cards and used the wire cutter to hold the breadboard down so that the board wouldn’t lift when the servo motor turned the potentiometer.

Using an ultrasonic ranger, I detected the distance from the build. The ranger determined the angle of the servo motor which was attached to the potentiometer. This potentiometer then determined the brightness of the LED.

By replacing the small breadboard with a bigger version, I was able to make a less cluttered double transducer.

Here is a video of my working double transducer. I displayed the input and output values using the Serial Monitor on Arduino. Through the video, you can see that the light turns brighter when the box is closer to the ultrasonic sensor and dimmer when the box is further away.

Eric’s Version

Similar to Erica’s version, I connected the servo to the potentiometer through a paperclip and servo mount.

Due to the noisiness of the ultrasonic data, I added a moving average filter to smooth that out. Also, I found out the analog input pins do not have PWM capabilities which was a helpful reference for later.

 

Ultrasonic to Accelerometer to LED

Erica’s Contribution

We soldered the 3-axis accelerometer and a terminal, ensuring a strong connection for our middle step in the transducer. The final configuration of the objects on the board was tightly put together, with the 3-axis accelerometer acting like a protective hood over the terminal.

For the final project, I also configured the LCD to display the outputs. Working with the LCD was difficult because of the intense amount of wiring, but through following tutorials online, I was able to successfully have the LCD display our input and output values.

Eric’s Contribution

To convert the accelerometer’s 3-axis acceleration readings into an angle value that could be interpreted as a parallel to the servo’s rotation, there was a little trig involved (taking an inverse tangent of two axes, modeled after the unit circle). The above clip is me testing the accelerometer’s analog inputs and figuring out the range of raw inputs to map to -1 and 1 for both x and y values on the unit circle.

For the final transducer, I soldered part of the proto-board that the accelerometer attaches to and mounted the the board onto the servo arm via paper clips.

Detail Shots of Final Project

Code

/*
 * 60-223, Project 1
 * Eric Zhao (ezhao2), Erica Fu (efu)
 * time spent: 20 hours 
 *
 * Collaboration and sources: 
 * 1) Eric and Erica worked together from planning, coding, to building the final project
 * 2) Zach assisted many times throughout the process
 * 3) We borrowed heavily from the Arduino guide to use the LiquidCrystal library
 * website link: https://www.arduino.cc/en/Tutorial/LibraryExamples/HelloWorld
 * 4) We implemented this moving average filter to smooth out ultrasonic data values:
 * https://courses.ideate.cmu.edu/60-223/s2021/tutorials/code-bites#exponential-moving-average-filter
 * Challenge(s): Since there are many wires, the wiring often became jumbled and confusing. 
 * Also, the LCD display could only use certain pins, causing us to have to rewire the whole project.
 * The connection from the servo motor to the 3-axis-accelerometer was also quite difficult since
 * we had to customize parts and eventually settle for using a paperclip to make a mechanical connection.
 * 
 * Next time: We will organize wiring better so that the circut is clearer so that any change 
 * of wiring will be less confusing.
 *To prevent breaking any more Arduinos, Erica will double check the wiring to ensure that 
 * there is minimal damage caused in the future.
 * 
 * Description: The entire breadboard is mounted to a servo motor whose output shaft is connected to a 
 * rigid vertical structure. Depending on the input voltage from the ultrasonic sensor, the servo motor 
 * will output a corresponding angle, causing the entire breadboard to rotate. An accelerometer attached 
 * to the breadboard will read the tilt angle of the breadboard caused by the servo. The input voltage 
 * will determine the output voltage of the LED.
 * 
 * Pin mapping:
 * 
 * Arduino pin | type   | description
 * ------------|--------|-------------
 * A0            input     xInput of the 3-axis accelerometer
 * A1            input     yInput of the 3-axis accelerometer
 * A2            input     zInput of the 3-axis accelerometer
 * 9             output    mini servo motor
 * 6             output    red LED 
 * 12            output    rs pin for the LCD monitor
 * 11            output    en pin for the LCD monitor
 * 5             output    d4 pin for the LCD monitor
 * 4             output    d5 pin for the LCD monitor
 * 3             output    d6 pin for the LCD monitor
 * 2             output    d7 pin for the LCD monitor
 * 
 */
 
#include <Servo.h>
#include <NewPing.h>
#include <LiquidCrystal.h>

#define TRIGGER_PIN 8
#define ECHO_PIN 7
#define MAX_DISTANCE 75

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);

const int waitTime = 250;
long prevTime = 0;

const int xInput = A0;
const int yInput = A1;
const int zInput = A2;
const int SERVOPIN = 9;
const int LED = 6;
Servo SERVO;

float filtered_val = 0;  // this variable, of type float (decimal), holds the filtered sensor value
const float PREV_WEIGHT = 0.8; // this variable, of type float (decimal), determines the previously filtered value's weight.
const float CUR_WEIGHT = 1 - PREV_WEIGHT; // this variable, of type float (decimal), determines the current sample's weight.
const int SENSOR_PIN = A0; // this variable, of type int, determines the sensor's pin.

// 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 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

void setup() {
  // put your setup code here, to run once:
  pinMode(xInput, INPUT);
  pinMode(yInput, INPUT);
  pinMode(zInput, INPUT);
  pinMode(LED, OUTPUT);
  SERVO.attach(SERVOPIN);
  Serial.begin(115200);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);
}

void loop() {
  // put your main code here, to run repeatedly:
  
  delay(50);
  //raw data by axis from accelerometer
  int x = analogRead(xInput);
  int y = analogRead(yInput);
  int z = analogRead(zInput);
  //data from accelerometer, mapped to units -1000 to 1000
  int xVect = map(x, 260, 390, -1000, 1000);
  int yVect = map(y, 250, 380, -1000, 1000);
  int zVect = map(z, 320, 385, 0, 1000);
  //below variables are the above vars but divided by 1000 to achieve unit circle
  float xVectUnbound = xVect/1000.0;  
  float yVectUnbound = yVect/1000.0;
  float zVectUnbound = zVect/1000.0;
  //constraining final readings to unit circle -1 to 1
  float xVectFinal = constrain(xVectUnbound, -1, 1); 
  float yVectFinal = constrain(yVectUnbound, -1, 1);
  float zVectFinal = constrain(zVectUnbound, 0, 1);
  //final arctan value (takes two axes and converts into degrees)
  float degreeVal = atan2(xVectFinal, zVectFinal) * 180/PI;

  //creates a weighted reading
  float cur_reading = sonar.ping_cm();
  if(cur_reading != 0){
    filtered_val = filtered_val * PREV_WEIGHT + cur_reading * CUR_WEIGHT;
  }

  //takes a smoothed out sonar reading and converts to servo degrees
  int servoVal = map(filtered_val, 0, 75, 0, 180);
  //takes accelerometer degree reading and converts to
  int outputVal = map(degreeVal, -55, 90, 0, 255);
  if(cur_reading != 0 && servoVal > 0){
    SERVO.write(servoVal);
  }
  
  if(outputVal > 0){
    analogWrite(LED, outputVal);
  }

  int inputDisplay = map(filtered_val, 0, 75, 0, 100);
  int middleActDisplay = map(servoVal, 0, 180, 0, 100);
  int middleSensorDisplay = map(outputVal, 0, 255, 0, 100);

  if(millis() - prevTime > waitTime){
    //outputs data to LCD display 4 times a second
    lcd.setCursor(0,0);
    lcd.print((String)"i:"+ inputDisplay);
    lcd.setCursor(5,0);
    lcd.print((String)"m:" + middleActDisplay);
    lcd.setCursor(7,1);
    lcd.print(middleSensorDisplay);
    lcd.setCursor(11,1);
    lcd.print((String)"o:" + middleSensorDisplay);

    prevTime = millis();
  }

}

 

Reflection

We found a lot more issues throughout the span of this project than either of us imagined would happen! Different libraries conflicted with each other (for example, the Servo library shut down certain pins that the NewPing ultrasonic library utilized). Mechanical connections between certain parts were difficult to make robust enough to handle the servo’s torque; we ended up using paperclips for a lot of these as compared to tape, which was a lot weaker.

]]>
Double Transducer: Light to Position to Movement https://courses.ideate.cmu.edu/60-223/s2021/work/double-transducer-light-to-position-to-movement/ Mon, 08 Mar 2021 19:03:48 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12289 Tinkercad Video

The potentiometer in this video is representative of our joystick middle step.

Overall photos for proportion and scale

Tate

 

Tate’s final board

My final version had correct transduction and displayed values at good fidelity, but even with an added transistor to the vibration motor it drew so much current that it would dim the LCD screen, but otherwise, this version had a functioning double transduction.

Dominique

Dominique’s final board

At first I thought my final version had some wiring issues surrounding the vibration motor, but upon closer inspection, and the addition of a replacement vibration motor, my double transducer actually worked fine. The LCD sensor and actuator values were being displayed properly, and luckily, it did not dim when the vibration motor was triggered, and I did not use a transistor, so this was a peculiar but happy outcome.

Final Working Version in Chain

Prototype Details

At first our LCD had many display issues. First the backlight would not turn on, then the values flashed too fast, and so forth. After implementing a special delay in void loop and switching libraries, we were able to fix the problems, at least on one of our prototypes.

 

Servo-joystick prototyping

We used our two prototypes to test different things, Dominique’s explored the LCD more and mine focused on the mechanical interface from servo to the joystick.

Prototype video

Hopefully, you can hear the vibration motor buzzing in this video as I move the flashlight closer to the photoresistor on the other end of the board. And you can see the middle step (servo moving a joystick) as well. I had to cover the photoresistor with my hand in order to block out ambient light (that was really messing with the sensory data because it was a very bright room and my flashlight was dying), so you can’t quite see the flashlight action, but it’s happening, please trust me.

Simple narrative description

Our double transducer first takes in light in a room and records the brightness through the Arduino. That value is then used to determine the rotation degree of a servo motor; more light equals a higher degree up within a specified range. The servo pushes on a joystick, from which a y-Axis position is read and stored in Arduino. Finally, a vibration motor receives that output and vibrates more as the y-axis position increases.

Progress images

Tate

 

LCD hieroglyph issues

I struggled a lot with my LCD displaying odd values because of the vibration motor current draw creating noise in the circuit.

Servo-Joystick interface and soldering to protoboard

I also struggled a lot with soldering, as I accidentally grabbed a non-powered protoboard so after soldering my adapters for the servo and joystick I had a long period of debugging to find the cause of that. It was good soldering practice because I had to bridge connections with quarter-inch lengths of wire.

Dominique

Prototyping popsicle stick connection

The hardware for this circuit was actually relatively simple to build, at least on the breadboard. The hard part was configuring the delicate servo to properly trigger the joystick. So as you can see here, that problem has not been solved yet.

LCD prototyping

This was when the LCD still was not working properly. As you can see, it is not displaying anything, and that’s due to a number of reasons which are explained in detail in the Discussion section. The biggest problem here was that the LCD was wired incorrectly.

Discussion

Even though we went into the project anticipating the hardware components for wiring a transducer that involved a joystick would be complex, that part ended up not being that difficult and only took a short amount of time to configure.

As far as the difficult aspects of the project, we ran into a lot of hiccups with writing to the LCD. One of the issues was especially mundane and we did not realize it; for the longest time, the LCD would not display any coherent information, despite the code looking to be fine. After consulting with Zach, we discovered that we were not using the right library the whole time. We were using commands from LiquidCrystal_I2C and but the LCD we have does not have the I2C backpack. So not only did we not realize we had a different LCD than the tutorials, we were wiring it wrong. Anyway, we sorted this, fortunately, but the LCD on one of the two double transducers we built still had issues we could not troubleshoot.

We also had a strange issue where as our joystick value went up, the vibration intensity went down. We wanted both to increase in direct proportion. Turns out there was a typo for one of our map() functions where the value was reversed. Also we ended up writing a bit of extra code that constrained the max value of joystickVal which helped to keep our values in line.

Tinkercad also had its own set of issues. because some inputs could not be sensed by Tinkercad, we had to “fake it.” It was interesting figuring out how to do this, but ultimately not too challenging. Since the first input is light, we could simply make that value increase and decrease automatically and the rest of the sensors and actuators respond accordingly. Because there’s no joystick in Tinkercad, we replaced it with a potentiometer, just to clarify.

There’s also the issue of figuring out how to get the tiny servo arm to push the joystick, which does not budge very easily. We used superglue to glue half a popsicle stick to the arm, as you can see in the photos, and we taped down the motor, which did help. The motor on one transducer pushed sideways on the joystick, and the motor on the other was configured to push downward, and both seemed to work fine.

Finally, for one of the two double transducers we built, it unfortunately broke after working properly a few times. The cause of the break is still kind of unknown even after checking the serial monitor and wiring. Because it was only the vibration motor that stopped responding even though the vibration value was displaying appropriately, we figured it was a wiring issue, one of the complications from a less-than-stellar soldering technique. It did look like the vibration wires were burned and not very attached, but after replacing the vibration motor and still finding issues, we figured the problem was deeper in the hardware. That was until I switched power sources and everything was completely fine. I agonized for hours over this very simple issue (Dominique).

For future projects it certainly would be useful to get a better grasp on soldering with a steady hand. That did not seem to be my strong suit, and I’m sure it will be a useful skill for the future (Dominique).

Functional block diagram and schematic

Block diagram

Schematic drawing

Here is the code

/*
  Double Transducer: Light to Position to Movement
  Dominique Aruede and Tate Johnson

  Description:
  Takes in a light value which informs the degree rotation
  of a servo arm which pushes a joystick which informs the
  vibration intensity of a vibration motor.
 
  Pin mapping:
  Arduino pin | type   | description
  ------------|--------|-------------
  A0            input     photoresistor for initial input
  A2            input     reads joystick x axis (only needed in this sketch to keep the y axis stable)
  A3            input     reads joystick y axis
  A4            input     reads vibration motor output
  2             output    writes to pin D7 on LCD
  3             output    writes to pin D6 on LCD
  4             output    writes to pin D5 on LCD
  5             output    writes to pin D4 on LCD
  6             output    writes to vibration motor
  8             output    writes to servo motor
  11            output    writes to enable pin on LCD
  12            output    writes to RS pin on LCD

  Collaboration and sources:
  - https://www.arduino.cc/en/Tutorial/LibraryExamples/HelloWorld
  - https://canvas.cmu.edu/courses/22031/modules (photoresistor asynchronous lecture)
*/

#include <Wire.h>
#include <LiquidCrystal.h>
#include <Servo.h>

//pin constants
const int PHOTORESPIN = A0;
const int SERVOARMPIN = 8;
const int JOYSTICKPINx = A2;
const int JOYSTICKPINy = A3;
const int VIBRATIONPIN = 6;
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
const int WAIT = 300;
unsigned long timerVariable = 0;


int lightVal = 0;
int armVal = 0;
int joystickVal = 0;
int vibVal = 0;

/* Create an LCD display object called "screen" with I2C address 0x27
    which is 16 columns wide and 2 rows tall.*/

LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
Servo arm; // make a servo object

void setup()
{
  // initiate pins
  pinMode(PHOTORESPIN, INPUT);
  pinMode(JOYSTICKPINy, INPUT);
  pinMode(VIBRATIONPIN, OUTPUT);


  // servo is plugged into the assigned pin on Arduino
  arm.attach(SERVOARMPIN);

  //LCD setup
  lcd.begin(16, 2);

}

void loop()
{

  //digitalWrite(VIBRATIONPIN, HIGH);
  //convert light sensing to right range
  lightVal = analogRead(PHOTORESPIN);
  int LCDlightVal = 0;
  LCDlightVal = map(lightVal, 0, 1023, 0, 99);

  //write to the transducer first part
  armVal = map(lightVal, 0, 1023, 0, 170);
  int LCDarmVal = 0;
  LCDarmVal = map(lightVal, 0, 1023, 0, 99);
  arm.write(armVal);

  //read the second transducer part
  joystickVal = analogRead(JOYSTICKPINy);
  if (joystickVal >= 512) {
    joystickVal = joystickVal - 512;
  }
  else {
    joystickVal = 0;
  }
  int LCDjoystickVal = 0;
  LCDjoystickVal = map(joystickVal, 0, 512, 0, 99);

  // write to output
  vibVal = map(joystickVal, 0, 512, 0, 255);
  analogWrite(VIBRATIONPIN, vibVal);
  int LCDvibVal = 0;
  LCDvibVal = map(vibVal, 0, 255, 0, 99);


  if (millis() - timerVariable > WAIT) {
    lcd.clear();
    lcd.home();
    lcd.print("i:");
    lcd.print(LCDlightVal);
    lcd.print("  m:");
    lcd.print(LCDarmVal);
    lcd.setCursor(8, 1);
    lcd.print(LCDjoystickVal);
    lcd.setCursor(12, 1);
    lcd.print("o:");
    lcd.print(LCDvibVal);
    timerVariable = millis();
  }
}

 

]]>
Dates Double Transducer: Vibration to Distance https://courses.ideate.cmu.edu/60-223/s2021/work/dates-double-transducer/ Mon, 08 Mar 2021 01:47:54 +0000 https://courses.ideate.cmu.edu/60-223/s2021/work/?p=12318

 

Images:

 

James’ final build

 

Amelia’s final build

 

Taped connection between vibration motor and accelerometer for best transfer of signal

 

Cover for the light sensing part of transducer to get rid of noise from environment

 

Slot restricting the motion of Popsicle stick to mostly linear movement to create a change in distance

 

 

 

 

 

Narrative:

A vibrator is attached to a sensor which senses the rate of vibration. Based on this vibration, a light is turned on underneath a box. How much the vibrator vibrates determines how bright the light gets. So if the vibrator vibrates a lot, the light gets really bright, and if the vibrator does not vibrate a lot, the light does not get as bright. The brightness of the light is captured by another sensor which senses how bright the light is. The sensor then tells the computer how much to turn a motor to move a stick. So if the light is really bright, the motor is told to move the stick very far, and if the light is not as bright, the motor is told to move the stick not as far. The states of all of these inputs and outputs (i.e. the level of change) is fed to a display that shows how much each step has changed.

 

Progress images:

Diagnosing the noise in the analog input pins with an oscilloscope

Vibration motor connected to two wires with male ends to make better and more maneuverable connection to bread board

One of the many ways we tried to sense vibration frequency. Here we are trying to measure the duty cycle of the PWM type input from the vibration motor.

 

Putting together the distance component for the first time to get the layout

Discussion:

Throughout the development process, the easiest part was definitely the planning stage. The stage where we brainstormed three different ideas and paid little attention towards the actual build. It was a time where we let our imaginations run wild and had little to debug since the projects weren’t fully implemented, only idealized. Once we finally got to the building and coding stage however, we found implementing past the planning phase is much harder. It involved having to build the circuit while making sure none of the wires had loose connections, building a connection between the vibration motor and Arduino which meant stripping two male- to-female wires as well as the vibration motor and securing them together with athletic tape (neither of us had electrical tape on standby), measuring the value of the accelerometer with a broken accelerometer (which we only later realized), soldering an LED and photoresistor, building a linkage system out of popsicle sticks, and figuring out the code to tie these pieces together. All of these steps came with their own frustrating challenges that allowed us to grown our knowledge of sensors and Arduino development

 

The most frustrating thing that we learned was that analog input pins on the Arduino can pick up a lot of noise from other parts of the board. In particular, adjacent analog input pins can read signals from each other almost as if they were connected. In our case, we thought the accelerometer was wired to the Arduino and we were reading a signal from it, but it turned out to not be connected to the Arduino at all. Despite this fact, we still read an analog input from that pin and when compared to the signal produced by the potentiometer, the signals matched exactly in how they changed with input into the potentiometer. Instead of reading the accelerometer data, we were actually reading ghost signals from the adjacent potentiometer input pin which was only solved by moving the accelerometer input pin to the opposite side of the analog input pin array.

 

We also learned the importance of data structures in signal processing, especially when performing arithmetic operations. While trying to write values to our stepper motor, we came into a problem where we couldn’t get our code to run for more than 1 loop. This was caused by the way in which we were storing the variables used to calculated step count. We chose to store the all our variables as type “int” by default which meant that it would round down to the nearest integer when it stored the step value. The some of the values we were setting as the used to calculate the number of steps, however, were on a scale of 0 to π which meant that they were frequently in between 0 and 1. Because these values were rounded down even if they were 0.9, this meant that we ended up with division by zero causing our program to break and only run once. Storing the variables used to calculate step number solved this problem.

 

Looking back now, there are several factors that would’ve changed the direction of the project completely. For instance, the first time we met to work on the project was the Sunday before the project was due because we thought it was plenty of time before the deadline. This was a mistake on our part and we should’ve been more proactive about meeting before Sunday (i.e. on Friday and Saturday). This would’ve given us more time to realize where we were going wrong and what we could’ve done to fix the problem. Another factor would’ve been a better sensor to detect the frequency of the vibration coming from the vibration motor. We noticed that the accelerometer was pretty noisy and we had trouble reading the sensor. Maybe these changes would have improved our project, or possibly caused new problems, but these are just a few we’ve chosen to reflect on. 

 

Functional Block Diagram and Schematic

Code Submission

/*
   60-223, Project 1
   Amelia Lopez (aelopez)
   James Kyle (jkyle1)
   Time spent: 8 hours

   Description:
   Takes in a vibration input, transforms that analog input value
   into an LED brightness, which is then transformed into a distance
   controlled by the stepper motor. Vibration input is read through
   an accelerometer and LED intensity value is read through a photoresistor.

   Challenges:
   The stepper motor isn't responding to the photoresistor's value as 
   we intended, so that half of the code is buggy. Since the vibration
   motor works on a pulse, this causes the light to blink fairly fast but
   it still dims/brightens as a result of the vibration motor speed. 

   Next time: 
   Definitely take more time to understand what went wrong between the 
   photoresistor value and the stepper motor desired output. I think 
   looking at the Arduino libraries is a good place to start with this 
   because maybe someone else had the same problem and published their
   solution for open source use that we can cite and tweak to the specs 
   of our project 


   Collaboration and Sources:
   1) For the accelerometer readings (line 163-167), used code from
    https://tinyurl.com/Accelerometerlink
   2) For LCD display, used code from http://www.arduino.cc/en/Tutorial/LiquidCrystalHelloWorld
   3) For stepper motor, used code from https://tinyurl.com/StepperMotorLink

   Inputs: Potentiometer (which varies vibration motor rate)
   In-between: LED
   Output: Stepper motor, LCD display

  Pin mapping:

   Arduino pin | type   | description
   ------------|--------|-------------
   A0            input     potentiometer
   A1            input     X-pin Accelerometer
   A2            input     Y-pin Accelerometer
   A3            input     Z-pin Accelerometer
   A4            input     photoresistor
   13            output    Stepper Motor Driver IN1
   12            output    Stepper Motor Driver IN2
   ~11           output    Vibration motor
   ~10           output    Stepper Motor Driver IN3
   ~9            output    Stepper Motor Driver IN4
   8             output    LCD RS
   7             output    LCD E
   ~6            output    LED
   ~5            output    LCD D4
   4             output    LCD D5
   ~3            output    LCD D6
   2             output    LCD D7

   (digital PWM~)

     LCD circuit:
   LCD RS pin to digital pin 8
   LCD Enable pin to digital pin 7
   LCD D4 pin to digital pin 5
   LCD D5 pin to digital pin 4
   LCD D6 pin to digital pin 3
   LCD D7 pin to digital pin 2
   LCD R/W pin to ground
   LCD VSS pin to ground
   LCD VCC pin to 5V
   10K resistor:
   ends to +5V and ground
   wiper to LCD VO pin (pin 3)
*/

#include <Stepper.h>
#include <LiquidCrystal.h>


//DECLARING ARDUINO PINS
const int POTENT = A0;
const int ACCE_X = A1;
const int ACCE_Y = A2;
const int ACCE_Z = A3;
const int PHOTORES = A4;
const int STEP_IN1 = 13;
const int STEP_IN2 = 12;
const int VIBRATION_MOTOR = 11;
const int STEP_IN3 = 10;
const int STEP_IN4 = 9;
const int LCD_RS = 8;
const int LCD_E = 7;
const int LED_PIN = 6;
const int LCD_D4 = 5;
const int LCD_D5 = 4;
const int LCD_D6 = 3;
const int LCD_D7 = 2;

//DECLARING INTS FOR ACCELOREMETER AND LED
int accel_xVal = 0;
int lightVal = 0;


//DECLARING MISC. CONSTANTS USEFUL TO STEPPER MOTOR
const int maxAnalogValue = 1023;
const int stepsPerRevolution = 64; //fits the specification of our motor
const int motorSpeed = 20;
float currentDistance = distOfString / 2; //PRECONDITION: OBJECT HAS TO BE HALFWAY
int targetDistance;
float steps;
bool stepMotor = false;

//DECLARING INTS FOR LCD WAITING TIMES
const int WAIT_TIME = 300;
unsigned long timeVariable = 0;

// initialize the library by associating any needed LCD interface pin
// with the Arduino pin number it is connected to
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7);


Stepper myStepper(stepsPerRevolution, STEP_IN1, STEP_IN2, STEP_IN3, STEP_IN4);

void setup() {

  //INPUT PINS
  pinMode(POTENT, INPUT);
  pinMode(VIBRATION_MOTOR, OUTPUT);
  pinMode(ACCE_X, INPUT);
  pinMode(ACCE_Y, INPUT);
  pinMode(ACCE_Z, INPUT);
  pinMode(PHOTORES, INPUT);

  //OUTPUT PINS
  pinMode(LED_PIN, OUTPUT);
  pinMode(VIBRATION_MOTOR, OUTPUT);

  //MOTOR functions
  myStepper.setSpeed(motorSpeed);

  // set up the LCD's number of columns and rows:
  lcd.begin(16, 2);

  //print constant letters on screen
  lcd.print("i:");
  lcd.setCursor(6, 0);
  lcd.print("m:");
  lcd.setCursor(8, 1);
  lcd.print("0");
  lcd.setCursor(12, 1);
  lcd.print("o:");
}

void loop() {

  //READING POTENTIOMETER VALUE
  //POTENTIOMETER VALUE DETERMINES VIBRATION MOTOR RATE
  int potentValue = analogRead(POTENT); // 0 <= potentValue <= 1023
  int vibrationStrength = map(potentValue, 0, 1023, 0, 153);  // 0 <= vibrationStrength <= 155
  analogWrite(VIBRATION_MOTOR, vibrationStrength); //using PWM
  int xVal = analogRead(ACCE_X);

  //ACCELEROMETER MEASURES VIBRATION MOTOR RATE (x-axis)
  //RATE MEASURED IS USED TO LIGHT UP AN LED A CERTAIN INTENSITY
  int oldX = accel_xVal;
  accel_xVal = analogRead(ACCE_X);
  int dif = abs(oldX - accel_xVal);
  int lightVal = map(dif, 0, 520, 0, 255);
  analogWrite(LED_PIN, lightVal);


  //PHOTORESISTOR TAKES IN LED INTENSITY VALUE
  //PHOTORESISTOR VALUE USED TO CHANGE STEPPER MOTOR
  int photoValue = analogRead(PHOTORES); // 0 <= potentValue <= 1023
  int lowbound = 700; //bright light
  int highbound = 990; //no light
  //int stepVal = map(photoValue, lowbound, highbound,

  targetDistance = map(photoValue, 850, 1000, 0, 60);

  //Convert photoresistor value into desired distance into rotations for stepper motor
  if (targetDistance != currentDistance) {
    steps = (targetDistance - currentDistance) * stepsPerRevolution / 360;
    currentDistance = targetDistance;
    stepMotor = true;
  }

  //Setting step stepper motor to desired distance
  if (stepMotor == true) {
    myStepper.step(steps);
    delay(500); //Wait 0.5s for motor to finish moving
    stepMotor = false;
  }

  //UPDATING VALUES ON LCD
  if (millis() - timeVariable > WAIT_TIME) {
    //updating input sensor value
    lcd.setCursor(2, 0);
    lcd.print(map(xVal, 0, 525, 0, 99));

    //updating middle step actuator
    lcd.setCursor(8, 0);
    lcd.print(map(lightVal, 0, 255, 0, 99));

    //updating middle step sensor value
    lcd.setCursor(8, 1);
    lcd.print(map(photoValue, lowbound, highbound, 0, 99));

    //updating output actuator value
    lcd.setCursor(14, 1);
    lcd.print(map(steps, 0, currentDistance, 0, 99));
    delay(200);

    timeVariable = millis();
  }

}

 

 

 

]]>