comunicazione tra GSM/GPRS/GPS SHIELD e google maps

Ciao a tutti,
utilizzo arduino UNO e lo shield GSM/GPRS SHIELDV2 Servizio di incisione e taglio laser - FuturaShop con modulo FT971.
Arduino è collegato al pc tramite porta USB.
Sto cercando di realizzare un tracker satellitare. Ho cercato in lungo ed in largo relative info, capendo che è necessario seguire:

  • ricevere, ovviamente le coordinate dal GPS (cosa che riesco a fare)
  • creare un webclient (cosa che devo provare)
  • inviare al server la richiesta della pagina di google maps (cosa che non so fare)
  • ricevere via http la risposta di google maps e visualizzarla sul pc sempre tramite google maps (cosa che non so fare)

I passi elencati sopra sono corretti o manca qualcosa?
La comunicazione tra arduino e google maps deve avvenire per forza tramite gli AT commands o esistono delle librerie che semplificano lo sketch?
Se esistono delle librerie conoscete dei link relativi?

Grazie
David

http://www.cooking-hacks.com/documentation/tutorials/geolocation-tracker-gprs-gps-geoposition-sim908-arduino-raspberry-pi#realtime-geolocation-tracking

Grazie lesto.
Avevo già visto lo sketch presente nel link che hai postato: è implementato utilizzando gli AT command. Devo per forza utilizzarli o esiste una libreria adeguata?

esistono librerie che fanno il parsing degli at

per le Api di google e come fare prova guardare qui

se non ricordo male hai la possibilità di 1000 richieste di aggiornamento al giorno,
devi attivare alcune cose in google developers per avere possibilità di molte più richieste.

Ciao ragazzi,
ho usato due sketch, uno che riceve le coordinate e l'altro che invia dei dati alla mia pagina php tramite richiesta POST.
Singolarmente tali sketch funzionano benissimo, ma quando cerco di combinarli non funziona nulla. In particolare, il monitor seriale resta bianco, come se non venisse eseguita neanche la funzione void setup. Inoltre, mi sono accorto che il network led presente sul SIM908 resta spento, mentre con qualsiasi altro sketch lampeggia.
Il codice combinato è:

#include "SIM900.h"
#include <SoftwareSerial.h>
/**********************************codice aggiunto******************/
#include "inetGSM.h"
/******************************fine codice aggiunto******************/
//#include "sms.h"
//#include "call.h"
#include "gps.h"
#include "stdlib.h"

/**********************************codice aggiunto******************/
InetGSM inet;
/********************************fine codice aggiunto******************/

//CallGSM call;
//SMSGSM sms;

GPSGSM gps;

/**********************************codice aggiunto******************/
char msg[50];
int numdata;
char lat_str[10];
char long_str[10];
//char inSerial[50];
//int i=0;
//boolean started=false;
/********************************fine codice aggiunto******************/

char lon[15];
float lon_db;
char lat[15];
float lat_db;
char alt[15];
char time[20];
char vel[15];
char msg1[5];
char msg2[5];

char stat;
char inSerial[20];
int i=0;
boolean started=false;

void setup() 
{
  //Serial connection.
  Serial.begin(9600);
  Serial.println("GSM Shield testing.");
  //Start configuration of shield with baudrate.
  //For http uses is raccomanded to use 4800 or slower.
  if (gsm.begin(2400)){
    Serial.println("\nstatus=READY");
    gsm.forceON();	//To ensure that SIM908 is not only in charge mode
    started=true;  
  }
  else Serial.println("\nstatus=IDLE");
  
  if(started){
    //GPS attach
    if (gps.attachGPS())
      Serial.println("status=GPSREADY");
    else Serial.println("status=ERROR");
	
    delay(20000);	//Time for fixing
    stat=gps.getStat();
	if(stat==1)
		Serial.println("NOT FIXED");
	else if(stat==0)
		Serial.println("GPS OFF");
	else if(stat==2)
		Serial.println("2D FIXED");
	else if(stat==3)
		Serial.println("3D FIXED");
	delay(5000);
	//Get data from GPS
	gps.getPar(lon,lat,alt,time,vel);
	Serial.println(lon);
	Serial.println(lat);
	Serial.println(alt);
	Serial.println(time);
	Serial.println(vel);
/***************************codice aggiunto***********************/	
	lon_db=convert(lon);
        lat_db=convert(lat);
	sprintf(long_str,"%f",lon_db);
	sprintf(lat_str,"%f",lat_db);


//GPRS attach, put in order APN, username and password.
    //If no needed auth let them blank.
    if (inet.attachGPRS("internet.wind", "", ""))
      Serial.println("status=ATTACHED");
    else Serial.println("status=ERROR");
    delay(1000);
    
    //Read IP address.
    gsm.SimpleWriteln("AT+CIFSR");
    delay(5000);
    //Read until serial buffer is empty.
    gsm.WhileSimpleRead();
  
    //TCP Client GET, send a GET request to the server and
    //save the reply.
    numdata=inet.httpPOST("www.spaziopixel.com", 80, "/coordinate_arduino/index.php", "lat=lat_str&long=lon_str", msg, 50);
    //Print the results.
    Serial.println("\nNumber of data received:");
    Serial.println(numdata);  
    Serial.println("\nData received:"); 
    Serial.println(msg);
 /********************************fine codice aggiunto*****************/
  }
};

