venerdì 13 novembre 2015

ADXL335 su Photon Particle

Ho avuto modo di provare una scheda Particle Photon, un modulo programmabile con WiFi, che ha la caratteristica principale di essere programmabile via Cloud con una interfaccia Web. Il prezzo attuale e' circa sui 19 dollari (spedizione esclusa)


Il processore e' un ARM Cortex M3 con un 1Mb di memoria flash e 128 Kb di ram con sistema operativo FreeRTOS 
La scheda e' estremamente piccola (pesa sui 5 grammi ed ha dimensioni di 36.5x20.3x6.8 mm, vedi per confronto la breadboard) e puo' essere alimentata da Usb oppure da VIN con un intervallo da 3.6 a 5.5 V

Immagine ufficiale dal sito del produttore

Si puo' derivare corrente dal pin 3V3 (3.3 V) oppure dal VIN (4.8 V/1A)
Il consumo dichiarato e' di 80 mA ma nelle mie prove ho visto un valore medio di 40 mA (con trasmittente accesa)

Sono disponibili 7 pin analogici con un ADC a 12 bit (come Arduino Due), una seriale TTL e 7 pin GPIO digitali

La programmazione avviene puntando il browser su https://build.particle.io e selezionando il proprio dispositivo.


Si programma in modo molto simile ad una Arduino e per caricare lo sketch sulla scheda si preme il pulsante del fulmine. Visto che tutto avviene via rete non e' necessario nessun cavo di collegamento dati e non e' nemmeno necessaria la vicinanza fisica (io la prova l'ho effettuato programmando da remoto senza averla nemmeno mai vista direttamente)


L'aspetto forse piu' interessante e' che le variabili (per esempio la lettura di un sensore) si possono effettuare direttamente via cloud. Non e' necessario conoscere l'IP della Photon e non e' necessario smanettare sul router per le regole delle porte del firewall

se nello sketch si inserisce una riga del tipo

Spark.variable("volts_x", &volts_x, DOUBLE);

il valore di questa variabile sara' disponibile all'indirizzo (con servizio REST)

https://api.particle.io/v1/devices/ID_PHOTON/volts_x?access_token=ACCESS_TOKEN

dove si deve sostituire a ID_PHOTON una stringa alfanumerica di 24 caratteri identificativa del dispositivo mentre ACCESS_TOKEN e' una stringa di 40 caratteri (entrambe si recuperano dall'interfaccia web cliccando nella colonna a sinistra in basso sul simbolo del mirino (Devices) per ID_PHOTON e su Settings per l'ACCESS_TOKEN

La risposta del sito e' qualcosa di questo tipo (il valore della variabile nel campo result)
--------------------------------------------------------------------------------
{
  "cmd": "VarReturn",
  "name": "volts_x",
  "result": 2.0012695312499997,
  "coreInfo": {
    "last_app": "",
    "last_heard": "2015-11-13T09:19:34.112Z",
    "connected": true,
    "last_handshake_at": "2015-11-13T09:19:02.262Z",
    "deviceID": "430024000e47343233323032",
    "product_id": 6
  }
}
--------------------------------------------------------------------------------
Un altro vantaggio dell'approccio Cloud e' che si puo' ospitare una pagina Web su un IP pubblico e gestire tutti i sensori con indirizzi su rete privata Dato che le informazioni passano via Cloud non e' possibile avere un refresh estramamente veloce (nelle prove e' stato chiaro che scendere sotto 1Hz di refresh dei dati era molto difficile) Per provare la Photon ho collegato un Breakout ADXL335 di Sparkfun, accelerometro in uscita analogica, che e' settato per avere un passo di campionamento di 50 Hz (sono gia' presenti condensatori da 10 microFarad) con misure +/- 3g. Visto che e' stato alimentato a 3.3V la conversione tra V e g e' pari a 330mV/g. Quindi ad accelerazione zero viene letto un valore in tensione pari 1.65 v (3.3V/2). Effettuando la sottrazione tra il valore letto e 1.65 V ed effettuando la conversione si ha il valore in accelerazione g Il consumo dell'ADXL335 e' di circa 375 microAmpere
Attenzione : la sensibilita' e' differente sui vari assi. Su X e Y sono significative fino al centesimo di g mentre su Z e' significativo il decimo di g
Utilizzando questa pagina (modificata da un esempio trovato in rete) 
-----------------------------------------
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript" charset="utf-8"></script>
<script src="raphael-2.1.4.min.js"></script>
<script src="justgage-1.1.0.min.js"></script>
<script>
var accessToken = "INSERIRE ACCESS TOKEN";
var deviceID = "INSERIRE DEVICE ID"
var url_x = "https://api.spark.io/v1/devices/" + deviceID + "/volts_x";
var url_y = "https://api.spark.io/v1/devices/" + deviceID + "/volts_y";
var url_z = "https://api.spark.io/v1/devices/" + deviceID + "/volts_y";
function callback_x(data, status){
if (status == "success") {
volts_x = parseFloat(data.result);
g.refresh(volts_x);
setTimeout(getReading_x, 50);
} else {
alert("There was a problem");
}
}
function callback_y(data, status){
if (status == "success") {
volts_y = parseFloat(data.result);
g2.refresh(volts_y);
setTimeout(getReading_y, 50);
} else {
alert("There was a problem");
}
}
function callback_z(data, status){
if (status == "success") {
volts_z = parseFloat(data.result);
g3.refresh(volts_z);
setTimeout(getReading_z, 50);
} else {
alert("There was a problem");
}
}
function getReading_x(){
$.get(url_x, {access_token: accessToken}, callback_x);
}
function getReading_y(){
$.get(url_y, {access_token: accessToken}, callback_y);
}
function getReading_z(){
$.get(url_z, {access_token: accessToken}, callback_z);
}
</script>
</head>
<body>
<table><tr>
<td><div id="gauge_x" class="200x1600px"></div></td>
<td><div id="gauge_y" class="200x160px"></div></td>
<td><div id="gauge_z" class="200x160px"></div></td>
</tr></table>
<script>
var g = new JustGage({
id: "gauge_x",
value: 0,
min:-3.0,
max: 3.0,
title: "Acc. Z(g)",
decimals : 2
});
getReading_x();
</script>
<script>
var g2 = new JustGage({
id: "gauge_y",
value: 0,
min: -3.0,
max: 3.0,
title: "Acc. Y(g)",
decimals : 2
});
getReading_y();
</script>
<script>
var g3 = new JustGage({
id: "gauge_z",
value: 0,
min: -3.0,
max: 3.0,
title: "Acc. X(g)",
decimals : 2
});
getReading_z();
</script>
</body>
</html>
-----------------------------------------

Si puo' avere una lettura dei valori di accelerazione mediante Photon su Web


(ovviamente l'asse Z misura l'accelerazione di gravita' e quindi non e' zero, il valore dovrebbe essere piu' vicino ad 1, forse c'e' da rivedere il fattore di conversione)

Essendo una visualizzazione via Web il refresh dei dati e' piuttosto lento e lontano dalla frequenza di 50 Hz. In Javascript ho impostato un valore di lettura ogni 50 millisecondi ma aprendo in Chrome Strumenti per sviluppatori/Network si vede chiaramente che vengono impiegati dai 350 ai 500 ms per ogni transazione web (quindi un campionamento intorno a 2-3 Hz)



Una ultima considerazione : come "brand" scegliere Photon e Particle come nomi non e' che sia proprio un colpo di genio. Cercando sui motori di ricerca "Photon Particle" per ottenere informazioni su questo dispositivo saltano fuori seriosissimi articoli di fisica e non quanto desiderato

Nokia Lumia 630 Hard Reset

Il Nokia 630 ha smesso in maniera del tutto improvvisa di rispondere ai comandi (qualcosa mi  dice che Windows non perde il vizio di freezare in modo inaspettato)


L'unico sistema per riconquistare il controllo e' stato effettuare un hard reset. La procedura e' la seguente


  • Spengere il telefono
  • Riaccenderlo con il tasto Vol Giu' premuto e collegando l'alimentazione

a questo punto appare un punto esclamativo sullo schermo. Si procede con la sequenza

  • Vol Su
  • Vol Giu'
  • Tasto accensione
  • Vol Giu'

A questo punto compare l'immagine con gli ingranaggi (vedi foto).
Con questa procedura si ottiene la completa formattazione (non ci sono piu' contatti, foto, messaggi ecc.) ma le foto possono essere recuperati da OneDrive. Si deve quindi riprocedere con tutta la configurazione del telefono come se fosse uscito dal negozio

mercoledì 11 novembre 2015

Vertici IGM e Regione Toscana

Frugando su Internet ho scoperto per caso che nel paese in cui vivo e' presente
Sul sito dell'IGM all'ID 106602 e' presente la scheda di un punto geodetico della rete di raffittimento a 7 Km

Come si vede chiaramente anche dalla nota riportata a margine dell'immagine, la precisione del punto e' al secondo d'arco. Alle latitudine di interesse un secondo di arco di latitudine vale circa 22.3 m mentre un secondo d'arco di longitudine vale circa 30.8 m, una precisione del tutto inutile per utilizzi "seri". All'IGM non sono impazziti, semplicemente per avere dati piu' dettagliati questi devono essere pagati...

Ero gia' pronto all'esborso quando ho fatto una prova sul SIT della Regione Toscana.


Sul tema Punti geodetici di raffittimento 7 Km e' presente un punto a Caldine che ha lo stesso codice di quello del database IGM ma qui le coordinate sono espresse in Gauss Boaga con la precisione al centimetro

In estrema sintesi la Regione Toscana offre gratuitamente la stessa informazione che IGM pone a pagamento

A questo punto rimane la conversione delle coordinate del punto da Gauss Boaga in WGS 84, realizzata mediante il programma Traspunto

Gauss Boaga piane: 1685517.43 E, 4855934.06E
Gauss Boaga geografiche : 43.49566281,-1.08420721
WGS 84 geografiche gradi,primi,secondi: 43°49'58.9742",11°18'25.4385"
WGS 84 geografiche gradi decimali : 43.83304838,11.30706625




Riportando il punto su Google Earth si vede che la georefenziazione delle immagini di Google e' molto, molto buona nella zona di interesse


Dopo aver spostato un po' di erba e scavato un po' ecco il chiodo di riferimento


martedì 10 novembre 2015

Validazione MTK3339 (3)

Seguendo quanto iniziato qui, ho fatto una nuova serie di misure il 6 novembre 2015  (piu' ridotta nel tempo, circa 5000 misure) di giorno in modo da testare il sistema ricarica a pannello solare (misura dalle 12:13 alle  14:41)


La prima novita' e' stata che la qualita' della tramissione radio e' stranamente peggiorata con circa il 7 per mille dei messaggi giunti corrotti (nel dettaglio sono arrivati 5262 pacchetti corretti su un totale di 5655)

Il punto medio e' stato misurato in
Latitudine : 43.8335234
Longitudine : 11.3105038

nella misura precedente il punto medio era
Latitudine : 43.8335196
Longitudine : 11.310521

La distanza tra i due punti e' calcolata in circa 2 m (in realta' il punto era il medesimo per entrambe le misure)

Durante questa prova non e' mai stata attivata la Fix Quality 2

I valori di tensione della batteria sono variabili perche', essendo una misura fatta di giorno, il pannello solare ha funzionato in ricarica. Si vede intorno alla misura 2000 la ricarica del pannello verso la batteria Lipo

Il grafico di quota e' invece (per quanto inutile)


In definitiva l'MTK3339 risulta avere misure confrontabili nell'intorno di un paio di metri abbastanza indipendentemente dalla copertura dei satelliti

lunedì 9 novembre 2015

Gpsbabel

Un paio di comandi per scaricare i dati da un Gps Garmin (in questo caso un vecchio modello con la seriale collegata ad un cavo Serial2Usb). Il Gps deve essere impostato con interfaccia Garmin

Nel primo caso i dati vengono scaricati e salvati sul file dati.nmea in formato nmea (viene scritta solo la stringa $GPWPL e quindi ci sono le informazioni latitudine e longitudine)
gpsbabel -i garmin -f /dev/ttyUSB1 -o nmea -F dati.nmea


Per estrarre altri dati come l'ora di acquisizione ed i metadati del punto (come il nome) si puo' salvare in formato garmin_txt che estrae un csv con tabulatori come separatori

gpsbabel -i garmin_txt,date="MM/DD/YYYY",time="hh:mm:ss xx" -f /dev/ttyUSB1 -o garmin_txt,date="DD.MM.YYYY",datum="WGS 84",dist=m,prec=6,temp=c,time="HH:mm:ss",utc=+2 -F dati.txt

Lo scaricamento dei dati non e' particolarmente veloce. Per 500 punti ci vogliono circa 49 secondi da Garmin V.

Garmin GPS V e raw data

Mi e' stato prestato un Garmin GPS V, un modello piuttosto vecchiotto ed uscito piu' o meno in contemporanea del modello 12XL visto qui.

A differenza del 12XL il modelloV non e' esattamente un modello cartografico ma piu' un navigatore stradale (qualunque cosa volesse dire navigatore stradale nel 1998!!)


Questo Gps monta un software che ricorda molto da vicino i primi Etrex ed ha anche l'opzione WAAS oltre ad una antenna orientabile per mettere il display in orizzontale (uso in macchina) od in verticale.
L'antenna ha una sensibilita' decisamente pessima e bisogna armarsi di pazienza ed un cielo sgombro di ostacoli per ottenere la propria posizione (basta entrare in una via stretta con palazzi alti per perdere immediatamente il segnale)

Il connettore posteriore e' uguale al modello 12XL ed ho quindi provato a vedere se era possibile effettuare una acquisione raw con il programma async.

Il programma e' riuscito ad acquisire i pacchetti (importante che al momento dell'inizio dell'acquisizione il display mostri la scritta indichi GPS 3D) ma al momento della conversione in formato RINEX con la stessa stringa vista nel precedente post, veniva generata solo l'intestazione del file RINEX.
Visto pero' che il software assomiglia all'Etrex ho provato ad aggiungere lo switch -rinex -etrex ed ecco che e' stato generato il file RINEX idoneo per il postprocessing

Per esteso il comando di conversione e' qualcosa del tipo
./gar2rnx_1_48 057615.g12 -f -rinex -etrex -area test

(come curiosita' il file RINEX indica che l'antenna del Garmin V e' una GPS12 a sottolineare la somiglianza tra l'hardware dei due modelli)

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
--------------------------------------------------------------------




Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...