Project 1 – Intro to Physical Computing: Student Work Spring 2022 https://courses.ideate.cmu.edu/60-223/s2022/work Intro to Physical Computing: Student Work Mon, 11 Apr 2022 15:34:27 +0000 en-US hourly 1 https://wordpress.org/?v=5.8.9 Double Transducer: Rotational Position to Frequency of Tapping https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-rotational-position-to-frequency-of-tapping/ Wed, 16 Feb 2022 15:02:40 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15045
Tingsong's Double Transducer

Tingsong’s Double Transducer

Cassie’s double transducer

detail:shield

A shield to isolate the buzzer and sound detector from environmental noises

Scale to measure what angle the potentiometer is rotated to

Cute person attached to the servo

Narrative Description

When the potentiometer is turned it tells the buzzer to make sound and then the noise sensor listens to this sound and tells the servo to move its arm up and down once per second. When the potentiometer is turned more, the buzzer makes more noise and the servo moves its arm up and down twice per second. When the potentiometer is turned even more, the buzzer makes more noise and the servo moves its arm up and down three times per second. The Arduino lets the different pieces talk to each other and lets us change what they are saying to each other using coding.

Process Pictures

Testing buzzer’s frequency and volume range to ensure the sound detector sensitive enough to detect the volume change

Testing different materials and how well they muffle sound

Process of labeling and organizing board

Sound shield just after being constructed

Discussion

This project, while seemingly simple, was very difficult to make work. Conceptually both of us understood what it took to make this double transducer, but there were a lot of small issues that had to be overcome.

At the beginning of this project, Tingsong had suggested using a solenoid to create our tapping action, and looking back we wish that we had at least tried this method instead of going right to a servo. While a servo might be conceptually simpler, we ran into a lot of issues towards the end of our project with our servos. The largest was tackling the issue of not being able to use both the servo library and the buzzer library when coding. We ended up coding directly to the servo without using the library, but there were a lot of small complications that came from this. We also had two servos that acted completely differently despite using the same code.

There were also some issues that came with using the buzzer and the noise sensor. The noise sensor was having a lot of interference from ambient noise sources that threw off our results, especially with picking up noise from our servo instead of only the buzzer. We combated this with a small box to isolate the noise sensor and the buzzer and even experimented with different materials and what would block outside noise most effectively. We overcame this issue, but we spent a while thinking that a separate problem was due to the noise sensor detecting ambient sound, so this ended up confusing us and wasting time.

Despite the issues that we ran into, we both learned a lot from this project. Tingsong taught Cassie about some coding things that she was inexperienced with, and Cassie helped Tingsong solder for the first time. The wiring and mechanical side of this project was surprisingly easy and without issue other than the two servos that behaved differently. We worked very well as a team and stayed upbeat despite the setbacks.

 

Functional Block Diagram

Electrical Schematic

Code

/*Project Title: Double Transducer: Rotational Position to Frequency of Tapping
  Team Members: Casandra Rausch, Tingsong (Terrence) Ou
  Description: Using potentiometer to change the rotational angle, the angle range was limited to 0 to 90 degrees.
               Changing the rotational angle increases/decreases the Buzzer's volumn
               Sound detector detecting the Buzzer's volumn then map it to 0-1023 input read range
               Arduino mapping the value from sound detector to [500, 250, 166], which are delay times for different frequency
               Servo read delay and perform tapping, 500 delay causes 1 tapping per second, 250 causes 2, and 166 causes 3
             
  Pin mapping:
    Arduino pin | role   | description
    ------------|--------|-------------
    A0            input     Potentiometer
    A1            input     Sparkfun Sound Detector
    6             output    Servo for simulation tapping frequency
    9             defined   Buzzer (one connection)
    10            defined   Buzzer (another connection)
*/

#include <toneAC.h> //Library for buzzed
//Libries for LCD
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//Creating LCD
LiquidCrystal_I2C screen(0x27, 16, 2);

//Define pins
const int potenPIN = A0,
          sndDetPIN = A1,
          tapperPIN = 6;

//I tested several frequencies and found 1500 is
//responsive to the change of volume
const int defFreq = 1500,
          LCDLow = 0,
          LCDHigh = 99,
          volLow = 0,
          volHigh = 10,
          initTestPeriod = 2000; //Test time in void step() part

int detLow = 1023,  //initialize detected lowest value (as large as possible)
    detHigh = 0;  //initialize detected highest value (as small as possible)

int potenLCD = 0;
int buzzerLCD = 0;
int sndDetLCD = 0;

//creating a timer for LCD
unsigned long lastTime = 0;
unsigned long LCDInterval = 250; //refreahing LCD every 250 milliseconds



void setup() {
  //Initializing LCD
  screen.init();
  screen.home();
  screen.backlight();

  pinMode(potenPIN, INPUT);
  pinMode(sndDetPIN, INPUT);
  pinMode(tapperPIN, OUTPUT);

  Serial.begin(9600);


  /*Buzzer should first play sound in Lowest and Highest volumes
    such that sound detector can generate lower bound and higher bound
    of sound range*/
  int counter = 0;
  while (counter < initTestPeriod) {
    if (counter < initTestPeriod / 2) {
      toneAC(defFreq, volLow);
      delay(1);
      int sndRecVal = analogRead(sndDetPIN);
      if (sndRecVal < detLow) detLow = sndRecVal;
    } else {
      toneAC(defFreq, volHigh); //Offset
      delay(1);
      int sndRecVal = analogRead(sndDetPIN);
      if (sndRecVal > detHigh) detHigh = sndRecVal;
    }
    counter ++;
  }
  detHigh *= 0.75;
  toneAC(defFreq, volLow);
  delay(100);

}



void loop() {
  //reading value from potentiometer, convert to volumn
  int potenVal = analogRead(potenPIN);
  int buzzerVol = map(potenVal, 0, 1023, volLow, volHigh);
  toneAC(defFreq, buzzerVol);

  //detecting volumn
  int sndRecVal = analogRead(sndDetPIN);
  //converting read value to delaytime
    int delayTime = 1000;
    if (sndDetLCD < 30){
      delayTime = 500;
    } else if (sndDetLCD < 70){
      delayTime = 250;
    } else{
      delayTime = 166;
    }

  //Running servo
  runServo(delayTime);
  
  int servoLCD = 0;
  if (delayTime == 500) servoLCD = 0;
  else if (delayTime == 250) servoLCD = 50;
  else servoLCD = 99;

  //Displaying Values on LCD
  displayOnLCD(potenVal, buzzerVol, sndRecVal, servoLCD);
}


/*
  -----------------------HELPER FUNCTIONS--------------------
*/

void runServo(int delayTime){
  servoWrite(tapperPIN, 30);
  delay(delayTime);
  servoWrite(tapperPIN, 60);
  delay(delayTime);
}


//Maping values to 0-99 range then displaying on LCD
void displayOnLCD(int potenVal, int buzzerVol, int sndRecVal, int servoLCD) {
  if (millis() - lastTime >= LCDInterval) {
    //Map read values to LCD values (0 - 99);
    potenLCD = map(potenVal, 0, 1023, LCDLow, LCDHigh);
    buzzerLCD = map(buzzerVol, volLow, volHigh, LCDLow, LCDHigh);
    sndDetLCD = map(sndRecVal, detLow, detHigh, LCDLow, LCDHigh);
    sndDetLCD = constrain(sndDetLCD, LCDLow, LCDHigh);

    screen.clear();
    screen.home();
    screen.print("i:");
    screen.print(potenLCD);
    screen.setCursor(6, 0);
    screen.print("m:");
    screen.print(buzzerLCD);
    screen.setCursor(8, 1);
    screen.print(sndDetLCD);
    screen.setCursor(12, 1);
    screen.print("o:");
    screen.print(servoLCD);
    lastTime = millis();
  }
}



