A la recherche GPS sans port Serie

Salut à tous,

J'ai un GPS qui fonctionne très bien seul (avec la librairie TinyGPS++)mais qui merde quand il est intégré dans un code plus long: le port serie du GPS n'est pas lu en continu, mais seulement entre d'autres séries de mesure. Bref, il n'est pas vraiment utilisable dans l'application complète.

Du coup, une simple question ? Existe t'il un module GPS capable d'encoder lui même la position et de délivrer, une fois de temps en temps, la position GPS quand on lui demande ? i.e. un capteur GPS ne demandant par à l'arduino d'encoder lui même la position GPS ...

Ouvert a toute suggestion ...

Cordialement

ardethernet:
Salut à tous,

J'ai un GPS qui fonctionne très bien seul (avec la librairie TinyGPS++)mais qui merde quand il est intégré dans un code plus long: le port serie du GPS n'est pas lu en continu, mais seulement entre d'autres séries de mesure. Bref, il n'est pas vraiment utilisable dans l'application complète.

Du coup, une simple question ? Existe t'il un module GPS capable d'encoder lui même la position et de délivrer, une fois de temps en temps, la position GPS quand on lui demande ? i.e. un capteur GPS ne demandant par à l'arduino d'encoder lui même la position GPS ...

Ouvert a toute suggestion ...

Cordialement

bonjour
ta question manque de clarté , explique mieux ton son souhait
le modules gnss courants sont prevus pour delivrer des trames (sentences) NMEA une fois par seconde
si j'ai bien compris tu souhaiterais que le module ne "crache" qu'à la demande ?

Salut,

Pour un peu plus de clareté : le module GPS est un GT-U7.
le code de code qui marche bien :

#include <TinyGPS++.h>
#include <SdFat.h>
#include <sdios.h>
//long   lat,lon; // create variable for latitude and longitude object
float lat,lng,alt;
TinyGPSPlus gps; // create gps object
#include "RTClib.h"
RTC_DS3231 rtc;
int32_t starttime;
const byte SDCARD_CS_PIN = 4;
SdFat sd;
SdFile file;
char FileDataname[12] = "GPS_dat1.csv";

void setup(){
Serial.begin(57600); // connect serial
Serial.println("The GPS Received Signal:");
Serial3.begin(9600); // connect gps sensor
if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    Serial.flush();
    abort();
  }
    if (!sd.begin(SDCARD_CS_PIN, SPI_HALF_SPEED))
      {
        Serial.println("No SD");
      }
       if (!file.open(FileDataname,FILE_WRITE))
      {
        return;
      }
    file.close();
    if (sd.exists(FileDataname))
      {
        file.open(FileDataname,FILE_WRITE);   
        file.println("Year; Month; Day; Hour; Minutes; Second; Miliili; Lat; Lon; Alt");
        file.close();
      }
starttime = millis();
}
 
void loop()
{
  file.open(FileDataname,  FILE_WRITE  );
  if(Serial3.available())
    { // check for gps data
      getGPSdata();
    }
  //delay(10);
} 

void getGPSdata() {
  if (millis()-starttime >= 1000)
    {   
    if(gps.encode(Serial3.read()))// encode gps data
      { 
      Serial.println(millis());
      Serial.println(starttime);
      Serial.println(millis()-starttime);
      starttime = millis(); 
      //gps.f_get_position(&lat,&lon); // get latitude and longitude
      Serial.print("Satelites: ");
      Serial.println(gps.satellites.value());
      Serial.print("Position: ");
    
      //Latitude
      Serial.print("Latitude: ");
      Serial.print(gps.location.lat(),12);
    
      Serial.print(",");
    
      //Longitude
      Serial.print("Longitude: ");
      Serial.print(gps.location.lng(),12);

      Serial.print(",");
    
      //Longitude
      Serial.print("Altitude: ");
      Serial.println(gps.altitude.meters(),2);
      
      }
    }
  else
    {
      gps.encode(Serial3.read());
    }
}

Dans le boucle loop, si je décommente //delay(10); plus rien ne va. tout empire avec un delay (100 ) ou un delay(500) (durée la plus cohérente) avec le reste des operations.

J'ai l'impression, peut etre fausse, que cela est du au code qui agglomère les données et affiche les coordonnees une fois les donnees recues (toutes les secondes) i.e. l'Arduino encode les données brutes du gps pour calculer les coordonnées.

Je cherche un moduel GPS capable de faire cela et de fournir les donnees GPS à la requete, sans faire de Serial.read and gps.encode...

