yaboPP电子
项目

使用BNO055绝对方向传感器捕获IMU数据

2017年3月22日通过马克休斯

BNO055是博世的绝对方位传感器,结合传感器数据和微处理器来过滤和组合数据,给用户在空间中的绝对方位。

博世BNO055结合了三轴加速度计,陀螺仪和磁力计来为用户提供方向。

关于传感器

BNO055使用三个三轴传感器来同时测量切向加速度(通过加速度计),旋转加速度(通过陀螺仪),以及局部磁场的强度(通过磁力计)。然后可以将数据发送到外部微处理器或使用运行专有融合算法的M0 +微处理器在传感器内分析。然后,用户可以选择以各种格式从传感器请求数据。

该芯片还具有中断,可以在发生某些运动时通知主机微控制器(方向的变化,突然加速等)。

从数据表重新创建的框图

传感器必须在使用前进行校准,读取寄存器保持当前的校准状态。一旦校准,校准偏移量可以写入传感器,然后传感器立即准备好使用下一次上电。

看下面的视频学习如何校准传感器。

主机微控制器可以在非融合模式下请求来自传感器(加速度计,陀螺仪和/或磁力计)的任何或所有数据,并且可以要求绝对和相对方向(角度或四元数)在融合模式。

传感器可以返回M /S²或mg的加速度($ 1 mg = 9.81 \ frac {m} {s ^ 2} \ times 10 ^ { - 3} $$);MT中的磁场强度;陀螺仪数据以每秒或弧度(分别为DPS和RPS),欧拉角度为程度或弧度,或四分之一;和温度在°C或°F。所有选项都设置在Unit_Selection寄存器中(表3-11中数据表,pdf第30页)。

欧拉角与四元数

如果你正在为一个运动范围有限的系统设计传感器解决方案,你可以使用欧拉角。但如果你正在设计一个传感器,可以指向空间中的任何地方,你应该使用四元数。

欧拉角

欧拉角允许简单的可视化对象围绕垂直轴旋转三次(x-y-x、x-z-x y-x-y, y-z-y, z-x-z, z-y-z, x y z, x-z-y, y-x-z, y-z-x, z-x-y, z-y-x)。

X-Y-Z旋转来自Wolfram.com.

只要轴保持至少部分垂直,就足够了。然而,随着轴旋转,存在两轴可以描述相同的旋转 - 创建称为万能锁的条件的角度。当Gimbal Lock发生时,不可能在没有外部参考的情况下重新定位。看我的文章,不要在深空中迷失:理解四元数,了解更多关于万能锁的信息。

此动画具有三个万向节(显示为红色,绿色和蓝色固体圆筒段)以及可用的旋转(显示为红色,绿色和蓝色透明球面灯罩)。当内部绿色万向节的平面与红色万向节的平面对齐时,红色和蓝色万向节的旋转轴重叠和万能锁定发生(由浅黄色背景表示)。

使用四元数时,不存在万能锁定的问题。

四十二烷

1843年,威廉·汉密尔顿发明了四元数,用来乘除三个数字。在几十年的时间里,它们慢慢地失去了人们的喜爱,并在核时代和现代计算机图形编程中再次复兴。四元数由四个数组成:一个标量和一个三分量矢量。

其中w, x, y, z均为实数,i, j, k为四元数单位。

通常,W,x,y和z保持在-1和1之间的范围内,并且$$ \ sqrt {w ^ 2 + x ^ 2 + y ^ 2 + z ^ 2} = 1 $$。

这四个数字简单地在一次旋转中调整矢量的方向,无论长度如何变化。

蓝色和红色的向量是单位长度的。橙色是将蓝色矢量旋转为红色所需的旋转。

正常变换矩阵由九个数字组成,涉及应用三角函数。四元数由四个数字组成,全部小于或等于一个。可以将四元数转换为正交转换矩阵,但是,由于与万向锁相关联的数学属性(再次,请参阅我的四元数文章有关更多信息),从旋转矩阵到四元数稍微难以转换为四元数。

将四元数转换为3 × 3正交旋转矩阵的方法。

下面的代码片段演示了如何从四元数创建3×3转换矩阵和滚动、俯仰和偏航角。