// Reference: Robert Zacharias (class instructor)//
// function to drive servo motor without need for servo library
// sample use: servoWrite(SERVOPIN, 50);
void servoWrite(int servoPin, byte servoDegree){
  pinMode (servoPin, OUTPUT); // in case it's not already set

  const int INTERPULSEDELAY = 20; // typical delay between servo pulses
 
  static unsigned long lastPulseTime;

  if (millis() - lastPulseTime > INTERPULSEDELAY){
   
    // turn degree input to pulse length output
    unsigned int pulseWait = map(servoDegree, 0, 180, 544, 2400);

    // transmit pulse of specified length
    digitalWrite(servoPin, HIGH);
    delayMicroseconds(pulseWait);
    digitalWrite(servoPin, LOW);

    // reset timer
    lastPulseTime = millis();
  }
}

 

]]>
Double Transducer: Y-Axis Magnetic Field to Wheel of Color https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-y-axis-magnetic-field-to-wheel-of-color/ Wed, 16 Feb 2022 15:00:32 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15006

Project I: Y-Axis Magnetic Field to Wheel of Color

Images of Final Project

  1. Overall photo for proportion and scale

Sumayya Syeda’s overall picture

Tiana Porwanto’s overall picture

2. Details of part to highlight

This is the 3-axis compass/magnetometer. It is attached to a a breadboard which is elevated using paddlepop sticks. Adjusting to the group who acts as our input, we are only reading magnetic field in the Y-axis.

This is Tiana’s LED and photoresistor. Tiana’s photoresistor is poorly soldered to the protoboard, which leads to problems such as the code not running through the circuit. The green LED is directly touching the photoresistor to make sure the photoresistor gets the light.

This is our wheel of color with a servomotor as its pointer. The servomotor is supposed to move its handle and choose a color based on the light received by the photoresistor.

This is Sumayya’s LED and photoresistor attached to the protoboard. Her pieces are nicely soldered, creating a great connection through the circuit. Her photoresistor is not touching the LED, but it does face the LED directly.

3. Brief movie in mp4 format

Simple Narrative Description

This double transducer measures a magnet’s strength. Then it converts that measurement to a brightness level for an LED. The LED is brighter when there is more strength, and dimmer when there is less. Then a photoresistor measures how bright the LED is and sends that information to the servo. The servo reads how bright the LED is from the photoresistor and moves its arm accordingly to point to a color on the color wheel. 

Four Progress Images

This is Sumayya’s rough wiring before soldering or gluing any components. It is the rough structure Sumayya had before finalizing the placements of all my sensors.

Sumayya realized she had not added a photoresistor to her circuit. This is the image before she redid her soldering of the LED and photoresistor components.

This is Tiana’s circuit before she soldered or glued any components to the cardboard. At this point, she was still testing whether the code would work on her circuit.

Reading the grading rubric, Tiana realized she needed to solder her middle step (LED -> photoresistor). Professor recommended she use a protoboard and solder both LED and photoresistor to it. This is a picture before the soldering process.

Discussion

While planning for the project, our team decided on a very simple concept: a servomotor pointing a color on a color wheel. However, we later realized that this project was more complicated than planned. It took us some time to understand how the components should be wired and placed on the board while maintaining its aesthetics. We also learned that soldering was hard, since we needed to make sure we had the right circuit before permanently attaching it. This whole process helped us understand the importance of planning and double checking schematics before diving into the hands on work.

While dealing with the software of the project, we realized that we could not code according to theory. For example, mapping did not work great when we inserted min and max value as the input. We went through a lot of trials and errors to understand which interval best suited the mapping. We also realized that hardware issues can happen during the software process. Some pieces may be knocked over and lose their connection, leading us to think it was our software that had problems. By the end of the project, we were still proud of our accomplishments and learned a lot in a short period of time. 

Functional Block Diagram and Schematic

Code Submission

/**
 * @Title: Magnetometer to Color Double Transducer
 * @author: Sumayya Syeda
 * @co-author: Tiana Porwanto
 * 
 * This program measures the magnetic field measured by the QMC5883LCompass to turn a servo motor a certain angle 
 * and point at a certain color
 * The magnetic measurement sets the brightness of an LED. This brightness is measured by a photoresistor. The reading 
 * of the photoresistor sets the angle of the servo motor. 
 */
#include <QMC5883LCompass.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>


QMC5883LCompass Magnet;
LiquidCrystal_I2C lcd(0x27, 20, 4);
Servo servo;

int LED_PIN = 5;
int PHOTORESISTOR_PIN = 3;
int SERVO_PIN = 6;


void setup() {
  pinMode (LED_PIN, OUTPUT);
  pinMode (PHOTORESISTOR_PIN, INPUT);
  
  Magnet.init();
  lcd.init();

  servo.attach(SERVO_PIN);

  lcd.backlight();
  lcd.home();

  lcd.setCursor(16,  .0);

  Serial.begin(9600);
  lcd.println("Program Started!");
}


void loop() {
  // put your main code here, to run repeatedly:

  int avg_m_field
  int brightness;
  int lightVal;
  int servoVal;
  lcd.setCursor(0, 0);


  Magnet.read();
  delay(100);

  //read magnetic field 
  int y = Magnet.getY();
  avg_m_field = abs(y);
  int lcd_mag = map(avg_m_field, 1300, 10000, 0, 99);
  lcd.print("i:");
  lcd.print(abs(lcd_mag));


  //map magnetic field to led brightness
  brightness = map(avg_m_field, 1200, 10000, 0, 255);
  int lcd_brightness = map(brightness, 0, 255, 0, 99);
  lcd.setCursor(9, 0);
  lcd.print("m1:");
  lcd.print(lcd_brightness);
  analogWrite(LED_PIN, brightness);

  //photoresistor reads led brightness
  lightVal = analogRead(PHOTORESISTOR_PIN);
  int lcd_lightVal = map(lightVal, 60, 100, 0, 99);
  lcd.setCursor(0, 1);
  lcd.print("m2:");
  lcd.print(lcd_lightVal);

  //servo maps photoresistor values to servo values
  servoVal = map(lightVal, 60, 100, 10, 170);
  lcd.setCursor(8, 1);
  int lcd_servo = map(servoVal, 10, 170, 0, 99);
  lcd.print("o:");
  lcd.print(lcd_servo);
  servo.write(servoVal);

  delay(500);
  lcd.clear();



}

 

]]>
Double Transducer: Color to Rotational Position https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-color-to-rotational-position/ Wed, 16 Feb 2022 15:00:09 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15077 Photos that show scale:

Zoey’s scale compared to a quarter dollar

Jerry ‘s scale for a ruler

Videos:

Progress images:

A closer view to the speaker

The color sensor is not fixed so we can move it to whatever color we want to detect

Wiring process

Wiring before the RGB sensor was put in

Here is the soldered RGB sensor! This is the first time soldering for both of us, and it was very fun!

Simple Narrative Description

This double transducer is a machine that can read a color, map the color to a sound, and then map the volume of the sound to a rotation angle.

 

Coding process

Discussion

