Servo Bells.

July 21, 2008

This example was inspired by JD Barnhart's "Ruby on Bells" RAD demo (see http://www.vimeo.com/1272402), but using standard Arduino (and not Ruby) code.

This Arduino ServoBells example by John Plocher is released into the public domain.

Overview

This example uses servos as "wine glass" bell clappers. The basic idea is to fill a bunch of crystal glasses with the right amount of liquid to "tune them" to a musical scale, mount a "hammer" on each servo so that it can ring two different glasses and mount the servos such that the hammers end up at the same level as the wine glasses. Then the program simply uses a sequence of "home, left n degrees, home" and "home, right n degrees, home" servo commands to ring either the glass on the left or the one on the right.

Construction

Servo Bases

I stopped by TAP Plastics and purchased a 12"x16" sheet of black plastic for a dollar, cut it into 4x 4"x12" rectangles, drilled and cut out mounting holes for a servo and then clamped about 4" of the plastic into a vice, carefully heated it with a hot-air gun, and when the plastic slightly softened, bent each piece to form about a 30 degree angle. The only important "measurement" in all this is that the servo needs to fit in its mounting hole without bottoming out against the base.

Mounting the servos

Low temp hot melt glue is your friend! Drop the control wires and the servo into the mounting hole you cut in the plastic base and attach it to the base with a bead of hot melt glue. When it cools, flip the base over and squirt a small blob on each corner to act as no-slip feet. Let the "feet" cool/solidify BEFORE turning back over and setting it down - don't ask how I found this out :-)

Center the servos in the middle of their travel and mount the long straight "double" horn parallel with the long direction of the base.

Weighting down the bases

I happened to have some 2"x3/16" mild steel cutoffs that I hot melt glued to the plastic bases to keep them from moving when in use. You can also tape them down, stack books on them, whatever...

Making and mounting the hammers

I experimented with thick and thin blocks of wood, thick and thin dowels, felt, plastic and metal. Light weight was better than heavy, hard wood rather than soft. Springy shafts instead of rigid, and hard facing on the hammers. You want the shafts long enough to clear the plastic base by at least the diameter of a wine glass, with a low mass head.

Try the following suggestions, but play with things to get the best sound:

shafts

  • 1/8" dowels 12" long
  • 1/4" dowels 12" long

heads

  • 1/4"x1/4"x1/2" walnut block
  • 1/4"x1/4"x1/2" pine block with metal or plastic push pins stuck on each face

Mounting the hammers on the servos

Hot glue to the rescue - again. Make sure the hammer head is parallel to the ground so that it strikes the sides of the wine glasses cleanly, and run a bead of hot melt glue down the double horn on the servo. Set the end of the shaft in the glue so that it is attached to as much of the servo horn surface as possible.

Putting it all together

I used the Modern Devices Bare Board Arduino clone which has convenient pins for connecting servos and runs nicely off of USB power, as well as the Software Servo Library servo driver.

Oh, the code!

// Make music with servos and wine glases
// by John Plocher 
// Application: 4 servos with wooden hammers

#include <Servo.h>

int servo1Pin = 14;        // pwm outputs for servos
int servo2Pin = 15;
int servo3Pin = 16;
int servo4Pin = 17;

int home=93;        // Somewhere between 85 and 95 
                    // with a servo range of 0..180

Servo servo1, servo2, servo3, servo4;

void setup() {
    servo1.attach(servo1Pin);   servo1.write(home);  
    servo2.attach(servo2Pin);   servo2.write(home);  
    servo3.attach(servo3Pin);   servo3.write(home);  
    servo4.attach(servo4Pin);   servo4.write(home);  
    Servo::refresh();
}

void loop() {  // Play thru once each reset...
  play("abcdefg gfedcba  ");
  play("e2d2c2d2e2e2e4d2d2d4e2e2e6e2d2c2d2e2e2e4e2d2d2e2d2cDDD");
  play("ededcddcbcaeaeaeabcbcddcdede   ");
  play("fdfdcddcgbcafafafgabcbcddcdfdfg");
  while (1) { d20(); }  // stop after one loop to keep
                        // from annoying neighbors :-)
}

void play(char *s) {
  int l = strlen(s);
  for (int x = 0; x < l; x++) {
     switch (s[x]) {
       case 'a': a(); break;
       case 'b': b(); break;
       case 'c': c(); break;
       case 'd': d(); break;
       case 'e': e(); break;
       case 'f': f(); break;
       case 'g': g(); break;
       case 'D':       // Delays (cumulative)
       case ' ':
       case '8': d20();
       case '6': d20();
       case '4': d20();
       case '2': d20(); break;
     }
  }
}

// Play a note. 
//
//  Tweak delays to make for crisp ringing

void note(Servo *s, int n) {
    s->write(home + n);  Servo::refresh();  d20(); d20();
    s->write(home);      Servo::refresh();  d20(); d20();  d20(); d20();
}

// The "notes"
// Tweak the 2nd parameter to give strong, authoritative
// strikes without actually hitting the glass too hard.
// This value is influenced by the physical behavior of
// the materials you used to build the hammers.

void a() { note(&servo1,  -6); }
void b() { note(&servo1,  +6); }
void c() { note(&servo2,  -6); }
void d() { note(&servo2,  +5); }
void e() { note(&servo3, -12); }
void f() { note(&servo3, +12); }
void g() { note(&servo4, -12); }

// The servo library requires that the refresh
// method be called at least every 20mS, so
// we need to build up our own longer delays.

void d20()   { delay(20); Servo::refresh(); }
void d100()  { for (int x = 0; x < 5; x++)  { d20();  }}
void d1000() { for (int x = 0; x < 10; x++) { d100(); }}

Share