Timing events across 2 Arduino controllers

Hello everybody,

I am very new to Arduino world and I have only just started learning it for a rather specific reason. I am wanting to create a sketch that will operate Drag racing staging lights. I have so far written below sketch and have a little prototype working on tinkercad circuit whilst I'm waiting for Arduino controller to come in mail.

Now, I would like to expand this sketch in a way where I will have a second Arduino with 2 more sonar sensors connected to my first Arduino. I would like it to capture time from when green lights light up on Arduino 1 and trigger the sonar sensors on Arduino 2. In effect showing me time spent of an object traveling between Arduino 1 and 2.

From what I understand I could somehow use Millis() for this, however I am unsure how to get Millis() synced over 2 Arduino controllers?

Any help you could provide me would be greatly appreciated and needed as I am currently out of ideas and am unsure of what to research to get the right answers.


!

/* Pin allocation */

#define stageLEDL  A5 //Left staging light
#define stageLEDR  5 //Right staging light
#define yellow1  A4 //first yellow row
#define yellow2  2 //second yellow row
#define yellow3  3 //third yellow row
#define greenLEDR  4 //green left go light
#define greenLEDL  A3 //green right go light
#define TRIGGERLS_PIN   8  //for left staging sensor
#define ECHOLS_PIN      9  //for left staging sensor 
#define TRIGGERRS_PIN   12 //for left staging sensor 
#define ECHORS_PIN      13 //for left staging sensor
#define SWITCH_PIN 		11 //switch pic alocation

int echoTimeLS;             //time in us
int distanceLS;           //distance in mms

int echoTimeRS;				//time in us
int distanceRS;			  //distance in mms


void setup()
{
  /* Pin I/O allocation */
  
  //Serial.begin(9600);
  pinMode(SWITCH_PIN, INPUT);
  
  //LEDS
  
  pinMode(stageLEDL, OUTPUT);
  pinMode(stageLEDR, OUTPUT);
  pinMode(yellow1, OUTPUT);
  pinMode(yellow2, OUTPUT);
  pinMode(yellow3, OUTPUT);
  pinMode(greenLEDR, OUTPUT);
  pinMode(greenLEDL, OUTPUT);
  
  //Staging Sensors
  
  pinMode(TRIGGERLS_PIN, OUTPUT);
  pinMode(ECHOLS_PIN, INPUT);
  digitalWrite(TRIGGERLS_PIN, LOW);     //set trigger pin LOW - idle state
  
  pinMode(TRIGGERRS_PIN, OUTPUT);		//same as above but for right staing sensor
  pinMode(ECHORS_PIN, INPUT);
  digitalWrite(TRIGGERRS_PIN, LOW);
}

void loop()
{
 
  stagingSensors();
  
  if (digitalRead(SWITCH_PIN) == HIGH)
  {
             
         
            //LEDS
            if (digitalRead(stageLEDL) == HIGH && (digitalRead(stageLEDR) == HIGH)) 
            {
            delay(3000);						 //staging lights delay
            digitalWrite(yellow1, HIGH);  	 //first yellow row on and off
            delay(1000);
            digitalWrite(yellow1, LOW);
            digitalWrite(yellow2, HIGH); 	 	 //second yellow row on and off
            delay(1000);
            digitalWrite(yellow2, LOW);
            digitalWrite(yellow3, HIGH); 		 //third yellow row on and off
            delay(1000);
            digitalWrite(yellow3, LOW);
 			stagingSensors();
                if (digitalRead(stageLEDL) == HIGH )
                {  
                digitalWrite(greenLEDL, HIGH); 	 //green left go lights on
                }

                if (digitalRead(stageLEDR) == HIGH )
                {  
                digitalWrite(greenLEDR, HIGH); 	 //green left go lights on  
                }
            delay(2000);  
            digitalWrite(greenLEDL, LOW);
            digitalWrite(greenLEDR, LOW);
            digitalWrite(stageLEDL, LOW);
            digitalWrite(stageLEDR, LOW);
            }  
  }
}
/* This is staging sensors left and right constant check function */

