AndroidStudioでkotlinを用いてコンパスを作成しようとしています。
サイトにを参考にしてアプリを作って実行してみました。
しかし最初から針が方位を示していない上に端末を動かすと針の向きが変わってしまいます。
スマホを右に回した場合、回した角度以上に針が右に回ります。その逆も然りです。
エラーなどは出ていないです。
使用している端末はAndroid7.1.1です。
使用しているAndroidStudioのバージョンは4.1.1です。
こちらのサイトを参考にしています。
Androidで動作する簡易方位磁針の作成
Androidに表示する画像を動的に回転させる
こちらがコードです。
kotlin
1import android.content.Context 2import android.graphics.Matrix 3import android.hardware.Sensor 4import android.hardware.SensorEvent 5import android.hardware.SensorEventListener 6import android.hardware.SensorManager 7import android.os.Bundle 8import android.os.Handler 9import android.util.Log 10import android.widget.ImageView 11import android.widget.TextView 12import androidx.appcompat.app.AppCompatActivity 13import java.text.SimpleDateFormat 14import java.util.* 15 16 17class MainAdventure : AppCompatActivity() { 18 19 /* 現在時刻と経過時間の表示に用いる変数 */ 20 lateinit var currentTime_TextView: TextView 21 lateinit var elapsedtime_time: TextView 22 private var cnt = 0 23 private val hnd0 = Handler() 24 /* コンパスの描画に用いる変数 */ 25 lateinit var mSensorManager: SensorManager 26 lateinit var mAccelerationSensor: Sensor 27 lateinit var mMagneticSensor: Sensor 28 lateinit var mSensorEventListener: SensorEventListener 29 private var mMagneticFieldflg = false 30 private var mAccelerationValue: FloatArray = FloatArray(3) 31 private var mMagneticFieldValue: FloatArray = FloatArray(3) 32 lateinit var compassNeedle_ImageView: ImageView 33 lateinit var tmpMatrix: Matrix 34 35 36 // 1000msごとに発生するハンドラー 37 val rnb0 = object : Runnable{ 38 override fun run() { 39 cnt++ 40 //現在時刻更新 41 if(cnt % 10 == 0){ 42 val d = Date() 43 val sdf = SimpleDateFormat("a hh:mm") 44 currentTime_TextView.text = sdf.format(d) 45 } 46 // 経過時間更新 47 elapsedtime_time.text = "経過時間:${cnt/3600}時間 ${(cnt%3600)/60}分 ${(cnt%60)}秒" 48 hnd0.postDelayed(this, 1000) 49 } 50 } 51 52 override fun onCreate(savedInstanceState: Bundle?) { 53 super.onCreate(savedInstanceState) 54 setContentView(R.layout.adventure_main) 55 56 val d = Date() 57 val sdf = SimpleDateFormat("a h時 m分") 58 59 /* 現在時刻と経過時間表示処理 */ 60 currentTime_TextView = findViewById(R.id.currentTime_TextView) 61 currentTime_TextView.text = sdf.format(d) 62 elapsedtime_time = findViewById(R.id.elapsedtime_time) 63 hnd0.post(rnb0) 64 65 /* コンパス針表示処理 */ 66 // 子Viewを追加したいLinearLayoutオブジェクトを取得する。 67 currentTime_TextView = findViewById(R.id.currentTime_TextView) 68 compassNeedle_ImageView = findViewById(R.id.compassneedle_ImageView) 69 tmpMatrix = compassNeedle_ImageView.imageMatrix 70 initializeSensor() 71 compassNeedle_ImageView.post(object : Runnable { 72 override fun run() { 73 compassNeedle_ImageView.scaleType = ImageView.ScaleType.MATRIX 74 } 75 }) 76 } 77 78 private fun initializeSensor() 79 { 80 mSensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager 81 mAccelerationSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) 82 mMagneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) 83 mSensorEventListener = MySensorEventListener() 84 } 85 86 inner class MySensorEventListener: SensorEventListener 87 { 88 override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) 89 { 90 // センサーの精度が変更されても何もしない 91 } 92 93 override fun onSensorChanged(event: SensorEvent?) 94 { 95 if(event != null) 96 { 97 when(event.sensor.type) 98 { 99 Sensor.TYPE_ACCELEROMETER -> { 100 if (event.values != null) { 101 this@MainAdventure.setAccelerationValue(event.values) 102 } 103 } 104 Sensor.TYPE_MAGNETIC_FIELD -> { 105 if (event.values != null) { 106 this@MainAdventure.setMagneticFieldValue(event.values) 107 this@MainAdventure.setMagneticFieldflg(true) 108 } 109 } 110 } 111 // 地磁気センサーの値を取得することができたら 112 if(this@MainAdventure.mMagneticFieldflg){ 113 // 方位を出すための変換行列 114 var rotate = FloatArray(16) 115 var inclination = FloatArray(16) 116 // 回転角 117 var orientation = FloatArray(3) 118 // 行列化 119 SensorManager.getRotationMatrix(rotate, inclination, 120 this@MainAdventure.mAccelerationValue, 121 this@MainAdventure.mMagneticFieldValue) 122 //回転角取得 123 SensorManager.getOrientation(rotate, orientation) 124 val doubleOrientation = (orientation[0]).toDouble() 125 val degreeDir = Math.toDegrees(doubleOrientation).toFloat() 126 127 Log.d("Sensor",degreeDir.toString()) 128 // ここでコンパスを描画 129 drawCompass(degreeDir) 130 } 131 } 132 } 133 } 134 135 /* MySensorEventListenerクラスで使う関数たち */ 136 private fun setAccelerationValue(accelerationValue: FloatArray) 137 { 138 mAccelerationValue = accelerationValue 139 } 140 private fun setMagneticFieldValue(magneticFieldValue: FloatArray) 141 { 142 mMagneticFieldValue = magneticFieldValue 143 } 144 private fun setMagneticFieldflg(magneticFieldflg: Boolean) 145 { 146 mMagneticFieldflg = magneticFieldflg 147 } 148 private fun drawCompass(degreeDir: Float) 149 { 150 tmpMatrix.reset() 151 // 角度分回転させる(ImageViewの中心で回転) 152 tmpMatrix.postRotate(degreeDir, compassNeedle_ImageView.width * 0.5f, compassNeedle_ImageView.height * 0.5f) 153 // 行列を適用 154 compassNeedle_ImageView.imageMatrix = tmpMatrix 155 compassNeedle_ImageView.invalidate() 156 } 157 158 159 /* 各センサーにイベントリスナーを登録する */ 160 override fun onResume() { 161 super.onResume() 162 setSensorEventListener() 163 } 164 private fun setSensorEventListener() 165 { 166 mSensorManager.registerListener( 167 mSensorEventListener, 168 mAccelerationSensor, 169 SensorManager.SENSOR_DELAY_NORMAL 170 ) 171 mSensorManager.registerListener( 172 mSensorEventListener, 173 mMagneticSensor, 174 SensorManager.SENSOR_DELAY_NORMAL 175 ) 176 } 177 178}
サイトにあるコードを入力して間違いがないか何度も確認はしています。
mMagneticFieldflgがtrueとなっているため地磁気センサーから値を取得することはできています。
MySensorEventListenerクラスで取得した角度の単位をそのままでdrawCompass関数で使用しているのが悪いのかと思ってpostRotateを調べましたがどちらもdegrees単位の角度なので問題はないはずです。
そのためやはりMySensorEventListenerクラスで取得している角度自体に問題があるのかと思いました。
しかし下記のコードを見てもセンサーについて疎い私には何が悪いのか分かりません。
kotlin
1// 地磁気センサーの値を取得することができたら 2 if(this@MainAdventure.mMagneticFieldflg){ 3 // 方位を出すための変換行列 4 var rotate = FloatArray(16) 5 var inclination = FloatArray(16) 6 // 回転角 7 var orientation = FloatArray(3) 8 // 行列化 9 SensorManager.getRotationMatrix(rotate, inclination, 10 this@MainAdventure.mAccelerationValue, 11 this@MainAdventure.mMagneticFieldValue) 12 //回転角取得 13 SensorManager.getOrientation(rotate, orientation) 14 val doubleOrientation = (orientation[0]).toDouble() 15 val degreeDir = Math.toDegrees(doubleOrientation).toFloat() 16 17 Log.d("Sensor",degreeDir.toString()) 18 // ここでコンパスを描画 19 drawCompass(degreeDir) 20 }
こちらがdegreeDirのログの一部になります。
Log
12021-10-19 13:34:53.399 5673-5673/com.example.adventurecompass D/Sensor: -163.80122 22021-10-19 13:34:53.513 5673-5673/com.example.adventurecompass D/Sensor: -163.66557 32021-10-19 13:34:53.600 5673-5673/com.example.adventurecompass D/Sensor: -166.42857 42021-10-19 13:34:53.670 5673-5673/com.example.adventurecompass D/Sensor: -166.5633 52021-10-19 13:34:53.924 5673-5673/com.example.adventurecompass D/Sensor: -161.92937 62021-10-19 13:34:54.081 5673-5673/com.example.adventurecompass D/Sensor: -161.9288 72021-10-19 13:34:54.104 5673-5673/com.example.adventurecompass D/Sensor: -164.62039 82021-10-19 13:34:54.238 5673-5673/com.example.adventurecompass D/Sensor: -164.62105 92021-10-19 13:34:54.305 5673-5673/com.example.adventurecompass D/Sensor: -163.4262 102021-10-19 13:34:54.396 5673-5673/com.example.adventurecompass D/Sensor: -163.42574
どうかご教授いただきたいです。
よろしくお願い致します。

回答1件
あなたの回答
tips
プレビュー