Arduino to Arduino Wire Communication

Hey guys, this is my first question, so please bare with me if I'm doing something slightly wrong. I am currently making a GPS Waypoint Robot controller and have done so with two arduino nanos, a 9 axis IMU, and a BN880 module. I am using one arduino to decode GPS signals and compute the required heading and am currently sending it over software serial to the other arduino. It works, but it is incredibly slow and is already wired to work over i2c. Currently, I am working on getting the i2c communication to work, but consistently run into the problem of good communication for a couple seconds which is followed by the entire program not working. Here are the bits of code I am using to communicate over the Wire library:

// WIRE VARIABLE INITIALIZATION

union float_byte {

float value;

byte b[4];

};

union short_byte {

short value;

byte b[4];

};

union float_byte distanceTo;

union short_byte headingReq;

union float_byte currentLat;

union float_byte currentLon;

union short_byte currentSpeed;

// WIRE TEST END

void loop() {
...
distanceTo.value = dist;

headingReq.value = int(h);

currentLat.value = gps.location.lat();

currentLon.value = gps.location.lng();

currentSpeed.value = int(gps.speed.mph());

// 4 byte, 1 byte, 4 byte, 1 byte (end)

Wire.beginTransmission(4); //address is queued for checking if the slave is present

for (int i=0; i<4; i++)

{

  Wire.write(distanceTo.b[i]);  //data bytes are queued in local buffer

}

for (int i=0; i<4; i++)

{

  Wire.write(headingReq.b[i]);  //data bytes are queued in local buffer

}

Wire.endTransmission();
...

}

------------- on receiving end (where the problems lie) ----------
void receiveEvent(int howMany) {

Serial.println(howMany);

wireCount = 0;

while(4 < Wire.available() && wireCount <= 3) // loop through all but the last

{

distanceTo.b[wireCount] = Wire.read(); // receive byte as a character

wireCount++;

}

wireCount = 0;

while(0 < Wire.available() && wireCount <= 3) // loop through all but the last

{

headingReq.b[wireCount] = Wire.read(); // receive byte as a character

wireCount++;

}

//Serial.println("Dist: " + String(distanceTo.value) + "\tHeading: " + String(headingReq.value));

}

Welcome to the forum.

Can you please modify your original post to ensure the source code is in a single box. It should look like this.

// Your example source code

You need three ' at the beginning and end in the edit window? When you click on this icon </> you get.

```
type or paste code here
```

This ensures we can get all the source code. Right now if you copy the code there are invisible characters that prevent successful compilation and parts might be missing.

Also tell us which Arduino you are using and post a schematic of your system (hand drawn is OK). I2C requires pull-up resistors on both lines.

Not surprising. Software serial is never a good idea and, at times like this, a seriously bad one. With hardware serial Arduino<>Arduino comms can be at 500,000 baud.

It might be time to start talking about transmission distance.... I raise this because, if the distance is short enough for practical communications via I2C, it might be time to question why you are using two arduinos. I2C is typically used to communicate with peripherals - close ones. Further, I don't think I2C has ever been famous for speed. I believe SPI comms are faster. You might check the Nick Gammon site.

Yeah, haven't really looked into using hardware serial, but I'll leave that as a backup in case I'm not able to figure out this problem. As for transmission distance, all of the hardware is on a PCB with the i2c wires running no longer the 6 inches. Using two arduino nanos two handle two separate tasks. One is connected to the GPS over serial and determines required heading and distance between current location and waypoint. Second arduino runs PID loop to control all rover hardware. (in case you didn't' notice, making a UGV). I'll have to look into SPI. Currently using i2c cause I made the PCB connection and wasn't using it. Also, I'd really love to solve this problem for future projects where i2c arduino to arduino communication is useful.

Weirdest thing is that my code works, but for only about 3 seconds before I stop getting any serial output.

Hence the question, again: why are you using two Arduinos?

