venerdì 4 dicembre 2015

ADXL335 Accelerometro come tiltmetro

In questo post del 2012  avevo usato il componente CMPS10 per avere le indicazione di Yaw, Pitch e Roll.
Con il solo accelerometro (quindi senza una bussola) e' possibile tuttavia avere le informazioni di inclinazione dell'accelerometro in Pitch e Roll (Yaw non e' possibile perche' il calcolo richiede la scomposizione del vettore di accelerazione di gravita' e quindi la rotazione sul piano ortogonale al vettore gravita' non e' registrabile)



Sfruttando questo post ho provato a fare la stessa cosa con un ADXL335

Nel post e' peraltro interessante l'uso di un filtro passa basso.Agendo  sul parametro alpha si puo' ottenere un filtraggio meno (con numeri vicini a 1) o piu' aggressivi (con numeri dell'ordine di 0.1)
A sensore fermo la misura oscilla con filtro a 0.4 di circa +/- 1°
---------------------------------------------------------------------------
const float alpha = 0.5;

double fXg = 0;
double fYg = 0;
double fZg = 0;

double Xg = 0;
double Yg = 0;
double Zg = 0;


void setup()
{
    Serial.begin(9600);
    delay(100);
}

void loop()
{
    double pitch, roll, Xg, Yg, Zg;
    Xg = (analogRead(A5)*(5.0/1023.0))-1.59;
    Yg = (analogRead(A4)*(5.0/1023.0))-1.60;
    Zg = (analogRead(A3)*(5.0/1023.0))-1.67;

    Xg = 9.8*(Xg/0.33);
    Yg = 9.8*(Yg/0.33);
    Zg = 9.8*(Zg/0.33);
   
  
    //Low Pass Filter
    fXg = Xg * alpha + (fXg * (1.0 - alpha));
    fYg = Yg * alpha + (fYg * (1.0 - alpha));
    fZg = Zg * alpha + (fZg * (1.0 - alpha));

    //Roll & Pitch Equations
    roll  = (atan2(-fYg, fZg)*180.0)/M_PI;
    pitch = (atan2(fXg, sqrt(fYg*fYg + fZg*fZg))*180.0)/M_PI;

    Serial.print(pitch);
    Serial.print(":");
    Serial.println(roll);

    delay(100);
}

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

Pi Zero: ne vale la pena??

Grazie ad un amico che la ha acquistata il giorno di uscita, sono riuscito a mettere le mani su una Raspberry Pi Zero. Ma, a parte il prezzo di 5 dollari (la spedizione costa circa 6 volte di piu' che non l'oggetto) vale veramente la pena usare una Pi Zero al posto di una Raspberry B+ per esempio??


Il consumo del dispositivo e' decisamente inferiore ad un Raspberry B (110 mA contro circa il doppio della B...si e' bruciato il punto decimale del misuratore di corrente..si deve leggere 0.11 A)

Sul prezzo c'e' poco da dire, non esistono confronto se non con il futuro Chip (adesso in preordine).
Il problema che per usare una Pi Zero ci si deve munire di almeno un cavo microUsb-USB possibilmente OTG, un HUB Usb per attaccarci tastiera e mouse e un eventuale dongle Ethernet o Wifi (quindi forse e' meglio prendere un HUB alimentato), un non comunissimo cavo HDMI con un connettore standard ed uno in formato miniHDMI

In conclusione un sacco di cavi e cavetti sul tavolo che rendono inutili le dimensioni estremamente ridotte della Pi Zero (avessero messo almeno un Bluetooth ....). Puo' essere interessante come schedina da saldare in un progetto IOT (Internet of Things)... anche se per queste cose preferisco i microcontrollori al posto dei microprocessori ... ma come computer e' molto meglio la PI B+ (anche se molto piu' costosa)

Io nel frattempo ho fatto un preordine per CHIP..........




lunedì 30 novembre 2015

Maratona di Firenze 2015

6° Maratona....stesso sudicio
Anche quest'anno sono stato ripreso in foto andate su giornali on line (firenze.repubblica.it)




Integrazioni dati da accelerometro ADXL335/GY-61

Ho provato ad usare, su suggerimento di un amico, l'accelerometro come misuratore di spostamento.
In estrema sintesi integrando i dati di accelerazione si puo' avere una stima, seppure un po' grossolana, di quanto e' stato spostato il sensore (ovviamente se il sensore viene spostato con velocita' costante questo sistema non funziona)

Il sistema che ho usato e' una schedina GY-61 su cui e' montato un ADXL335 gia' usato altre volte nella versione Sparkfun


Il problema maggiore e' cercare di gestire il rumore dello strumento e la deriva (su quello orginale Sparkfun il modulo non mostra deriva mentre su questo modello cinese la deriva e' presente)

Questo e' lo script per la gestione del calcolo dello spostamento su due assi (x,y); l'asse z ha una sensibilita' differente a quella su x ed y e diventa difficile fare misure accurate

Per prima cosa viene convertito il valore delle porte analogiche in accelerazione in m/s2 togliendo l'offset per avere una misura piu'possibile vicina a zero in condizioni statiche
Successivamente viene integrata la velocita' ed in seguito lo spostamento (vedi questo link per una spiegazione piu' dettagliata)
L'integrazione avviene mediando il valore della accelerazione tra il valore attuale e quello precedente e moltiplicando per il delta di tempo (qui impostato a 0.05 secondi)
Succesivamente si passa allo spostamento sui due assi e calcolando quindi la risultante dello spostamento sui due assi

