J'ai essayé d'utiliser les données de l'axe Z de SensorEvent.values, mais cela ne détecte pas la rotation de mon téléphone dans le plan XY, c'est-à-dire. autour de l'axe Z.
Je l'utilise comme référence pour les axes de coordonnées. Est-ce correct?
Comment mesurer ce mouvement à l'aide des valeurs de l'accéléromètre?
Ces jeux font quelque chose de similaire: Extreme Skater , Doodle Jump.
PS: l'orientation de mon téléphone sera paysage.
Essentiellement, il y a 2 cas ici: l'appareil repose à plat et non à plat. Plat signifie ici que l'angle entre la surface de l'écran de l'appareil et le plan mondial xy (je l'appelle l'inclinaison) est inférieur à 25 degrés ou supérieur à 155 degrés. Pensez au téléphone à plat ou inclinez-vous un peu sur une table.
Vous devez d'abord normaliser le vecteur accéléromètre.
C'est-à-dire si g est le vecteur renvoyé par les valeurs d'événement du capteur de l'accéléromètre. Dans du code
float[] g = new float[3];
g = event.values.clone();
double norm_Of_g = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2]);
// Normalize the accelerometer vector
g[0] = g[0] / norm_Of_g
g[1] = g[1] / norm_Of_g
g[2] = g[2] / norm_Of_g
Ensuite, l'inclinaison peut être calculée comme
int inclination = (int) Math.round(Math.toDegrees(Math.acos(g[2])));
Donc
if (inclination < 25 || inclination > 155)
{
// device is flat
}
else
{
// device is not flat
}
Dans le cas d'une pose à plat, vous devez utiliser une boussole pour voir la rotation de l'appareil par rapport à la position de départ.
Dans le cas de pas à plat, la rotation (inclinaison) est calculée comme suit
int rotation = (int) Math.round(Math.toDegrees(Math.atan2(g[0], g[1])));
Maintenant, la rotation = 0 signifie que l'appareil est en position normale. C'est portrait sans inclinaison pour la plupart des téléphones et probablement paysage pour tablette. Donc, si vous tenez un téléphone comme sur votre photo ci-dessus et commencez à tourner, la rotation changera et lorsque le téléphone sera en paysage, la rotation sera de 90 ou -90 dépend du sens de rotation.
L'accéléromètre est suffisant pour vérifier si le téléphone est plat comme Hoan l'a très bien démontré.
Pour tous ceux qui arrivent ici et qui cherchent non seulement à vérifier si le téléphone est plat, mais aussi à déterminer la rotation du téléphone, cela peut être obtenu grâce au Rotation Vector Motion Sensor .
private double pitch, tilt, azimuth;
@Override
public void onSensorChanged(SensorEvent event) {
//Get Rotation Vector Sensor Values
double[] g = convertFloatsToDoubles(event.values.clone());
//Normalise
double norm = Math.sqrt(g[0] * g[0] + g[1] * g[1] + g[2] * g[2] + g[3] * g[3]);
g[0] /= norm;
g[1] /= norm;
g[2] /= norm;
g[3] /= norm;
//Set values to commonly known quaternion letter representatives
double x = g[0];
double y = g[1];
double z = g[2];
double w = g[3];
//Calculate Pitch in degrees (-180 to 180)
double sinP = 2.0 * (w * x + y * z);
double cosP = 1.0 - 2.0 * (x * x + y * y);
pitch = Math.atan2(sinP, cosP) * (180 / Math.PI);
//Calculate Tilt in degrees (-90 to 90)
double sinT = 2.0 * (w * y - z * x);
if (Math.abs(sinT) >= 1)
tilt = Math.copySign(Math.PI / 2, sinT) * (180 / Math.PI);
else
tilt = Math.asin(sinT) * (180 / Math.PI);
//Calculate Azimuth in degrees (0 to 360; 0 = North, 90 = East, 180 = South, 270 = West)
double sinA = 2.0 * (w * z + x * y);
double cosA = 1.0 - 2.0 * (y * y + z * z);
azimuth = Math.atan2(sinA, cosA) * (180 / Math.PI);
}
private double[] convertFloatsToDoubles(float[] input)
{
if (input == null)
return null;
double[] output = new double[input.length];
for (int i = 0; i < input.length; i++)
output[i] = input[i];
return output;
}
Ensuite, pour vérifier si le téléphone est plat, vous pouvez simplement comparer les valeurs tilt
et pitch
avec des valeurs de tolérance. Par exemple
public boolean flatEnough(double degreeTolerance) {
return tilt <= degreeTolerance && tilt >= -degreeTolerance && pitch <= degreeTolerance && pitch >= -degreeTolerance;
}
L'avantage de le faire de cette façon est que vous pouvez vérifier si le téléphone est maintenu dans une rotation spécifique.
Il convient de noter que l'orientation de l'application n'affectera pas les valeurs de tangage, d'inclinaison et d'azimut.
Travailler sur la réponse parfaite de @Dan
Il a manqué un tout petit peu d'informations que @ davy307 a souligné.
Lors de l'initialisation du mAccéléromètre, vous devez le définir comme Sensor.TYPE_ROTATION_VECTOR sinon, il n'aura pas le 3ème vecteur de rotation et lèvera une exception ArrayIndexOutOfBounds.
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
Sinon, c'est une solution parfaite ... Appréciée!