Double Transducer: Opacity to Rotation

Evelyn Bang, Aiden Magee

Table of Contents

Final Images

At the bottom, there is an LCD Display that shows the range of each function from 0 to 99. At the right middle, there is an LED and a photoresistor that checks opacity. In the left top, there is a DC Motor that has a CAM attatched to it. The cam presses on the lever microswitch that is right underneath it. On the left middle, there is a servo motor that outputs the translated speed of the DC motor's spin rate. Each important component has a sticky note attatched to it that describes the component's capabilities.

Evelyn's Double Transducer

Cardboard square with an Arduino at top left, a small breadboard containing a photoresistor and LED at to middle, a DC motor with Cam at top right, a microswitch just below the DC motor, a servo motor on a clay block at bottom center, and LCD screen at bottom left. Middle of the board has circuit boards with wires plugged in.

Aiden's Double Transducer

Detail Photos

This close up shows the input function of the system that has an LED and a photoresistor pointing at each other in the middle of the image. There are two post-it notes on top and on the bottom of the components that describe what they are. These components are soldered onto a green solder board.

Input: Opacity

The photoresistor receives the opacity of a thin object by showing how dark the light has gotten compared to when there are no obstructions in between the LED and the photoresistor.

On the left, is the DC Motor that is tied to a make-shift popsicle stick stand with pipe cleaners. The CAM is on the shaft towards the top right of the image. Underneath the CAM is a lever microswitch that is pressed by the rotating CAM. On the middle top side, there is a red solder board that connects the DC Motor through an H-Bridge to the Arduino Uno.

Middle Step: DC Motor Spin Rate

The DC motor spins faster as the light is not as obstructed. The higher the light level, the faster the DC motor spins and clicks the lever microswitch with a CAM, detecting the rate of rotation.

In the middle is the front view of the DC Motor which has the CAM on the shaft. The cam is currently pressing down the black lever microswitch that is pointing right. There is a popsicle stick and some hot glue that is holding the microswitch up to the CAM.

Middle Step: DC Motor Spin Rate

An alternative angle of the DC motor, CAM, and lever microswitch.

In the middle of the image is the Servo Motor that is pointing downward. It is placed on top of a few popsicle sticks that are glued together so that it is an inch above the board that everything is placed on. The servo has a white stick that shows the angle of position more clearly.

Output: Servo Motor

The servo motor receives the rate of rotation and then translates that into an angle between 0 and 170. The higher the rate of rotation, the higher the angle.

Final Project Movies

Evelyn_Bang_Project_1.mp4

Evelyn's Video:
"Hello, my name is Evelyn Bang. This project shows the change from opacity to rotational rate to a positional rotation. The input is detected by a photoresistor that has an LED pointing at it, allowing the level of light reaching the photoresistor to be received. The DC Motor then responds to the light level, turning slower as there is less light. The DC Motor has a CAM attatched to it, allowing the lever microswitch to be pressed, detecting the rate of rotation. Afterwards, the servo motor changes its angle, responding directly to the rate of the DC motor's rotation."

AIden_Magee_Proj1_movie.mp4

Aiden's Video:

When I pass an opaque material through my opacity-measuring mechanism, my DC motor slows down, causing my switch to actuate at a lower frequency. My LCD screen reflects this. Unfortunately, my Servo motor was not functioning properly. I believe this was due to a power issue, because when I tried to hard code an angle to set my Servo at, my Servo still moved sporadically. 

Narrative Description

Evelyn:

A light shines into a little stub that tells how bright the light is. Then, the small motor spins slower when there is less light shining on the stub. That then makes the lever attached to the black box be pressed less, which then lowers the degrees of the white stick on the blue box. So, the brighter the light is, the slower the motor spins, so the lower the angle is; the darker the light is, the faster the motor spins, so the higher the angle is.

Aiden:

We use a small light and sensor (top middle) to see how much light passes through something. This helps us figure out how fast our DC motor (top right) should spin. The motor moves a small part that pushes a button. Our Arduino measures how often the button is pushed and uses that rate to tell the servo motor (bottom middle) how many degrees to rotate.


Progress Images

On the left half of the screen is an open black laptop that shows code. The laptop is connected to a jumble of wires and objects that is running the code.

Evelyn - Troubleshooting the code. I needed to work on the code for multiple days in order to fine tune and get rid of kinks.

There is a cardboard that takes up the majority of the image with components taped on top of it with blue painter's tape. On the right side there is a red solder board that has wires and the H-Bridge soldered onto it. It is beig held down to the large carboard with clips and tape. On the bottom left, is the DC Motor that is mounted on a makeshift stand made out of popsicle sticks and pipe cleaners. That lets it press down onto the lever microswitch that is placed right underneath it. On the right middle is the LCD Display pointing to the right. On the top left is the Arduino Uno. On the top Right is a green solder board that has the LED and photoresistor on top of it. In the middle is a breadboard that has some wire connections.

