angle entre deux points GPS

bonjour,
Je suis en train de faire un petit montage avec un GPS NEO6, je voudrais enregistrer un point GPS et en me promenant pouvoir indiquer sur un écran (genge gauge avec Nextion), la direction a prendre pour rejoindre ce point.
J’ai trouver pour la distance.
Problèmes pour obtenir un angle entre ces deux points.
j’ai récupéré u code sur le net, mais apres pas mal d’essais ca ne veux toujours pas compiler (arduino uno ou nano, idem)

un petit coup de mains svp.

/****************** Angle par apport au Nord entre deux point GPS *********************/

   double latitudeOrigine = 47.495092;
   double longitudeOrigne = 0.339203;
   double latitudeDest = 47.871741;
   double longitudeDest = -0.2362630;
   
    double longDelta = longitudeDest - longitudeOrigne;
    
    double y = sin(longDelta) * cos(latitudeDest);
    double x = cos(latitudeOrigine)*sin(latitudeDest) - sin(latitudeOrigine)*cos(latitudeDest)*cos(longDelta);
    double Angle = degrees(atan2(y, x)); 

  // le problème viens après, l'IDE me dis "'Angle' does not name a type" la variable est pourtant déclarée
    Angle = ( Angle + 360) / 360;
    Angle = ( Angle + 360) % 360; // ici c'est le modulo qui ne passe pas 
    Angle = 360 - Angle;


void setup()
{
  Serial.begin(9600);
  Serial.print("angle =");
  Serial.println(Angle);
}



void loop()
{
  
}

Tu as déclaré du code en dehors d'une fonction.

oui en effet,
est-ce mieux ainsi?

le modulo ne passe pas.

/****************** Angle par apport au Nord entre deux point GPS *********************/

   double latitudeOrigine = 47.495092;
   double longitudeOrigne = 0.339203;
   double latitudeDest = 47.871741;
   double longitudeDest = -0.2362630;
   
   double longDelta = longitudeDest - longitudeOrigne;
   
void setup()
{
    double y = sin(longDelta) * cos(latitudeDest);
    double x = cos(latitudeOrigine)*sin(latitudeDest) - sin(latitudeOrigine)*cos(latitudeDest)*cos(longDelta);
    double Angle = degrees(atan2(y, x)); // "atan" ou "tan" j'ai un doute 

    Angle = ( Angle + 360) / 360;
    Angle = ( Angle + 360) % 360; // ici c'est le modulo qui ne passe pas
    // invalid operands of types 'double' and 'int' to binary 'operator%'

    Angle = 360 - Angle;
    
  Serial.begin(9600);
  Serial.print("angle =");
  Serial.println(Angle);
}

void loop()
{ 
}

Bonjour,

Le modulo ne s'applique que pour des entiers.
Mais il faut te demander ce que tu veux faire:

    Angle = ( Angle + 360) / 360;

Ça n'a vraiment aucun sens!

    Angle = ( Angle + 360) % 360; // ici c'est le modulo qui ne passe pas

Ca pourrait avoir un sens (mais pourquoi le +360) si angle peut être supérieur à 360. Mais comment atan2 peut retourner un angle supérieur à 360°?

Conclusion: supprimes ces deux lignes.

atan2 retourne un résultat entre -PI et +PI donc après conversion tu récupères une valeur entre -180° et +180°.
Qu’est-ce que tu voulais faire ensuite?

en cas d'angle négatif j'ajoute 360 ° et un moment ce serra supérieur a 360 d’où le modulo.
en fait j'aimerai pouvoir renseigner deux points GPS et avoir un cap entre les deux. comme la rose des vents de ce site :

https://www.sunearthtools.com/fr/tools/distance.php#top

Il suffit d'ajouter 180 pour que l'angle soit toujours positif et il n'y a pas besoin de modulo.

au passage, un angle "entre deux points" ça ne veut rien dire... :slight_smile:
(avec un troisième ça irait mieux)

