Tag Archives: wedding

Maker Wedding: Animated HTML / jQuery wedding site


One of the projects I took on for our wedding was our official wedding website, I registered two domains, esterandphil.com as well as philandester.com thus avoiding any confusion. Both site pointed to the same page, for the general public a simple splash with a dynamic forest animation accomplished with the help of jQuery.

We wanted to create a page that connected with our venue which was in a barn on a conservation area. I’ve always enjoyed sine path algorithms so I created a scene where silhouetted trees scroll slowly by in a parallax-esc fashion and fuzzy Will-o’-the-wisp dots float lazily upward on sine waves. Randomly the wisps will be replaced with rain and visiting the site during the day versus during the night will result in different colours and songs.

The trees are selected randomly from one of six or seven images which then have a random amount of transparency and speed applied so that some seem further in the distance. Once they disappear off of one side they are recycled, animating in from the starting side again. Similarly the wisps have random factors applied to their size, speed, sine curve and alpha. The wisps are also interspersed on the z-axis to move in front of some trees while behind others adding to the illusion of depth. The wisps are also recycled once they’ve floated out of view.

On the live site I adjust the parameters for some popular clients, such as iOS for which I disabled animation and reduced the number of trees and wisps.

Inaccessible to the public is a guest site which used the splash page concept as a background with only the a couple of wisps animating with static trees (still randomly generated).

While this exact example is probably not portable verbatim you may find the method libraries I used as well as the technique useful. I have outlined some of the initializer functions below and linked to the libraries, some of which I have modified. The final library, animate.js, is almost completely custom code for this site and thus would have to be altered to suit your needs.

Will-o’-the-wisp Initialize

window.numberOfDots = 50;

for(i=0;i<window.numberOfDots;i++)
  window.dots.push(new dot(i));

Forest Initialize

window.numberOfTrees = 15;

for(i=0;i<window.numberOfTrees;i++)
  window.trees.push(new tree(i,'http://philandester.com/'));

Rain Initialize

var raincolor = '#fff';

new Rain('canvas', {
    speed: 500,
    angle: 20,
    intensity: 5,
    size: 10,
    color: raincolor
  });

Main Loop Start

setInterval(function(){sine()}, 25);

