Split longitude and latitude floats into integers

Is there are some way to split floats of Geodata into integers?

I am having problems with sending floats over Bluetooth LE and was thinking about solution where I would simply separate floats directly on Arduino side into integers.

For example in C# it can be done this way:

string lat = "65.23423";
List<string> latitude = lat.Split('.').ToList();
string latitude1 = latitude[0];
string latitude2 = latitude[1];

For example I am having readings like:

65.23423
29.23434

I would like to split them for

Serial.print(65);
Serial.print(23423);
Serial.print(29);
Serial.print(23434);

Note! There are can be negative values for latitude and longitude.

show us the code you have and how you get those. Are they in a String, a cString, do you store the incoming data at all ?

if you have the number in a String (not what we prefer here) you could look for the dot, read an int (the dot will stop the parsing) and then read an int again starting at the character after the dot

String data = "65.23423";

void setup() {
  Serial.begin(115200); Serial.println();

  byte dotPosition = data.indexOf('.');
  long integralPart = data.toInt();
  long decimalPart = data.substring(dotPosition + 1).toInt();
  Serial.println(integralPart);
  Serial.println(decimalPart);
}

void loop() {}
1 Like

I am getting these values from NMEAGPS.h

gpsSpeed is int
latitude is float
longitude is float

static void GPSloop()
{
  while (gps.available(gpsPort))
  {
    fix = gps.read();
    if (fix.valid.speed)
    {
      gpsSpeed = fix.speed_kph();
      latitude = fix.latitude();
      longitude = fix.longitude();
    }
  }
}

Then in loop() I am sending these over Serial to Andorid device using Bluetooth LE

I think you need to first determine what you are working with... In the Adafruit GPS library, The lat / lon are parsed as: longitude and longitude but the code goes on and determines the "E" or "W"
The atof() is referenced here: https://www.cplusplus.com/reference/cstdlib/atof/
Your library in use may do it differently!

So, you are going to have to do a bit of extra credit to get the desired outcome.

  if (strstr(nmea, "$GPRMC")) {
   // found RMC
    char *p = nmea;

    // get time
    p = strchr(p, ',')+1;
    float timef = atof(p);
    uint32_t time = timef;
    hour = time / 10000;
    minute = (time % 10000) / 100;
    seconds = (time % 100);

    milliseconds = fmod(timef, 1.0) * 1000;

    p = strchr(p, ',')+1;
    // Serial.println(p);
    if (p[0] == 'A') 
      fix = true;
    else if (p[0] == 'V')
      fix = false;
    else
      return false;

    // parse out latitude
    p = strchr(p, ',')+1;
    latitude = atof(p);

    p = strchr(p, ',')+1;
    if (p[0] == 'N') lat = 'N';
    else if (p[0] == 'S') lat = 'S';
    else if (p[0] == ',') lat = 0;
    else return false;

    // parse out longitude
    p = strchr(p, ',')+1;
    longitude = atof(p);

    p = strchr(p, ',')+1;
    if (p[0] == 'W') lon = 'W';
    else if (p[0] == 'E') lon = 'E';
    else if (p[0] == ',') lon = 0;
    else return false;

    // speed
    p = strchr(p, ',')+1;
    speed = atof(p);

    // angle
    p = strchr(p, ',')+1;
    angle = atof(p);

    p = strchr(p, ',')+1;
    uint32_t fulldate = atof(p);
    day = fulldate / 10000;
    month = (fulldate % 10000) / 100;
    year = (fulldate % 100);

    // we dont parse the remaining, yet!
    return true;
  }

so you want to build an ASCII based BLE message with the values?

➜ just print them

Serial.write('$'); // start marker
Serial.print(latitude,6); // 6 digits precision
Serial.write(','); // separator
Serial.print(longitude,6);// 6 digits precision
Serial.write('\n'); // end marker (new line)

with a bit of a protocol so that it's easy to parse on the other side

Another option is to send the entire NMEA sentence as text.
Incidentally, I'm just working with a GPS "neo" module now and this is what I get as raw data:

$GPRMC,173218.00,A,3434.84830,N,00914.21872,E,0.190,,060422,,,A*75

The latitude and longitude are actually encoded in degrees and minutes which may or may not be what you want.

Why not ask for help with that?

Ok, but how would you combine them again when they are received?

What would happen if you do what you suggest for values like these?

65.02342
29.00234

Would it not be simpler to multiply each number by 100000, send each as a single long integer, then when they are received you can divide them by 100000 to get the original value back?

1 Like

This works fine with integers, but once I am adding floats, I am getting this one:

Here is what I am sending from Arduino:

  Serial.print("<1>");
  Serial.print(value1);
  Serial.print(",");
  Serial.print(value2);
  Serial.print(",");
  Serial.print(value3);
  Serial.print(",");
  Serial.print(value4);
  Serial.print(",");
  Serial.print(value5);
  Serial.print(",");
  Serial.print(value6, 5);
  Serial.print(",");
  Serial.print(value7, 5);
  Serial.print(",");
  Serial.print(value8);
  Serial.print(",");
  Serial.print(value9);
  Serial.print(",");
  Serial.print(value10);
  Serial.print(",");
  Serial.print(value11);

I have added a mark <1> just to visually separate received values.

