惯性导航 | 航迹推算与gazebo仿真

惯性导航 | 航迹推算与gazebo仿真

  • IMU数据进行短时间航迹推算
    • 代码
    • gazebo中进行仿真测试

IMU数据进行短时间航迹推算

代码

声明一个用与 IMU积分的类 ,来实现 短时间内的航迹推算

类的名字叫 IMUIntegration
构造函数 有三个变量进行私有变量初始化 重力、初始陀螺仪零偏、初始加速度零偏。

class IMUIntegration {public:IMUIntegration(const Vec3d& gravity, const Vec3d& init_bg, const Vec3d& init_ba): gravity_(gravity), bg_(init_bg), ba_(init_ba) {}

下面是在imu数据一帧一帧进来,如何实现状态的积分,在使用的时候则是来一帧IMU数据,调用一次这个函数
函数名称

void AddIMU(const IMU& imu) {

计算时间间隔,与上一帧IMU数据时间间隔

double dt = imu.timestamp_ - timestamp_;

时间间隔满足要求,间隔时间不能过长

if (dt > 0 && dt < 0.1) {

更新位置,用上一帧的速度与姿态

p_ = p_ + v_ * dt + 0.5 * gravity_ * dt * dt + 0.5 * (R_ * (imu.acce_ - ba_)) * dt * dt;

对应公式:
p j = p k + ∑ k = i j − 1 [ v k △ t + 1 2 g △ t 2 ] + 1 2 ∑ k = i j − 1 R k ( a ~ − b a , k ) △ t 2 p_{j}=p_{k} +\sum_{k=i}^{j-1} [v_{k}\triangle t+\frac{1}{2} g\triangle t^{2} ] +\frac{1}{2}\sum_{k=i}^{j-1}R_{k}(\tilde{a}-b_{a,k})\triangle t^{2} pj=pk+k=ij1[vkt+21gt2]+21k=ij1Rk(a~ba,k)t2

更新速度,用上一帧的姿态

v_ = v_ + R_ * (imu.acce_ - ba_) * dt + gravity_ * dt;

对应公式:
v j = v k + ∑ k = i j − 1 [ R k ( a ~ − b a , k ) △ t + g △ t ] v_{j}=v_{k}+\sum_{k=i}^{j-1}[R_{k}(\tilde{a}-b_{a,k})\triangle t+g\triangle t] vj=vk+k=ij1[Rk(a~ba,k)t+gt]

更新姿态(旋转矩阵)

R_ = R_ * Sophus::SO3d::exp((imu.gyro_ - bg_) * dt);

R j = R i ∏ k = i j − 1 exp ⁡ ( ( ω ~ − b g , k ) △ t ) R_{j}=R_{i}\prod_{k=i}^{j-1} \exp((\tilde{\omega } -b_{g,k})\triangle t) Rj=Rik=ij1exp((ω~bg,k)t)

更新时间,用于判断下一帧数据,在时间间隔上是否满足要求

timestamp_ = imu.timestamp_;

返回有IMU积分的各个航迹状态

    /// 组成NavStateNavStated GetNavState() const { return NavStated(timestamp_, R_, p_, v_, bg_, ba_); }SO3 GetR() const { return R_; }Vec3d GetV() const { return v_; }Vec3d GetP() const { return p_; }

下面是私有变量的声明

   private:// 累计量SO3 R_;Vec3d v_ = Vec3d::Zero();Vec3d p_ = Vec3d::Zero();double timestamp_ = 0.0;// 零偏,由外部设定Vec3d bg_ = Vec3d::Zero();Vec3d ba_ = Vec3d::Zero();Vec3d gravity_ = Vec3d(0, 0, -9.8);  // 重力

gazebo中进行仿真测试

在gazebo中的IMU插件对惯导的噪声描述很简单,仅有一个高斯噪声可以设置。
其中xacro设置的一个例子如下:

     <gazebo reference="imu_base_link"><gravity>true</gravity><sensor name="imu_sensor" type="imu"><always_on>true</always_on><update_rate>200</update_rate><visualize>true</visualize><topic>/jk/imu</topic><plugin filename="libgazebo_ros_imu_sensor.so" name="imu_plugin"><topicName>/jk/imu</topicName>         <bodyName>imu_base_link</bodyName><updateRateHZ>200.0</updateRateHZ>    <gaussianNoise>0.00329</gaussianNoise>   <xyzOffset>0 0 0</xyzOffset>     <rpyOffset>0 0 0</rpyOffset><frameName>imu_base_link</frameName>        </plugin><pose>0 0 0 0 0 0</pose></sensor></gazebo>

其中gaussianNoise噪声参数 可以进行手动设置。

与真实的IMU 噪声模型差别很大,用rotors的imu插件,可以尽可能模拟IMU噪声模型

    <gazebo><plugin filename="librotors_gazebo_imu_plugin.so" name="rotors_gazebo_imu${imu_suffix}_plugin"><robotNamespace>${namespace}</robotNamespace> <!-- (string, required): ros namespace in which the messages are published --><linkName>${namespace}/imu${imu_suffix}_link</linkName> <!-- (string, required): name of the body which holds the IMU sensor --><imuTopic>${imu_topic}</imuTopic> <!-- (string): name of the sensor output topic and prefix of service names (defaults to imu) --><gyroscopeNoiseDensity>${gyroscope_noise_density}</gyroscopeNoiseDensity> <!-- Gyroscope noise density (two-sided spectrum) [rad/s/sqrt(Hz)] --><gyroscopeRandomWalk>${gyroscope_random_walk}</gyroscopeRandomWalk> <!-- Gyroscope bias random walk [rad/s/s/sqrt(Hz)] --><gyroscopeBiasCorrelationTime>${gyroscope_bias_correlation_time}</gyroscopeBiasCorrelationTime> <!-- Gyroscope bias correlation time constant [s] --><gyroscopeTurnOnBiasSigma>${gyroscope_turn_on_bias_sigma}</gyroscopeTurnOnBiasSigma> <!-- Gyroscope turn on bias standard deviation [rad/s] --><accelerometerNoiseDensity>${accelerometer_noise_density}</accelerometerNoiseDensity> <!-- Accelerometer noise density (two-sided spectrum) [m/s^2/sqrt(Hz)] --><accelerometerRandomWalk>${accelerometer_random_walk}</accelerometerRandomWalk> <!-- Accelerometer bias random walk. [m/s^2/s/sqrt(Hz)] --><accelerometerBiasCorrelationTime>${accelerometer_bias_correlation_time}</accelerometerBiasCorrelationTime> <!-- Accelerometer bias correlation time constant [s] --><accelerometerTurnOnBiasSigma>${accelerometer_turn_on_bias_sigma}</accelerometerTurnOnBiasSigma> <!-- Accelerometer turn on bias standard deviation [m/s^2] --></plugin></gazebo>

其中关键参数包括:

  • accelerometer/gyroscopeNoiseDensity 测量噪声
  • accelerometer/gyroscope_random_walk 随机游走

其中发布出来的一包数据如下:

header:
seq: 128
stamp:
secs: 22
nsecs: 290000000
frame_id: “imu_base_link”
orientation:
x: 0.0016563453004138674
y: -0.0008542007888005784
z: 0.006514394955332766
w: 1.001055072733733
orientation_covariance: [1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05]
angular_velocity:
x: 0.0014246123123964744
y: 0.0027524592879204523
z: 0.0007163285834896606
angular_velocity_covariance: [1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05]
linear_acceleration:
x: -0.0029448312010755674
y: -0.00014593761997295991
z: 9.795575703789861
linear_acceleration_covariance: [1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05, 0.0, 0.0, 0.0, 1.08241e-05]

自定义的IMU数据结构体如下:

struct IMU {IMU() = default;IMU(double t, const Vec3d& gyro, const Vec3d& acce) : timestamp_(t), gyro_(gyro), acce_(acce) {}double timestamp_ = 0.0;Vec3d gyro_ = Vec3d::Zero();Vec3d acce_ = Vec3d::Zero();
};

所以需要在IMU的回调函数里面,赋值上面的结构体数据

        sad::IMU imu;imu.timestamp_ = Imu_msg->header.stamp.toSec();imu.gyro_ << Imu_msg->angular_velocity.x,Imu_msg->angular_velocity.y,Imu_msg->angular_velocity.z;imu.acce_ << Imu_msg->linear_acceleration.x,Imu_msg->linear_acceleration.y,Imu_msg->linear_acceleration.z;

然后将数据加入,在该函数内部,即完成航迹的推算

AddIMU(imu);

发布一个里程计数据,来查看航迹推算的结果

        nav_msgs::Odometry imu_Integration_Odom;//声明一个里程计 来记录推算的结果imu_Integration_Odom.header = Imu_msg->header;imu_Integration_Odom.pose.pose.position.x = p_[0];imu_Integration_Odom.pose.pose.position.y = p_[1];imu_Integration_Odom.pose.pose.position.z = p_[2];imu_Integration_Odom.twist.twist.linear.x = v_[0];imu_Integration_Odom.twist.twist.linear.y = v_[1];imu_Integration_Odom.twist.twist.linear.z = v_[2];

将旋转矩阵转成欧拉角单位为度,方便直观查看

        float yaw = atan2(R_.matrix()(1,0), R_.matrix()(0,0));  float roll = atan2(R_.matrix()(2,1), R_.matrix()(2,2));float pitch = atan2(-R_.matrix()(2,0), sqrt(R_.matrix()(0,0) * R_.matrix()(0,0) + R_.matrix()(1,0) * R_.matrix()(1,0)));imu_Integration_Odom.pose.pose.orientation.x = pitch/0.01745329252;imu_Integration_Odom.pose.pose.orientation.y = roll/0.01745329252;imu_Integration_Odom.pose.pose.orientation.z = yaw/0.01745329252;

发布里程计

imu_Integration_Odom_pub_.publish(imu_Integration_Odom);

无人机在地面静止不动情况下
曲线结果数据如下:

  • 位置(很快就飘掉了)
    在这里插入图片描述
  • 速度(与位置类似,越来越大)
    在这里插入图片描述
  • 欧拉角度 (航向角度保持还可以)
    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/725330.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python调用edge-tts实现在线文字转语音

edge-tts是一个 Python 模块&#xff0c;允许通过Python代码或命令的方式使用 Microsoft Edge 的在线文本转语音服务。 项目源码 GitHub - rany2/edge-tts: Use Microsoft Edges online text-to-speech service from Python WITHOUT needing Microsoft Edge or Windows or an…

Docker_设置docker服务以及容器开机自启

本文目录 docker服务开机自启动查询docker服务开机自启动状态将docker服务设置为开机自启动取消docker服务开机自启动 容器开机自启动修改docker容器为自启动容器启动时设置自启动-docker版容器启动时设置自启动-docker-compose版 docker服务开机自启动 查询docker服务开机自启…

33岁大马女星赴港打拼十年终夺「最佳女配」。

近两年有多位「大马女神」在香港走红&#xff0c;最火的莫过于甜美可人、样靓身材正的林明祯&#xff0c;不仅在电影圈有好成绩&#xff0c;还成了广告界的宠儿。 不过说到演技最精湛的「大马女神」&#xff0c;就不得不提近年在香港电影圈炙手可热的廖子妤&#xff0c;前年她凭…

C++_布隆过滤器

目录 1、布隆过滤器的用法 2、布隆过滤器的查找 3、布隆过滤器的删除 4、布隆过滤器的实现 结语 前言&#xff1a; 布隆过滤器是一种概率型数据结构&#xff0c;采用的是哈希思想&#xff0c;他在位图的原有基础上做了升级&#xff0c;因为位图处理不了数据为字符串的情…

安全增强型 Linux

书接上篇 一查看selinux状态 SELinux的状态&#xff1a; enforcing&#xff1a;强制&#xff0c;每个受限的进程都必然受限 permissive&#xff1a;允许&#xff0c;每个受限的进程违规操作不会被禁止&#xff0c;但会被记录于审计日志 disabled&#xff1a;禁用 相关命令…

springboot集成logback打印彩色日志

一、logback介绍 Logback是由log4j创始人设计的另一个开源日志组件,官方网站&#xff1a; logback.qos.ch。它当前分为以下三个模块&#xff1a; logback-core&#xff1a;其它两个模块的基础模块。logback-classic&#xff1a;它是log4j的一个改良版本&#xff0c;同时它完整实…

板级PDN(电源分配网络)设计要点综述

目录 目标阻抗去耦方法 确定目标阻抗 确定目标频点 VRM 去耦电容 安装电感 平面电容 总结 去耦电容 PCB叠层设计 扩展阅读 目标阻抗去耦方法 确定PCB去耦方案的策略是使用频域目标阻抗法&#xff0c;通过层间电容和分立电容器组合的使用&#xff0c;保证电源轨阻抗在…

TypeScript学习笔记(上):TypeScript的介绍、安装及常用类型

我对TypeScript的理解就是&#xff0c;TypeScript是增加了类型校验的JavaScript&#xff0c;能够把运行期错误提升至编译期 TypeScript是什么&#xff1f; TypeScript&#xff08;简称&#xff1a;TS&#xff09;是 JavaScript 的超集&#xff08;JS 有的 TS 都有&#xff09…

【LeetCode】升级打怪之路 Day 15:二叉树解题的思维模式 —— 遍历、分解问题

今日题目&#xff1a; 226. 翻转二叉树101. 对称二叉树114. 二叉树展开为链表 目录 LC 226. 翻转二叉树 【easy】LC 101. 对称二叉树 ⭐⭐⭐LC 114. 二叉树展开为链表 ⭐⭐⭐ 今天的题目主要是对二叉树递归遍历的应用&#xff0c;东哥带你刷二叉树&#xff08;思路篇&#xff0…

谈谈伦敦金操作策略中如何加码

在伦敦金操作策略中应该涉及加码的问题&#xff0c;什么叫加码呢&#xff1f;加码是指一笔伦敦金交易盈利以后&#xff0c;在市场中再注入资金进行加仓。在有利于自己的情况下&#xff0c;我们仓位越重&#xff0c;累积的盈利越多。而且这是在已经盈利的基础上加码&#xff0c;…

Java 学习和实践笔记(28):equals方法的使用

equals() 是Object类里的一个方法。而Object类是所有类的父类&#xff0c;所有的Java对象都拥有Object类的属性和方法。一切类&#xff0c;如果在类的声明中未使用extends&#xff0c;则默认继承Object类。如果声明了&#xff0c;那么Object类就变成该类的父类的父类的...类&am…

python+django高校澡堂洗浴浴室预约签到管理系统8d8c

本系统在设计过程中&#xff0c;高校洗浴管理系统的出现就有很大的需求。该系统可以很好地解决这些麻烦和问题。 很好地发挥了该开发方式的优势&#xff0c;让实现代码有了良好的可读性&#xff0c;而且使代码的更新和维护更加的方便&#xff0c;操作简单&#xff0c;对以后的维…

带你详细理解数组与指针(包含二维数组)

作者博客主页&#xff1a;谦逊码农的旅程 1. sizeof中单独放一个数组名&#xff0c;此时的数组名表示整个数组。 2. &数组名&#xff0c;表示整个数组的地址。 3. 在 C 语言中&#xff0c;变量的地址通常是由一个指针来表示&#xff0c;而指针的大小取决于计算机架构和操…

MySQL·SQL优化

目录 一 . 前言 二 . 优化方法 1 . 索引 &#xff08;1&#xff09;数据构造 &#xff08;2&#xff09;单索引 &#xff08;3&#xff09;explain &#xff08;4&#xff09;组合索引 &#xff08;5&#xff09;索引总结 2 . 避免使用select * 3 . 用union all代替u…

Linux之cd、pwd、mkdir 命令

cd命令&#xff0c;切换目录 1&#xff09;当Linux终端&#xff08;命令行&#xff09;打开的时候&#xff0c;会默认以用户的HOME目录作为当前的工作目录。 2&#xff09;我们可以通过cd命令&#xff0c;更改当前所在的工作目录。 3&#xff09;cd命令来自英文&#xff1a;C…

使用nvidia-ml-py事实监控GPU状态

平时监控GPU状态最常用的是watch配合nvidia-smi指令&#xff0c;但有时可能不仅仅需要监控&#xff0c;还需要记录状态数据&#xff0c;比如GPU的显存变化以及利用率变化等等。本文提供了一个使用nvidia-ml-py包编写的简易Demo&#xff0c;该Demo能够实现简易版的nvidia-smi功能…

C++之获取Windows系统信息

目录 1. 操作系统版本 2. 获取CPU信息 3. 获取内存信息 4. 获取硬盘信息 5.获取网络接口信息 6.获取计算机名称、用户名 在C中&#xff0c;你可以使用Windows API函数来获取Windows系统的各种信息。以下是一些常见的API函数和示例代码&#xff0c;用于获取Windows系统信息…

STM32使用标准库编写外部时钟控制oled显示计数(proteus仿真)

这节课的结果是在上节课的基础上更改的&#xff1a;电路图为&#xff1a;用一个开关来模拟外部时钟的高低电平的变化。 当然也可以配置一个外部时钟来模拟&#xff0c;也是可以的&#xff1a; 由于这节课的代码是在上节课的基础上有一点修改而来的&#xff0c;所以就只把更改的…

【python高级编程教程】笔记(python教程、python进阶)第三节:(1)多态与鸭子类型(Polymorphism and Duck Typing)

参考文章1&#xff1a;【比刷剧还爽】清华大佬耗时128小时讲完的Python高级教程&#xff01;全套200集&#xff01;学不会退出IT界&#xff01; 参考文章2&#xff1a;清华教授大力打造的Python高级核心技术&#xff01;整整100集&#xff0c;强烈建议学习&#xff08;Python3…

C++_程序流程结构_跳转语句_break

break 作用 用于跳出选择结构或循环结构 break使用的时机 出现在switch条件语句中&#xff0c;作用是终止case并跳出switch出现在循环语句中&#xff0c;作用是跳出当前的循环语句出现在嵌套循环中&#xff0c;跳出最近的内层循环语句 示例1 示例2 示例3