Raphael 1.5.2 – JavaScript Vector Library, MIT License (http://raphaeljs.com/)
http://philandester.com/rain.js

Andrew J. Peterson, NDP Software, MIT License (http://blog.ndpsoftware.com/)
http://philandester.com/colorfactory.js

Custom JavaScript Animation Library
http://philandester.com/animate.js

Maker Wedding: Thank you Edison-style light fixtures

Close to one year after our wedding, my wife Ester and I are, at long-last, sending out thank you packages. Having handcrafted the rustic Edison-style light fixtures for our wedding reception (with some much appreciated assembly line help from my Dad) we had hoped that we would be able to send those same lights to family and friends who not only shared with us and supported us on our wedding day, but support our family on a daily basis. In this way a light which helped to brighten our wedding festivities may continue to brighten, in some small way, the lives of our family and friends.

 
If you were part of our wedding, or lent your support, a package should be making its way to you. Postage services being what they are, if you have yet to receive a package by August, 2014, please let us know by sending an email to esterandphil [at] esterandphil [dot see oh ehm]. Those of you in Italy and in Australia will receive bulbs appropriately rated for 220-240 volts, while these weren’t in use at our wedding, rest assured that we’ll infuse them with loving and thankful vibes before sending them on their way.

These simple light fixtures were designed, selected from reclaimed barn wood (the Barn Board Store), cut, drilled, sanded and stained by Ester and I with our family and friends in mind — each one unique in character. The modest design allows for a number of use scenarios, it can be placed on a table or desk in virtually any orientation, the socket completing an a-frame support, or it can be wall mounted with the use of a corner bracket or two (not included) so that the light may hang through the hole in the fixture. Some uses require the plug to be threaded through the hole in the fixture, other uses require that the socket be connected to the light bulb through the hole in the fixture.

Lights delivered within North American will be 120 volts (Italy and Australia will be 220 volts). The switch is a 3-way, it will take two clicks to turn on the included bulb, however, should you replace the bulb with a 2-stage bulb (dim, bright) these clicks will toggle the brightness.

Thank you for all of your support, we hope you enjoy this small token of our appreciation. If you would like to share a photo of your light fixture once it’s settled in, we’d be delighted to see it! You can use the upload form below, or send it to esterandphil [at] esterandphil [dot see oh ehm].


 




 

Animated Arduino LED matrix lounge table top

Vinyl “flexi” record wedding invitations

XBee remote relay as photobooth RF camera trigger

Bachelor party wireless Arduino accelerometer Stab-O-Meter


JQuery Animated Wedding Website

A Maker Wedding

Initially I wasn’t sure how much our wedding was truly going to represent my fiancée and I, after all, we wanted our family and friends to enjoy themselves and feel included — as with any large event there are a lot of expectations to manage. After deciding to craft my own Edison-style light fixtures for our reception I realized that the occasion was, in addition to a celebration of our life-long commitment to each other, an opportunity for us to showcase our creativity and perhaps introduce some of our family and friends to aspects of ourselves they may not have known existed.

In retrospect we probably took on too much, but it allowed us to feel the occasion was a true reflection of ourselves — for me this meant soldering, stripping, crimping, twisting, programming and no small amount of brow furrowing. None of these projects could’ve come together without the help of my wonderful wife Ester, who not only said yes, but also collaborated throughout and trusted me to deliver on some very important aspects of our big day. In addition, a big thanks to my dear old Dad who took time to help me with the lengthy task of wiring the Edison fixtures and to the friends and family who helped us setup and teardown these, and other installations.

Animated Arduino LED matrix lounge table top

Vinyl “flexi” record wedding invitations

XBee remote relay as photobooth RF camera trigger

Bachelor party wireless Arduino accelerometer Stab-O-Meter

JQuery Animated Wedding Website


Various puppet arms available at Obscura Antiques & Oddities, New York

Maker Wedding: Animated Arduino LED matrix lounge table top


Finally got around to making an LED table top, as it turns out — for my wedding reception. We decided to have a lounge area and an LED coffee table seemed like the perfect centerpiece for it. I decided instead of making a full table that I would make a table top that fit onto an existing ottoman. I affixed the LED strips to a plywood board which had a 2″ raised frame with aluminium duct tape, to help with brightness.

Arranging the LED’s in a proper matrix turned out to be quite a job as the strips I used came pre-wired and there isn’t all that much length between LED’s on the strip. I ended up having to cut and re-splice the connection leads for each row of the 7 x 7 matrix, after that the construction went quickly. You could get around this by using a more modular LED strip solution, I initially had ShiftBrites slated for this project, but I made something else with them and when I got around to this table top there were much less expensive options available.

I created an outer frame with a bevel to support a glass top. Initially I went with plexiglass but it would bow in the middle with anything of weight on the table, I didn’t want to add supports as this would disrupt the light diffusion, so I opted for a piece of tempered glass (actually intended for table tops to boot).

Adding adhesive obscuring film to the glass didn’t have the diffusion effect I’d hoped for so I sandwiched a sheet of white tracing paper between the tempered glass and a similarly sized piece of plexiglass and this gave the soft white diffused look I wanted.

The issue of programming the animations took a little longer. I wanted to use the disco(esc) animations available from the fine folks responsible for the 1E Disco Dance Floor — which I also used in my ohDisco! app for iPad. These animations are 32 x 16 and can have hundreds of frames — too much to load completely into the Arduino’s memory. But I didn’t want to have to deal with reducing the animations to 7 x 7, or reducing their total frame count, as this would affect the quality and overall impression. Instead I opted to add an SD card reader to the setup which stores the animations. The 7 x 7 section of each frame is loaded on-demand from each animation file and displayed on the table, with this setup the Arduino has no memory problems whatsoever and with a little more code it could index and play animations from the SD card without the need for code changes.

Worth noting is that the SdFat library used to interface with the Seeedstudio SD Card Shield wouldn’t run reliably (or at all sometimes) on an ATmega128 so be sure to use a more powerful Arduino running an ATmega328.

Parts

Arduino Sketch


const int chipSelect = 10;

#include <SdFat.h>
#include "SPI.h"
#include "Adafruit_WS2801.h"

uint8_t dataPin  = 2;
uint8_t clockPin = 3;   

SdFat sd;
SdFile myFile;

int rows = 32;
int cols = 16;

long framesize = rows*cols*3;
long rowsize = cols*3;

int ledrows = 6;
int ledcols = 6;

int rep = 0;
long reps = 5;

int brightness = 15;
int delaytime = 40;

char* files[]={
  "pulsar.ddf",
  "snake.ddf",
  "inter3.ddf",
  "inter4.ddf",
  "inter5.ddf",
  "rings.ddf",
  "rings2.ddf",
  "rings3.ddf",
  "matrix.ddf"
  };

int fileCount = 9;

char* file;
int frame = 0;
int frames;

Adafruit_WS2801 strip = Adafruit_WS2801(50, dataPin, clockPin);

// strip to matrix addressing array
byte addressMatrix[7][7] = {
  1,2,3,4,5,6,7,
  14,13,12,11,10,9,8,
  15,16,17,18,19,20,21,
  28,27,26,25,24,23,22,
  29,30,31,32,33,34,35,
  42,41,40,39,38,37,36,
  43,44,45,46,47,48,49
};

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(0));
  delay(400);  // catch Due reset problem
  if (!sd.begin(chipSelect, SPI_FULL_SPEED))
    sd.initErrorHalt();

  file = files[ random(fileCount) ];

  strip.begin();
  strip.setPixelColor(0, 0, 0, 0);
  strip.show();
}