Il calcolo viene effettuato solo se viene superato un valore di trigger in modo da evitare di registrare tutto il rumore
ATTENZIONE : questo calcolo funziona solo per moti su superfici orizzontali. In caso contrario viene registrata anche una componente della accelerazione di gravita' per cui i dati sono falsati
--------------------------------------------------------------------------
unsigned long time, old_time;
int x,y,z;
float xx,yy,zz,ax,ay;
float old_ax,old_ay,old_vx,old_vy; //
float vx,vy,av_ax,av_ay,av_vx,av_vy; //valori medi di acc e vel sui due assi
float dx,dy,old_dx,old_dy; //spostamento
float delta_time;
float risultante;

void setup() {
  Serial.begin(115200);
  old_ax=0;
  old_ay=0;
  old_vx=0;
  old_vy=0;
  old_dx=0;
  old_dy=0;
  av_ax=0;
  av_ay=0;
  av_vx=0;
  av_vy=0;
}

void loop() {
  //z = analogRead(A3);
  y = analogRead(A4);
  x = analogRead(A5);
  //zz = z * (5.0 / 1023.0);
  yy = y * (5.0 / 1023.0)-1.67;
  xx = x * (5.0 / 1023.0)-1.61;
 
  ax = 9.8*(xx/0.33);
  ay = 9.8*(yy/0.33);

  //toglie offset
  ax = ax + 0.06;
  ay = ay + 0.68 ;
 
if ((ax-old_ax) > 0.3)
  {
  //time = millis();
  //delta_time = (time - old_time)/1000;
  delta_time = 0.05;
 
  //calcolo dell'accelerazione media
  av_ax = (ax+old_ax)/2;
  av_ay = (ay+old_ay)/2;

  //calcolo della velocita'
  vx = old_vx + (av_ax * delta_time);
  vy = old_vy + (av_ay * delta_time);

  // calcolo della velocita' media
  av_vx = (vx+old_vx)/2;
  av_vy = (vy+old_vy)/2;

  // spostamento
  dx = old_dx + (av_vx * delta_time);
  dy = old_dy + (av_vy * delta_time);

  // risultante
  risultante = sqrt((dx*dx)+(dy*dy));

  Serial.print(ax);
  Serial.print(";");
  Serial.print(ay);
  Serial.print(";");
  Serial.print(vx);
  Serial.print(";");
  Serial.print(vy);
  Serial.print(";");
  Serial.print(dx);
  Serial.print(";");
  Serial.print(dy);
  Serial.print(";");
  Serial.println(risultante);
  }

  delay(50);
  //old_time = time;

  //scambio delle variabili
  old_dx = dx;
  old_dy = dy;
  old_vx = vx;
  old_vy = vy;
  old_ax = ax;
  old_ay = ay;
}

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

giovedì 26 novembre 2015

Primi passi con Octave

