我是靠谱客的博主 大气猫咪,最近开发中收集的这篇文章主要介绍用 Qt Creator 创建项目来转换 ros 消息(涉及 ros 消息的订阅、接收、解析 以及 ros 消息的发布)1 说明2 创建 QT 项目2 将消息头文件复制到 QT 项目工作目录3 修改 .pro 文件4 main.cpp 的准备工作5 我的程序总览6 订阅 ros 消息并解析7 发布 ros 消息8 代码运行,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

文章目录

  • 1 说明
  • 2 创建 QT 项目
  • 2 将消息头文件复制到 QT 项目工作目录
  • 3 修改 .pro 文件
  • 4 main.cpp 的准备工作
    • 4.1 添加`#include`项:
    • 4.2 ros 初始化
  • 5 我的程序总览
  • 6 订阅 ros 消息并解析
  • 7 发布 ros 消息
  • 8 代码运行

1 说明

本文以 ros 消息的转换为例介绍如何使用 c++ 来:

  1. 接收 ros 消息并解析
  2. 发布 ros 消息

本案例运行的环境:

  • Ubuntu 16.04LTS
  • Qt Creator 4.11.1 (Based on Qt 5.14.1 (GCC 5.3.1 20160406 (Red Hat 5.3.1-6), 64 bit))
  • ROS Kinetic
  • c++ 11

2 创建 QT 项目

File - New File or Project ...(或Ctrl+N);
选择Qt Console Application,然后点击Choose...
在这里插入图片描述

设置项目名和路径后点击Next >,设置编译工具为qmake后一直点击Next >

在这里插入图片描述
然后就自动生成了项目文件(show是我的项目名称,之后的演示是基于重新生成的tran_msg项目):
在这里插入图片描述
自动生成的文件如下:
show.pro:

QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += 
        main.cpp

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

main.cpp:

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    return a.exec();
}

2 将消息头文件复制到 QT 项目工作目录

消息的头文件是根据*.msg生成的 c++ 头文件,一般在 catkin 工作空间下,具体路径为<path to workspace>/devel/include/<package name>/,如果要创建自己的消息可以参考这篇文章:使用 catkin 的方式创建自定义的 ros 消息。
对于我来说,将以下消息的头文件复制进了工作目录,为了方便理解消息的字段结构,我也将消息文件本体*.msg复制到了工作目录。
在这里插入图片描述
需要注意的是,如果消息中包涵自定义消息类型的字段,需要将这个自定义消息的头文件也拷贝到工作目录中。
例如,我们有两个*.msg文件:

  • A.msg
  • B.msg

A 消息的内容为:

int 32 id
...
B b_object
...

此时 A 就嵌套了 B 消息,如果我们的项目中需要用到 A 消息,除了需要将 A 消息的头文件拷贝到项目的工作目录,同时也需要把 B 消息的头文件拷贝到项目的工作目录。

3 修改 .pro 文件

.pro文件中包涵了编译的一些信息,需要进行修改,修改之后的文件为

QT += core
QT -= gui

CONFIG += c++11 console
CONFIG -= app_bundle

TEMPLATE = app
INCLUDEPATH += /opt/ros/indigo/include 
               /opt/ros/kinetic/include 
               ./planner 
               /usr/include/eigen3

DEPENDPATH += /opt/ros/indigo/include 
              /opt/ros/kinetic/include

LIBS += -L/opt/ros/indigo/lib -L/opt/ros/kinetic/lib -L/usr/local/lib 
    -lroscpp -lrospack -lpthread -lrosconsole 
    -lrosconsole_log4cxx -lrosconsole_backend_interface 
    -lxmlrpcpp -lroscpp_serialization -lrostime 
    -lcpp_common  -lroslib -lpthread

SOURCES += main.cpp

HEADERS += 
    BodyIMU.h 
    CarlaEgoVehicleControl.h 
    CarlaEgoVehicleInfo.h 
    CarlaImu.h 
    ChasisStatus.h 
    GPSPoint.h 
    insMsg.h

具体来说,添加了复制进来的消息头文件:

