【cartographer_ros】五: 发布和订阅陀螺仪Imu信息

上一节介绍了里程计Odometry传感数据的订阅和发布。

本节会介绍陀螺仪Imu数据的发布和订阅。陀螺仪在cartographer中主要用于前端位置预估和后端优化。

在终端查看消息数据结构:

rosmsg show sensor_msgs/Imu

Odometry消息类型数据结构如下:

Header header
geometry_msgs/Quaternion orientation
float64[9] orientation_covariance // Row major about x, y, z axes
geometry_msgs/Vector3 angular_velocity
float64[9] angular_velocity_covariance // Row major about x, y, z axes
geometry_msgs/Vector3 linear_acceleration
float64[9] linear_acceleration_covariance // Row major x, y z

其中linear_acceleration表示线加速度,angular_velocity表示角速度,orientation表示姿态,使用四元数表示。covariance表示对应协方差,体现各个数据的误差

陀螺仪用的是LPMS-IG1 RS232,这个陀螺仪同时能提供角速度 ,线加速度,和欧拉角。

#include <ros ros.h>
#include <tf tf.h>
#include <sensor_msgs imu.h>

using namespace std;

unsigned int step = 0;
unsigned int data_i = 0;
unsigned int data_len = 0;
unsigned char handle_buf[2048];

float acc[3];
float gyo[3];
float eular[3];

void DataReceivedCallback(std::vector<unsigned char> &data)
{
    unsigned char datasingle1;
    for (size_t k = 0; k < data.size(); k++)
    {
        datasingle1 = data[k];
        switch (step)
        {
        case 0:
        {
            if (datasingle1 == 0x3A)
            {
                step = 1;
                data_i = 0;
                memset(handle_buf, 0, 2048);
            }
            break;
        }
        case 1: // sensor id low
        {
            handle_buf[0] = datasingle1;
            step = 2;
            break;
        }
        case 2: // sensor id high
        {
            handle_buf[1] = datasingle1;
            step = 3;
            break;
        }
        case 3: //&#x6307;&#x4EE4;&#x53F7; low
        {
            handle_buf[2] = datasingle1;
            step = 4;
            break;
        }
        case 4: //&#x6307;&#x4EE4;&#x53F7; high
        {
            handle_buf[3] = datasingle1;
            step = 5;
            break;
        }
        case 5: //&#x6570;&#x636E;&#x957F;&#x5EA6; low
        {
            handle_buf[4] = datasingle1;
            data_len = datasingle1;
            step = 6;
            break;
        }
        case 6: //&#x6570;&#x636E;&#x957F;&#x5EA6; high
        {
            handle_buf[5] = datasingle1;
            data_len += (uint16_t)handle_buf[5] * 256;
            if (data_len > 512)
            {
                step = 0;
                cout << " data_len error : " << hex << datasingle1 << ",  " << data_len << std::endl;
            }
            else
            {
                if (data_len > 0)
                {
                    data_i = 0;
                    step = 7;
                }
                else
                {
                    step = 0;
                    cout << " data_len error : " << hex << datasingle1 << ",  " << data_len << std::endl;
                }
            }
            break;
        }
        case 7:
        {
            handle_buf[data_i + 6] = datasingle1;
            data_i++;
            if (data_i >= data_len + 4) //&#x5B8C;&#x6574;&#x4E00;&#x5E27;
            {
                //&#x5224;&#x65AD;&#x5305;&#x5C3E;
                if ((handle_buf[data_len + 8] != 0x0D) && (handle_buf[data_len + 9] != 0x0A))
                {
                    step = 0;
                    cout << " tail error : " << hex << handle_buf[data_len + 8] << ",  " << hex << handle_buf[data_len + 9] << std::endl;
                    break;
                }

                uint16_t lrc = ((uint16_t)handle_buf[data_len + 7] * 256) + (uint16_t)handle_buf[data_len + 6];

                //&#x5224;&#x65AD;lrc
                uint16_t sum_lrc = 0;
                for (unsigned int i = 0; i < (6 + data_len); i++)
                {
                    sum_lrc += handle_buf[i];
                }

                if (lrc != sum_lrc)
                {
                    step = 0;
                    cout << " crc error : " << lrc << ",  " << sum_lrc << std::endl;
                    break;
                }

                //&#x7EBF;&#x52A0;&#x901F;&#x5EA6;(&#x542B;&#x91CD;&#x529B;)
                acc[0] = *((float *)&handle_buf[22]);
                acc[1] = *((float *)&handle_buf[26]);
                acc[2] = *((float *)&handle_buf[30]);

                //&#x89D2;&#x901F;&#x5EA6;(&#x9640;&#x87BA;&#x4EEA;I&#x7684;&#x8F93;&#x51FA;)
                gyo[0] = *((float *)&handle_buf[82]);
                gyo[1] = *((float *)&handle_buf[86]);
                gyo[2] = *((float *)&handle_buf[90]);

                //&#x6B27;&#x62C9;&#x89D2;
                eular[0] = *((float *)&handle_buf[146]);
                eular[1] = *((float *)&handle_buf[150]);
                eular[2] = *((float *)&handle_buf[154]);

                step = 0;
            }
            break;
        }
        default:
            break;
        }
    }
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "Imu_publisher");

    ros::NodeHandle n;
    ros::Publisher imu_pub = n.advertise<sensor_msgs::imu>("imu", 50);

    string device = "/dev/ttyUSB0";
    int baud_rate = 921600;
    int data_bits = 8;
    int stop_bits = 0;
    string parity = "n";

    boost::shared_ptr<serialport> serialPort;
    serialPort.reset(new SerialPort(device, baud_rate, data_bits, stop_bits, parity));
    auto binding = bind(&DataReceivedCallback, this, std::placeholders::_1);
    serialPort->setcallback(binding);
    if (serialPort->Open())
    {
        serialPort->LoadConfig();
        cout << "Init serial open success";
    }
    else
        cout << "Init serial open false";

    ros::Rate r(1.0);
    while (n.ok())
    {

        ros::spinOnce();

        sensor_msgs::Imu imu;
        imu.header.stamp = ros::Time::now();
        imu.header.frame_id = "base_link";
        imu.linear_acceleration.x = acc[0] * (-9.8);
        imu.linear_acceleration.y = acc[1] * (-9.8);
        imu.linear_acceleration.z = acc[2] * (-9.8);
        imu.angular_velocity.x = gyo[0] * 3.1415926 / 180.0;
        imu.angular_velocity.y = gyo[1] * 3.1415926 / 180.0;
        imu.angular_velocity.z = gyo[2] * 3.1415926 / 180.0;
        imu.orientation = tf::createQuaternionMsgFromRollPitchYaw(eular[0], eular[1], eular[2]);

        //&#x53D1;&#x5E03;Imu&#x6D88;&#x606F;
        imu_pub.publish(imu);

        last_time = current_time;
        r.sleep();
    }
}
</serialport></sensor_msgs::imu></unsigned></sensor_msgs></tf></ros>

