Go Down

Topic: Maledette funzioni!! (Read 15052 times) previous topic - next topic

paolometeo2

Ragazzi, come promesso vi metto al corrente degli sviluppi sulla precisione del calcolo delle distanze terrestri su Arduino.
Per fare i confronti ho usato, sia la mia fidata calcolatrice HP 11C con 10 cifre significative, sia un programma in Fortran che usa i real*8 ovvero floating point a 64 bit. Non solo, ma una delle distanze ottenute l'ho misurata anche con il "righello" di Google Earth. I risultati sono molto confortanti e li ho scritti come commenti sul codice qui sotto. (Le distanze sono in metri e le direzioni in gradi rispetto al N)
Code: [Select]
#include <math.h>
     float direct;
     float dis;
void setup(){
  Serial.begin(9600);
/*
   float la1 = 45.78956;
   float lo1 =  9.36424;
   float la2 = 45.78897;
   float lo2 =  9.36514;
   */
//   dis = 95.6; direct = 133.1     HP:  95.8   133.2  Fortran 95.6 133.1
//   Google Earth 96  133
   
   /*
   float la1 = 45.78956;
   float lo1 =  9.36424;
   float la2 = 45.77297;
   float lo2 =  9.36514;
   */
   // dis = 1846.1  direct = 177.8   HP:  1846  177.8  Fortran 1846.1  177.8
/* 
   float la1 = 45.78956;
   float lo1 =  9.36424;
   float la2 = 45.78957;
   float lo2 =  9.36514;
*/
   // dis = 69.8  direct = 89    FORTRAN  69.8  89.0
   float la1 = 45.78956;
   float lo1 =  9.36424;
   float la2 = 45.78937;
   float lo2 =  9.36426;

//  dis = 20.8  direct = 180   FORTRAN 20.8  direzione 180

   dis =  Distance(la1, lo1, la2, lo2);
   Serial.print(" distanza = ");
  Serial.println(dis);
  Serial.print(" direzione = ");
  Serial.println(direct);
}
void loop(){
 
}
////////////////////////////////////////////////////////////////////////
  float Distance(float lat1, float lon1, float lat2, float lon2){
  float rt = 6371000;  // raggio terra in m
  float pi = 3.141592654;
  float coslat = cos((lat1+lat2)*pi/360);
  float dx = rt*(lon2-lon1)*coslat*pi/180;
  float dy = rt*(lat2-lat1)*pi/180;
  float dist = sqrt(dx*dx + dy*dy);
  //
  if(dist < 4){
    direct = 0;
  }
  else{
        if(abs(dx) < 4 && dy >= 0){
              direct = 360;
         }
         else if(abs(dx) < 4 && dy < 0){
              direct = 180;
         }
         else{
              direct = 180*atan(dy/dx)/pi;
              if(dx > 0){
                 direct = 90 - direct;
              }
              if(dx < 0){
                 direct = 270 - direct;
              } 
         }
    }
      return(dist);
  }
paolo
www.meteoenergia.it

leo72

1) quindi hai risolto continuando ad usare i float. E cos'era allora che non andava?
2) abituati a fare i confronti float con float, quindi questo if:
Code: [Select]
if (dist < 4)
fallo diventare:
Code: [Select]
if (dist < 4.0)
3) l'Arduino già predefinisce pi greco come costante PI.
4) nell'Arduino hai già delle costanti predefinite per la conversione gradi/radianti e viceversa, DEG_TO_RAD e RAD_TO_GRAD.

Trovi le costanti nel file /hardware/arduino/cores/arduino/Arduino.h

paolometeo2

Il problema era iniziato con le variabili passate attraverso le funzioni, poi si è spostato sulla precisione dei calcoli fatti con le latitudini e longitudini di un GPS per calcolare distanze e direzioni. Adesso, dopo queste prove, sono abbastanza sicuro che i float di Arduino sono abbastanza precisi da garantirmi qualche metro, che è la stessa precisione di un buon GPS. 
Il mio progetto consiste nel mettere insieme il GPS Shield di Adafruit, la bussola LSM303 di Pololu e il LCD Color di Sparkfun, per fare uno strumento che ti dice dove sei e quanto sei distante da un punto di coordinate note, oltre alla direzione che devi prendere per raggiungere il punto. E' più da tracking che da navigazione in auto, ma i navigatori spesso non ti permettono certe funzioni, E poi vuoi mettere il gusto di costruirselo da solo!
Grazie dei consigli sulle costanti.
Paolo

