Dancing Rover v2

First thanks to Jarcand for all his help thus far. I’ve got my robot dancing and singing now and the code is 95% working. Maybe someone else can take a look and make it just right. The only issue I’m having at this point is if you play the missions impossible song there are a few delays in commands being sent. I’m not sure why because my mod’s to the code look for serial.available and there is no ouput from the robot over serial.

Anyway, You will need the tone library for this sketch. You’ll also need a speaker (possibly a buzzer) on pin 3 (this can be changed). Here’s the code.

[code]/To control the rover, Copy and paste the code below into the Arduino software/

#include <Tone.h>

Tone tone1;

#define OCTAVE_OFFSET 0

int notes] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};

//char *song = “The Simpsons:d=4,o=5,b=160:c.6,e6,f#6,8a6,g.6,e6,c6,8a ,8f#,8f#,8f#,2g,8p,8p,8f#,8f#,8f#,8g,a#.,8c6,8c6,8 c6,c6”;
//char *song = “Indiana:d=4,o=5,b=250:e,8p,8f,8g,8p,1c6,8p.,d,8p,8 e,1f,p.,g,8p,8a,8b,8p,1f6,p,a,8p,8b,2c6,2d6,2e6,e, 8p,8f,8g,8p,1c6,p,d6,8p,8e6,1f.6,g,8p,8g,e.6,8p,d6 ,8p,8g,e.6,8p,d6,8p,8g,f.6,8p,e6,8p,8d6,2c6”;
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,8 e5,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,8 f#5,8p,8f#5,8e5,8e5”;
//char *song = “Entertainer:d=4,o=5,b=140:8d,8d#,8e,c6,8e,c6,8e,2c .6,8c6,8d6,8d#6,8e6,8c6,8d6,e6,8b,d6,2c6,p,8d,8d#, 8e,c6,8e,c6,8e,2c.6,8p,8a,8g,8f#,8a,8c6,e6,8d6,8c6 ,8a,2d6”;
//char *song = “Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8 b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e, g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f, 8e,f,8c6,8c,8d,e,8e,d,8d,c”;
//char *song = “Xfiles:d=4,o=5,b=125:e,b,a,b,d6,2b.,1p,e,b,a,b,e6, 2b.,1p,g6,f#6,e6,d6,e6,2b.,1p,g6,f#6,e6,d6,f#6,2b. ,1p,e,b,a,b,d6,2b.,1p,e,b,a,b,e6,2b.,1p,e6,2b.”;
//char *song = “Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6 ,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6, 8d6,8a,8c6,8g,8a#,8a,8f”;
//char *song = “20thCenFox:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,3 2p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p, b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4 p,8e,8g#,8b,1c#6,8f#,8a,8c#6,1e6,8a,8c#6,8e6,1e6,8 b,8g#,8a,2b”;
//char *song = “Bond:d=4,o=5,b=80:32p,16c#6,32d#6,32d#6,16d#6,8d#6 ,16c#6,16c#6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6, 16d#6,16d#6,16c#6,32d#6,32d#6,16d#6,8d#6,16c#6,16c #6,16c#6,16c#6,32e6,32e6,16e6,8e6,16d#6,16d6,16c#6 ,16c#7,c.7,16g#6,16f#6,g#.6”;
//char *song = “MASH:d=8,o=5,b=140:4a,4g,f#,g,p,f#,p,g,p,f#,p,2e., p,f#,e,4f#,e,f#,p,e,p,4d.,p,f#,4e,d,e,p,d,p,e,p,d, p,2c#.,p,d,c#,4d,c#,d,p,e,p,4f#,p,a,p,4b,a,b,p,a,p ,b,p,2a.,4p,a,b,a,4b,a,b,p,2a.,a,4f#,a,b,p,d6,p,4e .6,d6,b,p,a,p,2b”;
//char *song = “StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6 ,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b. 6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b., 8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c# 6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6”;
//char *song = “GoodBad:d=4,o=5,b=56:32p,32a#,32d#6,32a#,32d#6,8a# .,16f#.,16g#.,d#,32a#,32d#6,32a#,32d#6,8a#.,16f#., 16g#.,c#6,32a#,32d#6,32a#,32d#6,8a#.,16f#.,32f.,32 d#.,c#,32a#,32d#6,32a#,32d#6,8a#.,16g#.,d#”;
//char *song = “TopGun:d=4,o=4,b=31:32p,16c#,16g#,16g#,32f#,32f,32 f#,32f,16d#,16d#,32c#,32d#,16f,32d#,32f,16f#,32f,3 2c#,16f,d#,16c#,16g#,16g#,32f#,32f,32f#,32f,16d#,1 6d#,32c#,32d#,16f,32d#,32f,16f#,32f,32c#,g#”;
//char *song = “A-Team:d=8,o=5,b=125:4d#6,a#,2d#6,16p,g#,4a#,4d#.,p, 16g,16a#,d#6,a#,f6,2d#6,16p,c#.6,16c6,16a#,g#.,2a#”;
//char *song = “Flinstones:d=4,o=5,b=40:32p,16f6,16a#,16a#6,32g6,1 6f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6,16a#,16c 6,d6,16f6,16a#.,16a#6,32g6,16f6,16a#.,32f6,32f6,32 d#6,32d6,32d6,32d#6,32f6,16a#,16c6,a#,16a6,16d.6,1 6a#6,32a6,32a6,32g6,32f#6,32a6,8g6,16g6,16c.6,32a6 ,32a6,32g6,32g6,32f6,32e6,32g6,8f6,16f6,16a#.,16a# 6,32g6,16f6,16a#.,16f6,32d#6,32d6,32d6,32d#6,32f6, 16a#,16c.6,32d6,32d#6,32f6,16a#,16c.6,32d6,32d#6,3 2f6,16a#6,16c7,8a#.6”;
//char *song = “Jeopardy:d=4,o=6,b=125:c,f,c,f5,c,f,2c,c,f,c,f,a., 8g,8f,8e,8d,8c#,c,f,c,f5,c,f,2c,f.,8d,c,a#5,a5,g5, f5,p,d#,g#,d#,g#5,d#,g#,2d#,d#,g#,d#,g#,c.7,8a#,8g #,8g,8f,8e,d#,g#,d#,g#5,d#,g#,2d#,g#.,8f,d#,c#,c,p ,a#5,p,g#.5,d#,g#”;
//char *song = “Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f, g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#, 32g#,a#,f#,a,f,g#,f#,8d#”;
//char *song = “Smurfs:d=32,o=5,b=200:4c#6,16p,4f#6,p,16c#6,p,8d#6 ,p,8b,p,4g#,16p,4c#6,p,16a#,p,8f#,p,8a#,p,4g#,4p,g #,p,a#,p,b,p,c6,p,4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8 b,p,4g#,16p,4c#6,p,16a#,p,8b,p,8f,p,4f#”;
//char *song = “MahnaMahna:d=16,o=6,b=125:c#,c.,b5,8a#.5,8f.,4g#,a #,g.,4d#,8p,c#,c.,b5,8a#.5,8f.,g#.,8a#.,4g,8p,c#,c .,b5,8a#.5,8f.,4g#,f,g.,8d#.,f,g.,8d#.,f,8g,8d#.,f ,8g,d#,8c,a#5,8d#.,8d#.,4d#,8d#.”;
//char *song = “LeisureSuit:d=16,o=6,b=56:f.5,f#.5,g.5,g#5,32a#5,f 5,g#.5,a#.5,32f5,g#5,32a#5,g#5,8c#.,a#5,32c#,a5,a# .5,c#.,32a5,a#5,32c#,d#,8e,c#.,f.,f.,f.,f.,f,32e,d #,8d,a#.5,e,32f,e,32f,c#,d#.,c#”;
//char *song = “MissionImp:d=16,o=6,b=95:32d,32d#,32d,32d#,32d,32d #,32d,32d#,32d,32d,32d#,32e,32f,32f#,32g,g,8p,g,8p ,a#,p,c7,p,g,8p,g,8p,f,p,f#,p,g,8p,g,8p,a#,p,c7,p, g,8p,g,8p,f,p,f#,p,a#,g,2d,32p,a#,g,2c#,32p,a#,g,2 c,a#5,8c,2p,32p,a#5,g5,2f#,32p,a#5,g5,2f,32p,a#5,g 5,2e,d#,8d”;

