草庐IT

六轴陀螺仪简介及在智能车中的应用

DoTheTran 2023-06-18 原文

一、陀螺仪简介

实验室常用的两种陀螺仪:
mpu6050
icm20602

不管是ICM还是MPU,精度都能达到要求。

陀螺仪是感受空间姿态的传感器,是控制小车平衡,判断和调节姿态的核心元件。
六轴陀螺仪结合了三轴陀螺仪和三轴加速度计,其“六轴”分别为加速度xyz轴,角速度xyz轴,即既能感知角度变化,也能感知加速度变化,这六个量经过运算,可以返回三个姿态角:
俯仰角(车头绕Y轴翘起角度),

航向角(车身绕Z轴旋转角度),

翻滚角(侧轮绕X轴抬起角度)。

陀螺仪在竞速智能车中的主要作用有以下几点:

  1. 与转向环串级使用,与Z轴角速度关联,增加转向力度;
  2. 调整平衡车姿态,使车身平衡且能正常转向和前进
  3. 角度环闭环控制的输入,比如过三叉路打60度角;
  4. 判断车身姿态,调整状态。比如感知过环岛的角度变化;感知翻车,进行保护;
  5. 温度传感器,电机高温报警(陀螺仪一般离电机较近,自身带有温度传感器)

二、基本的使用方法

六轴陀螺仪结合了三轴角速度计和三轴加速度计。

1.角速度计

角速度计返回的数据实际上是弧度制的角速度,旋转陀螺仪时,返回相应轴的角速度参考量。一般我们要对角速度积分得到角度,用起来直观方便。积分得到的角度是相对角度,开始积分时的姿态即为参考0角度。
对于2ms的积分值为0.000124左右,实际使用时需要调整,将陀螺仪转动一周,计算得到的角度应为360。

/***放于定时器中2ms执行一次***/
fun()
{
	Angle_yaw += GZ * 0.00012480f;
}

积分总会带来误差,随着时间不断增加。另外,陀螺仪还存在零点漂移现象,即车静置时会输出非0的角速度值, 每次上电时需要重新校准偏移值,或者定期校准,后续检测时减去偏移值即可消除此误差。

float GX_Zero = -11.5;//零点偏移值
float GY_Zero = 6;
float GZ_Zero = -1;
......
GX = gx0 - GX_Zero; //去零漂之后的陀螺仪采集值
GY = gy0 - GY_Zero;
GZ = gz0 - GZ_Zero;

2.加速度计

加速计返回的加速度并不是一般意义的加速度。 加速度计相当于一个重锤在中间的弹簧系统,四面八方有弹簧撑着它。平放在桌面时,有的弹簧被拉长,有的被压扁。变化时,不同的弹簧受到不同的压缩,从而侦测出不同方向的力。因此实际上静止不动时也会产生由于重力引起的“加速度”数值。注意这个“加速度”并不稳定,由于车模本身的摆动所产生的加速度会产生很大的干扰信号,因此不宜过于信赖这个数值。

只用加速度计就能得到车身的俯仰角,且是对地的绝对角度。摆动加速度计时,对应轴的重力加速度分量改变,利用反三角函数即可求出角度的变化。但因为加速度计的不稳定,叠加在重力测量信号上使输出信号不能很好的反映车模的倾角。

#include <math.h>
fun()
{
	angle_ratio = (double)(AX / (AZ + 0.1));//+0.1防止分母为0
	Angle_acc = (float)(atan(angle_ratio) * 57.29578049); 
	//加速度计得到的角度  57.3=180/3.14
}

三、更精确的数据处理

因为数据存在误差、不稳定、有零漂,因此需要对数据进行处理。

1.滤波

输入级使用算数平均滤波就可以,取十次求平均一般比较稳定。如果要使用加速度,可以再加一个系数比较小的低通滤波。
角速度记得去掉零点偏移值。

2.角度融合

角速度积分得到的角度比较稳,但会随时间慢慢漂移且只反映变化量;加速度取反三角函数得到的角度不稳,但跟随真实角度,且是对地的绝对角度。
平衡车整个过程都要用到角度这个变量,单纯角速度积分带来的漂移偏差不可忽视,而且参考点不好确定,所以需要用角度融合,将两者得出的角度进行滤波融合,取长补短,就能得到比较可靠的角度。

角度融合滤波的方法比较常用的有:互补滤波、二阶互补滤波、卡尔曼滤波、清华滤波、四元数滤波。
以下为互补滤波程序