Es ce que cela est formulé plus clairement ?

Cordialement

ardethernet:
Salut,

Pour un peu plus de clareté : le module GPS est un GT-U7.
le code de code qui marche bien :

#include <TinyGPS++.h>

#include <SdFat.h>
#include <sdios.h>
//long   lat,lon; // create variable for latitude and longitude object
float lat,lng,alt;
TinyGPSPlus gps; // create gps object
#include "RTClib.h"
RTC_DS3231 rtc;
int32_t starttime;
const byte SDCARD_CS_PIN = 4;
SdFat sd;
SdFile file;
char FileDataname[12] = "GPS_dat1.csv";

void setup(){
Serial.begin(57600); // connect serial
Serial.println("The GPS Received Signal:");
Serial3.begin(9600); // connect gps sensor
if (! rtc.begin()) {
   Serial.println("Couldn't find RTC");
   Serial.flush();
   abort();
 }
   if (!sd.begin(SDCARD_CS_PIN, SPI_HALF_SPEED))
     {
       Serial.println("No SD");
     }
      if (!file.open(FileDataname,FILE_WRITE))
     {
       return;
     }
   file.close();
   if (sd.exists(FileDataname))
     {
       file.open(FileDataname,FILE_WRITE);  
       file.println("Year; Month; Day; Hour; Minutes; Second; Miliili; Lat; Lon; Alt");
       file.close();
     }
starttime = millis();
}

void loop()
{
 file.open(FileDataname,  FILE_WRITE  );
 if(Serial3.available())
   { // check for gps data
     getGPSdata();
   }
 //delay(10);
}

void getGPSdata() {
 if (millis()-starttime >= 1000)
   {  
   if(gps.encode(Serial3.read()))// encode gps data
     {
     Serial.println(millis());
     Serial.println(starttime);
     Serial.println(millis()-starttime);
     starttime = millis();
     //gps.f_get_position(&lat,&lon); // get latitude and longitude
     Serial.print("Satelites: ");
     Serial.println(gps.satellites.value());
     Serial.print("Position: ");
   
     //Latitude
     Serial.print("Latitude: ");
     Serial.print(gps.location.lat(),12);
   
     Serial.print(",");
   
     //Longitude
     Serial.print("Longitude: ");
     Serial.print(gps.location.lng(),12);

Serial.print(",");
   
     //Longitude
     Serial.print("Altitude: ");
     Serial.println(gps.altitude.meters(),2);
     
     }
   }
 else
   {
     gps.encode(Serial3.read());
   }
}




Dans le boucle loop, si je décommente //delay(10); plus rien ne va. tout empire avec un delay (100 ) ou un delay(500) (durée la plus cohérente) avec le reste des operations.

J'ai l'impression, peut etre fausse, que cela est du au code qui agglomère les données et affiche les coordonnees une fois les donnees recues (toutes les secondes) i.e. l'Arduino encode les données brutes du gps pour calculer les coordonnées. 

Je cherche un moduel GPS capable de faire cela et de fournir les donnees GPS à la requete, sans faire de Serial.read and gps.encode...

Es ce que cela est formulé plus clairement ?

Cordialement

ok
comme çà à chaud , je dirais qu'il "suffit" de verifier l'etat du buffer serial (buffer de 64bytes )
çà fait un moment que je n'ai pas retouché à la lib tyinygps++ , mais il ne doit pas être trop difficile de recuperer de dernier timestamp FIX valide .

datasheet de ton module ?
il est peut etre possible de l'alimenter à la demande directement par un pin arduino (à voir probleme de temps de FIX ? )

J'ai un GPS qui fonctionne très bien seul (avec la librairie TinyGPS++)mais qui merde quand il est intégré dans un code plus long: le port serie du GPS n'est pas lu en continu, mais seulement entre d'autres séries de mesure. Bref, il n'est pas vraiment utilisable dans l'application complète.