/*从四元数创建旋转矩阵rm */ double rm[3][3];rm [1] [1] = quat.w quat.w () * () + quat.x () * quat.x()——quat.y () * quat.y()——quat.z () * quat.z ();rm [1] [2] = 2 * quat.x () * quat.y()——2 * quat.w () * quat.z ();rm [1] [3] = 2 * quat.x quat.z () * () + 2 * quat.w () * quat.y ();rm [2] [1] = 2 * quat.x quat.y () * () + 2 * quat.w () * quat.z ();rm [2] [2] = quat.w () * quat.w()——quat.x quat.x () * () + quat.y () * quat.y()——quat.z () * quat.z ();rm [2] [3] = 2 * quat.y () * quat.z()——2 * quat.w () * quat.x ();rm [3] [1] = 2 * quat.x () * quat.z()——2 * quat.w () * quat.y ();rm [3] [2] = 2 * quat.y quat.z () * () + 2 * quat.w () * quat.x ();rm [3] [3] = quat.w () * quat.w()——quat.x () * quat.x()——quat.y quat.y () * () + quat.z () * quat.z (); /* Display Rotation Matrix */ Serial.print(rm[1][1],5);Serial.print(" \t"); Serial.print(rm[1][2],5);Serial.print(" \t"); Serial.println(rm[1][3],5); Serial.print(rm[2][1],5);Serial.print(" \t"); Serial.print(rm[2][2],5);Serial.print(" \t"); Serial.println(rm[2][3],5); Serial.print(rm[3][1],5);Serial.print(" \t"); Serial.print(rm[3][2],5);Serial.print(" \t"); Serial.println(rm[3][3],5); /* Create Roll Pitch Yaw Angles from Quaternions */ double yy = quat.y() * quat.y(); // 2 Uses below double roll = atan2(2 * (quat.w() * quat.x() + quat.y() * quat.z()), 1 - 2*(quat.x() * quat.x() + yy)); double pitch = asin(2 * quat.w() * quat.y() - quat.x() * quat.z()); double yaw = atan2(2 * (quat.w() * quat.z() + quat.x() * quat.y()), 1 - 2*(yy+quat.z() * quat.z())); /* Convert Radians to Degrees */ float rollDeg = 57.2958 * roll; float pitchDeg = 57.2958 * pitch; float yawDeg = 57.2958 * yaw; /* Display Roll, Pitch, and Yaw in Radians and Degrees*/ Serial.print("Roll:"); Serial.print(roll,5); Serial.print(" Radians \t"); Serial.print(rollDeg,2); Serial.println(" Degrees"); Serial.print("Pitch:"); Serial.print(pitch,5); Serial.print(" Radians \t"); Serial.print(pitchDeg,2); Serial.println(" Degrees"); Serial.print("Yaw:"); Serial.print(yaw,5); Serial.print(" Radians \t"); Serial.print(yawDeg,2); Serial.println(" Degrees");

将传感器与Arduino连接

我购买了BNO055传感器贴在开发板与支持组件Adafruit.可以通过从中购买BNO055来节省一点钱Digi-Key要么逮老鼠并将其焊接到7.5×4.4mm28引脚LGA到DIP转换器用于在无焊接面包板上进行原型设计。但是对于发货后的边际成本节省,我不会推荐它。

要开始使用Arduino与BNO055接触,请按照下列步骤操作:

  1. 连接电源、接地、SDA和SCL
  2. 打开Arduino IDE,然后单击草图→包括库→管理库
  3. 搜索并安装“Adafruit BNO055”和“Adafruit Sensor”
  4. 打开并编辑File→Examples→Adafruit BNO055→Raw Data,注释掉Euler角部分,取消注释四元数部分,或者复制粘贴下面的删节代码。
#include  #include  #include  #include  / *该程序是Adafruit BNO055 Rawdata.ino的删节版本,安装了Adafruit BNO055图书馆文件→示例→Adafruit BNO055→Arduino上的原始数据连接UNO ========================================================================= scl到模拟5 |SDA为模拟4 |VDD到3.3V DC |GND到共同的地面* / #define bno055_samplerve_delay_ms(100)//数据请求之间的延迟adafruit_bno055 bno = adafruit_bno055();//基于ADAFRUIT_BNO055库VOID SETUP(VOID){SERIAL.BEGIN(115200);创建传感器对象BNO;//开始串口通信if(!bno.begin())//初始化传感器通信{serial.print(“ooops,未检测到bno055 ...检查您的接线或i2c addr!”);延迟(1000);bno.setextcrystaluse(true);//在开发板上使用晶体} void循环(void){imu ::四元数quat = bno.getquat(); // Request quaternion data from BNO055 Serial.print(quat.w(), 4); Serial.print("\t"); // Print quaternion w Serial.print(quat.x(), 4); Serial.print("\t"); // Print quaternion x Serial.print(quat.y(), 4); Serial.print("\t"); // Print quaternion y Serial.print(quat.z(), 4); Serial.println(); // Print quaternion z delay(BNO055_SAMPLERATE_DELAY_MS); // Pause before capturing new data }

该程序简单地通过I²C与BNO055通信,并通过UART端口将数据流回计算机。四元数数据被作为制表符分隔的数据发送回来,每个四元数之后都有换行符。

请记住,在校准传感器之前,您的数据无效。

示例四元数数据

