Компас в Android
Я пытаюсь запрограммировать компас с Android с помощью ускорителя и датчика магнитного поля, теперь мне интересно, как получить правильный угол для моего компаса.
Я читаю значения акселерометра и датчика магнитного поля в "accele" и "magne" соответственно. Чтобы получить угол, я выполняю следующее:
float R[] = new float[9];
float I[] = new float[9];
boolean success = SensorManager.getRotationMatrix(R, I, accele, magne);
if(success) {
float orientation[] = new float[3];
SensorManager.getOrientation(R, orientation);
azimuth = orientation[0]; // contains azimuth, pitch, roll
....
Позже, я использую матрицу вращения, чтобы поместить мою иглу:
rotation.setRotate(azimuth, compass.getWidth() / 2, compass.getHeight() / 2);
canvas.drawBitmap(needle, rotation, null);
Теперь в документации на getOrientation говорится, что ориентация [0] должна быть вращением вокруг оси z. В документации для TYPE_ORIENTATION говорится, что "азимут, угол между магнитным северным направлением и осью y, вокруг оси z (от 0 до 359). 0 = север, 90 = восток, 180 = юг, 270 = запад".
Мой азимут, однако, не находится между 0 и 359, а около -2 до 2. Что такое азимут от getOrientation и как его преобразовать под углом?
Ответы
Ответ 1
Используйте для преобразования из заданного азимута в радианах (-PI, +PI) в градусы (0, 360)
float azimuthInRadians = orientation[0];
float azimuthInDegress = (float)Math.toDegrees(azimuthInRadians);
if (azimuthInDegress < 0.0f) {
azimuthInDegress += 360.0f;
}
имена переменных, используемые для удобства ;-)
Ответ 2
Фрагмент кода можно получить из https://github.com/iutinvg/compass
Он не использует устаревшие вещи, применяет фильтр нижних частот.
Ответ 3
Я нашел это в google ApiDemos:
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.apis.graphics;
import android.app.Activity;
import android.content.Context;
import android.graphics.*;
import android.hardware.SensorListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.util.Config;
import android.util.Log;
import android.view.View;
public class Compass extends GraphicsActivity {
private static final String TAG = "Compass";
private SensorManager mSensorManager;
private SampleView mView;
private float[] mValues;
private final SensorListener mListener = new SensorListener() {
public void onSensorChanged(int sensor, float[] values) {
if (Config.LOGD) Log.d(TAG, "sensorChanged (" + values[0] + ", " + values[1] + ", " + values[2] + ")");
mValues = values;
if (mView != null) {
mView.invalidate();
}
}
public void onAccuracyChanged(int sensor, int accuracy) {
// TODO Auto-generated method stub
}
};
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mSensorManager = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
mView = new SampleView(this);
setContentView(mView);
}
@Override
protected void onResume()
{
if (Config.LOGD) Log.d(TAG, "onResume");
super.onResume();
mSensorManager.registerListener(mListener,
SensorManager.SENSOR_ORIENTATION,
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
if (Config.LOGD) Log.d(TAG, "onStop");
mSensorManager.unregisterListener(mListener);
super.onStop();
}
private class SampleView extends View {
private Paint mPaint = new Paint();
private Path mPath = new Path();
private boolean mAnimate;
private long mNextTime;
public SampleView(Context context) {
super(context);
// Construct a wedge-shaped path
mPath.moveTo(0, -50);
mPath.lineTo(-20, 60);
mPath.lineTo(0, 50);
mPath.lineTo(20, 60);
mPath.close();
}
@Override protected void onDraw(Canvas canvas) {
Paint paint = mPaint;
canvas.drawColor(Color.WHITE);
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
paint.setStyle(Paint.Style.FILL);
int w = canvas.getWidth();
int h = canvas.getHeight();
int cx = w / 2;
int cy = h / 2;
canvas.translate(cx, cy);
if (mValues != null) {
canvas.rotate(-mValues[0]);
}
canvas.drawPath(mPath, mPaint);
}
@Override
protected void onAttachedToWindow() {
mAnimate = true;
super.onAttachedToWindow();
}
@Override
protected void onDetachedFromWindow() {
mAnimate = false;
super.onDetachedFromWindow();
}
}
}
Как вы можете видеть, вы получаете степень от 0 до 360