int E1 = 6; //M1 Speed Control
int E2 = 5; //M2 Speed Control
int M1 = 8; //M1 Direction Control
int M2 = 7; //M2 Direction Control
void setup(void)
{
int i;
for(i=5;i<=8;i++)
pinMode(i, OUTPUT);
Serial.begin(9600);
tone1.begin(3); //Change this number to desired pin for speaker
}
#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(Serial.available())
  moveRobot();
if(note)
{

  tone1.play(notes(scale - 4) * 12 + note]);
  delay(duration);
  tone1.stop();
  }
else
{

  delay(duration);
  }
}

}

void moveRobot(void)
{

while (Serial.available() < 1) { // Wait until a character is received
}
char val = Serial.read();
int leftspeed = 255; //255 is maximum speed
int rightspeed = 255;
switch(val) // Perform an action depending on the command
{
case ‘w’://Move Forward
forward (leftspeed,rightspeed);
break;
case ‘s’://Move Backwards
reverse (leftspeed,rightspeed);
break;
case ‘a’://Turn Left
left (leftspeed,rightspeed);
break;
case ‘d’://Turn Right
right (leftspeed,rightspeed);
break;
default:
stop();
break;
}
}
void stop(void) //Stop
{
digitalWrite(E1,LOW);
digitalWrite(E2,LOW);
}
void forward(char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void reverse (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}
void left (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,HIGH);
analogWrite (E2,b);
digitalWrite(M2,LOW);
}
void right (char a,char b)
{
analogWrite (E1,a);
digitalWrite(M1,LOW);
analogWrite (E2,b);
digitalWrite(M2,HIGH);
}

