06/5
19:15
IT 嵌入式

四旋翼飞行器之——MPU6050 六轴姿态传感器

MPU-6000(6050)为全球首例整合性6轴运动处理组件,相较于多组件方案,免除了组合陀螺仪与加速器时之轴间差的问题,减少了大量的包装空间。MPU-6000(6050)整合了3轴陀螺仪、3轴加速器,并含可藉由第二个I2C端口连接其他厂牌之加速器、磁力传感器、或其他传感器的数位运动处理(DMP: Digital Motion Processor)硬件加速引擎,由主要I2C端口以单一数据流的形式,向应用端输出完整的9轴融合演算技术。

InvenSense的运动处理资料库,可处理运动感测的复杂数据,降低了运动处理运算对操作系统的负荷,并为应用开发提供架构化的API。

MPU-6000(6050)的角速度全格感测范围为±250、±500、±1000与±2000°/sec (dps),可准确追緃快速与慢速动作,并且,用户可程式控制的加速器全格感测范围为±2g、±4g±8g与±16g。产品传输可透过最高至400kHz的IC或最高达20MHz的SPI(MPU-6050没有SPI)。

以上摘自百度百科

mpu6050

芯片本身体积较小,规格为4*4*0.9mm,与Arduino板子连接,使用I2C端口。我使用的是Arduino senser 扩展板, 上面自带有SCL和SDA接口。如果没有扩展板的,可以将A4接SDA,A5接SCL。详见arduino学习笔记37 - Arduino Uno + MPU6050首例整合性6轴演示实验

连接好电路就可以烧代码进去了

#include "Wire.h"

// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"

// class default I2C address is 0x68
// specific I2C addresses may be passed as a parameter here
// AD0 low = 0x68 (default for InvenSense evaluation board)
// AD0 high = 0x69
MPU6050 accelgyro;

int16_t ax, ay, az;
int16_t gx, gy, gz;

#define LED_PIN 13
bool blinkState = false;

void setup() {
    // join I2C bus (I2Cdev library doesn't do this automatically)
    Wire.begin();

    // initialize serial communication
    // (38400 chosen because it works as well at 8MHz as it does at 16MHz, but
    // it's really up to you depending on your project)
    Serial.begin(38400);

    // initialize device
    Serial.println("Initializing I2C devices...");
    accelgyro.initialize();

    // verify connection
    Serial.println("Testing device connections...");
    Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");

    // configure Arduino LED for
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    // read raw accel/gyro measurements from device
    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);

    // these methods (and a few others) are also available
    //accelgyro.getAcceleration(&ax, &ay, &az);
    //accelgyro.getRotation(&gx, &gy, &gz);

    // display tab-separated accel/gyro x/y/z values
    Serial.print("a/g:\t");
    Serial.print(ax/16384.0); Serial.print("\t");
    Serial.print(ay/16384.0); Serial.print("\t");
    Serial.print(az/16384.0); Serial.print("\t");
    Serial.print(gx/131.0); Serial.print("\t");
    Serial.print(gy/131.0); Serial.print("\t");
    Serial.println(gz/131.0);

    // blink LED to indicate activity
    blinkState = !blinkState;
    digitalWrite(LED_PIN, blinkState);
}

上面ax,ay,az 除以一个浮点数16384并且gx,gy,gz除以了131. 在MPU寄存器中每个分量加速度和角速度都是用16bits来储存,也就是存储范围可以达0~65535。上面提到MPU提供了几个不同的精度标准:MPU-6000(6050)的角速度全格感测范围为±250、±500、±1000与±2000°/sec (dps),可准确追緃快速与慢速动作,并且,用户可程式控制的加速器全格感测范围为±2g、±4g、±8g与±16g。并且默认情况下,MPU的initialize 函数是这样的:

void MPU6050::initialize()
{
    setClockSource(MPU6050_CLOCK_PLL_XGYRO);
    setFullScaleGyroRange(MPU6050_GYRO_FS_250);
    setFullScaleAccelRange(MPU6050_ACCEL_FS_2);
    setSleepEnabled(false); // thanks to Jack Elston for pointing this one out!
}

