マイクロビット(e_12)MAG3110 地磁気センサー(2)
MAG3110 (I2C) 地磁気センサー(2)
前回からの続きになります。micro:bitに実装されているI2Cデバイスの地磁気センサーMAG3110(Tree-Axis Digital Magnetometer)の校正を行い、方位角を計算してみます。
3.MAG3110の補正値を得る
下図のように地磁気センサーの減点からずれていると補正が必要らしいです。
3-1.回転させデータを取集
前回のスクリプトを改良してmicro:bitを回転させデータを取集して補正値を調べます。
for文で回しているだけです。計算はx,y,zの3つとし、不要な表示はコメントアウトして最後の結果だけにしました。
from microbit import *
#fugoutuki keisan no kannsuu
def s_comp(value):
# value '0b_1111_1111_1111_1111' no form
# '0b'wo nozoku
a = value[2:]
b_dat = '0'*(16-len(a)) + a
conv_value = -int(b_dat[0]) << 15 | int(b_dat,2)
return conv_value
# MAG3110 ID=0x0E(14)
addr=14
n=0
for i in range(500):
i2c.write(addr, b'\x01') # b'\x01'のレジスタから
b_data=i2c.read(addr,6) # 6バイト(6個)HL no x,y,z register read
l_data=list(b_data)
#print(l_data)
#print( 'x_MSB,X_LSB=', hex(l_data[0]), hex(l_data[1]) )
#MSB 8bitshift 8bit_Hi+8bit_Low to onazi 16ビットデータにする
x_data= int(l_data[0]) << 8 | int(l_data[1])
y_data= int(l_data[2]) << 8 | int(l_data[3])
z_data= int(l_data[4]) << 8 | int(l_data[5])
#print('x_data (int, hex, bin)',x_data,hex(x_data),bin(x_data))
x_mes=bin(x_data) # 2の補数関数に送るためbinデータにする
y_mes=bin(y_data)
z_mes=bin(z_data)
#16bit fugou tuki keisan he
x_hole = s_comp(x_mes) #関数に送る
y_hole = s_comp(y_mes)
z_hole = s_comp(z_mes)
#print('out_X(hex,int)=', hex(x_hole), x_hole)
print (i, x_hole, y_hole, z_hole) #x,y,zのデータを表示
sleep(250)
n=n+1
if n>150: #150個データでブレーク
break
3-2.測定データ
左から番号、x,y,zのデータです。150個のデータをテキストにコピペしてファイルにしました。
さらにExcelなどでcvsファイル化して150個のデータを散布図にしました。補正の式は大雑把にPx=X+1475、Py=Y-1750としました。(原点に戻す値)
しかしながら、先のデータ(-1256)にPxを加算しても整合しませんでした。
out_X(hex,int)= -0x4e8 -1256 # x軸の符号付きデータ
get_x(hex,int)= -0x4ed8 -20184 # get_x関数で取得したデータ
4.方位の計算
レジスタからのデータとget_x()の値は違いましたがそのまま方位の計算をします。今までのスクリプトつなぎ合わせて、compass.heading()で得た値と比較しました。
上手くいかなかったので結果の1例だけを下に記載します。
>>> %Run 1014_mag_3110_reg_calc-NG.py
calc_deg1 = 324.537 # 補正なし
calc_deg2 = 105.147 # (x_hole+1500,y_hole-1750)補正あり
heading = 278 # compass.heading()の方位
4-1. 見直し
原因を調べてみました。
補正値を代入した状態で計算の場合分けをしないでデータだけ調べました。
符号付きのデータを得たのちの部分だけ記載しています。for文にして、micro:bitを360°机の上でゆっくり回転しながら50個のデータをとりました。
hdeg:compass.heading()の値
ndeg:レジスタデータに補正値を加味して計算した角度
ath :レジスタから得た磁気強度から計算したatanΘ
ax :レジスタから得たx軸の磁気強度
ay :レジスタから得たy軸の磁気強度
コピペしてメモ帳などに貼り付けてファイル保管した後にExcel などで表計算します。
各データをhdeg:compass.headingをx軸にして散布図にしました。以下のような結果となりました。なんとなくデータはしっかり採れているようです。
本来は、ndeg(レジスタデータから計算した角度)とcompass.headingが同じになるハズです。傾きも逆になっています。なので少なくても-ndegの形になりそうです。よく考えると90-ndeg、270-ndegにすれば良さそうです。その場合分けをどうするか・・ちょうどaxの正負で対応しているのが分かります。
したがって、
ax <= 0 方位角=90-ndeg、a x> 0 方位角=270-ndeg
で良さそうです。
さらに、ここでax、ayのグラフをみると上下がやや均等ではありません。たぶん、上下均等にするには補正値をさらに修正すれば良さそうです。axの場合(340-250)/2=45を補正値(1500)から引けば良いようです。同様にayは(250-350)/2=-50を補正値(-1750)から引きました。
よって各補正値を(x_hole+1455, y_hole-1700)にすれば良さそうです。
4-2.再計算
For文を除いて全部をまとめました。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from microbit import *
import math
#符号付きビットの計算
def s_comp(value):
# value '0b_1111_1111_1111_1111' no form
# '0b'wo nozoku
a = value[2:]
b_dat = '0'*(16-len(a)) + a
conv_value = -int(b_dat[0]) << 15 | int(b_dat,2)
return conv_value
# MAG3110 のID=0x0E(14)
addr=14
#compass.headingの角度
hdeg=compass.heading()
#print ('heading = ', hdeg)
sleep(100)
# b'\x01'のレジスタから
i2c.write(addr, b'\x01')
sleep(100)
# 6バイト(6個)HL no x,y,z register を読み取る
b_data=i2c.read(addr,6)
#データのリスト化
l_data=list(b_data)
#print(l_data)
#print( 'x_MSB,X_LSB=', hex(l_data[0]), hex(l_data[1]) )
#MSB 8bitshift 8bit_Hi+8bit_Low to onazi 16ビットデータにする
x_data= int(l_data[0]) << 8 | int(l_data[1])
y_data= int(l_data[2]) << 8 | int(l_data[3])
z_data= int(l_data[4]) << 8 | int(l_data[5])
#print('x_data (int, hex, bin)',x_data,hex(x_data),bin(x_data))
#2の補数関数に送るためbinデータにする
x_mes=bin(x_data)
y_mes=bin(y_data)
z_mes=bin(z_data)
#16bit 符号付き計算の関数に
x_hole = s_comp(x_mes)
y_hole = s_comp(y_mes)
z_hole = s_comp(z_mes)
#符号付き各レジスタのデータ x,y,z軸の磁気強度データ
#print (x_hole, y_hole, z_hole)
#hosei data x_hole+1500, y_hole-1750 概算値
ax=x_hole+1455
ay=y_hole-1700
#角度計算
try:
xx = (ay)/(ax)
except ZeroDivisionError:
xx = 0
ath = math.atan(xx)
ndeg= math.degrees(ath)
# 方位角計算の場合分け
if ax <= 0:
rdeg= 90 - ndeg
else:
rdeg= 270 - ndeg
#micro:bitのコンパスの方位角、M3110レジスタデータからの方位角
print('heading =', hdeg)
print('reg_deg =', rdeg)
実行結果です。
>>> %Run 1016_mag_reg_deg_b.py
heading = 12
reg_deg = 13.3517
>>> %Run 1016_mag_reg_deg_b.py
heading = 276
reg_deg = 277.301
ピッタリでは無いですが、headingの方位角とレジスタデータからの方位角がほぼ同じになりました。地磁気センサーのMA3110のレジスタデータから方位角が算出できたと思います。
まとめ
micro:bitに実装されているI2C接続のMAG3110地磁気センサー(Tree-Axis Digital Magnetometer)の直接的な使い方について記載しました。
BBC:Micropythonのcompass.heading()で簡単に得られますが、compass.get_x()、compass.get_y()からも算出し確認しました。
さらにレジスタからデータを取り出し方位角を求めました。I2C接続デバイスの使い方の練習にもなったと思います。