Something that was quite easy was coming up with the idea. Transducers seem to be quite common in the world around us (even though most transducers are single transducers, or so it seems); we just pulled from transducers that we have seen from the past, and the commonality of volume as a signal mechanism was very helpful in brainstorming ideas. Something that was hard was the process of coding the project. We ran into some issues with the libraries that we were using due to our physical components and the requirements of each component. We had to reach out to the Professor in order to resolve this problem. A tweak that would have changed the direction of this entirely would have been the emphasis on code in the beginning. Our group focused on building first rather than testing little parts, which resulted in us having to debug a massive amount of problems that were all inter-related. In terms of our creative growth, we were able to find useful applications for things that we found in real life. In terms of our technical growth, we were both able to become more familiar with the process of turning an idea into something physical! Next time, we would like to grow more in the efficiency process. We skipped a lot of steps, as well as performed many important steps out of order. As a result, we were less efficient than we could have been. Overall, however, the process was quite fun and interactive. We engaged in several troubleshooting sessions – first it was establishing the pieces that we needed, as well as the wiring for them. We had to go onto the websites of each piece to understand how the wiring and the code worked. Secondly, as mentioned previously, we had to focus on coding. Since C is pretty nit–picky sometimes, we had to make sure that everything that we were coding was intentional and not full of things that were unnecessary. In the end, our code was quite shorter than the beginning brainstorming session. 

Functional Block Diagram

Schematic Diagram

Double Transducer: Color to Rotational Position

// this includes all of the necessary libraries and sub-portions
#include <Wire.h>
#include "Adafruit_TCS34725.h"
#include <toneAC.h>
#include <LiquidCrystal_I2C.h>

// the following lines introduce global variables that have a baseline value of 0; this will be adjusted in local code later. 
Adafruit_TCS34725 tcs = Adafruit_TCS34725(TCS34725_INTEGRATIONTIME_50MS, TCS34725_GAIN_4X);
unsigned long lastTime = 0;
unsigned long lastQuarterTime = 0;
float red, green, blue=0;
float hue=0;
LiquidCrystal_I2C screen(0x27, 16, 2);
const int MOTORPIN = 3;
int volume = 0;
int degree = 0;

#define ENVELOPE A0
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))

//A function converting RGB value to Hue 
float getHue(float red, float green, float blue) {

  float min = MIN(MIN(red, green), blue);
  float max = MAX(MAX(red, green), blue);

  if (min == max) {
    return 0;
  }
  float h = 0;
  if (max == red) {
    h = (green - blue) / (max - min);

  } else if (max == green) {
    h = 2 + (blue - red) / (max - min);

  } else {
    h = 4 + (red - green) / (max - min);
  }

  h = h * 60;
  if (h < 0) h = h + 360;

  return h;
}
// Code for servo motor without using library 
void servoWrite(byte servoPin, byte servoDegree) {
  pinMode (servoPin, OUTPUT); // in case it's not already set

  const int INTERPULSEDELAY = 20; // typical delay between servo pulses

  static unsigned long lastPulseTime;

  if (millis() - lastPulseTime > INTERPULSEDELAY) {

    // turn degree input to pulse length output
    unsigned int pulseWait = map(servoDegree, 0, 180, 544, 2400);

    // transmit pulse of specified length
    digitalWrite(servoPin, HIGH);
    delayMicroseconds(pulseWait);
    digitalWrite(servoPin, LOW);

    // reset timer
    lastPulseTime = millis();
  }
}



void setup() {
  // set up the LCD's number of columns and rows:
  screen.init();

  // turn on the backlight to start
  screen.backlight();

  // set cursor to home position, i.e. the upper left corner
  screen.home();
  
  pinMode(MOTORPIN, OUTPUT);
  pinMode(ENVELOPE, INPUT);
  Serial.begin(9600);
}

void loop() {
 
// get hue value of the color
    tcs.getRGB(&red, &green, &blue);
    hue = getHue(red, green, blue);
    int color = map(hue, 0, 360, 0, 10);
// make speaker to make a sound
    toneAC(440, color, 0, true);
    volume = analogRead(ENVELOPE);
// mapping the volume signal into the degree signal
    degree = map(volume, 0, 10, 0, 90);
    servoWrite(MOTORPIN, degree);

// to display the necessary indicators onto the led
  if (millis() - lastQuarterTime >= 25) {
    screen.setCursor(0, 0);
    screen.print((String)"i:" + (int)hue + "  m:" + volume);
    screen.setCursor(1, 9);
    screen.print((String)"     " + (int)hue + "  o:" + degree);
    lastTime = millis();

  }

}

 

]]>
Double Transducer: From Height to Light https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-from-height-to-light/ Wed, 16 Feb 2022 11:56:48 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15176

Overall photo for proportion and scale

Overall photo for proportion and scale (alternate angle)

Overall photo of version_juan for proportion and scale, with a pen as reference for size

Close-ups

Here is a closeup of the motor setup. Here you can see how both the motor and the IR sensor are elevated and the propellor is attached to the tip of the motor, allowing it to spin over the top of the sensor.

 

Here is our first IR sensor which is used to get the height of the index card off of the table. It was necessary to hold down the wires to the side to ensure minimal interference with the sensor’s readings.

 

 

 

Narrative description

For our double transducer, we were tasked with converting the height of an index card, ranging from 1 to 4 inches, to the blinking rate of an LED. When considering how to gauge the height of the index card, we started looking at the different proximity sensors that would be useful in this situation. After consulting with both Zach and Eric, we determined that the best one to use would be the IR sensor, which emits a light and then receives it after it bounces off a nearby surface. With this, one challenge that we faced was adjusting the potentiometer attached for ambient light, which changed constantly even in the classroom. For our second component, we decided that an interesting conversion to explore would be the rotational speed of a motor. We decided to use a DC motor, and then another IR sensor to detect the number of rotations that occurred within a given time period. This was gauged by marking the number of times an attached wooden piece went over the IR sensor per second. Finally, we converted this to the rate at which an LED blinked. At the request of the group after us, we maintained that every time the LED turned on, it would only stay on for 25 milliseconds. Because of this, we were actually manipulating the time between blinks as opposed to the time the LED was on. This range was constructed to stay between about 1-20 blinks per second.

Progress images

Here is an image of what we had as we were initially figuring out the IR sensor and how to hook it up to the Arduino.

Here we have our proximity sensor, LCD display, and LED hooked up to the arduino, making sure that each part is able to run properly without the motor component.

This is the setup we used to trigger our second IR sensor, which detected the change in rotation of the motor. The wooden piece attached to the top was essential to allowing the IR sensor to count the rotations for rps.

Here is the initial setup for our motor, where we propped it up on popsicle sticks to make it so the propeller overhead was at a good height for the reader.

Discussion 

The path to creating our double transducer was by no means a simple and smooth one. Unsurprisingly, there were a few hurdles in creating our double transducer which both challenged and strengthened our problem-solving and researching abilities. Of the 10 components used in our project, nearly half were components we were already experienced in from previously assigned online course modules. We knew how to work with the Arduino UNO controller, potentiometers (of which we needed 2), as well as our final output: an LED light. Ultimately, that meant that we needed to familiarize ourselves with 5 new components: an LCD screen, an IR sensor (of which we’d use two), an H-Bridge motor driver, a DC barrel jack adapter, and a DC motor. For the sake of time, we decided to assign ourselves each half of the total new components to work on. Shreeja was responsible for the two IR sensors and LCD screen, and Juan was responsible for the H-Bridge motor driver, DC barrel jack adapter, and the DC motor itself.