angle pas bien. il faut employer “roulement” visiblement :wink:
tu a raison “fdufnews” je m’y remet de ce pas.
je sent que je touche au but.

roulement??
J'utiliserais plutôt gisement.

a oui oui très juste le gisement.

je viens de me rendre compte que les valeurs calculées son en degrés et non en radiants. je corrige et test ça.

Ca a l’aire de fonctionner.
a voir maintenant une fois intégré dans le scketch final.
dîtes-moi ce que vous en pensez.

/***************************************/

   double lat1 = 47.780331 * 0.017453293; // mobile
   double lon1 = -0.462627 * 0.017453293; // mobile
   
   double lat2 = 47.364512 * 0.017453293; // fix
   double lon2 = -0.364868 * 0.017453293; // fix
 
   double longDelta = lon2 - lon1;
   
void setup()
{
    double y = sin(longDelta) * cos(lat2);
    double x = cos(lat1)*sin(lat2) - sin(lat1)*cos(lat2)*cos(longDelta);
    double Angle = degrees(atan2(y, x));
    while (Angle < 0) {
      Angle += 360;
    }        
  Serial.begin(9600);
  Serial.print("Angle = ");
  Serial.println(Angle);
}

void loop()
{ 
}

j'ai encore un petit soucis avec les variable.
bibli: TinyGPS++
lorsque je lis la valeur GPS

Serial.print(" Longitude= ");
Serial.print(gps.location.lng(),6);
ca me donne ca:
Longitude= 2.379759

mais quand j’essaie d'attribuer une variable, exemple:
double Lon1 = gps.location.lng(); // si j'ecris : (gps.location.lng(),6) bien sur ça me donne la valeur 6
Serial.print(" Lon1= ");
Serial.print(Lon1);
ça donne :
Lon1= 2.38

pour la précision c'est pas le top, y a t'il un moyen d'avoir au moins 6 chiffres après la virgule?

Le second paramètre 6 de la fonction print c’est le nombre de décimale à l’affichage.

Par défaut si vous affichez un float et ne mettez pas de second paramètre, alors c’est deux chiffres après la virgule.

 double Lon1 = gps.location.lng(); 

Serial.print("   Lon1 avec 2 chiffres = ");
Serial.println(Lon1); // si on demande rien, print avec 2 chiffres après la virgule

Serial.print("   Lon1 avec 4 chiffres = ");
Serial.println(Lon1, 4); // print avec 4 chiffres après la virgule

Serial.print("   Lon1 avec 6 chiffres = ");
Serial.println(Lon1, 6); // print avec 6 chiffres après la virgule

Lon1 lui a toujours toute la précision possible d’un float, c’est juste l’affichage que vous changez...

merci je ne savait pas. J'ai pas bien appris mes leçon :frowning:

Pour votre commentaire ici double Lon1 = gps.location.lng(); // si j'ecris : (gps.location.lng(),6) bien sur ça me donne la valeur 6

Vous avez bien compris que c’était "n’importe quoi" d’essayer cette écriture ? Le ,6 n’a rien à voir avec la variable précédente c’était juste l’écriture pour le second paramètre d’appel de la fonction print.

Il se trouve qu’en langage C ou C++ on peut bâtir une expression composée en séparant des expressions par une virgule (donc rien à voir avec un appel de fonction où la virgule sert de séparateur des paramètres) .

Si on écrit expression1 [b][color=red] , [/color][/b] expression2 le langage dit que le compilateur doit évaluer d’abord expression1 puis expression2 et la valeur retournée par cette expression composée est la valeur issue de l’évaluation de expression2

En faisant double Lon1 = (gps.location.lng(),6);Le compilateur appelait la méthode lng() sur l’objet gps.location ce qui retournait la longitude, ce résultat était ignoré et ensuite le compilateur évaluait la seconde expression, ici la valeur 6 donc son évaluation c’est 6. C’est cette seconde valeur qui était retournée par l’expression composée et donc voilà pourquoi vous aviez 6 dans la variable Lon1.

C’est important de bien comprendre la syntaxe du langage.

