calcolo percentuale pendenza

Ciao, dopo molto tempo ho ripreso in mano l’arduino UNO che ho e ho deciso di farmi un computer home-made per la bicicletta.
Le funzioni sono le solite standard (velocità, distanza, tempo ecc.) però voglio avere la possibilità di visualizzare sullo schermo anche la pendenza della strada che sto percorrendo. Dunque come posso fare, utilizzando i valori dei 3 assi dell’accelerometro?
In questo momento l’accelerometro è collegato così:
SL → 3.3v
0g → non collegato
GS → GND
ST → GND
VCC → 3.3v

EDIT: ho dimenticato il codice che sto usando:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <math.h>

#define SCLK 7
#define DIN 6
#define DC 5
#define CS 4
#define RST 3

#define LM35_PIN A3

Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK, DIN, DC, CS, RST);

// Define the axis variables
int x = 0;
int y = 0;
int z = 0;

double angleYZ = 0;
double angleXZ = 0;

// Define values for LM35
int val;
float temp;

void setup()   {
  
  Serial.begin(9600);
  analogReference(EXTERNAL);   // HO COLLEGATO AREF AI 3.3V 

  // Initialize the LCD
  display.begin();
  display.setContrast(25);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  
}


void loop() {
  
  x = analogRead(0);
  y = analogRead(1);
  z = analogRead(2);
  
  x = map (x, 0, 1023, -511, 511);
  y = map (y, 0, 1023, -511, 511);
  z = map (z, 0, 1023, -511, 511);
  
  angleYZ = atan ((double) y / (double) z);
  angleYZ = angleYZ * 57,2958;
  
  angleXZ = atan ((double) x / (double) z);
  angleXZ = angleXZ * 57,2958;
  
  val = analogRead(LM35_PIN);
  temp = val * 0.322265625;
  
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("YZ = ");
  display.println(angleYZ);
  display.print("XZ = ");
  display.println(angleXZ);
  
  display.print("temp = ");
  display.println(temp);
  
  display.display();
  
  Serial.print("\nx: ");
  Serial.print(x);
  Serial.print("\ty: ");
  Serial.print(y);
  Serial.print("\tz: ");
  Serial.print(z);
  delay(100);  
  
  
  
}

dovrebbe bastare dividere la componente dell asse X per la componente dell asse Z e moltiplicarlo per 100.

Ciao Uwe

grazie per la risposta, con l'accelerometro in piano sulla scrivania ho i seguenti valori:
x = 497
y = 555
z = 680
purtroppo non sono stabili ma continuano a variare ad ogni lettura rimanendo comunque in un range ristretto.
Ora se faccio come mi hai consigliato ottengo:
Angolo YZ = 555/680 * 100 = 81.61 %
sicuro che sia giusto? devo per caso calibrare l'accelerometro nel setup() ? se si come?

Che modello di accelerometro hai? devi sotrarre forse l' offset?
Ciao Uwe

giusto, mi sono scordato di metterlo, è l' MMA7361.

ho trovato un altro codice che mi convince di più per il calcolo, però non capisco perchè sull'asse y che dovrebbe essere il mio "pitch" ho 350 gradi, non dovrebbe essere 0?
stessa cosa per l'asse x che è a 13 gradi quando mi aspetterei un valore prossimo allo 0...

void getAngles()
{
value_x = analogRead(X_PIN);
value_y = analogRead(Y_PIN);
value_z = analogRead(Z_PIN);

xv=(value_x / 1024.0 * ADC_ref - zero_x) / sensitivity_x;
Serial.print ("x= ");
Serial.print (xv);
Serial.print(" g ");

yv=(value_y / 1024.0 * ADC_ref - zero_y) / sensitivity_y;
Serial.print ("y= ");
Serial.print (yv);
Serial.print(" g ");

zv=(value_z / 1024.0 * ADC_ref - zero_z) / sensitivity_z;
Serial.print ("z= ");
Serial.print (zv);
Serial.print(" g ");
Serial.print("\n");

Serial.print("Rotation ");

Serial.print("x= ");
angle_x =atan2(-yv,-zv)*57.2957795+180;
Serial.print(angle_x);
Serial.print(" deg");
Serial.print(" ");

Serial.print("y= ");
angle_y =atan2(-xv,-zv)*57.2957795+180;
Serial.print(angle_y);
Serial.print(" deg");
Serial.print(" ");

Serial.print("z= ");
angle_z =atan2(-yv,-xv)*57.2957795+180;
Serial.print(angle_z);
Serial.print(" deg");
Serial.print("\n");

}

EDIT: ho capito che dovrebbe essere questione d aggiustare lo zero dei valori, magari fare anche la media di una decina di letture.