Setting up and utilizing the parts we were already familiar with (the LED, Arduino, and potentiometers) was relatively trivial. It was only until we began experimenting with the new components that the difficulty of the project increased. Each new component took some time to get used to, and although some required more time than others, there were a few components that stuck out more in terms of giving us the most difficulty. The two components that come to mind are the IR sensors and the H-Bridge motor driver. The H-Bridge motor driver was a fairly non-trivial component since it essentially served as a mini-arduino for the DC motor in the sense that it read input and gave output that was directly tied to the DC motor. The H-Bridge required some soldering in addition to research in order to ensure that it would work with the DC barrel jack adapter and DC motor. The IR sensors, on the other hand, were deceptively difficult; we were technically able to get them functioning early on, but we were constantly having difficulty adjusting the sensor’s sensitivity to our liking. Factors such as ambient lighting (which the potentiometers helped us control), possibly faulty sensors, and confusion with the software aspect of IR sensor input and output led to a majority of our time being spent on fine-tuning the IR sensors to work like we wanted them to. They were, after all, crucial to our transducer as not only was it how our final project received input, it was also the means in which we were able to measure the speed of our motor. Given their importance, the long period of time we spent trying to perfect our IR sensor settings was in retrospect justified.

I can’t help but wonder what would’ve happened if we had decided to use an ultrasonic ranger instead of our IR sensors to detect distance. We had initially chosen to use IR sensors because we felt that it was more straightforward and natural, but in theory we could have also used an ultrasonic sensor to at the very least detect the height of an index card, and maybe even to detect the rotations our DC motor is spitting out. It’s possible that such a substitution could have dramatically reduced the time we spent on the project since we wouldn’t have to constantly adjust our IR sensors, but it’s also probable that we would have run into some other roadblock instead.

Overall, the project itself was enjoyable and more importantly quite educational. We were able to learn how to use certain components like LCD screens, DC motors, and IR sensors, decently well enough to the point where we could use them in future projects with much more comfort. If this project is any indication on how future projects will be for the course, then we’re very much looking forward to progressing through the course and learning even more components and arduino-related material.

Functional block diagram and schematic

Functional block diagram

Schematic

//Double Transducer: from height to light
//
//By Team 7
//
// For the code, in addition to establishing each of the pins used
// as inputs or outputs in the arguino, we also did most of our mapping
// conversions with the code. Also, we used the code to time each of the 
// parameters and display the values on our LCD.
//
//
// Each of the pins are commented below to explain their function:

// shortcut to refer to the IR sensor pin
const int PROXPIN = A0;
//shortcut to refer to LED pin 
const int LEDPIN = 4;
//shortcut to refer to motor pin
const int MOTORPIN = 10;
//shortcut to refer to the IR that reads the motor val
const int PROXMOTOR = A1;

int motorProxPrevious = 0;
int rotations = 0;
int rps = 0;
int lastCycle = 0;
unsigned long timer = 0;
const int INTERVAL = 1000; //number of milliseconds per second for reading

unsigned long lastTime = millis();
unsigned long LEDwait = millis();
unsigned long LEDon = millis();
  
// imports the LCD programming library
// and initializes the screen with it's dimensions
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C screen(0x27, 16, 2);

byte frowny[] = {
  B00000,
  B11011,
  B11011,
  B00000,
  B00000,
  B01110,
  B10001,
  B00000
}; 

void setup() {
  //initializes the input IR sensor to get the proximity of the index card
  pinMode(PROXPIN, INPUT);
  Serial.begin(9600);

  pinMode(MOTORPIN, OUTPUT);
  Serial.begin(9600);
  
  pinMode(LEDPIN, OUTPUT);
  digitalWrite(LEDPIN, LOW);

  pinMode(PROXMOTOR, INPUT);
  Serial.begin(9600);

  //initializes the LCD screen and turns on backlight, sets cursor home
  screen.init();
  screen.backlight();
  screen.home();
}

void loop() {
  int readVal;
  readVal = analogRead(PROXPIN);
  
  //to find difference in distance between them
  int motorProx;
  motorProx = analogRead(PROXMOTOR);
  Serial.println(motorProx);

  //translates the index card height to the speed of the motor
  int motorSpeed = map(readVal, 10, 90, 50, 70);
  analogWrite(MOTORPIN, motorSpeed);
    
  //measure motor fan rotational speed
  int difference = 0;
  //change in diff
  if (motorProx != 0){
    difference = motorProx - motorProxPrevious; 
  }
  
  //when piece is detected, increment rotations (one complete rotation)
  if (difference >=2){
      rotations++;
  }
  
  motorProxPrevious = motorProx;
   

  if (millis() >= timer){
    rps = rotations;
    rotations = 0;
    timer = millis() + INTERVAL;
  }

  int blinkGap = map(rps, 0, 10, 25, 925);

  digitalWrite(LEDPIN, LOW);
  delay(blinkGap);
  digitalWrite(LEDPIN, HIGH);
  delay(25);
  
  //screen display code
  screen.print("i:");
  screen.print(readVal); //shows the IR value
  screen.print("  ");
  screen.print("m: ");
  screen.print(motorSpeed);
  screen.setCursor(0, 1);
  screen.print("       ");
  screen.print(rps);
  screen.print("  o: ");
  screen.print(blinkGap);
  screen.home();
}

Project done by Shreeja and Juan

]]>
Double Transducer: Light Brightness to Rotational Speed https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-light-brightness-to-rotational-speed/ Wed, 16 Feb 2022 05:48:39 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15138 Images and Videos

Tristan’s Final

Nicole’s Final

Close up Image of Infrared Proximity Sensor

Close up Image of DC Motor and Motor Driver

Description

This Double Transducer takes in the brightness of light as an input and converts that into a rotational position and then finally converts that rotational position into a rotational speed. A photoresistor detects the brightness of light hitting it which is then converted to a rotational position between 0 and 180 degrees. The servo motor rotates a popsicle stick to this position and an IR sensor detects how far away the popsicle stick is. The IR sensor sends this information back to the Arduino and the Arduino maps this value to an amount of voltage. This voltage is then sent to a DC motor, the transducer’s final output. Based on the voltage supplied the rotational speed of the DC motor varies between 20 and 60 rpm. 

Progress Pictures

Figuring out the distance between the IR sensor and popsicle stick.

Having trouble with pulley system.

We tested many different layouts for the components on the board to determine which was the most sensible.

Testing the photoresistor range of inputs to determine the range to use in the map function

 

Discussion

Our final project was a successful double transducer but there were many unforeseen challenges and modifications we had to make to our original idea. The preliminary middle step was to have a servo motor rotate a pulley, moving an index card back and forth. In theory this seemed like a simple mechanical system to construct, however all of our available options for a rope did not work. There was too much friction between the rope and the 3-D printed part for the pulley to successfully rotate the rope. Unfortunately, we had to scrap the pulley system idea and come up with another way for the servo motor to move the popsicle stick to various positions. At this point we had already wired the IR sensor and written the code for it so we didn’t want to rethink the entire middle step. We decided to instead attach the popsicle stick directly to the servo motor and then position the IR sensor to detect how far away it is. This ended up being much easier to execute than our original idea and was also a more reliable system. Being forced to deviate from our original idea was unsettling at first but worked out for the best in the end. Having to pivot taught us that you will often have to rethink and rework your original plan and to be prepared for failure when you attempt to execute your ideas. The importance of having an adaptable mindset is just as important as the planning process when working on physical computing projects. 

Another misstep we faced was due to soldering. I did not truly understand the importance of precision when soldering until an overlooked error led to me short circuiting my Arduino. At first I did not understand why attaching the board I had soldered to my Arduino resulted in my Arduino immediately shutting down. My first instinct was that it was a faulty wire, but after testing all my wires and all of them working I knew it had to be from the way I soldered. When I looked at my soldering more closely I realized that there was melted metal connecting ground and power which was causing the entire system to fail. Surely enough when I fixed this error the board and the Arduino started working again. This misstep taught me it is important to not rush soldering and if a system is failing to check if it’s from a soldering error.  

