【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/712962/

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

(0)

大家都在看

  • quartz框架(七)-JobStore

    在之前的博文中,博主已经写了关于Job的相关内容。本篇博文,博主将介绍JobStore相关的内容。 JobStore是存放Job和Trigger的地方。当我们调用Scheduler…

    技术杂谈 2023年7月24日
    071
  • Canal.adapter报错

    Canal.adapter报错 报错如下: 2021-09-09 15:56:33.669 [Thread-12] ERROR c.a.o.canal.adapter.launch…

    技术杂谈 2023年6月21日
    072
  • 动手搭建ServerLess服务

    一、前言 ​ 通常我们在做ServerLess的时候会想到用各种云的Faas服务,比如腾讯云,AWS,阿里云等等。但我们很少去研究自己怎么搭建一个ServerLess服务。本篇文章…

    技术杂谈 2023年5月31日
    0112
  • 浅析Promise的设计核心思想及其实现

    前言:这篇文章应该会和你见到的大部分手写Promise文章都不一样,文中不会讲到Promises/A+规范,也不会提到Promise.race / race等语法糖。在本文中,我会…

    技术杂谈 2023年5月31日
    093
  • Docker-compose资源编排

    Docker-compose 1.简介 Docker-Compose项目是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。 Docker-Compose将所管…

    技术杂谈 2023年7月10日
    068
  • Prototype原型模式

    定义: prototype pattern是指原型实例指定创建对象的种类,并且通过复制这些原型创建新的对象。是一种创建模式。 角色 Prototype(抽象原型类):它是声明克隆方…

    技术杂谈 2023年5月31日
    0113
  • 线程池的极简用法——内置线程池multiprocessing

    大家好,今天博主来分享一个线程池的小捷径——内置线程池的使用方法 一、背景 说道多线程,对变成层有了解的小伙伴一定不陌生,虽然不知道是什么但是也会从各大网站、面试分享等途径听说过。…

    技术杂谈 2023年7月11日
    063
  • 63.殉情的抹香鲸

    sdfds posted @2022-09-28 08:36 随遇而安== 阅读(24 ) 评论() 编辑 Original: https://www.cnblogs.com/55…

    技术杂谈 2023年6月21日
    0114
  • 做自动化测试选择Python还是Java?

    你好,我是测试蔡坨坨。 今天,我们来聊一聊测试人员想要进阶,想要做自动化测试,甚至测试开发,如何选择编程语言。 自动化测试,这几年行业内的热词,也是测试人员进阶的必备技能,更是软件…

    技术杂谈 2023年7月11日
    089
  • 开发,从未如此清晰

    关于开发,我们已经有了太多的方法论和工具,这之间其实很难说哪个方法论是正确的,哪个工具是最好用的;其实开发是”任性的”,它没有定律,如人饮水冷暖自知,其过程…

    技术杂谈 2023年5月31日
    0112
  • Elasticsearch+kibana+logstash 搭建日志收集分析平台

    Elasticsearch+kibana+logstash 搭建日志收集分析平台 环境搭建: 虚拟机内存配置: sysctl -w vm.max_map_count=262144 …

    技术杂谈 2023年6月21日
    096
  • 学会Linux,看完这篇就行了!

    转载请注明出处❤️ 作者:测试蔡坨坨 原文链接:caituotuo.top/797ab07d.html 你好,我是测试蔡坨坨。 对于测试同学来说,Linux基本属于必学必会内容,招…

    技术杂谈 2023年7月11日
    083
  • 使用mybatis-plus转换枚举值

    1. 使用mybatis-plus转换枚举值 枚举值转换方式有很多,有以下方式: 后端写一个通用方法,只要前端传枚举类型,后端返回相应的枚举值前端去匹配 优点:能够实时保持数据一致…

    技术杂谈 2023年7月25日
    069
  • flexible如何实现自动判断dpr?

    判断机型, 找出样本机型去适配. 比如iphone以6为样本, 宽度375px, dpr是2 Java Program! Original: https://www.cnblogs…

    技术杂谈 2023年5月31日
    0108
  • vi和vim文本编辑器

    vi和vim文本编辑器 vi和vim模式的相互切换 快捷键使用案例 拷贝当前行yy; 拷贝当前行向下的5行 5yy; 并粘贴(p) 删除当前行dd; 删除当前行向下的5行 5dd …

    技术杂谈 2023年7月11日
    071
  • mahout分类学习和遇到的问题总结

    这段时间学习Mahout有喜有悲。在这里首先感谢樊哲老师的指导。以下列出关于这次Mahout分类的学习和遇到的问题,还请大家多多提出建议:(全部文件操作都使用是在hdfs上边进行的…

    技术杂谈 2023年5月30日
    070
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球