GPS + RF module

Good evening,
I would ask help to solve a simple problem. I’m creating a simple code with an GPS shield and RF module but when I activate the string SetupRFDataTxnLink(transmit_pin, baudRate) and all the parts related to the RF module, the GPS doesn’t work. If I comment them the GPS works and in the Serial Monitor the coordinates appear.

The simple code is:
#include "TinyGPS++.h"
#include "SoftwareSerial.h"
#include <VirtualWire.h>
#include <string.h>
#include <stdio.h>
#include <DataCoder.h>
#include <VirtualWire.h>

SoftwareSerial serial_connection(10, 11);
TinyGPSPlus gps;

int transmit_pin = 12;
int baudRate = 1000;

void setup()
{

  SetupRFDataTxnLink(transmit_pin, baudRate);
  
 Serial.begin(9600);
  serial_connection.begin(9600);
  Serial.println("GPS Start");
  
}

void loop()
{ 
  float outArray[RF_DATA_ARRAY_SIZE];

  while(serial_connection.available())
  { 
    gps.encode(serial_connection.read());
  }
  if(gps.location.isUpdated())
  {
   
  outArray[1] = (gps.location.lat(), 6);
  outArray[2] = (gps.location.lng(), 6);

  union RFData outDataSeq; 
  EncodeRFData(outArray, outDataSeq);  
  TransmitRFData(outDataSeq);  

    Serial.println("Latitude:");
    Serial.println(gps.location.lat(), 6);
    Serial.println("Longitude:");
    Serial.println(gps.location.lng(), 6);

  }
}

Thank you very much
Best Regards
Denis Sangaletti

One major problem is SoftwareSerial. It blocks interrupts every time a GPS character comes in. You should use AltSoftSerial if you can put the GPS on pins 8 & 9. If not, try my NeoSWSerial instead. Both are much more efficient than SoftwareSerial.

You may also be interested in a smaller, faster GPS library, NeoGPS. Here is a NeoGPS & NeoSWSerial version of your sketch:

#include <NMEAGPS.h>
#include <NeoSWSerial.h>
#include <VirtualWire.h>
#include <DataCoder.h>

NeoSWSerial gps_port(10, 11);
NMEAGPS     gps;

int transmit_pin = 12;
int baudRate = 1000;

void setup()
{
  Serial.begin(9600);
  Serial.println( F("GPS Start") );  // F macro saves RAM

  SetupRFDataTxnLink(transmit_pin, baudRate);

  gps_port.begin(9600);
}

void loop()
{ 
  while (gps.available( gps_port ))
  { 
    gps_fix fix = gps.read();

    if (fix.valid.location)
    {
      float outArray[RF_DATA_ARRAY_SIZE];
      outArray[0] = fix.latitude();  // Arrays start at 0, not 1.  Did you really mean [1] here?
      outArray[1] = fix.longitude();

      Serial.println( F("Latitude:") );
      Serial.println( outArray[0], 6 );
      Serial.println( F("Longitude:") );
      Serial.println( outArray[1], 6 );

      union RFData outDataSeq; 
      EncodeRFData(outArray, outDataSeq);  
      TransmitRFData(outDataSeq);  
    }
  }
}

Notice that it checks to make sure you actually have a location value. If the satellite reception is bad, you may not have a location.

NeoGPS is available from the Arduino IDE 1.6.x Library Manager, or you can download the ZIP from the link above.

Cheers,
/dev

Thank you really really much. Now works correctly.

I'm sorry for the index numbers: when I formulated the question I deleted some useless parts and I forgot to change the numbers.

If I can, I would add another question.

with the gps shield I can obtain something like that Latitude: 45.465421 Longitude: 9.185924

but I receive just 45.50 and 9.20 when I would receive all the decimal part of the coordinates. Can you help me to correct the code in order to send all the numbers?

Thank you really much for your availability Best regard Denis Sangaletti

  outArray[1] = (gps.location.lat(), 6);
  outArray[2] = (gps.location.lng(), 6);

What do you think the , 6 crap there is doing? It is NOT.

Now works correctly.

The code you didn't post now does what you want, except it doesn't really, and you want to know why. Well, that's obvious. Something is wrong with the code you didn't post.

I’m sorry…
The trasmitter code is the same as suggested by /dev. The receiver code, instead is:

#include <DataCoder.h>
#include <VirtualWire.h>

const int rx_pin = 11;
const int led_pin = 13;
const int baudRate = 1000;

void setup()
{
  delay(1000);
  Serial.begin(9600);
  pinMode(led_pin,OUTPUT);
  digitalWrite(led_pin,LOW);
  SetupRFDataRxnLink(rx_pin, baudRate);

}

