方位センサー(HMC5883L)で方角を測定して見ます

〔Arduinoの動かせ方入門に戻る〕


HoneywellのHMC5883Lを使用したコンパスモジュール(3軸高感度地磁気センサ)を使います。
お値段がお高めなのがぁあれですがぁ、秋月電子のこちらで購入しています。(販売終了みたい *2))
接続はI2Cで、I2C用プルアップ抵抗はモジュールに内蔵しています。
尚、ストロベリー・リナックスのこちらはだいぶんお安いですね〜、プルアップなしで、電源は3.3Vで
使用する位の違いでしょうかぁ。んん...良いかもぉ。

また、データシートは販売先のページを参照しましょう。

このHMC5883Lには電源管理を目的とした3つの動作モードが有ります。

アイドルモード(Idle Mode)
 このページのスケッチでの初期化はこのモードから開始しています。
 このモード時はI2C回路以外は動作していない状態で約2uAの消費電流らしい。

連続測定モード(Continuous-Measurement Mode)
 設定されたレートに従い連続で測定を行います、データ(X/Y/Z軸)が読み出されないと測定データは
 更新されません。
 レートは、0.75Hz〜75Hz(デフォルトは15Hz)の設定が出来ます、尚、測定時の消費電流は100uA。

シングル測定モード(Single-Measurement Mode):デフォルト
 1回づつ測定するモードで、測定が完了すればアイドルモードになります。
 また、この場合の出力レートは160Hz固定です。


方角の概念図 左は方角の概念図です。
X/YはセンサーのXY軸方向です。
ここのスケッチでは方角に対して、角度(0-360)と
方角の名称(北東=NE)を得る事が出来ます。

とにかくHMC5883Lはキャリブレーションしないと
使い物になりません

潟~ューズ・ロボティクスさんのこちらの様な事を
行えば良いのでしょうけど....
面倒だったので、コンパスを見ながら適当な
数値を入れて見て調整しました。(^0^;)
結果的には、各方向で5°程ずれています。
面倒だったので、これで良しとしましたが、
良い子は、ちゃんと行って下さいね。

HMC5883Lは当然、地磁気での北(磁北)を示します、地図上の北(真北)ではないです。
この差を磁気偏角と言います。

磁気偏角のズレ具合を知るには?

@ 国土地理院地図を表示させます。
A 調べたい場所を拡大表示させ、右上の[機能]→「表示」→「磁北線」を"ON"させます。
  (但し、ある程度拡大させないと表示されません)
B 表示された度数だけ右方向(西偏)が”真北”と言う事です。
  日本では大体4°(沖縄) 〜 9°(北海道)程右側にズレれるらしい、我が家では6.6°でした。

  因みにぃ、もし度数が何度何分、例えば「5゚12"」は 5+12/60(60分で1度)で5.2°となる。

《配線図》

配線図 回路電源は5Vです。

ここでのサンプルスケッチではLCDは利用していませ
ん、結果の表示はIDEのシリアルモニターに出力して
います。
下記の実験風景の様に外で動作させたのでLCDを
付けて置きましたので、LCDで表示させたい人は
こちらの記事を参考にして下さい。

I2C用プルアップ抵抗は方位センサモジュールに
内蔵されているのでそれを利用しています。

 実験する場合は、パソコン(電化製品)や金属等の
 磁気を発生しそうな物から離して実験をしましょう。

 センサーの"DRDY"端子は今回使っていません、
 これは測定値の変換が終了しデータの更新が
 行われた場合に、250usの間LOWを出力します。

 又、センサー内部のステータスレジスター(0x09)のRDY(0ビット)が1になるのを検出してもOKですが、
 今回これも利用していません。

《ダウンロードスケッチについて》

↓ここからArduino用サンプルスケッチファイルをダウンロードして下さい。
skHMC5883L.zip

解凍すると下の様に展開されます。
[skHMC5883L]─┬─[examples]───[Compass]--- Compass.ino
        ├ skHMC5883L.cpp
        ├ skHMC5883L.h
        └ keywords.txt
ライブラリの登録方法は、ここのページの登録方法1を参照してインストールしましょう。

Compass.ino  ・・・・・・・本体のサンプルスケッチ
skHMC5883L.cpp ・・・・方位センサー(HMC5883L)用関数ライブラリソース
skHMC5883L.h ・・・・・・ヘッダファイル
keywords.txt ・・・・・・・・キーワードファイル

Compass.ino

Compass.inoを開くには、
IDEを起動して、メニューバーの「ファイル」→「スケッチの例」→「skHMC5883L」→[Compass]
をクリック操作すればファイルが開かれます。
次に、IDEツールバーの「Upload」ボタンをクリックしてコンパイルとarduinoボードに書込みを行います。

