Rotazione schermo tramite accellerometro

Ciao a tutti,

utilizzo un accellerometro 9 assi LSM9DS1 e una display ST7735 160x60 il tutto gestito da un micro ESP32.

Vorrei riconoscere l'inclinazione e la rotazione dell'accellerometro in modo da poter ruotare lo schermo in maniera opportuna, in pratica come fanno i cellulari.

Sapete se ci sono già algoritmi che fanno già questo o librerie?

Grazie

Più che un accelerometro, credo che ti serva un giroscopio. Poi devi trasporre le coordinate del display quando scrivi, cancellando il display e riscrivendo tutto ogni volta che superi i 50° di rotazione rispetto al piano orizzontale (facendolo a 45° avresti instabilità nel punto di commutazione; così, invece, hai 10° in cui non può ricommutare).

Ciao,

esatto, l’LSM9DS1 può fare anche da giroscopio.

Spulciando in giro ho trovato queste formuline trigonometriche che sembrano convertire in gradi angolari le informazioni dell’accellerometro.

read_accelerometer();
float x = imu.calcAccel(imu.ax);
float y = imu.calcAccel(imu.ay);
float z = imu.calcAccel(imu.az);

float pitch, roll;
pitch = atan2(x, sqrt(y * y) + (z * z));
roll = atan2(y, sqrt(x * x) + (z * z));
pitch *= 180.0 / M_PI;
roll *= 180.0 / M_PI;

Giocandoci un pò riesco piu’ o meno a capire quando lo schermo ruota e di conseguenza lo re-inizializzo con la rotazione corretta e ridisegnando il quadro.

if ( pitch<= 35 && pitch >=-90 )  orientation = 0x01;
if ( roll<=-35 && roll >=-90 )	orientation = 0x04;

Per cercare di migliorarlo un pò ho anche aggiunto un timer che scatta non appena viene fatta una rotazione, in modo che per tot secondi non sia possibile rifarne un’altra subito dopo (credo che i cellulari appunto facciano un qualcosa di simile, in quanto subito dopo una rotazione lo schermo rimane fermo così per un pò o almeno la mia impressione é quella).
Il tutto funziona. Cercavo di capire se qualcuno ci aveva già sbattuto la testa e se esistevano librerie o algoritmi che già facevano considerazioni di questo tipo per limitare effetti di confine, cioè quando la rotazione è in bilico.
Grazie

Più che il ritardo, che trovo alquanto scomodo, metterei un'isteresi, ad esempio dall'orizzontale è necessaria una rotazione di 60° in senso orario per far ruotare il display di 90°; appena ciò avviene, è necessaria una rotazione antioraria di 30° per farlo tornare nello stato precedente. Prova anche altri valori. In questo modo, facendo una rotazione errata, ad esempio per un movimento del braccio, in un attimo si torna a quella desiderata, senza dover attendere alcun tempo.

Giustissimo.

Il progetto è per uno smartwatch, quindi si basa appunto sul mostrare data e ora a seconda dell'inclinazione del braccio.

E' solo per gioco, fatto in maniera un po' rudimentale, o che altro? :slight_smile:

Si, assolutamente hobby.

Qui il github del manufacturer

Come già detto é basato su ESP32 (quindi tutta la parte radio) , dotato di sensore di posizione e display 160x60.

Devo dire che per quello che l'ho pagato (mi pare sui 15USD) è veramente giocoso.
Unico vero limite é la gestione energetica.
Con sleep di micro, sensori e display la batteria da 100mAh dura non piu' di 20h.
Se si inizia a usare il BLE il calo é abbastanza drastico.

Carino. È la versione battery plus o quella standard?

Plus

Risolto cosi:

funzione che rileva il cambio dei fronti e ritorna ultimo valore dello stato

bool oldRetCode[2] = { false, false };

bool isteresi(int index,float value,float min,float max)
{

  bool retCode = false;
  if (value > max) {
    retCode = false;
  } else if ( value < min ) {
    retCode = true;
  } else {
    retCode = oldRetCode[index];
  }
  oldRetCode[index] = retCode;
  return retCode;
}