HEADERS += 
    BodyIMU.h 
    CarlaEgoVehicleControl.h 
    CarlaEgoVehicleInfo.h 
    CarlaImu.h 
    ChasisStatus.h 
    GPSPoint.h 
    insMsg.h

添加了一些依赖项/链接库的路径:

INCLUDEPATH += /opt/ros/indigo/include 
               /opt/ros/kinetic/include 
               ./planner 
               /usr/include/eigen3

DEPENDPATH += /opt/ros/indigo/include 
              /opt/ros/kinetic/include

LIBS += -L/opt/ros/indigo/lib -L/opt/ros/kinetic/lib -L/usr/local/lib 
    -lroscpp -lrospack -lpthread -lrosconsole 
    -lrosconsole_log4cxx -lrosconsole_backend_interface 
    -lxmlrpcpp -lroscpp_serialization -lrostime 
    -lcpp_common  -lroslib -lpthread

4 main.cpp 的准备工作

4.1 添加#include项:

  1. ros 依赖
#include "ros/ros.h"
#include "ros/init.h"
  1. 消息头文件
#include "BodyIMU.h"
#include "CarlaImu.h"

(下面的示例就用到这两个消息)

4.2 ros 初始化

参考ros 初始化和关闭 (ros::init(); ros::shutdown())。
在 main 函数的开头进行 ros 的初始化,其命令格式为:

ros::init(argc,argv,"my_node_name");

ros::init(argc,argv,"my_node_name",ros::init_options::AnonymousName);

初始化选项有

  • NoSigintHandler: 不安装 SIGINT 句柄。这种情况下你需要自己安装SIGINT句柄来保证节点在退出时候会正确的关闭 。 SIGINT的默认操作是终结一个进行,所以如果你想自己处理 SIGTERM 你需要使用这个选项。
ros::init_options::NoSigintHandler 
  • AnonymousName: 匿名节点名称,增加一个随机数在节点名的后面,使得节点名唯一。
ros::init_options::AnonymousName 
  • NoRosout:不向/rosout 话题广播 rosconsole
ros::init_options::NoRosout 

我这里直接使用第一种方式:

ros::init(argc,argv,"TransTool");

5 我的程序总览

下面是我的main.cpp函数的内容,接下来的两个部分我将结合这个函数讲解 ros 消息的接收和发送。

#include "ros/ros.h"
#include "ros/init.h"

#include "BodyIMU.h"
#include "CarlaImu.h"

// 因为要在`main`和消息处理函数`CarlaImuInfoCallback`都使用这个变量,所以将其定义为全局变量
static ros::Publisher car_imu_info;
// 处理接收到的消息的函数
void CarlaImuInfoCallback(const trans_msg::CarlaImu &msg)
{
    trans_msg::BodyIMU imu;

    imu.acc_x = msg.linear_acceleration.x;
    imu.acc_y = msg.linear_acceleration.y;
    imu.acc_z = msg.linear_acceleration.z;

    imu.rot_x = msg.angular_velocity.x;
    imu.rot_y = msg.angular_velocity.y;
    imu.rot_z = msg.angular_velocity.z;

    imu.frame_num = msg.header.seq;
    imu.time_stamp = msg.header.stamp.nsec;
    // 发布消息
    car_imu_info.publish(imu);
//    printf("get imun");
}

int main(int argc, char *argv[])
{
    ros::init(argc,argv,"TransTool");

    ros::Subscriber carla_imu_info;
//    ros::Publisher car_imu_info;
    ros::NodeHandle NodeHandle;

    car_imu_info = NodeHandle.advertise<trans_msg::BodyIMU>("carImu",10);
    carla_imu_info = NodeHandle.subscribe("/carla/ego_vehicle/imu/imu1",10,CarlaImuInfoCallback);
	// 定时接收消息
    while(1)
    {
        ros::spinOnce();
        usleep(100000);
    }
}

6 订阅 ros 消息并解析

参考ROS自定义消息。
定义订阅实例:

ros::Subscriber carla_imu_info;

实例化NodeHandle

NodeHandle 是roscpp用于创建订阅者、发布者的接口。详情参见http://docs.ros.org/melodic/api/roscpp/html/classros_1_1NodeHandle.html