実行結果  IDEの[シリアルモニタ]画面を表示させましょう。
 こんな感じ(左図)に1秒毎に表示されると成功です
 "Initialization abnormal ans=?"と表示されたら失敗
 です、配線などをよ〜くぅ確かめてみましょう。


X/Y/Z軸の表示はセンサー値のそのままの値です、
その後に、方角の略称名表示と角度表示です。


skHMC5883L.h

方位センサー(HMC5883L)用関数のインクルードファイルです。
関数ライブラリを利用する場合は、メニューバーの「スケッチ」→「ライブラリを使用」→「skHMC5883L」を
クリック操作すれば、"#include <skHMC5883L.h>"がスケッチに追加されます。
まぁ、手動でキー入力しても良いんですけどね。
この値をいじり調整(キャリブレーション)を行います。

#define ADJUST_X_ANGLE     -252         // X軸を調整する値
#define ADJUST_Y_ANGLE     +102         // Y軸を調整する値
skHMC5883L.cpp

まず利用する場合は下記2行をスケッチの最初に記述します。
#include <Wire.h>
#include <skHMC5883L.h>

setup( )関数内で下の様にI2Cを使用する為の初期化処理を記述します。("Compass.ino"を参照)
Wire.begin() ;   // マスターとする

デバイスのI2C通信速度は最大400KHzまでの様ですがArduinoは100KHzで初期化されます。

方位センサー(HMC5883L)用関数の使い方を説明します。

skHMC5883L
 方位センサー(HMC5883L)用関数ライブラリを使用する為に必要な宣言(初期化)を行います。
 skHMC5883L Compass(address) ;
  address :デバイス(スレーブ)のI2Cアドレスを指定します(0x1E)
 "Compass"の名前は任意に変更可能です。
 例)
 #define SENSOR_ADRS 0x1E // デバイスのI2Cアドレス  skHMC5883L Compass(SENSOR_ADRS) ; // 方位センサーライブラリの生成を行う

アドレス設定  アドレスは7ビットで表します、左図の1〜7ビットです。
 0ビット目はR/Wでこれはデバイスに対する読書き指示ビットです。
 R/W=0 : 書き込み要求です(デバイスは受信モード)
 R/W=1 : 読み込み要求です(デバイスは送信モード)

 このHMC5883Lは固定("0011110":1Eh)("0011110"+R/W)となりますので
 R/W=0書込みなら"0011110"+"0"で0x3C、R/W=1読込みなら"0011110"+"1"で0x3Dとなりますが
 ここでは7ビットで指定なので
 #define SENSOR_ADRS  0x1E  // デバイスのI2Cアドレス
 となっています。

ans = Compass.Begin( )
 方位センサの初期値設定を行う処理です。
 設定のデータは、データのサンプル数は8回平均で設定、サンプルレートは15Hzです、
 通常の”測定モード”に設定し、ゲイン(検出レンジ)は1.3Gaussで設定。
 また、デバイスの初期動作モードは"アイドル"でスタートです。
 この初期設定を変更する場合は、"skHMC5883L.h"の記述を書き換えて下さい。
 (設定値の詳しい内容はデータシートを参照して下さい)

  ans   :戻り値   0=正常終了、それ以外はI2C通信エラーです
             1=送ろうとしたデータが送信バッファのサイズを超えた(32バイトMAX)
             2=スレーブ・アドレスを送信し、NACKを受信した
             3=データ・バイトを送信し、NACKを受信した
             4=その他のエラー
             5=データ受信エラー

  ゲイン(検出レンジ)の初期値は1.3Gaussです、地磁気は24000-66000nT(0.24-0.66Gauss)
   らしいので通常の場所では測定値がオーバーフローする事は無いと思いますがぁ....

ans = Compass.ActionMode(mode)
 方位センサの動作モード(測定モード)を設定する処理です。
 測定モードに切り替えると測定を開始します。
 尚、この関数は6msの待ちが発生します。
  mode :動作モードを指定します
       H43_MODE_IDLE          = アイドル状態にします。
       H43_MODE_SINGLE      = シングル測定モードにします。
       H43_MODE_CONTINUE = 連続測定モードにします。
  ans    :戻り値、0=正常終了 それ以外 Compass.Begin( )のans値を参照

ans = Compass.Receive(reg_adrs,*data,kosu)
 デバイスから指定個数のデータを受信する処理です。
  reg_adrs:読出すデータのレジスターアドレスを指定する
           連続的に読出す場合は、読出すレジスターの先頭アドレスを指定
  *data    :読出したデータの格納先を指定する(格納先配列の個数はkosu分確保する事)
  kosu     :読出すデータのバイト数を指定する
  ans       :戻り値、0=正常終了 それ以外Compass.Begin( )のans値を参照