void loop() 
{
  //Read for new byte on serial hardware,
  //and write them on NewSoftSerial.
  serialhwread();
  //Read for new byte on NewSoftSerial.
  serialswread();
};

void serialhwread(){
  i=0;
  if (Serial.available() > 0){            
    while (Serial.available() > 0) {
      inSerial[i]=(Serial.read());
      delay(10);
      i++;      
    }
    inSerial[i]='\0';
    if(!strcmp(inSerial,"/END")){
      Serial.println("_");
      inSerial[0]=0x1a;
      inSerial[1]='\0';
      gsm.SimpleWriteln(inSerial);
    }
    //Send a saved AT command using serial port.
    if(!strcmp(inSerial,"GPS")){
        stat=gps.getStat();
	if(stat==1)
		Serial.println("NOT FIXED");
	else if(stat==0)
		Serial.println("GPS OFF");
	else if(stat==2)
		Serial.println("2D FIXED");
	else if(stat==3)
		Serial.println("3D FIXED");

delay(5000);
//Get data from GPS
gps.getPar(lon,lat,alt,time,vel);
lon_db=convert(lon);
lat_db=convert(lat);
Serial.println("dd.dddddd data:");
Serial.print("LON: ");
Serial.println(lon_db,4);
Serial.print("LAT: ");
Serial.println(lat_db,4);


    }
    //Read last message saved.
    if(!strcmp(inSerial,"MSG")){
      Serial.println(msg1);
    }
    else{
      Serial.println(inSerial);
      gsm.SimpleWriteln(inSerial);
    }    
    inSerial[0]='\0';
  }
}

void serialswread(){
  gsm.SimpleRead();
}

int strpos(char *str, char *target) {
char *res=0;
res = strstr(str, target);
if (res == NULL) return false;
else return res - str;
}

float convert(char* str){
float mmmmmm;
float dd;
int pos;
pos=strpos(str,".");
char dd_str[pos-1];
dd_str[0]='\0';
char mmmmmm_str[6];
mmmmmm_str[0]='\0';
for (int i=0; i<pos-2; i++){
dd_str[i]=str[i];
}
dd_str[pos-2]='\0';
dd=atof(dd_str);
mmmmmm_str[0]=str[pos-2];
mmmmmm_str[1]=str[pos-1];
mmmmmm_str[2]=str[pos];
mmmmmm_str[3]=str[pos+1];
mmmmmm_str[4]=str[pos+2];
mmmmmm_str[5]=str[pos+3];
mmmmmm_str[6]='\0';
mmmmmm=atof(mmmmmm_str);
float result;
result=dd+mmmmmm/60;
return result;
}

Dove sbaglio?

non è che usi troppa ram? quando compili cosa ti dice (ide >= 1.5.0)

l'IDE mi dice:
"Dimensione del file binario dello sketch: 18.846 bytes (su un massimo di 32.256 bytes)"

scarica l'ide beta 1.5.x dall apagina download (scorri la pagina in basso), lui ti dice ancge luso di ram statico

Ho installato la versione consigliata da te, lesto.
Avevi ragione lesto, le variabili globali occupano il 105% di memoria. Ho letto i consigli su come ridurre la dimensione dello sketch, ma non posso ridurlo perchè devo per forza utilizzare i float.
La soluzione quale sarebbe?
Forse è per questo motivo che mi avevi consigliato di utilizzare lo sketch con gli AT command presente nel sito cooking hacks?
In generale, quest'ultimo tipo di sketch è più performante?

