Store GPS data in variable calculation error

Hi im new to arduino. What im trying to do is move the stepper motor and servo according to the angle calculation. But first, my angle calculation need to get the latitude and longitude from gps. im using GPS module using this code.

#include <SoftwareSerial.h>
#include <TinyGPS.h>

SoftwareSerial mySerial(10, 9);
TinyGPS gps;

void gpsdump(TinyGPS &gps);
void printFloat(double f, int digits = 2);

void setup()  
{
  // Oploen serial communications and wait for port to open:
  Serial.begin(9600);
  // set the data rate for the SoftwareSerial port
  mySerial.begin(9600);
  delay(1000);
  Serial.println("uBlox Neo 6M");
  Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
  Serial.println("by Mikal Hart");
  Serial.println();
  Serial.print("Sizeof(gpsobject) = "); 
  Serial.println(sizeof(TinyGPS));
  Serial.println(); 
}

void loop() // run over and over
{
  bool newdata = false;
  unsigned long start = millis();
  // Every 5 seconds we print an update
  while (millis() - start < 5000) 
  {
    if (mySerial.available()) 
    
    {
      char c = mySerial.read();
      //Serial.print(c);  // uncomment to see raw GPS data
      if (gps.encode(c)) 
      {
        newdata = true;
        break;  // uncomment to print new data immediately!
      }
    }
  }
  
  if (newdata) 
  {
    Serial.println("Acquired Data");
    Serial.println("-------------");
    gpsdump(gps);
    Serial.println("-------------");
    Serial.println();
  }
  
}

void gpsdump(TinyGPS &gps)
{
  long lat, lon;
  float flat, flon;
  unsigned long age, date, time, chars;
  int year;
  byte month, day, hour, minute, second, hundredths;
  unsigned short sentences, failed;

  gps.get_position(&lat, &lon, &age);
  Serial.print("Lat/Long(10^-5 deg): "); Serial.print(lat); Serial.print(", "); Serial.print(lon); 
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");
  
  // On Arduino, GPS characters may be lost during lengthy Serial.print()
  // On Teensy, Serial prints to USB, which has large output buffering and
  //   runs very fast, so it's not necessary to worry about missing 4800
  //   baud GPS characters.

  gps.f_get_position(&flat, &flon, &age);
  Serial.print("Lat/Long(float): "); printFloat(flat, 5); Serial.print(", "); printFloat(flon, 5);
    Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.get_datetime(&date, &time, &age);
  Serial.print("Date(ddmmyy): "); Serial.print(date); Serial.print(" Time(hhmmsscc): ");
    Serial.print(time);
  Serial.print(" Fix age: "); Serial.print(age); Serial.println("ms.");

  gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
  Serial.print("Date: "); Serial.print(static_cast<int>(month)); Serial.print("/"); 
    Serial.print(static_cast<int>(day)); Serial.print("/"); Serial.print(year);
  Serial.print("  Time: "); Serial.print(static_cast<int>(hour+8));  Serial.print(":"); //Serial.print("UTC +08:00 Malaysia");
    Serial.print(static_cast<int>(minute)); Serial.print(":"); Serial.print(static_cast<int>(second));
    Serial.print("."); Serial.print(static_cast<int>(hundredths)); Serial.print(" UTC +08:00 Malaysia");
  Serial.print("  Fix age: ");  Serial.print(age); Serial.println("ms.");

  Serial.print("Alt(cm): "); Serial.print(gps.altitude()); Serial.print(" Course(10^-2 deg): ");
    Serial.print(gps.course()); Serial.print(" Speed(10^-2 knots): "); Serial.println(gps.speed());
  Serial.print("Alt(float): "); printFloat(gps.f_altitude()); Serial.print(" Course(float): ");
    printFloat(gps.f_course()); Serial.println();
  Serial.print("Speed(knots): "); printFloat(gps.f_speed_knots()); Serial.print(" (mph): ");
    printFloat(gps.f_speed_mph());
  Serial.print(" (mps): "); printFloat(gps.f_speed_mps()); Serial.print(" (kmph): ");
    printFloat(gps.f_speed_kmph()); Serial.println();

  gps.stats(&chars, &sentences, &failed);
  Serial.print("Stats: characters: "); Serial.print(chars); Serial.print(" sentences: ");
    Serial.print(sentences); Serial.print(" failed checksum: "); Serial.println(failed);
}

void printFloat(double number, int digits)
{
  // Handle negative numbers
  if (number < 0.0) 
  {
     Serial.print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;
  
  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  Serial.print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0)
    Serial.print("."); 

  // Extract digits from the remainder one at a time
  while (digits-- > 0) 
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    Serial.print(toPrint);
    remainder -= toPrint;
  }
}

This works fine. But the error shown when i try to combine my code with the GPS code. It shows ‘TinyGPS::f_get_position(float&)’ error. i did many thing to fix this but failed. This is the code that i made.

#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <Servo.h>
#include <Stepper.h>

const int stepsPerRevolution = 200;  // number of steps per revolution - stepper motor


// initialize the stepper library on pins 2 through 5:
Stepper myStepper(stepsPerRevolution, 2, 3, 4, 5);

