Introduction: Christmas Present Mystery Enhancement With Motion-Detecting Noisemaker

About: Technology is subversive.

Utterly childish ridiculousness.

This is a simple motion-detecting noisemaker that generates an amusing set of tones in response to movement. It sounds a bit like R2D2 being tickled. I find it kind of fascinating -- your brain senses there's a pattern to the sound that is determined by the axis of movement, but it's a fuzzy connection and very very delicate and hard to control. You won't be learning a set of movements that will generate the Star Wars Imperial Theme on this one, but you will be tempted to try. The only vaguely practical use I could figure out for this was to stick it inside a Christmas or Birthday gift to give a little extra entertainment value to the old "pick up the package, turn it around, shake it a bit" routine.

For this project, you'll need:

Piezo Speaker: I cannibalized mine from an old PC

Arduino/Leonardo/Genuino board or similar

LSM9DS0 9DOF Accel/Mag/Gyro board

4-Line Bi-Directional Level Shifter

USB External battery.

Step 1: Set Up Your Hardware...

Wire up the boards as shown in the Fritzing above. Your motion detector runs on 3.3 volts maximum, so you'll pass the SCL and SCA signals through a Bi-directional Level Shifter and segregate the two voltages from each other using the opposite rails of your breadboard. I put the Piezo on pin 8.

Step 2: Load Up Your Software

/*****************************************************************
Modified from LSM9DS0_Simple.ino
SFE_LSM9DS0 Library Simple Example Code
Jim Lindblom @ SparkFun Electronics
Original Creation Date: February 18, 2014

https://github.com/sparkfun/LSM9DS0_Breakout
The LSM9DS0 is a versatile 9DOF sensor. It has a built-in
accelerometer, gyroscope, and magnetometer. Very cool! Plus it
functions over either SPI or I2C.
This Arduino sketch demonstrates a simple movement-detection
routine that generates an endearing set of random, but responsive
chirps when moved. A bit like tickling R2-D2. 
*****************************************************************/
//Connect a simple scavenged piezo speaker (the Beep generator in any old PC -- usually a squat black 
//cylinder with a centre hole and two wires) to Pin8(red lead) and GND(black lead)
// The SFE_LSM9DS0 requires both the SPI and Wire libraries.
// Unfortunately, you'll need to include both in the Arduino
// sketch, before including the SFE_LSM9DS0 library.
#include  // Included for SFE_LSM9DS0 library
#include 
#include 
long randNumber;
bool BadData;
// SDO_XM and SDO_G are both grounded, so our addresses are:
#define LSM9DS0_XM  0x1D // Would be 0x1E if SDO_XM is LOW
#define LSM9DS0_G   0x6B // Would be 0x6A if SDO_G is LOW
// Create an instance of the LSM9DS0 library called `dof` the
// parameters for this constructor are:
// [SPI or I2C Mode declaration],[gyro I2C address],[xm I2C add.]
LSM9DS0 dof(MODE_I2C, LSM9DS0_G, LSM9DS0_XM);
#define PRINT_SPEED 500 // 500 ms between prints
void setup()
{
  Serial.begin(115200); // Start serial at 115200 bps
  // Use the begin() function to initialize the LSM9DS0 library.
  uint16_t status = dof.begin();
}
void loop()
{
  BadData = false;
    Serial.print("<====    ");
  MonitorForMovement();  
  // We're only using the magnometer, monitoring for movment on the variables: "M: mx, my, mz" -- the X, Y, and Z axis 
}
void MonitorForMovement()
{
  // To read from the magnetometer, you must first call the
  // readMag() function. When this exits, it'll update the
  // mx, my, and mz variables with the most current data.
  dof.readMag();
  // Now we can use the mx, my, and mz variables 
  float pos1 = dof.calcMag(dof.mx);
  float pos3 = dof.calcMag(dof.my);
  float pos5 = dof.calcMag(dof.mz);
  //This delay determines sensitivity -- the space between movement measurements to compare. At 20, I was getting noise values - chirps at rest.
  delay(100);
  dof.readMag();
  float pos2 = dof.calcMag(dof.mx);
  float pos4 = dof.calcMag(dof.my);
  float pos6 = dof.calcMag(dof.mz);
  //Convert to Absolute values -- don't want negative values here
    float xdif = abs(abs(pos1) - abs(pos2)) * 100;
    float ydif = abs(abs(pos3) - abs(pos4)) * 100;
    float zdif = abs(abs(pos5) - abs(pos6)) * 100;  
//First let's monitor for bad data. For some reason, I was getting false readings of movment from the board,
//but always within a specific range of X around .02 -.05, y the same, and Z usually around 3. 
//By excluding the following range I managed to silence the spurious chirps! 
//Well, almost entirely. One or two still sneak past my trap, ideally enough to make a curious
//victim approach the package to investigate and pick it up
  if (xdif < 1.00 && ydif < 1.00 && zdif > 2.00) {BadData = true; Serial.print("  <=== BadData");} 
//Now let's compare the good readings before and after the delay. If they are sufficiently 
// different, trigger sound.
//Your board may report different values -- a minimum of an absolute difference of 3 for any value worked for me.
  if ((xdif > 3 || ydif > 3 || zdif > 3) && (BadData == false))
  {
     
    Serial.print("<==== SOMETHING MOVED   ");
 
//This combination of an arbitrary start frequency, modified by the changes in X,Y, and Z combined and multiplied 
//times 100, simply produced a nice R2D2 Like set of sounds. 
    int Freq = 209 + (xdif + ydif + zdif) * 100;
    Serial.print("Freq: ");
    Serial.print(Freq);
    tone(8, Freq,0);
    //Just to give a little variety, a longer 50 pulse shifting tone:
    if (Freq < 500) {
      randNumber = random(-10, 10);
      
    for (int x = 0; x < 50; x++) {
      
      tone(8,Freq,20);
      delay(4);
      Serial.print(Freq);
      Serial.println("xxxxxxxx");     
      Freq = Freq + randNumber;
      randNumber = randNumber + randNumber;}
    
    }
    //And for added personality, a little burp chirp. 
    if (zdif > 10 && zdif < 16) {
    tone(8,33,200); Serial.print(" <===== BURP");
    delay(200); 
  }
   }
   else { noTone(8);}
Serial.println(" "); 
    Serial.print(xdif);
    Serial.print("  ");
    Serial.print(ydif);
    Serial.print("   ");
    Serial.print(zdif);
}

Step 3: Test & Close Up

Pick the board up and test the sound you get against a range of motion. You may need to tweak values to get something you really like. When you're satisfied, plug in your external power source and put it into the box with your present. (Do not forget to include actual present!). Put packing materials around the board so it's snug and doesn't get so jostled around that a wire comes loose. I use a big beefy USB power source of 10400 mAh which will run the Arduino for a little more than two daya without charging.

Now, enjoy the guessing game about what's in the box as it twitters and chirps in response to being picked up, turned around, and moved through space.

Arduino Contest 2016

Participated in the
Arduino Contest 2016