martedì 23 febbraio 2016

Mini Tennis su Arduino

Sono abbastanza vecchio da aver giocato a Pong sulle consolle di fine anni 70-inizio anni 80 (in particolare alla versione Polistil) ed avendo una mezz'ora libera ed un schermo oled SSD1306 (32x128 pixel) ho voluto provare a farmi la mia versione di Pong con Arduino


Pong della Polistil

Questo progettino e' fatto soltanto per divertirsi e per imparare ad usare l'SSD1306, non c'e' nessuna pretesa di giocabilita'


Come sul pong originale il controllo della racchetta avviene mediante un potenziometro.
Via via che il gioco va avanti la velocita' della palla aumenta

// -------------------------------------------------------------------------------------
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define OLED_RESET 4

Adafruit_SSD1306 display(OLED_RESET);


int x;
int y;
int dx = 2;
int dy = 2;
int yb = 0;
int punteggio;
int contatore;
int ritardo;

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif

void setup()   {         
  Serial.begin(9600);
       
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  
  display.display();
  delay(200);
  punteggio = 48; //codice ASCII per il numero zero
  x = 64;
  y = random(30);
  contatore = 0;
  ritardo = 40;
  
  randomSeed(analogRead(0));

}


void loop() {
  x = x + dx;
  y = y + dy;
  display.clearDisplay();

  // disegna il punto
  display.drawPixel(x, y, WHITE);

  //disegna il punteggio
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(120,0);
  display.write(punteggio);
  //display.display();

  //legge il potenziometro
  int pot = analogRead(A2);
  Serial.println(pot);
  yb = round(pot/25);

  // disegna il rettangolo
  display.fillRect(1, yb, 2, 7, 1);
  display.display();

  // se trova una parete rimbalza
  if (x >= 127) dx = -dx;
  if (y >= 31) dy = -dy;
  //if (x <= 1) dx = -dx;
  if (y <= 1) dy = -dy;
  
  // se e' sulla parete di destra controlla la posizione
  // della barra
  // se rimbalza inverte la direzione
  if (x < 7)
     {
       if ((y >= yb) && (y <= yb+7))
           {
             dx = -dx;
             // dopo 10 rimbalzi consecutivi il gioco si fa piu' veloce 
             contatore = contatore + 1;
              if (contatore == 3)
                  {
                  contatore = 0;
                  ritardo = ritardo = ritardo - 3;
                  }
             }
       else
           {
              punteggio = punteggio + 1;
              delay(500);
              x = 64;
              y = random(30);
              dx = 2;
              dy = 2;
              ritardo = 40;
              contatore = 0;
           }
      } 

delay(ritardo);
}


lunedì 22 febbraio 2016

Validazione UBlox M8T

Tempo fa avevo provato a validare il modulo GPS di Adafruit (con pessimi risultati) usando un punto trigonometrico di coordinate conosciute



Stavolta e' stato il turno dell'UBlox M8T



Il sistema e' stato messo in registrazione dei dati in modalita' binaria e poi i dati sono stati postprocessati mediante RTKPost di RTKLib in modo differenziale con la registrazione dell'antenna dell'ex Provincia di Firenze (i dati sono scaricabili da qui, in formato Rinex compresso e aggiornati ogni ora con passo a 30 secondi)

Come si vede si ottiene il fix del punto differenziale dopo circa 5 minuti di registrazione (il che corrisponde a circa 10 misure visto il passo a 30 secondi)




Una volta ottenuto il fix la posizione e' molto stabile (dell'ordine del centimetro)

2016/02/18 09:21:00.000   43.833049301   11.307061053   203.6658   1   7   0.0016   0.0011   0.0027   0.0006  -0.0005  -0.0013   0.00   22.2

Visto che l'antenna della Provincia ha una posizione conosciuta si puo' tentare anche il posizionamento assoluto del punto di misura dell'Ublox
Secondo quanto riportato dal calcolo di post processing la posizione incognita risulta essere

Lat = 43.8330496301
Long = 11.307061053
(conversione effettuata mediante questo servizio online)

che corrisponde in coordinate metriche Gauss Boaga Fuso Ovest a

N = 1685517.05
E = 4855934.20

secondo quanto riportato dalla scheda del punto trigonometrico (fonte Regione Toscana) la posizione del punto in coordinate metriche e'

