Serial.parseFloat() считывает 0, несмотря на то, что я ввел другое значение

Я пытаюсь создать робота, который спрашивает у пользователя долготу и высоту, а затем использует собранные GPS данные, чтобы добраться до нужного места. Однако, когда я использую Serial.parseFloat(), чтобы получить местоположение от пользователя, я получаю правильное значение широты, а долгота почему-то возвращает ноль. вот код, который я написал

#include "Adafruit_FONA.h"

// стандартные штифты для щита, при необходимости отрегулируйте
#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      //Триггер
#define echo1 A2        //Эхо
#define trigger2 A4
#define echo2 A5
#define trigger3 A0
#define echo3 A1

// Мы по умолчанию используем программный последовательный порт. Если вы хотите использовать аппаратный последовательный порт
// (т.к. softserial не поддерживается) закомментируйте следующие три строки
// и раскомментируйте строку HardwareSerial
#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;

// Аппаратный последовательный порт также возможен!
// Аппаратный последовательный порт *fonaSerial = &Serial1;
Adafruit_FONA fona = Adafruit_FONA(FONA_RST);
// У вас есть FONA 3G? используйте вместо этого этот тип объекта
//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"));
    // Попробуйте включить 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;

    // если вы запросите показания высоты, getGPS вернет false, если 3D-фиксации нет
    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...");
    }
}

, 👍2

Обсуждение

Можете ли вы продемонстрировать проблему с помощью более простой программы?, @Craig

Крейг, я бы очень хотел сделать это проще, но я думаю, что проблема вызвана GPS, поэтому я просто хочу, чтобы люди взглянули на весь код и поняли, где я ошибся., @Abdullah Shalaby

Но проблема в том, что функция void getLatitude() работает очень хорошо, в то время как функция void getLongitude(), которая очень похожа на нее, работает не так хорошо. Когда я ввожу долготу назначения в последовательный монитор, он присваивает переменной longitudeDestination значение ноль, независимо от того, какое значение я ввожу., @Abdullah Shalaby

Вы уверены, что не можете сделать что-то проще с этой проблемой? Можете ли вы сделать более простую версию, которая работает для чтения широты/долготы?, @Craig

к сожалению, нет, так как код предназначен для получения координат от пользователя и получения сигнала от Raspberry Pi о том, что пользователь прошел систему распознавания лиц и начать навигацию к ней, все это в одном коде Arduino, @Abdullah Shalaby

Крейг, этот метод работал отлично, когда я использовал его сам по себе, но при добавлении его в этот код для работы с GPS он не показывает той же эффективности, и, насколько мне известно, нет более простых способов определения широты/долготы, чем этот., @Abdullah Shalaby

Вы устанавливаете переменные расстояния широты/долготы до считывания широты/долготы с GPS., @Craig

Что именно вы ему отправляете? Как выглядит ваша строка местоположения?, @gre_gor

@gre_gor это выглядит примерно так 31.215486. просто обычное число с плавающей точкой. Я просто хотел бы отметить, что первая функция getLatitude() работает отлично в отличие от другой getLongitude, @Abdullah Shalaby


1 ответ


Лучший ответ:

2

Конечно, вполне возможно, что человек, печатающий текст (или автоматизированная система, передающая данные в пакетах по нестабильной связи), не сможет предоставить допустимое число за время (по умолчанию 1 секунда) до истечения времени ожидания parseFloat().

Однако, учитывая, что это второе значение, которое нужно прочитать, существует более сложная возможность.

Вероятно, фактически отправленная последовательность может быть чем-то вроде

123.45\r\n

В этом случае 123.45 и первый незначимый символ \r будут использованы первым parseFloat().

Но это оставляет оставшийся \n в последовательном буфере, поэтому проверка serialAvailable() выполняется немедленно, а следующий parseFloat() начинается до того, как пользователь начал печатать. Если только он не ответит очень быстро, время ожидания может истечь еще до того, как он начнет.

Если предполагается, что пользователь будет использовать терминальную программу, которая отправляет возврат каретки и/или новую строку, вам, вероятно, следует изменить обработку ввода, чтобы она либо обрабатывалась до конца строки, либо обрабатывалась.

Или вы можете сделать свой код гибким, убедившись, что все конечные символы конца строки учтены (после проверки на них с помощью Serial.peek()) до того, как вы решите, что пользователь начал вводить новое значение, и начнете следующий вызов parseFloat().

Вы также можете создать свой собственный, более сложный parseFloat(), используя другой алгоритм.

,

два значения должны быть отправлены одновременно из последовательного монитора, разделенные каким-либо нецифровым символом. parseFloat игнорирует нецифровые начальные символы., @Juraj

@Juraj parseFloat игнорирует и потребляет начальные нецифровые символы и один конечный. Но если их два, то второй вызовет проверку последовательных данных аскера и немедленно запустит второй тайм-аут анализа. Значения, о которых идет речь, **вводятся в ответ на отдельные запросы**, так что нет, они не будут отправлены «сразу», если только кто-то не решит проигнорировать запросы и ввести их сразу же или передать данные из скрипта. Изменение программы для запроса всех значений в одной строке может как-то сработать, если терминал находится в режиме строки или пользователь будет осторожен и не будет делать пауз., @Chris Stratton

Крис, именно это я и имел в виду. Session Monitor отправляет строку сразу, @Juraj