E dal loop principale:

	read_accelerometer();
	float x = imu.calcAccel(imu.ax);
	float y = imu.calcAccel(imu.ay);
	float z = imu.calcAccel(imu.az);


	  float pitch, roll;

	  pitch = atan2(x, sqrt(y * y) + (z * z));
	  roll = atan2(y, sqrt(x * x) + (z * z));
	  pitch *= 180.0 / M_PI;
	  roll *= 180.0 / M_PI;

	  Serial.print(pitch); Serial.print ("    ");    Serial.print(roll);  Serial.print("   ");
	  Serial.print(isteresi( 0, pitch, -45.0 , -55.0)); Serial.print ("   ");
	  Serial.print(isteresi( 1, roll,  -45.0 , -55.0));
	  Serial.println();
	  delay(100);

	  if (isteresi( 0, pitch, -45.0 , -55.0))
	  {
		  orientation = 0x01;
	  }

	  if ( isteresi(1, roll, -45.0,-55.0))
	  {
			orientation = 0x04;
	  }

Questo un esempio dell’output:

-0.71    -1.87   0   0
-0.68    -1.80   0   0
-0.76    -1.87   0   0
-0.88    -1.89   0   0
-0.78    -1.77   0   0
-0.80    -1.76   0   0
-0.72    -1.74   0   0
0.72    -0.66   0   0
0.02    -3.83   0   0
-9.82    -2.20   0   0
-15.85    -2.11   0   0
-19.77    -1.72   0   0
-29.21    -0.93   0   0
-35.65    -3.24   0   0
-39.82    -4.50   0   0
-41.88    -7.24   0   0
-52.40    -2.83   0   0
-57.96    -3.01   1   0
-62.27    -3.53   1   0
-64.81    -3.50   1   0
-73.50    -2.64   1   0
-84.93    -0.51   1   0
-82.45    -2.72   1   0
-80.32    -2.54   1   0
-78.58    -2.88   1   0
-77.44    -3.47   1   0
-74.35    -3.19   1   0
-76.86    -3.49   1   0
-78.39    -1.91   1   0
-68.12    -3.63   1   0
-53.67    -2.30   0   0
-35.25    -4.73   0   0
-24.05    -2.39   0   0
-11.27    -1.07   0   0
-9.84    -4.39   0   0
-8.05    -0.77   0   0
-4.73    -1.64   0   0
5.31    3.98   0   0
-0.99    1.74   0   0
-0.16    -0.85   0   0
0.35    -1.93   0   0
-1.11    -2.11   0   0
-0.78    -2.06   0   0
-0.82    -1.80   0   0
1.16    -1.89   0   0
-2.10    -0.34   0   0
-0.60    -0.96   0   0
-1.83    -1.71   0   0
-0.73    0.10   0   0
-2.55    -3.42   0   0
-0.25    -0.13   0   0
3.73    -12.90   0   0
-1.34    -22.65   0   0
0.65    -26.12   0   0
1.18    -24.09   0   0
1.59    -60.79   0   1
-15.61    -71.43   0   1
2.40    -86.89   0   1
2.96    -86.46   0   1
2.65    -86.79   0   1
2.53    -86.95   0   1
2.82    -86.62   0   1
3.05    -86.46   0   1
2.91    -86.51   0   1
2.69    -86.75   0   1
2.67    -86.77   0   1
2.87    -86.57   0   1
2.84    -86.57   0   1
2.88    -86.56   0   1
2.71    -86.75   0   1
1.62    -87.56   0   1
3.61    -84.99   0   1
2.50    -81.27   0   1
-0.28    -75.01   0   1
-4.49    -54.28   0   0
0.41    -34.59   0   0
1.34    -16.24   0   0
0.62    -9.85   0   0
0.97    14.78   0   0
-0.54    -0.75   0   0
-1.39    -2.59   0   0
-0.61    -1.66   0   0
-0.61    -1.56   0   0
-0.59    -1.75   0   0
-0.79    -1.72   0   0
-0.76    -1.72   0   0
-0.66    -1.36   0   0
-0.73    -1.29   0   0
-1.44    -1.82   0   0
-0.45    -2.06   0   0
-0.55    -2.22   0   0
-0.74    -1.80   0   0
-0.71    -1.74   0   0
-1.55    -1.44   0   0
-0.61    -1.52   0   0
-0.70    -1.66   0   0
-0.78    -1.49   0   0
-0.63    -1.71   0   0
-0.77    -1.76   0   0
-0.75    -1.74   0   0
-0.80    -1.81   0   0

Per valutare se devo re-inizializzare lo schermo:

if (prev_orientation != orientation)
{
		  prev_orientation = orientation;
		  init_display(orientation, ON);
		  elapsed_rotation_ms = millis();
}

:slight_smile: