当前位置: 首页 > news >正文

基于飞迪RTK/INS组合导航模组的里程计发布方法

文章目录

  • 概要
  • 解算过程
    • 获取初始化点
    • 经纬度坐标系转UTM
    • 计算航向角
    • 发布odom坐标
  • 完整代码

概要

这篇博客主要介绍,如何将GPS_fix、磁偏角转成odom信息。
PS:官方的驱动包中是自带odom信息,但是对于原点的定义尚未找到出处,故自己另外写了一套发布odom信息。

解算过程

获取初始化点

第一个获取的GPS_fix点为初始点

initPose.latitude = gpsFix->latitude;
initPose.longitude = gpsFix->longitude;
initPose.altitude = 0;
init = true;

经纬度坐标系转UTM

/*原点经纬度转UTM*/
geographic_msgs::GeoPoint gpInit;
gpInit.latitude = initPose.latitude;
gpInit.longitude = initPose.longitude;
geodesy::UTMPoint ptInit(gpInit);
initX = ptInit.easting;
initY = ptInit.northing;

计算航向角

记得减去当地的磁偏角,在这个网站进行查询。

tf::Quaternion qua;
tf::quaternionMsgToTF(odomMsg->pose.pose.orientation, qua);
double roll, pitch, yaw;//定义存储roll,pitch and yaw的容器
tf::Matrix3x3(qua).getRPY(roll, pitch, yaw); //进行转换
yaw = yaw - 0.5 * M_PI + MagDec / 180.0 * M_PI;

发布odom坐标

  /***publish gps_odom**/
nav_msgs::Odometry odom;
odom.header.stamp = ros::Time::now();
odom.header.frame_id = "odom";
odom.pose.pose.position.x = fixX - initX;
odom.pose.pose.position.y = fixY - initY;
odom.pose.pose.orientation.x=qua.x();
odom.pose.pose.orientation.y=qua.y();
odom.pose.pose.orientation.z=qua.z();
odom.pose.pose.orientation.w=qua.w();        
gpsOdomPub.publish(odom);

完整代码

#include <ros/ros.h>
#include "turtlesim/Pose.h"
#include <sensor_msgs/NavSatFix.h>
#include <geometry_msgs/PoseStamped.h>
#include <geometry_msgs/PolygonStamped.h>
#include <geometry_msgs/QuaternionStamped.h>
#include <geographic_msgs/GeoPoseStamped.h>
#include <geodesy/utm.h>
#include <nav_msgs/Odometry.h>
#include <nav_msgs/Path.h>
#include <math.h>
#include <message_filters/synchronizer.h>
#include <message_filters/subscriber.h>
#include <message_filters/sync_policies/approximate_time.h>
#include <message_filters/time_synchronizer.h>
#include <boost/thread/thread.hpp>
#include <iostream>//全局变量
static double EARTH_RADIUS = 6378.137;//地球半径class OdomPublisher
{public:OdomPublisher();void gpsCallback(const sensor_msgs::NavSatFixConstPtr& gpsFix,const nav_msgs::Odometry::ConstPtr& odomMsg);double rad(double d);private:ros::Publisher state_pub_, smallCarPub, gpsOdomPub;geometry_msgs::PolygonStamped carPolygon;nav_msgs::Path ros_path_;ros::NodeHandle n, nhPrivate;message_filters::Subscriber<sensor_msgs::NavSatFix> *subGPS;message_filters::Subscriber<nav_msgs::Odometry> *subOdom;typedef message_filters::sync_policies::ApproximateTime<sensor_msgs::NavSatFix, nav_msgs::Odometry> syncPolicy;message_filters::Synchronizer<syncPolicy> *sync;bool init;struct my_pose{double latitude;double longitude;double altitude;};my_pose initPose, fixPose;double initX, initY, MagDec;std::string gpsFixTopic, gpsOdomTopic, gpsOdomPubTopic;
};OdomPublisher::OdomPublisher():nhPrivate("~")
{    ROS_INFO("Initialization");nhPrivate.param("gpsFixTopic", gpsFixTopic, std::string("/gps/fix"));nhPrivate.param("gpsOdomTopic", gpsOdomTopic, std::string("/odom"));nhPrivate.param("gpsOdomPubTopic", gpsOdomPubTopic, std::string("/gps_fix/odom"));nhPrivate.getParam("MagDec", MagDec);subGPS = new message_filters::Subscriber<sensor_msgs::NavSatFix> (n, gpsFixTopic.c_str(), 1);subOdom = new message_filters::Subscriber<nav_msgs::Odometry> (n, gpsOdomTopic.c_str(), 1);sync = new message_filters::Synchronizer<syncPolicy> (syncPolicy(10), *subGPS, *subOdom);sync->registerCallback(boost::bind(&OdomPublisher::gpsCallback, this, _1, _2));state_pub_ = n.advertise<nav_msgs::Path>("/trajectory/gps", 10);smallCarPub = n.advertise<geometry_msgs::PolygonStamped>("/trajectory/car", 10);gpsOdomPub = n.advertise<nav_msgs::Odometry>(gpsOdomPubTopic.c_str(),10);			init = false;
}//角度制转弧度制
double OdomPublisher::rad(double d) 
{return d * 3.1415926 / 180.0;
}void OdomPublisher::gpsCallback(const sensor_msgs::NavSatFixConstPtr& gpsFix,const nav_msgs::Odometry::ConstPtr& odomMsg)
{// ROS_INFO_STREAM("Starting to work!!!");// std::cout << "Starting to work!!!" << std::endl;//初始化if(!init){initPose.latitude = gpsFix->latitude;initPose.longitude = gpsFix->longitude;initPose.altitude = 0;init = true;/*原点经纬度转UTM*/geographic_msgs::GeoPoint gpInit;gpInit.latitude = initPose.latitude;gpInit.longitude = initPose.longitude;geodesy::UTMPoint ptInit(gpInit);initX = ptInit.easting;initY = ptInit.northing;}else{geographic_msgs::GeoPoint gp;gp.latitude = gpsFix->latitude;gp.longitude = gpsFix->longitude;geodesy::UTMPoint pt(gp);double fixX = pt.easting;double fixY = pt.northing;tf::Quaternion qua;tf::quaternionMsgToTF(odomMsg->pose.pose.orientation, qua);double roll, pitch, yaw;//定义存储roll,pitch and yaw的容器tf::Matrix3x3(qua).getRPY(roll, pitch, yaw); //进行转换yaw = yaw - 0.5 * M_PI + MagDec / 180.0 * M_PI;qua.setRPY(0,0,yaw);// ROS_INFO("After optmized, yaw is %f", yaw);/***publish gps_odom**/nav_msgs::Odometry odom;odom.header.stamp = ros::Time::now();odom.header.frame_id = "odom";odom.pose.pose.position.x = fixX - initX;odom.pose.pose.position.y = fixY - initY;odom.pose.pose.orientation.x=qua.x();odom.pose.pose.orientation.y=qua.y();odom.pose.pose.orientation.z=qua.z();odom.pose.pose.orientation.w=qua.w();        gpsOdomPub.publish(odom);ros_path_.header.frame_id = "odom";ros_path_.header.stamp = ros::Time::now();  geometry_msgs::PoseStamped pose;pose.header = ros_path_.header;pose.pose.position = odom.pose.pose.position;ros_path_.poses.push_back(pose);state_pub_.publish(ros_path_);}
}int main(int argc,char **argv)
{ros::init(argc,argv,"gps_fix");OdomPublisher op;ros::spin();return 0;
}

