Per terminare la serie, dopo Kalman e Madgwick un esempio di Complementary Filter
Dal punto di vistra computazionale e' il piu' semplice perche' si tratta di una sola formula
senza ricorsione e matrici
angle = 0.98 *(angle+gyro*dt) + 0.02*acc
(i parametri possono essere ottimizzati)
Una breve statistica (per raffronto con le prove precedenti)
Nr campioni : 20121
Media : -11.97
Range : 0.41
Std : 0.02
Varianza : 0.0005
Skewness :0.62
Il codice e' stato adattato da qui
-----------------------------------------------------------------------
// Complementary filter
#include <Wire.h>
int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;
float pitch=0;
float pitchAcc;
float P_CompCoeff= 0.98;
unsigned long delta_t,old_time;
void ComplementaryFilter(int ax,int ay,int az,int gy,int gz) {
long squaresum=(long)ay*ay+(long)az*az;
delta_t = micros()- old_time;
old_time = micros();
pitch+=((-gy/32.8f)*(delta_t/1000000.0f));
pitchAcc =atan(ax/sqrt(squaresum))*RAD_TO_DEG;
pitch =P_CompCoeff*pitch + (1.0f-P_CompCoeff)*pitchAcc;
}
void setup() {
Serial.begin(115200);
//Inizio configurazione clock interno
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
// Inizializzazione Accelerometro intervallo di 8g Fattore di scala 4096
Wire.beginTransmission(0x68);
Wire.write(0x1C);
Wire.write(0x10);
Wire.endTransmission();
// Inizializzazione Gyro Intervallo di 500 deg/sec LSB (fattore di scala) 65.5 deg/s
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x08);
Wire.endTransmission();
old_time = micros();
}
void loop() {
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68, 14);
while (Wire.available() < 14);
axRaw = Wire.read() << 8 | Wire.read();
ayRaw = Wire.read() << 8 | Wire.read();
azRaw = Wire.read() << 8 | Wire.read();
temperature = Wire.read() << 8 | Wire.read();
gxRaw = Wire.read() << 8 | Wire.read();
gyRaw = Wire.read() << 8 | Wire.read();
gzRaw = Wire.read() << 8 | Wire.read();
/*Serial.print(axRaw/4096.0); Serial.print(",");
Serial.print(ayRaw/4096.0); Serial.print(",");
Serial.print(azRaw/4096.0); Serial.print(",");
Serial.print(gxRaw/131.0); Serial.print(",");
Serial.print(gyRaw/131.0); Serial.print(",");
Serial.println(gzRaw/131.0);*/
ComplementaryFilter(axRaw,ayRaw,azRaw,gyRaw,gzRaw);
Serial.println(pitch);
delay(2);
}
martedì 19 marzo 2019
lunedì 18 marzo 2019
Filtro Madgwick con MPU6050 ed Arduino
Un test del filtro di Madgwick , un possibile sostituto per il filtro Kalman su processori meno potenti
La libreria per Arduino si trova a questo link
Da notare prima di tutte che :
1) la finestra di campionamento del filtro in Madgwick.begin aumenta o diminuisce la velocita' di convergenza dei dati
2) i dati devono essere inseriti nel filtro con le corrette unita' fisiche (m/sec2 e deg/sec) e non con i dati raw in uscita dal sensore
3) la libreria permette di inserire anche i dati di un sensore magnetico (che non e' pero' presente nella 6050)
Una prova veloce con il filtro Madgwick e MPU statica
Nr campioni : 73071
Media : 9.82
Range : 0.56
Std : 0.04
Varianza : 0.001
Skewness : -0.01
Nelle stesse condizioni ma con filtro Kalman
Nr campioni : 16568
Media : 9.84
Range : 0.44
Std : 0.04
Varianza : 0.001
Skewness : 0.05
Aggiornamento : per calcolare il valore della Temperatura in gradi Celsius si usa la formula
T = (lettura/340.0)+36.53
--------------------------------------------------------------------------------------------
#include <MadgwickAHRS.h>
#include <Wire.h>
int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;
Madgwick MadgwickFilter;
void setup() {
Serial.begin(115200);
//Inizio configurazione clock interno
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
// Inizializzazione Accelerometro intervallo di 8g Fattore di scala 4096
Wire.beginTransmission(0x68);
Wire.write(0x1C);
Wire.write(0x10);
Wire.endTransmission();
// Inizializzazione Gyro Intervallo di 500 deg/sec LSB (fattore di scala) 65.5 deg/s
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x08);
Wire.endTransmission();
// Inizializzazione LPF (Filtro passa basso) 43 Hz
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x03);
Wire.endTransmission();
MadgwickFilter.begin(100); // 100 Hz
}
void loop() {
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68, 14);
while (Wire.available() < 14);
axRaw = Wire.read() << 8 | Wire.read();
ayRaw = Wire.read() << 8 | Wire.read();
azRaw = Wire.read() << 8 | Wire.read();
temperature = Wire.read() << 8 | Wire.read();
gxRaw = Wire.read() << 8 | Wire.read();
gyRaw = Wire.read() << 8 | Wire.read();
gzRaw = Wire.read() << 8 | Wire.read();
/*Serial.print(axRaw/4096.0); Serial.print(",");
Serial.print(ayRaw/4096.0); Serial.print(",");
Serial.print(azRaw/4096.0); Serial.print(",");
Serial.print(gxRaw/65.5); Serial.print(",");
Serial.print(gyRaw/65.5); Serial.print(",");
Serial.println(gzRaw/65.5);*/
MadgwickFilter.updateIMU(gxRaw/65.5,gyRaw/65.5,gzRaw/65.5,axRaw/4096.0,ayRaw/4096.0,azRaw/4096.0) ;
Serial.println(MadgwickFilter.getRoll());
//ROLL = MadgwickFilter.getRoll();
//PITCH = MadgwickFilter.getPitch();
//YAW = MadgwickFilter.getYaw();
delay(2);
}
La libreria per Arduino si trova a questo link
Da notare prima di tutte che :
1) la finestra di campionamento del filtro in Madgwick.begin aumenta o diminuisce la velocita' di convergenza dei dati
2) i dati devono essere inseriti nel filtro con le corrette unita' fisiche (m/sec2 e deg/sec) e non con i dati raw in uscita dal sensore
3) la libreria permette di inserire anche i dati di un sensore magnetico (che non e' pero' presente nella 6050)
Una prova veloce con il filtro Madgwick e MPU statica
Nr campioni : 73071
Media : 9.82
Range : 0.56
Std : 0.04
Varianza : 0.001
Skewness : -0.01
Nelle stesse condizioni ma con filtro Kalman
Nr campioni : 16568
Media : 9.84
Range : 0.44
Std : 0.04
Varianza : 0.001
Skewness : 0.05
Aggiornamento : per calcolare il valore della Temperatura in gradi Celsius si usa la formula
T = (lettura/340.0)+36.53
--------------------------------------------------------------------------------------------
#include <MadgwickAHRS.h>
#include <Wire.h>
int16_t axRaw, ayRaw, azRaw, gxRaw, gyRaw, gzRaw, temperature;
Madgwick MadgwickFilter;
void setup() {
Serial.begin(115200);
//Inizio configurazione clock interno
Wire.beginTransmission(0x68);
Wire.write(0x6B);
Wire.write(0x00);
Wire.endTransmission();
// Inizializzazione Accelerometro intervallo di 8g Fattore di scala 4096
Wire.beginTransmission(0x68);
Wire.write(0x1C);
Wire.write(0x10);
Wire.endTransmission();
// Inizializzazione Gyro Intervallo di 500 deg/sec LSB (fattore di scala) 65.5 deg/s
Wire.beginTransmission(0x68);
Wire.write(0x1B);
Wire.write(0x08);
Wire.endTransmission();
// Inizializzazione LPF (Filtro passa basso) 43 Hz
Wire.beginTransmission(0x68);
Wire.write(0x1A);
Wire.write(0x03);
Wire.endTransmission();
MadgwickFilter.begin(100); // 100 Hz
}
void loop() {
Wire.beginTransmission(0x68);
Wire.write(0x3B);
Wire.endTransmission();
Wire.requestFrom(0x68, 14);
while (Wire.available() < 14);
axRaw = Wire.read() << 8 | Wire.read();
ayRaw = Wire.read() << 8 | Wire.read();
azRaw = Wire.read() << 8 | Wire.read();
temperature = Wire.read() << 8 | Wire.read();
gxRaw = Wire.read() << 8 | Wire.read();
gyRaw = Wire.read() << 8 | Wire.read();
gzRaw = Wire.read() << 8 | Wire.read();
/*Serial.print(axRaw/4096.0); Serial.print(",");
Serial.print(ayRaw/4096.0); Serial.print(",");
Serial.print(azRaw/4096.0); Serial.print(",");
Serial.print(gxRaw/65.5); Serial.print(",");
Serial.print(gyRaw/65.5); Serial.print(",");
Serial.println(gzRaw/65.5);*/
MadgwickFilter.updateIMU(gxRaw/65.5,gyRaw/65.5,gzRaw/65.5,axRaw/4096.0,ayRaw/4096.0,azRaw/4096.0) ;
Serial.println(MadgwickFilter.getRoll());
//ROLL = MadgwickFilter.getRoll();
//PITCH = MadgwickFilter.getPitch();
//YAW = MadgwickFilter.getYaw();
delay(2);
}
venerdì 15 marzo 2019
RS485 su Arduino
Dovendo acquisire dati in un posto in cui non posso usare nessuna trasmissione radio e dovendo mettere ad almeno 15-20 m il sensore dal micro controllore cercavo una trasmissione seriale "robusta" ed ho voluto provare la seriale RS485 di tipo industriale che e' data per trasmissioni fno al chilometro (ovviamente dipende dalla velocita' di trasmissione, qualita' dei cavi ecc.)
L'utilizzo e' molto trasparente. Si collega il cavo A+ con tutti i dispositivi presenti sulla linea di comunicazione (possono essere piu' di due) ed il cavo B-
Il connettore TTL-RS485 deve essere semplicemente alimentato e collegato alla seriale TTL di Arduino sui pin D0 e D1
Sul lato PC il dongle RS485-USB e' stato riconosciuto in modo immediato da Linux
E visto che ci siamo comprati un oscilloscopio perche' non usarlo
L'utilizzo e' molto trasparente. Si collega il cavo A+ con tutti i dispositivi presenti sulla linea di comunicazione (possono essere piu' di due) ed il cavo B-
Il connettore TTL-RS485 deve essere semplicemente alimentato e collegato alla seriale TTL di Arduino sui pin D0 e D1
Sul lato PC il dongle RS485-USB e' stato riconosciuto in modo immediato da Linux
E visto che ci siamo comprati un oscilloscopio perche' non usarlo
Progetto Due
Il progetto due prevede un sistema ad alimentazione solare con una Arduino MKR1400 collegata ad un accelerometro ADXL345 che invia un SMS nel momento in cui il sensore registra un movimento
Per l'alimentazione solare ho usato un modulo basato su CN3065 per la ricarica della LiPo con una LiPo da 2000 mAh ed un pannello solare da 0.5W. I cavi sono stati saldati sulla piastra invece su usare i connettori JST (per la batteria ed il pannello solare ci sono sia i connettori JST che le basi per saldare...per l'output su SYS ho collegato i cavi dietro al JST)
Le connessioni sono piuttosto semplici
ADXL345 : il pin di interrupt e' collegato a D8 di MKR. Gli altri cavi sono 3.3V, GND SDA ed SCL in modo standard
Un problema che e' stato riscontrato e' che l'interrupt 1 dell'ADXL345 passa da uno stato High ad uno Low mentre la MKR si aspetta l'esatto contrario per attivare l'interrupt
Per questo motivo il collegamento tra INT1 di ADXL345 e D8 di MKR1400 passa attraverso un circuito di logic inverter (in pratica una porta NOT) realizzato con un transistor 2n2222a
Sull'IN e' stato collegato INT1 di ADXL345 e su out D8 di MKR
Per la versione finale sara' usato l'integrato SN74HC04N, un integrato con 6 porte NOT a tensioni tra 2 e 6V
Il consumo in standby e' di circa 20 mA (mi aspettavo di meno...forse ho sbagliato qualcosa??)
mentre quando viene attivato il GSM e si invia l'SMS la corrente raggiunge un picco di circa 220 mA con valori stabili per una decina di secondi sopra i 100 mA
Questo e' lo sketch di funzionamento
----------------------------------------------------
#include "ArduinoLowPower.h"
#include <SparkFun_ADXL345.h>
#include <MKRGSM.h>
// Pin per wakeup
const int interruptPin = 8;
// GSM
GSM gsmAccess;
GSM_SMS sms;
ADXL345 adxl = ADXL345();
volatile int invia = 0;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(interruptPin, INPUT);
delay(5000);
adxl.powerOn();
adxl.setRangeSetting(2);
adxl.setInterruptLevelBit(1);
adxl.setSpiBit(0);
adxl.setActivityXYZ(1, 1, 1);
adxl.setActivityThreshold(50);
adxl.setTapDetectionOnXYZ(1, 1, 1);
adxl.setTapThreshold(50);
adxl.setTapDuration(55);
adxl.ActivityINT(1);
adxl.singleTapINT(1);
LowPower.attachInterruptWakeup(interruptPin, funzione, CHANGE);
}
void loop() {
if (invia == 1){
bool connected = false;
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
while (!connected) {
if (gsmAccess.begin() == GSM_READY) {
connected = true;
}
delay(1000);
sms.beginSMS("+393471xxxxxx");
sms.print("Luca mi ha toccato");
sms.endSMS();
invia = 0;
}
}
LowPower.sleep();
}
void funzione() {
invia = 1;
}
Per l'alimentazione solare ho usato un modulo basato su CN3065 per la ricarica della LiPo con una LiPo da 2000 mAh ed un pannello solare da 0.5W. I cavi sono stati saldati sulla piastra invece su usare i connettori JST (per la batteria ed il pannello solare ci sono sia i connettori JST che le basi per saldare...per l'output su SYS ho collegato i cavi dietro al JST)
Le connessioni sono piuttosto semplici
ADXL345 : il pin di interrupt e' collegato a D8 di MKR. Gli altri cavi sono 3.3V, GND SDA ed SCL in modo standard
Un problema che e' stato riscontrato e' che l'interrupt 1 dell'ADXL345 passa da uno stato High ad uno Low mentre la MKR si aspetta l'esatto contrario per attivare l'interrupt
Per questo motivo il collegamento tra INT1 di ADXL345 e D8 di MKR1400 passa attraverso un circuito di logic inverter (in pratica una porta NOT) realizzato con un transistor 2n2222a
Sull'IN e' stato collegato INT1 di ADXL345 e su out D8 di MKR
Circuito di prova...l'interrutore serve a simulare il cambio di stato del pin |
Il consumo in standby e' di circa 20 mA (mi aspettavo di meno...forse ho sbagliato qualcosa??)
mentre quando viene attivato il GSM e si invia l'SMS la corrente raggiunge un picco di circa 220 mA con valori stabili per una decina di secondi sopra i 100 mA
Questo e' lo sketch di funzionamento
----------------------------------------------------
#include "ArduinoLowPower.h"
#include <SparkFun_ADXL345.h>
#include <MKRGSM.h>
// Pin per wakeup
const int interruptPin = 8;
// GSM
GSM gsmAccess;
GSM_SMS sms;
ADXL345 adxl = ADXL345();
volatile int invia = 0;
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(interruptPin, INPUT);
delay(5000);
adxl.powerOn();
adxl.setRangeSetting(2);
adxl.setInterruptLevelBit(1);
adxl.setSpiBit(0);
adxl.setActivityXYZ(1, 1, 1);
adxl.setActivityThreshold(50);
adxl.setTapDetectionOnXYZ(1, 1, 1);
adxl.setTapThreshold(50);
adxl.setTapDuration(55);
adxl.ActivityINT(1);
adxl.singleTapINT(1);
LowPower.attachInterruptWakeup(interruptPin, funzione, CHANGE);
}
void loop() {
if (invia == 1){
bool connected = false;
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
while (!connected) {
if (gsmAccess.begin() == GSM_READY) {
connected = true;
}
delay(1000);
sms.beginSMS("+393471xxxxxx");
sms.print("Luca mi ha toccato");
sms.endSMS();
invia = 0;
}
}
LowPower.sleep();
}
void funzione() {
invia = 1;
}
Bare Metal C64 con Raspberry 3D Case
Sto giocando con BMC64 e, non volendo sacrificare un case di C64 funzionante, mi sono adattato con questo caso stampato in 3D
I colori sono quelli del VIC 20 ma va benissimo cosi'
I colori sono quelli del VIC 20 ma va benissimo cosi'
giovedì 14 marzo 2019
Regolatori di tensione per Arduino
Per provare un pannello solare con una batteria ho preso un regolatore di tensione (il pannello solare esce a circa 19 V mentre la batteria e' da 12 V
https://www.amazon.it/gp/product/B01EL9IG6K/ref=oh_aui_search_asin_title?ie=UTF8&psc=1
Per prova ho testato un LM317, un regolatore di tensione lineare. Il componente ha una Vdroput di 3V per cui se si applica una tensione di Vin di 12 V non potremo ottenere piu' di 9 V dal Vout
Per pilotare il componente si usano 2 resistenze
Per il calcolo della Vout si usa la formula
R2 = [(Vin/1.25)-1]* R1
Per esempio se si vuole ottenere una Vout di 5v data un R1 di 220 Ohm si dovra' impostare una R2 di 660 Ohm
Questi componenti non sono molto efficienti e dissipano la corrente in eccedenza come calore.
Prendendo una Arduino ed una sorgente di una batteria di 9V si ha che la potenza dissipata e' data da
W = (9-5)V*0.04A = 0.16W
E' necessario usare un dissipatore termico per valori superiori a 0.25W
usando il rapporto di 19°C/W si ha che l'integrato si riscalda di circa 3°C
Ma ha senso usare un regolatore di tensione esterno su Arduino Uno??
La Arduino Uno usa un regolatore di tensione LDO NCP1117ST50T3G che eroga una tensione fissa di 5V con un dropout di soli 1.2V ed una tensione di Vin di 20 V.
Il pannello solare eroga in piena insolazione 19.7 V.....e' molto al limite forse troppo (le tensioni consigliate per il regolatore di tensione sono 7-12V max 19V) ma in ogni caso e' integrato un circuito di protezione
Per prova ho testato un LM317, un regolatore di tensione lineare. Il componente ha una Vdroput di 3V per cui se si applica una tensione di Vin di 12 V non potremo ottenere piu' di 9 V dal Vout
Per pilotare il componente si usano 2 resistenze
Per il calcolo della Vout si usa la formula
R2 = [(Vin/1.25)-1]* R1
Per esempio se si vuole ottenere una Vout di 5v data un R1 di 220 Ohm si dovra' impostare una R2 di 660 Ohm
Questi componenti non sono molto efficienti e dissipano la corrente in eccedenza come calore.
Prendendo una Arduino ed una sorgente di una batteria di 9V si ha che la potenza dissipata e' data da
W = (9-5)V*0.04A = 0.16W
E' necessario usare un dissipatore termico per valori superiori a 0.25W
usando il rapporto di 19°C/W si ha che l'integrato si riscalda di circa 3°C
Regolatore tensione Arduino Uno |
Ma ha senso usare un regolatore di tensione esterno su Arduino Uno??
La Arduino Uno usa un regolatore di tensione LDO NCP1117ST50T3G che eroga una tensione fissa di 5V con un dropout di soli 1.2V ed una tensione di Vin di 20 V.
Il pannello solare eroga in piena insolazione 19.7 V.....e' molto al limite forse troppo (le tensioni consigliate per il regolatore di tensione sono 7-12V max 19V) ma in ogni caso e' integrato un circuito di protezione
Filtro Kalman e tempo di campionamento
Stavo continuando a provare questa libreria del filtro Kalman per MPU quanto, per risparmiare spazio su disco, ho provato a modificare il tempo di campionamento da 20 ms ad 1 secondo ed ' accaduto qualcosa che non mi aspettavo
Tempo di campionamento 1 sec
Nr campioni : 5085
Media : -0.35
Range : 7.44
Std : 0.21
Varianza : 0.044
Skewness : -14.8
Tempo di campionamento 0.02 sec
Nr campioni : 67889
Media : -0.35
Range : 0.33
Std : 0.0.37
Varianza : 0.0014
Skewness : -0.011
Come si vede il valore medio e' comparabile ma la standard deviation e' decisamente peggiore con il tempo di campioanmento di 1 secondo
Tempo di campionamento 1 sec
Nr campioni : 5085
Media : -0.35
Range : 7.44
Std : 0.21
Varianza : 0.044
Skewness : -14.8
Tempo di campionamento 0.02 sec
Nr campioni : 67889
Media : -0.35
Range : 0.33
Std : 0.0.37
Varianza : 0.0014
Skewness : -0.011
Come si vede il valore medio e' comparabile ma la standard deviation e' decisamente peggiore con il tempo di campioanmento di 1 secondo
Iscriviti a:
Post (Atom)
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...
-
In questo post viene indicato come creare uno scatterplot dinamico basato da dati ripresi da un file csv (nel dettaglio il file csv e' c...
-
Questo post e' a seguito di quanto gia' visto nella precedente prova Lo scopo e' sempre il solito: creare un sistema che permet...
-
La scheda ESP32-2432S028R monta un Esp Dev Module con uno schermo TFT a driver ILI9341 di 320x240 pixels 16 bit colore.Il sito di riferiment...