Description

The device takes sound as an input and outputs light based on how loud the sound is. On one end is a microphone, which is the input. Based on how loud the sound picked up by the microphone is, a servo will turn a potentiometer a certain amount. Based on the position of the potentiometer, the LED will light up brighter or dimmer. In the end, louder sounds will lead to more light, while quieter sounds will lead to less light.

Demonstration:

Progress Videos

The progress videos of the input and output domains.

The overall layout of the project

Input Sound detector to detect the volume of the sound produced.

“Servometer” (servo coupled to  potentiometer)  controlled by the input from the sound volume. It rotates the potentiometer.

LED output to produce different variation of brightness as controlled by the input from potentiometer

Discussion

We’ll start with what was easy. Getting the input, output, and middle man wired up was probably the easiest part. The code wasn’t too difficult, but there was some tweaking needed in order to get the desired behavior (mostly tweaking the ranges).

One of the big challenges was actually assembling the middle man portion of the device; namely, coupling the servo motor to the potentiometer. At first, I tried just taping a horn to the potentiometer shaft, but that wasn’t reliable enough, and looked terrible. In the end, I 3D printed a shaft coupler made for an SG-90 hobby servo (what we used) and drilled a hole in the other end of it to friction-fit onto the potentiometer. That did the job.

Schematic

Code

/*
   Project 1
   Seth Geiser (sgeiser) and Olaitan Adisa (okadisa)

   Collaboration: Ola is my partner and she came up with the
   schematic and other ideas.
   Some references:
   
   https://courses.ideate.cmu.edu/60-223/s2020/tutorials/I2C-lcd
   https://courses.ideate.cmu.edu/60-223/s2020/reference/class-log#codebook-periodic-updating

   Challenge: The biggest challenge was coupling the servo to
   the potentiometer so that we could adjust the LED brightness.

   Next time: I don't know... keep going?

   Description: The purpose is to create a double-transducer. The
   input is sound, read by a sound detector. The sound reading
   triggers a servo (coupled to a potentiometer) to change its
   position, thus changing the potentiometer's position. This
   changes the brightness of the LED. Louder sounds should result
   in the LED emitting brighter light, and vice versa.

   Pin mapping:

   pin  | mode  | description
   -----|-------|------------
   A0     input   potentiometer
   A1     input   sound detector
   11     output  LED
   2      output  servo
   SDA/SCL        display

*/

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>
Servo myservo;

/*
   Create an LCD display object called "screen" with I2C address 0x27
   which is 16 columns wide and 2 rows tall.
*/

LiquidCrystal_I2C screen(0x27, 16, 2);

const int POTPIN = A0;
const int SOUNDPIN = A1;
const int LEDPIN = 11;
const int SERVOPIN = 2;

// "global" variables in this section can be used by any function in the whole sketch
float filtered_val = 0;  // this variable, of type float (decimal), holds the filtered sensor value
const float PREV_WEIGHT = 0.99; // this variable, of type float (decimal), determines the previously filtered value's weight.
const float CUR_WEIGHT = 1 - PREV_WEIGHT; // this variable, of type float (decimal), determines the current sample's weight.

unsigned long timer = 0; // variable for timing
const int INTERVAL = 250; // milliseconds between updates


void setup() {
  pinMode(POTPIN, INPUT);
  pinMode(SOUNDPIN, INPUT);
  pinMode(LEDPIN, OUTPUT);

  myservo.attach(SERVOPIN);
  screen.init();
  screen.backlight();
  screen.home();

  filtered_val = analogRead(SOUNDPIN);

}

void loop() {

  int soundValue = (float) analogRead(SOUNDPIN); // casting from int to float

  int soundValueLCD = map(soundValue, 0, 500, 0, 99);  // mapping first input (sound)to range 0-99

  filtered_val = filtered_val * PREV_WEIGHT + soundValue * CUR_WEIGHT;

  int servoPosition = map(filtered_val, 0, 400, 0, 180); // mapping sound values to range 0 - 180 degrees

  int servoValueLCD = map(servoPosition, 0, 180, 0, 99); // mapping first output (servo)to 0-99

  myservo.write(servoPosition);

  int potVal = analogRead(POTPIN);
  int potValueLCD = map(potVal, 1, 1024, 0, 99);

  int mapPotVal = map(potVal, 1, 1024, 0, 254);   // pot to LED values

  analogWrite(LEDPIN, mapPotVal);
  int ledValueLCD = map(mapPotVal, 0, 254, 0, 99);


  // updating the LCD output
  if (millis() >= timer) {
    screen.setCursor(0, 0);
    screen.print((String) "i:" + soundValueLCD);
    screen.setCursor(6, 0);
    screen.print((String) + "m:" + servoValueLCD);
    screen.setCursor(8, 1);
    screen.print((String) potValueLCD );
    screen.setCursor(12, 1);
    screen.print((String) "o:" + ledValueLCD);
    timer = millis() + INTERVAL; // and update timer
  }

}