void loop() {
  if (!myFile.open(file, O_READ)) {
    sd.errorHalt("failed");
    rep = reps + 1;
    return;
  }

  // seek to next frame
  if(myFile.fileSize() < ((frame*framesize)+1))
  {
    myFile.close(); 

    frame = 0;
    rep = rep + 1;

    if(rep > reps)
    {
      rep = 0;
      file = files[ random(fileCount) ];
      Serial.println(file);
    }

    return;
  }
  else
  {
    myFile.seekSet(frame*framesize);
  }

  // adjust reps for number of frames
  if(frame == 0)
  {
    frames = myFile.fileSize()/framesize;
    reps = 750/frames;
    Serial.println(frames,DEC);
    Serial.println(reps,DEC);
  }

  int data;

  int column = 0;
  int row = 0;

  while (row <= ledrows)
  {
    while (column <= ledcols)
    {
      data = myFile.read();
      // read red
      int r = map(data,0,255,0,255);
      // read green
      data = myFile.read();
      int g = map(data,0,255,0,255);
      // read blue
      data = myFile.read();
      int b = map(data,0,255,0,255);

      // set pixel address
      byte address = addressMatrix[row][column];

      // set pixel color
      strip.setPixelColor(address, map(r,0,255,0,brightness), map(g,0,255,0,brightness), map(b,0,255,0,brightness));

      // next column
      column = column + 1;
    }

    // reset column count
    column = 0;

    // increment row
    row = row + 1;

    // skip extra pixels
    myFile.seekSet((frame*framesize)+(row*rowsize));
  }

  // turn off first pixel (7x7 matrix, 1 unused pixel)
  strip.setPixelColor(0, 0, 0, 0);

  // send current frame to strip
  strip.show();

  // close the file
  myFile.close();

  // increment frame
  frame = frame + 1;

  // rest
  delay(delaytime);
}

Maker Wedding: Bachelor party wireless accelerometer Stab-O-Meter

Since I had disassembled the Wine-O-Meter I’d made for a friend’s bachelor party I needed to come up with something else for my own, I wanted to do an updated strongman competition. I decided to put together a wireless accelerometer to hopefully measure the speed and impact of various activities such as swinging a baseball bat, a sledgehammer, a hatchet, a tennis racket — get the idea? Sort of like the measurement tools used on shows like MythBusters or Deadliest Warrior. Along the lines of the Wine-O-Meter I dubbed the project the Stab-O-Meter as measuring arm movements reminded me of one of my favourite Futurama characters, Roberto.