Merci pour cette précision J_M_L.

J’ai retravaillé le code pour mon indicateur de direction.
je fix un point de départ et une fois en mouvement j’aimerai avoir la distance, et la dirrection de ce point.
arduino nano ou méga, gps Neo-6M ou BN-880

le calcul du gisement a l’aire d’être bon, la distance c’est pas terrible je n’arrive pas a trouver la bonne valeur, la route a suivre pour retrouver la point de départ m’indique n’importe quoi.
la partie pour convertir les coordonnées gps en DMS (degrés, minutes, secondes) marche bien. c’est déja ça :wink:

#include <Wire.h>

/************* gps ******************/
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(8, 7);
Adafruit_GPS GPS(&mySerial);
#define GPSECHO  true

float alti;
int Alti; // sans virgule pour affichage
int sat;
int Vits;
float Vitesse;
int compas;
float Latitude;
float Longitude;


/************************ variables calcul GPS ****************************/
bool timer = 0; // compteur pour declanchement calcule route et distance
double lat2 = 0; // set latitude pour calcule
double lon2 = 0; // set longitude pour calcule
double lat1 = 0;
double lon1 = 0;

double flat = 0 ; // fix
double flon = 0 ; // fix
double tlat = 0 ; // mouv
double tlon = 0 ; // mouv

double gisement = 0; // pour calcul gisement

int route = 0;       // pour calcul route
int routeV = 0;      // pour calcul route
int dif = 0;         // pour calcul route

int distance = 0;  // distance
float tlatRad = 0;   // distance
float tlonRad = 0;   // distance
float midLat = 0;    // distance
float midLon = 0;    // distance
float dist = 0;      // distance
float latRad = 0;    // pour calcul distance
float lonRad = 0 ;   // pour calcul distance

int vitesse = 0;

/************** conversion décimales DMS ************/
float lat_dd;
String lat_SouthN;
int Lat_NS;
float lat_d1;
int lat_d;
float lat_m1;
int lat_m;
float lat_s;

float lon_dd;
String lon_SouthN;
int Lon_EW;
float lon_d1;
int lon_d;
float lon_m1;
int lon_m;
float lon_s;

int lat_rest;
int lat_sec;
int lon_rest;
int lon_sec;




void setup() {
  Wire.begin();
  Serial.begin(115200); 
  mySerial.begin(9600); // Serial GPS


  /************** gps*****************/
  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  GPS.sendCommand(PGCMD_NOANTENNA);

  
  /*******************************/
}

uint32_t timergps = millis(); //gps