Writing the code was straightforward and didn’t present many challenges. However, determining the ranges to use in the map function was more difficult than anticipated and required more trial and error than expected. A lot of times our transducer not working was attributed to inaccurate ranges. At first we struggled to identify the optimal range for the transducer to work. As we continued to aimlessly plug and chug different numbers we realized that by interacting with the device we would get a better understanding of what values are needed for the map function. Another challenge was that the values of the inputs in the system, the photoresistor and IR sensor were often changing drastically. We learned that the IR sensor’s values were changing due to the potentiometer moving so we made sure it was more secured in one position. The photoresitor’s values were changing due to a change of environment, however as long as the transducer was in the classroom the same range of values worked. Adjusting the ranges taught us how to be more systematic about how we test values for inputs and outputs for the future. 

Prior to this project, we both had limited experience with wiring inputs and outputs to the Arduino. From working on the double transducer we learned how to wire and program a photoresistor, IR sensor, LCD display, servo motor, and DC motor. This experience made both of us more comfortable with the challenges that come along with using these various inputs and outputs. For this project particularly, the DC motor presented the most frustration. Unlike the servo motor that can be wired directly to the breadboard, the DC motor needed an additional power source and assistance from a motor driver in order to work. We spent a while toying around with the DC motor before learning that its failure was due to the absence of a motor driver. This set back taught us to not expect similar inputs and outputs to work the same. The DC motor and servo motor may function similarly but their wiring and software are different. This project was a valuable introduction to physical computing and allowed both of us to become familiar with using several new inputs and outputs.

Functional Block Diagram

Schematic

Code

/*
   Double Transducer: Light Brightness -> Rotational Speed

   Team Members: Nicole Monaco, Tristan Hineman

   Description:
    The program is disigned to recieve input from the photoresistor and covert
    the value to an angle for the servo motor with a popsicle stick to move to
    where then an infrared proximity sensor will detect the distance of the popsicle stick and convert that to
    a rotational speed between 20 and 60rpm for the DC motor to output.

   Pin Mapping Table:

   Arduino pin  |  description
   -------------|-------------
   A0             Photoresistor

   A2             Servo Motor
   A1             Infrared Proximity Sensor

   5              Driver chip for DC Motor

   SDA            SDA pin, LCD Display
   SCL            SCL pin, LCD Display


   References:
   https://courses.ideate.cmu.edu/60-223/s2022/tutorials/reading-a-photoresistor
   https://courses.ideate.cmu.edu/60-223/s2022/tutorials/servo
   https://courses.ideate.cmu.edu/60-223/s2022/tutorials/IR-proximity-sensor
   https://courses.ideate.cmu.edu/60-223/s2022/tutorials/I2C-lcd
*/

//Libraries
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo servoMotor;

//Pin for photoresistor
const int photoPIN = A0;

//Pin for infrared proximity sensor
const int irPIN = A1;

//Pin for servo motor
const int servoPIN = A2;

//Pin for dc motor driver chip
const int dcPIN = 5;

//Variables for LCD display
unsigned long lastServoTime = 0;
unsigned long lastIRTime = 0;
unsigned long lastDCTime = 0;
unsigned long lastLCDTime = 0;

//Setup to LCD display
LiquidCrystal_I2C screen(0x27, 16, 2); // create LCD display object
void updateScreen(int photoVal, int servoPos, int IRreadVal, int DCSpeed) {
  screen.setCursor(3, 0);
  screen.print(map(photoVal, 80, 300, 0, 90)); 
  screen.setCursor(11, 0);
  screen.print(servoPos);
  screen.setCursor(3, 1);
  screen.print(map(IRreadVal, 45, 960, 0, 90)); 
  screen.print(map(DCSpeed, 50, 80, 36, 60)); 
}

void setup() {

  //Pin setup
  pinMode(photoPIN, INPUT);
  pinMode(irPIN, INPUT);
  pinMode(dcPIN, OUTPUT);
  servoMotor.attach(servoPIN);

  Serial.begin(9600);

  //LCD screen initialization
  screen.init();
  screen.backlight();
  screen.home();
  screen.print("i:");
  screen.setCursor(7, 0);
  screen.print("m1:");
  screen.setCursor(0, 1);
  screen.print("m2:");
  screen.setCursor(7, 1);
  screen.print("o:");
}

void loop() {

  screen.setCursor(5, 0);
  screen.print (" ");

  //Variable to store photoresistor value
  int photoVal = analogRead(photoPIN);
  Serial.print(photoVal);
  Serial.print("     ");

  //Variable to set servo position
  int servoPos;

  //Adjust the angle of the servo motor according to the registered light brightness from the photoresistor
  if (millis() - lastServoTime >= 500) {
    servoPos = map(photoVal, 80, 300, 0, 45);
    servoMotor.write(servoPos);
    lastServoTime = millis();
  }

  //Variable to store infrared proximity sensor value
  int IRreadVal;

  //Read and print infrared proximity sensor value
  IRreadVal = analogRead(irPIN);
  if (millis() - lastIRTime >= 50) {
    lastIRTime = millis();
  }
  Serial.println(IRreadVal);

  //Variable to set the speed of the DC motor
  int DCSpeed;

  //Adjust the speed of the dc motor accoding to the distance from the infrared proximity sensor
  if (millis() - lastDCTime >= 500) {
    DCSpeed = map(IRreadVal, 45, 960, 50, 80);
    analogWrite(dcPIN, DCSpeed);
    lastDCTime = millis();
  }

  //display on the LCD
  if (millis() - lastLCDTime >= 500) {
    updateScreen(photoVal, servoPos, IRreadVal, DCSpeed);
    lastLCDTime = millis();
  }
}

 

]]>
Double Transducer: Flight of the Bumblebeep https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-flight-of-the-bumblebeep/ Wed, 16 Feb 2022 05:25:24 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15009 60223 Project 1 – David Wu and Jiaying (Vina) Wei

Double Transducer: Flight of the Bumblebeep

This double transducer takes in a rotational input of 10-80 degrees, and outputs a pitch from 200-2000 Hz. It goes through a middle step of LED brightness, and detects this brightness with a photoresistor.

Final Project Photos

David’s Final Version. It contains no restrictions on the input range.

Vina’s Final Version. It is more optimized for a certain 70 degree range.

Detailed Component Images

Input Area. A popsicle stick wedged in a potentiometer served to measure a change in angle from the input.

Middle Step Area. A LED and a photoresistor are soldered together, and bent to face each other for maximum light detection.

Output Area. A piezo electric buzzer emits a variable pitch depending on the output signal.

Video Demonstrations

David’s Version:

Vina’s Version:

Simple Narrative Description

The device takes in something turning and puts out a noise from a speaker. A popsicle stick can be turned around. As it turns towards the right, a blue light glows brighter, which is detected and converted into a higher pitch. As it turns left, the blue light becomes dimmer, and a lower pitch is played.

Progress Images

David Progress Image 1. This was the discussion and problem-solving behind the concern of inverted input ranges when linking to other devices.

David Progress Image 2. Everything is wired up, and placement is being played around with.

Vina Progress Image 1. This was initial circuit design to test if the input worked- the LED has not been bent to face the photoresistor yet.

Vina Progress Image 2. Everything, from input to output, is placed on a single breadboard to test if the code would work.

Discussion and Reflection

In general, the project was relatively straightforward. The transmission from the input to the output turned out rather smooth, and most connections were through the Arduino (for example, from initial input to middle input, and from middle output to final output), making potential mechanical errors to be nearly none. As such, most struggles ended up during the programming stage, particularly the mapping of sensory input/outputs.