Durante il dottorato ho avuto il modo di utilizzare (a livello decisamente base) Matlab apprezzandone la sintassi compatta. Purtroppo non ho piu' disponibilita' della licenza universitaria e quindi ho deciso di provare Octave, una versione open source simile a Matlab (anche se chi lavora in modo serio con Matlab mi dice che Octave e' ancora ad anni luce di distanze per alcune funzionalita')

L'aspetto interessante e' che con la versione 3.8 e' stata implementata una GUI simile a Matlab (prima si lavorava praticamente a linea di comando da shell)

Il programma e' stato compilato da sorgenti su Centos 6
Le dipendenze sono
yum install gcc gcc-c++ kernel-devel make mercurial libtool libtool-ltdl-devel libtool-ltdl autoconf cmake lapack-devel \ lapack pcre-devel readline-devel readline fftw-devel glpk-devel suitesparse suitesparse-devel gnuplot libcurl-devel zlib-devel \ flex texlive gperf fltk-devel qhull-devel hdf5-devel gl2ps-devel qrupdate-devel arpack-devel qscintilla-devel llvm-devel qt-devel \ bison ghostscript-devel librsvg2-tools icoutils readline pcre
Dopo la compilazione (un po' lunghina per la verita' ...ma la mia macchina e' un po' vecchiotta) si lancia il programma con

octave --force-gui



Questo e' uno script base su Octave che dovrebbe funzionare senza troppi problemi su Octave
----------------------------------------------------------------------------
clear all
close all
echo off

function rad = radians(degree)
    rad = degree .* pi / 180;
end;

function [a,c,dlat,dlon]=haversine(lat1,lon1,lat2,lon2)
    dlat = radians(lat2-lat1);
    dlon = radians(lon2-lon1);
    lat1 = radians(lat1);
    lat2 = radians(lat2);
    a = (sin(dlat./2)).^2 + cos(lat1) .* cos(lat2) .* (sin(dlon./2)).^2;
    c = 2 .* asin(sqrt(a));
    #arrayfun(@(x) printf("distance: %.8f m\n",6372800 * x), c);
end;

[volt,lat,lon,quota]=textread("tetto_6_11_ridotto.csv", "%u;%u;%u;%u");
mlat = mean(lat);
mlon = mean(lon);
minlat = min(lat);
maxlat = max(lat);
minlon = min(lon);
maxlon = max(lon);
stdlat = std(lat);
stdlon = std(lon);
[r,c] = size(lat);
fprintf("Media Lat: %d\n",mean(lat));
fprintf("Media Lon: %d\n",mean(lon));
fprintf("Std Lat: %d\n",std(lat));
fprintf("Std Lon: %d\n",std(lon));
fig = figure;
plot(lat,lon);
axis([minlat maxlat minlon maxlon]);
title('Originali')
print(fig,'gps','-dpng');
centro = centroid(lat,lon);
fprintf("Centroide %d %d\n",centro);
#plot(volt)
#print(fig,'volt','-dpng')
disp ("-----------------")
mlat = double(mlat)/10000000.0
mlon = double(mlon)/10000000.0
#fprintf("MLat: %f\n",mlat);

ripuliti = zeros(r,2);
indice = 1;

for n = 1:r
  #fprintf("MLat: %f\n",mlat);
  #fprintf("MLon: %f\n",mlon);
  #fprintf("Lat: %f\n",double(lat(n))/10000000.0);
  #fprintf("Lon: %f\n",double(lon(n))/10000000.0);
  [a,c,dlat,dlon] = haversine(mlat,mlon,double(lat(n))/10000000.0,double(lon(n))/10000000.0);
  #fprintf("Distanza %i :%f\n",n,double(c)*6378160.0);
  if (c*6378160.0) < 5.0
        ripuliti(indice,1) = double(lat(n))/10000000.0;
        ripuliti(indice,2) = double(lon(n))/10000000.0;
        indice = indice + 1;
        end
end

fig2 = figure;
plot(ripuliti(1:indice-1,1),ripuliti(1:indice-1,2))
axis([double(minlat)/10000000.0 double(maxlat)/10000000.0 double(minlon)/10000000.0 double(maxlon)/10000000.0]);
title("Filtrati")
mflat = mean(ripuliti(1:indice-1,1));
mflon = mean(ripuliti(1:indice-1,2));
devflat = std(ripuliti(1:indice-1,1));
devflon = std(ripuliti(1:indice-1,2));

