Lingo 发表于 2017-6-10 16:27:55

【CurieNano】对于此板指南针的个人研究

我一直都想把curie的6-axis跟 板上的compass融合一下,问题是这个板上的compass太多bug了。所以我把我对此板compass的研究说一下,希望一些想9轴融合的老哥指点指点。
DFRobot的官方放出来的library是给HMC5883L用的,大家用的时候,出来的数字一定基本上是怪怪的,如果我没猜错的话(至少我是这样)。

经过多番研究,我终于发现了一个东西,我的板上的compass有几个小字:M883。然后经过我多番research,在某个网站上看到的是,如果compass上面是M883的是HMC5883(注意没L), 如果L883的才是HMC5883L (我暂时没法证明这个说法是对还是错,不过我M883的跟着没L的说明书来弄能运行)。

我的板是CurieNano V2.0, 所以有这批的老哥想用compass的话请注意你的compass是写着M883还是L883。你们可以下载看看datasheets:






(1) HMC5883跟HMC5883L的功能差不多,I2C的地址也一样,但是在Configuration Register A(datasheets的p12)的时候有些不一样。话不多说,放图:


对于HMC5883来说, CRA6跟CRA5需要是0才能正常工作。对于HMC5883L的话,CRA6跟CRA5可以是00,01,10,11 。所以一旦老哥们用的library是setSamples这个东西的,可能会导致HMC5883没L不工作。


(2) 对于Configuration Register B的时候(datasheets的p13),有L跟没L的CRB7 to CRB0位置都一样,但是他们的range跟gain不一样。
但是这个Gain是给人看的,后面校准的时候我会解释为什么这个gain没卵用,我们自己测gain。

(3)对于Mode Register的话(datasheets的p14), 两个差不多,一般都是写入0x00(Continuous-Measurement Mode)。HMC5883L的MR7是给High Speed的I2C用的,所以一般都是关掉的,所以一般有L没L都是写入0x00 。


问题分析完了,那么我就开始使用HMC5883没L了。对于这个CRB这个+/-1.9 Gauss这个range,因为我试了0.9跟1.2这两个range,我的板会返回-4096这些奇怪的数字,一看就知道这个不可以用。从1.9以后的range都没有这样的问题。对于这个问题,我暂时无法解释,datasheet 15页说overflow就是 -4096了。作为老哥,我们需要稳住。


我的setup是这样搞:

#include<Wire.h>
const uint8_t HMC5883 = 0x1E;               //有L没L都是这个地址了
uint8_t outputData;         //这个一定要是 unsigned的,有LSB会装在里面,这是一个buffer

void setup() {
Serial.begin(9600);

Wire.begin();
Wire.beginTransmission(HMC5883);
Wire.write(0x00);       //Configuration Resgister A
Wire.write(0b00010100); //30HZ
Wire.endTransmission();

Wire.beginTransmission(HMC5883);
Wire.write(0x01);   //Configuration Resgister B
Wire.write(0b01000000);       // +/- 1.9Ga Range
Wire.endTransmission();

Wire.beginTransmission(HMC5883);
Wire.write(0x02);   //Mode Register
Wire.write(0x00);   // Continuous-Measurement Mode
Wire.endTransmission();   
}


void loop() {
int16_t x,y,z;         //这里不能直接int。一般int是16位的但是intel这个int好像是32位的,所以用int会把MSB的第一个正负号bit变成数字,这里只能short或int16_t 。


Wire.beginTransmission(HMC5883);
Wire.write(0x03);         // 从0x03开始读,参考datasheet p11
Wire.endTransmission();   
delay(30);
Wire.requestFrom(HMC5883, 6);


if(6 <= Wire.available()) // If the number of bytes available for reading be <=6.
    {
      for(int i=0;i<6;i++)
      {
            outputData=Wire.read();//Store the data in outputData buffer
      }
    }
    Wire.endTransmission();

    //下面这里看p11啦
    x=outputData << 8 | outputData; //Combine MSB and LSB of X Data output register
    z=outputData << 8 | outputData; //Combine MSB and LSB of Z Data output register
    y=outputData << 8 | outputData; //Combine MSB and LSB of Y Data output register


    Serial.print(x);
    Serial.print(" ");
    Serial.print(y);
    Serial.print(" ");
    Serial.println(z);
}


上面这个program,我们需要各个方位乱动去尽量把x,y,z的raw data的最大最小拿到(xyz跟你地方的地磁线重叠就可以比较容易拿到,后面会说到不同地方的地磁线)。但是拿到raw data我们怎样用呢。话不多说,先上图:



这个是compass 的x跟y的plot,如果我plot了z,那么这个就是个球体/椭圆。我们可以看到我这个HMC5883的offset还是比较大的。
那么我们需要做的就是把这个球的圆心放到中间,所以 x_offset = (最大的x+最小的x)/2,y_offset = (最大的y+最小的y)/2,z_offset = (最大的z+最小的z)/2
然后我们把得到的raw data依次减去这些offset就好。


然后我们还需要把这些applied offset的raw data normalized了,因为减去offset以后,这个球/椭圆的圆心在origin了。正常情况下,我xyz轴跟地球磁线正向或反向重叠,我最大x需要跟最大y和最大z是一样得到的数才能说的过去,最小的同理。这些就是我最近一次得到的最大最小xyz (没有减去offset):
#define MAG0MAX 575
#define MAG0MIN -265

#define MAG1MAX 586
#define MAG1MIN -265

#define MAG2MAX 378
#define MAG2MIN -393


可见z的peak-to-peak是771(约等于5883没L的datasheet p13给出的Gain:768),但x跟y的peak-to-peak是800多,所以说datasheet给出的gain没卵用,实际上gain就是xyz三轴的peak-to-peak。所以我要做这样的计算把它们normalize了:

float magOffset = { (MAG0MAX + MAG0MIN) / 2, (MAG1MAX + MAG1MIN) / 2, (MAG2MAX + MAG2MIN) / 2 };
mx = (x-magOffset)/(MAG0MAX - MAG0MIN);
my = (y-magOffset)/(MAG1MAX - MAG1MIN);
mz = (z-magOffset)/(MAG2MAX - MAG2MIN);
mx,my,mz就是normalize之后的以gauss为单位的值(这些值不一定是准确的值,但是他们三个是normalize之后的值,就是它们相除的时候会得到准确的比例,yaw就是跟x和y的比例依赖性很高)。

我们得到mx,my,mz,基本上就大功告成啦。

这里要说一下地球的地磁线,因为这东西对compass的影响很大:



地磁线就是上图那个蓝色的线,Declination只是一个真北跟磁北的区别,我们用compass的原因是我们希望得到一个yaw(heading)的Reference,所以无论是真北或者磁北对heading的References影响不大,因为如果想得到真北,只需要减去declination就好。

但是Inclination对于compass的影响,我可以说是比较大的。 因为当compass的Z轴跟这个field正反向重叠的时候,z的值会去到最大或者最小。这个时候x跟y的值会变的很小很小,然后会在0上下浮动。如果x是正,y是负,那么heading就在270-360度之间;如果x是负,y是正,那么heading就是90-180度之间。这就说明指南针失灵了。这个情况就像你在地磁南极或者北极,inclination是+/- 90度,你拿着个指南针平衡于地面,指南针就找不到北了。

Inclination是跟纬度的关系比较大,在赤道,大概是0度,然后广州大概是向下34度。越高纬度越向下。
https://www.ngdc.noaa.gov/geomag-web/#igrfgrid
这个网站能根据你当地的经纬给出declination跟inclination,在magnetic components那里选,然后最后calculate他会给你一个xml文件,里面有D跟I。

在calibration的时候,应该避免compass靠近高电流的电线,因为那个磁场会影响compass的reading。

Last: 对于老哥想用9轴的数据去得到一个很好的AHRS,如果用Madgwick的filter的话,记得把指南针的的坐标跟curie的坐标对齐(mx变成my,my变成-mx),然后在把他们放进 function。
这个是我对curie的Reference Axes的猜测(望老哥指正,curie里面的是BMI160),HMC5883的Reference Axes是对的(根据datasheet):



9轴的Madgwick或者是Mahony filter的code我就不放上来了,用update(9个东西) 取代 updateIMU(6个东西)。

其实arduino里面的库可以搜索AHRS,它会显示三个result。三个src我都看过,adafruit那个比较完善,里面有Madgwick跟Mahony,然后这个Mahony还可以设置sample的frequency (在库里直接搜索ahrs得到的mahony不能设置frequency,直接默认512hz)。你们还可以试试两个filter有什么不同。


这个放个code给老哥们得到最大最小的xyz,不要靠近高电流的地方,这个程序会不断记录你知道现在为止最大或最小的xyz:

#include<Wire.h>

const uint8_t HMC5883 = 0x1E;
uint8_t outputData;

int16_t maxmagx = 0;
int16_t minmagx = 0;
int16_t maxmagy = 0;
int16_t minmagy = 0;
int16_t maxmagz = 0;
int16_t minmagz = 0;

void setup() {
Serial.begin(9600);

Wire.begin();
Wire.beginTransmission(HMC5883);
Wire.write(0x00);       //Configuration Resgister A
Wire.write(0b00010100); //30HZ
Wire.endTransmission();

Wire.beginTransmission(HMC5883);
Wire.write(0x01);
Wire.write(0b01000000);
Wire.endTransmission();

Wire.beginTransmission(HMC5883);
Wire.write(0x02);
Wire.write(0x00);
Wire.endTransmission();   
}

void loop() {
int16_t x,y,z;


Wire.beginTransmission(HMC5883);
Wire.write(0x03);
Wire.endTransmission();   
delay(30);
Wire.requestFrom(HMC5883, 6);


if(6 <= Wire.available()) // If the number of bytes available for reading be <=6.
    {
      for(int i=0;i<6;i++)
      {
<i style="background-color: initial;">            outputData=Wire.read();//Store the data in outputData buffer
      }
    }
    Wire.endTransmission();

    x=outputData << 8 | outputData; //Combine MSB and LSB of X Data output register
    z=outputData << 8 | outputData; //Combine MSB and LSB of Z Data output register
    y=outputData << 8 | outputData; //Combine MSB and LSB of Y Data output register

    if (x > maxmagx) maxmagx = x;
    else if (x < minmagx) minmagx = x;

    if (y > maxmagy) maxmagy = y;
    else if (y < minmagy) minmagy = y;

    if (z > maxmagz) maxmagz = z;
    else if (z < minmagz) minmagz = z;

    Serial.print("Orientation: ");
    Serial.print(maxmagx);
    Serial.print(" ");
    Serial.print(minmagx);
    Serial.print(" ");
    Serial.print(maxmagy);
    Serial.print(" ");
    Serial.print(minmagy);
    Serial.print(" ");
    Serial.print(maxmagz);
    Serial.print(" ");
    Serial.println(minmagz);
}</i>
我看论坛有个老哥搞蓝牙跟6轴的,然后想搞9轴,我希望我这个文章可以帮到你。对于您抖动的情况, 那个setgyrorate跟setAccelxxxxxRate可以把它弄到50,filter.begin(50) 然后下面microsPerReading = 1000000 / 50。 如果你想快速roll跟pitch,可以把那个setxxxxrange调高, 下图。不过在convertRaw的方程里面你要把相应的数字放进去。

Ricky 发表于 2017-6-10 23:13:23

专业贴,必须赞一个。

422234 发表于 2017-6-11 20:27:41

非常棒的文章啊!!!!赞

O_oYYQ 发表于 2017-6-12 11:06:04

好帖顶一个

Grey 发表于 2017-6-12 12:19:28

老哥,这波稳,服!

pATAq 发表于 2017-6-12 14:45:39

感谢分享

422234 发表于 2017-6-12 15:04:52

确实是883


Angelo 发表于 2017-6-12 15:37:23

厉害, 挖得有点深!

Lingo 发表于 2017-6-12 15:59:44

422234 发表于 2017-6-12 15:04
确实是883

我的是M883,按道理是HMC5883
如果是L883, 应该才是HMC5883L
(我看到外arduino官方的论坛有个老哥是这样说的,根据我的经历,好像也是这样)

老哥你可以试试我贴上的第一堆code, 那个是直接输出 xyz三轴的raw data。

如果数字一直有变的话就是用我的code能动,因为http://www.eeboard.com/bbs/thread-95424-1-1.html这个老哥用了DFRobot在github上找的hmc5883L的code(DFRobot给的library里的示例)出现这样的问题。

我也有这样的问题,所以我才做了一系列的研究才写自己的code来运行。

422234 发表于 2017-6-12 16:12:11

Lingo 发表于 2017-6-12 15:59
我的是M883,按道理是HMC5883
如果是L883, 应该才是HMC5883L
(我看到外arduino官方的论坛有个老哥是这 ...

好的,非常感谢!!!回头我试试

nicho 发表于 2017-6-12 17:07:16

稳! 赞一个!!

Lay 发表于 2017-6-12 21:03:45

好厉害

hnyzcj 发表于 2017-6-14 11:10:38

厉害了

xhuaihe 发表于 2017-7-31 08:49:36

厉害了

gray6666 发表于 2017-9-5 10:39:41

厉害。。。。。。。。。。。

派大星ym 发表于 2022-8-5 09:56:39

牛牛牛牛牛

派大星ym 发表于 2022-8-5 10:11:07

{:6_214:}。。。。

花生编程 发表于 2023-8-16 14:15:33

厉害厉害

花生编程 发表于 2023-8-16 14:16:37

不错不错

三春牛-创客 发表于 2023-8-17 12:05:56

厉害厉害

三春牛-创客 发表于 2023-8-17 12:09:33

赞赞赞!
页: [1]
查看完整版本: 【CurieNano】对于此板指南针的个人研究