loading

Super Complicated Code (playing music and moving servos at the same time)

Hey all! I'm trying to make a present for a friend and it's not working out at all :( (due this tuesday).

So I ripped up a teddy bear, put some servos in it's arm, and a speaker in it's stomach. I'm trying to use my arduino uno to play tunes over the speaker while make it's arms wobble. My problem is that the song contains delays for getting the notes on beat, which means that I can't have other things going on at once. Is there anything else I can do?
I'm stuck with just making it's arms move, then having the tunes play while the arms are still, then having them move again. 

Now I did figure out a method to get the servos to move without using a delay function. That's at the very bottom void move();
I know it's probably about the worst way to make servos move slowly without delay but it works. I'm not worried about that. I'm just wondering
how am I going to play music and have the servos move at the same time? Thanks!

Here's my code. 



int speakerPin = 5;
int buttonPin = 6;
int buttonPress;
int buttonCount; 
int leds = 13;
#include <Servo.h>
int servospeed(100);
Servo servoleft;
Servo servoright;
int val = 20;
int val2;
boolean state = true;
unsigned long currentMillis;
unsigned long previousMillis;
int songLength1 = 7000;
int songLength2;


/*****************************************************************************************************/
/* Smaller value -> all tunes play faster; bigger -> slower. Recommend you don't change this, but
instead use playTune() to pass different beatLength values to parseTune() for different songs */
const int beatLength = 50;
// Generate a tone by passing a square wave of a certain period to the piezo
void playTone(int tone, int duration) {
  for (long i = 0; i < duration * 1000L; i += tone * 2) {
    digitalWrite(speakerPin, HIGH);
    delayMicroseconds(tone);
    digitalWrite(speakerPin, LOW);
    delayMicroseconds(tone);
  }
}
/* This works out what period, in microseconds, to use for the square wave for a given note. To calculate these,
p = ((1 / freq) * 1,000,000) / 2. We divide by 2 because the signal will be HIGH for p microseconds and then LOW
for p microseconds. Frequencies for the notes obtained from http://www.phy.mtu.edu/~suits/notefreqs.html
The range defined below covers 2 octaves from C4 (middle C, or 261.63Hz) to B5 (987.77Hz). Feel free to modify. */
void playNote(char note, int duration, boolean sharp) {
  char names[] = {
    'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C', 'D', 'E', 'F', 'G', 'A', 'B'         };
  int tones[] = {
    1915, 1700, 1519, 1432, 1275, 1136, 1014, 956, 851, 758, 716, 636, 568, 506         };
  // these are the "sharp" versions of each note e.g. the first value is for "c#"
  char names_sharp[] = {
    'c', 'd', 'f', 'g', 'a', 'C', 'D', 'F', 'G', 'A'         };
  int tones_sharp[] = {
    1804, 1607, 1351, 1204, 1073, 902, 804, 676, 602, 536         };
  // play the tone corresponding to the note name
  if (sharp == false) {
    for (int i = 0; i < 14; i++) {
      if (names[i] == note) {
        playTone(tones[i], duration);
      }
    }
  }
  else {
    for (int i = 0; i < 10; i++) {
      if (names_sharp[i] == note) {
        playTone(tones_sharp[i], duration);
      }
    }
  }
}


/* Take a string representing a tune and parse it to play the notes through the piezo.

Parameters:
char notes[]: a string that represents the notes of the song. The grammar for parsing the string is described at the top of this file.
int beatLength: changes the tempo. Smaller value -> quicker; bigger -> slower
boolean loopSong: if true, the song will loop indefinitely (until you press the microswitch)
*/
void parseTune(char notes[], int beatLength, boolean loopSong) {
  boolean play = true;
  // 1 iteration of this loop == 1 note played
  for (int i = 0; notes[i] != '.' && play == true; i++) { // stop iteration if '.' is the next char

      if (notes[i] == ',') { // ',' signifies a rest
      // Look at the number (max. 2 digits) following from the ',' to work out the duration of the rest
      char len[3];
      int count = 0;
      while (notes[i+1] >= '0' && notes[i+1] <= '9' && count < 2) {
        len[count] = notes[i+1];
        count++;
        i++;
      }
      len[count] = '\0';
      int duration = atoi(len);
      delay(duration * beatLength); // rest duration
    }
    else { // play the next note, represented by a series of characters e.g. 'c4', 'a#12'
      char note = notes[i];
      boolean sharp;
      // if the next character is a '#' then we must make the note a sharp
      if (notes[i+1] == '#') {
        i++;
        sharp = true;
      }
      else {
        sharp = false;
      }
      // Look at the number (max. 2 digits) following from the note name to work out the note duration
      char len[3];
      int count = 0;
      while (notes[i+1] >= '0' && notes[i+1] <= '9' && count < 2) {
        len[count] = notes[i+1];
        count++;
        i++;
      }
      len[count] = '\0';
      int duration = atoi(len);
      playNote(note, duration * beatLength, sharp);
    }
    delay(beatLength / 2); // pause between notes
  }
}


// Write your tunes in here using the grammar described at the top of this file. Can have up to 4 tunes.
void song1()
{
  char notes[] = "d4g4g2a2g2f#2e4c4e4a4a2b2a2g2f#4d4f#4b4b2C2b2a2g4e4d2d2e4a4f#4g8,8.";
  parseTune(notes, beatLength * 1.25, false);
}
void song2()
{
  char notes[] = "b4b4b8b4b4b8b4D4g6a2b12,4C4C4C6C2C4b4b4b2b2b4a4a4b4a8D8b4b4b8b4b4b8b4D4g6a2b12,4,C4C4C6C2C4b4b4b2b2D4D4C4a4g12,8.";
  parseTune(notes, beatLength, false);
}
/**********************************************************************************************************/
void setup()
{
  pinMode(speakerPin, OUTPUT);
  pinMode(buttonPin, INPUT);
  pinMode(leds, OUTPUT);
  servoleft.attach(8);
  servoright.attach(7);
  servoleft.write(30);
  servoright.write(120);
  Serial.begin(9600);
}
void loop()
{
  currentMillis = millis();
  move();
  song1();

}
/**************************************/
void move()
{
  if (currentMillis - previousMillis > 50)
  {
    if ( val <= 60 && state == true)
    {
      val++;
      servoleft.write(val);
      val2 = map(val, 20, 60, 80, 120);
      servoright.write(val2);
      if (val >= 60)
      {
        state = false;
      }
    } //

    if (val >= 20 && state == false)
    {
      val--;
      servoleft.write(val);
      val2 = map(val, 60, 20, 120, 80);
      servoright.write(val2);
      if (val <= 20)
      {
        state = true;
      }
    }//

    previousMillis = currentMillis;
    Serial.println(val);
  } // if millis
}

sort by: active | newest | oldest
iceng2 years ago

Back when machine code 8008 pre CPM ...... what hooked me was a slowly materializing monochrome American flag while a low cost AM radio played the National Anthem when placed near the cpu enclosure.

THAT'S Right the drawing pixel code segments broadcast RFI in tempo to the tune !

Use the timer interrupts to implement the delays, so that "background" tasks can continue.

Scrap the music side of the bit. Get yourself a wave shield then you can play any MP3 you want and have the servos go through their steps while the file plays.

HavocRC (author)  mpilchfamily2 years ago
I would love to but it's a gift. . . I'm not giving her my arduino and a shield! Any other ideas?

Blinking evil red LED teddy bear eyes.