Mapping sensory inputs/outputs was crucial for trying to maintain a good LCD display from 0-99, but also as accurate a transmission of signals as well. However, it proved to be challenging because of inconsistency. For some strange reasons, the photoresistor used to detect the LED brightness seemed to almost recalibrate itself when the device was in use- causing values to go haywire and the mapping to shoot past 0 or 99. It was also affected by environmental light, a factor that was not particularly noticed until the device was used outside of the worktable it was created at (the calibration so finely made was then incorrect). In retrospect, it would have been smart to build a black box for the middle step, which would help to standardize calibration (and perhaps eased the inconsistencies). While this had been an initial thought, it had been disregarded, since bending the photoresistor and LED to face each other seemed to be enough for the signal to transmit. While not entirely wrong in broad considerations, it was incorrect when considering finer details. In the end, to resolve this issue, we used some conditional statements to bound the value to 0-99, and using a lot of calibrating, the device was nearly perfectly mapped, with the display showing from about 2-99.

Another trouble was during consideration of how the device would eventually be linked to the other devices. While technically outside the required scope of the project, it was still a consideration, mostly for courtesy and being a team player. The trouble was that while our designated input was from 10 to 80 degrees, this range of 70 degrees would differ due to a mirroring issue. Our input would be in a counterclockwise direction, like a usual Cartesian coordinate system, but the previous team’s output, should they approach the same intuitive counterclockwise direction, would be mirrored- they would be our input’s 170 to 100 degrees. As such, should we strictly map our input to how we viewed it, it would be completely useless when attached to the previous team. Thus, we created two devices- one of which was more finely tuned to 10 to 80 degrees, which would have the most accurate standards for the individual project grading; one of which was mapped to the entire range, so that the previous team’s input could be taken in, regardless of which direction and which range they ended up using. This allowed us to tackle both challenges at the same time, at the expense of writing two slightly different programs. Mechanically, they were still identical.

Other than these struggles, the project proved to be an exciting test and learning opportunity for the sensors and materials available to us. We discovered many things amidst our adventures: Arduino functions, photoresistors, different blades to whittle popsicle sticks- even the fact that a certain piezo buzzer sounded like “Flight of the Bumblebee” was an unexpected, but fun way to obtain the name of our project. All in all, while the process did not go as smoothly as it could have, the end result worked splendidly, and we are very proud of that.

Functional Block Diagram and Schematic

 

Project Code (David’s Version)

This code is optimized to have the input be the entirety of the potentiometer range.

/* Project Title: Flight of the Bumblebeep
 * Creators: David Wu and Jiaying (Vina) Wei
 * 
 * This code takes in the input of a potentiometer turning, and maps 
 * it to output the brightness of an LED. It then reads in the value 
 * of a photoresistor, which should be reading the aforementioned LED, 
 * and maps it to output the pitch of a piezo buzzer. The four steps
 * are all mapped to 0-99 and displayed on a LCD display.
 * 
 * Pin Mapping:
 * Potentiometer : A0
 * Photoresistor : A1
 * LED           : 5
 * Piezo Buzzer  : 6
 * LCD SDA/SCL   : SDA/SCL       : 
 * 
 * Credit to CMU 60-223 Professor Zacharias's code for the LCD Display
 */

#include <Wire.h>
#include <LiquidCrystal_I2C.h>


const int POTPIN = A0; // potentiometer intput
const int PHOTOPIN = A1;// photoresistor input
const int LEDPIN = 5; // LED output
const int SPEAKPIN = 6; // speaker/buzzer output
unsigned long lastDispTime = 0; // to stop LCD flickering

LiquidCrystal_I2C screen(0x27, 16, 2);

void setup() {
  pinMode(POTPIN,INPUT);
  pinMode(LEDPIN,OUTPUT);
  pinMode(PHOTOPIN,INPUT);
  pinMode(SPEAKPIN, OUTPUT);
  Serial.begin(9600);

  
  // display code
  // initialize the screen and backlight
  screen.init();
  screen.backlight();

  // initial variable display
  screen.home();
  screen.print("i:"); // potentiometer
  screen.setCursor(6, 0);
  screen.print("m:"); // LED brightness
  screen.setCursor(8, 1);
  screen.print(""); // displayed brightness
  screen.setCursor(12, 1);
  screen.print("o:"); // pitch
}

void loop() {
  // read potentiometer with popsicle stick
  int potVal = analogRead(POTPIN);
  
  // convert potentiometer to LED brightness 
  int LEDBright = map(potVal,0,1000,0,250);
  analogWrite(LEDPIN,LEDBright);

  // detect the brightness using photoresistor
  int detectBright = analogRead(PHOTOPIN);

  // convert detected brightness to pitch
  int pitch = map(detectBright,43,270,200,2000);
  tone(SPEAKPIN, pitch);

  // display code
  // change display 8 times a second
  if (millis() - lastDispTime >= 125) {
    // adjusting values for display purposes
    int potValAdj = map(potVal, 100, 1022, 0, 99);
    if (potValAdj < 0) potValAdj = 0;
    if (potValAdj > 99) potValAdj = 99;
    
    int LEDBrightAdj = map(LEDBright, 10, 255, 0, 99);
    if (LEDBrightAdj < 0) LEDBrightAdj = 0;
    if (LEDBrightAdj > 99) LEDBrightAdj = 99;
    
    int detectBrightAdj = map(detectBright, 230, 70, 0, 99);
    if (detectBrightAdj < 0) detectBrightAdj = 0;
    if (detectBrightAdj > 99) detectBrightAdj = 99;
    
    int pitchAdj = map(pitch, 1700, 500, 0, 99);
    if (pitchAdj < 0) pitchAdj = 0;
    if (pitchAdj > 99) pitchAdj = 99;
    
    // display formatting
    screen.home();
    screen.print("i:"); // potentiometer
    screen.print(potValAdj);
    screen.setCursor(6, 0);
    screen.print("m:"); // LED brightness
    screen.print(LEDBrightAdj);
    screen.setCursor(8, 1);
    screen.print(detectBrightAdj); // displayed brightness
    screen.setCursor(12, 1);
    screen.print("o:"); // pitch
    screen.print(pitchAdj);
    lastDispTime = millis();
  }
}

 

]]>
Double Transducer: Rate of Blinking Light –> Rotational Position https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-rate-of-blinking-light-rotational-position/ Tue, 15 Feb 2022 23:47:20 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=15066 Gallery
Noni's double transistor: photoresistor to buzzer to sound detector to rotational popsicle stick by a servo motor

[Noni] View of the completed double transistor with the input (photoresistor) on the right and the output (rotational position) on the left

A close-up of a photoresistor in the project

A detailed view of the photoresistor that bends to make contact with the blinking LED

 

A detailed view of the sparkfun sound detector

A close-up of the buzzer and Sparkfun Sound Detector soldered.

 

[Catherine] View of the completed double transistor with the input (photoresistor) on the left and the output (rotational position) on the right

sound detector and buzzer close ups

[Catherine] A close-up of the passive buzzer and the Sparkfun Sound Detector

servo motor popsicle stick close up

[Catherine] A close up of the servo motor and popsicle stick rotation

a close up of the photoresistor

[Catherine] A detailed view of the photoresistor

Description

This device transfers light into sound, into movement. A small device measures light. An LED light will blink at different rates, and depending on how fast it blinks it, a sound will play with varying volume (faster blinks = higher volume). Another device will then measure the volume, and will tell a popsicle to move a certain angle.

Process

whiteboard block diagram

The first stage of understanding how the circuit would function and what the inputs and outputs would be

Whiteboard notes on how to detect a blinking LED

The ideation of how to properly detect a blinking LED

Wiring of a buzzer

