Summary:

Make a robot that dances to your music. Realistically this should have been part of the Day 10 DSP project, but due to time constraints I had to split up the days.

Background:

Last week I saw the Dance, Rose, Dance! project on my Hackaday.io feed. I thought it would make a perfect day of code project to recreate a limited subset of that project with what I had on hand.

Materials:

materials-7

  1. Arduino
  2. USB-Micro Cable
  3. Adafruit MAX9814 - Electret Microphone
  4. Servo-based gimbal, like this
  5. Breadboard & Leads
  6. Arduino IDE

Process:

Prerequisites:

Complete the Day 10 DSP setup, and grab that code example. It'll form the basis for today's work.

Assembly:

Assemble the Day 10 components as described. Connect the GND pin of the Arduino to both servo leads. Connect the 5V Arduino pin to both servo VCC pins. Connect an Arduino PWM pin to one servo's signal pin, and a different PWM pin to the other servo's signal pin. If the servo pan-tilt gimbal needs to be assembled, do so.

connections-3

Get Moving:

The pan-tilt gimbal has 2 servos that, when centered (50% PWM duty cycle) are centered in each axis. I want to base all dance 'moves' off this center position. But first we need a way to control the servos.

For that we'll use the Arduino Servo library to abstract some PWM signal generation from us. We'll also instantiate and initialize a Servo object for each axis of the gimbal. Then we'll center the gimbal and give it time to move to position.

#include <Servo.h>

Servo panServo;
Servo tiltServo;
bool wasPan = false;

void setup() {
    // Other code
    panServo.attach(10);
    tiltServo.attach(9);
    
    panServo.write(90);
    tiltServo.write(90);
    delay(200);
}

Dance Moves:

From the Day 10 DSP code we already have a convenient way to detect a beat. We'll replace lighting up an LED with triggering a dance move.

First we'll define a constant to store how much we want to rotate per dance move. We'll also seed the random function so we can use it later.

// Not more than 90
#define DANCE_OFFSET 30

void setup() {
    // Other Code
    randomSeed(analogRead(0));
}

Inside loop we can add code to perform our dance moves. If we need to trigger an action we'll first determine where to move by calculating a random offset from 90 degrees. I decided that it would look comical if the robot alternated rotating and nodding, so I added a variable to flip flop which servo to update. Finally, we write the new position and update the toggle variable.

// We used to light up an LED
// digitalWrite(6, (beat>THRESHOLD) ? HIGH : LOW);
// Now we want to do more
if (beat > THRESHOLD) {

    // Get a random offset from 90
    int newMove = random((90-DANCE_OFFSET),(90+DANCE_OFFSET));

    if (wasPan) {
        tiltServo.write(newMove);
        wasPan = false;
    } else {
        panServo.write(newMove);
        wasPan = true;
    }
}

We don't need (or want) to wait for the servo to move into position like before. Firstly, because this would naively stall our sampling loop. Also, even if the next detected beat is so close to the previously triggered one that the servo is still moving, issuing a new position will not hurt the servo. It might even give the effect that the robot is dancing with vigorously to the frenetic beats.

dance

Code:

Example code for today can be found here.

Future Work:

I'd like to add some more functionality to this. For starters, I want to base the amount of movement per beat on the relative intensity of the beat, so that as the music gets louder or more intense the robot dances more fervently. I'd also like to replace random movement with some predefined dances that look more human, possibly cycling through some moves.