Here is what I am getting on Android phone:

"0,604<1>530,917,58,99,0,0.00000,0.00000,23,530,0,604<1>530,917,58,86,0,0.00000,0.00000,23,530,0,604<1>530,918,59,95,0,0.00000,0.00000,23,530,0,604<1>530,918,58,85,0,0.00000,0.00000,23,530,0,604<1>530,917,59,91,0,0.00000,0.00000,23,530,0,604<1>530,9"

and next string:

"18,59,91"

and next string:

",0,0.00000,0.00000,23,530,0,604<1>530,917,59,89,0,0.00000,0.00000,23,530,0,604<1>530,917,59,95,0,0.00000,0.00000,23,530,0,604<1>530,917,59,86,0,0.00000,0.00000,23,530,0,603<1>530,917,60,98,0,0.00000,0.00000,23,529,0,604<1>530,917,59,86,0,0.00000,0."

and next string:

"00000,23"

receiving data asynchronously is not an issue. you should expect that. that's why we often use a start and end marker so that you can build a full phrase and parse it.

Also remember there is a size limit to a BLE payload (if I remember well it's 33 bytes for BLE 4)

without seeing the code for actually sending through BLE and receiving, it's hard to say what's going on.

explaining what your hardware set up is would help too.

The library you are using offers lat/lon as 32 bit integers, with higher precision and accuracy than floats. Send those instead.

a location structure (i.e., latitude and longitude), accessed with

  • fix.latitudeL() and fix.longitudeL() for the higher-precision integer degrees, scaled by 10,000,000 (10 significant digits)

I am using Arduino Mega 2560 with HM-19, I think it is Bluetooth 4.0 LE. Then receiving values on Android phone with code written in Java. I have been trying to work with start and end markers, but then as "next coming string" is always example "00000,23". There is slight delay noticeable in readings. Currently all goes smooth on Android side if I am receiving all the time correct string, latency level is just fine.

P.S. I have now tried with integer values, but incoming message on Android looks like this again :face_with_spiral_eyes:

"2,452,582412,919,63,98,145,6589654,8956235,23,412,452,582412,918,63,87,145,6589654,8956235,23,412,452,579412,919,63,99,145,6589654,8956235,23,412,452,574412,919,64,87,145,6589654,8956235,23,412,452,570412,919,63,99,145,6589654,8956235,23,412,452,57"

and next incoming string:

"1412,919"

In readings
latitude = 6589654
longitude = 8956235

Without these GPS values, everything works just fine... Getting on Android side something like this: "410,921,62,85,0,23,408,0,570" all the time. Without these strange enormous strings

are you actually using BLE or just the standard BT in SPP mode?

can you share the Arduino sketch and the Java code?

Here is Arduino part. I have added fake numbers in output string just to demonstrate the length of the string. This one gets messed up already:

Just checked, it seems like this is maximum string size to be sent: "346,897,65,94,0,2147483647,2,23,351,0,556"
Equal to 41 characters = bytes?

Does it make any difference between using Serial.print(); and Serial.write("); ?

#include <NMEAGPS.h>
#include <GPSport.h>

static NMEAGPS gps;
static gps_fix fix;

int gpsSpeed;
float latitude;
float longitude;

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

void loop(void)
{
  GPSloop();

  // Print data to Serial 0 aka BLE output
  printOutDataForBLE();
}

static void GPSloop()
{
  while (gps.available(gpsPort))
  {
    fix = gps.read();
    if (fix.valid.speed || fix.valid.location)
    {
      gpsSpeed = fix.speed_kph();
      latitude = fix.latitude();
      longitude = fix.longitude();
    }
  }
}

void printOutDataForBLE()
{
  // char s[200];
  // sprintf(s, "%d,%d,%d,%d,%d,%d,%d,%d,%d", tachometerValue, fuelValue, voltageValue, oilPressureValue, gpsSpeed, airTemperatureValue, engineTemperatureValue, waterTemperatureValue, lightSensorValue);

  // Serial.println(s);

  int lat = latitude * 100000;
  int lon = longitude * 100000;

  Serial.print(355);
  Serial.print(",");
  Serial.print(856);
  Serial.print(",");
  Serial.print(85);
  Serial.print(",");
  Serial.print(85);
  Serial.print(",");
  Serial.print(lat);
  Serial.print(",");
  Serial.print(lon);
  Serial.print(",");
  Serial.print(458);
  Serial.print(",");
  Serial.print(52);
  Serial.print(",");
  Serial.print(452);
  Serial.print(",");
  Serial.print(120);
  Serial.print(",");
  Serial.print(1025);
}

I can add Java here once I will get to my laptop.

on a MEGA you will likely overflow the int (2 bytes only) capacity

your arduino code should only print the data when the fix is ready. Not blasting at the speed of the loop()... esp. at 9600 bauds you'll very soon get a pause in the code because print will not be able to write in the output buffer and that will possibly lead to loosing GPS input and not getting any good fix anymore because the sentences you'll receive will have been overwritten in the small (64 byte) buffer

also it probably does not compile because I don't see where gps or fix are defined...

I don't know C#, but that doesn't look like it splits a float into integers - it looks like it splits a string into two strings.

2 Likes

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