Rusty Trombone

The Muses of Ancient Greece are dead and gone, and I’ve discovered why.

The concept is simple: buttons for tones, distance sensor for modulation.

Schematic:

Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
/* Name: Jan
Project: Rusty Trombone
*/
// keeping track of button input pins
int buttonPins[] = {A1, A2, A4, A5};
int buttonRed = A1;
int buttonGreen = A2;
int buttonYellow = A4;
int buttonBlue = A5;
// distance sensor pins
int pinTrigger = 9;
int pinEcho = 8;
// buzzer pins
int buzzer = 12;
// keeping track of base tones {C, E, G, A}
float baseNotes[] = {262, 330, 392, 440};
//difference between semitones, for use with modulation
float semitone = 15;
float modulation = 0;
float inches;
int fret = 1;
void setup() {
Serial.begin(9600);
//initializing pins
pinMode(buzzer, OUTPUT);
pinMode(pinTrigger, OUTPUT);
pinMode(pinEcho, INPUT);
//setting the buttons to INPUT_PULLUP means i don't have to worry about pull down resistors clogging up my board
pinMode(buttonRed, INPUT_PULLUP);
pinMode(buttonGreen, INPUT_PULLUP);
pinMode(buttonYellow, INPUT_PULLUP);
pinMode(buttonBlue, INPUT_PULLUP);
}
void loop() {
fret = 0;
bool buttonPressed = 0;
inches = getDistance();
for (int i = 0; i < 20; i+=2) {
fret++;
if (inches < i) {
modulation = semitone * fret;
break;
}
}
if (digitalRead(buttonRed) == LOW) { //if the first key is pressed
tone(buzzer, 262 + modulation);
Serial.println(inches);
}
else if (digitalRead(buttonGreen) == LOW) { //if the second key is pressed
tone(buzzer, 330 + modulation);
}
else if (digitalRead(buttonYellow) == LOW) { //if the third key is pressed
tone(buzzer, 392 + modulation);
}
else if (digitalRead(buttonBlue) == LOW) {
tone(buzzer, 440 + modulation);
}
else {
noTone(buzzer); //if no key is pressed turn the buzzer off
}
}
float getDistance()
{
float echoTime; //variable to store the time it takes for a ping to bounce off an object
float calculatedDistance; //variable to store the distance calculated from the echo time
//send out an ultrasonic pulse that's 10ms long
digitalWrite(pinTrigger, HIGH);
delayMicroseconds(1);
digitalWrite(pinTrigger, LOW);
echoTime = pulseIn(pinEcho, HIGH); //use the pulsein command to see how long it takes for the
//pulse to bounce back to the sensor
calculatedDistance = echoTime / 148.0; //calculate the distance of the object that reflected the pulse (half the bounce time multiplied by the speed of sound)
return calculatedDistance; //send back the distance that was calculated
}
/* Name: Jan Project: Rusty Trombone */ // keeping track of button input pins int buttonPins[] = {A1, A2, A4, A5}; int buttonRed = A1; int buttonGreen = A2; int buttonYellow = A4; int buttonBlue = A5; // distance sensor pins int pinTrigger = 9; int pinEcho = 8; // buzzer pins int buzzer = 12; // keeping track of base tones {C, E, G, A} float baseNotes[] = {262, 330, 392, 440}; //difference between semitones, for use with modulation float semitone = 15; float modulation = 0; float inches; int fret = 1; void setup() { Serial.begin(9600); //initializing pins pinMode(buzzer, OUTPUT); pinMode(pinTrigger, OUTPUT); pinMode(pinEcho, INPUT); //setting the buttons to INPUT_PULLUP means i don't have to worry about pull down resistors clogging up my board pinMode(buttonRed, INPUT_PULLUP); pinMode(buttonGreen, INPUT_PULLUP); pinMode(buttonYellow, INPUT_PULLUP); pinMode(buttonBlue, INPUT_PULLUP); } void loop() { fret = 0; bool buttonPressed = 0; inches = getDistance(); for (int i = 0; i < 20; i+=2) { fret++; if (inches < i) { modulation = semitone * fret; break; } } if (digitalRead(buttonRed) == LOW) { //if the first key is pressed tone(buzzer, 262 + modulation); Serial.println(inches); } else if (digitalRead(buttonGreen) == LOW) { //if the second key is pressed tone(buzzer, 330 + modulation); } else if (digitalRead(buttonYellow) == LOW) { //if the third key is pressed tone(buzzer, 392 + modulation); } else if (digitalRead(buttonBlue) == LOW) { tone(buzzer, 440 + modulation); } else { noTone(buzzer); //if no key is pressed turn the buzzer off } } float getDistance() { float echoTime; //variable to store the time it takes for a ping to bounce off an object float calculatedDistance; //variable to store the distance calculated from the echo time //send out an ultrasonic pulse that's 10ms long digitalWrite(pinTrigger, HIGH); delayMicroseconds(1); digitalWrite(pinTrigger, LOW); echoTime = pulseIn(pinEcho, HIGH); //use the pulsein command to see how long it takes for the //pulse to bounce back to the sensor calculatedDistance = echoTime / 148.0; //calculate the distance of the object that reflected the pulse (half the bounce time multiplied by the speed of sound) return calculatedDistance; //send back the distance that was calculated }
/* Name: Jan
   Project: Rusty Trombone

*/

