Project tutorial
Motion-Activated Musical Trophy

Motion-Activated Musical Trophy © GPL3+

It looks like a normal trophy from the outside, but the slightest touch will cause this trophy to break out into song.

  • 1,665 views
  • 3 comments
  • 5 respects

Components and supplies

Mini Breadboard
Only one is necessary for this project.
×1
Microchip ATtiny85 DIP
These can be also be obtained at a much lower price from DigiKey. Only one is necessary for this project.
×1
Jumper Wires
×1
Adafruit industries ada1536 image
Buzzer
×1
Fast Vibration Switch
×1
Some Kind of Trophy
×1
61vhxtmzbyl
AA Batteries
×1
2xAA Battery Holder
×1
A000066 iso both
Arduino UNO & Genuino UNO
Used only for programming the ATtiny85
×1
Panasonic eca1hm2r2
Capacitor 10 µF
Used only for programming the ATtiny85
×1

Necessary tools and machines

09507 01
Soldering iron (generic)
Hy gluegun
Hot glue gun (generic)

Apps and online services

About this project

Everyone likes getting trophies. They're shiny, have a nice heft, and feel great to hold in your hand. They're visual and tactile, but decidedly lacking in the auditory department. Let's fix that, shall we?

The video above should give you a pretty good idea of just how sensitive you can get your circuit to be. Just the slightest motion causes it to break out in A-ha's Take On Me (sorry, I couldn't find an RTTL version of We Are the Champions).

Step 1

The first step in your path to musical trophy greatness is to prepare the vibration switch. I prefer the "fast" model, but if you don't want your circuit to be as sensitive you can order a medium or slow variant from Adafruit. Take the switch and solder a small piece of wire to the very thin wire coming out of the switch. This will allow us to put it in the breadboard.

To make the whole thing more rigid you can apply a small dollop of hot glue as shown in the photo. It also serves to insulate the two connections from each other. You're now ready to start wiring!

Step 2

The next thing to do is breadboard your circuit on your mini breadboard. If your AA battery holder has leads that cannot be stuck in the breadboard you may need to solder on some solid-core wire. The circuit diagram is shown above. It is also available at circuits.io.

Where the button is in the breadboard you're going to use the vibration switch. Connect one of the pins to ground and the other to pin 2 on the ATtiny.

Step 3

Now that you have your circuit wired you can upload the code to the ATtiny85. The Arduino file is in the "Attachments" section. This tutorial is a great resource that shows you how you can program your ATtiny with an Arduino Uno. Just make sure the AA batteries aren't connected when your Uno is connected! If you give the breadboard a shake the tune should start playing.

Some ATtiny cores do not come with the tone() function built-in, which is necessary for this project. I know for a fact that the following board manager URL core has it built in: https://raw.githubusercontent.com/damellis/attiny/ide-1.6.x-boards-manager/package_damellis_attiny_index.json. You can add this to your list of board managers URLs, then using the board manager install this ATtiny core.

A quick little side note here about power: the ATtiny is using something called pin change interrupts to save power. While the ATtiny is sleeping and waiting for an event from the vibration switch it's hardly using any power at all. In fact, your tiny can sleep for years on the power provided by those AAs. My multimeter isn't even sensitive enough to measure the tiny amount of current flowing through it! As shown in the YouTube video, the circuit draws about 6mA when active and making noise. Just turn on the batteries and forget about it!

Pin 2 is connected via software to a pull-up resistor, meaning that when there's no electrical connection between some voltage level (either 3v, ground, etc) the pin is "pulled" to a logic high, which in this case is about 3 volts. When the spring on the inside of the vibration switch comes into contact with the lead (the trophy is shaken), the pin is briefly pulled low, which triggers a pin change interrupt on the ATtiny. This then wakes it up from sleep. Cool, huh?

Step 4

Now that the wiring is done you can prepare the trophy! My particular one is a chess trophy that I won a few years ago - there's a small nut in the bottom that allows the whole thing to be disassembled. Pretty much any relatively large trophy will do. Start by taking yours apart.

In order to get the breadboard to fit I needed to cut away some of the internal support material of the trophy. This can be accomplished with a pair of scissors.

