稼働中

マイクロビット(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接続デバイスの使い方の練習にもなったと思います。