// keeping track of button input pins
int buttonPins[] = {A1, A2, A4, A5};
int buttonRed = A1;
int buttonGreen = A2;
int buttonYellow = A4;
int buttonBlue = A5;

// distance sensor pins
int pinTrigger = 9;
int pinEcho = 8;

// buzzer pins
int buzzer = 12;

// keeping track of base tones {C, E, G, A}
float baseNotes[] = {262, 330, 392, 440};

//difference between semitones, for use with modulation
float semitone = 15;

float modulation = 0;
float inches;
int fret = 1;

void setup() {
  
  Serial.begin(9600);

  //initializing pins
  pinMode(buzzer, OUTPUT);
  
  pinMode(pinTrigger, OUTPUT);
  pinMode(pinEcho, INPUT);

  //setting the buttons to INPUT_PULLUP means i don't have to worry about pull down resistors clogging up my board
  pinMode(buttonRed, INPUT_PULLUP);
  pinMode(buttonGreen, INPUT_PULLUP);
  pinMode(buttonYellow, INPUT_PULLUP);
  pinMode(buttonBlue, INPUT_PULLUP);

}

void loop() {
  fret = 0;
  bool buttonPressed = 0;
  inches = getDistance();
  for (int i = 0; i < 20; i+=2) {
    fret++;
    if (inches < i) {
      modulation = semitone * fret;
      break;
    }
  }

  if (digitalRead(buttonRed) == LOW) {      //if the first key is pressed
    tone(buzzer, 262 + modulation); 
    Serial.println(inches);                 
  }
  else if (digitalRead(buttonGreen) == LOW) { //if the second key is pressed
    tone(buzzer, 330 + modulation);                   
  }
  else if (digitalRead(buttonYellow) == LOW) { //if the third key is pressed
    tone(buzzer, 392 + modulation);                    
  }
  else if (digitalRead(buttonBlue) == LOW) {
    tone(buzzer, 440 + modulation);
  }
  
  else {
    noTone(buzzer);                        //if no key is pressed turn the buzzer off
  }
}


float getDistance()
{
  float echoTime;                   //variable to store the time it takes for a ping to bounce off an object
  float calculatedDistance;         //variable to store the distance calculated from the echo time

  //send out an ultrasonic pulse that's 10ms long
  digitalWrite(pinTrigger, HIGH);
  delayMicroseconds(1);
  digitalWrite(pinTrigger, LOW);

  echoTime = pulseIn(pinEcho, HIGH);      //use the pulsein command to see how long it takes for the
                                          //pulse to bounce back to the sensor

  calculatedDistance = echoTime / 148.0;  //calculate the distance of the object that reflected the pulse (half the bounce time multiplied by the speed of sound)


  return calculatedDistance;              //send back the distance that was calculated
}

Evidence of My Crimes

Reflections: Code as is requires a lot of fine-tuning for the buzzer not to sound like it’s gently caressing a combine harvester. More specifically, changing the changes in tone from continuous to discrete kept the buzzing down. Tweaking the distance intervals at which the tone goes up or down a semitone keeps it from oscillating too much, as might changing how often the tone sounds. The equation for calculating distance from the sensor also has a lot of room for tuning, but I have not the hubris to claim to be a master of time nor space. Fun project though, had a blast.

Assignment 3: Double Trouble

This is a simplistic extension of the wall bouncing puzzle shown in last class. The goal is twofold: make the ball bounce in a third dimension, and make the ball duplicate.

