A picture of Janelle's Double Transducer that specifically looks for red light as its input. The red light will then trigger a servo motor with a wooden umbrella on it to cover a photoresistor with shade. The provided shade will then cause the linear actuator with a magnet to move back and forth and create a diy magnetic field
A picture of Ana's Double Transducer that specifically looks for red light as its input. The red light then triggers a servo motor with a wooden umbrella on it to cover a photoresistor with shade (that is placed on a relaxing beach scene). The provided shade will then cause the linear actuator with a magnet to move back and forth and creating a magnetic field.
POV: you are the input color red slowly getting closer to the color sensor and you will trigger the double transducer
Another angle of the double transducer. I just wanted to show off the beautiful beach theme (and the messy wires demonstrating the trash in the ocean, bringing awareness to keeping our seas clean)
Detailed shot of the lovely beach vacation
Another angle of the double transducer showing the lcd screen.
A video of Janelle using the color red on a phone to move it in front of the color sensor, causing the rest of the components to react
A video of Ana using the color red on a phone to start the circuit. Shows the whole double transducer working as well as the skip the middle video.
To put it simply, we take in the color red, which makes an umbrella cover a light sensor. Once the light sensor gets enough shade, it begins to make a linear actuator with a magnet on the end of it move back and forth. This will create a DIY magnetic field!
In more detailed languaged, this is our Double Transducer that takes in light color as the input and outputting a magnetic field. The middle step includes a servo motor that controls an umbrella that, when given the color red, would move and provide shade to a photoresistor. Once the photoresistor receives enough shade, a linear actuator with a magnetic attached to the end of the actuator begins to move back and forth. This would then creator our magnetic field output.
One of our project's where we taped down our components before decorating
A picture of our photoresistor before we soldered it onto a protoboard!
Us optimistically writing down code on how to use our linear actuator
Our soldered middle step, the photoresistor :D
We found that the easier parts were figuring out the wiring between components and how to connect them to one another. Since we already did some practice in class as well as from the videos we watched on Canvas, it was fun to connect the pieces together in our project.
However, everything else was relatively hard! There was a steep learning curve in understanding what we needed to make and create in such a short amount of time. From the beginning, we had a tough time just researching how to do our input (light color) and our output (creating a magnetic field). For example, we spent a good hour or so just doing research on light color and the specific component we had to use (the APDS-9960). There was no documention on it in ioref. Thus, this sent us on a wild goose chase finding the particular part, any example code, and figure out the wiring schematic. This experience taught us to do research on components effectively and how to understand components that do not exist on ioref.
We also found it pretty difficult to code the linear actuator and how to measure the 'magnetic field' that was being created such that it can be displayed on our LCD Display. Because there is no definite way to measure the distance of the actuator moving back and forth, we had to create an 'internal clock' for it where we would define a middle state distance and, once the actuator exceeds that distance, it should move back and then forth, etc.. It was a pretty tough coding challenge and we were unable to complete it. But, from this experience, we learned a lot about how we should structure our code such that its easier for us to debug.
If we were to make a little tweak, we could have started a lot earlier and received more debugging help at the beginning. If we did that, then we probably would have figured out the linear actuator component quicker. Side note, if I (Janelle) were to be present during the final days of submission it would have tremendously helped in our efforts in finishing the project. I would like to thank Ana for working with Zach and Ella with debugging and reconstructing the code I was working on. Thanks :)
/*
Double Transducer: Light Color to Magnetic Field
The Double Transducer follows these steps:
1) read light color as input, specifically the color red
2) as the level of the color red increases, the servo motor with an umbrella moves
3) the umbrella covers a photoresistor
4) once the photoresistor receives enough shade, it triggers the linear actuator to move
5) the linear actuator has a magnet attached at the end, the horizontal movement allows for a magnetic field to be created
6) if the red light level goes below its needed threshold, the linear actuator retracts
Note:
When a button is held down, it skips the middle step
where the middle step is the servo motor and photoresistor.
Pin mapping:
Arduino pin | role | details
------------------------------
6 input momentary button
A3 output photoresistor
8 output servo motor
10 output linear actuator A
11 output linear actuator B
Released to the public domain by the authors, January 2024
Ana Diaz-Yong, adiazyou@andrew.cmu.edu &&
Janelle Tecson, jtecson@andrew.cmu.edu
*/
/*************************************************************
[ 1 ] read inputs (gather information from the world)
*************************************************************/
// Libraries
#include <Servo.h>
#include <Wire.h> // color sensor
#include <SparkFun_APDS9960.h>
#include <LiquidCrystal_I2C.h>
// Define Liquid Screen
LiquidCrystal_I2C screen(0x27, 16, 2);
// Arudino Run Time
unsigned long HALFSECONDWAIT = 500; // 500 milliseconds is half a second
unsigned long nexttimetorun = 0;
// Defining Pins
int currentdistance = 0;
Servo umbrellaMotor;
const int PHOTOPIN = A3;
const int UMBRELLAMOTORPIN = 8;
const int LINEARACTUATORA = 11;
const int LINEARACTUATORB = 10;
const int BUTTONPIN = 6;
// Global Variables
//color sensor
SparkFun_APDS9960 apds = SparkFun_APDS9960();
uint16_t ambient_light = 0;
uint16_t red_light = 0;
uint16_t green_light = 0;
uint16_t blue_light = 0;
void setup() {
//make same order normally
pinMode(LINEARACTUATORA, OUTPUT);
pinMode(LINEARACTUATORB, OUTPUT);
pinMode(PHOTOPIN, INPUT);
umbrellaMotor.attach(UMBRELLAMOTORPIN);
pinMode(BUTTONPIN, INPUT);
Serial.begin(9600);
// Code to get sensor started [https://learn.sparkfun.com/tutorials/apds-9960-rgb-and-gesture-sensor-hookup-guide/all]
if (apds.init()) {
Serial.println(F("APDS-9960 initialization complete"));
} else {
Serial.println(F("Something went wrong during APDS-9960 init!"));
}
// Start running the APDS-9960 light sensor (no interrupts)
if (apds.enableLightSensor(false)) {
Serial.println(F("Light sensor is now running"));
} else {
Serial.println(F("Something went wrong during light sensor init!"));
}
// Wait for initialization and calibration to finish
delay(500); // this may be an issue
screen.init();
screen.backlight();
screen.home();
}
void loop() {
/*************************************************************
[ 1 ] read inputs (gather information from the world)
*************************************************************/
int photoVal = analogRead(PHOTOPIN);
int buttonVal = digitalRead(BUTTONPIN);
delay(250);
// safety check
if (!apds.readAmbientLight(ambient_light) || !apds.readRedLight(red_light) || !apds.readGreenLight(green_light) || !apds.readBlueLight(blue_light)) {
Serial.println("Error reading light values");
}
/*************************************************************
[ 2 ] using gathered data to change different variables
*************************************************************/
int brella = map(red_light, 25, 700, 120, 50);
int distance = map(photoVal, 300, 900, 0, 99);
int distancetotravel = currentdistance - distance;
long forwardStartTime;
long backwardStartTime;
if(buttonVal == LOW) {
/*************************************************************
[ 3 ] driving outputs
*************************************************************/
umbrellaMotor.write(brella);
// tell the linear actuator where to go
// while distance to travel is positive you'll extend for a cetain amount of time
// once you have extended/retract then turn the motor off digital write to low
if (250 < photoVal) {
forwardStartTime = millis();
Serial.println(" MOVING FORWARD");
digitalWrite(LINEARACTUATORA, HIGH);
digitalWrite(LINEARACTUATORB, LOW);
}
else {
backwardStartTime = millis();
Serial.println(" MOVING BACKWARD");
digitalWrite(LINEARACTUATORA, LOW);
digitalWrite(LINEARACTUATORB, HIGH);
}
}
if (buttonVal == HIGH) {
if (300 < red_light) {
forwardStartTime = millis();
Serial.println(" MOVING FORWARD (skip)");
digitalWrite(LINEARACTUATORA, HIGH);
digitalWrite(LINEARACTUATORB, LOW);
}
else {
backwardStartTime = millis();
Serial.println(" MOVING BACKWARD (skip)");
digitalWrite(LINEARACTUATORA, LOW);
digitalWrite(LINEARACTUATORB, HIGH);
}
}
// figure out linear actuator distance
long currTime = millis();
long deltaForwardTime = currTime - forwardStartTime;
long deltaBackwardTime = currTime - backwardStartTime;
if(deltaForwardTime > 6400) {
// we are at full distance
distance = deltaForwardTime - deltaBackwardTime;
}
/*************************************************************
[ 4 ] reporting information back to the user
*************************************************************/
if (millis() >= nexttimetorun) {
long inputvalue = (red_light * 99) / 5000;
long photoprint = ((long)photoVal * 99) / 800;
long brellaprint = ((long)brella * 99) / 180;
Serial.print("red_light: ");
Serial.print(red_light);
Serial.print(", photoVal: ");
Serial.print(photoVal);
Serial.print(", distance: ");
Serial.println(distance);
screen.clear();
screen.home();
screen.print("i: ");
screen.print(inputvalue);
screen.setCursor(5, 0);
screen.print("m: ");
screen.print(brellaprint);
screen.setCursor(8, 4);
screen.print(photoprint);
screen.setCursor(12, 5);
screen.print("o: ");
screen.print(distance);
nexttimetorun = millis() + HALFSECONDWAIT;
}
}