Evelyn - Placing the components onto a board layout before realizing there needed to be a format. I had to take off the tape in order to place the components in the right locations.

Microswitch in the center with DC motor to its right, connected by wires and circuit boards in the background.

Aiden - I finally got my DC motor switch actuator functioning properly.

Cardboard square with an Arduino at top left, a small breadboard containing a photoresistor and LED at to middle, a DC motor with Cam at top right, a microswitch just below the DC motor, a servo motor on a clay block at bottom center, and LCD screen at bottom left. Middle of the board has circuit boards with wires plugged in.

Aiden - After many trials of placing and replacing my components, I decided on my final layout.

At the bottom left, there is a row of CAMs that have been cut out. Each of the 5 CAMs are a result of trial and error. At the bottom right, there are successful CAMs that fit the DC Motor. At the top left, there are scraps from cutting out the CAMs.

Laser cutting the CAMs. The left bottom pieces did not fit the DC motor, so they needed to be reprinted in order to be able to click the lever microswitch well.

Discussion

Evelyn:

In retrospect, I found it to be quite different from my expectations, as someone new to Arduinos and circuitry. I thought that I would have to memorize the names and components more, but it wasn't like that in reality. I struggled when the components didn't function as expected, leading me to troubleshoot the wiring and the code. I learned the importance of organizing wires effectively, utilizing parallel placement on the breadboard for related components and specific colors to signify wire functions. Despite initial struggles, the task felt manageable and even enjoyable, since I like organizing and keeping things neat.

On the other hand, the code proved to be another hurdle, with comments and variables becoming jumbled. Despite this, debugging was both frustrating and satisfying, prompting me to refine and organize the code structure. What I found most rewarding was conceptualizing the middle steps in between the input and output, which allowed me to be creative with coming up with different ideas. This particular class reminds me of modded Minecraft, which has a lot of connections from physical computing. For example, Greg Tech is a famous mod that has resistors that you can use to craft certain blocks. These two experiences lining up enhanced my enjoyment of assembling the parts for this project.

Aiden:

Despite not being fully satisfied with my final project given that it was not fully functioning, I must say that the process was nevertheless rewarding. I am used to being confined in my coursework, but given the loose constraints of this project, I felt like I could freely pour my creativity into the square-foot cardboard canvas. 

While I didn't find the circuitry to be too challenging, I did realize some poor practices that were made more and more clear as my project progressed.  My wire management was poor. I failed to consistently color-coordinate my wires, which made my circuits harder to debug when I needed to. I also didn't cut my wires to size, leaving many of them too long and sticking out. I told myself that I would go back and fix this once I got everything working, but I never did. Next time I should properly manage my wires from the beginning to avoid this. Similarly, my poor aesthetics were clear in my final project. While I did appreciate the loose design constraints, I do recognize that aesthetics are important and it is something that I should work to refine more in the future. 

I am very grateful for this experience as it enabled me to feel comfortable as a Tinkerer. I have always wanted to get into hobby electronics or small projects like this one,  but I was always held back by something. I think I needed to just try it. Now that I know that many of my imaginative projects are feasible, I can turn my ideas into reality. 

Functional Block Diagram and Electrical Schematic

On the left is the input step of the process, which has a photoresistor and and LED that is connected to the Aruino Uno in the middle. On the right bottom is the second step that has the arrow from the Arduino Uno branching out into the H-Bridge Motor Driver, which then is connected to the DC Motor and then the Lever Microswitch. On the top right is the third step, which is just a servo motor that has an input signal from the Arduino Uno.
On the left middle side is the first step that has a resistor, LED, and a photoresistor that is connected to power, ground and the Arduino Uno. On the bottom left is the LCD Display that is conencted to power, ground, and the Arduino Uno's SDA and SCL pins. In the middle is the Arduino Uno. In the middle bottom is the lever microswitch with power, ground, and a resistor. The switch's normally open is connected to pin 2 on the Arduino. On the top right is the servo motor which is connected to the power, ground, and the Arduino's pin 13. On the bottom left is the H-Bridge Motor Driver that is connected to two power sources, four grounds, the DC Motor, and the Arduino Uno's pin 5, 6, and 7.

Code

/*

  Title: Double Transducer: Opacity to Rotation

  By: Evelyn Bang and Aiden Magee

  Description: The code takes in a value from the photoresistor that shows how much light is being shined into it. It then translates it into the DC motor speed. The lever microswitch detects the rotation by looking at the time difference in between each press, then adds it to an array of the last 5 recorded times it took for each press. These values are then averaged and then translated into the servo motor's angle which is in between 10 and 170 for the purpose of the servo motor's physical limitations.


  Pin mapping:

  pin | mode   | description

  ---------------------------------

  2   | INPUT  | Lever Microswitch

  5   | OUTPUT | Motor signal A (LOW)

  6   | OUTPUT | Motor signal B (HIGH)

  7   | OUTPUT | Motor enable

  13  | OUTPUT | Servo motor

  A3  | INPUT  | Photoresistor

  5V  | OUTPUT | LED (just on)

  -------- I^2C LCD PINS --------

  SDA |        | SDA (next to reset button to the right of 13)

  SCL |        | SCL (right next to SDA)


  NOTES:

  - LED is constantly on

  - Servo motor limit to 10-170 degrees due to hardware limitations

  - RPM of DC motor range (870, 1430) ms between every rotation

  - LCD on 1 frame for 200 ms (5 fps)

*/

