まなびサイエンス

3 軸電子コンパス センサ モジュールを使う

カバーイメージ

 I2C 接続の 3 軸電子コンパス センサ モジュールを入手できたので、RaspberryPi に接続して実験してみました。センサの周囲に磁石などがなければ地磁気から南北を計測できるので、例えば、ロボットに搭載することで、ロボットの向いている方角や傾きを知ることができます。また、磁石や鉄板などをセンサに近づけると計測値が変化することを利用して、簡易的な金属探知機のようなガジェットを作ることもできそうです。

結線

 センサ モジュールとしては各社から様々なバリエーションが発売されているようですが、私が Amazon.co.jp で購入したものには、基盤に CJ-M49 のプリントがあり、3.3V のレギュレータを搭載して、5V 電源でも使えるものでした。何れもセンサの核心部分は同じ HMC5883L であるため、だいたい使い方は同じと思います。eBay では、一つ 250 円くらいから販売があります。
 RaspberryPi とは I2C で接続でき、I2C で必要な 3 本とは別に電源が必要で、計 4 本で接続します。

  • センサ: 3V3 ⇔ RasPi: 3V3
  • センサ: SCL ⇔ RasPi: GPIO3 (SCL)
  • センサ: SDA ⇔ RasPi: GPIO2 (SDA)
  • センサ: GND ⇔ RasPi: GND

初期設定とデータの試し読み

 まずは、シェルからポチポチとコマンドを叩いて実験してみます。基本的な使い方に限れば、ネット検索でこのようなブログ記事がヒットするので事足りますが、読書きするアドレスやデータの詳細や、書かれていない機能について知るには、データシートを読むしかありません。データシートは大抵が英語で書かれていて、また専門用語が多く読むのにかなり苦労すると思いますが、感度調整や取得できるデータを切り替えられたり、実は便利な機能があったりと、目を通す価値は十分にあります。

### バスに接続されたスレーブを一覧して、センサのアドレスを調べます
$ 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 軸でプロットしてみました。


Fig.1

 そこそこ綺麗な円ですが*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 のデータシートから拾ったメモ書きです。

  • 最大 8G(ガウス)の磁場環境下で 5mG の測定精度を持つ 12bit AD コンバータ
  • 最大測定周期 160Hz
  • 設定レジスタ A:1~8 回の計測結果の平均値を出力するよう選択可、測定周期は 0.75~75Hz で選択可
  • 設定レジスタ B:測定ゲイン ±0.88~±8.1G で選択可、地磁気は高々 0.66G 程度なので、地磁気を正確に測定するなら、最も感度を高くしても測定範囲内に収まる。
  • 出力値は、測定ゲインの範囲において -2048~+2047

参考リンク

  1. *1 もし、テーブルが水平から傾いていた場合には楕円になるはず

カテゴリー

過去ログ