void stagingSensors()
{
  /* Left lane staging sensor */
  digitalWrite(TRIGGERLS_PIN, HIGH);    //send trigger pulse
  delayMicroseconds(10);
  digitalWrite(TRIGGERLS_PIN, LOW);
  echoTimeLS = pulseIn(ECHOLS_PIN, HIGH); //capture the echo signal and determine duration of pulse when HIGH
  distanceLS = (echoTimeLS*0.034*10)/2;    //obtain distance (in mm), from time
  
  /* Right lane staging sensor */
  digitalWrite(TRIGGERRS_PIN, HIGH);    //send trigger pulse
  delayMicroseconds(10);
  digitalWrite(TRIGGERRS_PIN, LOW);
  echoTimeRS = pulseIn(ECHORS_PIN, HIGH); //capture the echo signal and determine duration of pulse when HIGH
  distanceRS = (echoTimeRS*0.034*10)/2;    //obtain distance (in mm), from time
  
  /* Distance sensitivity of the sonar sensors in mm */
  
  if (distanceLS >= 200 &&  distanceLS <=2000)
  {
    digitalWrite(stageLEDL, HIGH);
  } else {
    digitalWrite(stageLEDL, LOW);
  }
  
  if (distanceRS >= 200 &&  distanceRS <=2000)
  {
    digitalWrite(stageLEDR, HIGH);
  } else {
    digitalWrite(stageLEDR, LOW);
  }   
}

Make the second Arduino respond with its "local time" millis() on the start message. Then calculate the time difference and use it to translate all subsequent times.

If you suspect a considerable time lag in transmissions then determine the travel time by sending a message and check how many millis it takes until the answer arrives. This will give the time for 2 transmissions, hence and forth, so that the delay between an event and the arrival of the event message on the other system is half that measured delay.

How far apart will the two Arduinos be?

For the testing purposes I am just connecting them through wire.h library and they will only be about a meter apart until I get the sketch to perform the timing. In the long run I was hoping to use wifi modules on both Arduinos to talk to each other.

When the light goes green, send something, anything over the wire/wifi to Arduino2. Have it be looping waiting for that message and when it arrives, store millis. Store millis in another variable when the sonar sees something.

There's the means to calculate your elapsed time. It can be transmitted back to Arduino1 if necessary.

I will start experimenting with this right away! So to dumb it down for myself; I would run millis on Arduino2 then send it to Arduino1 where I would grab the remote millis and take away from Arduino1 millis. Which in turn would leave me with time difference between the two? then depending if its positive or negative I would plus or minus this difference from all subsequent times?

Understood about testing 1 metre apart but how far apart will they be in practice ? If nothing else it will influence which wireless technology you use

You mention WiFi. Will both of the Arduinos be in range of the same WiFi router ?

Just go the easy way. Sync each Arduino to a good time source (such as connecting a GPS module to each Arduino). Then, at the start of the race, capture the current time at Arduino 1. At the end of the race, capture the current time at Arduino 2. Subtract the two times and you got travel time between A and B. This works with Arduinos that are a meter apart, or 10 kms apart.

Its a valid approach if the 'race' less than one second, you can use the GPS PPS output to start a timer.

For longer races, appreciate that two GPSs even 1M apart can report times (as in hours\mins\seconds) that are different by 1 - 2 seconds, possibly more.

Yes :slight_smile:

I was thinking of utilizing NRF24L01 modules for both Arduinos, in the perfect world I would like them to be 40m apart and hopefully still be in signal range of each other. As it will be in an open environment with no buildings to interfere

if (digitalRead(stageLEDL) == HIGH )
                {  
                digitalWrite(greenLEDL, HIGH); 	 //green left go lights on
                Wire.beginTransmission(4); // transmit to device #8
                Wire.write("GLedL");        // sends five bytes
                Wire.endTransmission();    // stop transmitting  
                }

so far I am able to send this to the Arduino2, and receive and print to serial using

void setup()
{
  Wire.begin(4);                // join i2c bus with address #4
  Wire.onReceive(receiveEvent); // register event
  Serial.begin(9600);           // start serial for output
}

void loop(){
}

void receiveEvent(int howMany){
  while(Wire.available() > 0) // loop through all but the last
  {
       char a = Wire.read(); // receive byte as a character
    	Serial.print(a);
    delay(10);
  }
delay(500);
}

Now, i am struggling to assign anything i send to the slave to a variable where I could use it in an IF statement.. for example if led = "GLedL" then capture millis. How would i go about that?

