How to perform 2 tasks with 2 arduinos for the same amount of Millies

Hi,

I have 2 Unos connected via serial Tx-Rx.
I run different tasks on each Arduino.

Let's say I decide to run task1 on the Arduino1 for 1min 66sec.
Now I need to tell Arduino2 to do it's task1 for the same amount of time simultaneously.

I'm stuck sending these 2 parameters (task number & unsigned floating time variable) to
the second Arduino and recieving them.

Thanks for your help.

When you say "simultaneously" what amount of error in the synchronisation would be acceptable - how many millisecs?

On solution that comes to mind is for Arduino A to send a message to Arduino B something like Serial.println("<1,126>"); where '1' is the task number and 126 is the number of seconds.

After sending the message Arduino A starts the task and after receiving the message Arduno B starts the task.

...R

Thanks Robin,

"When you say "simultaneously" what amount of error in the synchronisation would be acceptable - how many millisecs? , Almost simultaneously is ok. Not worried about that.

I also thought of the solution you suggest but 1.66 is a floating variable and I read you can only send integers. (?) So maybe send 166 as integer then divide by 100 when received ?

How do I parse the received values ?

Let's say I decide to run task1 on the Arduino1 for 1min 66sec.

Or two minutes and six seconds, as it is more commonly expressed.

ba47:
I also thought of the solution you suggest but 1.66 is a floating variable

It is not a floating variable. It is two numbers (minutes and seconds) that happen to be separated by a full-stop.

IMHO it would be much simpler to convert the time to a number of seconds (as in my Reply #1). But if you want to send the minutes and seconds separately you can do it like this Serial.println("<1,1,66>");

As far as the parsing is concerned have a look at the parse example in Serial Input Basics - simple reliable non-blocking ways to receive data.

...R

If you want more precise timing you can use Robin2's serial parsing code to send task details and then have a digital pin on Uno1 that tells Uno2 "You know what to do and for how long, go do it NOW".

What are you doing that needs this functionality?

Thanks all for the kind replies.

To be honest, I had read Robin's excellent post on Serial Input Basics but it was a little over my head and couldn't understand it all. I'm a rookie, not his fault . :slight_smile:
I'll go back and study it again, promise.

In the meantime, I will take the easy way, as Robin suggested, converting the number.

Wildbill, the first Arduino is controlling 25 servos performing different tasks and the second
will play music based on the task performed by the first one.

Cheers.

ba47:
post on Serial Input Basics but it was a little over my head

If there is some specific thing you don't understand then please ask.

I find with most new programming techniques that they become clearer after the 14th reading :slight_smile:

...R

Robin,

I tried using your example 5 of Serial Input Basics, leaving out the text (HelloWorld) part,
using the serial monitor as sender and all is ok.

Now I need to implement this code for use between my 2 Arduinos, sending 2 variables: TaskN and Duration.

The sender Arduino will have (??):

// SENDER   

int TaskN = 5;
float Duration = 2.34;

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

}

void loop() {

  Serial.write(<TaskN, Duration>);
}

I have 3 questions Please:

  1. Is the sender code ok ? (sorry can't try it myself yet, loaned my second Arduino to a friend for a couple
    of days)
  2. Can I take the sender's and the receiver's code out of the " void loop" and just send once and receive
    once in " void setup " making sure I received all?
  3. In your tutorial you mention " If you need to ensure the Serial input buffer is empty you can do so
  • like this/i]*

* *while (Serial.available() > 0) {     Serial.read(); }* *

  • Where exactly do I put this code ?*
    Thank you for your kind help.

This

Serial.write(<TaskN, Duration>);

should be

Serial.print('<');
Serial.print(TaskN);
Serial.print(',');
Serial.print(Duration);
Serial.print('>');

I don't understand what you have in mind with this

  1. Can I take the sender's and the receiver's code out of the " void loop" and just send once and receive
    once in " void setup " making sure I received all?

Where exactly do I put this code ?

At the point in the program where you want to ensure that the buffer is empty - that is usually before you ask for new data.

Why is the duration a float?

...R

Robin,

After some contemplation and reading tutorials like your excellent "Planning and Implementing an Arduino Program" I think I've chosen the wrong approach to my problem. Let me explain better:

Arduino1 has n functions (task1, task2,....taskn) each task moves 25 servos in different pattern
for different amount of time. What I'm trying to do is when Arduino1 is doing, lets say, task1 then
Arduino2 should play music called "song1.wav", task2 then play "song2.wav", and so on.
When Arduino1 has finished task1 then Arduino2 should stop playing "song1".

I think my approach of sending the duration of the song play to Arduino2 is wrong . because I have to go through measuring the time laps of all tasks on Arduino1 before hand.

Instead I should just send the song number to Arduino2 (done already) and send a stop play music signal
to arduino2. Something like if a button is pressed then stop playing , but no button just a serial STOP.

I don't know how to "interrupt" Arduino2 from playing the song and wait for the next song number to arrive.

As you can tell I'm a newbie, trying to learn, and could ask stupid questions but I appreciate the help I'm getting in this forum.

