martedì 25 luglio 2017

FHT su Arduino

Un bel po' di tempo fa avevo provato ad accoppiare un microfono ad Arduino ma i risultati non mi avevano entusiasmato...visto che volevo provare ad usare FFT su Arduino ho ritirato fuori il vecchio modulo e lo ho accoppiato alla libreria ArduinoFHT di Open Music Lab

Lo sketch Arduino e' interessante perche' non si tratta di leggere solo l'input A0 ma inserisce un bel po' di trucchetti come mandare l'ADC in modalita' free running per velocizzare al massimo il campionamento

-----------------------
/*
fht_adc.pde
guest openmusiclabs.com 9.5.12
example sketch for testing the fht library.
it takes in data on ADC0 (Analog0) and processes them
with the fht. the data is sent out over the serial
port at 115.2kb.  there is a pure data patch for
visualizing the data.
*/

#define LOG_OUT 1 // use the log output function
#define FHT_N 256 // set to 256 point fht

#include <FHT.h> // include the library

void setup() {
  Serial.begin(115200); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < FHT_N ; i++) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fht_input[i] = k; // put real data into bins
    }
    fht_window(); // window the data for better frequency response
    fht_reorder(); // reorder the data before doing the fht
    fht_run(); // process the data in the fht
    fht_mag_log(); // take the output of the fht
    sei();
    Serial.write(255); // send a start byte
    Serial.write(fht_log_out, FHT_N/2); // send out the data
  }
}
-----------------------
ci sono diversi tipi di rappresentazione del risultati (nell'esempio viene indicata la rappresentazione logaritmica).
La rappresentazione del formato di output e' descritta qui. In pratica nel caso in esempio sono sequenze di 256 byte in cui ciascuno rappresenta una suddivisione dello spettro di frequenze
Per calcolare quanto e' ampio un intervallo si deve conoscere il passo di campionamento secondo la regola
  • Frequency(k) = (k)*(sample_rate)/(FHT_N)
Per modificare il passo di campionamento e' sufficiente lavorare sul valore di prescaler del convertitore analogico digitale
Di default il prescaler di ADC e' impostato a 128 il che porta ad un passo di campionamento di 9600 Hz (16.000 Hz/ 128 ovvero prescaler diviso di nuovo per 13 cicli processore per fare la conversione ADC)..in queste condizioni la massima frequenza analizzabile per il teorema di Nyiquist e' di 4800 KHz (il che va bene per suoni musicali)

In condizioni standard quindi ogni divisioni in frequenza e' larga 9600/256 =37.5Hz). Nel caso in esempio pero' tale valore e' modificato ed e' pari a 5 (gli ultimi 3 bit del valore esadecimale E5). Per variare il prescaler si deve agire sul registro ADCSRA
In pratica

#define CLOCK_PRESCALER_1 (0x0)
#define CLOCK_PRESCALER_2 (0x1)
#define CLOCK_PRESCALER_4 (0x2)
#define CLOCK_PRESCALER_8 (0x3)
#define CLOCK_PRESCALER_16 (0x4)
#define CLOCK_PRESCALER_32 (0x5)
#define CLOCK_PRESCALER_64 (0x6)
#define CLOCK_PRESCALER_128 (0x7)
#define CLOCK_PRESCALER_256 (0x8)


I dati che vengono inviati sulla porta seriale sono di tipo binario ed e' quindi necessario un programma per leggerli. Ho quindi installato Pure Data Extended e carico lo script di esempio arduinofft_display. Una volta settata la giusta porta seriale si vede il grafico popolarsi con i dati derivanti dalla Arduino



Sono stati suonati su una tastiera 3 Do a diversa altezza

NB: e' interessante leggere il codice sorgente di FHT.h perche' il codice e' quasi in tutto in ASM per ATMEGA

venerdì 21 luglio 2017

Force resistive sensor FSR402 ed Arduino

Un sensore comodo, anche se abbastanza costoso, da accoppiare ad un Arduino sono le resistenze variabile in funzione della pressione (Force-sensitive resistor o FSR)

In pratica premendo con qualche forza di pochi grammi al centro del sensore la resistenza varia fino ad annullarsi (in generale essendo funzione della pressione maggiore e' l'area interessata a parita' di pressione e maggiore sara' la risposte). E' quindi possibile sfruttare questo comportamento per creare un partitore di tensione
e misurare i dati in un ingresso analogico di Arduino
Nell'immagine sottostante uno schema base con una resistenza da 10 KOhm




Come riportata da questo sito in pratica ci sono due superfici separate da un sottile strato d'aria. Premendo si crea il contatto tra la superficie superiore e quella inferiore

Per il miglior funzionamento il sensore deve essere posto su una base liscia e piana

In generale non puo' essere usato per misurare l'intensita' di pressione (per questo esistono gli strain gauge) ma solo come una sorta di interruttore a pressione

giovedì 20 luglio 2017

GNSS raw data in Android N

Con Android N sono disponibili le API per accedere ai dati raw del GPS e comtemporaneamente e' stato rilasciato un programma di esempio GNSSLogger sia in formato sorgente che in apk



I dati che si possono registrare sono molto interessanti perche' riguardano sia lo pseudorange che le informazioni di fase permettendo quindi un posizionamento GPS estremamente preciso.

Il problema e' attualmente principalmente legato all'hardware. Sono pochi attualmente i dispositivi che hanno una antenna GPS atta a registrare tutte le informazioni

Per esempio (vedi questo link) il Nexus 5x e' un pessimo candidato mentre e' decisamente piu' appetibile il Nexus 9 (parlando dei dispositivi che uso)





Per elaborare il file dati in uscita da GNSSLogger Google mette a disposizione degli script Matlab ma non possedendo una licenza ho trovato preferibile usare uno script in Python di Lukasz Bonenberg’s all'indirizzo 
https://github.com/DfAC/AndroidGNSS

Per fare girare lo script ipynb (iPython notebook) ho dovuto smanettare sulla mia Debian Box perche' e' stato necessario installare jupyter

pip install jupyter 

e poi sono state aggiornate alcune librerie mediante pip --upgrade

pip install --upgrade scipy


(si fa la stessa cosa con le librerie pandas, seaborn, numpy e matplotlib)

finiti gli aggiornamenti delle librerie si lancia

jupyter notebook --allow-root 

e si apre il file ProcessRanges.ipynb modificando il nome del file alla riga data_file e, dal menu, si lancia Cell/Run All



e si ottengono i dati delle elaborazioni. Nel caso del Nexus 5x lo script genera un errore quasi subito nel popolare un array mentre con i dati di Nexus 9 (grafici sottostanti) l'elaborazione si sviluppa fino a quando si cerca di elaborare la costellazione Galileo (non presente sul sensore del Nexus 9)









martedì 18 luglio 2017

Sostituzione display Nexus 5

In questo post viene indicato come sostituire uno schermo non funzionante di un Nexus 5 (la parte di ricambio e' stata comprata su Aliexpress....la qualita' del ricambio non e' per niente buona ma funziona ed soprattutto ha un prezzo che giustifica l'acquisto..il ricambio originale non e' conveniente)

Questo progettino non e' per utenti pavidi: bisogna armarsi di micro cacciavite ma soprattutto di phon per rimuovere le parti incollate

Per prima cosa si deve rimuovere lo scocca posteriore: Attenzione: al contrario di molti altri telefoni dove questo componente e' solo un pezzo di plastica, nel Nexus 5 sono ospitati dei componenti nella back cover. Rimuovere con delicatezza magari usanto un plettro di plastica


Con un piccolo cacciavite si rimuovono le parti nere sopra e sotto la batteria. Quello superiore e' solo uno schermo in plastica mentre quello inferiore ospita elettronica e deve essere prestata maggiore attenzione

A questo punto si devono rimuovere nell'ordine il cavo flat T (che libera la batteria) ed il connettore della batteria. Per i connettori basta esercitare una leggera pressione verso l'alto metre la batteria e' saldamente incollata


Si solleva quindi il connettore della flat P



Qui arriva la parte piu' delicata perche' si deve rimuovere la piastrina dove e' inserita la microUSB che risulta essere incollata. Al di sotto di questa si trovera' la flat del display




A questo punto si deve rimuovere lo schermo dalla parte anteriore...ulteriore colla. Nella foto sottostante il display e' stato separato dallo chassis e si vede la flat. Questa deve essere fatta scivolare nell'incavo dello chassis per liberare lo schermo


Si monta il nuovo schermo e si ripetono le operazioni al contrario

giovedì 29 giugno 2017

OBD e MKR1000

Un breve esempio su come interfacciare una Arduino MKR1000 con un trasmettitore ODB Wifi



l'ELM327 OBD con trasmissione WiFi si comporta come un hotspot WiFi senza nessuna autenticazione. Se ci si collega all'indirizzo 192.168.0.10 con telnet sulla porta 35000 si puo' interagire con il sistema diagnostico dell'auto.
In questo esempio si interroga il numero di giri motore: per prima cosa si inviano i codici ATZ e AT SP 0 per resettare ELM327 e per definire il protocollo di comunicazione, in seguito si invia la richiesta 010C per ottenere il numero di giri motore (vedi qui)

----------------------------------------------------------
#include <SPI.h>
#include <WiFi101.h>

char ssid[] = "WiFi_OBDII"; //  your network SSID (name)
char pass[] = "";    // your network password (use for WPA, or use as key for WEP)

int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

IPAddress server(192,168,0,10);
WiFiClient client;



void setup() {
  // attempt to connect to WiFi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid);

    // wait 10 seconds for connection:
    delay(10000);
  }

WiFi.maxLowPowerMode()

  // you're connected now, so print out the status:
  printWiFiStatus();

 if (client.connect(server, 35000)) {
    Serial.println("connected");
  } else {
    Serial.println("connection failed");
  }
  client.println("ATZ");
  delay(2000);
  client.println("AT SP 0");
  delay(2000);

}


void loop() {
  client.println("010C");

  while (client.available())
    {
      char c = client.read();
      Serial.print(c);
    }
  Serial.println();
  delay(1000);
}


void printWiFiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

------------------------------------------

Questo e' il log di una sessione. L'Elm327 puo' rispondere con

Searching....
No data
Engine Off

nel caso in cui il sistema non riesca ad interrogare il numero di giri motore. Altrimenti si ha un codice di 4 gruppi del tipo 41 0C a conferma della richiesta e poi due byte (byte alto e byte basso) che indicano il numero di giri motore moltiplicato per 4
------------------------------------------
SSID: WiFi_OBDII
IP Address: 192.168.0.13
signal strength (RSSI):-37 dBm
connected
ATZ



ELM327 v1.5

>
AT SP 0
OK

>
010C
SEARCHING...

41 0C 0C 84


>010C
41 0C 0C 8C


>
010C
41 0C 0C 90

>
010C
41 0C 0C 70

>
010C
41 0C 0C 8C

>
010C
41 0C 0C 78


>
010C
41 0C 0C 84


>010C
41 0C 0C 88


>
010C
41 0C 0C 80


>
010C
41 0C 0C 88

martedì 20 giugno 2017

Geo posizionamento Google Photo

Ho sempre pensato che Google usasse, per le immagini di Photo,  solo le informazioni derivanti dal GPS o dai metadati dell'header..questo fino a ieri

Google mi ha consigliato che la foto sottostante fosse stata scattata a Firenze nel Giardino di Boboli


In realta' l'immagine e' relativa ad una copertina di un disco "Firenze Sboccata" di Riccardo Marasco e quindi non ha una precisa impostazione geografica...ma l'immagine riportata sulla copertina e' relativa alla Fontana del Bacchino ubicata proprio nel Giardino di Boboli

Quindi Google ha effettuato una lettura dell'immagine e, studiando le affinita' con altre foto geotaggate, ha proposto il Giardino di Boboli come posizione di scatto

OBDSIM in Java




Per prima cosa si scarica IntelliJ Idea Commumity Edition e si importa i progetto File/New/Project from existing sources/Maven e si clicca sulla radice del progetto





poi da File/Project Structure si clicca su Libraries e si aggiunge la libreria jar bluecove che fornisce le librerie non presenti nel progetto preso da GitHub



Una volta cliccato Run si deve cliccare Edit Configuration, si preme + e si crea una Application.
Si imposta la classe Main e siamo quindi pronti a lanciare il progetto. Per creare il file .jar (in modo da non avere bisogno dell'IDE) si va in File/Project Structure/Artifacts si clicca + si aggiunge come JAR

java -cp obdsim.jar so.mwil.obdsim.Main

Si telnetta su

telnet 127.0.0.1 35000

e si richiedono i dati dei giri motore con

010C

il sistema risponde sempre al solito modo (non e' random) ovvero ripetendo il comando inviato con poi il codice 41 0C (codice di risposta) e 4b0 (il numero di giri in esadecimale ovvero 1200 che va diviso per 4 per ottenere gli RPM link)

010C
41 0C 4b0

Se Centos e' obbligatorio sbloccare la porta 35000, che e' filtrata dal firewall, con i comandi

firewall-cmd --zone=public --add-port=2888/tcp


Aruco Tag e filtri Kalman

Usando gli Aruco tag in ambiente esterno con illuminazione solare a diverse ore e in diversi periodi dell'anno ho trovato un errore nell...