N = 1685517.43
E = 4855934.06

in conclusione la differenza di posizione e' di circa 38 cm su N e 14 cm su E. In realta', come si vede dalla figura, l'antenna non era posizionata esattamente al centro del chiodo ma spostata di circa 20 cm e si deve tenere conto anche dell'incertezza sulla conversione)

Si puo' dire che l'Ublox M8T e' validato con postprocessing per precisione alla decina di centimetri


Disabilitare video su Raspberry

Spesso uso la Raspberry in modalita' headless.
Adesso visto che lavoro ad un progetto in cui e' necessario risparmiare energia ho voluto provare a vedere se e' possibile disabilitare l'output da HDMI e da Video-Out (il connettore giallo) e se cio' diminuisce i consumi



Senza modifiche il consumo di Raspberry e' di circa 330 mA.
Mediante il comando

/opt/vc/bin/tvservice --off 

e' possibile disabilitare completamente l'output video. In questa modalita' il consumo passa a circa 300 mA con un  risparmio di circa il 10%. Non tantissimo ma puo' valere la pena di usare questa funzionalita' in caso di alimentazione a batteria

Consolle seriale su Raspberry

La possibilita' di amministrare una Raspberry via porta seriale e' particolarmente utile nel caso di una Pi Zero, vista l'assenza di una scheda di rete preinstallata.

La Raspberry dispone di una porta seriale TTL (in /dev/ttyAMA0) sui pin GPIO 8 (TX) ed 10 (RX) a cui si puo' connettere un modulo FTDI (attenzione, deve essere a 3.3 V pena il rischio di bruciare la porta). Attenzione: deve essere connesso anche il GND, l'alimentazione non e' obbligatoria ed e' necessaria solo se la Raspberry non ha nessuna altra alimentazione



Normalmente su questa porta seriale (115200, 8N1) vengono dirottati i messaggi di boot del kernel ma in Raspbian, tramite raspi-config (Avanzato,opzione A8) e' possibile ottenere una shell collegandosi via seriale



Schermata di raspi-config
Dal PC, per connettersi alla Raspberry si utilizza il comando screen

screen /dev/ttyUSB0 115200


Ovviamente se e' impostata questa funzione la porta seriale non sara' disponibile per altri usi, come per esempio interfacciarsi con una Arduino. In questo caso dovranno essere disabilitati, oltre alla shell mediante raspi-config, anche i messaggi di boot modificando il file in /boot/cmdline.txt






giovedì 18 febbraio 2016

RTKLib su Raspberry

Allo scopo di usare una attrezzatura piu' leggera e di maggiore durata di batteria ho provato ad accoppiare l'UBlox M8T ad una Raspberry B alimentando il tutto con un power bank da 10000 mAh