int stepCount = 0;         // number of steps the stepper motor has taken

Servo myservo;  // servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;  // variable to store the servo position


SoftwareSerial mySerial(12, 13);
TinyGPS gps;

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

void gpsdump(TinyGPS &gps);

void printFloat(double f, int digits = 2);


 myservo.attach(30);  // attaches the servo on pin 9 to the servo object
  myStepper.setSpeed(60);
  


const float pi = 3.141592654;

const float Re = 6378.137;

const float h = 35786;

const float r = 42164.137;

const float Satlon = 91.5;

float flat = gps.TinyGPS::f_get_position(flat);
float flon = gps.TinyGPS::f_get_position(flon);


float Adeg = (flon - Satlon);
float Arad = (Adeg*(pi/180));

float Bdeg = flat;
float Brad = (Bdeg*(pi/180));


float y = (acos((cos(Arad))*(cos(Brad))));
float d = (sqrt(((Re*Re)+(r*r)) - ((2*Re*r)*(cos(y)))));

float el = (acos ((r/d)*(sin(y))));
float eldeg = (el*(180/pi));

float az = (asin (sin(Arad)/sin(y)));
float azdeg = (az*(180/pi));
float azStep = (azdeg/1.8);


if (pos < eldeg){
  myservo.write(eldeg);// servo go for elevation angle
}
else if (pos > 90) {
  myservo.write(pos);
}
  

  if  (stepCount < azStep)
  {
  myStepper.step(azStep);
  delay(500);
  }
  else if (stepCount > azStep);
  {
  myStepper.step(stepCount);
  delay (500);
  }
  
}

void loop() 
{
 bool newdata = false;
  unsigned long start = millis();
  // Every 5 seconds we print an update
  while (millis() - start < 5000) 
  {
    if (mySerial.available()) 
    
    {
      char c = mySerial.read();
      //Serial.print(c);  // uncomment to see raw GPS data
      if (gps.encode(c)) 
      {
        newdata = true;
        break;  // uncomment to print new data immediately!
      }
    }
  }
  
  if (newdata) 
  {
    gpsdump(gps);
    
  }


}


void gpsdump(TinyGPS &gps)
{
   float flat, flon;
  
  
  
  gps.f_get_position(&flat, &flon);
  printFloat(flat, 5); printFloat(flon, 5); 
   // get float point latitude and longitude

}

void printFloat(double number, int digits)
{
  // Handle negative numbers
  if (number < 0.0) 
  {
    
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;
  
  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0)
    

  // Extract digits from the remainder one at a time
  while (digits-- > 0) 
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    
    remainder -= toPrint;
  }
}

i want to store the gps data latitude and longitude in the variable flat and flon for the calculation.

Thank you for your help.

From the code that you say works

 gps.f_get_position(&flat, &flon);

It looks like the function is passed 3 parameters by reference so that they can be updated by the function

In your code

 float flon = gps.TinyGPS::f_get_position(flon);

You are only passing one parameter and what's more you are passing by value

The error message

no matching function for call to 'TinyGPS::f_get_position(float&)

Indicates that there is no matching function in the library

I’m sorry, but I am not clear about the parameter… can u explain more…?

But somehow i did try this to fix the error.

float flat, flon; 

gps.f_get_position(&flat, &flon);

It shows no error now but the motor does not seems to get any instruction from the calculation. Is it related to my gps unable to receive data?

I’m sorry, but I am not clear about the parameter… can u explain more…?

When you call a function you can include a list of values (parameters) that the function can use. Such as

int anInt = 123;
Serial.println(anInt);

Sometimes you want the function to manipulate the values sent and maybe send back the result as in

int startNumber = 123;
int theSquare = squareInt(startInt);
//other code here

int squareInt(int aNumber)  //function to return the square of a number
{
  return aNumber * aNumber;  //return the answer to the calling program
}

Note that the value of startInt is passed to the function and the function does not change its value and that only one value can be returned. This is known as passing by value.

But suppose you want to get more than one value from a function. You can do something like this

gps.f_get_position(&flat, &flon);

Note that the function is not called in the same way. At first glance it would appear that nothing is returned by the function but the variables that it has been called with have a & in front of their name. This is known as calling by reference and in English it means “here is a reference to a variable and you (the function) have permission to make changes to the value of the variable”. This is known as passing by reference

So

gps.f_get_position(&flat, &flon);

means “execute the function and put the results in the 2 variables for use later by the main program”

Now look at your working and non working programs and spot the difference between

gps.f_get_position(&flat, &flon);

and

float flon = gps.TinyGPS::f_get_position(flon);

First, you have to call “begin” on the GPS serial port.

Then your sketch must wait long enough for the GPS to send characters over that port. The parser will gradually “consume” those characters until the GPS fields are assembled in the Arduino. Each character takes 1ms, and the GPS device typically sends about 150 characters per update (once per second).

This means that you cannot try to get the lat/lon in setup. It isn’t inside the Arduino yet.

And that loop structure will not do what you expect. The main loop has a 5-second update rate, and the servo/stepper code will add an additional 1 second of delay.