My plan was to use an Arduino to read an accelerometer and use a pair of XBees to wireless relay the information to a laptop. The laptop would be running a Processing sketch to handle the high score display, reset and current readings. It took a little bit to find the right Arudino code to read the LIS331 Triple Axis Accelerometer I’d selected but it worked well once I found it. I don’t know a whole heck of a lot about accelerometers, but this one measures g-forces on three axis, x, y and z. After some trial and error I decided to add all positive g-force readings together and then add all negative g-force readings together. If the positive total was higher I used that as the current amalgamated reading otherwise I used the absolute sum of the negative values. Comment if you’re aware of a better way to translate x, y, z g-forces into a single number representing the speed of the motion (see Hank’s comment below).

Hank Cowdog

A neg X Acc means acc along the negative X axis. The magnitude of the acc is the important measurement, so a better approach would be to sum the squares of each X,Y,Z component and then take the square root (as per the Pythagorean Theorem). This computes the magnitude of the Acc regardless of the direction (or orientation of the accelerometer chips).

result = sqrt(xAcc*xAcc + yAcc*yAcc + zAcc*zAcc);


The Arduino sent the single number amalgamated reading in realtime (or as close as possible) via it’s serial connection to a XBee which in turn wirelessly relayed the serial data to a laptop running a processing sketch to read and deal with the data. The Processing sketch displayed a realtime reading bar on the right, the highest reading yet recorded in large numbers in the center and a RESET button to clear the current highest reading. With this system each contestant could reset the high score using the RESET button or the spacebar and the proceed to swing a bat or stab a tree or whatnot to find they’re personal best, which was then ranked against other’s scores on a white board.

This part worked great, however in impact scenarios (actually hitting something) it was too easy to max out the sensor, which has a max of 24g, so we restricted our games to non-impact swings. I had added hand wrap to the sensor case in order to secure it to the implement of choice, however I quickly realized that it also needed a non-slip surface for grip, I epoxied some rubber salvaged from a guitar effect pedal. Even with the hand wrap and the rubber footing the first full-force swing with a baseball bat sent the sensor soaring into a neighbouring house — duct tape provided the necessary upgrade in grip, but downgrade in polish.

The video below is, aside from my Roberto impression, an early test using a preliminary Processing sketch and no cases for the components. When I get a chance I’ll record a video of the finished setup, perhaps as I demolish my garage this weekend. Yes, it’s an odd video, but that’s what YouTube is for, right?

Parts

Arduino Sketch

// 3-axis Accelerometer
// Sparkfun Electronics Triple Axis Accelerometer Breakout - LIS331
// Arduino UNO

/* Wiring:
    UNO LIS331

    3.3V VCC
    GND GND
    10 CS
    11 SDA/SDI
    12 SA0/SDO
    13 SCL/SPC
    */

#include <SPI.h>
#include <stdlib.h>
#include <stdio.h>

#define SS 10 // Serial Select -> CS on LIS331
#define MOSI 11 // MasterOutSlaveIn -> SDI
#define MISO 12 // MasterInSlaveOut -> SDO
#define SCK 13 // Serial Clock -> SPC on LIS331

#define SCALE 0.0007324; // approximate scale factor for full range (+/-24g)
// scale factor: +/-24g = 48G range. 2^16 bits. 48/65536 = 0.0007324

// global acceleration values
double xAcc, yAcc, zAcc;

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

  // Configure SPI
  SPI_SETUP();

  // Configure accelerometer
  Accelerometer_Setup();
}

void loop()
{
  readVal(); // get acc values and put into global variables

  int pos = 0;
  int neg = 0;

  if(xAcc > 0)
  {
    pos = pos + xAcc;
  }
  else
  {
    neg = neg + abs(xAcc);
  }

  if(yAcc > 0)
  {
    pos = pos + yAcc;
  }
  else
  {
    neg = neg + abs(yAcc);
  }

  if(zAcc > 0)
  {
    pos = pos + zAcc;
  }
  else
  {
    neg = neg + abs(zAcc);
  }

  int result = neg;

  if(pos > neg)
    result = pos;

  Serial.println(result,1);

   /*
    Serial.print(xAcc, 1);
    Serial.print(",");
    Serial.print(yAcc, 1);
    Serial.print(",");
    Serial.println(zAcc, 1);
  */

  delay(10);
}