ros::NodeHandle NodeHandle;

然后就是订阅节点了,一般的用法如下:

void callback(const std_msgs::Empty::ConstPtr& message)
{
}
ros::Subscriber sub = handle.subscribe("my_topic", 1, callback);

对应于我的代码就是:

carla_imu_info = NodeHandle.subscribe("/carla/ego_vehicle/imu/imu1",10,CarlaImuInfoCallback);
// 处理接收到的消息
void CarlaImuInfoCallback(const trans_msg::CarlaImu &msg)
{
    // 处理函数
}

说明:下面代码中的trans_msg是我自定消息所在package的名称,不太清楚可以打开消息头文件查看
在这里插入图片描述

接下来需要写一个 ros 消息回调处理函数,这个函数有两个选项:

  • ros::spin()
  • ros::spinOnce()

ros::spin()自身就是一个循环体,也就是说代码执行到这个语句就进入ros::spin()的内循环了,不断的触发,如果接收到订阅的节点的消息,就回调声明的消息处理函数;
ros::spinOnce()的特性如其名,只监听一次消息,只触发一次回调函数,执行完它之后程序还会继续执行。如果要用ros::spinOnce()持续监听消息,则需要将其放置在循环体中。

在我的代码里就是将其放置在循环体中来实现周期性监听消息的目的的:

 while(1)
 {
     ros::spinOnce();
     usleep(100000);
 }

7 发布 ros 消息

先实例化一个Publisher

ros::Publisher car_imu_info;

然后设置publisher(下面这一句的含义是:发布名为carImu,消息类型为trans_msg::BodyIMU,队列长度10)

car_imu_info = NodeHandle.advertise<trans_msg::BodyIMU>("carImu",10);

下面是初始化一个 trans_msg::BodyIMU 类型的消息

trans_msg::BodyIMU imu;

imu.acc_x = msg.linear_acceleration.x;
imu.acc_y = msg.linear_acceleration.y;
imu.acc_z = msg.linear_acceleration.z;

imu.rot_x = msg.angular_velocity.x;
imu.rot_y = msg.angular_velocity.y;
imu.rot_z = msg.angular_velocity.z;

imu.frame_num = msg.header.seq;
imu.time_stamp = msg.header.stamp.nsec;

最后发布这个消息:

car_imu_info.publish(imu);

如果不是像我这样有一个消息来触发创建当前消息,可以用一个循环来持续发布消息,如下:

// 设置循环的频率 
ros::Rate loop_rate(1); 
while (ros::ok()) { 
	// 初始化std_msgs::String类型的消息 
	my_topic::topic_msg msg;
	// 发布消息 
	pub_topic.publish(msg); 
	// 按照循环频率延时 
	loop_rate.sleep(); 
}

8 代码运行

使用QT运行 ros 项目的问题参见https://blog.csdn.net/amnesiagreen/article/details/108356826

我的程序的功能是将CARLA 仿真环境中车的IMU消息订阅并解析,然后转换为另一种格式的IMU消息。
我先运行CARLA的仿真环境,然后运行我的消息转换工程:
在这里插入图片描述

最后

以上就是大气猫咪为你收集整理的用 Qt Creator 创建项目来转换 ros 消息(涉及 ros 消息的订阅、接收、解析 以及 ros 消息的发布)1 说明2 创建 QT 项目2 将消息头文件复制到 QT 项目工作目录3 修改 .pro 文件4 main.cpp 的准备工作5 我的程序总览6 订阅 ros 消息并解析7 发布 ros 消息8 代码运行的全部内容,希望文章能够帮你解决用 Qt Creator 创建项目来转换 ros 消息(涉及 ros 消息的订阅、接收、解析 以及 ros 消息的发布)1 说明2 创建 QT 项目2 将消息头文件复制到 QT 项目工作目录3 修改 .pro 文件4 main.cpp 的准备工作5 我的程序总览6 订阅 ros 消息并解析7 发布 ros 消息8 代码运行所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(36)

评论列表共有 0 条评论

立即
投稿
返回
顶部