ça veut dire que le reste du code est mal fichu - peut-être même truffé de delay() ou de désactivation des interruptions (j'ai pas lu le code plus haut)... et vous laissez déborder le buffer d'entrée lié au GPS et donc ce que vous fournissez à TinyGPS++ n'a pas de sens...

les GPS sont souvent à 9600 bauds, soit environ 960 caractères par seconde. le buffer d'entrée contient 64 octets max. Il ne faut donc pas que la loop() prenne plus de 15ms. Si c'est le cas il faut régorganiser le code ou rajouter des lectures du port GPS ça à la dans la boucle pour qu'il y ait moins de 15ms entre deux lectures du buffer du GPS.

De plus il ne faut pas lire qu'un seul caractère dans le buffer d'entrée quand vous y êtes, lisez tout ce qui est reçu bien sûr et fournissez le à gps.encode()

EDIT: j'ai parcouru le fichier fourni qui soi disant fonctionne... c'est loin d'être un modèle d'architecture... il faut vraiment structurer le code pour lire à chaque tour de loop() le port série du GSP en appeler encode() si vous avez quelque chose. Pas le faire toutes les secondes.

D'autre part regardez le file.open() de la loop n'a pas de close.

une approche comme cela est plus appropriée pour faire quelque chose à chaque fois que vous avez un fix (tapé ici, sans vérification d'erreurs sur la SD etc)

#include <SdFat.h>
#include <RTClib.h>
#include <TinyGPS++.h>

TinyGPSPlus gps; // create gps object

const byte SDCARD_CS_PIN = 4;
const char* dataFileName = "GPS_dat1.csv";
SdFat sd;
SdFile file;

RTC_DS3231 rtc;

bool getGPSdata()
{
  bool gotFix = false;
  while (Serial3.available()) {
    if ((gotFix = gps.encode(Serial3.read()))) break;
  }
  return gotFix;
}

void setup() {
  Serial.begin(57600); // connect serial
  Serial3.begin(9600); // connect gps sensor
  rtc.begin();
  sd.begin(SDCARD_CS_PIN, SPI_HALF_SPEED);
}

void loop() {
  if (getGPSdata()) {
    file.open(dataFileName, FILE_WRITE);
    // ...
    file.close();
  }
}

Bonjour,

Merci pour ces réponses:

@Artouste: le GPS vient de . Je n'ai jamais vérifier les trames sur le port serie pour chercher le dernier timestamp. un lien vers un tuto approchant ?

@J-M-L. le reste du code fait des acquisitions sur d'autres capteurs, aucun delay dans le le code, juste le temps nécessaire de lire les autres données sur un cycle. Un cycle prends 700 ms.
Comment pourrais je lire llensemble du port série ?

Je pense que la solution la plus simple serait un module GPS qui renvoie les coordonnées seulement à la demande> Savez-vous si un tel module existe ?

Cordialement

Un cycle prends 700 ms.

il faut traiter vos capteurs en asynchrone... lancer la demande de mesure, puis revenir plus tard lire le résultat.

Quel est le capteur ?

Je pense que la solution la plus simple serait un module GPS qui renvoie les coordonnées seulement à la demande> Savez-vous si un tel module existe ?

Non la solution la plus simple est sans doute de coder en prenant en compte la contrainte. Mais si vraiment vous voulez cela, vous prenez un arduino de plus, par exemple un nano ou micro qui n'aura que ça à faire, et vous connectez le GPS sur le port Serial et vous faites un petit bout de code sur cet Arduino qui répond à des demandes en I2C ou SPI.

Re bonjoru,

quelques centrales inertielles et mesure de distances pour les autres capteurs.
En asynchrone, avec un interrupt ou un timer ?
Je débute vraiment en Arduino, mais pas en codage... je me trouve vite limiter par les capacités du hard et les miennes en codage.
Autre solution, existe il un arduino multi-coeur ?

un ESP32 aura 2 coeurs, mais ça va être plus compliqué à programmer ...

en asynchrone, ça peut se faire de différence façon, interrupt si le module le supporte, timer (pour plusieurs centaines ms on peut gérer cela directement avec millis()) etc. certaines bibliothèques offrent directement cette possibilité de lancer l'acquisition et soit vous avez un call-back soit vous revenez de temps en temps voir si le résultat est dispo.

si vraiment vous galérez, la solution avec un arduino dédié et un petit protocole "maison" reste simple à mettre en oeuvre.

Bonjour à tous,

J'ai testé le code de J-M-L (un peu adapté) que voici :

#include <SdFat.h>
#include <RTClib.h>
#include <TinyGPS++.h>
RTC_DS3231 rtc;
TinyGPSPlus gps; // create gps object

const byte SDCARD_CS_PIN = 4;
const char* dataFileName = "GPS_AVDE.csv";
SdFat sd;
SdFile file;



bool getGPSdata()
{
  bool gotFix = false;
  while (Serial3.available()) {
    if ((gotFix = gps.encode(Serial3.read()))) break;
  }
  return gotFix;
}

void setup() {
  Serial.begin(57600); // connect serial
  Serial3.begin(9600); // connect gps sensor
  rtc.begin();
  sd.begin(SDCARD_CS_PIN, SPI_HALF_SPEED);
}

void loop() {
  if (getGPSdata()){
    Serial.println("Ecriture");
    file.open(dataFileName, FILE_WRITE);
    DateTime now = rtc.now();
    int YY = now.year();
    int MO = now.month();
    int DD = now.day();
    int HH = now.hour();
    int MI = now.minute();
    int SS = now.second();
    file.print(YY);
    file.print("; ");
    file.print(MO);
    file.print("; ");
    file.print(DD);
    file.print("; ");
    file.print(HH);
    file.print("; ");
    file.print(MI);
    file.print("; ");
    file.print(SS);
    file.print("; ");
    file.print(millis());
    file.print("; ");
    file.print(gps.location.lat(),12);
    file.print("; ");
    file.print(gps.location.lng(),12);
    file.print("; ");
    file.println(gps.altitude.meters(),2);
    file.close();
  }
//delay(500);
}

le code marche assez bien, environ trois écritures par seconde, trois fois la même mesure et les coordonnées changent toutes les secondes.
En revanche, si je dé-commente le delay(500) pour simuler le reste de la boucle (autres capteurs), l'intervalle entre les mesures est très irrégulier: entre 300 ms (comme sans le delay(500) et plusieurs dizaines de secondes, les coordonnées changent peu ...

Du coup, deux hypothèses :

  • le delay n'est pas la bonne manière de simuler la boucle,
  • la lecture du port serie (i.e. du GPS) n'est pas continue ....

Des pistes pour le dernier petit pas pour atteindre le but ?

Cordialement

Edit :

en intégrant ce bout de code dans le code principal, sans le delay puisque les autres capteurs sont là:

  • fréquence d'acquisition erratique mais données existantes tout le long de l'enregistrement (environ 2h)
  • les coordonnées (latitude, longitude) et altitude sont constantes ... la mise à jour de la position ne se fait pas ...

J'ai l'impression que l'encodage du port série ne se fait pas comme il faut ...

Bref, toujours au même point. D'autres idées pour avoir l'actualisation (sans passer par un autre arduino) ?

Cordialement

le code marche assez bien, environ trois écritures par seconde, trois fois la même mesure et les coordonnées changent toutes les secondes.

le fait que les données soient identiques est normal puisque votre GPS est sans doute configuré pour émettre une trame par seconde. A moins de changer ce paramètre (fréquence d'obtention des fix) vous n'aurez pas mieux.

le buffer série est limité à 64 caractères et à 9600 bauds

Une trame GPS fait souvent plus de 64 caractères, par exemple cette trame en contient 67

$GPRMC,045103.000,A,3014.1984,N,09749.2872,W,0.67,161.46,030913,,,A*7C\r\n

Quand le GPS va émettre la trame à 9600 bauds, le 65ème caractère va arriver au bout de 68ms. L'arrivée de ce caractère va faire perdre le plus vieux caractère dans le buffer

Si vous faites une pause trop longue entre deux lectures du port série, les 64 caractères restants dans le buffer seront (pour la trame ci dessus)

RMC,045103.000,A,3014.1984,N,09749.2872,W,0.67,161.46,030913,,,A*7C\r\n

le parser de TinyGPS++ ne va donc pas recevoir un $GPRMC et va ignorer entièrement la ligne.

==> comme dit précédemment vous ne pouvez pas vous permettre de ne pas extraire les données du buffer du port série du GPS pendant trop longtemps et c'est ce que vous faites avec votre delay(500)

pour avoir l'actualisation correcte, virez tout ce qui est bloquant, travaillez au maximum en asynchrone et s'il y a trop de tâches un peu longues / à risque dans la loop, lisez plusieurs fois le GPS dans la loop.

Une alternative serait de modifier le code de la bibliothèque qui gère le port série affecté au GPS de façon à augmenter la taille du buffer (si vous avez assez de RAM dans votre arduino) ou alors d'alimenter directement tinyGPS depuis le code d'interruption du hardware ou software serial (au risque de rester super longtemps dans l'interruption car tinyGPS fait pas mal de calculs une fois la trame reçue)...

Bonjour J-M-L,

Merci pour tes conseils .. .je suis allé bidouiller la taille du buffer en bidouillant le fichier HardwareSerial.h !
je l'ai mis à 256 et cela semble bien tourné ...

Par contre, cela engendre un problème avec un bout de code qui marchait très bien (récupération de données via un shield ethernet) ... le code complet fait 42210 bytes
Voici le tableau du buffer, et des variables globales ...

  • Buffer de 256, 69% de mémoire utilise - le code complet bug
  • Buffer de 128, 63% de mémoire utilise - le code bug
  • Buffer de 64, 60% de mémoire - cela marche, mais le GPS est dans les choux
    [/li][/list]

En gros, j'ai déshabillé Pierre pour habiller Jacques ... et cela vient d'un problème de mémoire ... je vaisessayer d'optimiser mon code en réduisant les tailles des des variables, mais je suis preneur de toute bidouille (genre utiliser une partie de la carte SD comme mémoire) ...

Cordialement

je suis preneur de toute bidouille

  • assurez vous que tous les print() de texte statique se font avec le texte en mémoire flash (macro F()). Par exemple au lieu de sortie.print("longitude: ");faites sortie.print(F("longitude: "));

  • n'utilisez pas la classe String

  • assurez vous d'utilisez des variables du bon type. Pas besoin d'un int (2 ou 4 octets) si vous voulez stocker dedans vrai ou faux ou HIGH ou LOW. un uint8_t suffit (1 seul octet)

postez éventuellement votre code, je jetterai un oeil

Bonjour,

J'ai pas mal optimisé mais ce n'est pas encore suffisant ... un lidar 2d basé sur ethernet necesiste l'envoie de commande et je verifie la bonne réception ...
Sans ces verifs (ex en desous), tout va bien : 61% de mémoire utilisée.
Avec des verif, 64% et cela déconne ...

char ans[30];
        
        int ilogin = 0;
        while (lidar2d.available())
          {
            ans[ilogin] = lidar2d.read();
            ilogin = ilogin + 1;
            ans[ilogin] = '\0';
          }       
        if (strstr(ans,"sAN SetAccessMode 1") != NULL)
          {
            Serial.println("login OK");
          }
        memset(&ans,0, sizeof ans);
        lidar2d.flush();

Des idées pour faire cela avec moins de memoire ?

Cordialement

Si vous êtes sur AVR vous pouvez utiliser strstr_P() pour comparer avec "sAN SetAccessMode 1" que vous mettriez en mémoire flash.

je vois aussi Serial.println("login OK");qui aurait dû être Serial.println(F("login OK"));comme déjà mentionné...

Vous devriez tester que vous ne recevez pas plus de 29 caractères dans

        while (lidar2d.available())
          {
            ans[ilogin] = lidar2d.read();
            ilogin = ilogin + 1;
            ans[ilogin] = '\0';
          }

de plus vous n'êtes pas garanti de lire tout ce qui arrive avec cette approche, le port série est asynchrone, vous pouvez vider le buffer d'entrée plus vite que les caractères n'arrivent

Re,

Je ne suis pas sous AVR, j'au un arduino mega de base.

merci ! j'ai changé les Serial.println et je les ai meme remplacé par return; en changeant le test dans le if.
63% ... pas encore assez stable.

Pour les 29 caractère, j'ai change le ans[30] par un ans [100], toujours 63%.
Il me faut encore gagner 2% .... je prends les autres idees ...

Cordialement

Je ne suis pas sous AVR, j'au un arduino mega de base.

si, si --> un Atmel AVR ATmega2560

Pour les 29 caractères, j'ai change le ans[30] par un ans [100], toujours 63%.

le compilateur ne reporte pas la mémoire dynamique. Si votre tableauchar ans[30];est dans le code d'une fonction, l'allocation se fait sur la pile et donc ce n'est pas pris en compte dans ce que vous dit le compilateur

utilisez vous la classe String ?

Re bonour,

J;ai essayé le code avec strstr_P, cela plante ... des incompatibilités connues avec des bibliothèques.
Je n'ai qu'une seule String, pour les données reçus d'un capteur.
C'est une char, transformée en string pour utilise la fonction String.remove
le char ans[30] est en dans dans le setup, mais je peux peut être le placer dans un void si cela peut aider ...

Cordialement

Je n'ai qu'une seule String, pour les données reçus d'un capteur.
C'est une char, transformée en string pour utilise la fonction String.remove

c’est sans doute coûteux... vous pouvez mettre ce code ? Il doit y avoir moyen de faire la même chose avec les fonctions des cStrings