Top view of Emily's Double Transducer.
magnetometer (left), speaker (right)
Magnolia's Double Transducer.
magnetometer (left), speaker (right)
Motor brings the object up when the magnet is close to the magnetometer
Magnet is being moved along the y-axis
The intentional use of yellow and orange cabling to highlight SCL and SDA connections
Emily's Double Transducer Video
Magnolia's Double Transducer shown close up on the mechanical middle component
Magnolia's Double Transducer Skip the Middle Button
Our device begins with a sensor that detects the magnetic field from a nearby magnet. This sensor measures the magnetic strength in one direction (the Y-axis) and uses it to adjust a motor that can turn between 10 and 170 degrees. As the magnetic field changes, the motor moves an object up or down using a pulley system. A laser sensor below measures how far the object is, and this distance then determines a sound frequency: the farther the object, the higher the pitch.
Adding a support structure so the Lego piece does not spin as it move
Soldering the components together
Changed ultrasonic ranger to laser distance sensor to get more accurate measurements
LCD mapping finally working partially!
The double transducer project was quite challenging overall, with many components not working as expected and numerous unexpected issues. Our double transducer consisted of four components that were new to us, it took us a while to make each work. Ultimately we learn a lot about Arduino-based techniques such as debugging, soldering, and breadboarding.
Most of our components required different libraries to be downloaded and one major challenge we faced was a library conflict. Our code produced long error messages, and we initially had no idea what was wrong. We spent a lot of time troubleshooting the wiring but found out later that the problem was due to the fact that most of the libraries we used were timer-based. Running them simultaneously caused the system to crash. Fortunately, we resolved this issue by replacing some of the libraries. In the future, we would approach debugging with more consideration, ensuring that we fully understand the errors before assuming the problem is with the wiring.
In addition to coding challenges, crafting the physical setup was a significant part of the project. We have a pulley system as a middle step, which added a hands-on element to the build. Initially, our pulley had a very limited range of movement, only spanning a few centimeters. We replaced the ultrasonic sensor with a laser distance sensor to improve accuracy. However, the laser sensor’s readings were highly dependent on how well the pulley was constructed, which made it difficult to get stable data and map the values accurately.
Overall, project 1 has prepared us to work with new components and design interactive devices using Arduino more confidently.
//Double Transducer: Magnetic Field to Pitch
//Emily Lau and Magnolia Luu
// Receives input from the magnetometer, and maps that to the 0-180 degree servo, the distance sensor reads the object's distance. That's then mapped to the tone of the speaker. All the maps are displayed on the LCD Display
//Pin Map:
// SDA & SCL --> 3-Axis Magnetometer, LCD Display, and Laser Distance Sensor VL53L0X
// Pin 2 --> input --> Servo Motor
// Pin 8 --> input --> Skip the Middle Button
// Pin 10 --> output --> Speaker
#include<Servo.h>
#include<Wire.h>
#include<LiquidCrystal_I2C.h>
#include <DFRobot_VL53L0X.h>
#include <QMC5883LCompass.h>
QMC5883LCompass Magnet;
DFRobot_VL53L0X sensor;
Servo motor;
const int motorPin = 2;
const int SPEAKER_PIN = 10;
const int BUTTON_PIN = 8;
//event timer (Taken from the course website)
//const int QUARTERWAIT = 250; // this variable, of type integer, is the number of milliseconds to wait between blinks
//unsigned long quarterTimer = 0; // this variable, of type "unsigned long," will help keep track of passing time
const unsigned long quarterSecondWait = 500;
unsigned long next_time_to_run = 0;
//unsigned long WAIT = 0; // each event loop needs a unique timer variable
LiquidCrystal_I2C screen(0x27, 16, 2);
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT);
pinMode(SPEAKER_PIN, OUTPUT);
//Servo motor
motor.attach(motorPin);
//magnetometer
Magnet.init();
//distance sensor
Wire.begin();
sensor.begin(0x50);
sensor.setMode(sensor.eContinuous, sensor.eHigh);
sensor.start();
//LCD Display
screen.init();
screen.backlight();
screen.home();
}
void loop() {
//step 1: gather input
Magnet.read(); //read Magnet
int y = Magnet.getY();//read the Y value output from the magnetometer
int abMField = abs(y); //magnetic field variable assigned to abs. value of y
int sensorDist = sensor.getDistance();
int buttonVal = digitalRead(8); //high and low for the skip the middle button
int motorPosition = map(abMField, 30, 28000, 5, 175); //map magnetometer output to servo motor output
unsigned int frequency = 2000;
//Step 2: make decision do math (Compute and make decisions based on the inputs)
if (buttonVal == LOW) { //when button is not pressed
frequency = map(sensorDist, 35, 85, 2000, 4210);
tone(SPEAKER_PIN, frequency, 0); //tone based on laser distance sensor
//Step 3: do output
motor.write(motorPosition);
} else { //if button is pressed
tone(SPEAKER_PIN, abMField, 0); //tone based on magnetometer
motorPosition = 5; //reset motor position to lowest part of its range
motor.write(motorPosition);
}
//Step 4: print/report information back to the user
//Serial.println(avMField);
//Serial.print("Distance: ");
//Serial.println(frequency);
// if it has at least 250 milliseconds since the quarter-second light last changed:
//if ( (millis() - quarterTimer) >= QUARTERWAIT ) { // millis() is always the number of milliseconds since the Arduino powered up
if (millis() >= next_time_to_run) {
//LCD
screen.setCursor(0, 0);
screen.print("I:");
//Print Magnetometer Input
int fieldConstrain = constrain(abMField, 30, 28000);
screen.print(map(fieldConstrain, 30, 28000, 0, 99));
//Print Motor Position
screen.setCursor(5, 0);
int motorPositionConstrain = constrain(motorPosition, 5, 175);
screen.print("m:");
screen.print(map(motorPositionConstrain, 5, 175, 0, 99));
//Print Distance Sensor
screen.setCursor(5, 1);
int sensorDistConstrain = constrain(sensorDist, 35, 85);
screen.print("m:");
screen.print(map(sensorDistConstrain, 35, 85, 0, 99));
//Print Speaker Output
screen.setCursor(12, 1);
int frequencyConstrain = constrain(frequency, 2000, 4210);
screen.print("O:");
screen.print(map(frequencyConstrain, 2000, 4210, 0, 99));
next_time_to_run = millis() + quarterSecondWait; // reset the timer before exiting the function.
}
}