fprintf("Media Filtrata Lat: %.7f\n",mflat);
fprintf("Media Filtrata Lon: %.7f\n",mflon);
fprintf("DevSt Filtrata Lat: %.7f\n",devflat);
fprintf("DevSt Filtrata Lon: %.7f\n",devflon);
----------------------------------------------------------------------------


Octave ha un corrispettivo dei toolbox di Matlab, ovvero di pacchetti di estensioni dei comandi che possono essere scaricati, a seconda delle necessita' da Octave Forge
Se per esempio si vuole leggere/scrivere una porta seriale si deve scaricare il pacchetto instrument control in formato tar.gz e si installa con il comando

pkg install instrument-control-0.2.1.tar.gz

Di seguito un semplice esempio per leggere i dati seriali (da Arduino). Per far utilizzare la porta seriale ad un normale utente, quest'ultimo deve essere aggiunto al gruppo dialout (adduser luca dialout)
----------------------------------------------------------------------------
#! /usr/local/bin/octave -qf
pkg load instrument-control
s1 = serial("/dev/ttyACM0");
srl_flush(s1);
get(s1);
set(s1,"baudrate",9600);
set(s1,"bytesize",8);
set(s1,"parity",'N');
set(s1,"stopbits",1);
get(s1);
while true
   valore = srl_read(s1,6);
   char(valore)
   pause(1);
endwhile
srl_close(s1)



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

Per quanto riguarda la connettivita' con i database la versione attuale si interfaccia solo con PostgreSql mediante il pacchetto database 

pkg install database-2.3.2.tar.gz
(deve essere installato il pacchetto devel di postgresql, esempio ripreso da qui. Prima di arrivare ad una connessioni con Postgres c'e' un post da smanettare con la configurazione del server, in particolare con il file pg_hba.conf)

----------------------------------------------------------------------------
pkg load database
conn = pq_connect (setdbopts ("dbname", "test")); 
pq_exec_params (conn, "create table testtable (t text, i int2, b bytea);") 
pq_exec_params (conn, "insert into testtable values ($1, $2, $3);", {"name1", 1, uint8([2, 4, 5])}) 
 pq_exec_params (conn, "select * from testtable;")
 pq_exec_params (conn, "drop table testtable;")
 pq_close (conn);
----------------------------------------------------------------------------


I programmi in Octave possono essere lanciati anche all'esterno dell'ambiente di sviluppo rendendo eseguibile il file .m ed inserendo il testa al file .m la riga
#!/usr/local/bin/octave -qf


Newrez su Centos 6

Un po' per pigrizia utilizzo lo script newrez (gia' descritto qui) per avere una risoluzione personalizzata su portatili un po' vecchiotti (1024x768 oramai e' un po' troppo riduttiva come risoluzione

Attualmente ho montato una Centos 6 su un ToughBook ed ho scoperto che lo script non funziona.
La cosa e' facilmente risolvibile eseguendo il comando xrandr
Newrez si aspetta di dover gestire LVDS1 e VGA1 mentre su Centos lo schermo del portatile viene chiamato LVDS-0

-------------------------------------------------------------------------
Screen 0: minimum 320 x 200, current 1600 x 1000, maximum 4096 x 4096
LVDS-0 connected 1600x1000+0+0 (normal left inverted right x axis y axis) 0mm x 0mm
   1024x768       60.0*+
   800x600        60.3     56.2 
   640x480        59.9 
VGA-0 disconnected (normal left inverted right x axis y axis)
   1600x1000      59.9 
TV-0 unknown connection (normal left inverted right x axis y axis)
   848x480        59.9 +
   640x480        59.9 +
   1024x768       59.9 
   800x600        59.9 
-----------------------------------------------------------------------------

basta modificare lo script e tutto torna a funzionare (certo che 1600x1000 su uno schermo da 10 pollici e' un po' troppo per gli occhi)
------------------------------------------------------------
#!/bin/bash

# newrez

# Marc Brumlik, Tailored Software Inc, tsi-inc@comcast.net

# up to v 0.8
# use 'xrandr' to scale video output to the display

# v 0.9
# Wed Jan  2 05:23:54 CST 2013
# rewrite to handle mouse boundaries when scaled (mouse confined)
# by setting requested resolution to the unused VGA-0 device
# then scaling that for display on the LVDS-0 device

