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

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


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°となる。

《配線図》

ピンの構成図 左はピンの構成図です。
16F1829にはMSSP機能が2個有るのでI2C接続は
SSP1側(SCL1/SDA1)を利用しています。
I2C用プルアップ抵抗は方位センサモジュールに
内蔵されているのでそれを使えば良いと思ったの
ですがぁ、LCDが表示されずPIC内蔵のプルアップ
もONにしたらOKでした。

 センサーの"DRDY"端子は今回使っていません、これは測定値の変換が終了しデータの更新が
 行われた場合に、250usの間LOWを出力します。
 また、センサ内部のステータスレジスタ(0x09)のRDY(0bit目)が1になるのを検出してもOKですが、
 今回これも利用していません。
 任意のタイミングで見に行っています。

 下図は実態配線図で、回路電源は5Vです。

配線図
表示用にLCDを利用していますが、ここでは説明を省きまのでこちらの記事を参照下さい。
実験する場合は、パソコン(電化製品)や金属等の磁気を発生しそうな物から離して実験をしましょう。

PIC16F1829について

今まで実験では、16F1827を使うか16F1938/18F25K22を利用して来ましたが、
floatの計算をさせると16F1827(18P:4Kword)ではプログラム容量が足らず、
16F1938/18F25K22(28P)ではブレッドボードのスペースを取りすぎです、
なのでこれからは16F1829(20P:8Kword)を使う事にしました。
因みに、今回のプログラムをコンパイルしたら93%程でした、おお\(◎o◎)/、ギリギリ。

《ダウンロードプログラムについて》

↓ここからサンプルプログラムソースファイルをダウンロードして下さい。
skHMC5883L.lzh

プログラムソースをダウンロードしたら、MPLAB Xにてプロジェクトを作成します。
以下のファイルをプロジェクトディレクトリにコピーしてプロジェクトに取込んで下さい。
次にコンパイルPIC書き込みを実行して下さい。
MPLAB(R) XC8 C Compiler Version 1.32コンパイラを使用しています。

ダウンロードファイルを解凍すると下記の様なファイル構成です。
 Compass.c・・・・・・・・・ 本体のプログラムソースファイル
 skHMC5883L.c・・・・・ 方位センサー(HMC5883L)用関数ソースファイル
 skHMC5883L.h・・・・・ 方位センサー(HMC5883L)用インクルードファイル
 skI2CLCDlib.c・・・・・・ I2C接続LCDライブラリ関数ソースファイル
 skI2CLCDlib.h・・・・・・ I2C接続LCDライブラリ用インクルードファイル
 skI2Clib.c・・・・・・・・・・ I2C通信を行う関数ソースファイル
 skI2Clib.h・・・・・・・・・・ I2C通信を行う関数のインクルードファイル

 尚、CPUのクロックは16MHzを想定しています。
 なので通信速度等(I2C)はシステムクロック16MHzで計算されています。

Compass.c

実行結果  動作すれば左の様に表示されます、(写真が見難いですが...)

 "Init NG"と表示されたら失敗です、
 配線などをよ〜くぅ確かめてみましょう。
 3秒後に表示開始し、500ms毎に表示更新します。

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


skHMC5883L.h

HMC5883L用関数のインクルードファイルです。
"skHMC5883L.c"を利用する場合に
#include "skHMC5883L.h" をプログラムの先頭で記述して下さい。

今回は16MHzで利用しているので、
 #ifndef _XTAL_FREQ
  // Unless already defined assume 16MHz system frequency
  // This definition is required to calibrate __delay_us() and __delay_ms()
  #define _XTAL_FREQ 16000000    // 使用するPIC等により動作周波数値を設定する
 #endif
と記述しています、16MHz以外で利用する人は"16000000"を書き換えて下さい。
この値をいじり調整(キャリブレーション)を行います。

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

このライブラリはHMC5883Lから方位のデータをI2C接続で読み出す関数集です。
ですので、この関数集にはskI2Clib.c/skI2Clib.hのファイルが必要です。

この関数集を利用する場合は、"skI2Clib.c"の"InitI2C_Master( )"関数を呼び出した後使います、
使い方の例は、"Compass.c"を参照下さい。

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

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

  address :デバイス(スレーブ)のI2Cアドレスを指定します(SENSOR_ADRS=0x1E)
  ans       :戻り値   0=正常終了、それ以外はI2C通信エラーです
              1=異常(相手からACKが返ってこない)

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

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

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

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

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

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

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

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

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

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

ans = CompassGetOrientation(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 = CompassSingleRead(&Deg,0) ;
     if (ans == 0) {
          ans = CompassGetOrientation(Deg) ;
          printf((char *)&DirectionName[ans]) ;
     }
  "skHMC5883L.h"ファイルに”DIRECTION_DIVISION”の記述が有ります、
   これを"8"とすると8分割での計算に出来ます。

skI2CLCDlib.c
skI2CLCDlib.h
skI2Clib.c
skI2Clib.h

この内容は”秋月電子I2C接続小型LCDモジュールに表示を行う”を参照下さい。

尚、システムクロックを変えた人は"skI2Clib.c"ファイル内の"InitI2C_Master( )"関数と、
"skI2CLCD.h"のファイルを変更する必要が有ります。
また、HMC5883LはI2C通信速度が最大400KHz対応です、ここでは400KHzで行っています。

《その他》

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

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

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

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



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


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