mingzhe123 发表于 2024-12-1 12:14

【Follow me第二季第4期】任务二:学习IMU基础知识,调试IMU传感器,通过串口打印...

本帖最后由 mingzhe123 于 2024-12-1 12:16 编辑

<p><span style="font-size:18px;"><strong>IMU原理及选型介绍</strong></span></p>

<p>所谓IMU(Inertial Measurement Unit)是指惯性测量单元,利用惯性的变化测量物体加速运动和旋转。其中目前主流的惯性测量器件是MEMS(微机电)传感器,它将用于机械结构缩小至纳米尺度,可测量机器人加速度与旋转角速度。后面讨论的内容应该可以归为捷联式惯导系统(Strapdown Inertial Navigation System),即测量单元直接安装于被测物体上,与平台式惯导系统区别开来。</p>

<p>需要注意的是,IMU或者说六轴(6Dof)传感器讨论的是三轴加速度计和三轴角速度计(俗称陀螺仪),与AHRS(航姿参考系)或者说9轴(9Dof)传感器是有区别的,后者增加了磁力计,以地磁场作为参考。但是在地面机器人运动并且夹杂大量电机磁干扰的情况下,引入微弱的地磁作为绝对航向并不是一个好主意。</p>

<h3 id="原理">原理</h3>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>当物体运动的惯性改变时,根据牛顿第二定律实际上物体内部会有相对的作用力,我们可以想象一个加速度计的结构如上图,在整个系统加速或减速时弹簧会有不同程度的伸长或压缩,通过测量弹簧的所连接的物体的位移可以测量出实际加速度的大小,当然这其中也包含重力加速度。在目前MEMS工艺制造的传感器中这些结构都被缩得非常小,以至于测量的位置可以视为被缩在同一点上。</p>

<p>而角速度计的原理类似,但是测量原理是令质量块不断在轴的径向上产生移动,探测其切向偏移测量科氏力大小,从而推出角速度的大小。</p>

<h3 id="性能">性能</h3>

<p>通常情况下,这两种传感器都有一般传感器所拥有的性能指标,例如不论是机械制造的误差还是A/D采样带来的偏置,满刻度误差,以及采样数据的噪声还有抗震性能,当然这些也会受到温度和输入电压的影响。有些误差的校正会在后续的校准中提到。</p>

<h2 id="IMU参数">IMU参数</h2>

<p>作为一种电子元器件,基本的参数都可以在其数据手册(datasheet)中查到,这些参数说明了IMU的性能范围,可以为选型提供参考,这里列举一些常用的参数</p>

<ul>
        <li><strong>量程和灵敏度</strong>(sensitivity):代表最大角速度或加速度范围和取样精度,通常有数字接口的IMU都会有这项</li>
        <li><strong>敏感度温漂</strong>(sensitivity change over temperature/ sensitivity temperature drift):敏感度随温度的改变,通常用百分比或者FS/K(满刻度每度)</li>
        <li><strong>零偏</strong>(zero-rate offset/level):IMU中尤其针对角速度计的一个重要参数,它代表了角速度计/加速计在静止时仍然输出的大小,是后续IMU校准中重点讨论的参数。我们希望它越小越好,以避免积分时带来的累计误差。通常目前IMU给出的典型值都是在1deg/s以上。</li>
        <li><strong>温度漂移</strong>(zero-rate offset change over temperature):零偏随温度改变的大小,同样是角速度计的重要参数,越小代表IMU的零偏随温度影响越小。</li>
        <li><strong>噪声系数</strong>(noise):代表输出噪声与带宽的关系,单位一般为(ug/&radic;Hz或者dps/&radic;Hz),直观的说就是影响对真实信号的辨识程度。</li>
        <li><strong>交叉轴敏感度</strong>(cross-axis sensitivity):通常情况下三个轴的输出应该都是独立的,但实际上可能出现跨轴影响输出的现象,这个参数就是用于衡量各轴之间的影响程度</li>
        <li><strong>加速度敏感度</strong>(g-sensitivity):角速度计特有的参数,用于衡量加速度对角速度计输出的影响大小,通常单位为dps/g</li>
        <li><strong>零偏不稳定性</strong>:主要针对角速度计的参数,代表零偏在较长时间下的随机游走</li>
</ul>

<h2 id="IMU选型">IMU选型</h2>

<p>目前可以找到的IMU厂商有以下几个:</p>

