(二)在QT中添加ROS项目+简单的利用QT推送消息+RVIZ显示插件接收消息

4 篇文章 4 订阅

一、配置QT中的ROS环境

参考下面文章

x86架构与ARM架构(AGX、TX2、NX等)下配置带ROS插件的QtCreator(Qt+ROS+ubuntu18)(源码编译安装方式)_带插件的qtcreator_灰灰子衿的博客-CSDN博客

 二、在QT中添加简单的ROS项目

1.添加工作空间

点击【New Project】添加工作空间,选择【其他项目】,选中【ROS Workspace】选项,点击【Choose...】按钮。

输入【Name】工作空间名称,选择【Workspace Path】工作空间地址 ,【Distribution】默认为melodic,【Build System】默认为CatkinMake,点击【下一步】按钮。

 点击【完成】按钮即完成工作空间的添加。

 此时生成下面工作控件目录。

 如果没有出现src目录,点击【过滤器树形视图】(即下面按钮),将菜单里的勾选框全部取消选中。

 2.添加包

选中【src】目录,右击鼠标,点击【添加新文件...】 。

 

弹出下面弹窗,选择【ROS】下面的【Package】,点击【Choose...】按钮 。

 填写【Name】名称,和【Catkin】依赖,点击【下一步】按钮。

 

点击【完成】按钮。

 此时目录结构如下

3. 添加节点

选中已添加包下面的src,右击鼠标出现菜单,选中【添加新文件...】 。

选择【Ros】下的【Basic Node】,点击【Choose...】按钮。

输入【名称】信息,点击【下一步】按钮。

点击【完成】按钮。

生成以下目录。

生成代码如下。

4.修改CMakeLists.txt文件

#指定项目所需的最低 CMake 版本。
cmake_minimum_required(VERSION 3.0.2)
#定义项目的名称
project(marker)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

#查找并导入外部依赖库。
find_package(catkin REQUIRED COMPONENTS
  roscpp
)

#这用于指定包的依赖关系,由依赖于这个包的其他软件包使用。
catkin_package(
#包的导出包含路径
  INCLUDE_DIRS include
#从项目中导出的库
#  LIBRARIES marker
#本项目依赖的其他catkin项目
#  CATKIN_DEPENDS roscpp
#此项目所依赖的非 catkin CMake 项目
  DEPENDS system_lib
)

#添加头文件搜索路径,编译器使用这些目录来查找头文件,第一个参数“include”表示包中的include/目录也是路径的一部分。
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

#指定将要构建的可执行文件的名称,以及它所依赖的源文件
add_executable(${PROJECT_NAME}_node src/marker_test.cpp)
#设置可执行文件依赖的库。
target_link_libraries(${PROJECT_NAME}_node ${catkin_LIBRARIES})

5.构建

点击左侧工具栏中的【项目】,选中【Build】,选择【Build System】为【CatkinMake】,默认即为该选项。

点击QT界面上的构建图标,或者键盘Ctrl+B,进行构建。

 6.运行(方法1)

点击左侧工具栏中的【项目】,选中【Run】,点击【Add Run Step】,选择【Ros Run Step】。

出现下面界面。

 选择【Package】中刚刚创建的功能包,我的包名为marker。

 选择【Target】可执行文件名,在CMakeLists.txt中add_executable(${PROJECT_NAME}_node src/marker_test.cpp)语句中设置的可执行文件名称为marker_node。

 点击【运行】按钮即可运行。

查看终端

 7.运行(方法2)

打开终端,到创建的工作空间根目录下

 设置项目环境

 执行运行命令

rosrun 包名称 执行文件名称

参考下面文章

Qt+ROS+ubuntu18.04配置教程(带界面)_qt ros_灰灰子衿的博客-CSDN博客

三、在QT中添加RVIZ消息推送

8.添加界面

在上述操作步骤下,继续有机包下面的【src】,点击【添加新文件...】。

选择【Qt】下的【Qt设计师界面类】,点击【Choose...】按钮。

 选择【Widget】,点击【下一步】按钮。

输入【类名】,点击【下一步】按钮。

 点击【完成】按钮。

 此时目录结构如下:

 

9.添加消息推送代码(以Marker消息类型为例)

修改marker_test.cpp文件

#include <ros/ros.h>
#include <QApplication>
#include "basic.h"

int main(int argc, char **argv)
{
    ros::init(argc, argv, "marker_test");
    ros::NodeHandle nh;
    QApplication a(argc,argv);
    Basic w;
    w.show();
    return a.exec();

    //ROS_INFO("Hello world!");
}

添加basic.ui界面

 修改basic.h

#ifndef BASIC_H
#define BASIC_H

#include <QWidget>
#include <ros/ros.h>
#include <visualization_msgs/Marker.h>

namespace Ui {
class Basic;
}

class MyPublisher;