void loop()
{
	
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  
  union RFData inDataSeq;//To store incoming data
  
  float inArray[RF_DATA_ARRAY_SIZE];//To store decoded information
  
  
  if(RFLinkDataAvailable(buf, &buflen))
  {
        digitalWrite(led_pin, HIGH);
        
        for(int i =0; i< buflen; i++)
        {
          inDataSeq.s[i] = buf[i];
        }
        
        Serial.println();
        
        digitalWrite(led_pin, LOW);
      
        DecodeRFData(inArray, inDataSeq);
        
       
        Serial.print("Incoming:");

        for (int i=0; i < RF_DATA_ARRAY_SIZE; i++)
          {
            Serial.print(inArray[i]);
            Serial.print(", ");
          }
          Serial.println();

  }
  
}

and I would like to receive more precise coordinates.

Thank you very much
Best regard
Denis

It is receiving the full precision sent by the transmitter, but it is only printing 2 decimals. The default print of a float only shows 2 digits after the decimal point. You can tell it to print more:

    Serial.print( inArray[nobbc][i][/nobbc][b][size=3], 6[/size][/b] );

However, a float only has 7 significant digits, so 45.465421 is only good to 5 decimal places (2 for the "45" leaves 5 for the ".46542"). The 9.185924 is correct with 7 digits (1 for "9" and 6 for ".185924").

Cheers, /dev

thank you really much for your help,

But in this case I obtain 9.200000 and not 9.185924. Maybe I forgot something when I define the message sent with the RF module.

Maybe, do you know what I forgot?

thank you really really much again. Best Regards Denis

I obtain 9.200000 and not 9.185924.

Ok, that's officially weird. It's not easy to round like that.

Please post the transmitter and the receiver code again, just to be sure.

Also attach the files (or a zip) of the DataCoder library. Select the "Attachments and other options" in the lower-left corner.

Cheers, /dev

thank you…
the trasmitter code is

#include <NMEAGPS.h>
#include <NeoSWSerial.h>
#include <VirtualWire.h>
#include <DataCoder.h>

NeoSWSerial gps_port(10, 11);
NMEAGPS     gps;

int transmit_pin = 12;
int baudRate = 1000;

void setup()
{
  Serial.begin(9600);
  Serial.println( F("GPS Start") );  // F macro saves RAM

  SetupRFDataTxnLink(transmit_pin, baudRate);

  gps_port.begin(9600);
}

void loop()
{ 
  while (gps.available( gps_port ))
  { 
    gps_fix fix = gps.read();

    if (fix.valid.location)
    {
      float outArray[RF_DATA_ARRAY_SIZE];
      outArray[0] = (fix.latitude());  
      outArray[1] = (fix.longitude());

      Serial.println( F("Latitude:") );
      Serial.println( outArray[0], 6 );
      Serial.println( F("Longitude:") );
      Serial.println( outArray[1], 6 );

      union RFData outDataSeq; 
      EncodeRFData(outArray, outDataSeq);  
      TransmitRFData(outDataSeq);  
    }
  }
}

the receiver code, instead,is

#include <DataCoder.h>
#include <VirtualWire.h>

const int rx_pin = 11;
const int led_pin = 13;
const int baudRate = 1000;

void setup()
{
  delay(1000);
  Serial.begin(9600);
  pinMode(led_pin,OUTPUT);
  digitalWrite(led_pin,LOW);
  SetupRFDataRxnLink(rx_pin, baudRate);

}

void loop()
{
	
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;
  
  union RFData inDataSeq;//To store incoming data
  
  float inArray[RF_DATA_ARRAY_SIZE];//To store decoded information
  //RF_DATA_ARRAY_SIZE can be changed if need be inside DataCoder.h
  
  
  if(RFLinkDataAvailable(buf, &buflen))
  {
        digitalWrite(led_pin, HIGH);
    
        for(int i =0; i< buflen; i++)
        {
          inDataSeq.s[i] = buf[i];
        }
        
        Serial.println();
        
        digitalWrite(led_pin, LOW);
      
        DecodeRFData(inArray, inDataSeq);
        
        //Do something with the information that have been received
       
        Serial.print("Incoming Data:");

        for (int i=0; i < RF_DATA_ARRAY_SIZE; i++)
          {
            Serial.print(inArray[i], 6 );
            Serial.print(", ");
          }
          Serial.println();
          Serial.print("Bytes Used:");
          Serial.println(RF_DATA_ARRAY_SIZE * 2);
  }
  
}

thank you really much
Best regards
Denis

DataCoder.zip (7.82 KB)

Dear /Dev,

I think to have found the problem. If you look the file DataCoder.h there are the following lines:

#define RF_DATA_ARRAY_SIZE 4 //The number of elements to be held in the array

#define RF_DATA_DECIMAL_PLACES 1//The number of decimal places that will be encoded

