macsbug

Just another WordPress.com site

Digital Compass HMC5883L with ESP8266

leave a comment »

ESP8266 + HMC5883L で デジタル・コンパス を作りました。           2016.11.15

HMC5883L は 3軸地磁気センサー です。費用は 927円です。


 

Processing によるマック上での表示。(スケッチ:HMC5883L_processing)


 

準備:費用=927円   : 円レートで価格が変動します。2016.11.15 現在(1$ 107.85)。

No.  Nomen  Link  Price(円)  Memo
01 WeMos D1 mini *  D1 Mini 347  1個 C 4.34
02 HMC5883L  HMC5883L 262  1個 GBP 1.94
03 1.4″ 128X120 SPI Color TFT  1.44″ Color TFT 318  1個 C 3.98
04 チップ抵抗 10KΩ  4個  –
05 カプトンテープ  –  –
05 両面テープ  –  –
06 Library:HMC5883L Arduino-HMC5883L jarzebski氏に感謝
07 設定:magnetic declination  地域の設定  –
08 校正  HMC5883L_calibrate  –

.
* WiFi.mode(WIFI_OFF);:この命令で送信電波を停止し without TELEC にします。
.
1.44″ TFT:Ver 1.1, V1.4, V2.1 があります。基板の裏に記載してあります。購入者
_ からは選択ができなく どれが来るか解りません。おおまかにはイニシャライズ
_ によって画素の位置が変わります。今回のスケッチは 宣言文で Ver A,C を選択
_ する事により対応できる様にしてあります。調べるとかなり奥が深いです。
_ 1.44″ でなく 1.8″ TFT を使用する方法が得策です。
.
HMC5883L ( GY-273 ):VCC=3.3V, SDA,SCLは 3.3V入力です。DRDYは使用しません。
_ 回路図参照の事。回路図に誤記あり:詳細は参照の*に記載。


 

配線:TFT基板は 3.3V使用の為 基板上の U1 LDO(5V to 3.3V) の J1 Jumper は
_  ジャンパーをします。(しなくても動作します)
_  チップ抵抗4個は TFT基板の上にカプトンテープを敷きハンダ付けします。
_  D1 mini は両面テープで TFT基板に直付けし 11本の配線をします。


 

地磁気センサーの設定:TFTの表示と地磁気センサーの向きを合わす必要があります。
_ 方位磁石やスマホの方位計を参照し 針とN極の方向を合わせ 基板に磁気センサー
_ を固定します。


 

地磁気センサー:
低価格と動作確認済みの中から HMC5883L(GY-273) を使用しました。
GY-85(HMC5883L) も動作確認しましたので使用できます。
3軸地磁気センサー( Magnetic ) は 以下の物があり 価格は高いですが GY-9150 や
GY-85 は Gyro, Acclerometer を含み  他の応用が可能となります。
MAG3110 は 値の幅が狭く正しい値が取れない為に 課題とします。


 

ライブラリー HMC5883L:magnetic-declination 値 と 校正値の設定。
_ HMC5883L ライブラリーは 複数ありますが 動作しない物があります。
_ 設定値:magnetic-declination.com の値を設定します。
_  Find the magnetic declination at your location に接続し magnetic-declination
_  を入手。東京の場合は  「-7’25E (negative)」 で 以下のスケッチになります。
_  float dec_angle=(-7+(25.0/60.0))/(180/M_PI); // Tokyo:-7.25
_ 校正値:ライブラリの中にあるサンプル「HMC5883L_calibrate」を実行。
_  以下のスケッチになります。
_  compass.setOffset(32, -202); // Set calibration offset
_ 感度:HMC5883L_RANGE_1_3GA を使用しています。*=同文
_  HMC5883L_RANGE_8_1GA : 8.1 Ga 4.35 mG 230 Lsb/gauses
_  *5_6GA : 5.6 Ga 3.03 mG 330,*4_7GA : 4.7 Ga 2.56 mG 390
_  *4GA : 4 Ga 2.27 mG 440,*2_5GA : 2.5 Ga 1.52 mG 660
_  *1_9GA : 1.9 Ga 1.22 mG 820,*1_3GA : 1.3 Ga 0.92 mG 1090 : default
_  HMC5883L_RANGE_0_88GA : 0.88Ga 0.73 mG 1370
_ レンジ:3つ:HMC5883L_SINGLE を使用しています。
_  HMC5883L_IDLE, HMC5883L_SINGLE,HMC5883L_CONTINOUS
_ 計測モード:HMC5883L_DATARATE_30HZ を使用しています。
_  HMC5883L_DATARATE_75HZ, *30HZ,*15HZ, *7_5HZ,*3HZ, *1_5HZ
_ サンプルアベレージ:HMC5883L_SAMPLES_8 を使用しています。
_  HMC5883L_SAMPLES_8, *4,*2,*1


 

参考:
haoyuelectronics:Index of /Attachment/GY-273:モジュール回路図
_  * この回路図はピン番号がずれています。1,2,3,4,5 は 1,5,2,3,4 です。
Axis_Compass_Magneticfield_Module-SCHEMATIC:モジュール回路図
_  SDA,SCLにPull_up 抵抗の無い回路図です。
Henny’s Bench:Arduino GY-273 HMC5883L Magnetometer Compass Tutorial
I2Cdevlib:HMC5883L Class Reference
dev/jarzebski:3-osiowy magnetometr HMC5883L
Manualzz:29133-CompassModuleHMC5883L-v1.0
HMC5883L_3-Axis_Digital_Compass_IC
simtronyx-:Digitaler Kompass: HMC5883L(GY-271),TFT(HY-1.8)
HMC5883L 製作マニュアル:秋月さんのページから。
HMC5883L 半導体資料:秋月さんのページから。
秋月:HMC5883L DIP, HMC5883L / HMC5883L モジュール・データシート
Strawberry Linux:HMC5883L


 

感想:
コンパスの凄さ:子供の頃 初めて手にした丸いコンパス を回して遊んだものです。
_ その時 目に見えない磁力で方向が解る事が不思議でした。 現在 電子コンパス
_ を個人で作れる時代になりました。
部品価格:国内での価格は相変わらず高いです。4桁には驚きます。
_ ebay:HMC5883L:262円。
_ 秋月:HMC5883L DIP KIT:600円
_ aitendo:デジタルコンパスモジュール [ATD5883L]:695円
_ Strawberry Linux:HMC5883L:700円
_ スイッチサイエンス:HMC5883L:1868円
_ 
地磁気センサーとライブラリー:価格では HMC5883L を 選択。ライブアリーは
_ Arduino-HMC5883L を選択。jarzebski氏に感謝致します。
_ 地磁気測定は要素が多く 設定や校正等も必要です。
周囲の磁力:磁力の付いた物を近づけると針が回る感度があります。
ESP8266の端子:GPIO15はスケッチ書込みの為に Low です。Hi を出力する物は
_ 接続できません。CS 信号は接続可能で書込み時のエラーも回避できます。
GY-85, GY9150:Gyro とAccelero Meter のチップが搭載されていますので これを
_ 使用した物が直ぐ作れる環境になり 3次元の位置情報や加速度を楽しめます。
Processing :ライブラリーにある Processing でのスケッチは大変助かりました。
_ 完成度の高い表示は 素晴らしいですね。再び jarzebski氏 に感謝致します。


 

スケッチ:

// Digital Compass                             // 2016.11.12 macsbug
// ESP8266 + HMC5883L + 1.44" Color TFT        //
//--------------------------------------------------------------------
// http://www.jarzebski.pl/arduino/czujniki-i-sensory/3-osiowy-magnetometr-hmc5883l.html
// https://github.com/jarzebski/Arduino-HMC5883L  Arduino-HMC5883L
// https://www.youtube.com/watch?v=zG3uzQW3wc0
// Digital Compass: HMC5883L (GY-271), 1.4" SPI TFT (HY-1.8)
// http://blog.simtronyx.de/digitaler-kompass-hmc5883l-gy-271-tft-hy-1-8-und-ein-arduino/
// http://www.ngdc.noaa.gov/geomag-web/#declination : Magnetic Field Calculators
//--------------------------------------------------------------------
// Find yours here: http://www.magnetic-declination.com/
// Tokyo:
// Latitude: 35° 41' 22.2" N
// Longitude: 139° 41' 30.1" E
// Magnetic declination: -7° 25' 
// Declination is NEGATIVE (WEST)
// Inclination: 49° 32' 
// Magnetic field strength: 46597.1 nT
//--------------------------------------------------------------------
// Set declination angle on your location and fix HDG
// You can find your declination on: http://magnetic-declination.com/
// (+) Positive or (-) for negative
// Tokyo declination angle is -7'25E (negative)
// Formula: (deg + (min / 60.0)) / (180 / M_PI);
// float dec_angle = (-7 + (25.0 / 60.0)) / (180 / M_PI);
// TFT 128x128 : x = 1 to 127, y = 0 to 127
//--------------------------------------------------------------------
#include <ESP8266WiFi.h>                        // ESP WiFi
#include <Wire.h>                               //
#include <SPI.h>                                //
#include <HMC5883L.h>                           // HMC5883L
#include "Adafruit_GFX.h"                       // Adafruit Grafic
#include "Adafruit_ST7735.h"                    // Adafruit ST7735
#define CS    D8                                // TFT CS  : D0 = 16
#define RST   D2                                // TFT RST : D2 =  4
#define DC    D1                                // TFT DC  : D1 =  5 
#define SCLK  D5                                // TFT SLCK: D5 = 14 
#define MOSI  D7                                // TFT MOSI: D7 = 13 
Adafruit_ST7735 tft 
  = Adafruit_ST7735( CS, DC, MOSI, SCLK, RST);  // TFT
HMC5883L compass; 
int pre_HD = 0;
float HD = 0;                                   // Heading new
float HD_old = 360;                             // Heading oled
uint16_t cx, cy;                                // center x,y
const uint16_t rad = 64;                        // radius of length
const float deg = 2 * PI / 360;                 // radian to degree
uint16_t osx, osy;
//String v = "A";                               // TFT ver A : V1.1
//String v = "B";                               // TFT ver B : V1.4 ?
  String v = "C";                               // TFT ver C : V2.1

void setup(void){
  WiFi.mode(WIFI_OFF);                          // without TELEC
  Serial.begin(115200);Serial.println();        // 
  Wire.begin(D4, D3);                           // HMC5883L SDA,SCL,D4,D3
  while (!compass.begin()){delay(500);}         // Initialize HMC5883L
  compass.setRange(HMC5883L_RANGE_1_3GA);       // Set measurement range
  compass.setMeasurementMode(HMC5883L_CONTINOUS);//Set measurement mode
  compass.setDataRate(HMC5883L_DATARATE_30HZ);  // Set data rate
  compass.setSamples(HMC5883L_SAMPLES_8);       // Set number of samples averaged
  compass.setOffset(32, -202);                  // Set calibration offset
  //--------------------------------------------// See HMC5883L_calibration.ino
  if (v == "A"){tft.initR(INITR_144GREENTAB);}  // 1.44 v1.1
  if (v == "C"){tft.initR(INITR_18GREENTAB);}   // 1.44 v2.1 
  tft.fillScreen(ST7735_BLACK);                 //
  tft.setTextColor(0x5FCC);                     // GREEN
  tft.setRotation(1);                           //
  //--------------------------------------------//
  cx = tft.width()/2; cy = tft.height()/2;      // Center Calculate
  if (v == "C" ){ cx = cx + 14; }               //
  osx = cx; osy = cy;                           //
  face();                                       // indicator face
}

void loop(void){
  Vector norm = compass.readNormalize();        // data read
  float HDG = atan2(norm.YAxis, norm.XAxis);    // Calculate HDG
  float dec_angle=(-7+(25.0/60.0))/(180/M_PI);  // Tokyo:-7.25
  HDG += dec_angle;                             // heading data
  if (HDG < 0   ){HDG += 2 * PI;}
  if (HDG > 2*PI){HDG -= 2 * PI;}
  float fixeds_HD = HDG * 180/M_PI;             // Convert to degrees to fix
 
  int smooth_HD = round(fixeds_HD);             // Smooth angles +/- 3deg
  if (smooth_HD < (pre_HD + 3) &&
      smooth_HD > (pre_HD - 3)){
      smooth_HD = pre_HD;
  }
  pre_HD = smooth_HD; HD = smooth_HD;
  Serial.print(norm.XAxis);Serial.print(":");   // Output to processing
  Serial.print(norm.YAxis);Serial.print(":");
  Serial.print(norm.ZAxis);Serial.print(":");
  Serial.print(HD);Serial.print(":");
  Serial.print(fixeds_HD );Serial.print(":");
  Serial.print(smooth_HD);Serial.println();
  delay(30); // One loop: ~5ms,115200,delay ~28ms:allow data rate 30Hz (~33ms)

  if(HD != HD_old){
    indication_Triangle();                      // Triangle indication
  //indication_Line();                          // line     indication
    indication_Dot();                           // dot      indication
    HD_old = HD;                                // old HD save
  }
  delay(250);
}

void face(){
  uint16_t xd,yd;
  tft.fillScreen(ST7735_BLACK);                 // Dsplay Clear
  tft.fillCircle(cx, cy, rad-2, 0x3CDF);        // BLUE  Ring
  tft.fillCircle(cx, cy, rad-5, 0x0000);        // BLACK
  tft.setTextSize(1);
  tft.setTextColor(ST7735_WHITE);
  xd = cos(-90 * deg) * (rad - 11) + cx;
  yd = sin(-90 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-1, yd-1);tft.println("N");   // N
  xd = cos(  0 * deg) * (rad - 11) + cx;
  yd = sin(  0 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-3, yd-3);tft.println("E");   // E
  xd = cos( 90 * deg) * (rad - 11) + cx;
  yd = sin( 90 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-1, yd-5);tft.println("S");   // S
  xd = cos(180 * deg) * (rad - 11) + cx;
  yd = sin(180 * deg) * (rad - 11) + cy;
  tft.setCursor(xd-0, yd-2);tft.println("W");   // W
  for (int i = 0; i < 360; i += 30) {           // 12 point
    xd = cos((i - 90) * deg) * (rad - 5) + cx;
    yd = sin((i - 90) * deg) * (rad - 5) + cy;
    if ( i ==   0 ){ xd = xd + 1;}
    if ( i == 180 ){ xd = xd + 1;yd = yd + 1;}
    if ( i == 270 ){ yd = yd + 1;}
    tft.drawPixel(xd, yd, 0xFFFF);              // pixel ring
  }
  if ( v == "A" ){ apple_icon( 1,1);}           // apple icon
  if ( v == "C" ){ apple_icon(31,1);}           // apple icon
}
void apple_icon(int px,int py){                 // apple icon
  tft.drawLine(6+px, 1+py,7+px, 1+py,0x07E0);
  tft.drawLine(5+px, 2+py,6+px, 2+py,0x07E0);
  tft.drawLine(5+px, 3+py,5+px, 3+py,0x07E0);
  tft.drawLine(2+px, 4+py,8+px, 4+py,0xFFE0);
  tft.drawLine(1+px, 5+py,9+px, 5+py,0xFFE0);
  tft.drawLine(1+px, 6+py,7+px, 6+py,0xFD24);
  tft.drawLine(1+px, 7+py,7+px, 7+py,0xFD24);
  tft.drawLine(1+px, 8+py,9+px, 8+py,0xF800);
  tft.drawLine(1+px, 9+py,9+px, 9+py,0xF800);
  tft.drawLine(2+px,10+py,8+px,10+py,0x3CDF);
  tft.drawLine(3+px,11+py,4+px,11+py,0x3CDF);
  tft.drawLine(6+px,11+py,7+px,11+py,0x3CDF);
}

void indication_Triangle(){
  int cr = 41; float r = M_PI/180;
  float h1 = HD_old;
  tft.fillTriangle(                              // analog clear
    cx-cr*cos(r* h1   ),cy+cr*sin(r* h1   ),
    cx+cr*cos(r*(h1+5)),cy-cr*sin(r*(h1+5)),
    cx+cr*cos(r*(h1-5)),cy-cr*sin(r*(h1-5)),
    ST7735_BLACK);
  float h2 = HD;
  tft.fillTriangle(                              // analog draw
    cx-cr*cos(r* h2   ),cy+cr*sin(r* h2   ),     // x0,y0
    cx+cr*cos(r*(h2+5)),cy-cr*sin(r*(h2+5)),     // x1,y1
    cx+cr*cos(r*(h2-5)),cy-cr*sin(r*(h2-5)),     // x2,y2
    ST7735_RED);
  float d1,d2;                                   // deg decode
  if ((h1<=360)&&(h1>=90)){d1=90*((h1/90)-3);}   // 90-270:-180-  0
  if ((h2<=360)&&(h2>=90)){d2=90*((h2/90)-3);}   // 90-270:-180-  0 
  if ((h1<= 90)&&(h1>= 0)){d1=90*((h1/90)+1);}   //  0- 90:+180- 90
  if ((h2<= 90)&&(h2>= 0)){d2=90*((h2/90)+1);}   //  0- 90:+180- 90
  int xa = 103; if (v == "C" ){ xa = 135;}
  set_text(xa, 1, String(int(d1)), 0x0000, 1);  // digital clear
  set_text(xa, 1, String(int(d2)), 0x5FCC, 1);  // digital draw
  tft.fillCircle(cx, cy, 7, ST7735_RED);         // Circle r = 6
  tft.fillCircle(cx, cy, 3, ST7735_BLACK);
//apple_icon(64-5,64-5);
}
void set_text(int x,int y,String text,
              uint16_t color,byte size){
  tft.setTextSize(size);  tft.setCursor(x,y);
  tft.setTextColor(color);tft.print(text);
}

void indication_Dot(){
  uint16_t xa,ya,xb,yb;
  int h1 = HD_old - 90;
  int h2 = HD - 90;
  xa = sin(h1 * deg) * (rad - 8) + cx;          // ring old x
  ya = cos(h1 * deg) * (rad - 8) + cy;          // ring old y
  xb = sin(h2 * deg) * (rad - 8) + cx;          // ring new x
  yb = cos(h2 * deg) * (rad - 8) + cy;          // ring new y
  tft.fillRect(xa, ya-1, 3, 3, 0x0000);         // 9 dot clear
  tft.fillRect(xb, yb-1, 3, 3, 0x07E0);         // 9 dot draw
}

void indication_Line() {
  float h = HD - 90;
  float sx = sin(h * deg) * (rad - 18) + cx +1;
  float sy = cos(h * deg) * (rad - 18) + cy;
  tft.drawLine(osx, osy, cx, cy, 0x0000);       // Erase old positions 
  tft.drawLine(sx,  sy,  cx, cy, 0xFFFF);       // Draw  new positions           
  tft.fillCircle(cx, cy, 3, 0xFFFF);            // r = 3 Circle
  osx = sx; osy = sy;                           // Update x & y coords
}

Written by macsbug

11月 13, 2016 @ 3:27 am

カテゴリー: ESP8266

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。