I then placed my breadboard and battery in the notch I cut and affixed the whole thing with some hot glue.

The rod running down the center of my trophy takes up a lot of space, so I decided to just scrap it and hot glue the whole trophy together. This thing is a lot weaker without that rod holding it together, so don't go dropping it. The hot glue is strong enough to allow you to shake the trophy vigorously, however.

Helpful Tidbits

That vibration switch is more sensitive along some axis than others. Take a look at the below image from Adafruit of the sensor cut open:

As you can see, the entire sensor is just a spring wrapped around a rigid lead. It's consequently more sensitive along the x-axis and y-axis than the z-axis, so plan your placement accordingly.

Going Further

Of course, Take on Me is not the only song you can play. The sketch attached in this thread has a ton of other songs. You can even create your own using an online MP3/MIDI to RTTL converter. In order to make your circuit much smaller you can scrap the breadboard and switch to a perfboard or a protoboard. This will also make the circuit much more resistant to breaking. You could even design a PCB to eliminate having to wire components! Thanks for reading, and let me know below if you end up making this!

Code

SoundTrophy.inoArduino
This is the sketch you will upload to your ATtiny
//Sketch produced by Alex Wulff (www.AlexWulff.com)
//RTTL Code written by Brett Hagman http://www.roguerobotics.com/
//Pin change interrupt code obtained from https://thewanderingengineer.com/2014/08/11/pin-change-interrupts-on-attiny85/
//Sleep code obtained from https://bigdanzblog.wordpress.com/2014/08/10/attiny85-wake-from-sleep-on-pin-state-change-code-example/

#include "avr/interrupt.h"
#include "avr/sleep.h"

const int speakerPin = 1;
const int vibPin = 3;

#define OCTAVE_OFFSET 0

int notes[] = { 0,
262, 277, 294, 311, 330, 349, 370, 392, 415, 440, 466, 494,
523, 554, 587, 622, 659, 698, 740, 784, 831, 880, 932, 988,
1047, 1109, 1175, 1245, 1319, 1397, 1480, 1568, 1661, 1760, 1865, 1976,
2093, 2217, 2349, 2489, 2637, 2794, 2960, 3136, 3322, 3520, 3729, 3951
};

const char *song = "TakeOnMe:d=4,o=4,b=160:8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5,8f#5,8e5,8f#5,8f#5,8f#5,8d5,8p,8b,8p,8e5,8p,8e5,8p,8e5,8g#5,8g#5,8a5,8b5,8a5,8a5,8a5,8e5,8p,8d5,8p,8f#5,8p,8f#5,8p,8f#5,8e5,8e5";
void setup(void)
{
  pinMode(vibPin, INPUT_PULLUP);
  pinMode(speakerPin, OUTPUT);
}

void loop(void)
{
  sleep();
  play_rtttl(song);
}

ISR(PCINT0_vect)
{
    //This is not needed for the current sketch
}

void sleep() {

    GIMSK |= _BV(PCIE);                     // Enable Pin Change Interrupts
    PCMSK |= _BV(PCINT3);                   // Use PB3 as interrupt pin
    ADCSRA &= ~_BV(ADEN);                   // ADC off
    set_sleep_mode(SLEEP_MODE_PWR_DOWN);    // replaces above statement

    sleep_enable();                         // Sets the Sleep Enable bit in the MCUCR Register (SE BIT)
    sei();                                  // Enable interrupts
    sleep_cpu();                            // sleep

    cli();                                  // Disable interrupts
    PCMSK &= ~_BV(PCINT3);                  // Turn off PB3 as interrupt pin
    sleep_disable();                        // Clear SE bit
    ADCSRA |= _BV(ADEN);                    // ADC on

    sei();                                  // Enable interrupts
} 

#define isdigit(n) (n >= '0' && n <= '9')

