Running a stepper while a sound file is playing

According to the Adafruit documentation for the Music Maker Mp3 shield, processes can be run while the sound file/files are playing if run within the while loop playingMusic.

while (mp.playingMusic) {
    // file is now playing in the 'background' so now's a good time
    // to do something else like handling LEDs or buttons :)
  
     stepper.moveTo(-400); // move this many pulses away from home position
     stepper.runToPosition(); // Update the motor and wait for it to reach destination
     delay(300);
     stepper.moveTo(-100);  // move this many pulses away from home position
     stepper.runToPosition(); // Update the motor and wait for it to reach destination
     delay(300);
}

The stepper code above works perfectly fine in a standalone sketch. As does the music code, it plays the music until stopPlaying is sent, in its standalone sketch.

Yes, I know a state machine is the best way to handle this, and I’m moving toward that but I don’t understand, why, if the docs says you can run things while the music is playing, I can’t seem to do so.

The motor moves one step and then the program stops

UPDATE:

for those having the same issue, the following code will play the music file and run the motor from the while playingMusic section of the code
I’ve excluded the defines constants instance and variables for brevity.

the accelstepper is set up on pins 4&5 so as not to conflict with the music shield pins

void setup() {
	Serial.begin(9600);

	stepper.setMaxSpeed(1000); // Set max speed. Steps per second
	stepper.setAcceleration(300);  // set motor acceleration
	stepper.setSpeed(1000);

	Serial.println("Adafruit VS1053 Library Test");

	// initialise the music player
	if (!musicPlayer.begin()) { // initialise the music player
		Serial.println(F("Couldn't find VS1053, do you have the right pins defined?"));
		while (1);
	}
	Serial.println(F("VS1053 found"));

	musicPlayer.sineTest(0x44, 500);    // Make a tone to indicate VS1053 is working

	if (!SD.begin(CARDCS)) {
		Serial.println(F("SD failed, or not present"));
		while (1);  // don't do anything more
	}
	Serial.println("SD OK!");
	// Set volume for left, right channels. lower numbers == louder volume!
	musicPlayer.setVolume(20, 20);

	// This option uses a pin interrupt. No timers required! But DREQ
	// must be on an interrupt pin. For Uno/Duemilanove/Diecimilla
	// that's Digital #2 or #3
	// See http://arduino.cc/en/Reference/attachInterrupt for other pins
	// *** This method is preferred
	if (!musicPlayer.useInterrupt(VS1053_FILEPLAYER_PIN_INT))
		Serial.println(F("DREQ pin is not an interrupt pin"));
}



void loop() {

	// Start playing a file from the passed in music player object
	
		if (!musicPlayer.startPlayingFile("trainxng.mp3")) {
			Serial.println("Could not open file trainxng.mp3 from original musicPlayer");
			while (1);
		}
	

	while (musicPlayer.playingMusic) {
		// file is now playing in the 'background' so now's a good time
		// to do something else like handling LEDs or buttons :)
		
		Serial.println("In a second, stepper should move");
		//this works in standalone version
		stepper.moveTo(358);  // move this many pulses away from home position
		stepper.setSpeed(200); // Update the motor and wait for it to reach destination
		stepper.run();
				
	}
	Serial.println("Done playing music");
}

You are using BLOCKING AccelStepper functions and you have delay()s. You need to avoid both completely.

if you use stepper.run() or stepper.runSpeed() the AccelStepper will not block. It is important that those functions are called much more frequently than the desired step rate. I don't know enough about the mp.playingMusic() function but I would prefer to see an IF instead of the WHILE and rely on loop() to do the repetitions.

...R

Robin2

It is important that those functions are called much more frequently than the desired step rate

Could you elaborate on what that means?
I would prefer an if statement there as well but I was following the documentations protocol

The stepper.run() function needs to be called frequently. Each time it is called it checks to see if it is time for another step. If not, it does nothing.

Imagine that you want 1 step per second and you only call run() once every 2 seconds - it can't achieve the required step rate.

Imagine if you only call it once every 750 millisecs - it will be very late with most steps.

But if you call it 100 times per second the maximum error will be 10 msecs.

Have a go at re-writing the program and if it does not work post your code and explain what it actually does.

...R