1

I'm trying to make a robot that asks the user for the longitude and the altitude form the user and then using the data the GPS collects to go to the wanted location, however when I use Serial.parseFloat() to get the location from the user, i get the right value for the latitude and the longitude returns zero for some reason here's the code i wrote

#include "Adafruit_FONA.h"

// standard pins for the shield, adjust as necessary
#define FONA_RX 2
#define FONA_TX 3
#define FONA_RST 4
#define PIN13 13
#define IN1 6      //IN1
#define IN2 7        //IN2
#define ENA 5          //ENA
#define ENB 10        //ENB
#define IN3 8          //IN3
#define IN4 9          //IN4
#define trigger1 A3      //Trigger
#define echo1 A2        //Echo
#define trigger2 A4
#define echo2 A5
#define trigger3 A0
#define echo3 A1

// We default to using software serial. If you want to use hardware serial
// (because softserial isnt supported) comment out the following three lines
// and uncomment the HardwareSerial line
#include <SoftwareSerial.h>
SoftwareSerial fonaSS = SoftwareSerial(FONA_TX, FONA_RX);
SoftwareSerial *fonaSerial = &fonaSS;
int counter;
char serialData;
int duration;
float distance1, distance2, distance3;
float latitudeDestination, longitudeDestination;

// Hardware serial is also possible!
//  HardwareSerial *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// Have a FONA 3G? use this object type instead
//Adafruit_FONA_3G fona = Adafruit_FONA_3G(FONA_RST);

void getLatitude(){
    Serial.println("Enter the latitude destination :");
    while (Serial.available() == 0){}
    latitudeDestination = Serial.parseFloat();
}

void getLongitude()
{
    Serial.println("Enter the longitude destination :");
    while (Serial.available() == 0){}
    longitudeDestination = Serial.parseFloat(); 
}

void securityPassed()
{
    Serial.println("You need to pass security first");
    while (Serial.available() ==0){}
    serialData = Serial.read();
    if (serialData == '1')
    {
        Serial.println("Passed") ;
    }
    else {}
}

void setup() {
    pinMode(PIN13, INPUT);
    pinMode(trigger1, OUTPUT);
    pinMode(echo1, INPUT);
    pinMode(trigger2, OUTPUT);
    pinMode(echo2, INPUT);
    pinMode(trigger3, OUTPUT);
    pinMode(echo3, INPUT);
    pinMode(IN1 , OUTPUT);
    pinMode(IN2, OUTPUT);
    pinMode(IN3, OUTPUT);
    pinMode(IN4, OUTPUT);
    pinMode(ENA, OUTPUT);
    pinMode(ENB, OUTPUT);

    digitalWrite(ENA , HIGH);
    digitalWrite(ENB, HIGH);

    Serial.begin(9600);

    getLatitude();
    getLongitude();
    securityPassed();

    Serial.println(F("Adafruit FONA 808 & 3G GPS demo"));
    Serial.println(F("Initializing FONA... (May take a few seconds)"));
    fonaSerial->begin(4800);
    if (! fona.begin(*fonaSerial)) {
        Serial.println(F("Couldn't find FONA"));
        while (1);
    }
    Serial.println(F("FONA is OK"));
    // Try to enable GPRS
    Serial.println(F("Enabling GPS..."));
    fona.enableGPS(true);
}

