Part 1. Overall Images of the Final Product
Part 2. Details
Part 3. Demonstration
Dunn’s project in action.
Mo’s project in action.
Bhairavi’s project in action.
Part 4. Narrative
A sensor reads the distance of an object in front of it, then converts that data to transparency through the use of a light valve. Our team had some different approaches to the middle step of the device. Mo used wind speed as the middle step, while Dunn and Bhairavi used sound. Mo’s project uses a fan that blows into a wind sensor for the middle step, while Dunn and Bhairavi’s projects use a buzzer and a microphone.
Part 5. Processes
Dunn’s process:
Mo’s Process:
Part 6. Discussion
Overall, this project was an excellent introduction to physical computing: how everything works and comes together. Though our team had different solutions and approaches, they were equally unique and valid. We learned the hard lesson that the product might not work as you intended on the presentation day, and there are always issues to be resolved. It was interesting to see how our teammates approached the project prompt – each of us faced different constraints, leading us to end up with different middle steps for our transducers.
Since there was only one fan present in the classroom, both Dunn and Bhairavi chose to use buzzers generating sound for their middle steps. Dunn chose to control the volume of the buzzer for the middle step, since he found this easier than controlling the frequency. However, Bhairavi had trouble accurately detecting the volume of the buzzer and decided to hone in on the small range of frequencies in which the microphone could detect a linear increase in frequency.
Another difference between our projects was that the sensitivity of the transparency to movement was significantly different. Both Dunn and Bhairavi found it necessary to significantly limit the range in which the laser could detect movement due to range limitations in their middle step, while Mo was able to detect and express a larger range of movement.
Part 7. Functional Block Diagram and Schematic
Part 8. Code Submission
/* File/Sketch Name: transducer_test Version No.: v2.0 Created Feb 14 2023 Bhairavi Chandersekhar Description: This code works to run an Arduino Uno powered double transducer. The transducer converts distance to transparency. The double transducer uses a VL53L0X 'Time of Flight' Laser distance sensor to input distance (must be between 40 and 220 mm). The distance signal is then converted by the Arduino to a frequency between 290 and 335 Hz. which is then sent to a passive piezo buzzer. An electret microphone picks up the signal from the passive buzzer and uses the frequency to control the transparency of a light valve. Input, intermediate, and output values are displayed on an LCD screen. Notes: - all frequencies between 290 and 355 Hz are not able to be used. Frequencies from 300-315 Hz are very frequently not picked up accurately by the microphone. This is why much of the code is split up using if statements; frequencies in two different nonadjacent ranges are generated, and the frequencies picked up are also present in two nonadjacent ranges. Frequencies above, below, or between these ranges are disregarded as noise. - Specific ranges in which the microphone is able to detect the frequency accurately depend on the specific choice of buzzer and microphone, as well as the ambient noise in the room. Pin Mappings: 5 one lead of the piezo buzzer (other lead to ground) 10 one lead of the light valve (other lead to ground) A0 electret microphone input 3.3 V runs to electret microphone and laser distance sensor 5V runs to LCD display. SCL/SDA connects to both the LCD display and to the laser distance sensor FFT code based on AudioFrequencyDetector code written by Clyde A. Lettsome, PhD, PE, MEM For more information visit https://clydelettsome.com/blog/2019/12/18/my-weekend-project-audio-frequency-detector-using-an-arduino/ */ #include "arduinoFFT.h" #include <Wire.h> #include <VL53L0X.h> #include <LiquidCrystal_I2C.h> #define SAMPLES 128 //SAMPLES-pt FFT. Must be a base 2 number. Max 128 for Arduino Uno. #define SAMPLING_FREQUENCY 3000 //Ts = Based on Nyquist, must be 2 times the highest expected frequency. #define PIEZO_PIN 5 // Pin connected to the piezo buzzer. #define LIGHTVALVE 10 // digital pin connected to the light valve VL53L0X sensor; LiquidCrystal_I2C screen(0x27, 16, 2); arduinoFFT FFT = arduinoFFT(); unsigned int samplingPeriod; unsigned long microSeconds; unsigned long previousMillis; double vReal[SAMPLES]; //create vector of size SAMPLES to hold real values double vImag[SAMPLES]; //create vector of size SAMPLES to hold imaginary values int peak; int LCD_peak; void setup() { // FFT setup Serial.begin(115200); //Baud rate for the Serial Monitor samplingPeriod = round(1000000*(1.0/SAMPLING_FREQUENCY)); //Period in microseconds // TOF distance sensor setup delay(100); Wire.begin(); screen.init(); screen.backlight(); screen.home(); sensor.setTimeout(500); if (!sensor.init()) { Serial.println("Failed to detect and initialize sensor!"); while (1) {} } // Start continuous back-to-back mode (take readings as // fast as possible). To use continuous timed mode // instead, provide a desired inter-measurement period in // ms (e.g. sensor.startContinuous(100)). sensor.startContinuous(); previousMillis = millis(); peak = 0; LCD_peak = 0; } double fft() { /*Sample SAMPLES times*/ for(int i=0; i<SAMPLES; i++) { microSeconds = micros(); //Returns the number of microseconds since the Arduino board began running the current script. vReal[i] = analogRead(0); //Reads the value from analog pin 0 (A0), quantize it and save it as a real term. vImag[i] = 0; //Makes imaginary term 0 always /*remaining wait time between samples if necessary*/ while(micros() < (microSeconds + samplingPeriod)) { //do nothing } } /*Perform FFT on samples*/ FFT.Windowing(vReal, SAMPLES, FFT_WIN_TYP_HAMMING, FFT_FORWARD); FFT.Compute(vReal, vImag, SAMPLES, FFT_FORWARD); FFT.ComplexToMagnitude(vReal, vImag, SAMPLES); /*Find peak frequency and print peak*/ double new_peak = FFT.MajorPeak(vReal, SAMPLES, SAMPLING_FREQUENCY); long transparency; // print detected frequency to LCD screen. if (new_peak < 1000) { peak = new_peak; LCD_peak = map(peak, 865, 955, 0, 17); LCD_peak = constrain(LCD_peak, 0, 17); transparency = map(peak, 865, 955, 0, 17); //transparency = constrain(transparency, 0, 17); } else if (new_peak > 1190 && new_peak < 1410) { peak = new_peak; LCD_peak = map(peak, 1190, 1410, 17, 99); LCD_peak = constrain(LCD_peak, 17, 99); transparency = map(peak, 1190, 1410, 17, 99); //transparency = constrain(transparency, 17, 99); } /* int LCD_peak = map(peak, 850, 1500, 0, 99); LCD_peak = constrain(LCD_peak, 0, 99); */ screen.setCursor(6, 1); screen.print(LCD_peak); if (transparency < 0) { transparency = 0; } analogWrite(LIGHTVALVE, transparency); int LCD_transparency = map(transparency, 0, 120, 0, 99); LCD_transparency = constrain(LCD_transparency, 0, 99); screen.setCursor(12, 1); screen.print(LCD_peak); Serial.print("peak frequency: "); Serial.println(peak); //Print out the most dominant frequency. Serial.print("transparency: "); Serial.println(transparency); } void buzz() { // detect distance int distance = sensor.readRangeContinuousMillimeters(); // print to LCD screen screen.home(); screen.print("i:"); // map distance from 0-100 long LCD_distance = map(distance, 40, 210, 0, 99); LCD_distance = constrain(LCD_distance, 0, 99); screen.print(LCD_distance); //calculate piezo freq. based on distance int frequency; if (distance < 85) { frequency = map(distance, 40, 85, 290, 295); frequency = constrain(frequency, 290, 295); } else { frequency = map(distance, 85, 220, 315, 335); frequency = constrain(frequency, 315, 335); } tone(PIEZO_PIN, frequency); //print to LCD screen, column 6 row 0 screen.setCursor(6, 0); screen.print("m:"); // map frequency from 0 - 99; int LCD_frequency; if (frequency <= 295) { LCD_frequency = map(frequency, 290, 295, 0, 17); LCD_frequency = constrain(LCD_frequency, 0, 17); } else { LCD_frequency = map(frequency, 315, 335, 17, 99); LCD_frequency = constrain(LCD_frequency, 17, 99); } screen.print(LCD_frequency); if (sensor.timeoutOccurred()) { Serial.print(" TIMEOUT"); } } void loop() { // first generate a sound buzz(); // then read in the frequency fft(); // refresh the screen every half a second. unsigned long currentMillis = millis(); if (currentMillis - previousMillis > 500) { screen.clear(); previousMillis = currentMillis; } }