// Read the accelerometer data and put values into global variables
void readVal()
{
  byte xAddressByteL = 0x28; // Low Byte of X value (the first data register)
  byte readBit = B10000000; // bit 0 (MSB) HIGH means read register
  byte incrementBit = B01000000; // bit 1 HIGH means keep incrementing registers
  // this allows us to keep reading the data registers by pushing an empty byte
  byte dataByte = xAddressByteL | readBit | incrementBit;
  byte b0 = 0x0; // an empty byte, to increment to subsequent registers

  digitalWrite(SS, LOW); // SS must be LOW to communicate
  delay(1);
  SPI.transfer(dataByte); // request a read, starting at X low byte
  byte xL = SPI.transfer(b0); // get the low byte of X data
  byte xH = SPI.transfer(b0); // get the high byte of X data
  byte yL = SPI.transfer(b0); // get the low byte of Y data
  byte yH = SPI.transfer(b0); // get the high byte of Y data
  byte zL = SPI.transfer(b0); // get the low byte of Z data
  byte zH = SPI.transfer(b0); // get the high byte of Z data
  delay(1);
  digitalWrite(SS, HIGH);

  // shift the high byte left 8 bits and merge the high and low
  int xVal = (xL | (xH <<8));
  int yVal = (yL | (yH <<8));
  int zVal = (zL | (zH <<8));

  // scale the values into G's
  xAcc = xVal * SCALE;
  yAcc = yVal * SCALE;
  zAcc = zVal * SCALE;
}

void SPI_SETUP()
{
  pinMode(SS, OUTPUT);

  // wake up the SPI bus
  SPI.begin();

  // This device reads MSB first:
  SPI.setBitOrder(MSBFIRST);

  /*
  SPI.setDataMode()
  Mode    Clock Polarity (CPOL) Clock Phase (CPHA)
  SPI_MODE0    0    0
  SPI_MODE1    0    1
  SPI_MODE2    1    0
  SPI_MODE3    1    1
  */
  SPI.setDataMode(SPI_MODE0);

  /*
  SPI.setClockDivider()
  sets SPI clock to a fraction of the system clock
  Arduino UNO system clock = 16 MHz
  Mode SPI Clock
  SPI_CLOCK_DIV2 8 MHz
  SPI_CLOCK_DIV4 4 MHz
  SPI_CLOCK_DIV8 2 MHz
  SPI_CLOCK_DIV16 1 MHz
  SPI_CLOCK_DIV32 500 Hz
  SPI_CLOCK_DIV64 250 Hz
  SPI_CLOCK_DIV128 125 Hz
  */

  SPI.setClockDivider(SPI_CLOCK_DIV16); // SPI clock 1000Hz
}

void Accelerometer_Setup()
{
  // Set up the accelerometer
  // write to Control register 1: address 20h
  byte addressByte = 0x20;
  /* Bits:
  PM2 PM1 PM0 DR1 DR0 Zen Yen Xen
  PM2PM1PM0: Power mode (001 = Normal Mode)
  DR1DR0: Data rate (00=50Hz, 01=100Hz, 10=400Hz, 11=1000Hz)
  Zen, Yen, Xen: Z enable, Y enable, X enable
  */
  byte ctrlRegByte = 0x37; // 00111111 : normal mode, 1000Hz, xyz enabled

  // Send the data for Control Register 1
  digitalWrite(SS, LOW);
  delay(1);
  SPI.transfer(addressByte);
  SPI.transfer(ctrlRegByte);
  delay(1);
  digitalWrite(SS, HIGH);

  delay(100);

  // write to Control Register 2: address 21h
  addressByte = 0x21;
  // This register configures high pass filter
  ctrlRegByte = 0x00; // High pass filter off

  // Send the data for Control Register 2
  digitalWrite(SS, LOW);
  delay(1);
  SPI.transfer(addressByte);
  SPI.transfer(ctrlRegByte);
  delay(1);
  digitalWrite(SS, HIGH);

  delay(100);

  // Control Register 3 configures Interrupts
  // Since I'm not using Interrupts, I'll leave it alone

  // write to Control Register 4: address 23h
  addressByte = 0x23;
  /* Bits:
  BDU BLE FS1 FS0 STsign 0 ST SIM
  BDU: Block data update (0=continuous update)
  BLE: Big/little endian data (0=accel data LSB at LOW address)
  FS1FS0: Full-scale selection (00 = +/-6G, 01 = +/-12G, 11 = +/-24G)
  STsign: selft-test sign (default 0=plus)
  ST: self-test enable (default 0=disabled)
  SIM: SPI mode selection(default 0=4 wire interface, 1=3 wire interface)
  */
  ctrlRegByte = 0x30; // 00110000 : 24G (full scale)

  // Send the data for Control Register 4
  digitalWrite(SS, LOW);
  delay(1);
  SPI.transfer(addressByte);
  SPI.transfer(ctrlRegByte);
  delay(1);
  digitalWrite(SS, HIGH);
}