/***互补滤波角度计算***/
void AngleGet(void
{
        float dt = 0.0001249;//Gy 2ms时间积分系数
        double angle_ratio;//加速度比值
        Anglefiltering();//入口滤波,算数平均

         /***以下为加速度计取反正切得到角度***/
        angle_ratio=((double)ax)/(az+0.1);
        Angle_acc=(float)atan(angle_ratio)*57.29578049;//加速度计得到的角
        if(Angle_acc > 89)
          Angle_acc = 89;
        if(Angle_acc < -89)
          Angle_acc = -89;
        
         /***以下为角速度计积分,同融合加速度,得到角度***/
        Gy = (float)(gy)
        GY = Gy -GY_Zero; //去零漂之后的陀螺仪采集值

        Angle = (float)(Angle-(float)(GY * dt));
        Angle = Angle + (Angle_acc-Angle)*0.001; 
		//相当于Angle = Angle*(1-0.00105) + Angle_acc*0.001
}

最后两条语句是最关键的部分,简单解释一下:
当前值(陀螺仪)=上次值+角速度微分值
当前值(融合)=当前值(陀螺仪)*(1-a) - 当前值(加速度)*a (a为权重)

陀螺仪积分得到的角度稳定,加速度得到的角度最接近真实值
以陀螺仪积分算出来的角度为主导,用加速度得到的角度作纠正,防止角度误差随时间不断累计

“a”要调到什么状态呢?让角度既要跟随真实角度,不能太滞后,又不能有太大波动

互补滤波的调试过程可以看这个视频
https://www.bilibili.com/video/BV1Y541177rD。
不管是互补滤波还是四元数滤波,拿到后都需要重新调参,车不一样参数也不一样。
车刚开始启动时要注意,如果用融合算法得到角度值,会有从值比较小的角速度积分,逐渐过渡到真实值的过程,持续时间大概在0.3s到1s,因此刚启动的这段时间用融合角度不合适,而只用加速度取反三角函数得到的角度更真实。

/***以下函数放于定时器中2ms执行一次***/
void Angle_get(void)
{
  static int angle_start_flag = 0;//刚开始,单独使用加速度标志
  double angle_ratio = 0; //加速度比值
  static float Angle_acc_last = 0;

	*******(滤波过程略)

	/***以下为刚开始时的加速度角度单独处理***/
  {
    Angle_acc_last = Angle_acc;
    angle_ratio = (double)(a_x / (a_z + 0.1));
    Angle_acc = (float)(atan(angle_ratio) * 57.29578049); //加速度计得到的角度

    if (angle_start_flag == 0) //低通限幅滤波
    {
      Angle_acc_last = Angle_acc;
    }
    Angle_acc = 0.5 * Angle_acc + 0.5 * Angle_acc_last;
    if (Angle_acc > 89)
      Angle_acc = 89;
    if (Angle_acc < -89)
      Angle_acc = -89;
  }

	*******(融合过程略)

  if (angle_start_flag < 300) //刚开始运行的0.6s时,取加速度轴得到的角度
  {
    Angle = Angle_acc;//加速度得到的角度
    angle_start_flag++;
  }
  else
  {
    Angle = pitch;//融合后的结果
  }
}

若只是暂时利用角度处理别的东西,比如用来计算入环岛360度角度,入三叉60度角度,用角速度积分足够了。 计算周期为2ms的积分系数大概是0.0124,慢跑跟剧烈晃动的跑积分出来的角度值有小偏差,因此不要太过信赖这个角度。

有关六轴陀螺仪简介及在智能车中的应用的更多相关文章

  1. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

    总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

  2. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

  3. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  4. ruby-on-rails - Rails 3 中的多个路由文件 - 2

    Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

  5. ruby - 将差异补丁应用于字符串/文件 - 2

    对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl

  6. ruby-on-rails - Rails - 一个 View 中的多个模型 - 2

    我需要从一个View访问多个模型。以前,我的links_controller仅用于提供以不同方式排序的链接资源。现在我想包括一个部分(我假设)显示按分数排序的顶级用户(@users=User.all.sort_by(&:score))我知道我可以将此代码插入每个链接操作并从View访问它,但这似乎不是“ruby方式”,我将需要在不久的将来访问更多模型。这可能会变得很脏,是否有针对这种情况的任何技术?注意事项:我认为我的应用程序正朝着单一格式和动态页面内容的方向发展,本质上是一个典型的网络应用程序。我知道before_filter但考虑到我希望应用程序进入的方向,这似乎很麻烦。最终从任何

  7. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  8. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  9. ruby - 无法运行 Rails 2.x 应用程序 - 2

    我尝试运行2.x应用程序。我使用rvm并为此应用程序设置其他版本的ruby​​:$rvmuseree-1.8.7-head我尝试运行服务器,然后出现很多错误:$script/serverNOTE:Gem.source_indexisdeprecated,useSpecification.Itwillberemovedonorafter2011-11-01.Gem.source_indexcalledfrom/Users/serg/rails_projects_terminal/work_proj/spohelp/config/../vendor/rails/railties/lib/r

  10. ruby-on-rails - Rails 应用程序中的 Rails : How are you using application_controller. rb 是新手吗? - 2

    刚入门rails,开始慢慢理解。有人可以解释或给我一些关于在application_controller中编码的好处或时间和原因的想法吗?有哪些用例。您如何为Rails应用程序使用应用程序Controller?我不想在那里放太多代码,因为据我了解,每个请求都会调用此Controller。这是真的? 最佳答案 ApplicationController实际上是您应用程序中的每个其他Controller都将从中继承的类(尽管这不是强制性的)。我同意不要用太多代码弄乱它并保持干净整洁的态度,尽管在某些情况下ApplicationContr

随机推荐