Constantine Westerink- Double transducer final prototype
Isabel Fleck - Double transducer final prototype
Step 1 on the far left, is the laser distance sensor which recives initial Input of hand distance. Step 5 in the middle, is the LED which after following the middle step will display the final ouput through color. Step 6, on the far right, is the button to skip the middle step, making the data from the first step have direct influence on step 5.
Syringe 2 is mounted onto the load cell, so as water is added or removed, the load cell can determine the amount of water weight sensed and translate this data to the LED later.
Servo motor is used to translate rotational to linear data with the wire attached to it. As the servo roates, it forces in or pulls the end of a attached syringe (see image 2). This takes the data from the distance sensor and translates this to linear movement.
As we were using a stronger servo, we attached a external power supply to a 6V charger to ensure clean movement and strength.
Constantine Westerink - Documentation video
Isabel Fleck - Documentation video
As seen in the images above, this projects purpose was to create a double transduscer that translated distance as an initial input, into light and color as a final output. Including the middle step, we translated Distance - Linear Movement - Weight - LED.
As an object moves closer to the laser distance sensor, this distance data informs the movement of a servo motor connected to a syringe filled with water. As the object is closer, the servo will turn further to the right pushing water out of one syringe and into the other attached syringe. And left when things are further, retracting water. As the water is forced out of the first syringe and into the second, a load cell bar measures the water weight as it gradually increases. As the load cell bar senses more weight, a LED will change color along a spectrum of blues based on the amount of water data it receives. As the Ultrasonic ranger senses an object moving farther away, then the actuator is triggered to pull back in, receding water from the syringe attached to the laod cell, removing weight from the load cell bar, therefore changing the color of the LED to a deeper blue. With returning weight, the LED will appear to be a brighter blue.
Mounting mechanics onto a solid base and positioning input and output along the edges.
We don't have a process photo of the earliest stages. However, we initially used a Ultrasonic ranger, but after testing found the values to be to inaccurate and used a laser distance sensor instead for improved accuracy. (Could insert photo above of the pieces?)
Attempts to mount syringe and servo using a cardboard, wood block and popsicle sticks. Servo was temporarily taped down. Successful translation of rotational to linear movement, however the mounted base was unstable influencing data received in load cell.
Detail shot - using balsa wood to stabilize load cell to receive more accurate data, will mount in permanently in future, to ensure precision in small scale.
Initial Ideations + Sketches
Reflecting back on this project, we found it overall to be pretty well balanced with its challenges across all aspects. From a hardware perspective, the assembly and execution of the hydraulics system was especially challenging, especially as we searched to find a way to press the end of the syringe mechanically. Initially considering the use of a linear actuator, we found this option not as beneficial, as this would require a less flexible system to translate distance data into position, since the actuator does not use the same information ability as a servo motor. In our decision to use the servo instead to create the hydraulics, we tested a few different materials and wires to try and force the syringe, considering the use of different hinges and different contraptions. However, we found this solution to be much simpler, and instead used a single bar in the center, that would be able to rotate freely at a pivot on either end.
In our search to find a way to identify the difference in water weight of the syringe movement, we considered the use of a force receptor. However, using this would require a much larger amount of water in order to get enough force. Even then, the accuracy of information would make it much more difficult to configure the data received. In the end, we found that using a load cell bar would allow for the sensitivity needed. In using this, we also found that there was no need for a cup to pour liquid into, but could rather attach another syringe to complete the hydraulics, and subtract the weight of the syringe itself, and properly find the water weight in movement.
Across this project, we found ourselves growing in skills as we worked to improvise every problem we encountered. By doing so, we found this process to be important in developing and executing an idea, as we actively encountered what would not work, and instead create simpler and more elegant solutions. Overall, we both worked to understand the use of new materials from both a mechanical and software perspective, identifying and applying possible uses of these. In the future, it would be interesting to work with more creative solutions to translate light at the end, and explore some of our other ideas around a color wheel contraption, as well as increasing accuracy of movement response and a more definitive display of light and color.
/*
Project 1: Double Transducer
60-223 Intro to Physical Computing
A time of flight sensor reads the distance between itself and an object. This is used to drive a servo motor from 0-180 degree range. The servo's rotation is converted to linear motion, driven by a metal rod that pushes and pull the plunger of a syringe. The syringe transfers water into and out of another syringe. The varying weight of the syringe is recorded with a load cell that is fixed underneath it. This value is then used to change the color of an LED (smart neopixel). When the pushbutton is pressed the distance values drives the color of the LED ignoring the middle step of the transducer.
Pin mapping:
Arduino pin | role | description
-------------------------------------
2 input load cell (DOUT)
3 input load cell (SCK)
A4 input tof sensor (SDA)
A5 input tof sensor (SCL)
7 input skip the middle part button
5 output servo motor (Pushes syringe)
9 output RGB LED
code by Constantine Westerink and Isabel Fleck
February 2025
*/
#include <Servo.h>
#include <Wire.h>
#include <VL53L0X.h>
#include "HX711.h"
#include <PololuLedStrip.h>
#include <LiquidCrystal_I2C.h>
const int SYRINGE_SERVO_PIN = 5,
RGB_LED_PIN = 9,
BUTTON_PIN = 7,
LOADCELL_DOUT_PIN = 2,
LOADCELL_SCK_PIN = 3;
const int LOADCELL_CALIBRATION_FACTOR = 3475; // Unique for each load cell
// MIN and MAX weight of syringe in grams
const float MIN_LOADCELL_VALUE = 0,
MAX_LOADCELL_VALUE = 7.45;
// input data variables
float distanceVal, loadcellVal;
int buttonVal; // HIGH, LOW
// internal mapping values (0 - 99)
int mappedDistanceVal, mappedLoadcellVal, mappedSyringeServoPos;
// output values
int syringeServoPos;
rgb_color color[1];
VL53L0X distanceSensor;
Servo syringeServo;
HX711 loadCell;
PololuLedStrip<RGB_LED_PIN> led;
LiquidCrystal_I2C screen(0x27, 16, 2);
void setupScreen() {
screen.init();
screen.backlight();
screen.home();
screen.print("Hello, world!");
}
void setupLoadcell() {
loadCell.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
loadCell.set_scale(LOADCELL_CALIBRATION_FACTOR);
loadCell.tare();
}
void setupSyringeServo() {
syringeServo.attach(SYRINGE_SERVO_PIN);
syringeServo.write(180); // Extended position
delay(1000);
}
void setupLED() {
rgb_color initColor;
initColor.red = 0;
initColor.green = 100;
initColor.blue = 0;
color[0] = initColor;
led.write(color, 1);
}
void setupButton() {
pinMode(BUTTON_PIN, OUTPUT);
}
void setupDistanceSensor() {
Wire.begin();
distanceSensor.setTimeout(500);
if (!distanceSensor.init())
{
Serial.println("Error Distance sensor not working");
while (1) {}
}
}
void setup() {
Serial.begin(9600);
Serial.println("Setup Begin");
setupSyringeServo();
setupScreen();
setupLED();
setupLoadcell();
setupButton();
setupDistanceSensor();
Serial.println("Setup Complete");
}
void readInputs() {
distanceVal = distanceSensor.readRangeSingleMillimeters();
loadcellVal = loadCell.get_units(1);
buttonVal = digitalRead(BUTTON_PIN);
}
void updateInternalState() {
// map the photoresistor value to a range of 0 to 99
int constrainedDistanceVal = constrain(distanceVal, 50, 150);
mappedDistanceVal = map(constrainedDistanceVal, 50, 150, 0, 99);
// map the potentiometer value to a range of 0 to 99
int constrainedLoadcellVal = constrain(loadcellVal, MIN_LOADCELL_VALUE, MAX_LOADCELL_VALUE); // TODO
mappedLoadcellVal = map(constrainedLoadcellVal, MIN_LOADCELL_VALUE, MAX_LOADCELL_VALUE, 0, 99);
Serial.println(loadcellVal);
syringeServoPos = map(mappedDistanceVal, 0, 99, 0, 180);
mappedSyringeServoPos = map(syringeServoPos, 0, 180, 0, 99);
// // make a decision about driving the buzzer output based on the button state
if (buttonVal == HIGH) {
color[0] = getColor(mappedDistanceVal);
} else {
color[0] = getColor(mappedLoadcellVal);
}
}
rgb_color getColor(int value) {
rgb_color color;
color.blue = 200;
color.red = 100;
color.green = map(value, 0, 99, 0, 255);
return color;
}
void driveOutputs() {
if (buttonVal == LOW) {
syringeServo.write(syringeServoPos);
}
led.write(color, 1);
}
void loop() {
readInputs();
updateInternalState();
driveOutputs();
logToScreen();
delay(50);
}
void logToScreen() {
screen.clear();
// Print Input value
screen.print('i');
screen.print(':');
screen.print(mappedDistanceVal);
// Print middle step values
screen.setCursor(6,0);
screen.print('m');
screen.print(':');
screen.print(mappedSyringeServoPos);
screen.setCursor(8,1);
screen.print(99 - mappedLoadcellVal);
// Print output value
screen.setCursor(12,1);
screen.print('o');
screen.print(':');
screen.display();
}