I2C 接続の 3 軸電子コンパス センサ モジュールを入手できたので、RaspberryPi に接続して実験してみました。センサの周囲に磁石などがなければ地磁気から南北を計測できるので、例えば、ロボットに搭載することで、ロボットの向いている方角や傾きを知ることができます。また、磁石や鉄板などをセンサに近づけると計測値が変化することを利用して、簡易的な金属探知機のようなガジェットを作ることもできそうです。
センサ モジュールとしては各社から様々なバリエーションが発売されているようですが、私が Amazon.co.jp で購入したものには、基盤に CJ-M49 のプリントがあり、3.3V のレギュレータを搭載して、5V 電源でも使えるものでした。何れもセンサの核心部分は同じ HMC5883L であるため、だいたい使い方は同じと思います。eBay では、一つ 250 円くらいから販売があります。
RaspberryPi とは I2C で接続でき、I2C で必要な 3 本とは別に電源が必要で、計 4 本で接続します。
まずは、シェルからポチポチとコマンドを叩いて実験してみます。基本的な使い方に限れば、ネット検索でこのようなブログ記事がヒットするので事足りますが、読書きするアドレスやデータの詳細や、書かれていない機能について知るには、データシートを読むしかありません。データシートは大抵が英語で書かれていて、また専門用語が多く読むのにかなり苦労すると思いますが、感度調整や取得できるデータを切り替えられたり、実は便利な機能があったりと、目を通す価値は十分にあります。
### バスに接続されたスレーブを一覧して、センサのアドレスを調べます $ i2cdetect -y 1 ⇒ センサのアドレスは 0x1e ### レジスタの値を読んでみます $ i2cget -y 1 0x1e 0x0a 0x48 ← Identification Register A $ i2cget -y 1 0x1e 0x0b 0x34 ← Identification Register B $ i2cget -y 1 0x1e 0x0c 0x33 ← Identification Register C ### 設定レジスタを設定します $ i2cset -y 1 0x1e 0x00 0x10 ← 計測レートを 15Hz(デフォルト値)に設定します $ i2cset -y 1 0x1e 0x02 0x00 ← 連続測定モードに切り替えます ### 計測値を読出します $ i2cget -y 1 0x1e 0x03 w 0x46fe ← 上位バイト(MSB)と下位バイト(LSB)が入れ替わっているので注意
センサをあっちこっちに傾けながら i2cget コマンドを叩くと、取得される値が変化しています。
とりあえず、センサを正しく結線できて、何等かのデータを読み出せているようなので、連続してデータを取得できるよう python スクリプトを書いてみます。
#!/usr/bin/python
# -*- coding: utf-8 -*-
import smbus # I2C を使う
import math
from time import sleep
### define #############################################################
DEV_ADDR = 0x1E # device address
REG_CONFIG_A = 0x00 # config register A
REG_MODE = 0x02 # mode register
MAGNET_XOUT = 0x03 # data register X
MAGNET_ZOUT = 0x05 # data register Z ←注意
MAGNET_YOUT = 0x07 # data register Y ←注意
# 1byte read
def read_byte( addr ):
return bus.read_byte_data( DEV_ADDR, addr )
# 2byte read
def read_word( addr ):
high = read_byte( addr )
low = read_byte( addr+1 )
return (high << 8) + low
# Sensor data read
def read_word_sensor( addr ):
val = read_word( addr )
if( val < 0x8000 ): # positive value
return val
else: # negative value
return val - 65536
### Main function ######################################################
bus = smbus.SMBus( 1 )
bus.write_byte_data( DEV_ADDR, REG_CONFIG_A, 0xe0 );
bus.write_byte_data( DEV_ADDR, REG_MODE, 0x00 );
while 1:
print 'X=%6d' % read_word_sensor( MAGNET_XOUT ),
print 'Y=%6d' % read_word_sensor( MAGNET_YOUT ),
print 'Z=%6d' % read_word_sensor( MAGNET_ZOUT ),
print # 改行
sleep( 1 )
上記のスクリプトを実行しながら、そこそこ水平なテーブルの上で、Z 軸を中心にセンサをぐるっと 1 回転させ、その出力を X-Y 軸でプロットしてみました。
そこそこ綺麗な円ですが*1、X 軸および Y 軸の絶対値に差があり、中心が原点からずれてしまっています。そのため、正確に方位角を求めたい場合には、センサの校正は必須になります。スマートホンでセンサを校正する場合、本体を 8 の字に動かして校正することがありますが、これは原点を補正するために、各軸の測定値について最大値と最小値を求める必要があるからです。
また、計測された地磁気について、自宅のある地点の地磁気値を求めると、全磁力=474.30mG、水平分力=307.77mG、鉛直分力=360.89mG とのことでした。また、センサの感度(Configuration Register B)は標準設定のままなので、磁力 1000mG につきセンサの出力値 1090 ですから、実際の地磁気の値に比べて、センサの測定値が小さいようです。ただ、これもセンサ周辺に置かれた磁性体がもろに影響するため、測定値の絶対量を利用して何かするのはなかなか難しい感じがじます。
先のグラフでは、X-Y 軸成分のみ検定してみましたが、X-Y-Z の 3 軸について正しく校正されていれば、 X2+Y2+Z2=(一定) と考えられるので、センサ基盤の傾きを計算できるかもしれません。
HMC5883L のデータシートから拾ったメモ書きです。