void loop() {

   
 
  /************** gps ******************/
  char c = GPS.read();
  if ((c) && (GPSECHO))

    if (GPS.newNMEAreceived()) {

      if (!GPS.parse(GPS.lastNMEA()))
        return;
    }

  if (millis() - timergps > 1000) {
    timergps = millis();
    alti = (GPS.altitude);
    Alti = alti;
     Serial.print(" Altitude = ");
     Serial.print(Alti);

    sat = (GPS.satellites);
     Serial.print(" Nb Sat = ");
     Serial.print(sat);

    Vits = (GPS.speed);
    Vitesse = Vits * 1.852;
    vitesse = Vitesse;
     Serial.print(" Vitesse = ");
     Serial.print(vitesse);

    compas = (GPS.angle);    
     Serial.print("  Compas = ");
     Serial.println(compas);

    /////// Latitude ////////
    Latitude = (GPS.latitudeDegrees);

    lat_dd = Latitude;//  47.3849600;
    if (lat_dd < 0) {
      lat_SouthN = "S";
      Lat_NS = 0;
    }
    else {
      lat_SouthN = "N";
      Lat_NS = 1;
    }
    lat_d1 = abs(lat_dd);
    lat_d = lat_d1;
    lat_m1 = (lat_d1 - lat_d) * 60;
    lat_m = lat_m1;
    lat_s = (lat_m1 - lat_m) * 60;
    lat_sec = lat_s;
    lat_rest = (lat_s - lat_sec) * 10000;

    /////// Longitude ////////
    Longitude = (GPS.longitudeDegrees);

    lon_dd = Longitude;//-0.3391100;
    if (lon_dd < 0) {
      lon_SouthN = "W";
      Lon_EW = 0;
    }
    else {
      lon_SouthN = "E";
      Lon_EW = 1;
    }
    lon_d1 = abs(lon_dd);
    lon_d = lon_d1;
    lon_m1 = (lon_d1 - lon_d) * 60;
    lon_m = lon_m1;
    lon_s = (lon_m1 - lon_m) * 60;
    lon_sec = lon_s;
    lon_rest = (lon_s - lon_sec) * 10000;
 

    /******************************* Calcul Distance **************************/

     if (timer == 0)
     {
        flat = (GPS.latitude)  ; // fix
        flon = (GPS.longitude) ; // fix
        timer = 1;
  }

    double tlat = (GPS.latitude)  ; // mobile
    double tlon = (GPS.longitude) ; // mobile

    latRad = flat  * 0.017453293;  // set lat pour calcul distance
    lonRad = flon  * 0.017453293;  // set lon pour calcul distance
    tlatRad = tlat * 0.017453293;
    tlonRad = tlon * 0.017453293;

    midLat = tlatRad - latRad;
    midLon = tlonRad - lonRad;
    float latSin = sin((latRad - tlatRad) / 2);
    float lonSin = sin((lonRad - tlonRad) / 2);

    dist = 2 * asin(sqrt((latSin * latSin) + cos(latRad) * cos(tlatRad) * (lonSin * lonSin)));

    distance = dist * 6371000; // distance en Km ( rayon de la terre)

     Serial.print(" distance = ");
     Serial.print(distance);

    /****************************** Calcul Gisement ***************************/
    lat2 = tlat * 0.017453293; // mobile
    lon2 =  tlon * 0.017453293; // mobile
    latRad = lat2;  // set lat pour calcul distance
    lonRad = lon2;  // set lon pour calcul distance
    timer = timer = 1 ;


    double lat1 = flat * 0.017453293; // fix
    double lon1 = flon * 0.017453293; // fix

    double longDelta = lon2 - lon1;
    double y = sin(longDelta) * cos(lat2);
    double x = cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(longDelta);
    gisement = degrees(atan2(y, x));

    while (gisement < 0) {
      gisement += 360;
    }

     Serial.print("   gisement = ");
     Serial.print(gisement);
    /******************************* Calcul Route *****************************/
    int moyenneAngle;
    for (int i = 0; i < 30; i++) {
      moyenneAngle += (GPS.angle);
      delay(1);
    }
    moyenneAngle /= 30;
    int degr = moyenneAngle;// (GPS.angle); // compas

    if (degr <= 180) {
      if (degr < gisement) {
        route = gisement - degr;
      }
      if ( degr > gisement) {
        route = degr - gisement;
        route = 360 - route;
      }
    }
    if (degr > 180) {
      if (degr < gisement) {
        dif = gisement - degr;
        route = 360 - dif;
        route = 360 - route;
      }
      if ( degr > gisement) {
        dif = degr - gisement;
        route = 360 - dif;
      }
    }

     Serial.print("    route = ");
     Serial.print(route);

  }

}

Quand vous avez ce genre de calcul math-trigo à valider, je vous conseille de faire des jeux de test avec des résultats connus à l'avance.
Jeu 1 : point 1 sur l'équateur longitude 0. Point 2 latitude 1° N longitude 1° est. Cap 45°.
Jeu 2 : point 1 au pôle nord, longitude quelconque. Point 2 latitude 89° N longitude quelconque. Cap 180°.
Etc...
J'ai l'impression que vos formules sont approchées pour des petits déplacements. S'en servir pour faire un vol Paris-San-Francisco sur une orthodromie risque de vous ramener des surprises.

S'en servir pour faire un vol Paris-San-Francisco

le service en ligne "Great Circle Mapper" donne une idée du Heading en tenant compte de la rotondité