公開日:2020/09/19
title.png

12th Season


#12-8 電子コンパス(その2)

 今回作るのは、電子コンパスの第二案です。最初の電子コンパスは、9軸加速度・ジャイロ・磁気センサMPU9250に内蔵された磁気センサAK8963で地磁気ベクタを計測、サーボモータを駆動して常に北方位を指し示すコンパスでした(下図)。

ar9a_expr.jpg

 この装置(以下、マーク1と呼びます)の最大の難点は、「サーボモータの可動範囲が180°しかない」と、言う事です。このため、北の方角がサーボモータの可動範囲内に無かった場合には、北方位を指し示すことが出来ず、装置を180°回転させる必要がありました。

磁気センサ

 磁気センサとしてはマーク1と同じく、MPU9250(下図)内のAK8963を使います。

ar9a_mpu9250.jpg

 マーク1の時に作ったプログラム(e_compas.ino)に追加するので、回路図のMPU9250接続シートはそのまま流用できます(以下図、再掲)。

ar9a_schem1.png

 I/O電圧5VのUNOを使いますので、MPU9250(3.3V定格)との接続にはL/Sが必要です(上回路図の通り)。

 マーク1の時に解説済みですが、MPU9250の外部I2Cバス側(ECL,EDA)を使い、直接内部のAK8963へアクセスします。マーク1で回路図を作った時(Rev.1)には、プライマリI2Cバス側(SCL,SDA)を接続せずに浮かせてあったのですが、悪さしないようにプルアップしておきました(Rev.2)。

※ここで使用した双方向L/Sは、オープンドレイン+プルアップタイプなので、接続しておくとプルアップしたのと同じことになります。

 AK8963の制御方法については、マーク1の記事(「#9-10 電子コンパスの作成」)を参照してください。

表示装置

 冒頭で述べた通り、サーボモータでは可動範囲が180°しかなかったため、可動範囲の反対側に北方位がある場合、北の方角を指し示すことができませんでした。物理的に物が動く電子コンパスはそれなりに面白かったのですが、アプリケーションとしては大きな欠点でした。

 今回は円形配置RGB LED(下図)を使って、360°どの方角に北があっても、方位を表示可能な電子コンパスにしたいと思います。

a112_rgbring.jpg

 フルカラーのRGB LED(WS2812B)が円形に24個配置されたモジュールです。円形に配置されているので、ぐるっと360°、360°/24個=15°毎に方位を示すことが可能です。以下の定数でモジュールのピクセル数を指定することができます。

  const int rgb_MAX_PIX=24;

 rgb_MAX_PIXが4の倍数だった場合には、東西南北の4方位を表示することができるので、以下の色で各方位を表示することにします。

    北(青)  
西(黄)

🗾

東(緑)
  南(赤)  

 ピクセル数が4の倍数ではないモジュールを使った場合には、北だけを表示します。

 WS2812Bの制御方法については「#11-2 円形配置RGB LED(WS2812B)を使う」を参照してください。

電子コンパス(マーク2)の設計

 円形配置RGB LEDを表示に使った、マーク2を設計して行きます。

物理的配置の検討

 まずは、部品の物理的配置から検討します。
 磁気センサAK8963で計測した地磁気ベクタを円形配置RGB LEDの座標系にマッピングする必要があるので、予め円形配置RGB LEDに以下図の様な座標系を設定しておきます。

a128_rgbled.png

 円形配置RGB LEDの円をU-V平面に置き、円の中心を原点に設定しました。後で地磁気ベクタとu軸とのなす角度を計算して、光らせるべきピクセル位置を求めるため、中心からピクセル#0へ向かう直線をu軸、LEDの配置(発光)面がw軸正方向となるように座標軸UVW系を設定します。残るv軸は、v=w×u(×はベクタ積)で定義します。

 ちゃんとした筐体を作るつもりはないので(1^^;)、円形配置RGB LEDとMPU9250をブレッドボードに直挿しして使います(下図)。

a128_compas.png

 座標軸の黒丸は紙面に対して垂直に奥側へ延びる矢印、白丸は逆に手前側に延びる矢印を表しています。
 MPU9250のシルクに表示された座標軸は、加速度センサとジャイロセンサを使う時の座標軸です。磁気センサAK8963は、同一パッケージ内に封入された別チップのため、座標軸が異なっています。そこへ更に、円形配置RGB LEDのUVW系が登場するので、大騒ぎです。対応は以下の通りとなります。

  シルクのx:y:z軸 ⇔ AK8963のy:x:−z軸 ⇔ 円形配置RGB LEDのw:v:−u軸

 プログラムでは、AK8963から読みだした地磁気ベクタ(x,y,z)から、円形配置RGB LEDの表示座標(u,v,w)への変換が必要になります。関係性は以下の通りとなります。

  円形配置RGB LEDのu:v:w軸 ⇔ AK8963のz:x:y軸

 コードとしては以下の様になります(一部抜粋)。

  meas_ak8963 (hx,hy,hz);
  // affine transform
  hu=hz;
  hv=hx;
  hw=hy;


 上図とは異なる配置にする場合には、上コードの変換式を変更する必要があります。

表示方法

 マーク1の時と同様にして、地磁気ベクタとu軸(下図ではx軸に相当)とのなす角度θを−180°≦θ≦180°の範囲で求めます(下図左側)。

ar9a_comps.png

※上図は「#9-10 電子コンパスの作成」からの流用です。右半分のサーボの図は無視してくださいm(1__)m。

 上図のy軸が円形配置RGB LEDに設定したUVW系のv軸に相当しますので、UVW系の定義図に当てはめるとθ>0°方向は反時計回りとなり、ピクセル番号が減少する反対周りとなります。また、−180°〜+180°よりも、0°〜360°で算出された方が使い易いので、以下の様に角度を補正して、光らせるピクセルを決定します。

  // set compass
  th=-th;
  while (th<0)
    th += 360;
  while (th>=360)
    th -= 360;

  // North, blue
  idx=rgb_SIZ_PIX*(rgb_MAX_PIX*th/360);
  pbuf[idx + 0]=0;
  pbuf[idx + 1]=0;
  pbuf[idx + 2]=rgb_MAX_LUM;


 ここで、変数thがθに相当する変数名です。上の処理によって、thはピクセル#0から時計回りに0°〜360°の範囲で北方位を示します。

 ネットリスト(接続表)でも良いくらいなのですが、一応、回路図を示しておきます(↓)。

a128_schem.png

マーク1(サーボモータ版)回路図に於けるシート2の置き換えで、シート2Bとしてあります。

 RGB LEDチップWS2812Bの定格電源電圧はVdd=3.5〜5.3[V]なので、微妙に、3.3Vでは駆動できない仕様です。まあ、UNOを使うので5VをつないでおけばOKです。DUE等で使おうとすると面倒だな……、と、思っただけです。

プログラムの改修

 プログラムはマーク1で作成したe_compas.inoを改造して使おうと思います。

 円形配置RGB LED(WS2812B)の制御には8ビットタイマ(TC2)を使っています。Servoライブラリも、何らかのタイマを使って制御されているはずで、はたしてWS2812BとServoライブラリは共存できるのだろうか?と、Servoライブラリのソースを確認してみたのですが、複雑すぎて良く解りません(1^−^;)。多分見た感じ、UNOだと16ビットタイマ(TC1)が使われているみたい??なので、恐らく共存可能だな……、と……(自信無し)。
 ただ、e_compas.ino自体のコードで、北方位がサーボモータの可動範囲から外れた時のエラー表示がdelay()関数を使ったLED表示になっているため、この間、処理がブロックされてしまうことが判りました。このため、共存させず#ifdefで場合分けすることにしました(↓)。

  #ifdef USE_RGB_LED_RING
    :
    : マーク2(円形配置RGB LED版)の処理
    :
  #else // USE_RGB_LED_RING
    :
    : マーク1(サーボモータ版)の処理
    :
  #endif // USE_RGB_LED_RING


 従って、マーク1(サーボモータ版)とマーク2(円形配置RGB LED版)は、排他的に、どちらかを選択してコンパイルすることが出来ます。


 以下に、完成したプログラムをリンクしておきます。

  完成版プログラム:e_compas.ino

 いつもの様にオリジナルを差し替えてあるので、どこからダウンロードしても最新のコードとなります。
 ダウンロードした状態だと、先頭付近の「#define USE_RGB_LED_RING」をコメントしてあります。その状態だとマーク1(サーボモータ版)の制御となっています。マーク2(円形配置RGB LED版)の制御に使用する場合は、先頭付近の「#define USE_RGB_LED_RING」を有効化してください。

実験

 前節の回路(シート1およびシート2B)をブレッドボードなどに構築してUNOと接続したら、プログラム(e_compas.ino)の「#define USE_RGB_LED_RING」を有効にしてコンパイル&書き込みしてください。この状態でもう、電子コンパス(マーク2)として機能しています。
 デバッグ用機能以外はシリアルモニタを必要としないので、モバイルバッテリ(例えば以下図)などを使って、UNOごと持ち歩くことが出来ます。

ar66_mbatt.jpg


 以下、実験中の様子です。

a128_expr.jpg

 今回のプログラムでは、円形配置RGB LEDに設定したUVW系のw軸正方向が鉛直上方向に向いていることを前提としていますので、ひっくり返すと東西が逆転してしまいます。正しい向きで使ってください。

 実験中の様子を動画で確認していただけます(↓)。



 近くに強い磁場を発生する機器があると、間違った方位を表示することがあります。適切な環境で実験してみてください。


 サーボモータを使って機械的に方位を示す電子コンパスも面白かったけど、機械的な可動機構を作り込むのは結構大変でした。その点、機械的な動きのない円形配置RGB LEDを使ったマーク2は、実現が容易であった上に表示不能範囲もなく、良いこと尽くし。ガックシ……m(1__)m。


btn_arduino.png

btn_prev.png btn_next.png

home