0

I am working on an Arduino project, where I am transmitting GPS data between two Arduinos. This code can transmit the raw GPS data:

int a = Serial1.available(); 
if(a){
    uint8_t hej[a]; 
    for(int i=0; i<a; i++){
        hej[i] = Serial1.read(); 
    }

    rf95.send(hej, a);
}

I need to be able to identify the device that's transmitting the data. This can be in form of an integer value. I have tried to add a value to the array, but that messes up the data when I receive it. Is there a simple way to add an ID to the data I am transmitting?

3
  • Send your data as a struct.
    – PhillyNJ
    Dec 6, 2017 at 11:37
  • Are you sure your data isn't being messed up when you incorrectly read it from serial? hackingmajenkoblog.wordpress.com/2016/02/01/…
    – Majenko
    Dec 6, 2017 at 12:03
  • I have had a lot of trouble sending the GPS data from the transmitter to the receiver. But with this code I atleast get something back, as you can see in this screenshot from the serial monitor on my receiver: prntscr.com/hjtvql The data is sometimes messed up as you mention, but I don't know how to solve it. The only data I need is actually some kind of ID (this can be premade) and then the location data (latitude and longitude) Dec 6, 2017 at 12:32

3 Answers 3

2

I would suggest:

  1. Use a library (TinyGPS++ for example) to read the GPS data and extract just what you want.
  2. Use a struct to craft a packet that you can send over bluetooth, or send the data as a textual representation, depending on your needs.

For a struct you can:

struct packet {
    uint8_t id;
    float latitude;
    float longitude;
};

struct packet myPacket;
myPacket.id = 32; // Unique ID
myPacket.latitude = gps.getLatitude(); // Whatever function call here
myPacket.longitude = gps.getLongitude(); // or whatever
rf95.send((uint8_t *)&myPacket, sizeof(struct packet));
0

Well, the main problem here is that you don't know when the string will enter from the serial port. For instance, let's see a sample communication:

$GPGGA,154655,4328.1874,N,00340.5185,W,1,03,08.5,-00044.7,M,051.6,M,,*79 
$GPGSA,A,2,13,23,25,,,,,,,,,,08.5,08.5,00.9*0E 
$GPGSV,3,1,10,02,50,290,26,04,60,210,26,08,33,173,29,10,21,296,00*7E

Making a sample reading like this:

int a = Serial1.available(); 
if(a){
    uint8_t hej[a]; 
    for(int i=0; i<a; i++){
        hej[i] = Serial1.read(); 
    }

    Serial.print("Received \"");
    Serial.write(hej, a);
    Serial.println("\"");
}

you will see something like

Received "$GPG"
Received "GA,1546"
Received "5"
Received "5,4"

or, most probably,

Received "$"
Received "G"
Received "P"
Received "G"
Received "G"
Received "A"

so it is difficult to detect where to insert your ID.

I have two solutions for you.

The simpler one is to use the fact that the GPS sends formatted sentences. According to the NMEA specification, the message is at most 82 chars long and is terminated by a LF (0x10) char. This means that you can do something like this (I assume you want to use a 4-chars ID, and in this case the ID is MYID)

#define ID_LENGHT 5 /* 4 chars and a separator */
#define BUFFERSIZE ID_LENGHT+82 /* ID plus the max NMEA sentence*/
byte recvBuffer[BUFFERSIZE];
byte recvIdx;

void setup()
{
    // ... other initialization

    // Fill the ID at the beginning, and prepare to store data at the end of ID
    memcpy(recvBuffer, "MYID-", ID_LENGHT * sizeof(byte));
    recvIdx = ID_LENGHT;
}

void loop()
{
    // ... other program

    while (Serial1.available())
    {
        byte ch = Serial1.read();
        if (recvIdx >= BUFFERSIZE)
            continue; // Should never arrive here, since the sentences are shorter
        recvBuffer[recvIdx++] = ch;
        if (ch == 0x10) // received LF, so end of sentence
        {
            // Send the buffer (plus the identifier)
            rf95.send(recvBuffer, recvIdx);
            // Reset the idx (and so you will overwrite previous buffer
            recvIdx = ID_LENGHT;
        }
    }

    // ... Other code
}

This approach transfers a lot more thata then needed, since you want to only transfer the latitude and longitude. So the second (and best) approach in my opinion is to have a NMEA parser on the arduino that extracts the lat and long values you need and then sends a (formatted) message to the master, with ID, lat and long.

This is the best solution, but I don't have experience with NMEA parsers so you'd better try searching online for some library and, most important, have the necessary computational power and flash available to perform this computation

0

You could try NeoGPS. NeoGPS is smaller, faster, more reliable and more accurate than all other GPS libraries. It packages all the GPS fields into a structure for you:

#define gpsPort Serial1

struct msg_t {
  uint8_t ID;   // A node's ID
  gps_fix fix;  // The NeoGPS structure containing all configured GPS fields
};

msg_t msg = { THIS_NODE_ID };

void loop()
{
  if (gps.available( gpsPort )) {  // parses characters
    msg.fix = gps.read();          // gets the struct when it's ready (once per second)

    rf95.send( (uint8_t *) &msg, sizeof(msg) );  // send the msg struct
  }
}

The receiving side will similarly read into the same struct, something like:

    rf95.receive( (uint8_t *) &msg, sizeof(msg) );
    if ((msg.id == ROVER_ID) && msg.fix.valid.location) {
      // Check lat/lon against target location
       ...

This will also coordinate the RF transmission with the GPS quiet time, helping to avoid losing GPS characters while the RF transmission is busy.

The gps_fix structure can be quite small, depending on what GPS fields you enable in the NeoGPS configuration files. This structure is 10x to 80x smaller than the raw NMEA data, so it is transmitted very quickly. The default configuration uses only 31 bytes; most GPS devices send about 400 bytes per second.

If you'd like to try it, NeoGPS is available from the Arduino IDE Library Manager, under the menu Sketch -> Include Library -> Manage Libraries. You should also read about Choosing a Serial Port and the Troubleshooting tips.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.