<ul>
        <li><a href="https://invensense.tdk.com/" rel="noopener" target="_blank">TDK InvenSense</a>:MEMS加速度计,角速度计,磁力计,六轴/九轴厂商,有广泛使用的IMU MPU6050,价位中等(也有更贵的高性能的ICM系列)</li>
        <li><a href="https://www.st.com/en/mems-and-sensors/inemo-inertial-modules.html" rel="noopener" target="_blank">ST(意法半导体)</a>:MEMS加速度计,角速度计以及六轴厂商,主要为智能手机市场提供IMU,例如有LSM6DS3TR,价位偏低</li>
        <li><a href="https://www.bosch-sensortec.com/products/motion-sensors/" rel="noopener" target="_blank">Bosch(博世)</a>:MEMS加速度计,角速度计,磁力计,六轴/九轴厂商,主要为机器人和无人机市场提供IMU,六轴传感器的有BMI系列,价位偏高</li>
        <li><a href="https://www.analog.com/cn/parametricsearch/11172#/" rel="noopener" target="_blank">ADI</a>:老牌半导体公司,有加速度计和六轴,主要用于汽车和军事领域,性能最高但价位也是极高。当然也有低端的加速计ADXL35x系列</li>
        <li><a href="http://www.qstcorp.com/101/" rel="noopener" target="_blank">QST(上海矽睿)</a>:磁力计,加速度计以及六轴的国产厂商,有QMI8658/QMI8610等六轴传感器</li>
</ul>

<p>选型过程自然要比较性能,当然主要看零偏,温漂以及噪声。考虑到价格因素,ADI的六轴这个选项基本可以舍弃。高性能的一档有ICM4x6xx,BMI0xx,QMI86xx和LSM6Dx的性能略逊一筹。</p>

<p>截止目前,已知官方有库存的只有ST和QST。在疫情的背景下,选用国产的IMU或许更能确保稳定供应。</p>

<p><span style="font-size:18px;"><strong><u>Arduino</u>&nbsp;Nano RP2040 Connect&nbsp; --&nbsp; LSM6DSOX</strong></span></p>

<p>开发板使用的是LSM6DSOXTR是一款高性能的6轴惯性测量单元(IMU),由STMicroelectronics(意法半导体)制造。集成了3轴数字加速度计和3轴数字陀螺仪,采用系统级封装技术,具有出色的性能和低功耗特性。提供SPI、I&sup2;C和MIPI I3C串行接口,支持主处理器数据同步。是一款功能强大、性能卓越的6轴IMU。其手册特征如下图所示。意法半导体为其封装了传感器专用库-<a href="https://github.com/stm32duino/X-NUCLEO-IKS01A3" style="font-family:&quot;Open Sans&quot;, &quot;Lucida Grande&quot;, lucida, verdana, sans-serif; box-sizing:inherit; scrollbar-color:var(--color-scrollbar-body) transparent; scrollbar-width:thin; font-size:1rem; font-weight:600 !important; letter-spacing:0.01em; color:var(--color-accent-4); cursor:pointer; font-style:normal; text-decoration:none; transition:color 0.2s ease-out; 27.2px">STM32duino X-NUCLEO-IKS01A3</a>库,使用Arduino编程只需调用其库即可。</p>

<p> &nbsp;</p>

<p><strong><span style="font-size:18px;">IMU编程与调试</span></strong></p>

<p><b><a href="https://www.digikey.cn/zh/products/detail/arduino/ABX00052/14123941" target="_blank">Arduino&reg; Nano RP2040 Connect</a>代码:</b></p>

<pre>
<code class="language-cpp">
/* WIRING
In order to use the Adafruit lsm6dsox sensor with a ST nucleo board,
plug Nucleo "+3.3V" to AdafruitLSM6DOX "VIN",
plug Nucleo "GND" to AdafruitLSM6DOX "GND",
plug Nucleo "SCL"(D15) to AdafruitLSM6DOX "SCL",
plug Nucleo "SDA"(D14) to AdafruitLSM6DOX "SDA".*/

#include "LSM6DSOXSensor.h"
#include &lt;Arduino.h&gt;
// Declare LSM6DSOX sensor. Sensor address can have 2 values LSM6DSOX_I2C_ADD_L (corresponds to 0x6A I2C address) or LSM6DSOX_I2C_ADD_H (corresponds to 0x6B I2C address)
// On Adafruit lsm6dsox sensor, LSM6DSOX_I2C_ADD_L is the default address
LSM6DSOXSensor lsm6dsoxSensor = LSM6DSOXSensor(&amp;Wire, LSM6DSOX_I2C_ADD_L);

int flag;
longlast_update_time;


// Timer variables
unsigned long lastTime = 0;
unsigned long timerDelay = 1000;

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

Serial1.begin(115200); // opensserial port, sets data rate to 115200 bps
while(Serial1.read()&gt;= 0){}//clear serialbuffer

pinMode(LED_BUILTIN,OUTPUT);

digitalWrite(LED_BUILTIN,LOW);

Wire.begin();

// Default clock is 100kHz. LSM6DSOX also supports 400kHz, let's use it
Wire.setClock(400000);

// Init the sensor
lsm6dsoxSensor.begin();

// Enable accelerometer and gyroscope, and check success
if (lsm6dsoxSensor.Enable_X() == LSM6DSOX_OK &amp;&amp; lsm6dsoxSensor.Enable_G() == LSM6DSOX_OK) {
    Serial.println("Success enabling accelero and gyro");
} else {
    Serial.println("Error enabling accelero and gyro");
}