void loop() {
    delay(2000);

    float latitude, longitude, speed_kph, heading, speed_mph, altitude;
    float latitudeDistance = latitudeDestination - latitude ;
    float longitudeDistance = longitudeDestination - longitude;

    // if you ask for an altitude reading, getGPS will return false if there isn't a 3D fix
    boolean gps_success = fona.getGPS(&latitude, &longitude, &speed_kph, &heading, &altitude);
    if (gps_success) {
      Serial.print("GPS lat:");
      Serial.println(latitude, 6);
      Serial.print("GPS long:");
      Serial.println(longitude, 6);
      Serial.print("GPS speed KPH:");
      Serial.println(speed_kph);
      Serial.print("GPS speed MPH:");
      speed_mph = speed_kph * 0.621371192;
      Serial.println(speed_mph);
      Serial.print("GPS heading:");
      Serial.println(heading);
      Serial.print("GPS altitude:");
      Serial.println(altitude);
      Serial.print("Latitude Distance: ");
      Serial.println(latitudeDistance);
      Serial.print("Longitude Distance: ");
      Serial.println(longitudeDistance);

      if ( latitudeDistance < 0.00001 && latitudeDistance > -0.00001)
      {

        if ( longitudeDistance < 0.00001 && longitudeDistance > -0.00001)
        {
          Serial.print("Arrived");
          stopm();
        }
        else
        {
          if (!counter == 1 && longitudeDistance > 0 )
          {
            moveRight();
            Serial.println("Turning Right");
            counter =1;
          }
          else if ( !counter == 1 && longitudeDistance < 0 )
          {
            moveLeft();
            Serial.println("Turning Left");
            counter=1;

          }
          moveForward();
        }
      }
      else
      {
        moveForward();
        Serial.print("Going To Destination");
      }
    }
    else {
      Serial.println("Waiting for FONA GPS 3D fix...");
    }
}
  • Can you demonstrate the problem with a simpler program? – Craig Jun 14 '18 at 20:28
  • Craig, I really wish I could make it simpler but I think the problem is caused by the GPS, so I just want people to take an look at the whole code to figure out where I went wrong – Abdullah Shalaby Jun 14 '18 at 20:36
  • but the problem simply is that the function void getLatitude() works very well while the function void getLongitude() which is very similar to it doesn't work so well, when i enter the longitude destination in the serial monitor it gives the variable longitudeDestination a valure of zero no matter what value i enter – Abdullah Shalaby Jun 14 '18 at 20:38
  • Are you sure you can't make something simpler with the problem? Can you make a simpler version that works to read the lat/long? – Craig Jun 14 '18 at 20:53
  • 1
    You are setting the lat/long Distance variables before reading the lat/long from the GPS. – Craig Jun 14 '18 at 21:16
2

It is certainly possible that a person typing (or an automated system feeding data in packets over a spotty link) might fail to provide a valid number in the (default 1 second) time before parseFloat() times out.

However, given this is the second value to be read, there's a more complex possibility.

It's likely that the sequence actually sent might be something like

123.45\r\n

In this case 123.45 and the first non-value character \r will be consumed by the first parseFloat().

But that leaves a remaining \n in the serial buffer, so the serialAvailable() check is satisfied immediately and the next parseFloat() begins before the user has even started typing. Unless they're very quick to respond, it may time out before they even begin.

If the user is supposed to use a terminal program that sends a carriage return and/or newline, you should probably change input processing to either consume until the end of the line before processing.

Or you can make your code flexible by being sure to consume any trailing line end characters (after checking for them with Serial.peek()) before you decide that the user has begun entering a new value and starting your next parseFloat() call.

You could also make your own more sophisticated parseFloat() using a different algorithm.

  • the two values should be send at once from Serial Monitor, separated by some non-digit character. parseFloat ignores non-digit initial characters. – Juraj Jun 15 '18 at 16:23
  • @Juraj parseFloat ignores and consumes leading non-digit characters and one trailing one. But if there are two, that second will trip the asker's serial data check, and cause the second parsing timeout to begin immediately. The values in question are entered in response to distinct prompts so no, they wouldn't be sent "at once" unless someone decided to ignore the prompts and type them in immediate succession, or pipe in data from a script. Changing the program to request all values on the same line could sort of work, if the terminal is in line mode or the user is careful not to pause. – Chris Stratton Jun 15 '18 at 17:26
  • Chris, exactly what I meant. Session Monitor sends the line at once – Juraj Jun 15 '18 at 17:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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