void loop(void)
{
play_rtttl(song);
}[/code]

[video=youtube;JegvbNcu_Vc]http://www.youtube.com/watch?v=JegvbNcu_Vc

I am having some issues with the code and it appears to be in the tone library. This is the errors I get when verifying my sketch.

C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp: In member function ‘void Tone::begin(uint8_t)’:
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:121: error: ‘bitWrite’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:123: error: ‘digitalPinToPort’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:123: error: ‘portOutputRegister’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:124: error: ‘digitalPinToBitMask’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp: In member function ‘void Tone::play(uint16_t, uint32_t)’:
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:198: error: ‘OUTPUT’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:198: error: ‘pinMode’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:294: error: ‘bitWrite’ was not declared in this scope
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp: In member function ‘void Tone::stop()’:
C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp:361: error: ‘digitalWrite’ was not declared in this scope

Any help would be greatly appreciated. Thanks in advance. I am new to writing code.

Nickhead.

Did you make any changes to your Tone library on your computer? It seems like it is missing a reference to the main Arduino.h file.

You should be able to modify this file: C:\Users\Nick\Documents\Arduino\libraries\Tone\Tone.cpp

And add this line at line 26 (instead of wiring.h, if it’s still there):

#include <Arduino.h>

Hope this helps,

Thank you Jarcand.
That got rid of the errors but looks like I still have some work to do. I just downloaded the tone library from the arduino website and made no mods to any of the files but your help fixed that problem.
Thanks again.
Nick.

Thanks for the code and the help with it. I got the little guy working. My error was that I thought this code would make the robot dance based on the music playing. I did not realize till digging further that I still had to use the W,A,S,D commands but very cool either way. By watching the youtube video I would say that Hatefuel is a very skilled trackable driver lol. Tons of fun and this is why I purchase this kit. worth every penny and cant wait to get the autonomous aspect going.
Nickhead.

That put a big smile on my face - thank you very much for sharing! For dancing, consider adding two inexpensive servos:
robotshop.com/en/9g-micro-servo-motor-4-8v.html

That looks great! I think your delays in commands being received is because the mission impossible notes last longer and this note I made in the other thread:

In order to fix this issue, you would have to get the moveRobot() function to run while you are doing the two delay(duration). This is a little more complicated, but the basics is that you need to replace the delay(duration) with something like moveRobotWhileDelay(duration).

The new function would do something like:

void moveRobotWhileDelay(int duration) {
  unsigned long start = millis();
  unsigned long end = start + duration;
  while (millis() < end) {
    if(Serial.available()) {
      moveRobot();
    }
  }
}

We haven’t tested this, so you may need to verify the syntax and do some debugging. Hope this helps!