相关文章:

  • centos7.9 postgresql 16.0 源码安装部署
  • MySQL进阶_5.逻辑架构和SQL执行流程
  • 数据结构(c语言版) 栈
  • 互联网系统安全(一)
  • 小程序员 scroll滚动与页面滚动冲突造成快速滑到底部卡顿失败问题
  • 蓝桥杯官网填空题(激光样式)
  • C#解析XML并反序列化为Model的方法
  • ubuntu20.04 安装cudnn
  • 单链表(3)
  • 成绩公布方式,这样操作更方便
  • 十三、W5100S/W5500+RP2040树莓派Pico<FTP Server>
  • ActiveMq学习⑨__基于zookeeper和LevelDB搭建ActiveMQ集群
  • 论文阅读:Ensemble Knowledge Transfer for Semantic Segmentation
  • 阿里云99元服务器2核2G3M带宽_4年396元_新老用户均可
  • VScode + opencv + c++ + win配置教程
  • “大数据应用场景”之隔壁老王(连载四)
  • ES6 ...操作符
  • es6要点
  • github从入门到放弃(1)
  • MySQL的数据类型
  • php ci框架整合银盛支付
  • vue:响应原理
  • 闭包,sync使用细节
  • 从@property说起(二)当我们写下@property (nonatomic, weak) id obj时,我们究竟写了什么...
  • 构造函数(constructor)与原型链(prototype)关系
  • 汉诺塔算法
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 学习使用ExpressJS 4.0中的新Router
  • 第二十章:异步和文件I/O.(二十三)
  • 扩展资源服务器解决oauth2 性能瓶颈
  • 新年再起“裁员潮”,“钢铁侠”马斯克要一举裁掉SpaceX 600余名员工 ...
  • ​io --- 处理流的核心工具​
  • ​卜东波研究员:高观点下的少儿计算思维
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (SpringBoot)第二章:Spring创建和使用
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (附源码)springboot车辆管理系统 毕业设计 031034
  • (附源码)springboot码头作业管理系统 毕业设计 341654
  • (机器学习-深度学习快速入门)第一章第一节:Python环境和数据分析
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)程序员疫苗:代码注入
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .Net(C#)常用转换byte转uint32、byte转float等
  • .NET开源的一个小而快并且功能强大的 Windows 动态桌面软件 - DreamScene2
  • .NET框架类在ASP.NET中的使用(2) ——QA
  • .vue文件怎么使用_vue调试工具vue-devtools的安装
  • @FeignClient注解,fallback和fallbackFactory
  • @RequestBody与@ModelAttribute
  • [Android] Amazon 的 android 音视频开发文档
  • [Android]Tool-Systrace
  • [BZOJ1089][SCOI2003]严格n元树(递推+高精度)
  • [C++从入门到精通] 14.虚函数、纯虚函数和虚析构(virtual)