ba47:
Instead I should just send the song number to Arduino2 (done already) and send a stop play music signal
to arduino2. Something like if a button is pressed then stop playing , but no button just a serial STOP.

That sounds like a good idea.

I don't know how to "interrupt" Arduino2 from playing the song and wait for the next song number to arrive.

You need to post the program that plays the songs

...R

Sure, here is my "spaghetti" code to play the song.

I've not included the part where I receive the song number which will be like your example 5 in your
Serial Input Basics/b] without the "HelloWorld".
```
**//// RICEVE SONG NUMBER <<<<<<<<<<<<<

#include "SD.h"
#define SD_ChipSelectPin 4
#include "TMRpcm.h"
#include "SPI.h"

TMRpcm tmrpcm;

byte n = 0;

void setup() {

tmrpcm.speakerPin = 9;
  Serial.begin(9600);
  SD.begin(SD_ChipSelectPin);

// Recieve Song number
// will use Robin's code example 5 without " Hello World "
//xxxxxxxxxxx

tmrpcm.setVolume(5);

switch (n) {
    case 0:
      goto DONT PLY or Stop Playing; // ??
      break;

case 1:
      tmrpcm.play("song1.wav");
      break;
    case 2:
      tmrpcm.play("song2.wav");
      break;

case 3:
      tmrpcm.play("song3.wav");
      break;

case 4:
      tmrpcm.play("song4.wav");
      break;
    case 5:
      tmrpcm.play("song5.wav");
      break;
    case 6:
      tmrpcm.play("song6.wav");
      break;
    case 7:
      tmrpcm.play("song7.wav");
      break;
    case 8:
      tmrpcm.play("song8.wav");
      break;
    default:
      // if nothing else matches, do the default
      Serial.println("No song number");
      // default is optional
      break;
  }

}

void loop() {

}**
```

ba47:
Sure, here is my "spaghetti" code to play the song.

It seems that the library you are using has a stopPlayback() function

...R

thanks for the link.

So now I just have to send a STOP = 0 signal and add :

switch (n) { .  // song number received
    case 0:
      audio.stopPlayback();      stops the music, but leaves the timer running
      break;
    case 1:

ba47:
So now I just have to send a STOP = 0 signal and add :

I think so.

...R

Isn't the processor busy playing music and not listening to incoming STOP ?
How do I implement listen to incoming signal for STOP while busy playing ?

thanks

Thank you Robin,

Here's my code which works fine. Please DO tell me if it can be improved.

Sender code :

// SEND songN  

byte songN = 1;  // songN = 0 will stop the current song which is playing
                         // songN = 1 plays "song1.wav", songN = 2 plays "song2.wav", etc.

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

void loop() {
  Serial.write(songN);
}

The ReceiverAndPlayer code:

//// receive songN and play songN.wav

#include "SD.h"
#define SD_ChipSelectPin 4
#include "TMRpcm.h"
#include "SPI.h"

TMRpcm tmrpcm;

byte songN = 0;
byte songPlaying = 0;

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

  if (!SD.begin(SD_ChipSelectPin)) {
    Serial.println("SD fail");
    return;
  }

  tmrpcm.setVolume(5);
  tmrpcm.speakerPin = 9;

}

void loop()
{
  recvSongN();

  if (songN != songPlaying) {
    songPlaying = songN;
    PlaySong();
  }

}  // end of loop



//================

void recvSongN() {   // if serial data available, read songN

  while (Serial.available() > 0 )
    songN = Serial.read();


  // while (Serial.available() > 0) {   // Empty buffer
  //   Serial.read();
}


//===============

void PlaySong() {

  switch (songN) {
    case 0:
      tmrpcm.stopPlayback();
      break;

    case 1:
      tmrpcm.play("song1.wav");
      break;
    case 2:
      tmrpcm.play("song2.wav");
      break;

    case 3:
      tmrpcm.play("song3.wav");
      break;

    case 4:
      tmrpcm.play("song4.wav");
      break;
    case 5:
      tmrpcm.play("song5.wav");
      break;
    case 6:
      tmrpcm.play("song6.wav");
      break;
    case 7:
      tmrpcm.play("song7.wav");
      break;
    case 8:
      tmrpcm.play("song8.wav");
      break;
    default:
      // if nothing else matches, do the default
      Serial.println("No songN recieved");
      // default is optional
      break;
  } // end of switch

} // end of PlaySong

By the way Robin, thank you for your tutorials and your help. You are a kind and excellent mentor.

ba47:
Here's my code which works fine. Please DO tell me if it can be improved.

Glad to hear it works.

I'm not good at improvements - if it works, it works.

From Reply #16

Isn't the processor busy playing music and not listening to incoming STOP ?

I guess you missed the bit in the link in Reply #13 where it says Asynchronous Playback: Allows code in main loop to run while audio playback occurs.

...R

A possible improvement might be to build the song name string on the fly rather than hardcoding them all in a case statement. Sprintf would help you to do it. Before you do though, consider whether you're going to add move music files and what their naming convention would be.