Per fare cio' era necessario compilare le RTKLib sulla Raspbian. La compilazione e' avvenuta senza nessuna modifica rispetto a quella che si esegue su desktop e rtkrcv funziona correttamente anche su Raspberry (ovviamente ci vuole molta pazienza per compilare i sorgenti data la velocita' del processore)

Per scaricare i dati e' stato sufficiente abilitare l'SFTP e connettersi con un cavo cross da portatile

giovedì 11 febbraio 2016

RTKLib postprocessing base e rover

Viene qui descritta una prova di post processing i dati di un Ublox M8T mediante il software RTKLib

L'attrezzatura e' costituita da una base Leica 500 ed un modulo Ublox M8T in acquisizione raw collegato ad un pc Debian





Il Leica 500 era configurato per una acquisizione al secondo (come l'Ublox) e permette la registrazione di L1+L2 mentre l'M8T acquisisce solo L1

Entrambi i dispositivi erano statici al momento dell'acquisizione

Questa e' la mappa dei punti derivati da una acquisizione senza post processing


Come si vede i dati sono distribuiti su un'area di raggio di circa 3 m. (la zona di acquisizione aveva alberi e non era particolarmente ben esposta)

I dati del Leica 500 sono stati esportati in Rinex mediante il proprio software mentre i dati binari dell'Ublox sono stati convertiti in Rinex con RTKLib

L'elaborazione del dato e' stata effettuata con RTKPost sotto Windows e mostra come i dati dell'Ublox risultino migliori con fluttuazioni di circa +/- 20 cm rispetto al punto medio





--------------------------------------------------------
Se non si  ha una stazione base si puo' sfruttare lo stesso principio per migliorare le misure basandosi su stazioni di misura che distribuiscono dati su Internet come la rete RING (nel mio caso la stazione piu' vicina e' quella di Carmignano di Prato). I dati vengono distribuiti in directory che hanno come nome il giorno progressivo dell'anno .... per esempio il giorno 8 febbraio 2016 si trovera' nella cartella 039 e cosi' via

I dati si possono scaricare il giorno successivo a quello dell'acquisizione e sono in formato Rinex compatto (CRinex). Per poterlo usare con RTKPost deve essere convertito in Rinex standard mediante il software crx2rnx che e' incluso nel pacchetto di RTKLib

Questi sono i risultati di una prova. In questo caso ci sono oltre 20 chilometri tra l'Ublox e la stazione remota (che risulta essere dalla scheda anagrafica un Leica 1200) ed il passo di campionamento e' differente perche' la stazione remota registra dati solo ogni 30 secondi

La distribuzione dei punti senza correzione e' molto migliore del caso precedente perche' l'antenna GPS M8T e' stata montata su un tetto; comunque i punti sono compresi in un cerchio di +/- 1 m rispetto al punto medio




Per migliorare il dato, oltre ai file Rinex, si possono scaricare da qui i dati relativi alle effemeridi dei satelliti . I dati sono organizzati in directory secondo il criterio settimana_gps_numero del giorno. Per esempio il giorno 10 febbraio 2016 corrisponde alla cartella 1883 (ovvero la 1883° settimana GPS) ed il giorno mercoledi' corrisponde al codice 3 (0=domenica). Le effemeridi sono nel file .sp3 e sono divise in 4 file di 6 ore ciascuno (per i dati delle ore 10 si deve scarica il file igu18833_06.sp3).
Lo stesso si puo' fare per i dati del modello della ionosfera da ftp://ems.estesc.esa.int/pub/  dove sono distribuiti file .ems sempre con il formato del giorno progressivo (in questo caso mercoledi' 10 febbraio corrisponde alla directory d041 in cui i dati sono poi divisi per ora)

Nelle opzioni deve essere scelto il passo di campionamento piu' lento (in questo caso quello della base a 30 secondi)






Anche in questo caso e' visibile un miglioramento del dato grezzo (gia' peraltro buono) con una incertezza dell'ordine di 20 cm

mercoledì 10 febbraio 2016

RTKLib e Ublox M8T su Debian

RTKLib e' un software per gestire dati GPS in modalita' avanzata. Viene fornita una versione gia' compilata per Windows ma e' possibile farlo funzionare anche su Linux compilando i sorgenti (su Linux non e' prevista l'interfaccia grafica ma solo i programmi a linea di comando)

Sistema di acquisizione Toughbook CF-18 con Debian collegato a Ublox M8T


Si parte scaricando il pacchetto da GitHub (questo perche' e' disponibile una versione piu' avanzata rispetto a quella linkata sul sito.

 Prima di iniziare si devono soddisfare le dipendenze

sudo apt-get install build-essential
sudo apt-get install automake
sudo apt-get install checkinstall
sudo apt-get install liblapack3gf
sudo apt-get install libblas3gf


dopo aver scompattato il pacchetto di GitHub si entra nella directory app e si lancia la compilazione con
makeall.sh
in questo modo si compila la versione 2.4.2 p11, ho avuto invece problemi con la 2.4.3

Connettendo la USB dell'Ublox M8T questo viene riconosciuto come seriale virtuale su /dev/ttyACM0

il programma per effettuare l'acquisizione dati si chiama rtkrcv e si configura mediante un file testo (io ho un po' barato nel senso che prima ho creato un file di configurazione con RTKNavi su Windows e poi lo ho importato, ovviamente modificando alcune parti, sulla Linux box)

Il file compilato si trova in RTKLIB-master/app/rtkrcv/gcc