struct MarkerMsg
{
    QString ns;
    int id;
    uint32_t shape;
    float pos_x;
    float pos_y;
    float pos_z;
    float orientation_x;
    float orientation_y;
    float orientation_z;
    float orientation_w;
    float scale_x;
    float scale_y;
    float scale_z;
    float color_r;
    float color_g;
    float color_b;
    float color_a;
};

class Basic : public QWidget
{
    Q_OBJECT

public:
    explicit Basic(QWidget *parent = 0);
    ~Basic();

private slots:
    void on_pushButton_clicked();
signals:
    void sigToStart();
private:
    Ui::Basic *ui;

    QThread *thread;
    MyPublisher *myPublisher;
};

class MyPublisher : public QObject
{
    Q_OBJECT
public:
    MyPublisher(QObject *parent = nullptr);
    ~MyPublisher();

    void setMarkerMsg(MarkerMsg msg){marker_msg = msg;}

public slots:
    void publishMsg();

private:
    MarkerMsg marker_msg;
};


#endif // BASIC_H

修改basic.cpp

#include "basic.h"
#include "ui_basic.h"
#include <QDebug>
#include <QThread>

Basic::Basic(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Basic)
{
    ui->setupUi(this);

    myPublisher = new MyPublisher;
    thread = new QThread;
    connect(this,&Basic::sigToStart,myPublisher,&MyPublisher::publishMsg);
    myPublisher->moveToThread(thread);
    thread->start();
    on_pushButton_clicked();
    emit sigToStart();
}

Basic::~Basic()
{
    delete ui;
}


void Basic::on_shape_valueChanged(int arg1)
{
    if(arg1 == 0)
        ui->label_shape->setText("ARROW");
    else if(arg1 == 1)
        ui->label_shape->setText("CUBE");
    else if(arg1 == 2)
        ui->label_shape->setText("SPHERE");
    else if(arg1 == 3)
        ui->label_shape->setText("CYLINDER");
}

void Basic::on_pushButton_clicked()
{
    MarkerMsg msg;
    msg.ns = ui->ns->text();
    msg.id = ui->id->text().toInt();
    msg.shape = ui->shape->value();
    msg.pos_x = ui->pos_x->text().toFloat();
    msg.pos_y = ui->pos_y->text().toFloat();
    msg.pos_z = ui->pos_z->text().toFloat();
    msg.orientation_x = ui->orientstion_x->text().toFloat();
    msg.orientation_y = ui->orientstion_y->text().toFloat();
    msg.orientation_z = ui->orientstion_z->text().toFloat();
    msg.orientation_w = ui->orientstion_w->text().toFloat();
    msg.scale_x = ui->scale_x->text().toFloat();
    msg.scale_y = ui->scale_y->text().toFloat();
    msg.scale_z = ui->scale_z->text().toFloat();
    msg.color_r = ui->color_r->text().toFloat();
    msg.color_g = ui->color_g->text().toFloat();
    msg.color_b = ui->color_b->text().toFloat();
    msg.color_a = ui->color_a->text().toFloat();

    myPublisher->setMarkerMsg(msg);
}

MyPublisher::MyPublisher(QObject *parent)
{

}

MyPublisher::~MyPublisher()
{

}