P.S.
per chi volesse vedere i tre pezzi in funzione, ho un paio di immagini qui:

http://www.meteoenergia.it/GPS/03082013382.jpg
http://www.meteoenergia.it/GPS/03082013384.jpg
paolo
www.meteoenergia.it

leo72

Ma all'alimentazione ci hai pensato?

paolometeo2

Dovendo essere portatile, dovrò alimentarlo con una batteria, magari ricaricabile con la presa 12 V dell'auto. Non ho ancora misurato l'assorbimento di tutto il trabiccolo.
paolo
www.meteoenergia.it

leo72

Era quello il punto, perché un modulo GPS più un display LCD immagino che succhino abbastanza corrente.

PaoloP


Ma @paolo non è abbastanza skillato? Fà molti interventi nel forum


Ci sono più Paolo qui. Non è che ti confondi.  :smiley-mr-green:

paolometeo2

Vuol dire che siamo tutti skillati!!  :smiley-mr-green: :smiley-mr-green:
paolo
www.meteoenergia.it

Etemenanki


Vuol dire che siamo tutti skillati!!  :smiley-mr-green: :smiley-mr-green:


...  :smiley-roll-blue: ...

Spero che tu non ti offenda per una battuta, ma ... sei sicuro che ci andavano le "elle" e non le "zeta" ? ... :P XD XD XD
"Sopravvivere" e' attualmente l'unico lusso che la maggior parte dei Cittadini italiani,
sia pure a costo di enormi sacrifici, riesce ancora a permettersi.

lestofante


Volevo proprio evitare di usare i puntatori e concentrarmi più sul problema numerico, infatti Guglielmo mi ha capito.


allora non puoi sfruttare i parametri, però puoi ritornare una struttura che al suo interno contiene i 2 volori, oppure un array se i valori da ritornare sono dello stesso tipo.
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

paolometeo2

Ho risolto con le variabili globali.  Infatti i due valori che devo calcolare con la funzione hanno sempre lo stesso significato, sia nella funzione che nel main.
paolo
www.meteoenergia.it

leo72

Paolo, hai letto i miei suggerimenti al reply #16?

paolometeo2

oggi implemento il tutto e posto il codice con una foto
paolo
www.meteoenergia.it

paolometeo2

#28
Aug 07, 2013, 06:14 pm Last Edit: Aug 07, 2013, 06:16 pm by paolometeo2 Reason: 1
Ecco il programma finito!  :) Il GPS fa le seguenti cose:
1) Rileva i parametri GPS (lat, lon, alt..)
2) Rileva la direzione del puntatore del GPS rispetto al N con la bussola
3) Calcola la distanza tra la posizione attuale e un punto fisso assegnato all'interno del programma
4) Calcola la direzione in cui è "visto" il punto fisso rispetto al puntatore del GPS.
Purtroppo non posso postarlo perchè eccede il limite massimo, lo posto fino al setup() compreso.

Code: [Select]
// This software demonstrates the possibility of this hardware:
// Arduino UNO,
// GPS-Shield from Adafruit,
// Color-LCD from Sparkfun,
// LSM303 tilt compensated compass from Pololu,
//
//  to be working together. Futhermore it computes the distance and the direction
//  of a fixed poit from the current  position.
//
//  This code is a merge among the:
//     Adafruit GPS Library Parsing.ino
//     Color Shield Library by Jim Lindblom  TestPattern.ino
//     Pololu LSM303 Library  Heading.ino
//  with some lines from the author (Paolo Bonelli 07/August/2013)
//
/*     ******WIRING  LSM303 COMPASS******

Wiring:
pre. Arduino Uno/Duemilanove     LSM303 board
                   5V  ->  VIN
                  GND  ->  GND
         Analog Pin 5  ->  SCL
         Analog Pin 4  ->  SDA


    ******* WIRING  Adafruit GPS shield ****
     
     Cut cupper strips between D7, RX and D8, TX
     Jump RX and TX to pin D10 and D12

      ******WIRING Sparkfun Color LCD******
     
      LCD      Arduino UNO
      8          D8
      9          D9
      11         D11
      13         D13
      3.3        3.3
      5          5
      GND        GND
*/