SerialPort是自定义的串口通信类,附上代码:

(1) 通过rosbag订阅

rostopic echo /imu

(2) 通过rviz查看
打开rviz

rosrun rviz rviz

Fixed Frame修改为base_link,添加Imu并将Topic设为/imu

(3) 编写程序打印

#include "ros/ros.h"
#include "sensor_msgs/Imu.h"

void imuCallback(const sensor_msgs::Imu::ConstPtr &msg)
{
    ROS_INFO("imu: %f, %f, %f, %f, %f, %f, %f, %f, %f, %f", msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z,
             msg->angular_velocity.x, msg->angular_velocity.y, msg->angular_velocity.z,
             msg->orientation.w, msg->orientation.x, msg->orientation.y, msg->orientation.z);
}

int main(int argc, char **argv)
{
    ros::init(argc, argv, "listener");
    ros::NodeHandle node;
    ros::Subscriber subimu = node.subscribe("imu", 1000, imuCallback);
    ros::spin();
    return 0;
}

【完】

下一节会介绍路标Landmark数据的发布和订阅。

Original: https://www.cnblogs.com/CloudFlame/p/16443733.html
Author: CloudFlame
Title: 【cartographer_ros】五: 发布和订阅陀螺仪Imu信息

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/805043/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 在读学生自学Ubuntu20.04用C++调用matplotlib历程

    1.学习CMake 程序的编译需要用CMake,因此如果是Ubuntu小白的话,最好学一下。(小白的建议) http://file.ncnynl.com/ros/CMake%20P…

    Python 2023年9月3日
    055
  • mysql 即学a又学b_学习python

    python优缺点 简单易学免费,开源,高层语言,可移植型,解释性,面向对象,可扩展性,丰富的库,规范的代码 缺点 运行速度,国内市场小,中文资料匮乏,构架选择太多 (所有的库在p…

    Python 2023年9月25日
    044
  • vscode下c++使用matplotlib-cpp的环境配置教程

    matplotlib-cpp库见:传送门,本质上是C++调用python,该库将调用过程封装成了类,便于我们使用。 vscode配置g++编译环境 使用快捷键Ctrl+Shift+…

    Python 2023年8月30日
    061
  • Pytest基本操作

    1、安装及快速入门 2、pytest的前后置 3、运行规则 4、断言 5、标记mark的使用 安装命令:pip3 install pytest 创建第一个测试用例 import p…

    Python 2023年9月14日
    033
  • RC滤波器(高通/低通)

    RC既可以构成低通滤波电路,也可以构成高通滤波电路 1、高通滤波器 如果输入是个直流电压,ui电压的变化率为0,所以RL上没有电流通过,根据欧姆定律,即out=0V,电容完全&#8…

    Python 2023年11月7日
    059
  • python矩阵运算内存占用计算

    半精度单精度双精度 三者分别是16位、32位、64位,一个字节8位因此分别是2位、4位、8位,它们都分成3部分,符号位,指数和尾数。不同精度只不过是指数位和尾数位的长度不一样: ;…

    Python 2023年8月29日
    067
  • python爬虫部署hadoop_Python爬虫进阶一之爬虫框架Scrapy安装配置

    初级的爬虫我们利用urllib和urllib2库以及正则表达式就可以完成了,不过还有更加强大的工具,爬虫框架Scrapy,这安装过程也是煞费苦心哪,在此整理如下。 Windows …

    Python 2023年10月6日
    046
  • Informer时序模型(自定义项目)

    开源项目 说明 读完代码解析篇,我们针对开源项目中的模型预测方法做一下介绍。作者在Github上给出了模型预测方法以及Q、K图的做法,这里提供下载链接 首先,在不更改任何参数的情况…

    Python 2023年8月1日
    0102
  • 【基础知识】pandas入门

    两种:一维数组型的Series对象+二维表格型的DataFrame对象 andas的索引对象index是不可变的,因此用户不能对其进行修改。但index中可以包含重复的标签。选择重…

    Python 2023年8月17日
    052
  • 【云服务器 ECS 实战】云服务器新手指南(配置+使用详解)

    * – 一、写在前面 – 二、ECS 云服务是什么 – 三、云服务器的购买与配置 – + 购买云服务器 + 密码与安全组配置 + 远…

    Python 2023年9月28日
    040
  • 基于Python+MySQL的图书管理系统

    目录 前言一、开发环境与开发工具二、系统需求分析三、系统功能分析四、数据库设计1、数据库概念结构设计(1)数据流程图(2)系统ER图2、数据库逻辑结构设计3、数据库物理结构设计五、…

    Python 2023年7月31日
    047
  • FastAPI(七十四)实战开发《在线课程学习系统》接口开发– 删除留言

    可以对留言进行删除,这里的删除,我们使用的是逻辑的删除,不是物理删除 我们来梳理下这里的逻辑 1.用户需要登录 2.请求携带留言的id 3.判断删除留言是否存在 4.存在则删除 那…

    Python 2023年6月15日
    053
  • [BUUCTF] 集训第六天

    [BSidesCF 2019]Futurella 火星文 复制粘贴搜索框就可以获得flag 看源码 轻易得不敢copy flag ; [GYCTF2020]FlaskApp 这里会…

    Python 2023年8月13日
    053
  • python入门06 动画精灵和碰撞检测pygame

    目录 动画精灵和碰撞检测 前提 一、动画精灵 ​ ①、一堆沙滩球都反弹 ②、让小球动起来 二、碰撞检测 矩形碰撞与像素完美结合 三、统计时间 用 pygame.time.Clock…

    Python 2023年9月20日
    076
  • pandas–groupby相关操作

    pandas——groupby操作 实验目的熟练掌握pandas中的groupby操作 实验原理groupby(by=None, axis=0, level=None, as_in…

    Python 2023年8月16日
    036
  • 点云作业python基础

    DataFrame是pandas包中的重要数据类型,相当于表格数据类型,常用的操作如下: 创建DataFrame import pandas as pd df = pd.DataF…

    Python 2023年8月20日
    041
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球