#include <Servo.h>

#include <LiquidCrystal_I2C.h>

#include <Wire.h>


// GLOBAL VARIABLES

// SERVO MOTOR

Servo serv;

const int SERVOPIN = 13;

// DC MOTOR

const int MOTORSIGA = 5;

const int MOTORSIGB = 6;

const int MOTORENABLE = 7;

// PHOTORESISTOR + LED

const int PHOTORES = A3;

// LEVER MICROSWITCH

const int SWITCHPIN = 2;

int switchState = LOW;

int lastSwitchState = LOW;

const int switchTimeCount = 5;

int switchTimes[switchTimeCount];

int lastPressMillis = 0;

int lowestTime = 870;

int highestTime = 1500;

int timeTaken;

// LCD

LiquidCrystal_I2C lcd(0x27, 16, 2);

unsigned long frameTime = 100;  // milliseconds in between each frame

unsigned long nextToRun = 0;    // next time to turn the lcd



void setup() {

  // Attach pins

  serv.attach(SERVOPIN);

  pinMode(MOTORSIGA, OUTPUT);

  pinMode(MOTORSIGB, OUTPUT);

  pinMode(MOTORENABLE, OUTPUT);

  pinMode(PHOTORES, INPUT);

  pinMode(SWITCHPIN, INPUT);

  // Starts + prints on LCD

  lcd.init();

  lcd.backlight();

  // Timer for LCD

  nextToRun = millis() + frameTime;

  Serial.begin(9600);

}



void loop() {

  /*

    -------------------------------------------      1      -------------------------------------------

    -------------------------------------------LIGHT AND LED-------------------------------------------

  */

  // Get current opacity/light level

  int currLight = analogRead(PHOTORES);

  /*

    -------------------------------------------      2      -------------------------------------------

    ------------------------------------------- MOTOR SPEED -------------------------------------------

  */

  // Turn light level into motor speed

  int motorSpeed = int((currLight / 1023.0f) * 125.0f + 130.0f);

  digitalWrite(MOTORENABLE, HIGH);

  digitalWrite(MOTORSIGA, LOW);

  analogWrite(MOTORSIGB, motorSpeed);

  // Detect switch lever press rate

  lastSwitchState = switchState;

  switchState = digitalRead(SWITCHPIN);

  // Check how long since last press down

  int timeSinceLastPress = millis() - lastPressMillis;

  // Checks to see if switch was just pressed

  if (switchState == HIGH && lastSwitchState == LOW && timeSinceLastPress >= 400) {

    // Check how much time has taken since last pressed

    timeTaken = 0;

    for (int i = switchTimeCount - 1; i > 0; i--) {

      switchTimes[i] = switchTimes[i - 1];

      timeTaken += switchTimes[i];

    }

    switchTimes[0] = timeSinceLastPress;

    timeTaken += switchTimes[0];

    // Take average of all the past "switchTimeCount" times

    timeTaken /= switchTimeCount;

    // Serial.println(timeTaken);

    lastPressMillis = millis();  // Update pressed time

  }

  /*

    ------------------------------------------      3      ------------------------------------------

    ------------------------------------------ SERVO ANGLE ------------------------------------------

    */

  // If fast => higher angle of servo (max set to 170) + if slow => lower angle of servo (min set to 10)

  float servPer = float(timeTaken - lowestTime) / float(highestTime - lowestTime);

  int servMotVal = int((servPer * 160.0f) + 10.0f);

  serv.write(servMotVal);

  // Printing out to the LCD screen

  if (millis() >= nextToRun) {

    // LCD setup

    lcd.clear();

    lcd.setCursor(0, 0);

    lcd.print("i:");

    lcd.setCursor(6, 0);

    lcd.print("m:");

    lcd.setCursor(12, 1);

    lcd.print("o:");

    // Input

    lcd.setCursor(2, 0);

    int inputMap = int((float(currLight) / 1023.0f) * 99.0f);

    lcd.print(inputMap);

    // Middle input

    lcd.setCursor(8, 0);

    int midInput = int((float(motorSpeed - 130) / 125.0f) * 99.0f);

    lcd.print(midInput);

    // Middle output

    lcd.setCursor(8, 1);

    int midOutput = int(servPer * 99.0f);

    lcd.print(midOutput);

    // Output

    lcd.setCursor(14, 1);

    int output = int((float(serv.read() - 10) / 160.0f) * 99.0f);

    lcd.print(output);

    // Resetting timer for when to run LCD screen next

    nextToRun = millis() + frameTime;

  }

}