#define UNION_EXPANSION_FACTOR 2//The number of bytes occupied by each element of the encoded RFData packet. This data is //stored in dataBox[]. See below.

I imposed the following data:

define RF_DATA_ARRAY_SIZE 2

define RF_DATA_DECIMAL_PLACES 4

define UNION_EXPANSION_FACTOR 4

and now I obtain this:

Trasmitter: 45.726005, 9.655824

Receiver: Incoming Data: 45.724998, 9.650000, Bytes Used:4

I don't understand why I cannot receive for example

45.726000, 9.656 or more precise numbers

Can you help me to understand where I made mistakes?

thank you really really much Best regard Denis

After looking at the DataCoder library, I have to ask: Do you have to use the DataCoder library? It is limited to 5 significant digits, like you are seeing.

It would be much easier to use the basic sender/receiver examples in the VirtualWire library. Here is your transmitter sketch without the DataCoder library:

#include <NMEAGPS.h>
#include <NeoSWSerial.h>
#include <VirtualWire.h>

NeoSWSerial gps_port(10, 11);
NMEAGPS     gps;

const int transmit_pin = 12;
const int baudRate     = 1000;

const int LED          = 13;

void setup()
{
  Serial.begin(9600);
  Serial.println( F("GPS Start") );
  if (sizeof(gps_fix) > VW_MAX_PAYLOAD) {
    Serial.print( F("ERROR - fix message size too large: ") );
    Serial.print( sizeof(gps_fix) );
    Serial.print( F(" > MAX ") );
    Serial.println( VW_MAX_PAYLOAD );
    Serial.println( F("Edit Libraries/NeoGPS/GPSfix_cfg.h and comment out some of the #defines") );
    for (;;); // stop here!
  }

  // Initialise the IO and ISR
  vw_set_tx_pin(transmit_pin);
//vw_set_rx_pin(rx_pin);
  vw_setup(baudRate);       // Bits per sec

  pinMode( LED, OUTPUT );
  digitalWrite( LED, LOW );
  
  gps_port.begin(9600);
}

void loop()
{
  // Check for GPS data
  while (gps.available( gps_port ))
  { 
    gps_fix fix = gps.read();

    if (fix.valid.location)
    {
      Serial.println( F("Latitude:") );
      Serial.println( fix.latitude(), 6 );
      Serial.println( F("Longitude:") );
      Serial.println( fix.longitude(), 6 );

      // Only send another fix if the previous one was finished sending
      if (!vx_tx_active())
      {
        // Send the entire fix
        vw_send( (uint8_t *)&fix, sizeof(fix) );
      }
    }
  }

  // Show transmitter status
  digitalWrite( LED, vx_tx_active() );
}

It just sends all the bytes of a fix. The receiver will get everything you have configured in GPSfix_cfg.h, including the valid flags. Remove the LED statements if you don’t want to flash the on-board LED.

The receiver sketch should be something like this:

#include <VirtualWire.h>

const int rx_pin    = 11;
const int baudRate = 1000;

void setup()
{
  Serial.begin(9600);
  Serial.println( F("GPS Receiver Start") );
  if (sizeof(gps_fix) > VW_MAX_PAYLOAD) {
    Serial.print( F("ERROR - fix message size too large: ") );
    Serial.print( sizeof(gps_fix) );
    Serial.print( F(" > MAX ") );
    Serial.println( VW_MAX_PAYLOAD );
    Serial.println( F("Edit Libraries/NeoGPS/GPSfix_cfg.h and comment out some of the #defines") );
    for (;;); // stop here!
  }

  // Initialise the IO and ISR
//  vw_set_tx_pin(transmit_pin);
vw_set_rx_pin(rx_pin);
  vw_setup(baudRate);       // Bits per sec

}

void loop()
{
  // Check for received RF data
  uint8_t buf[VW_MAX_MESSAGE_LEN];
  uint8_t buflen = VW_MAX_MESSAGE_LEN;

  if (vw_get_message(buf, &buflen)) // Non-blocking
  {
    if (buflen == sizeof(gps_fix)) {
      // Map the received characters onto a fix structure
      gps_fix & fix = *((gps_fix *)buf);

      Serial.println( F("Latitude:") );
      if (fix.valid.location)
        Serial.print( fix.latitude(), 6 );
      Serial.println();
      Serial.println( F("Longitude:") );
      if (fix.valid.location)
        Serial.println( fix.longitude(), 6 );
      Serial.println();
    }
  }
}

This should receive the exact same fix structure that was filled out by NeoGPS on the transmitting Arduino. It has extra precision in latitudeL and longitudeL. See NMEAloc.ino for an example of printing out those long integers (instead of float) if you want the extra precision (7 decimals).

Cheers,
/dev