No need to be so complicated. Just send 'G'. Then you can test it with:

if(a=='G')

I haven't had much time to work on this unfortunately due to work commitments. However I have come up with some stuff that sort of work, but still does not do certain things I would like it to. I actually managed to get it to print time elapsed from the green light time to trigger time at the finish line. However when I try to modify the sketch so I can time the left and right lanes separately, I run into issues with wire.write and wire.read. Here is some of the relevant code, hopefully I can grab some further helpful hints from you. At this point when I try to assign variables from data to either a and b it will only assign a = 1 and not b = 2. I'm assuming its something to do with how arduino2 is receving the write.read data. when i print data variable to serial it appears as 1 followed by 2.

here is the sketch from both arduinos.
Arduino1

if (digitalRead(stageLEDL) == HIGH )
                {  
                digitalWrite(greenLEDL, HIGH); 	 //green left go lights on
                Wire.beginTransmission(4); // transmit to device #4
                Wire.write(1);        // sends this to slave
                Wire.endTransmission();    // stop transmitting 
                }
				
                if (digitalRead(stageLEDR) == HIGH )
                {  
                digitalWrite(greenLEDR, HIGH); 	 //green right go lights on
                Wire.beginTransmission(4); // transmit to device #4
                Wire.write(2);        // sends this to slave
                Wire.endTransmission();    // stop transmitting   
                }

Arduino2

void loop(){
  
  if (a == 1) {
  GreenTimeLS = millis();
  a = 0;
  }
  if (b == 2) {
  GreenTimeRS = millis();
  b = 0;
  }

  Sensors();
  
  if (distanceLS >= 400 &&  distanceLS <=3000){      
  TriggerTimeLS = millis();
  (ElapsedTimeLS = TriggerTimeLS - GreenTimeLS);
    if (GreenTimeLS > 0){
      Serial.print("Left Lane: ");
      Serial.print(ElapsedTimeLS);
      Serial.println(" ms");
      ElapsedTimeLS = 0;
      GreenTimeLS = 0;
    }
  }
  if (distanceRS >= 400 &&  distanceRS <=3000){      
  TriggerTimeRS = millis();
  (ElapsedTimeRS = TriggerTimeRS - GreenTimeRS);
    if (GreenTimeRS > 0){
      Serial.print("Right Lane: ");
      Serial.print(ElapsedTimeRS);
      Serial.println(" ms");
      ElapsedTimeRS = 0;
      GreenTimeRS = 0;
    }
  }    
}


void receiveEvent(int howMany){
  while(Wire.available() > 0) // loop through all but the last
  {
    data = Wire.read(); // receive byte as a character
     if (data == 1){
      a = 1;
     if (data == 2){
      b = 2;
  }
     }
    Serial.println(data); // shows both 1 followed by 2
    //Serial.print(a);  //prints value of 1 to serial as intended, but for some reason it shows up twice
    //Serial.print(b);  //only ever prints 0, twice as well for some reason
    delay(10);
  }
}

Your code, as is, does not make much sense to me.
Misplaced parentheses, let the IDE format your code.
Why delay()?

How many millis does a transfer take? I'd use micros instead.

Sorry about that, I will fix it up as soon as I get onto my desktop! I removed the delay() as well as made some other tweaks and I actually have it working now! I can time left and right individually sides, which is pretty awesome!

Now I am moving onto last stages of my project and I have come across another challenge.

I need to send back the left and right timing back to Arduino1 to display on an LCD screen. Now I am just thinking, how can I send the data e.g. 1500ms and 2500ms. How will Arduino1 know which is left and which is right?

Any ideas of how I can go about this?

Because you will precede the data with a label

Could you please shine some more light on this for me, at the moment when I try to send var containing the elapsed time from the slave to the master, I get a whole bunch of 255255255 instead of what the variable contains.

ElapisedTimeLS is unsigned long

Master

void loop()
{
           	Wire.requestFrom(4, 4);    // request 4 bytes from slave device #4

            while (Wire.available()) { 
              int c = Wire.read();
              Serial.print(c);        
            }
  			delay(500);
}

Slave

void requestEvent() {
  Wire.write(ElapsedTimeLS); 
}

Output on master:
image

See the Arduino Reference for Wire.write(). It only sends a single byte. You have to call it 4 times to transmit 4 bytes.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.