Code:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
let gCircleSizeMax = 60;
let gCircleSizeMin = 10;
let gXSpeed = 2;
let gYSpeed = 4;
let gZSpeed = 1;
let gCircleArray = [];
let circlesMade = 0;
class BouncingCircle {
constructor(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID) {
this.x = xpos;
this.y = ypos;
this.xSpeed = xSpeed;
this.ySpeed = ySpeed;
this.zSpeed = zSpeed;
this.circleSize = circleSize;
this.ID = ID;
}
//give ball speed
update() {
this.x += this.xSpeed;
this.y += this.ySpeed;
this.circleSize += this.zSpeed;
}
checkWallCollisions() {
let r = this.circleSize / 2;
if (this.x < r || this.x > width - r) {
this.xSpeed = -this.xSpeed;
}
if (this.y < r || this.y > height - r) {
this.ySpeed = -this.ySpeed;
}
}
checkBounce() {
if (this.circleSize <= gCircleSizeMin) {
if (this.xSpeed > 0 || this.ySpeed > 0 ) {
this.zSpeed = -99/100 * this.zSpeed;
this.xSpeed = 99/100 * this.xSpeed;
this.ySpeed = 99/100 * this.ySpeed;
if (this.zSpeed > gZSpeed/2) {
duplicate(this)
}
}
else {
//this.zSpeed = 0;
//gCircleArray.splice(circle.ID, 1);
}
}
if (this.circleSize >= gCircleSizeMax) {
this.zSpeed = -this.zSpeed;
}
}
drawSelf() {
fill(255);
ellipse(this.x, this.y, this.circleSize, this.circleSize);
}
}
function duplicate(circle) {
//if (circlesMade < 4) {
//if (random(100) > 50) {
print("Double Trouble")
let xpos = circle.x;
if (xpos > width - gCircleSizeMax)
xpos = width - gCircleSizeMax
if (xpos < gCircleSizeMax)
xpos = gCircleSizeMax
let ypos = circle.y;
if (ypos > height - gCircleSizeMax)
ypos = height - gCircleSizeMax;
if (ypos < gCircleSizeMax)
ypos = gCircleSizeMax;
let xSpeed = circle.ySpeed;
let ySpeed = circle.xSpeed;
let zSpeed = gZSpeed;
let circleSize = gCircleSizeMin + 5;
let ID = gCircleArray.length;
let newCircle = new BouncingCircle(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID)
gCircleArray.push(newCircle);
print(gCircleArray);
circlesMade++
//}
//}
if (gCircleArray.length >= 25) {
gCircleArray.splice(0, gCircleArray.length / 2)
}
}
function setup() {
gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
createCanvas(400, 400);
smooth();
}
function draw() {
background(0);
for (var i = 0; i < gCircleArray.length; i++) {
gCircleArray[i].update();
gCircleArray[i].drawSelf();
gCircleArray[i].checkWallCollisions();
gCircleArray[i].checkBounce();
}
if (gCircleArray.length == 0) {
gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
}
circlesMade = 0
}
let gCircleSizeMax = 60; let gCircleSizeMin = 10; let gXSpeed = 2; let gYSpeed = 4; let gZSpeed = 1; let gCircleArray = []; let circlesMade = 0; class BouncingCircle { constructor(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID) { this.x = xpos; this.y = ypos; this.xSpeed = xSpeed; this.ySpeed = ySpeed; this.zSpeed = zSpeed; this.circleSize = circleSize; this.ID = ID; } //give ball speed update() { this.x += this.xSpeed; this.y += this.ySpeed; this.circleSize += this.zSpeed; } checkWallCollisions() { let r = this.circleSize / 2; if (this.x < r || this.x > width - r) { this.xSpeed = -this.xSpeed; } if (this.y < r || this.y > height - r) { this.ySpeed = -this.ySpeed; } } checkBounce() { if (this.circleSize <= gCircleSizeMin) { if (this.xSpeed > 0 || this.ySpeed > 0 ) { this.zSpeed = -99/100 * this.zSpeed; this.xSpeed = 99/100 * this.xSpeed; this.ySpeed = 99/100 * this.ySpeed; if (this.zSpeed > gZSpeed/2) { duplicate(this) } } else { //this.zSpeed = 0; //gCircleArray.splice(circle.ID, 1); } } if (this.circleSize >= gCircleSizeMax) { this.zSpeed = -this.zSpeed; } } drawSelf() { fill(255); ellipse(this.x, this.y, this.circleSize, this.circleSize); } } function duplicate(circle) { //if (circlesMade < 4) { //if (random(100) > 50) { print("Double Trouble") let xpos = circle.x; if (xpos > width - gCircleSizeMax) xpos = width - gCircleSizeMax if (xpos < gCircleSizeMax) xpos = gCircleSizeMax let ypos = circle.y; if (ypos > height - gCircleSizeMax) ypos = height - gCircleSizeMax; if (ypos < gCircleSizeMax) ypos = gCircleSizeMax; let xSpeed = circle.ySpeed; let ySpeed = circle.xSpeed; let zSpeed = gZSpeed; let circleSize = gCircleSizeMin + 5; let ID = gCircleArray.length; let newCircle = new BouncingCircle(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID) gCircleArray.push(newCircle); print(gCircleArray); circlesMade++ //} //} if (gCircleArray.length >= 25) { gCircleArray.splice(0, gCircleArray.length / 2) } } function setup() { gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0)); createCanvas(400, 400); smooth(); } function draw() { background(0); for (var i = 0; i < gCircleArray.length; i++) { gCircleArray[i].update(); gCircleArray[i].drawSelf(); gCircleArray[i].checkWallCollisions(); gCircleArray[i].checkBounce(); } if (gCircleArray.length == 0) { gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0)); } circlesMade = 0 }
let gCircleSizeMax = 60;
let gCircleSizeMin = 10;
let gXSpeed = 2;
let gYSpeed = 4;
let gZSpeed = 1;

let gCircleArray = [];
let circlesMade = 0;

class BouncingCircle {
  constructor(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID) {
    this.x = xpos;
    this.y = ypos;
    this.xSpeed = xSpeed;
    this.ySpeed = ySpeed;
    this.zSpeed = zSpeed;
    this.circleSize = circleSize;
    this.ID = ID;
  }
  //give ball speed
  update() {
    this.x += this.xSpeed;
    this.y += this.ySpeed;
    this.circleSize += this.zSpeed;
  }
  
  checkWallCollisions() {
    let r = this.circleSize / 2;
    if (this.x < r || this.x > width - r) {
      this.xSpeed = -this.xSpeed;
      
    }
    if (this.y < r || this.y > height - r) {
      this.ySpeed = -this.ySpeed;
    }
  }
  
  checkBounce() {
    if (this.circleSize <= gCircleSizeMin) {
      if (this.xSpeed > 0 || this.ySpeed > 0 ) {
        this.zSpeed = -99/100 * this.zSpeed;
        this.xSpeed = 99/100 * this.xSpeed;
        this.ySpeed = 99/100 * this.ySpeed;
        if (this.zSpeed > gZSpeed/2) {
          duplicate(this)
        }
        
      }
      else {
        //this.zSpeed = 0;
        //gCircleArray.splice(circle.ID, 1);
      } 
    }
    if (this.circleSize >= gCircleSizeMax) {
      this.zSpeed = -this.zSpeed;
    }
  }
  
  drawSelf() {
    fill(255);
    ellipse(this.x, this.y, this.circleSize, this.circleSize);
  }
  
}


function duplicate(circle) {
  //if (circlesMade < 4) {
  
    //if (random(100) > 50) {
      print("Double Trouble")

      let xpos = circle.x;
      if (xpos > width - gCircleSizeMax)
        xpos = width - gCircleSizeMax
      if (xpos < gCircleSizeMax)
        xpos = gCircleSizeMax

      let ypos = circle.y;
      if (ypos > height - gCircleSizeMax)
        ypos = height - gCircleSizeMax;
      if (ypos < gCircleSizeMax)
        ypos = gCircleSizeMax;

      let xSpeed = circle.ySpeed;
      let ySpeed = circle.xSpeed;
      let zSpeed = gZSpeed;
      let circleSize = gCircleSizeMin + 5;
      let ID = gCircleArray.length;

      let newCircle = new BouncingCircle(xpos, ypos, xSpeed, ySpeed, zSpeed, circleSize, ID)

      gCircleArray.push(newCircle);
      print(gCircleArray);
      
      circlesMade++
    //}
  //}
  
  if (gCircleArray.length >= 25) {
    gCircleArray.splice(0, gCircleArray.length / 2)
  }
  
  
}

function setup() {

  gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
  
  createCanvas(400, 400);
  smooth();
}

function draw() {
  background(0);
  
  for (var i = 0; i < gCircleArray.length; i++) {
    gCircleArray[i].update();
    gCircleArray[i].drawSelf();
    gCircleArray[i].checkWallCollisions();
    gCircleArray[i].checkBounce();
  }
  
  if (gCircleArray.length == 0) {
    gCircleArray.push(new BouncingCircle(25, 72, gXSpeed, gYSpeed, gZSpeed, 15, 0));
  }
  
  circlesMade = 0
  
}

Sketch: