ArduinoとProcessingで作るリアルタイムデジタルコンパス
このArduinoプロジェクトでは、Arduino、MEMS磁力計、Processing IDEを使ってクールなコンパスを作る方法を紹介します。コンパスのデモ動画はこちら: このプロジェクトに必要なのは、地球磁場を測定するMEMS磁力計、Arduinoボード、ジャンパーワイヤーだけです。例として、GY-80ブレークアウトボードに搭載されたHMC5883L(3軸磁力計)を使用します。 まず、I2CプロトコルでArduinoボード経由でセンサーからデータを取得します。次に、センサーのX軸とY軸の値を使って方位角を計算し、その値をシリアルポート経由でProcessing IDEに送信します。以下のコードでそれが可能です: MEMS磁力計の仕組みやデータ取得方法について詳しく知りたい場合は、私のMEMSセンサーチュートリアルをご覧ください。 ここではまず、シリアルポートから送られてくる方位値を受信します。詳細については、私のArduinoとProcessingチュートリアルをご覧ください。 コンパスは実際には画像、より正確にはProcessing IDEに読み込まれた複数の透過画像で構成されています。画像はスケッチの作業ディレクトリに配置する必要があります。draw()セクションで画像オブジェクトを定義した後、image()関数を使って背景画像(オプション、単色背景でも可)を読み込みます。次にコンパス画像を読み込み、rotateZ()関数で方位値に合わせて回転させます。その上にコンパスの矢印画像を読み込みます。 Processing IDEのコードはこちら: プロジェクトファイル、画像、ソースコードはこちらからダウンロードできます:概要
コンパスの仕組み
Arduino部分
/* Arduino Compass
*
* by Dejan Nedelkovski,
* www.HowToMechatronics.com
*
*/
#include <Wire.h> //I2C Arduino Library
#define Magnetometer_mX0 0x03
#define Magnetometer_mX1 0x04
#define Magnetometer_mZ0 0x05
#define Magnetometer_mZ1 0x06
#define Magnetometer_mY0 0x07
#define Magnetometer_mY1 0x08
int mX0, mX1, mX_out;
int mY0, mY1, mY_out;
int mZ0, mZ1, mZ_out;
float heading, headingDegrees, headingFiltered, declination;
float Xm,Ym,Zm;
#define Magnetometer 0x1E //I2C 7bit address of HMC5883
void setup(){
// Initialize Serial and I2C communications
Serial.begin(115200);
Wire.begin();
delay(100);
Wire.beginTransmission(Magnetometer);
Wire.write(0x02); // Select mode register
Wire.write(0x00); // Continuous measurement mode
Wire.endTransmission();
}
void loop(){
//---- X-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mX0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mX0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mX1 = Wire.read();
}
//---- Y-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mY0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mY0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mY1 = Wire.read();
}
//---- Z-Axis
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ1);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mZ0 = Wire.read();
}
Wire.beginTransmission(Magnetometer); // transmit to device
Wire.write(Magnetometer_mZ0);
Wire.endTransmission();
Wire.requestFrom(Magnetometer,1);
if(Wire.available()<=1) {
mZ1 = Wire.read();
}
//---- X-Axis
mX1=mX1<<8;
mX_out =mX0+mX1; // Raw data
// From the datasheet: 0.92 mG/digit
Xm = mX_out*0.00092; // Gauss unit
//* Earth magnetic field ranges from 0.25 to 0.65 Gauss, so these are the values that we need to get approximately.
//---- Y-Axis
mY1=mY1<<8;
mY_out =mY0+mY1;
Ym = mY_out*0.00092;
//---- Z-Axis
mZ1=mZ1<<8;
mZ_out =mZ0+mZ1;
Zm = mZ_out*0.00092;
// ==============================
//Calculating Heading
heading = atan2(Ym, Xm);
// 位置に応じた偏角で方位を補正
// 偏角はこちらで確認: https://www.ngdc.noaa.gov/geomag-web/
// 私の場所では4.2度 => 0.073 rad
declination = 0.073;
heading += declination;
// 符号が反転した場合の補正
if(heading <0) heading += 2*PI;
// 偏角加算による補正
if(heading > 2*PI)heading -= 2*PI;
headingDegrees = heading * 180/PI; // 方位角(度単位)
// 出力角の平滑化 / ローパスフィルター
headingFiltered = headingFiltered*0.85 + headingDegrees*0.15;
// シリアルポート経由でProcessing IDEに方位値を送信
Serial.println(headingFiltered);
delay(50);
}Processing IDE部分
/* Arduino Compass
*
* by Dejan Nedelkovski,
* www.HowToMechatronics.com
*
*/
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;
Serial myPort;
PImage imgCompass;
PImage imgCompassArrow;
PImage background;
String data="";
float heading;
void setup() {
size (1920, 1080, P3D);
smooth();
imgCompass = loadImage("Compass.png");
imgCompassArrow = loadImage("CompassArrow.png");
background = loadImage("Background.png");
myPort = new Serial(this, "COM4", 115200); // シリアル通信開始
myPort.bufferUntil('\n');
}
void draw() {
image(background,0, 0); // 背景画像読み込み
pushMatrix();
translate(width/2, height/2, 0); // 座標系を画面中心に移動、中心で回転させるため
rotateZ(radians(-heading)); // Z軸周りにコンパスを回転
image(imgCompass, -960, -540); // コンパス画像読み込み、座標系が移動したため -960x, -540y(画面サイズの半分)に配置
popMatrix(); // 座標系を元の位置 0,0,0 に戻す
image(imgCompassArrow,0, 0); // コンパス矢印画像読み込み、popMatrix()のおかげでrotateZ()の影響を受けない
textSize(30);
text("Heading: " + heading,40,40); // 画面に方位値を表示
delay(40);
}
// シリアルポートからデータ読み取り開始
void serialEvent (Serial myPort) {
data = myPort.readStringUntil('\n');// シリアルポートからデータを読み取り、String変数 "data" に格納
heading = float(data); // String値をFloat値に変換
}
製造プロセス
- Arduinoで作るモニター用Ambilightシステム:没入感アップの自作ガイド
- Arduinoで超音波レベーション(浮遊)装置を自作:ステップバイステップガイド
- Arduinoと1Sheeldで作る万能Androidリモコン──IR制御で家電を一括操作
- Arduinoとスマホで作るスマート電圧計 – 簡単DIYプロジェクト
- Arduino UNOで周波数とデューティサイクルを高精度測定
- Arduinoで作るパンチングキーボードボタン:ストレス解消カスタムキー
- Arduino超音波センサーとProcessingで作るリアルタイム距離測定ソナー
- スマート駐車場カウンター:Arduino、Processing、PHPでリアルタイム車両管理
- Bolt IoTとArduino UNOでLED輝度をシームレス制御
- スマートなArduino制御ロボットアームの製作:簡単DIYチュートリアル
- PHPベースのWebインターフェースでArduino Unoを制御する構築ガイド