• If you are citizen of an European Union member nation, you may not use this service unless you are at least 16 years old.

  • You already know Dokkio is an AI-powered assistant to organize & manage your digital files & messages. Very soon, Dokkio will support Outlook as well as One Drive. Check it out today!

View
 

levitating water fountain

Page history last edited by Matt pinner 12 years, 9 months ago

How often do you get to see water defying gravity, which is outside the constraints of time and space? Not very often except in movies, but this cool levitating water display actually makes drops of water move up and down so slow that our eyes are able to watch them clearly!

 

This display is actually an optical illusion, as perfectly tuned strobe lights flashes at the water streams at specific frame rates similar to that of a projector to trick the human brain into thinking the water drops are actually moving up and down.

 

 

internally lit acrylic :

IMG_7032.JPG

 

 

 

IMG_0006.JPG

this thing is crossing from analog to digital... watch it go.

IMG_0007.JPG

 

 

 

here is the code:

 

 

/* 
 * tones and buttons and a pot
 *
 */
// lib to generate frequencies on any arduino digital pin
#include <TimerOne.h>

// pins defined
//
int tonePin = 9;
int ledPin = 13;
int buttonInPin[] = {4, 5, 6};
int buttonOutPin[] = {7, 8, 9};

boolean DEBUG = false;

//
// tone vars defined
//
//globals

int tones[] = {59, 60, 61};
int toneCount = 3;
int toneDuration = 1000; //ms
int toneDutyCycle = 72;

//
// button vars
//
//globals
int buttonCount = 3;
long debounceThreshold = 50; //ms
//loop vars
int state[] = {0, 0, 0};
int reading[] = {0, 0, 0};
long lastReading[] = {0, 0, 0}; //ms

// do this once
void setup () {
  if (DEBUG) Serial.begin(9600);
  for (int i = 0; i<buttonCount; i++) {
    pinMode(buttonInPin[i], INPUT);
    pinMode(buttonOutPin[i], OUTPUT);
    digitalWrite(buttonOutPin[i], HIGH);
  }

  pinMode(tonePin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  Timer1.initialize(calcPeriod(tones[1]));         // initialize timer1, and set a 1/2 second period
  Timer1.pwm(tonePin, toneDutyCycle);                // setup pwm on pin 9, 50% duty cycle
  Timer1.attachInterrupt(callback);  // attaches callback() as a timer overflow interrupt  
  
  return;
}


void callback()
{
  digitalWrite(ledPin, digitalRead(ledPin) ^ 1);
}

// do this everytime
void loop() {
  
  readButtons();
  writeButtons();
  saveReadings(); 

  return;  
}

//do this to read inputs into globals
void readButtons() {
  
  for (int i = 0; i<buttonCount; i++) {
    reading[i] = digitalRead(buttonInPin[i]);
    
    if (reading[i] != state[i]) {
      // reset the debouncing timer
      lastReading[i] = millis();
    } 
    
    if ((millis() - lastReading[i]) > debounceThreshold) {
      state[i] = reading[i];
      if (state[i]) {
          setTone(tones[i % toneCount]);
        if (DEBUG) Serial.print("switching to ");
        if (DEBUG) Serial.println(tones[i % toneCount]);
      }
    }
  
  } // end button loop
  
  return;
}

// do this to react to latest settings
void writeButtons() {
  
  for (int i = 0; i<buttonCount; i++) {
    digitalWrite(buttonOutPin[i], state[i]); 
  }
  
  return;
}

// save state for next loop
void saveReadings() {
  
  for (int i = 0; i<buttonCount; i++) {
  // save the reading.  Next time through the loop,
  // it'll be the lastButtonState:
   state[i] = reading[i];
  }
  
  return; 
}

// calculates new tone period in micro seconds
// hardcoded to use A0 for fudge factor
int calcPeriod(int freq) {
  int absolute = 1000002 / freq;
  int reading =  analogRead(A0) - 512;
  return absolute - reading;
}


void setTone(int freq) {
  Timer1.pwm(tonePin, toneDutyCycle, calcPeriod(freq));
  return;
}

Comments (0)

You don't have permission to comment on this page.