il grosso problema direi che è il fatto che le tue variabili sono tutte globali. cerca di racchiudere il punto in cui ti servono in blocchi (ovvero {}), in tal modo quando il blocco si chiude la variabile "muore" e rilascia lo spazio ram.

sopratutto tutti qugli array di char... cerca di farli nascere e morire solo quando servono!

e occio che con i float perdi precisione sulle posizioni, anche di vari km a seconda delle latitudini

Ciao,
ho cercato di ridurre le variabili globali, ma invano. Ho deciso di provare a realizzare quanto in oggetto tramite lo sketch con gli AT command, che utilizza una quantità di memoria minore.
Invece di provare lo sketch completo, ho deciso di iniziare con quello che alla pressione di un pulsante, fa una chiamata voce ad un numero telefonico:

int8_t answer;
int onModulePin = 2;
int button = 12;
char aux_str[30];

char phone_number[]="123456789";     // ********* is the number to call

void setup(){

    pinMode(onModulePin, OUTPUT);
    pinMode(button, INPUT);
    digitalWrite(button, HIGH);
    Serial.begin(115200);      
    
    Serial.println("Starting...");
    power_on();
    
    delay(3000);
    
    // sets the PIN code
    //sendATcommand("AT+CPIN=****", "OK", 2000);
    
    //delay(3000);
    
    Serial.println("Connecting to the network...");

    while( (sendATcommand("AT+CREG?", "+CREG: 0,1", 500) || 
            sendATcommand("AT+CREG?", "+CREG: 0,5", 500)) == 0 );

    sprintf(aux_str, "ATD%s;", phone_number);
    sendATcommand(aux_str, "OK", 10000);
    
    // press the button for hang the call 
    while(digitalRead(button)==1);        

    Serial.println("ATH");            // disconnects the existing call
    

}

void loop(){

}

void power_on(){

    uint8_t answer=0;
    
    // checks if the module is started
    answer = sendATcommand("AT", "OK", 2000);
    if (answer == 0)
    {
        // power on pulse
        digitalWrite(onModulePin,HIGH);
        delay(3000);
        digitalWrite(onModulePin,LOW);
    
        // waits for an answer from the module
        while(answer == 0){     // Send AT every two seconds and wait for the answer
            answer = sendATcommand("AT", "OK", 2000);    
        }
    }
    
}

int8_t sendATcommand(char* ATcommand, char* expected_answer, unsigned int timeout){

    uint8_t x=0,  answer=0;
    char response[100];
    unsigned long previous;

    memset(response, '\0', 100);    // Initialize the string
    
    delay(100);
    
    while( Serial.available() > 0) Serial.read();    // Clean the input buffer
    
    Serial.println(ATcommand);    // Send the AT command 


    x = 0;
    previous = millis();

    // this loop waits for the answer
    do{
        if(Serial.available() != 0){    
            // if there are data in the UART input buffer, reads it and checks for the asnwer
            response[x] = Serial.read();
            x++;
            // check if the desired answer  is in the response of the module
            if (strstr(response, expected_answer) != NULL)    
            {
                answer = 1;
            }
        }
         // Waits for the asnwer with time out
    }while((answer == 0) && ((millis() - previous) < timeout));   

    return answer;
}

Considerate che tale sketch è presente nel sito di cooking-hacks ed adatto per lo shield fornito da loro. Io, invece utilizzo, lo shield acquistato da futura shop Servizio di incisione e taglio laser - FuturaShop. Caricando tale sketch in arduino nel monitor seriale visualizzo "starting" e poi stampa sempre AT, AT....
DOMANDA N°1: non capisco bene cosa fa la funzione "power on".
DOMANDA N°2: il problema sopra esposto credo derivi dal fatto che la board non riesce a comunicare con lo shield. Negli sketch usati prima era presente la libreria "software serial". Devo usarla anche in questo caso?

powerOn manda il comando "AT" via seriale finchè il modulo non risponde "OK"

il fatto che il comando "AT" arrivi al PC, vuol dire che quel codice non usa una porta seriale visrtuale ma quella fisica (pin 0 e 1) che sono usati per la USB.. quindi o usi il monitor seriale o usi il mduelo GPS.

consigli: inutile saltare da codice a codice, prendine uno e focalizzati. Per usare i comandi AT, devi assicurarti che il tuo modulo funzioni allo stesso modo. Puoi aprire la libreria giusta e vedere come funziona, e datasheet alla mano capire cosa è obbligatorio, e cosa puoi omettere.