// Read ID of device and check that it is correct
uint8_t id;
lsm6dsoxSensor.ReadID(&amp;id);
if (id != LSM6DSOX_ID) {
    Serial.println("Wrong ID for LSM6DSOX sensor. Check that device is plugged");
} else {
    Serial.println("Receviced correct ID for LSM6DSOX sensor");
}

// Set accelerometer scale at +- 2G. Available values are +- 2, 4, 8, 16 G
lsm6dsoxSensor.Set_X_FS(2);

// Set gyroscope scale at +- 125 degres per second. Available values are +- 125, 250, 500, 1000, 2000 dps
lsm6dsoxSensor.Set_G_FS(125);


// Set Accelerometer sample rate to 208 Hz. Available values are +- 12.0, 26.0, 52.0, 104.0, 208.0, 416.0, 833.0, 1667.0, 3333.0, 6667.0 Hz
lsm6dsoxSensor.Set_X_ODR(208.0f);


// Set Gyroscope sample rate to 208 Hz. Available values are +- 12.0, 26.0, 52.0, 104.0, 208.0, 416.0, 833.0, 1667.0, 3333.0, 6667.0 Hz
lsm6dsoxSensor.Set_G_ODR(208.0f);


}


void IMU_update(int interval)
{
// Read accelerometer
uint8_t acceleroStatus;
lsm6dsoxSensor.Get_X_DRDY_Status(&amp;acceleroStatus);
if (acceleroStatus == 1) { // Status == 1 means a new data is available
    int32_t acceleration;
    lsm6dsoxSensor.Get_X_Axes(acceleration);
    // Plot data for each axis in mg
    Serial.print("AccelerationX=");

    Serial.print(acceleration);

    Serial.print("mg, AccelerationY=");

    Serial.print(acceleration);

    Serial.print("mg, AccelerationZ=");

    Serial.print(acceleration);
    Serial.println("mg");


    if (millis() - last_update_time &gt; interval)
          {
                  if (acceleration &gt; 1000)
                  {
                        //encoder_diff--;
                        flag = 1;
      Serial.print("flag=1");
      Serial1.write(49);
      digitalWrite(LED_BUILTIN,LOW);
                  }
                else if (acceleration &lt; -1000)
                {
                //        encoder_diff++;
                        flag = 2;
      Serial.print("flag=2");
      Serial1.write(50);
      digitalWrite(LED_BUILTIN,HIGH);
                }
                else
                {
                        flag = 0;
                }

                last_update_time = millis();
          }
}

       

// Read gyroscope
uint8_t gyroStatus;
lsm6dsoxSensor.Get_G_DRDY_Status(&amp;gyroStatus);
if (gyroStatus == 1) { // Status == 1 means a new data is available
    int32_t rotation;
    lsm6dsoxSensor.Get_G_Axes(rotation);
    // Plot data for each axis in milli degrees per second
    Serial.print("RotationX=");

    Serial.print(rotation);

    Serial.print("mdps, RotationY=");

    Serial.print(rotation);

    Serial.print("mdps, RotationZ=");

    Serial.print(rotation);
    Serial.println("mdps");
}

}


void loop() {


IMU_update(200);

}</code></pre>

<p><strong>PICO2端代码:</strong></p>

<pre>
<code class="language-cpp">int val;



void setup() {



  Serial1.setRX(17);

  Serial1.setTX(16);

  Serial1.begin(115200); // opensserial port, sets data rate to 9600 bps  

  while(Serial.read()&gt;= 0){}//clear serialbuffer

  pinMode(25,OUTPUT);



}



void loop() {



   if (Serial1.available() &gt; 0) {

    delay(100); // 等待数据传完

    int numdata = Serial1.available();

    val=Serial1.read();

    Serial1.println(val);

    if(val==49)

    {

      Serial.println("Test OK");

      Serial.println(val);



     // delay(2000);

      digitalWrite(25, LOW);

    }

    if(val==50)

    {

      Serial.println("Test OK!!!");

      Serial.println(val);



      digitalWrite(25, HIGH);



    }

    while(Serial1.read()&gt;=0){} //清空串口缓存

  }

     




}</code></pre>

<p>上位机打印的IMU数据:</p>

<p><strong><span style="font-size:18px;">&nbsp; 总结:</span></strong></p>

<p><span style="font-size: 18px;"><b>&nbsp; </b></span>实现IMU的控制与数据读取还是十分简单的,只需调用官方Arduino库即可,这大大降低了开发者的开发难度。</p>

<p><span style="font-size: 18px;"><b>&nbsp; 演示视频:</b></span></p>

<p>&nbsp; &nbsp;32888557c56d34de4aa82d0d0364dcf8<br />
&nbsp;</p>

mingzhe123 发表于 2024-12-1 12:18

视频中应该是调用意法半导体官方的arduino库https://github.com/stm32duino

秦天qintian0303 发表于 2024-12-2 09:35

<p>IMU厂商,你这都是大厂啊&nbsp;&nbsp;</p>
页: [1]
查看完整版本: 【Follow me第二季第4期】任务二:学习IMU基础知识,调试IMU传感器,通过串口打印...