This was the first stage of finding the correct buzzer (passive vs. active) and wiring it up to start the code process.

 

In process stages (trying to get the sound detector and speakers to work)

At this stage, we were trying to understand how to get the rate of the LED blinks to map to the volume of the buzzer.

The input value of a blinking LED

When we were ready to test our project, we built a blinking LED to mimic the input we were going to measure

Discussion

While some aspects of this project were simple, some were quite challenging. Wiring the physical components was fairly straightforward, as well as trouble-shooting the buzzer, and getting it to work properly. With enough insight from our instructors, such as the fact that the millis() timer could not be shared by both the passive buzzer ToneAC library and the servo motor (h library), we were able to provide an alternative method to get the motor to properly move the popsicle stick.

It was really difficult to update all of the components in real time. Thus, getting the LCD screen to blink 4 times per second while also getting the servo motor to properly update it’s angle. Individually everything made sense, but having everything work together nicely was a different story. Thus, distributing the data into the servo motor and output the proper angle in real time, and properly getting the data onto the LCD screen and having it reflect the right numbers and components – it was a lot of troubleshooting to get to our result.

Conceptualizing and actually coding the photoresistor to understand the varying rates of blinks from the LED was really difficult. Thankfully we asked for help early on in the process and Zach was able to sit with us and have an hour long talk where we conceptualized everything and created a solution. However going from pseudocode to actually putting it in the Arduino software in tandem with all of the other components was difficult. There was a point when we reached exactly what we were looking for – the code written was able to determine when the LED went on and off and at what rate it blinked, but even with this major component down – our servo motor decided not to work. Thus, even more troubleshooting was needed.

There was a lot of math involved in this, and likewise a lot of math functions. It took a lot of work to figure these parameters and math requirements out in order to get the correct angles and such.

Overall, we enjoyed working with each other and through challenges together. As a design major and creative writing major, we did not have strong coding backgrounds so we found the project slightly challenging but in a good way. We also each used our strengths in other areas to add to the project so despite the slightly less than satisfactory outcome, we learned a lot through the process, not just about physical computing, but also about each other. We also found that we had the same birthday and same white converse shoes which was very cool. 

Schematic and Block Diagram

Functional Schematic

Functional Schematic

Block Diagram of light to sound to movement

Block Diagram

Code

/* Double Transducer: Light --> Sound --> Movement
 *  
* Catherine Liu and Noni Shelton
* 
* This code takes in the rate of a blinking LED through a photoresistor and outputs a change in volume through a passive buzzer, which is then detected by a 
* sparkfun sound detector and used as an input to drive a servo motor that rotates a popsicle stick to a certain angle
* 
* Pin Mapping:
* pin | mode   | description
* ----|--------|-------------
* A3 . input .   photoresistor
* 3 .  output .  servo motor
* A0 . input .   sound detector
* 
* Code Used:
* Robert Zacharias: Displaying data on an I²C LCD screen (https://courses.ideate.cmu.edu/60-223/s2022/tutorials/I2C-lcd)
* Referenced ToneAC library and Sparkfun Sound Dectector page for how to use buzzer and sound detector
*/



#include <LiquidCrystal_I2C.h> //LCD Display Module library
#include <toneAC.h> //buzzer library

LiquidCrystal_I2C screen(0x27, 16, 2); //initiate screen

//pins
const int PHOTOPIN = A3; 
const int GAUGEMOTORPIN = 3; 
#define SOUNDPIN A0

int photoVal; //light detected by photoresistor
int lightCount; //number of blinks per second
unsigned long lastTimeDisplay = 0; //tracks time for displaying on LCD
int volume; //volume outputted by buzzer
int soundDetect; //volume detected by sound detector
int rateArray[100]; //array for light readings
int arrayCount = 0; //counts number of values in array
int delayRange; //delay time for motor to get to certain angle
#define updateTime 20 //delay for servo motor

void setup() {
  pinMode(PHOTOPIN, INPUT);
  pinMode(GAUGEMOTORPIN, OUTPUT);
  Serial.begin(9600);

  LCDScreenSetup();
}

void loop() {
  LCDScreenDisplay();

  lightCount = 0;//reset lightcount after every loop

  for ( int i = 0; i < 100; i = i + 1) { //taking in reading
    photoVal = analogRead(PHOTOPIN);
    rateArray[i] = photoVal;
    delay(10);
  }
  for (int i = 1; i < 100; i = i + 1) { //counting number of blinks in array
    if (((rateArray[i]) - (rateArray[i - 1])) >= 100) {
      lightCount = lightCount + 1;
    }
  }
  for (int i = 0; i < 100; i = i + 1) { //resetting array
    rateArray[i] = 0;
  }

  //check blinking rate and map to buzzer volume
  volume = map(lightCount, 0, 20, 0 , 10);
  toneAC(400, volume);
  delay(1);

  // Check the envelope input and map to motor
  soundDetect = analogRead(SOUNDPIN);
  delayRange = map(value, 7, 45, 544, 2400);

  //call motor function
  motorAngle();

}

void motorAngle() { //delays the servo a certain amount of time for it to get to a specific angle
  digitalWrite(GAUGEMOTORPIN, HIGH);
  delayMicroseconds(delayRange);
  digitalWrite(GAUGEMOTORPIN, LOW);
  delay(updateTime);
}

void LCDScreenSetup() {
  // initialize the screen (only need to do this once)
  screen.init();

  // turn on the backlight to start
  screen.backlight();

  // set cursor to home position, i.e. the upper left corner
  screen.home();
}

void LCDScreenDisplay() {
  if (millis() - lastTimeDisplay >= 250) { //checks for when 250 milliseconds has passed
    screen.clear();
    
    // screen display photoresistor input
    screen.setCursor(0, 1);
    screen.home();
    screen.print("i:");
    int screenLight = map(lightCount, 0, 20, 0, 99);
    screen.setCursor(2, 0);
    screen.print(screenLight);

    //screen display volume output from buzzer
    screen.setCursor(5, 0);
    screen.print("m:");
    int screenVolume = map(volume, 0, 10, 0, 99);
    screen.setCursor(7, 0);
    screen.print(screenVolume);

    //screen display volume detected by sound detector
    int screenDetected = map(soundDetect, 7, 45, 0, 99);
    screen.setCursor(7, 1);
    screen.print(screenDetected);

    //screen display motor angle
    screen.setCursor(11, 1);
    screen.print("o:");
    int screenMotor = map(delayRange, 544, 2400, 0, 99);
    screen.setCursor(13, 1);
    screen.print(screenMotor);
    
    lastTimeDisplay = millis(); //updates the checking time
  }
}

 

 

]]>
Double Transducer: Rotational Speed to Magnetic Field Strength https://courses.ideate.cmu.edu/60-223/s2022/work/double-transducer-rotational-speed-to-magnetic-field-strength/ Sun, 13 Feb 2022 16:10:11 +0000 https://courses.ideate.cmu.edu/60-223/s2022/work/?p=14979

 

Sid's Double Transducer

Sid’s Double Transducer

Andy's double transducer

Andy’s Double Transducer

A 3D printed part for the stepper motor

3D printed spindle that reels up a string that is attached to a magnet.

A protoboard with IR sensor attached to the right and a popsicle stick attached to a servo motor to the left.

The IR sensor detects the movement in the servo motor and sends a signal to the Arduino.

Narrative Description

The double transducer receives input in the form of rotational speed and the final output is magnetic field strength. The intermediate output is an angular movement that alters the strength of the magnetic field. We measure rotational speed through a rotary encoder by calculating the number of rotations per second. This is communicated to the Arduino and used to calculate the degree of motion of a servo motor that moves within 20 degrees. The motion is observed by an IR Proximity Sensor which provides the input for a stepper motor to raise and drop a magnet with a string attached to a 3D printed spindle, therefore altering the magnetic field strength.