void MyPublisher::publishMsg()
{
    //初始化ROS,并在visualization_marker主题上创建一个ros::Publisher。
    ros::NodeHandle n;
    //用于设置循环频率,适用于Publisher程序无限循环  ros::Rate对象可以允许你指定自循环的频率
    ros::Rate r(1);
    ros::Publisher marker_pub = n.advertise<visualization_msgs::Marker>("visualization_marker", 1);

    //uint32_t shape = visualization_msgs::Marker::CUBE;

    while (ros::ok())
    {
      visualization_msgs::Marker marker;

      marker.header.frame_id = "basic";
      marker.header.stamp = ros::Time::now();

      //命名空间 (ns) 和 id 用于为此标记创建唯一名称。如果收到具有相同 ns 和 id 的标记消息,则新标记将替换旧标记。
      marker.ns = marker_msg.ns.toStdString();
      marker.id = marker_msg.id;

      marker.type = marker_msg.shape;

      //action 字段指定如何处理标记。选项是visualization_msgs::Marker::ADD 和visualization_msgs::Marker::DELETE。
      //ADD 有点用词不当,它的真正意思是“创建或修改”。
      marker.action = visualization_msgs::Marker::ADD;

      //设置了marker的位姿。 geometry_msgs/Pose 消息由一个 geometry_msgs/Vector3 来指定位置和一个 geometry_msgs/Quaternion 来指定方向。
      //这里将位置设置为原点,将方向设置为恒等方向(注意 w 的 1.0)。
      marker.pose.position.x = marker_msg.pos_x;
      marker.pose.position.y = marker_msg.pos_y;
      marker.pose.position.z = marker_msg.pos_z;
      marker.pose.orientation.x = marker_msg.orientation_x;
      marker.pose.orientation.y = marker_msg.orientation_y;
      marker.pose.orientation.z = marker_msg.orientation_z;
      marker.pose.orientation.w = marker_msg.orientation_w;

      //指定标记的比例。对于基本形状,所有方向上的 1 表示边长为 1 米。
      marker.scale.x = marker_msg.scale_x;
      marker.scale.y = marker_msg.scale_y;
      marker.scale.z = marker_msg.scale_z;

      //标记的颜色被指定为 std_msgs/ColorRGBA。每个成员应介于 0 和 1 之间。alpha (a) 值为 0 表示完全透明(不可见),1 表示完全不透明。
      marker.color.r = marker_msg.color_r;
      marker.color.g = marker_msg.color_g;
      marker.color.b = marker_msg.color_b;
      marker.color.a = marker_msg.color_a;

      //生命周期字段指定此标记在被自动删除之前应该保留多长时间。 ros::Duration() 的值意味着永远不会自动删除。
      //如果在达到生命周期之前收到新的标记消息,则生命周期将重置为新标记消息中的值。
      marker.lifetime = ros::Duration();

      //我们等待标记有订阅者,然后发布标记。
      while (marker_pub.getNumSubscribers() < 1)
      {
        if (!ros::ok())
        {
          return;
        }
        ROS_WARN_ONCE("Please create a subscriber to the marker");
        sleep(1);
      }
      marker_pub.publish(marker);

//      switch (shape)
//      {
//      case visualization_msgs::Marker::CUBE:
//        shape = visualization_msgs::Marker::SPHERE;
//        break;
//      case visualization_msgs::Marker::SPHERE:
//        shape = visualization_msgs::Marker::ARROW;
//        break;
//      case visualization_msgs::Marker::ARROW:
//        shape = visualization_msgs::Marker::CYLINDER;
//        break;
//      case visualization_msgs::Marker::CYLINDER:
//        shape = visualization_msgs::Marker::CUBE;
//        break;
//      }

     r.sleep();
   }
}

10.修改CMakeLists.txt文件

#指定项目所需的最低 CMake 版本。
cmake_minimum_required(VERSION 3.0.2)
#定义项目的名称
project(marker)

## Compile as C++11, supported in ROS Kinetic and newer
# add_compile_options(-std=c++11)

#查找并导入外部依赖库。
find_package(catkin REQUIRED COMPONENTS
  roscpp
)

#寻找Qt的包
find_package(Qt5  REQUIRED COMPONENTS  Widgets  )

#设置自动生成moc文件,一定要设置
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)#设置工程包含当前目录,非必须


#这用于指定包的依赖关系,由依赖于这个包的其他软件包使用。
catkin_package(
#包的导出包含路径
  INCLUDE_DIRS include
#从项目中导出的库
#  LIBRARIES marker
#本项目依赖的其他catkin项目
  CATKIN_DEPENDS roscpp
#此项目所依赖的非 catkin CMake 项目
  DEPENDS system_lib
)

#添加头文件搜索路径,编译器使用这些目录来查找头文件,第一个参数“include”表示包中的include/目录也是路径的一部分。
include_directories(
  include
  ${catkin_INCLUDE_DIRS}
)

#指定将要构建的可执行文件的名称,以及它所依赖的源文件
add_executable(${PROJECT_NAME}_node src/marker_test.cpp
                                    src/basic.cpp
                                    src/basic.ui)
#在定义消息类型时,编译的可执行文件依赖这些动态生成的代码,需要使用${PROJECT_NAME}_generate_messages_cpp进行配置。
#add_dependencies(${PROJECT_NAME}_node ${PROJECT_NAME}_generate_messages_cpp)
#设置可执行文件依赖的库。
target_link_libraries(${PROJECT_NAME}_node ${catkin_LIBRARIES})
target_link_libraries(${PROJECT_NAME}_node  Qt5::Widgets )#链接Qt库

11.构建与运行

上面二中已经进行了构建与运行的配置,直接运行即可。

运行会出现下面错误:

这是没有打开ros环境的原因,需打开终端,执行roscore命令

 此时即可打开程序。

12.打开rviz可视化工具显示插件

打开rviz可视化工具也需在已经运行roscore的情况下才能打开。

 点击【Displays】下的【Add】按钮,选择Marker插件,点击【OK】按钮。

 根据上面代码将【Fixed Frame】修改为basic。

此时即可出现Marker类型的图形, 修改属性即可修改rviz中相应的属性。

 13.查看推送的消息信息

查看所有的订阅消息列表

rostopic list

查看某个消息

rostopic echo /消息名称

例如:rostopic echo /visualization_marker

资源链接https://download.csdn.net/download/m0_67254672/88180519?spm=1001.2014.3001.5501

  • 4
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 22
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值