Joy's Double Transducer- this photo shows the entire set up of the double transducer from an angled top view with labeled elements.
Hannah's Double Transducer - Photo shows the whole set up from an angled top view.
Detail photos of any part that you’d like to highlight (two to five between the team members)
Joy's double transducer detail: The HC-SR04 and servo motor are soldered on to the protoboard.
Joy's double transducer detail: The button's wiring on the breadboard is shown in this image.
Hannah's double transducer detail: At the rested position the slab completely covers the HC-SRO4 sensor, resulting in a distance read of 0.
Hannah's double transducer detail: Arduino and soldered servomotor protoboard.
Hannah's double transducer detail: The neopixel and button wiring are shown in this image.
Joy's double transducer video
Hannah's Double Transducer Video.
When the sensor that senses force is pressed, it changes the rotation of the motor which raises and lowers the object hanging from the pulley. A distance sensor collects the distance that the object is from the table, which changes the color of light shown on the LED ring.
Joy's process pictures:
I originally used the large servo motor (as seen in this photo) for our pulley system. However, I realized that the force was too strong for the pulley and ditched it for the smaller blue servo motor.
The soldering job shown in this photograph was not working once the wires were plugged into the arduino and breadboard. I took a photograph of the soldering work just to remember the orientation/set up of the HC-SR04 on the protoboard.
I was able to fix the soldering issue by doing a cleaner job (not mixing the solder as much on the back side).
Hannah's process pictures:
The component that gave me the most difficulty was the HCSRO4 distance sensor, which in this photo would not give any information whatsoever. This was fixed by resoldering and replacing the distance sensor.
All components here are wired and ready to be put onto the board. However, the servo motor was behaving erratically, which would hinder the motion required to get a proper reading from the distance sensor. This was fixed by correcting the wiring on the force sensitive resistor, which allowed for a more controlled read of the force, and implementing a delay.
One day, my double transducer completely stopped working. A few wires were plugged incorrectly which caused the whole system to not receive any power. After contracting food poisoning I was able to rewire everything in my bedroom shower, which solved the issue.
The process of creating this double transducer was not easy, but we were able to overcome challenges a long the way through trial and error. With the limited knowledge we had about physical computing as a whole, we were tasked to create a multi-step transducer which required understanding of both wiring and software/coding.
Before beginning the physical building of our project, we were conflicted on how to achieve the middle conversion of distance. Originally, we were going to do a flat construction for our servo motor movement, but the ultrasonic ranger would not be able to detect the rotational motion from the servo. In response, we shifted to the pulley system and placed the distance sensor directly under the pulley object. Constructing the pulley was a matter of trial and error where we had to account for the servo motor's strength and range with a stable pulley structure. We had to implement several structural improvements such as a guardrail to keep the string in one place and supporting beams. This process could have been easier if we had measured out our building components first and accounted for the setbacks instead of responding to each new error that occurred.
Another struggle we had was getting the force sensitive resistor to read accurate numbers and read a value of 0 when there is no pressure applied. At one point of the project, the FSR would read some kind of force and would never reach 0 because of its sensitivity, therefore affecting the irregularity of the servo motor movement. Initially we changed the mapping to reflect the range of values given by the FSR (700-1023). However, the main issue was the wiring of the force sensitive resistor on our breadboard. After talking with the professor, we realized the problem with the FSR was that one pin of the FSR should be placed into the power on the breadboard, while the other pin should be placed in the same line as a pin going to the breadboard and the resistor going to ground. This change caused the FSR to start from 0 and go all the way up to around 900, and the servo motor movement was much less irregular.
If we were to begin this process again, we would probably rethink our middle step as it was a bit complicated structurally and caused us to spend unnecessary time on it that could've been spent on making our code stronger and fix other issues with the FSR and light outputs. We also could have improved on our planning bnefore beginning our building stage, which would have made our building process much more streamlined. We would also make sure to read all the instructions so that we are able to make sure we build with the rubric in mind and not have to fix our project to fit the rubric later. Overall, our team grew much stronger in our proficiency with both software and wiring compared to the start of the project and class.
Functional block diagram and schematic (one per team), drawn in draw.ioref.org using the conventions we discussed in class. Be sure that the images aren't cropped incorrectly (Google Sites will tend to crop without telling you as you resize images.) Samples shown below.
Code submission (one per team), embedded into the project page, and optionally also with a Github or other version control service public-facing link. Your code should be reasonably commented throughout so that people other than you (the author) can better understand it. You don’t need to explain every single line—that would be overkill—but leave useful notes in a reasonable measure. Write a comment block at the top of the code including:
the project title,
(optionally) your names,
a description (short or long) of what the code does,
a pin mapping table that would be useful to somebody else trying to recreate your work (this is a simple table that lists all of the connections to the Arduino pins),
appropriate credit to any other person’s/project’s code that you incorporated into your project, and
(optionally) a license notice (i.e. copyright, CC BY-SA 4.0, the MIT License, release it to the public domain, or just follow your heart). If you have written code that you wish to keep strictly proprietary for any reason, please speak with the instructor about an exception to this documentation requirement.
/*
Double Transducer: Force to Light Color
By Hannah and Joy :)
Force is recorded using a force sensitive resistor and is mapped to a variable that corresponds to a certain degree which the servo motor moves. The servo motor determines the distance read by the HCSRO4 ultrasonic ranger. The distance is mapped to a set of eight values, which each correspond to a different color light emitted by the Neopixel LED.
outside sources used:
HCSRO4 Ultrasonic Ranger Code --> https://courses.ideate.cmu.edu/60-223/f2024/tutorials/ultrasonic-ranger
LCD Display --> https://courses.ideate.cmu.edu/60-223/f2024/reference/class-log
*/
//including the libraries needed
# include <Servo.h>
# include <NewPing.h>
# include <Adafruit_NeoPixel.h>
# include <LiquidCrystal_I2C.h>
/*
pin mapping:
pin | role | details
------------------------------
A1 input force sensitive resistor
A3 output servo motor
4 output neopixel LED
7 input button to skip middle step
8 output trigger for ultrasonic sensor
9 output echo for ultrasonic sensor
*/
//Force Sensitive Resistor analog in pin
const int FSRpin = A1;
//Servo motor analog in pin
const int SERVO = A3;
// the analog read value of the FSR
int FSRREAD;
//distance sensor pins
//ultrasonic sensor
#define TRIGGER_PIN 8
#define ECHO_PIN 9
#define MAX_DISTANCE 12 //in centimeters
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); //make a new object called sonar
//servo motor
Servo servomotor;
int ServoVal;
int servomotormove;
//light
#define NUM_PIXELS 16
#define NPPIN 4
int distance;
int LightVal;
Adafruit_NeoPixel NeoPixel(NUM_PIXELS, NPPIN, NEO_GRB + NEO_KHZ800); // new object called neopixel
//button
const int BUTTONPIN = 7;
//display
LiquidCrystal_I2C display(0x27, 16, 2); //creating object called display
unsigned long runitback = 0; //counter
unsigned long WAIT = 500; //milliseconds before refresh
void setup() {
Serial.begin(9600);
// attachment points
pinMode(FSRpin, INPUT);
pinMode(SERVO, OUTPUT);
pinMode(BUTTONPIN, INPUT);
servomotor.attach(SERVO);
pinMode(NPPIN, OUTPUT);
//display set up
millis();
display.init();
display.backlight();
display.home();
runitback = millis() + WAIT;
}
void loop() {
//1. gathering input from the world
//force sensitive resistor
int FSRREAD = analogRead(FSRpin);
//button
int buttonVal = digitalRead(BUTTONPIN);
//ultrasonic sensor
int distance = sonar.ping_cm();
//2. using gathered data to make decisions
//determining motion of servomotor based on force input
ServoVal = map(FSRREAD, 0, 900, 0, 6);
//determining light color based on distance
LightVal = map(distance, 0, 12, 0, 6);
//3. driving outputs
//button is not pressed
if (buttonVal == LOW){
//output of the servo motor
delay(100);
servomotormove = ServoVal*25; //converting value to degrees
servomotor.write(servomotormove); //making the servo motor move
//LED component
if (LightVal == 0){ //no force is given, pulley is all the way down
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 0, 0)); //red
NeoPixel.show();
}
}
if (LightVal == 1){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 100, 0)); //orange
NeoPixel.show();
}
}
if (LightVal == 2){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 255, 0)); //yellow
NeoPixel.show();
}
}
if (LightVal == 3){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 255, 0)); //green
NeoPixel.show();
}
}
if (LightVal == 4){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 255, 255)); //teal
NeoPixel.show();
}
}
if (LightVal == 5){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 0, 255)); //blue
NeoPixel.show();
}
}
if (LightVal == 6){ //pulley is all the way up
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 0, 255)); //purple
NeoPixel.show();
}
}
}
if (buttonVal == HIGH){
NeoPixel.setBrightness(10);
LightVal = ServoVal; //when button is pressed, force input immediately becomes light value input
delay(100);
if (LightVal == 0){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 0, 0)); //red
NeoPixel.show();
}
}
if (LightVal == 1){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 100, 0)); //orange
NeoPixel.show();
}
}
if (LightVal == 2) {
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 255, 0)); //yellow
NeoPixel.show();
}
}
if (LightVal == 3){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 255, 0)); //green
NeoPixel.show();
}
}
if (LightVal == 4){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 255, 255)); //teal
NeoPixel.show();
}
}
if (LightVal == 5){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(15);
NeoPixel.setPixelColor(i, NeoPixel.Color(0, 0, 255)); //blue
NeoPixel.show();
}
}
if (LightVal == 6){
for(int i = 0; i < NUM_PIXELS; i++){
NeoPixel.setBrightness(20);
NeoPixel.setPixelColor(i, NeoPixel.Color(255, 0, 255)); //purple
NeoPixel.show();
}
}
}
//4. displaying information
if (millis() >= runitback){ //when the amount of milliseconds is equal to when we want it to run
display.clear();
display.print("I:");
display.print(map(FSRREAD, 0, 1000, 0, 99));
display.setCursor(0,1);
display.setCursor(5,0);
display.print("M-I:");
display.print(map(servomotormove, 0, 180, 0, 99));
display.setCursor(5,1);
display.print("M-O:");
display.print(distance);
display.setCursor(12,1);
display.print("O:");
display.print(LightVal);
runitback = millis() + WAIT; //increasing the value to activate the display function
}
}