ans = Compass.Send(reg_adrs,*data,kosu)
 デバイスに指定個数のデータを送信する処理です。
  reg_adrs:書出すデータのレジスターアドレスを指定する
           連続的に書出す場合は、書出すレジスターの先頭アドレスを指定
  *data    :書出すデータの格納先を指定する
  kosu     :書出すデータのバイト数を指定する
  ans       :戻り値、0=正常終了 それ以外Compass.Begin( )のans値を参照

ans = Compass.ContinueRead(*deg,dec)
 連続モードで読込みを行い方位の方向を角度で返す処理です。
 方位センサより連続読込みを行い、方位の計算をして度数を"deg"変数にセットします。
  *deg    :方位の計算結果(0.0-360.0)を返すのでfloat変数のアドレスを指定
  dec     :磁気偏角を度で指定、8°30′の場合8.5°(8+30/60)を指定
        (角度を真北でなく磁北で良い場合は"0.0"として下さい。)
  ans     :戻り値、0=正常終了 それ以外 Compass.Begin( )のans値を参照

  この関数を連続して読出す場合は、サンプルレートに従って下さい。(例えば、15Hzなら66ms毎)
   尚、XYZ軸のデータを読み出さないとサンプリングデータは更新されません。

  この関数を使用する前に"setup( )"内で"Compass.ActionMode(H43_MODE_CONTINUE)"を
   実行して置く必要が有ります。

ans = Compass.SingleRead(*deg,dec)
 シングルモードで読込みを行い方位の方向を角度で返す処理です。
 方位センサより単発読込みを行い、方位の計算をして度数を"deg"変数にセットします。
  *deg    :方位の計算結果(0.0-360.0)を返すのでfloat変数のアドレスを指定
  dec     :磁気偏角を度で指定、8°30′の場合8.5°(8+30/60)を指定
        (角度を真北でなく磁北で良い場合は"0.0"として下さい。)
  ans     :戻り値、0=正常終了 それ以外 Compass.Begin( )のans値を参照

  この関数を連続して読出す場合は、7ms以上毎に行います。
   また、この関数は6msの待ちが発生します。

  センサーからの生の読込み値は、RowX/RowY/RowZの各変数に格納されています。
   尚、この変数には計測地磁気が強すぎてオーバーフローした場合は、0xFFFFがセットされます。

ans = Compass.GetOrientation(float deg)
 方位の角度を16分割する処理。
 0〜360度を16分割して、指定した角度が何処の分割エリアに有るのか対応する分割の位置を
 返します。
  deg     :方位の角度を指定(0.0-360.0度)
  ans     :角度に対応する分割の位置を返す(16分割なら0-15を返す)

 例)
 char DirectionName[16][4] =  {" N ","NNE"," NE","ENE"," E ","ESE"," SE","SSE"," S ","SSW"," SW",
                                "WSW"," W ","WNW"," NW","NNW"} ;
  int   ans ;
  float Deg ;

     ans = Compass.SingleRead(&Deg,0) ;
     if (ans == 0) {
          ans = Compass.GetOrientation(Deg) ;
          Serial.print((char *)&DirectionName[ans]) ;
     }
  "skHMC5883L.h"ファイルに”DIRECTION_DIVISION”の記述が有ります、
   これを"8"とすると8分割での計算に出来ます。

《その他》

実験風景
LCDに表示させ外で実験を行っている風景です。
この実験では、磁気偏角は0で、磁北での表示です。

尚、PICでの実験の場合はセンサーモジュール内蔵プルアップ以外に、PIC内蔵プルアップも
ONにしないとLCDが表示されなかったのですがぁArduino時はそんな事は必要なかったです。
(あ、ArduinoのI2C通信速度が100KHzだからだったからかも??)

HMC5883Lはとにかくキャリブレーションが大変って言うかぁ、めんどいですねぇ、
なので下記のデバイス(RDCM-803)は同だろうか?

因みに、こちらページのPIC時の実験風景の様に、スイッチを押した時に半固定抵抗の値をX/Y軸の
調整値(ADJUST_?_ANGLE)として設定を行い計算させて、コンパスの方向と一致しているのかを
見て調整を行いましたその方が調整はやりやすかったです。

コンパスとして利用するだけなら、デジットのこちら(RDCM-803)のセンサーは、8/16分割した値を
4本の出力ピン(4ビットパターン)から読み取る様ですね、簡単かも。その内買って比較したいなぁ。*2)

それと、こちらの商品、ストロベリー・リナックスの角度出力の方位センサで、
なあんとぉ、角度で出力されるので計算の必要が無いと言うワンダフォーなセンサーです。 *1)



リンクの見直し(*2) 2020/03/20
追記(*1) 2015/06/16


【きむ茶工房ガレージハウス】
Copyright (C) 2006-2020 Shigehiro Kimura All Rights Reserved.