Processing Sketch

 import pitaru.sonia_v2_9.*;
 import processing.serial.*;

 Sample beep;

 float high;
 int count;

 int inside = -1;
 int bx=850; // position in X of the up corner of the botton
 int by=460; // position in Y of the up corner of the botton
 int h=40;
 int w=100;

 float inByte=0;
 float drawByte=0;

 PFont f;

 Serial myPort;         // The serial port
 int xPos = 10;         // horizontal position of the graph

public void stop()
{
  Sonia.stop();
  super.stop();
}

 void setup () {
   // set the window size:
   size(1024, 550);

   high = 0;
   count = 0;

   f = createFont("Verdana",6,true);

   // List all the available serial ports
   println(Serial.list());
   // I know that the first port in the serial list on my mac
   // is always my  Arduino, so I open Serial.list()[0].
   // Open whatever port is the one you're using.
   myPort = new Serial(this, Serial.list()[0], 9600);
   // don't generate a serialEvent() unless you get a newline character:
   myPort.bufferUntil('\n');
   // set inital background:
   background(0);

  Sonia.start(this);
  beep = new Sample( "beep-02.wav" );
 }

void draw()
{
  if(keyPressed)
  {
    if(key == ' ')
    {
      high = inByte;
    }
  }

  background(0);

  //stroke(255,0,0);
  rect(xPos, 500 - inByte, xPos+20, inByte);

  textFont(f,25);
  fill(255);
  text(inByte, xPos - 10, 500 - inByte - 25);

  count = count + 1;

  if(count > 2)
  {
    count = 0;

    if(drawByte < high - 200)
    {
     beep.play();
     drawByte = drawByte + 100;
    }
    else if(drawByte < high - 10)
    {
       beep.play();
       drawByte = drawByte + 10;
    }
    else if(drawByte < high - 1)
    {
      beep.play();
      drawByte = drawByte + 1;
    }
    else if(drawByte < high - .1)
    {
      beep.play();
      drawByte = drawByte + .1;
    }
    else if(drawByte < high - .01)
    {
      beep.play();
      drawByte = drawByte + .01;
    }
    else if(drawByte < high - .001)
    {
      beep.play();
      drawByte = drawByte + .001;
    }
    else if(drawByte < high)
    {
      drawByte = high;
    }
  }

  if(drawByte > high)
  {
    drawByte = high;
  }

  textFont(f,140);
  fill(255);
  text(drawByte, 200, 325);

  rect(bx,by,w,h); // Button 

  textFont(f,25);
  fill(0);
  text("RESET", bx+10, by+30);
  fill(255);
}

void mousePressed(){
  if(!(((mouseX > (bx+w))
  ||(mouseY > (by+h)))
  ||((mouseX < bx)
  ||(mouseY < by))))
  {
      high = inByte;
  }
}

void serialEvent (Serial myPort) {
   String inString = myPort.readStringUntil('\n');

   if (inString != null)
   {
     // trim off any whitespace:
     inString = trim(inString);
     // convert to an int and map to the screen height:
     inByte = float(inString);
     inByte = map(inByte, 0, 1023, 0, 500);

     if(inByte > high)
     {
       high = inByte;
     }
   }
 }