将 Arduino 指南针信号转换为可用航向

Posted

技术标签:

【中文标题】将 Arduino 指南针信号转换为可用航向【英文标题】:Converting Arduino compass signal to useable heading 【发布时间】:2020-02-18 00:51:20 【问题描述】:

背景

我从亚马逊购买了一个带有 QMC5883 芯片的 Arduino 磁力计/指南针,但是我得到的轴承输出与我在网上找到的计算不符。串行输出似乎是合理的(相位差为 90° 的正弦曲线),但我得到的计算方位的数字与他们应该得到的不匹配。我将串行输出存储为 .csv 文件,以绘制在 Excel 中旋转 360° 时的磁力计响应:

响应大致符合预期 - Z 大致保持稳定(除了由电缆引起的一些摆动!),X 和 Y 在 360° 内呈正弦变化。 (请记住,我无法用手以恒定速度转动磁力计,这就是曲线如此不稳定的原因)。

但是,下面是计算出的航向图;结果应该在 -180° 和 +180° 之间:

如您所见,它仅在 -60° 到 -160° 之间变化,并且每个方位读数都不是唯一的,因为它是由磁力计的两次不同旋转给出的。使用的代码中的具体计算(底部完整)为:

bearing =180*atan2(y,x)/3.141592654;    //values will range from +180 to -180°
bearing +=0-(19/60);    //Adjust for local magnetic declination

问题

我无法弄清楚计算有什么问题,因为它用于几个不同的来源,我想知道如何将我得到的读数转换为一对一的可用范围,而不是多对一,例如 -180° 到 +180° 或 0° 到 360°。

代码如下:

//There are several differences between the QMC5883L and the HMC5883L chips
//Differences in address: 0x0D for QMC5883L; 0x1E for HMC5883L
//Differences in register map (compare datasheets)
//Output data register differences include location of x,y,z and MSB and LSB for these parameters
//Control registers are also different (so location and values for settings change)

#include <Wire.h> //I2C Arduino Library

#define addr 0x0D //I2C Address for The QMC5883L (0x1E for HMC5883)

double scale=1.0;

void setup() 
// double scaleValues[9]=0.00,0.73,0.92,1.22,1.52,2.27,2.56,3.03,4.35;
// scale=scaleValues[2];
//initialize serial and I2C communications
Serial.begin(9600);
Wire.begin();

Wire.beginTransmission(addr); //start talking to slave
Wire.write(0x0B); 
Wire.write(0x01); 
Wire.endTransmission();

Wire.beginTransmission(addr); //start talking to slave
Wire.write(0x09);
Wire.write(0x1D);
Wire.endTransmission();


void loop() 

int x, y, z; //triple axis data

//Tell the QMC what regist to begin writing data into
Wire.beginTransmission(addr);
Wire.write(0x00); //start with register 00H for QMC5883L
Wire.endTransmission();

double bearing=0.00;
//Read the data.. 2, 8 bit bytes for each axis.. 6 total bytes
Wire.requestFrom(addr, 6);
//read 6 registers in order; register location (i.e.00H)indexes by one once read
if (6 <= Wire.available()) 
//note the order of following statements matters
//as each register will be read in sequence starting from data register 00H to 05H
//where order is xLSB,xMSB,yLSB,yMSB,zLSB,zMSB
//this is different from HMC5883L!
//data registers are 03 to 08 
//where order is xMSB,xLSB,zMSB,zLSB,yMSB,yLSB
x = Wire.read(); //LSB x; 
x |= Wire.read()<<8; //MSB x; bitshift left 8, then bitwise OR to make "x" 
// x*=scale;
y = Wire.read(); //LSB y 
y |= Wire.read()<<8; //MSB y; 
// y*=scale;
z = Wire.read(); //LSB z; irrelevant for compass 
z |= Wire.read()<<8; //MSB z; 
// z*=scale;

bearing =180*atan2(y,x)/3.141592654;//values will range from +180 to -180 degrees
bearing +=0-(19/60);//Adjust for local magnetic declination


// Show Values
//Serial.print("X:");
Serial.print(x);
//Serial.print("    Y: ");
Serial.print(",");
Serial.print(y);
//Serial.print("    Z: ");
Serial.print(",");
Serial.print(z);
//Serial.print("    B: ");
Serial.print(",");
Serial.println(bearing);

delay(500);
 

【问题讨论】:

【参考方案1】:

对于阅读此问题的其他人: OP 忘记实现 x、y、z 平滑和超出范围的值删除。这是如何实现的,以及它是如何完成的,看看这个QMC5883 compass library的源代码:

QMC5883L Compass 是一个 Arduino 库,用于将 QMC5583L 系列芯片板用作指南针。

它支持:

获取 XYZ 轴的值。 计算方位角。 获取 16 点方位角方位方向 (0 - 15)。 获取 16 点方位角方位角名称(N、NNE、NE、ENE、E、ESE、SE、SSE、S、SSW、SW、WSW、W、WNW、NW、NNW) 通过滚动平均和最小/最大去除来平滑 XYZ 读数。

【讨论】:

以上是关于将 Arduino 指南针信号转换为可用航向的主要内容,如果未能解决你的问题,请参考以下文章

将指南针的航向计算到特定坐标而不是北

有没有一种简单的方法可以在 phonegap 中获得手机的指南针航向精度?

如何在 Xamarin.Android 中获取指南针方向

iPhone 3.0 指南针:如何获取航向?

如何检查指南针航向是不是指向特定位置?

使用指南针指向位置