File M8T.conf
--------------------------------------------------------
# RTKNAVI options (2016/02/08 17:25:54, v.2.4.3 b8)pos1-posmode       =single     # (0:single,1:dgps,2:kinematic,3:static,4:movingbase,5:fixed,6:ppp-kine,7:ppp-static,8:ppp-fixed)
pos1-frequency     =l1         # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l5)
pos1-soltype       =forward    # (0:forward,1:backward,2:combined)
pos1-elmask        =15         # (deg)
pos1-snrmask_r     =off        # (0:off,1:on)
pos1-snrmask_b     =off        # (0:off,1:on)
pos1-snrmask_L1    =0,0,0,0,0,0,0,0,0
pos1-snrmask_L2    =0,0,0,0,0,0,0,0,0
pos1-snrmask_L5    =0,0,0,0,0,0,0,0,0
pos1-dynamics      =off        # (0:off,1:on)
pos1-tidecorr      =off        # (0:off,1:on,2:otl)
pos1-ionoopt       =brdc       # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc,7:qzs-lex,8:stec)
pos1-tropopt       =saas       # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad,5:ztd)
pos1-sateph        =brdc       # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
pos1-posopt1       =off        # (0:off,1:on)
pos1-posopt2       =off        # (0:off,1:on)
pos1-posopt3       =off        # (0:off,1:on,2:precise)
pos1-posopt4       =off        # (0:off,1:on)
pos1-posopt5       =off        # (0:off,1:on)
pos1-posopt6       =off        # (0:off,1:on)
pos1-exclsats      =           # (prn ...)
pos1-navsys        =1          # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:comp)
pos2-armode        =continuous # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
pos2-gloarmode     =off        # (0:off,1:on,2:autocal)
pos2-bdsarmode     =off        # (0:off,1:on)
pos2-arthres       =3
pos2-arthres1      =0.9999
pos2-arthres2      =0.25
pos2-arthres3      =0.1
pos2-arthres4      =0.05
pos2-arlockcnt     =0
pos2-arelmask      =0          # (deg)
pos2-arminfix      =10
pos2-armaxiter     =1
pos2-elmaskhold    =0          # (deg)
pos2-aroutcnt      =5
pos2-maxage        =30         # (s)
pos2-syncsol       =off        # (0:off,1:on)
pos2-slipthres     =0.05       # (m)
pos2-rejionno      =30         # (m)
pos2-rejgdop       =30
pos2-niter         =1
pos2-baselen       =0          # (m)
pos2-basesig       =0          # (m)
out-solformat      =llh        # (0:llh,1:xyz,2:enu,3:nmea)
out-outhead        =off        # (0:off,1:on)
out-outopt         =off        # (0:off,1:on)
out-timesys        =gpst       # (0:gpst,1:utc,2:jst)
out-timeform       =hms        # (0:tow,1:hms)
out-timendec       =3
out-degform        =deg        # (0:deg,1:dms)
out-fieldsep       =
out-height         =ellipsoidal # (0:ellipsoidal,1:geodetic)
out-geoid          =internal   # (0:internal,1:egm96,2:egm08_2.5,3:egm08_1,4:gsi2000)
out-solstatic      =all        # (0:all,1:single)
out-nmeaintv1      =0          # (s)
out-nmeaintv2      =0          # (s)
out-outstat        =off        # (0:off,1:state,2:residual)
stats-eratio1      =100
stats-eratio2      =100
stats-errphase     =0.003      # (m)
stats-errphaseel   =0.003      # (m)
stats-errphasebl   =0          # (m/10km)
stats-errdoppler   =1          # (Hz)
stats-stdbias      =30         # (m)
stats-stdiono      =0.03       # (m)
stats-stdtrop      =0.3        # (m)
stats-prnaccelh    =10         # (m/s^2)
stats-prnaccelv    =10         # (m/s^2)
stats-prnbias      =0.0001     # (m)
stats-prniono      =0.001      # (m)
stats-prntrop      =0.0001     # (m)
stats-prnpos       =0          # (m)
stats-clkstab      =5e-12      # (s/s)
ant1-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm)
ant1-pos1          =90         # (deg|m)
ant1-pos2          =0          # (deg|m)
ant1-pos3          =-6335367.6285 # (m|m)
ant1-anttype       =
ant1-antdele       =0          # (m)
ant1-antdeln       =0          # (m)
ant1-antdelu       =0          # (m)
ant2-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm)
ant2-pos1          =90         # (deg|m)
ant2-pos2          =0          # (deg|m)
ant2-pos3          =-6335367.6285 # (m|m)
ant2-anttype       =
ant2-antdele       =0          # (m)
ant2-antdeln       =0          # (m)
ant2-antdelu       =0          # (m)
misc-timeinterp    =off        # (0:off,1:on)
misc-sbasatsel     =0          # (0:all)
misc-rnxopt1       =
misc-rnxopt2       =
misc-pppopt        =
file-satantfile    =
file-rcvantfile    =
file-staposfile    =
file-geoidfile     =
file-ionofile      =
file-dcbfile       =
file-eopfile       =
file-blqfile       =
file-tempdir       =C:\Temp
file-geexefile     =
file-solstatfile   =
file-tracefile     =
file-cmdfile1      =ubx_m8t_glo_raw_1hz.cmd