# v 1.1
# Fri Dec 20 08:28:08 CST 2013
# fixed issue where setting to "default" after some other resulution
# left mouse-area at prior resolution

umask 000

# resolution can optionally be specified on command line
newrez=$1

# we MUST be running xrandr 1.3 or higher
if xrandr -v | grep "RandR version 1.[012]"
    then    zenity --info --title="XRandR version is too old" --text="You must be running Xrandr
version 1.3 or newer!
Time to upgrade your system  :-)"
        exit 0
fi

# find the currently connected devices, make a list
devices=`xrandr -q | grep connected | grep -v disconnected | cut -d"(" -f1`

# there MUST be a "connected" LVDS-0 and a "disconnected" VGA-0
current=`xrandr -q`

if echo "$current" | grep "LVDS-0 connected" >/dev/null
    then    : OK
    else    zenity --info --title="PROBLEM" --text="Current display must be LVDS-0"; exit 0
fi
if echo "$current" | grep "VGA-0 disconnected" >/dev/null
    then    : OK
    else    zenity --info --title="IMPORTANT" --text="The VGA-0 display resolution may be affected by this change"
fi

default=`echo "$current" | grep -A 1 "^LVDS-0" | tail -1 | awk '{print $1}'`
H=`echo $default | cut -d'x' -f1`
V=`echo $default | cut -d'x' -f2`
HZ=`echo $default | awk '{print $2}' | tr -d '[*+]'`

# echo DEFAULT: $default $H $V

if [ -z "$newrez" ]
    then    while true
        do
            newrez=`zenity --entry --title="Set New Resolution" \
                --text="Default Resolution: $default\n\nNew size (eg 1280x750 or 1450x1000)\n   -or- \"default\""` || exit 0
            case $newrez in
                default|[0-9]*x[0-9]*)    break ;;
            esac
        done
fi

case $newrez in
    default)    xrandr --output LVDS-0 --mode $default --scale 1x1
            xrandr --addmode VGA-0 $default
            xrandr --newmode $default $newmode
            xrandr --output VGA-0 --mode $default --scale 1x1
            exit 0 ;;
esac

newH=`echo $newrez | cut -d'x' -f1`
newV=`echo $newrez | cut -d'x' -f2`
modeline=`cvt $newH $newV $HZ | grep Modeline`
newmode=`echo "$modeline" | sed 's/^.*"//'`
cvtrez=`echo "$modeline" | sed -e 's/_.*//' -e 's/^.*"//'`

if [ "$newrez" != "$cvtrez" ]
    then    newrez=$cvtrez
        newH=`echo $newrez | cut -d'x' -f1`
        newV=`echo $newrez | cut -d'x' -f2`
fi

scaleH=`echo -e "scale=10\n$newH / $H\nquit" | bc`
scaleV=`echo -e "scale=10\n$newV / $V\nquit" | bc`

if echo "$current" | grep -A 100 "^VGA-0" | grep $newrez >/dev/null
    then    : already there
    else    xrandr --newmode "$newrez" $newmode
        xrandr --addmode VGA-0 $newrez
fi

if xrandr --output VGA-0 --mode $newrez --output LVDS-0 --fb $newrez --scale $scaleH"x"$scaleV 2>&1 | tee -a /tmp/xrandr.err
    then    : success
    else    zenity --info --title="Xrandr produced this error" --text="`cat /tmp/xrandr.err`"

The problem could be that Your video driver
does not support xrandr version 1.3
        rm -f /tmp/xrandr.err
fi

martedì 17 novembre 2015

Validazione MTK3339 (4)

Usando il punto geodetico visto qui, ho provato a testare l'MTK3339 in precisione (e non in accuratezza come negli esempi precedenti)


Effettuando circa 1100 misure Gps con MTK3339 il valore medio della posizione del ricevitore e' stata di
Lat : 43.833061N
Lon: 11.307075E



Confrontando con la posizione misurata con precisione nettamente superiore da IGM e Regione Toscana la distanza del punto misurato da MTK3339 si trova a circa 1.6 m dalla posizione geografica reale. Questo valore e' assolutamente in linea con le tolleranze del sensore


La nuvola dei punti e' stata estremamente ristretta perche' ciascuna singola coppia Lat/Lon e' ripetuta molte volte nel file di acquisizione

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