What, as opposed to one? It turns out I can't fit all my code onto a single arduino nano + GPS really slows down everything in a environment where delays of any sort can throw off my PID controller. My GPS UGV currently runs at a light jogging speed.

Might consider something like a Mega with its 3 extra hardware serial ports. There is a Pro Mega that is a smaller board.

But about the Wire problem I'm having. Anyone experience the same? Or perhaps have an example of sending multiple data types over the Wire library. From my testing, it seems like something is getting full. I originally though it was the Wire buffer, but that's not the case cause I used the flush command after receiving and the problem persisted. If I add a delay, my code works for a little bit longer. What else could be getting full?

Perhaps now would be a good time to show us your schematic as well.

Right, here you go.
**I've also added wires which go directly from one arduino's SDA/SCL pins to the other

You may well need pullup resistors on your SCL and SDA lines if they are not provided by the MPU9250 board as I don't think they are fitted on the Nano boards.

Hmm, I'll give it a shot. I just assumed no pull up due to the arduino example using the uno. Also, it shouldn't matter what it's pulled up to right (3.3 or 5)? Considering i2c works on both logic levels. Will probably pull up to 5, but I'll let you guys know if it does anything.

The pullup resistors go to the same voltage level that the processor is using.

Yeah, just tried this, but still have the same problem. Works for a couple seconds before serial output stops.

Never mind, I figured it out. Turns out the problem had to do with the way I programmed by Arduinos. I had my Arduino master acting as a slave when communicating with the other arduino. All I had to do is use the onRequest function as opposed to the onReceive. But thanks for your guys' help anyways. May eventually switch to SPI if I have the time.

If you guys are interested in my project you can check out my website: Nitish Chennoju

and a short youtube video I made of my rover (while using software serial lol): Arduino GPS Robot - YouTube

@nchennoju There are problems in your hardware and software. If you show the new sketch, then we can help to improve it.

You can edit a post, for example your top post, so we can read the sketch.
Put the sketch between three backward-single-quotes, or use the </> button.

```
Your sketch
```

We prefer to send a struct.
Tutorial: Use I2C for communication between Arduinos

You can read this page on my Wiki at Github to see what kind of trouble you are in: How to make a reliable I2C bus.

All my code is on github now. I was doing point 8 in "How to make a reliable i2c bus". Maybe something to figure out later if required, but for my purposes, it was a mistake of understanding. Anyhow, everything is implemented onto my UGV and I was able to make an update video of my progress: https://youtu.be/W_EcyfvVpvw.

For my code, check out my github repo: GitHub - nchennoju/Arduino-GPS-Waypoint-UGV

As for using structs, lets just say I've gotten a bit lazy after getting my wire COM to work using unions and a constant assortment. But, from next time onwards, I'll be sure to follow the proper code format. And thanks for the help.

I2C Slave

You don't need those unions, you can use a pointers.
Assuming distanceTo is a normal 'float':

Wire.write( (char *) &distanceTo, sizeof( distanceTo));

The variables that are used in a interrupt (the onRequest handler) should be "volatile".

I2C Master

You don't need all those while(12 < Wire.available()). Just one simple check is enough.
If 16 bytes are requested, then check if 16 bytes are received.

int n = Wire.requestFrom(4, 16);
if( n == 16)            // received the right amount of bytes ?
{
  for( int i=0; i<4; i++)
  {
    distanceTo.b[i] = Wire.read();
  }
  ...
}

If you transfer a 'struct', then you don't need all those for-loops. Just one simple Wire.readBytes() to get all 4 variables.

Please remove these lines: while (Wire.available() < 3);
I think I saw about 6 of those. That is nonsense code.

You could add a check for all the I2C sensors in setup(). Perhaps a connector is loose or a wire broken.

Hardware

The MPU-9250 is a 3.3V sensor with a 3.3V I2C bus. The Arduino Nano has a 5V I2C bus.

I can't see how the GND current from the motors is going.