la sprintf è una bruttissima cosa su una MCU, o usi una versione "alleggerita" apposta oppure non la usi proprio. strlcpy e simili sono tuoi amici

in realtà dovresti evitare a prescindere l'uso delle stringhe; o meglio, dovresti usare solo le stringhe costanti salvate su flash, e poi usare un sistema a stati (che di solito impiega 2 byte, uno per indicare lo stato attuale (i comandi parzialmente possibili) e uno per indicare a che indice sei arrivato.

per capirci abbiamo 3 stringhe, divise da uno spazio, che possiamo ottenere

CASA
CANE
CIBO

abbiamo un byte che indica i vari stati (diciamo S) e IND che è un byte che indica la posizione dell'array; all'inizio S = 1 e IND = 0
0: in errore, il carattere non era nessuno di quelli validi, azzera IND e resta in attesa di spazio, quando arriva spazio S verrà settata a 1
1: in attesa di primo carattere
2: il secondo carattere era una I, IND++, e continua fino a che non ricevi spazio incementando IND e verifiacnfo che il carattere letto sia uguale all'IND carattere nella stringa (per verificare che arrivi CIBO e non CICCIA, ed esempio)
3: il se secondo carattere è una A, IND++ resta in attesa del prossimo
4: se il terzo carattere è S allora come punto 2 ma con la stringa CASA
5: se il terzo carattere è N allora come punto 2 ma con la stringa CANE

ovviamente ogni errore porta al punto 0

Ciao.
Ho deciso di focalizzarmi sul codice che utilizza le librerie standard di arduino e non gli ATcommand.
Il problema dell'occupazione di memoria l'ho quasi risolto attuando quanto segue:

  • cancellando tutto quello che non uso nelle librerie
  • commentando i serial.print inutili, compresi quelli presenti nelle librerie
  • spostando parte del codice in un atmega328 standalone e quindi realizzando una configurazione master/slave tramite I2C

Preciso che sul master ho montato lo shield GPS/GPRS/GSM i quali comunicano tramite software serial coi pin 2 e 3.
Le variabili globali del master occupano il 70% di ram, mentre quelle dello slave il 30%. Vorrei ulteriormente snellire il master spostando altre parti di sketch nello slave, ma sono vincolato dal fatto che nel master sono presenti funzioni quali call, inetGSM ecc ecc, tutte funzioni che, credo, debbano stare nella board su cui è installato lo shield.
La domanda è: posso far comunicare lo slave con lo shield utilizzando la stessa seriale software o in qualsiasi altro modo?
Grazie a tutti.
David

io trasformerei quello che è collegato agli shield in slave, e praticmente lo renderei un "ponte" tra il master e gli shield. Esso si occupa di parlare con gli shield e di etrapolare le informazioni come richiesto dal master; poi glie le spedisce. Il master fa operazioni logiche. ma inrealtà questo funziona se la logica è tanta, altrimenti dividere equamente gli shiedl è un altra soluzione.. tutto dipende dal tuo codice!

Scusa lesto non ho capito bene. Tu dici che dovrei montare lo shield GPS/GPRS/GSM in un altro atmega standalone ottenendo così un master e due slave?

nono, di montare gli shiedl sullo slave, e usare il master che fa la logica. Ma non è detto che ciò basti o sia una buona idea, in base a quello che devi fare e come l'hai codato

Scambiare lo sketch del master con lo slave, si, posso farlo ma il problema resterebbe lo stesso, ovvero avrei le variabili globali dello slave che occuperebbero troppa memoria.
Di logica ne ho poca, solo quella relativa alla conversione delle coordinate nmea in gradi. Il resto sono tutte funzioni come inet, gps ecc.ecc- Oltre a queste dovrei ancora aggiungerne altre quali call e sms. L'ideale sarebbe poterle inserire nello slave (o nel master nel caso adottassi la soluzione da te consigliata) su cui non è installato lo shield GPS, ma non so se questo si possa fare.

bhe ma tra master e slave l'unica differenza è come decidi di chiamarli xD

a questo punto dividere le funzioni/shield in base alla "pesantezza" può essere una buona idea.

non ho idea su come dividere le funzioni tra due slave, cioè, come faccio a mettere ad esempio la funzione call in uno slave ed a farlo comunicare con lo slave in cui è presente il modulo GSM?