#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LSM303.h>
#include <ColorLCDShield.h>
#include <math.h>

    float direct;  //  direction of the fixed point respect to North in degree (from 0 to 360)
    float dis;     //  distance in m between current position and the fixed point
    float la2 = 45.51970;  //  fixed point latitude in degree
    float lo2 = 9.15294;   //  fixed point longitude in degree
    int heading = 0;       //  Compass direction respect to N in degree (from 0 to 360)
    float dismin = 4.0;    // minimum distance in m (GPS precision)
    int gpsperiod = 4000;  //  time period for updating GPS data (ms)

LSM303 compass;
LCDShield lcd;
SoftwareSerial mySerial(12, 10);
Adafruit_GPS GPS(&mySerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences.
#define GPSECHO  false
//  Set ECHO to true for printing some numbers
#define ECHO true
int buttons[3] = {3,4,5};
// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
char emi[3] ="  ";    //  emisphere  (N,S,W,E)
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
///////////////////////////////////////////////////////////////////////////////////
void setup()  
{
     for (int i=0; i<3; i++)
 {
   pinMode(buttons[i], INPUT);  // Set buttons as inputs
   digitalWrite(buttons[i], HIGH);  // Activate internal pull-up
 }
 // connect at 115200 so we can read the GPS fast enough and echo without dropping chars
 // also spit it out
 Serial.begin(115200);
 Wire.begin();
 compass.init();
 compass.enableDefault();
 // Calibration values. Use the Calibrate example program to get the values for
 // your compass.
 compass.m_min.x = -492; compass.m_min.y = -682; compass.m_min.z = -538;
 compass.m_max.x = 435; compass.m_max.y = 298; compass.m_max.z = 360;
 // 9600 NMEA is the default baud rate for Adafruit MTK GPS's- some use 4800
 GPS.begin(9600);
 
 // uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
 GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
 // uncomment this line to turn on only the "minimum recommended" data
 //GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
 // For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
 // the parser doesn't care about other sentences at this time
 // Set the update rate
 GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
 // For the parsing code to work nicely and have time to sort thru the data, and
 // print it out we don't suggest using anything higher than 1 Hz
 // Request updates on antenna status, comment out to keep quiet
 GPS.sendCommand(PGCMD_ANTENNA);
 // the nice thing about this code is you can have a timer0 interrupt go off
 // every 1 millisecond, and read data from the GPS for you. that makes the
 // loop code a heck of a lot easier!
 useInterrupt(true);
 delay(1000);
 // Ask for firmware version
 mySerial.println(PMTK_Q_RELEASE);
  // following two required for LCD
lcd.init(EPSON);
lcd.contrast(40); // sets LCD contrast (value between 0~63)
lcd.clear(BLACK);

}


Aggiungo un paio di foto
http://www.meteoenergia.it/GPS/trepezzi.png
http://www.meteoenergia.it/GPS/07082013388.jpg
paolo
www.meteoenergia.it

PaoloP

#29
Aug 07, 2013, 06:31 pm Last Edit: Aug 07, 2013, 06:34 pm by PaoloP Reason: 1
Ma lo puoi allegare.
Vai su Additional Options... nell'editor.

Così
Code: [Select]
    for (int i=0; i<3; i++)
 {
   pinMode(buttons[i], INPUT);  // Set buttons as inputs
   digitalWrite(buttons[i], HIGH);  // Activate internal pull-up
 }


o pomì
Code: [Select]
pinMode(buttons[0], INPUT_PULLUP);  // Set buttons as inputs and Activate internal pull-up
pinMode(buttons[1], INPUT_PULLUP);
pinMode(buttons[2], INPUT_PULLUP);

Go Up