前回、動かすたびに同じ方位でも値が異なり、うまくいきませんでしたが、
Arduino側でキャリブレーションするようにしたところ、比較的正確に方位を取得できるようになりました。
キャリブレーションといっても以下のような簡単な方法です。
OUT1とOUT2それぞれについて最大値、最小値を測定し、最小値~最大値の範囲で正規化します。
起動後にゆっくり2回転ほどさせると、正確な方位がとれるようになりました。
I2C版のHMC6352もキャリブレーション機能があるので、キャリブレーションは必須ということなのでしょう。
また、効果があるか良く分からないのですが、値の取得前にSET/RESET端子にパルスを入れるようにしています。
ArduinoのDIGITAL2をSET/RESET端子に接続します(10KΩの抵抗でプルダウン)。
■Arduinoスケッチ
// Calibration 初期値は安全な値を適当に設定
int cal_min1 = 488;
int cal_max1 = 515;
int cal_min2 = 463;
int cal_max2 = 489;
void setup()
{
pinMode(2, OUTPUT);
Serial.begin(9600);
}
void loop()
{
// SET/RESET PULSE
digitalWrite(2, LOW);
delay(10);
digitalWrite(2, HIGH);
delay(10);
digitalWrite(2, LOW);
delay(10);
// 読み取り
int val1 = analogRead(0);
int val2 = analogRead(1);
// キャリブレーション
if (val1<cal_min1) cal_min1 = val1;
if (val2<cal_min2) cal_min2 = val2;
if (val1>cal_max1) cal_max1 = val1;
if (val2>cal_max2) cal_max2 = val2;
int div1 = (cal_max1 - cal_min1 + 1);
int div2 = (cal_max2 - cal_min2 + 1);
float fval1 = (val1 - cal_min1 - div1 / 2.0) / div1;
float fval2 = (val2 - cal_min2 - div2 / 2.0) / div2;
// 角度(方位)を0~255に変換
int at = (atan2(fval1, fval2) + PI ) * 255 / (2*PI);
Serial.print(at, BYTE);
delay(100);
}
■Processingスケッチ
import processing.serial.*;
Serial myPort;
int val;
void setup()
{
size(200, 200);
myPort = new Serial(this, "COM9", 9600);
PFont font = createFont("Arial", 12);
textFont(font);
}
void draw()
{
if ( myPort.available() > 0) {
val = myPort.read();
}
background(0);
text(str(val), 1, 10);
translate(width/2, height/2);
rotate(val * 2 * PI/255);
triangle(-10, -40, 10, -40, 0, 40);
}