These delays cause the Arduino input buffer for the GPS port to overflow. (Let’s call it “gpsPort” instead of “mySerial”, shall we?). Unless your sketch constantly reads the gpsPort, the characters coming from the GPS device will start getting dropped. This prevents the parser from ever getting a complete “sentence” from the GPS device, and it will not be able to provide a lat/lon for you. Not consistently, anyway.

Instead, use the GPS device to “time” your updates to the stepper/servo. A batch of sentences comes from the GPS device at exactly 1 second intervals. When your sketch receives a new batch of sentences, with a new location, that’s when you should update the servo/stepper.

You should also consider using something besides SoftwareSerial, because it is very inefficient. It disables interrupts for the entire time that a character is being sent OR received, and it cannot do both at the same time (unlike all the other serial choices). This can interfere with other parts of your sketch, other device communications, or with libraries. This means that receiving one GPS character will prevent the servo/stepper library from handling interrupts. This could cause stuttering or inaccurate positioning.

Read this, then try one of these alternatives:

1) Put the GPS TX on pin 0. You do not have to connect the GPS RX pin, because you never send any configuration commands to it. You will have to disconnect pin 0 every time you want to upload a new sketch over USB. You can still do debug prints to the Serial Monitor window.

2) Put the GPS TX on pin 8 and use AltSoftSerial. This is the best software serial library, but it must be used on that pin. It also disables PWM on pin 10, and it transmits on pin 9. This is a good choice, but you may have to move the servo/stepper to other PWM pins (any pins except 8,9 & 10).

3) Leave the GPS TX on pin 12 and use https://github.com/SlashDevin/NeoSWSerial. This is almost as good as AltSoftSerial, but it can be used on any two pins. It only supports baud rates 9600, 19200 or 38400.

Here is your sketch, modified to have the suggested loop structure, and to use NeoSWSerial on pin 12/13:

#include <NeoSWSerial.h>
#include <NMEAGPS.h>
#include <Servo.h>
#include <Stepper.h>

const int stepsPerRevolution = 200;  // number of steps per revolution - stepper motor


// initialize the stepper library on pins 2 through 5:
Stepper myStepper(stepsPerRevolution, 2, 3, 4, 5);

int stepCount = 0;         // number of steps the stepper motor has taken

Servo myservo;  // servo object to control a servo
// twelve servo objects can be created on most boards

int pos = 0;  // variable to store the servo position


NeoSWSerial gpsPort(12, 13);

NMEAGPS gps; // the parser
gps_fix fix; // a structure that holds all the parsed GPS fields


const float pi     = 3.141592654;
const float Re     = 6378.137;
const float h      = 35786;
const float r      = 42164.137;
const float Satlon = 91.5;


void setup() 
{
  Serial.begin(9600);
  gpsPort.begin(9600);

  myservo.attach(30);  // attaches the servo on pin 9 to the servo object
  myStepper.setSpeed(60);
}  


void loop() 
{
  // Check for GPS characters and parse them
  if (gps.available( gpsPort )) {

    // Exactly once per second, a complete GPS fix is ready.
    fix = gps.read();
    gpsdump();
    updateServo();
  }
}


void gpsdump()
{
  if (fix.valid.location) {
    Serial.print( fix.latitude(), 6 );
    Serial.print( ',' );
    Serial.print( fix.longitude(), 6 );
  } else  {
    Serial.print( '?' );
  }
  Serial.println();
}


void updateServo()
{
  if (fix.valid.location) {
    float flat = fix.latitude();
    float flon = fix.longitude();

    float Adeg = (flon - Satlon);
    float Arad = (Adeg*(pi/180));

    float Bdeg = flat;
    float Brad = (Bdeg*(pi/180));


    float y = (acos((cos(Arad))*(cos(Brad))));
    float d = (sqrt(((Re*Re)+(r*r)) - ((2*Re*r)*(cos(y)))));

    float el = (acos ((r/d)*(sin(y))));
    float eldeg = (el*(180/pi));

    float az = (asin (sin(Arad)/sin(y)));
    float azdeg = (az*(180/pi));
    float azStep = (azdeg/1.8);


    if (pos < eldeg){
      myservo.write(eldeg);// servo go for elevation angle
    }
    else if (pos > 90)
    {
      myservo.write(pos);
    }
      

    if  (stepCount < azStep)
    {
      myStepper.step(azStep);
    }
    else if (stepCount > azStep)
    {
      myStepper.step(stepCount);
    }

  }
  
} // servoCalc

This use my NeoGPS library. It is smaller, faster, more accurate and more reliable than all other GPS libraries. There are many examples to show the correct program structure, and it supports many data fields. Even if you don’t use it, be sure the read the tips on the Installation and Troubleshooting pages.

Also notice that it does not try to use an invalid location. The GPS device may not know the location, so your sketch should not try to set the servo/stepper positions when you don’t have good satellite reception.

AltSoftSerial, NeoSWSerial and NeoGPS are available from the Arduino Library Manager, under the IDE menu Sketch → Include Library → Manage Libraries.