Discussion

This project has been eye-opening to the world of Arduino and hardware for both of us. The ideation stage was largely based on our individual creativity. Initially, for one of the plans, we thought about incorporating a mounted sensor on wheels to alter the distance as an intermediary step, but given the limited duration and our lack of technical awareness, we switched to a better alternative in the form of the servo motor. We also first thought about using a wire coil to change the magnetic field strength; however, Professor Zacharias informed us of the difficulty in that task and we had to find an alternative. We eventually landed on the idea of using a 3D printed spindle locked into a stepper motor with a string glued onto the spindle to raise and lower a magnetic which worked just as planned in the final demonstration.

It took the combined efforts to create a workable prototype in time for the final deadline. We hit a lot of roadblocks while building the prototype. The unfamiliarity of the potential applications of various hardware slowed us down as we were experimenting with different motors and sensors. However, the guidance we received from professor Zacharias, TA Eric, and the online sources allowed us to meet project deliverables in time.

There were a lot of problems we faced when we built out our individual prototypes especially with soldering and the wire connections to the respective sensors/motors. We tried to solder most of the wiring into one protoboard, however, one of the boards ended up short-circuiting the Arduino and sensor due to the lack of scrutiny. It was frustrating as it was a day before the deadline and everything just went horribly wrong. The Arduino did not work in the first run and the IR proximity sensor was short-circuited on the second try. It made us realize the importance of starting early and scheduling the process for managing the workload. Additionally, we understood the significance of proper documentation and schematics and careful inspection before soldering which would have avoided all these problems. Besides the technical implementation, we had issues identifying the right ranges for the input/output from the sensor to the motor. Initially, through trial and error, we used constants and equations to convert the IR proximity input to control the stepper motor. Nevertheless, the professor recommended using the map function in C, to control the stepper which streamlined the code and the implementation efficiently. Now looking back at the project, we could have used a calibration system similar to one that was used by some of our classmates to determine the range after the Arduino just starts up.

Despite all these issues and unfamiliarity, we were able to develop our individual projects by the deadline which worked in tandem with all the other projects on the presentation day.

A protoboard with a faulty circuit soldered onto it which led to short-circuiting.

The three red power wires on the left side were misplaced which caused the IR emitter and the Arduino to shortcircuit.

 

A misaligned screw terminal that was not noticed during the soldering process

In a rush, I (Andy) misaligned a screw terminal during the soldering process and couldn’t take out the terminal after realizing the mistake.

Picture of the prototype right before Andy shortcuited the IR sensor, Arduino, and the LCD display.

Picture of the prototype right before Andy short-circuited the IR sensor, Arduino, and the LCD display.

Our first working prototype with all the components together.

Functional Block Diagram

Electrical Schematic

Code

/*Project Title: Double Transducer: Rotational Speed to Magnetic Field Strength
  Team Members: Siddharth Parthiban, Weiwen (Andy) Jiang
  Description: Rotary encoder sends input to arduino to calculate rotational speed. 
             Based on input between the ranges of 20 and 60 rotations per second, the servo motor
             is shifted to ± 10 degrees from 90 degrees.
             IR proximity sensor reads the change in motion and sends output to arduino.
             The input from IR proximity sensor is mapped to the input for the stepper motor. 
             The stepper motor changes the height of the magnet based on the input. 
  Pin mapping:
    Arduino pin | role   | description
    ------------|--------|-------------
    A0            input     IR proximity sensor
    2             input     rotary encoder pin A
    3             input     rotary encoder pin B
    4             output    Stepper Motor
    5             output    Stepper Motor
    8             output    Servo motor 
    SCL                     SCL of LCD
    SDA                     SDA of LCD
  Rotoray Encoder Code adapted from https://dronebotworkshop.com/rotary-encoders-arduino/#Arduino_Motor_Encoder_Sketch DroneBot Workshop 2019
*/

#include <Servo.h>
#include <Encoder.h>
# include <AccelStepper.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

//Initialising time and position variables
unsigned long prevTime = 0;
unsigned long prevMotorTime = 0;
unsigned long prevServoTime = 0;
unsigned long oldTimeDisplay = 0;
unsigned long prevIRTime;

//Initialising other variables
long oldPosition  = 0;
float rotatSpeed;
float rotations;
float prevRotation = 0;
int pos = 800;
int prevIRVal = 0;
int servoDegree = 90;
int newDistance = 0, oldDistance = 0;
int changeCheckNew = 0, changeCheckOld = 0;
int irVal = 0;


//Initialising pin ports for Arduino
const int DOORMOTORPIN = 8;
const int STEP_PIN = 4;
const int DIR_PIN = 5;
const int INFRAREDPIN = A0;

//Constant for Rotary Encoder to Servo motor
const int encodToDegree = 20 / 1800;

//Making servo and stepper objects
AccelStepper myMotor(1, STEP_PIN, DIR_PIN);
Encoder myEnc(2, 3);
Servo doorMotor; 
int motorPOS;
int MotorCur;


LiquidCrystal_I2C screen(0x27, 16, 2); //Declaring LCD screen object

void setup() {
  Serial.begin(9600); //setting data rate
  doorMotor.attach(DOORMOTORPIN); //declaring pin for servo motor
  
  //Setting up servo motor
  doorMotor.write(servoDegree); 
  pinMode(INFRAREDPIN, INPUT);
  
  //Setting up Stepper motor
  myMotor.setMaxSpeed(1000);
  myMotor.setAcceleration(500);

  //Setting up LCD screen
  screen.init();
  screen.backlight();
  screen.home();
}

void loop() {
  rotations = myEnc.read(); //read rotary encoder input

  //Calculate rotational speed for every second
  if ((millis() - prevTime ) >= 1000) {
    prevTime = millis();
    rotatSpeed = ((rotations - prevRotation) / 80) * 60;
    prevRotation = rotations;
  }

  //Move servo motor based on rotational speed for every second
  if (( millis() - prevServoTime) >= 1000){
    prevServoTime = millis();
    if ((0 <= abs(rotatSpeed)) && (abs(rotatSpeed) <= 60)) {
      if (rotatSpeed > 0) {
        servoDegree = 90 + ((rotatSpeed) * 0.1667);
        doorMotor.write(servoDegree);
      } else {
        servoDegree = 90 - ((rotatSpeed) * 0.1667);
        doorMotor.write(servoDegree);
      }
    }
  }
  
  //Read IR proximity sensor input for every 1/2 second
  if ((millis() - prevIRTime) >= 500) {
    prevIRTime = millis();
    irVal = analogRead(INFRAREDPIN);
  }

  //Move Stepper motor based on input from IR proximity sensor every second
  if ((millis() - prevMotorTime ) >= 1000) {
    prevMotorTime = millis();
    motorPOS = map(irVal, 200, 350, 0, 5000);
    myMotor.moveTo(motorPOS);
    myMotor.run();
    MotorCur = myMotor.currentPosition() / 200;
  }
  myMotor.run(); // run Stepper motor

  //Display values to LCD screen
  if (millis() - oldTimeDisplay >= 250) {
    oldTimeDisplay = millis();
    screen.clear();
    screen.setCursor(0, 0);
    screen.print("i: " + (String) (int)rotatSpeed);
    screen.setCursor(7, 0);
    screen.print("m:" + (String) (int)servoDegree);
    screen.setCursor(7, 1);
    screen.print (irVal);
    screen.setCursor(11, 1);
    screen.print("o: " + (String) MotorCur);
  }

}

 

]]>