Ma volevi l’ angolo o la pendenza in %?

Il sensore ha un offset di ca 1,65V a una tensione di alimentazione di 3,3V (in pratica VDD/2)
Devi ricavare il valore di accelarazione sottraendo l’offset.

Ciao Uwe

a me interessa sapere la percentuale %, ma credo sia collegata all'angolo (forse mi sbaglio).
in ogni caso con quel codice ottengo prima i "g" per ogni asse, e da quelli calcolo l'angolo in °.
ora avendo l'angolo posso calcolare la % con la formula (wikipedia)
m% = 100 * tan(angolo)
così dovrebbe andare giusto?

La percentuale é calcolata dal dislivello fratto distanza (non lunghezza della strada, ma la sua proiezione sulla orizontale) Questi 2 valori li hai dati gia da accelerometro misurando l' accelerazione terrestre e non ti servono funzioni di trigonometria.

Ciao Uwe

intendi che dovrei fare il rapporto tra i valori delle forze g sugli assi x e y? ed è finita li?
m% = 100 * (delta_gY / delta_gX)

EDIT: Ho risolto, ho usato una libreria che ho trovato sul playground e mi sono accorto che la funzione tangente vuole i valori in radianti e non in gradi, per quello mi venivano numeri strani nei conti posto il mio codice finale:

#include <SPI.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <math.h>
#include <AcceleroMMA7361.h>

#define SCLK 7
#define DIN 6
#define DC 5
#define CS 4
#define RST 3

#define LM35_PIN A3

#define X_PIN A0
#define Y_PIN A1
#define Z_PIN A2

Adafruit_PCD8544 display = Adafruit_PCD8544(SCLK, DIN, DC, CS, RST);
 
float angle_x;
float angle_y;
float angle_z;

float per_x;
float per_y;
float per_z;

AcceleroMMA7361 accelero;

int x;
int y;
int z;

// Define values for LM35
int val = 0;
float temp;

void setup()   {
  
  Serial.begin(9600);
  analogReference(EXTERNAL);

  // Initialize the LCD
  display.begin();
  display.setContrast(25);
  display.setTextSize(1);
  display.setTextColor(BLACK);
  
  accelero.begin(13, 12, 11, 10, X_PIN, Y_PIN, Z_PIN);
  accelero.setARefVoltage(3.3);                   //sets the AREF voltage to 3.3V
  accelero.setSensitivity(HIGH);                   // HIGH sets the sensitivity to +/-1.5G, LOW to +/-6G
  accelero.calibrate();
  
  
}

void loop() {
  
  getTemp();
  
  y = accelero.getYAccel();
  
  angle_y = y * 1.11 * PI/180; // in radianti: 100 = 1g => 100 / 90° = 1.11
  per_y = 100 * tan(angle_y);
  
  display.clearDisplay();
  display.setCursor(0,0);
  display.print("% = ");
  display.println(per_y);
  display.print("t = ");
  display.println(temp);
  display.display();
  
  
  delay(500);  
  
}

void getTemp()
{
  val = analogRead(LM35_PIN);
  temp = val * 0.322265625;
}

cavde:
intendi che dovrei fare il rapporto tra i valori delle forze g sugli assi x e y? ed è finita li?
m% = 100 * (delta_gY / delta_gX)

siccuramerte non perché devi considrare X e Z.

per il resto sembra che mi sono sbaglaito io.
Ciao Uwe

nn state tenedo conto delle accelerazioni. funziona a banco, ma non nella realtà, altrimenti non servirebbero le IMU e MARG :smiley:

Ciao! Anche io sto progettando un mini computer per bicicletta quindi ti seguo :smiley:

Avevo letto questo pdf (http://aitendo3.sakura.ne.jp/aitendo_data/product_img/sensor/MMA7260Q/MMA7260QT_AN3107.pdf), che forse ti può aiutare.
In pratica dice di calcolare l'angolo di inclinazione (in gradi) così: angolo = arcsin [(Vout - Voffset)/Sensibilità] .
Dove nel tuo caso Voffest è 1650mV e la sensibilità è 800mV/g (se il piedini g-select è a massa, altrimenti è 206mV/g).
Poi per la pendenza percentuale in teoria basta fare: pendenza% = 100*tan(angolo).
Sinceramente non ci capisco molto quindi spero di non dire cavolate :sweat_smile: :sweat_smile:

Comunque, io nel mio avevo pensato di mettere questo sensore di pressione (http://it.farnell.com/freescale-semiconductor/mpl3115a2/sensore-pressione-20-110kpa-8lga/dp/2009084).
Oltre a misurare pressione e temperatura, lo avrei usato per calcolare l'altitudine. Dicono che sia molto preciso per il calcolo dell'altitudine (relativa). Lo dico perchè la maggior parte dei computerini da bici, per calcolare la pendenza, misurano rapporto tra il dislivello (misurato con un sensore di pressione) e la distanza (misurata con il classico sensore sulla ruota) in un certo periodo di tempo (in realtà bisogna calcolare la proiezione sull'orizzontale come diceva uwefed, ma non è un problema). La pendenza si aggiorna un po' lentamente, e da fermi non la calcola, ma potrebbe essere un modo alternativo all'accelerometro.

Ciao! :slight_smile:

Ah, come si fa a restringere un link in una parola sola? Così evito di scrivere link stratosferici :blush:

EDIT: Non avevo letto che avevi risolto lol

grazie per l'aiuto, praticamente il metodo che usi tu è giusto, a me non funzionava perchè nell'ultimo calcolo in cui usi la funzione tan() gli passavo l'angolo in gradi, quando invece lo vuole in radianti, quindi occhio a non fare il mio stesso errore :smiley:
in ogni caso, la libreria che sto usando fa lo stesso calcolo e in più fa la media di n letture, il tutto in modo trasparente, quindi è comoda.
La libreria ritorna un valore che è 100 se l'accelerazione è 1G, quindi moltiplico per 1,11 (= 100 / 90) e ottengo i gradi, dato che quando ho 1G sono a 90 gradi. Poi trasformo in radianti (PI/180) e posso calcolarmi la pendenza in percentuale.
Ora quello che mi interessa è l'intervento di 'lesto'. Quello che ho capito è che se si è in movimento si è sottoposti ad altre accelerazioni, oltre a quella dovuta alla forza gravitazionale, quindi le misurazioni dell'accelerometro andrebbero corrette. ma come? Approfondisci il discorso!!! :smiley:

EDIT: @Davide311, se ti va, dato che abbiamo un progetto in comune possiamo tenere aggiornato questo thread con eventuali domande o dubbi e se mai riusciamo ad arrivare alla fine del progetto facciamo un post nella sezione megatopic mettendo insieme il tutto

vano corrette usando gl stessi algoritmi che quadricotteri e simili usano.

filtro Kallman e DCM sono i 2 metodi più usati, in entrambi i casi come minimo serve un giroscopio. Eventualmente anche un magnetometro aumenta la qualità delle letture.

se vai sul mio github (lestofante) trovi l'implementazione DCM presa (e sistemata) dalla freeIMU, che ha il vantaggio che a partità di potenza di calcolo dà migliori risultati del Kallman e richiede molte meno risorse, ma ha lo svantaggio che non può essere migliorata più di tanto, mentre il kallman è aperto a millemila migliorameni

edit: come non detto, non ho caricato il codice "pulito", ma trovi un vecchio codice quì: arduinoSketch/QuadricotteroCompleto/stabilization at master · lestofante/arduinoSketch · GitHub

quindi non c'è speranza di utilizzare solo l'accelerometro per il calcolo della pendenza?
Avendo la velocità e quindi anche l'accelerazione ad ogni istante, non è possibile correggere (facendo un compromesso in termini di precisione) i dati dell'accelerometro?
L'unico giroscopio che ho a casa è quello del telecomando WII che avevo usato nella prima versione del quadricottero...

se hai la velocità ad istante X (v1) e velocità ad istante X+t (v2) puoi fare la derivata ed ottenere l'accelerazione:

(v2-v1)/T = A

dimensionalmente stiamo facendo: (sempre fare i conti dimensionalemente, vi accorgete subito se fate cagate sopratutto in fisica dove le dimensioni finali sono facili da ricordare)
(m/s - m/s)/s = m/s^2

ora prendiamo il valore dell'accelerometro che do per scontato essere già trasformata in accelerazione (quidi sempre in m/s^2) grazie al valore di conversione dato dal datasheet (oppure se il chip è "intelligente" fa la conversione da solo)

Ora, dano per scontato che l'asse avanti/indietro della bicicletta (parallelo al terreno e verso di marcia) sia la Y

fai Y-A = Yc

dove Yc è "accelerazione Y corretta". A questo punto, se hai un acceleromentro 3 assi, per controllare che tutto sia corretto misuri la lunghezza del vettore gravità rilevato dall'accelerometro al netto delle accelerazioni (G = sqrt(xx+YcYx+Z*Z)) e vericgichi che sia il più SIMILE possibile al valore di 1G (sempre ricavabile da datasheet, oppure facendo questa misurazione da acceleromentro fermo, una buona idea è ad inizio fare una calibrazione da fermo e verificare sia simile al valore da datasheet, ma poi usare il valore calibrato, ovviamente)

Per evitare la SQRT che è lenta, puoi semplicemente memorizzare G*G (9.8m/s^2 *2 = 19.6m/s^2), tra l'altro usando una costante così risparmi anche RAM. Il fatto di non eseguire la SQRT se non indispensabile è un trucchetto molto usato anche dai videogiochi :slight_smile:

ecco era proprio quello che volevo sentire :smiley:
dunque i passaggi dovrebbero essere questi:

  • accensione: calcolo il modulo del vettore G da fermo oppure uso la costante.
  • ad ogni passaggio del sensore sullo switch reed:
  • calcolo la velocità
  • calcolo l'accelerazione avendo la nuova velocità, quella vecchia e l'intervallo di tempo
  • correggo il valore dell'asse Y dell'accelerometro con l'accelerazione calcolata
  • (facoltativo) calcolo il modulo del vettore G usando la Y corretta e confronto col valore calcolato all'inizio
  • calcolo la pendenza avendo la Y corretta.

Ora mi viene in mente un'altro "problema": Mettiamo che una volta finito tutto il progetto io avrò il mio PCB con tutti i componenti saldati. Lo monto sulla bici e mi accorgo che l'accelerometro non è perfettamente orizzontale. E' possibile spostare lo zero dell'accelerometro in modo da regolarlo in base a come è montato? basta salvarsi il valore letto all'accensione e toglierlo in tutte le altre letture?

ahhh cavolo, no, non va bene neanche così, quando sei in curva entrano in gioco le accelerazioni centripede e ti sballano tutto lunglo l'asse "Z" (detra-sinitra, per intenderci).

Visto che a questo punto intercettare la velocità angolare (anzi, l'accelerazione) diventa complesso, conviene usare il metodo del modulo G per escludere queste misure.

l'asse dell'acceleromentro DEVE essere permettamente parallelo al verso di marcia, altrimenti tutti i conti che ho fatto vanno a pallino, e devi conoscere anche l'asse X (su giù), e devi trasposrtare la lettura X e Y da sistema di rifermiento dell'accelerometro a sitema di riferimento della bici; per questo stesso motivo l'acceleromentro va installato nel centro di massa (o baricentro) della bici! (se cerchi "rototraslazione sistema di riferimento troverai tanti bei testi ed esempi di "fisica 1", oppure chiedi a qualche ingeniere -che faccia VERA ingenieria (pun intended)-)

quindi ricapitolando è OBBLIGATORIO fare il calcolo del vettore gravità post-correzione e verificare che sia in range e che l'asse "Z" destra-sinistra sia ~zero (oppure bisogna escludere le curve a mano). A questo punto puoi usare la tangente. Se avessi un modo per avere anche la accelerazione angolare, puoi ricavare il vettore 3d di accelerazione G, il quale può essere "smontato"

ATTENZIONE: DERIVARE ed INTEGRARE in realtà lascia sempre un fattore "+c" che rappresenta l'errore di integrazione; esso è stimabile, però sta di fatto che avrai sempre un errore, ad ogni lettura, e quindi questo errore si accumula piano piano (quanto piano dipende da qualità dell'algoritmo, dei filtri, del sensore, etc..)

Con una IMU o una MARG puoi avere sicurezza sulla ROTAZIONE assoluta nello spazio rispetto al centro della terra; MA non la tua TRASLAZIONE. Per questo si usa GPS e barometri! essi danno misurazioni ASSOLUTE ma purtroppo soggette a grande errore.

Insomma, o hai un valore ASSOLUTO da GPS e baromentro che può cannare di tanto, ma all'interno di una certo limite, OPPURE hai un valore RELATIVO che può essere più preciso all'inizio, ma su un tempo lungo l'errore aumenta all'infinito. OPPURE, quello che fanno le sensor fuuzion, è "agganciare" i dati con complicati algoritmi (appunto DCM e Kallman per esempio) ed ottenere uan via di mezzo tra i due metodi.

Che mal di testa per misurare uno stupido angolo, vero? :smiley:

eh hai ragione, inoltre pedalando, la bici continua a oscillare, soprattutto in salita...ci vorrebbe un trucchetto smart per evitare tutte ste cose e approssimare la pendenza usando altre informazioni xD
è anche vero che non devo progettare il sistema di guida di un F35, quindi potrei fregarmene del fatto che in curva le letture sono sballate.
si potrebbe fare una cosa del genere (???): tengo solo le letture dell'asse Y che sono contemporanee ad una lettura dell'asse X in cui è piano (cioè uguale alla lettura di calibrazione iniziale). Quindi le letture in cui la bici è inclinata sono scartate...

EDIT: ah non ho visto la modifica del post

EDIT2: si mi serve altro paracetamolo