I’m in the process of building a remote control robot with a speaker on it. Here are the details of the design:
- I’m using an Arduino Uno
- I have a Wave Shield stacked on top of a motor controller shield.
- I need pins 2 and 3 for the interrupts that read the from the RC receiver, so I had to move the wave shield DAC from pins 2-5 to 4-7. I did this in “WavePinDefs.h” Not sure if this is relevant but figured it was worth mentioning.
- I tried a couple of WaveHC example files and they all work so I’m pretty sure it’s not a hardware problem
Ideally, I’d want one stick on my transmitter to control the drive motor (forward/reverse) and the other stick to control the audio. However I have a couple problems that may or may not be related. First of all, the audio won’t play at all unless I include a while loop directly following the play() function call. Unfortunately, this means I can’t drive the robot until the song is finished. Weirder: it has to be right after the play()… if I move the while loop to the main loop just following the call to playfile() (marked “THIS SPOT” in the code below), then I don’t get any audio and I haven’t the faintest idea what the difference is. The robot just completely dies as soon as the audio stick is pushed.
Worse, even after the song is done playing, I can’t get the robot to drive forward/reverse any more (until I reset). My debug statements clearly show that the interrupts are working and that it’s mapping the inputs properly, but apparently the analogwrites aren’t working? Apparently one of the WaveHC calls breaks something? No clue.
To summarize, the code below does the following: At first the drive works normally. If at any point the audio stick is pushed, the song plays and it doesn’t respond until the song is over. After the song is over, the drive no longer operates even though the debug statements show the mapping is working. Pushing the audio stick starts the song again.
Any help making this code work as intended would be much appreciated! I have no idea what’s wrong!
#include "WaveUtil.h"
#include "WaveHC.h"
#define dir 8 // pin 8
#define pwm_cy 9 // pin 9
#define Chan1Interrupt 1 // corresponds to pin 3 (int.1 = 3)
#define Chan2Interrupt 0 // corresponds to pin 2 (int.0 = 2)
// Remember: LCS, CLK, DI, and LAT were moved to pins 4-7
// Untouched: CCS, MOSI, MISO, SCK (pins 10-13)
SdReader card; // This object holds the information for the card
FatVolume vol; // This holds the information for the partition on the card
FatReader root; // This holds the information for the volumes root directory
WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
// Define macro to put error messages in flash memory
#define error(msg) error_P(PSTR(msg))
unsigned long Chan1_startPulse;
volatile double Chan1_val;
volatile double Chan1_val_last;
unsigned long Chan2_startPulse;
volatile double Chan2_val;
volatile double Chan2_val_last;
int pwmout = 0;
void setup()
{
Serial.begin(9600); // set up Serial library at 9600 bps for debugging
putstring_nl("\nWave test!"); // say we woke up!
putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
Serial.println(FreeRam());
// if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
if (!card.init()) { //play with 8 MHz spi (default faster!)
error("Card init. failed!"); // Something went wrong, lets print out why
}
// enable optimize read - some cards may timeout. Disable if you're having problems
card.partialBlockRead(true);
// Now we will look for a FAT partition!
uint8_t part;
for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
if (vol.init(card, part))
break; // we found one, lets bail
}
if (part == 5) { // if we ended up not finding one :(
error("No valid FAT partition!"); // Something went wrong, lets print out why
}
// Lets tell the user about what we found
putstring("Using partition ");
Serial.print(part, DEC);
putstring(", type is FAT");
Serial.println(vol.fatType(), DEC); // FAT16 or FAT32?
// Try to open the root directory
if (!root.openRoot(vol)) {
error("Can't open root dir!"); // Something went wrong,
}
// Whew! We got past the tough parts.
putstring_nl("Files found (* = fragmented):");
// Print out all of the files in all the directories.
root.ls(LS_R | LS_FLAG_FRAGMENTED);
attachInterrupt(Chan1Interrupt, Chan1_begin, RISING);
attachInterrupt(Chan2Interrupt, Chan2_begin, RISING);
pinMode(dir, OUTPUT);
pinMode(pwm_cy, OUTPUT);
}
void loop()
{
//stick is pushed forward
if (Chan1_val > 1488 && Chan1_val <= 1910) {
pwmout = map(Chan1_val,1488,1910,5,255);
// if (pwmout >= 240)
// pwmout = 255;
digitalWrite(dir, 0);
analogWrite(pwm_cy, pwmout);
}
//stick is pushed reverse
else if (Chan1_val >= 1040 && Chan1_val < 1460) {
pwmout = map(Chan1_val,1460,1040,5,255);
// if (pwmout >= 240)
// pwmout = 255;
digitalWrite(dir, 1);
analogWrite(pwm_cy, pwmout);
}
//stick is neutral
else {
analogWrite(pwm_cy, 0);
pwmout = 0;
}
//report out
Serial.print(Chan1_val);
Serial.print(" || ");
Serial.println(pwmout);
//play the wav file if stick 2 is pressed down
if(Chan2_val > 1650 && Chan2_val <= 1910) {
playfile("BRASS.WAV");
//while(wave.isplaying); {} <<<< THIS SPOT
}
}
void Chan1_begin() // enter Chan1_begin when interrupt pin goes HIGH.
{
Chan1_startPulse = micros(); // record microseconds() value as Chan1_startPulse
detachInterrupt(Chan1Interrupt); // after recording the value, detach the interrupt from Chan1_begin
attachInterrupt(Chan1Interrupt, Chan1_end, FALLING); // re-attach the interrupt as Chan1_end, so we can record the value when it goes low
}
void Chan1_end()
{
Chan1_val = micros() - Chan1_startPulse; // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue.
detachInterrupt(Chan1Interrupt); // detach and get ready to go HIGH again
attachInterrupt(Chan1Interrupt, Chan1_begin, RISING);
if (Chan1_val < 1000 || Chan1_val > 3000) { Chan1_val = Chan1_val_last;}
else {Chan1_val_last = Chan1_val;}
}
void Chan2_begin() // enter Chan1_begin when interrupt pin goes HIGH.
{
Chan2_startPulse = micros(); // record microseconds() value as Chan1_startPulse
detachInterrupt(Chan2Interrupt); // after recording the value, detach the interrupt from Chan1_begin
attachInterrupt(Chan2Interrupt, Chan2_end, FALLING); // re-attach the interrupt as Chan1_end, so we can record the value when it goes low
}
void Chan2_end()
{
Chan2_val = micros() - Chan2_startPulse; // when interrupt pin goes LOW, record the total pulse length by subtracting previous start value from current micros() vlaue.
detachInterrupt(Chan2Interrupt); // detach and get ready to go HIGH again
attachInterrupt(Chan2Interrupt, Chan2_begin, RISING);
if (Chan2_val < 1000 || Chan2_val > 3000) { Chan2_val = Chan2_val_last;}
else {Chan2_val_last = Chan2_val;}
}
//print error message and halt
void error_P(const char *str) {
PgmPrint("Error: ");
SerialPrint_P(str);
sdErrorCheck();
while(1);
}
// print error message and halt if SD I/O error, great for debugging!
void sdErrorCheck(void) {
if (!card.errorCode()) return;
PgmPrint("\r\nSD I/O error: ");
Serial.print(card.errorCode(), HEX);
PgmPrint(", ");
Serial.println(card.errorData(), HEX);
while(1);
}
void playfile(char *name) {
FatReader f;
// see if the wave object is currently doing something
if (wave.isplaying) {// already playing something, so stop it!
wave.stop(); // stop it
}
// look in the root directory and open the file
if (!f.open(root, name)) {
putstring("Couldn't open file "); Serial.print(name); return;
}
// OK read the file and turn it into a wave object
if (!wave.create(f)) {
putstring_nl("Not a valid WAV"); return;
}
// ok time to play! start playback
Serial.println("Should play now...");
wave.play();
while(wave.isplaying); {}
}