对于下面的例子,我从BNO055请求四元数数据,因为我把它放在我桌子附近的一个随机方向。您可以手动解释数据wolframalpha.com.通过将其作为逗号分隔的值输入,在第四边形(例如,“字样后括号中括起来四元(0.403,0.414,0.085,0.812)")

W X Y Z
0.40344238 0.41363525 0.08508301. 0.81176757
上面的数字是描述传感器相对于参考方向的当前取向的四元数。

图片来自wolframalpha.com.显示对象的默认和实际方向

图片来自wolframalpha.com.显示旋转轴和从默认位置到达当前位置所需的旋转量。

虽然当然没有必要在Internet上查找四元数数据来处理数据,但是可以选择重复检查您的工作。

用Mathematica获取数据

Mathematica是一个通用的计算机程序,几乎可以处理你能想到的任何数据。对于感兴趣的人,我将几行代码放在一起,演示如何从设备接收数据,以及如何使用Mathematica用几个基于四元数的函数计算数据。下面的代码是为Windows编写的,因此Linux和Mac用户可能必须更改输入设备行(以bConnect开头的行)。

通过下面的下载按钮可以获得Mathematica笔记本的截图

Mathematica允许实时和事后收集和处理数据。对于这个演示,我选择了一个程序,它从串行缓冲区收集数据,将其转换为旋转矩阵,并使用旋转矩阵在参考球体中重新定位箭头。

首先单击“Connect Arduino”,然后从缓冲区的数据开始。我没有结合任何数据验证或错误检查,因此如果数据区域是空白或不形式化的,则唯一的选项是回忆数据。

Mathematica能够在到达串行端口时读取和使用数据,但对于此演示,存储在缓冲区中的30段左右应足以查看程序的工作原理。

在Mathematica中分析了从BNO055发送的数据,并在参考领域重新定位箭头

quaternionwithmathematica.zip.

控制两轴框架

BNO055非常适合机器人应用。作为一个示例应用程序,我将使用BNO055来控制安装在基于伺服的两轴框架上的激光。对于任何有幸拥有第三个旋转轴的读者来说,代码应该允许无缝引入第三个旋转轴。

像以前一样连接BNO055并添加伺服,连接到数字引脚9-11。如果你使用万向节来支撑相机,考虑升级到Alorium XLR8板。伺服系统依赖于精确的时间,如果Arduino正在处理竞争任务,它可能会导致抖动。XLR8是由FPGA制成的Arduino的临时替代品。它有一个库,可以控制伺服从一个单独的“XLR8tor”(加速器)块稳定和流体伺服运动。

线路概述

Arduino Uno R3替换:XLR8 vs Sparkfun“Redboard”Arduino Uno R3
// ----包括库---- // #include  //I²C库#include  // trig函数#include  //care for sensors#包括 // bno055特定库#include  // vector,matrix和imumath库//#include  //标准伺服库#include // xlr8伺服库#include  // xlr8加速浮点数学#define bno055_samplerve_delay_ms(50)//在样本// ----变量声明之间设置暂停---- // boolean debug = true;// true / false =通过串行int rollpin = 9的额外/没有信息;//滚动int yawpin = 10的数字引脚;//偏航的数字引脚int pitchpin = 11;//螺距浮动辊,间距,偏航的数字销;//变量保持卷,间距,偏航信息Adafruit_bno055 bno = adafruit_bno055();//使用对象bno来保存信息伺服rollservo;//创建伺服rollservo servo pitchservo; // Create servo pitchServo Servo yawServo; // Create servo yawServo void setup(void) { rollServo.attach(rollPin); // The rollServo is connected at rollPin pitchServo.attach(pitchPin); // The pitchServo is connected at pitchPin yawServo.attach(yawPin); // The yawServo is connected at yawPin Serial.begin(115200); // Create serial connection at 115,000 Baud if (!bno.begin()) // Attempt communication with sensor { Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!"); } delay(100); // Wait 0.1 seconds to allow it to initialize bno.setExtCrystalUse(true); // Tell sensor to use external crystal } //---- Main Program Loop ----// void loop() { //---- Request Euler Angles from Sensor ----// imu::Vector<3> euler = bno.getVector(Adafruit_BNO055::VECTOR_EULER); if (debug) { // If debug is true, send information over serial Serial.print("Measured Euler Roll-Pitch-Yaw"); Serial.print("\t yaw: "); Serial.print(euler.x()); Serial.print("\t"); Serial.print("\t pitch: "); Serial.print(euler.z()); Serial.print("\t"); Serial.print("\t roll: "); Serial.print(euler.y()); Serial.println(); } /* Remap information from the sensor over the 0° - 180° range of the servo The Yaw values are between 0° to +360° The Roll values are between -90° and +90° The Pitch values are between -180° and +180° */ int servoYaw = map(euler.x(), 0, 360, 0, 180); int servoRoll = map(euler.y(), -90, 90, 0, 180); int servoPitch = map(euler.z(), -180, 180, 0, 180); if (debug) { // If debug is true, send information over serial Serial.print("Measured Euler Roll-Pitch-Yaw"); Serial.print("\t Yaw Servo: "); Serial.print(servoYaw); Serial.print("\t"); Serial.print("\t Pitch Servo: "); Serial.print(servoPitch); Serial.print("\t"); Serial.print("\t Roll Servo: "); Serial.print(servoRoll); Serial.println(); } // If debug is true, send information over serial if (debug) { Serial.println("Calculated Servo Roll-Pitch-Yaw"); Serial.print("\t roll:"); Serial.print(servoRoll, DEC); Serial.print("\t"); Serial.print("\t pitch:"); Serial.print(servoPitch, DEC); Serial.print("\t"); Serial.print("\t yaw:"); Serial.print(servoYaw, DEC); Serial.println(); } rollServo.write(servoRoll); // Send mapped value to rollServo pitchServo.write(servoPitch); // Send mapped value to rollServo yawServo.write(servoYaw); // Send mapped value to rollServo delay(BNO055_SAMPLERATE_DELAY_MS); // Wait before rerunning loop }

Hughes_BNO055.zip

下面是我的项目:

结论

BNO055是一种易于使用的惯性测量单元,可以纳入各种各样的应用,从机器人稳定(Quadcopter,倒置摆等)到相机稳定和导航(包括死算)。

与输出原始测量数据的其他9-DOF系统不同,BNO055滤波器和合成主机微控制器的数据,从而释放处理器带宽并占据编程中的猜测。

读者 - 如果您希望看到使用季倍的项目或文章,请在下面的评论部分中告知我们。

特色图片提供Adafruit

为自己提供这个项目!BOM。

30评论
  • 基督徒Bianchini 1. 2017年3月23日

    有趣的是,这篇文章展示了这个设备有多好,但没有显示人们的抱怨随着时间的推移漂移和不稳定的校准。

    喜欢的。 回复
    • 马克休斯 2017年3月23日
      @Christian Bianchini 1,谢谢您今天加入网站,让新成员总是很好。从您的评论的基调来看,我假设您拥有传感器并在您的应用程序中遇到困难。你遇到了什么问题和在什么申请中?(我假设您将校准值写入寄存器,而不是将其留在连续校准状态?)。标记
      喜欢的。 回复
  • 尼尔本森 2017年3月25日

    是的,请看,我想查看更多的四元数用法的例子。

    喜欢的。 回复