void play_rtttl(char *p)
{
  // Absolutely no error checking in here

  byte default_dur = 4;
  byte default_oct = 6;
  int bpm = 63;
  int num;
  long wholenote;
  long duration;
  byte note;
  byte scale;

  // format: d=N,o=N,b=NNN:
  // find the start (skip name, etc)

  while(*p != ':') p++;    // ignore name
  p++;                     // skip ':'

  // get default duration
  if(*p == 'd')
  {
    p++; p++;              // skip "d="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    if(num > 0) default_dur = num;
    p++;                   // skip comma
  }

  // get default octave
  if(*p == 'o')
  {
    p++; p++;              // skip "o="
    num = *p++ - '0';
    if(num >= 3 && num <=7) default_oct = num;
    p++;                   // skip comma
  }

  // get BPM
  if(*p == 'b')
  {
    p++; p++;              // skip "b="
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    bpm = num;
    p++;                   // skip colon
  }

  // BPM usually expresses the number of quarter notes per minute
  wholenote = (60 * 1000L / bpm) * 4;  // this is the time for whole note (in milliseconds)

  // now begin note loop
  while(*p)
  {
    // first, get note duration, if available
    num = 0;
    while(isdigit(*p))
    {
      num = (num * 10) + (*p++ - '0');
    }
    
    if(num) duration = wholenote / num;
    else duration = wholenote / default_dur;  // we will need to check if we are a dotted note after

    // now get the note
    note = 0;

    switch(*p)
    {
      case 'c':
        note = 1;
        break;
      case 'd':
        note = 3;
        break;
      case 'e':
        note = 5;
        break;
      case 'f':
        note = 6;
        break;
      case 'g':
        note = 8;
        break;
      case 'a':
        note = 10;
        break;
      case 'b':
        note = 12;
        break;
      case 'p':
      default:
        note = 0;
    }
    p++;

    // now, get optional '#' sharp
    if(*p == '#')
    {
      note++;
      p++;
    }

    // now, get optional '.' dotted note
    if(*p == '.')
    {
      duration += duration/2;
      p++;
    }
  
    // now, get scale
    if(isdigit(*p))
    {
      scale = *p - '0';
      p++;
    }
    else
    {
      scale = default_oct;
    }

    scale += OCTAVE_OFFSET;

    if(*p == ',')
      p++;       // skip comma for next note (or we may be at the end)

    // now play the note
    if(note)
    {
      freqout(notes[(scale - 4) * 12 + note], duration);      
    }
    else
    {
      delay(duration);
    }
  }
}

// freqout from http://www.arduino.cc/playground/Main/Freqout
void freqout(int freq, int t)  // freq in hz, t in ms
{
  int hperiod;                               //calculate 1/2 period in us
  long cycles, i;
  pinMode(speakerPin, OUTPUT);                   // turn on output pin

  hperiod = (500000 / freq) - 7;             // subtract 7 us to make up for digitalWrite overhead

  cycles = ((long)freq * (long)t) / 1000;    // calculate cycles

  for (i=0; i<= cycles; i++){              // play note for t ms 
    digitalWrite(speakerPin, HIGH); 
    delayMicroseconds(hperiod);
    digitalWrite(speakerPin, LOW); 
    delayMicroseconds(hperiod - 1);     // - 1 to make up for digitaWrite overhead
  }
pinMode(speakerPin, INPUT);                // shut off pin to avoid noise from other operations

}

Schematics

Breadboard Schematic

Comments

Similar projects you might like

The Annoy-O-Bug: A Chirping Light-Up Throwie

Project tutorial by Alex Wulff

  • 14,035 views
  • 16 comments
  • 54 respects

Xmas musical robot

Project showcase by benoitdr

  • 980 views
  • 0 comments
  • 2 respects

Mechanical Musical Arm

Project showcase by PIYUSH_K_SINGH

  • 920 views
  • 0 comments
  • 1 respect

3D-Printed RGB Wallet

Project tutorial by Alex Wulff

  • 1,989 views
  • 0 comments
  • 8 respects

Musical Cube

Project showcase by Team FabLab of Legends

  • 1,807 views
  • 0 comments
  • 1 respect

Integrated Solar ChargeController, Inverter, PowerBank, Lamp

Project tutorial by Shahariar

  • 12,053 views
  • 26 comments
  • 42 respects
Add projectSign up / Login