giovedì 5 novembre 2015

Arduino Xbee/GPS Solar Powered con ibernazione

Questo e' uno dei progetti piu' completo a cui lavoro da un po' di tempo a questa parte

Si tratta di un sistema GPS con microcontrollore Arduino e trasmissione dati via Xbee con alimentazione da batteria Lipo e ricarica solare

Penna per riferimento di scala sulla sinistra

I componenti utilizzati sono 
- Arduino Uno
- Adafruit GPS Breakeout (gia' visto in questo post)
- Shield Xbee e Xbee (gia' visto in questo post)
- Solar Charger Shield v2.2. (gia' visto in questo post con le modifiche apportate)
- Pannello solare da 1W (8x10 cm)
- Batteria Lipo da 3000 mAh
- Scatola per esterni 10x6.8x5.0 mm
- Accelerometro ADXL335 (attualmente non in uso)


Il sistema in completo funzionamento (trasmissione dati + acquisizione GPS) consuma circa da 50 a 70 mA. Con ibernazione del sistema GPS ed dello XBee scende intorno a 20 mA

La batteria completamente carica misura 4.1-4.12 V; il limite inferiore a cui il sistema continua ad essere operativo e stabile e' circa 3.65 V
In uso continuativo con la tramissione dati ed il Gps accesi si ha un consumo di 0.03V/ora di esercizio
E' piu' difficile sitmare la ricarica derivante dal pannello solare. A sistema spento, quindi solo in ricarica, in un paio di giornate soleggiate di novembre la ricarica e' stata compresa tra 0.1 e 0.2 V per giorno

Nello sketch seguente l'Arduino acquisisce e trasmette per circa 10 minuti i dati GPS (la trasmissione si attiva solo dopo il fix GPS) ed iberna sia il GPS che la trasmissione per circa un minuto. In queste condizioni, senza ricarica solare, si ha un consumo sulla batteria di circa 0.3 V/h.
--------------------------------------------------------------------
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>

#define XBEE_SLEEP 9

const int analogInPin = A0; 
int BatteryValue = 0;     
float outputValue = 0;

unsigned long delaytime=250;


//GESTIONE DEL RISPAMIO ENERGETICO
// in max_misure c'e' il valore di quante misure consecutive vengono effettuate
// in sleep_time il numero di millisecondi in cui il GPS deve risultare spento
const int max_misure = 600;
int conta_misure = 0;
unsigned long sleep_time = 60000; //in millesimi di secondo

SoftwareSerial mySerial(3, 2);
Adafruit_GPS GPS(&mySerial);
#define GPSECHO  true
boolean usingInterrupt = false;
void useInterrupt(boolean); 



void setup() {
  Serial.begin(9600);
  GPS.begin(9600);
  GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
  GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);   // 1 Hz update rate
  GPS.sendCommand(PGCMD_ANTENNA);
  //enable DPGS
  GPS.sendCommand(PMTK_ENABLE_SBAS);
  GPS.sendCommand(PMTK_ENABLE_WAAS);

  useInterrupt(true);
  delay(1000);
  mySerial.println(PMTK_Q_RELEASE);

  //setta il pin 9 come controllo dello sleep di XBEE
  pinMode(XBEE_SLEEP,OUTPUT);
  //mette a ground il pin ovvero sveglia la trasmissione
  analogWrite(XBEE_SLEEP,0);
  //digitalWrite(XBEE_SLEEP,LOW);
}

SIGNAL(TIMER0_COMPA_vect) {
  char c = GPS.read();
#ifdef UDR0
  //if (GPSECHO)
    //if (c) UDR0 = c;  
#endif
}

void useInterrupt(boolean v) {
  if (v) {
    OCR0A = 0xAF;
    TIMSK0 |= _BV(OCIE0A);
    usingInterrupt = true;
  } else {
    TIMSK0 &= ~_BV(OCIE0A);
    usingInterrupt = false;
  }
}

uint32_t timer = millis();



void loop() { 
  if (! usingInterrupt) {
    char c = GPS.read();
    //if (GPSECHO)
      //if (c) Serial.print(c);
  }
  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA()))  
      return;  
  }

  if (timer > millis())  timer = millis();

  if (millis() - timer > 1000) { 
    timer = millis(); // reset the timer

if (GPS.fix)
    {
     //NOME DELLA STAZIONE
    Serial.print("ST01-");
    
    //carica della batteria
    BatteryValue = analogRead(analogInPin);            
    // Calculate the battery voltage value
    outputValue = (float(BatteryValue)*5)/1023*2;
    Serial.print(outputValue);
    Serial.print("-");
    
    //GPS
    if (GPS.hour < 10) Serial.print("0");
    Serial.print(GPS.hour,DEC);
    Serial.print(":");
    if (GPS.minute < 10) Serial.print("0");    
    Serial.print(GPS.minute,DEC);
    Serial.print(":");
    if (GPS.seconds < 10) Serial.print("0");    
    Serial.print(GPS.seconds,DEC);
    //Serial.print(".");
    //Serial.print(GPS.milliseconds,DEC);
    Serial.print(" ");
    if (GPS.day < 10) Serial.print("0");    
    Serial.print(GPS.day, DEC); Serial.print('/');
    if (GPS.month < 10) Serial.print("0");    
    Serial.print(GPS.month, DEC); Serial.print("/20");
    Serial.print(GPS.year, DEC);

    Serial.print("-");
    /*Serial.print(GPS.latitude,4);
    Serial.print("-");
    Serial.print(GPS.lat);
    Serial.print("-");
    Serial.print(GPS.longitude,4);
    Serial.print("-");
    Serial.print(GPS.lon);
    
    Serial.print("-");*/
    Serial.print(GPS.latitude_fixed);
    Serial.print("-");
    Serial.print(GPS.longitude_fixed);

    Serial.print("-");
    Serial.print(GPS.altitude,1); 

    Serial.print("-");
    Serial.print(GPS.HDOP,1); 
    Serial.print("-");
    Serial.print((int)GPS.fixquality); 

    Serial.print("-");
    if (GPS.satellites < 10) Serial.print("0");    
    Serial.print((int)GPS.satellites);
    Serial.println("-LU");

    //conta_misure++;

    }
    conta_misure++;
     //GESTIONE RISPARMIO ENERGETICO    
    //controlla se e' stato raggiunto il numero limite di misure
    if (conta_misure >= max_misure)
             {
               //se e' stato raggiunto spenge il GPS, attende lo sleep_time e lo riaccende
               conta_misure = 0;
               GPS.standby(); //spenge il GPS
               analogWrite(XBEE_SLEEP,168); //spenge XBEE, 3.3V PWM  
               //digitalWrite(XBEE_SLEEP,HIGH);

               delay(sleep_time); //tempo di standby
               GPS.wakeup(); //risveglia il GPS
               analogWrite(XBEE_SLEEP,0); //risveglia XBEE
               //digitalWrite(XBEE_SLEEP,LOW);

             } 
  }
}
--------------------------------------------------------------------

La ricevente e' un sistema Xbee in modalita' coordinator montato su Xbee Explorer e collegato ad un PC



Lo script per ricevere i dati in Python e' il seguente
--------------------------------------------------------------------
import serial
import sys
s = serial.Serial('/dev/ttyUSB1',9600)

while 1:
try:
if s.inWaiting():
    val = s.readline(s.inWaiting())
sys.stdout.write(val)
    except serial.serialutil.SerialException:
       pass
--------------------------------------------------------------------