#

inpstr1-type       =serial     # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,7:ntripcli,8:ftp,9:http)
inpstr1-path       =ttyACM0:9600:8:n:1:off
inpstr2-path       =
inpstr3-path       =
inpstr1-format     =ubx        # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
inpstr2-format     =rtcm2      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
inpstr3-format     =rtcm2      # (0:rtcm2,1:rtcm3,2:oem4,3:oem3,4:ubx,5:ss2,6:hemis,7:skytraq,8:gw10,9:javad,10:nvs,11:binex,12:rt17,15:sp3)
inpstr2-nmeareq    =off        # (0:off,1:latlon,2:single)
inpstr2-nmealat    =0          # (deg)
inpstr2-nmealon    =0          # (deg)
outstr1-type       =file       # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
outstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
outstr1-path       =./soluzioni.txt
outstr2-path       =
outstr1-format     =llh        # (0:llh,1:xyz,2:enu,3:nmea)
outstr2-format     =llh        # (0:llh,1:xyz,2:enu,3:nmea)
logstr1-type       =file       # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr2-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr3-type       =off        # (0:off,1:serial,2:file,3:tcpsvr,4:tcpcli,6:ntripsvr)
logstr1-path       =./raw_data.ubx
logstr2-path       =
logstr3-path       =
misc-svrcycle      =10         # (ms)
misc-timeout       =10000      # (ms)
misc-reconnect     =10000      # (ms)
misc-nmeacycle     =5000       # (ms)
misc-buffsize      =32768      # (bytes)
misc-navmsgsel     =all        # (0:all,1:rover,2:base,3:corr)
misc-proxyaddr     =
misc-fswapmargin   =30         # (s)

--------------------------------------------------------
Per abilitare la trasmissione dei pacchetti Ublox si deve chiamare il file ubx_mt8_glow_raw_1hz.cmd. Nella directory data di RTKLib sono presenti anche altri file a diversi passi di campionamento (5Hz e 10Hz) e da differenti impostazioni (ubx_m8t_bds_raw_1hz.cmd). Il file ubx_raw_1hz.cmd serve solo per cambiare il passo di campionamento ed e' sostanzialmente inutile


I dati vengono salvati in due file
soluzioni.txt e' un semplice file testo in cui vengono salvati i dati della posizione gia' elaborati (sono presenti anche le colonne sdn,sde,sdu,sdne,sdeu,sdun che sono rispettivamente la standard deviation nelle componenti Nord, Est, Z e quelle sulla componente Nord-Est, Est-Z e Z-Nord ). Questo fase e' sostanzialmente inutile per il postprocessing

In raw_data.ubx  vengono salvati tutti i dati in uscita dalla seriale senza elaborazione ovvero le stringhe NMEA ed i pacchetti UBX binari. Questi ultimi possono essere utilizzati per il postprocessing convertendo i dati in Rinex mediante il programma convbin.

./convbin -od -os -oi -ot -f 1 data.ubx
Una volta creato il file M8T.conf si lancia ./rtkrcv e si apre una shell (altrimenti ./rtkrcv -o M8T.conf) . Si digita
load M8T.conf 
restart

il sensore entra in acquisizione
per vedere l'avanzamento si puo' digitare status. Altrimenti si puo' digitare solution per vedere l'aggiornamento del punto GPS con i relativi errori. Spesso aggiungendo un numero alla fine del comando si setta il tempo di refresh del comando per esempio solution 1 aggiorna la posizione una volta al secondo

file .ubx con le stringhe NMEA e pacchetti binari UBX

status

satellite

solution


Per terminare il comando e' shutdown
Con questa soluzione e' possibile evitare di usare U-Center e Windows


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