所以可见加速度默认的range是±2g,角速度默认的range是±250°/sec (dps)。那么用16位来覆盖这样的range,就用65536分别除以4和500,就得到上述的两个数字了。

这样就得到了传感器的输出结果

a/g:	0.01	0.01	1.06	4.77	-0.62	-6.92
a/g:	0.02	0.00	1.07	5.05	-0.50	-6.66
a/g:	0.01	0.01	1.07	5.04	-0.46	-6.53
a/g:	0.01	0.01	1.07	4.81	-0.55	-6.39
a/g:	0.01	0.01	1.07	4.96	-0.53	-6.37
a/g:	0.01	0.01	1.07	4.93	-0.65	-6.21
a/g:	0.01	0.00	1.06	4.94	-0.66	-6.18
a/g:	0.01	0.01	1.06	4.91	-0.55	-6.13
a/g:	0.01	0.01	1.07	4.89	-0.52	-6.16
a/g:	0.02	0.01	1.07	5.11	-0.56	-6.16
a/g:	0.02	0.01	1.06	4.99	-0.66	-6.09
a/g:	0.01	0.02	1.07	4.99	-0.60	-6.08
a/g:	0.01	0.01	1.06	4.76	-0.55	-6.12
a/g:	0.01	0.00	1.07	5.12	-0.63	-6.14
a/g:	0.01	0.00	1.07	4.93	-0.44	-6.44
a/g:	0.01	0.01	1.07	4.93	-0.37	-6.39
a/g:	0.02	0.01	1.06	4.85	-0.60	-6.40
a/g:	0.02	0.01	1.07	4.73	-0.44	-6.61
a/g:	0.02	0.01	1.07	5.08	-0.63	-6.42
a/g:	0.01	0.01	1.07	4.69	-0.49	-6.65
a/g:	0.02	0.01	1.05	5.01	-0.66	-6.67
a/g:	0.01	0.01	1.07	5.04	-0.57	-6.76
a/g:	0.02	0.01	1.07	4.71	-0.66	-6.69
a/g:	0.02	0.01	1.07	4.94	-0.54	-6.81
a/g:	0.01	0.01	1.07	5.08	-0.63	-6.71
a/g:	0.01	0.01	1.06	4.92	-0.63	-6.69
a/g:	0.01	0.00	1.06	4.87	-0.66	-6.69
a/g:	0.01	0.01	1.07	4.80	-0.60	-6.49

这个状态是水平放置的结果,前三列代码代表加速度,后三列表示角速度,分别都是x,y,z的顺序。加速度好理解前两个接近于0,后一列接近于1代表1g。z轴受到地面一个mg大小的反作用力,所以有一个大小为g的加速度。至于后面三个不等零的数字,我之前一直想不通,直到后来采集了大量数据放到matlab观测得到,无聊传感器以任何角度静止摆放,这个几个数字基本不动,所以基本确定下来这个几个数字是偏移量,只要用一个常数将他校准就可以了。

观测

这个图是我通过matlab画出的观测到的数据,总共有三千多组数据,其中三个短的线是加速度,分别为以三种不同角度摆放的加速度测量结果,又粗又大的是角速度偏移量,另一个细线是噪音,在这里将次忽略。画这个图的目的就是为了说明一个问题:无论传感器怎么摆放,在静止状态下的输出数据都是一个固定的点(会有波动),我们将此大量数据取平均,再在计算的时候将其减去,就可以达到矫正的效果了。

gx

gy

gz

以上是x,y,z 轴矫正后的误差分布图,都控制在了1以内。代码插入时,就在刚读取出角速度时候矫正就行:

    accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
    //reset gx gy gz
    gx = gx - 630;
    gy = gy + 62;
    gz = gz + 862;

以上是我测得的偏移量,不过对于每一个不同的传感器的偏移量应该都不一样,但是矫正的方法是一至的。
另外,目前对于加速度的教程的必要性还不明确,有待进一步探讨。

发表评论