QT5+ROS程序开发

    很多时候我们开发ROS程序的时候,会遇到GUI的需求。有几种方法可以在ROS中开发GUI程序,比如使用rqt_qt。若基于Python语言,还可以使用pyqt、thinker等GUI库。若基于C++,最好的选择是QT。

    ROS官方是支持QT4的,比如可以使用catkin_create_qt_pkg创建qt功能包,而ROS中很多著名的工具都是基于QT4。但是2020年,谁还用QT4,当然是拥抱QT5了。此外,ROS并没有一个官方的IDE,虽然使用编辑器+命令行也能满足需求,但是带界面的IDE更加赏心悦目是吧。故本文首先介绍如何使用Qt Creator这个IDE开发ROS程序,然后介绍如何在ROS程序中使用QT5库来开发GUI界面,最后介绍如何在QT中显示PCL库的点云。

Qt Creator开发ROS程序

     Levi-Armstrong大佬已经开发了对应的qt插件:ros_qtc_plugin使我们能在qt creator上编译ROS程序。这个插件以前使用ppa的方式进行安装,现在大佬已经把该插件集成到qt creator里面了,安装和使用文档。大致流程是:

1.安装Qt Creator for ROS

    下载对应系统的Qt安装包:分为在线和离线安装两种方式,然后运行.run安装包完成带插件的qt creator的安装。如果你之前使用ppa安装过的话,要先删除ppa。

2.配置Qt Creator for ROS

    教程里面配置了Qt Creator的各种选项,但其实只有第一项:配置Ubuntu允许debugging/ptrace是必要的。过程为:

(1.Open file: sudo gedit /etc/sysctl.d/10-ptrace.conf

(2.Change the value of kernel.yama.ptrace_scope to 0

(3.Reload the kernel configuration with sudo systemctl restart procps.service

    其它的都是可选的。

3.ROS程序创建

    在Qt Creator中创建catkin工作空间、创建功能包和节点。

A.首先创建catkin工作空间

    打开 “新建文件或项目”,选择ROS Workspace:

图片1.jpg

    下面填写工作空间名称和路径,ps:创建工作空间不会独立创建文件夹,因此最好先新建一个与该工作空间同名的文件夹作为路径。

图片2.jpg

B.创建功能包

    在工作空间下有一个src目录(默认是隐藏的,先设置显示空目录),右键该目录新建文件打开对话框,选择Package。

图片3.jpg

    填入功能包的名称、和依赖的功能包。

图片4.jpg

C.创建节点

    右键功能包目录下的src文件夹,新建文件打开对话框。选择对应节点类型。

图片5.jpg

    然后填入节点名称,比如test.cpp。

图片6.jpg

4.配置CMakeLists.txt

    跟普通的ROS程序一样,需要配置功能包的CMakeLists.txt文件才能编译。一个典型的CMakeLists.txt文件如下:

cmake_minimum_required(VERSION 2.8.3)
project(ros_basic)

find_package(catkin REQUIRED COMPONENTS
  geometry_msgs
  move_base_msgs
  nav_msgs
  roscpp
  rospy
  sensor_msgs
  std_msgs
  tf
)

catkin_package(
)

include_directories(
  ${catkin_INCLUDE_DIRS}
)

add_executable(time_test src/time_test.cpp)
target_link_libraries(time_test ${catkin_LIBRARIES} )

5.配置ROS程序

    点击项目,首先配置编译选项,使用CatkinMake编译系统。

图片7.jpg

    配置运行选项,设置运行的功能包和节点。

图片8.jpg

    配置完成后,编译程序,然后就可以运行了。



ROS程序使用QT5库

    在前面的基础上,添加Qt的GUI界面是很简单的。右键功能包新建文件,打开对话框,选择QT界面类:

图片9.jpg

    然后选择主窗口类:

图片10.jpg

    最后填入类名、头文件名、源文件名、界面文件名等完成创建。

图片11.jpg

    上面创建了一个qt窗口,但是只是增加了几个文件,并没有添加到编译系统。下面修改CMakeLists.txt使得catkin可以编译qt组件。一个典型的配置如下:

cmake_minimum_required(VERSION 2.8.3)
project(test_ros_qt)
add_compile_options(-std=c++11)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)
find_package(Qt5 REQUIRED COMPONENTS  Widgets)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(SOURCES
  src/test_node.cpp
  src/mainwindow.cpp
)
set(FORMS
  src/mainwindow.ui
)

catkin_package(
)

include_directories(
  include/test_node_qt
  ${catkin_INCLUDE_DIRS}
)

add_executable(${PROJECT_NAME}_node ${SOURCES} ${FORMS})
target_link_libraries(${PROJECT_NAME}_node
  ${catkin_LIBRARIES}
)
target_link_libraries(${PROJECT_NAME}_node  Qt5::Widgets )

    重要语句解释:

set(CMAKE_AUTOMOC ON) #QT中使用moc元对象编译器分析QT语句,然后才交给标准的C++编译器。
set(CMAKE_AUTOUIC ON) #QT中使用uic分析ui代码
set(CMAKE_INCLUDE_CURRENT_DIR ON) #设置工程包含当前目录

    然后编译运行即可。



QT中显示点云

    熟悉PCL的朋友应该知道它自带了可视化点云的类,这些组件基于VTK。因此若想在QT中显示点云,一个直接的方法是使用VTK进行显示。当然也可以使用OpenGL。下面介绍基于VTK的点云可视化方法:

  1. 安装VTK

首先从官网上下载VTK的源码:https://vtk.org/download/ 。我这里选择VTK8.2,解压后进行目录,执行:

mkdir build
cd build
cmake -DVTK_QT_VERSION:STRING=5 \
      -DQT_QMAKE_EXECUTABLE:PATH=/home/chen/QtCreator/latest/bin \
      -DVTK_Group_Qt:BOOL=ON \
      -DCMAKE_PREFIX_PATH:PATH=/home/chen/QtCreator/latest/lib/Qt/lib  \
      -DBUILD_SHARED_LIBS:BOOL=ON \
make -j4 #编译
sudo make install #安装

    PS:正常Qt应该是这么配置的,

cmake -DVTK_QT_VERSION:STRING=5 \ #QT版本
      -DQT_QMAKE_EXECUTABLE:PATH=/path/to/qt5.2.1-install/5.2.1/gcc_64/bin/qmake \ #qmake的路径
      -DVTK_Group_Qt:BOOL=ON \
      -DCMAKE_PREFIX_PATH:PATH=/path/to/qt.5.2.1-install/5.2.1/gcc_64/lib/cmake  \ #qt中cmake的路径
      -DBUILD_SHARED_LIBS:BOOL=ON
      .. #VTK目录

    编译安装完成后,将 build/lib/libQVTKWidgetPlugin.so 复制到 /home/chen/QtCreator/latest/lib/Qt/plugins/designer/目录下。ps:正常Qt应该复制到:/home/chen/Qt5.5/Tools/QtCreator/lib/Qt/plugins/designer/目录。这样使用Qt designer的时候,就出现该vtk控件了。

    下面通过一个综合实例来了解一下如何使用VTK组件显示点云。


综合实例:QT点云显示

    根据前面的介绍,建立的工程如下:

图片12.jpg

    其中ui设计文件如下:

图片13.jpg

    mainwindow.h的代码如下:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<QLabel>
#include <QVTKWidget.h>
#include <vtkRenderWindow.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>

typedef pcl::PointXYZRGB PointT;
typedef pcl::PointCloud<PointT> PointCloud;

namespace Ui {
    class MainWindow;
}
class MainWindow : public QMainWindow
{
  Q_OBJECT
public:
  explicit MainWindow(QWidget *parent = nullptr);
  ~MainWindow();
  boost::shared_ptr<pcl::visualization::PCLVisualizer> densePointCloudViewer;
  PointCloud::Ptr densePointCloud;
private:
  Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

    这里面定义一个点云指针,和一个PCL可视化对象,并设置为智能指针。

    mainwindow.cpp的代码如下:

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  densePointCloudViewer.reset (new pcl::visualization::PCLVisualizer ("DensePointMap", false));
     densePointCloudViewer->setBackgroundColor (0, 0, 0);
     densePointCloudViewer->addCoordinateSystem (0.5);//设置坐标轴大小
     densePointCloudViewer->initCameraParameters ();
     ui->qvtkWidget->SetRenderWindow (densePointCloudViewer->getRenderWindow());
     densePointCloudViewer->setupInteractor (ui->qvtkWidget->GetInteractor (), ui->qvtkWidget->GetRenderWindow ());
     ui->qvtkWidget->update ();
     
     
  densePointCloud.reset (new PointCloud);
  densePointCloud->points.resize (1000);
  for (size_t i = 0; i < densePointCloud->points.size (); ++i)
  {
    densePointCloud->points[i].x = 2 * rand () / (RAND_MAX + 1.0f);
    densePointCloud->points[i].y = 2 * rand () / (RAND_MAX + 1.0f);
    densePointCloud->points[i].z = 2 * rand () / (RAND_MAX + 1.0f);
    densePointCloud->points[i].r = 255;
    densePointCloud->points[i].g = 255;
    densePointCloud->points[i].b = 255;
  }

    densePointCloudViewer->addPointCloud (densePointCloud, "cloud");
    ui->qvtkWidget->update ();
}


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

    对熟悉PCL的朋友来说上面的代码还是很简单的,唯一需要注意的点是每次更新PCLVisualizer对象,都要将绑定的VTKWidget更新。

    test_node.cpp是节点主程序,代码如下:

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

int main(int argc, char **argv)
{
  ros::init(argc, argv, "test_node");
  ros::NodeHandle nh;
  ROS_INFO("Hello world!");
  ROS_INFO("Hello OK!klk");
  
  QApplication a(argc,argv);
  MainWindow w;
  w.show();
  return a.exec();
}

    接下来是重头戏,CMakeLists.txt如下:

cmake_minimum_required(VERSION 2.8.3)
project(test_ros_qt)

add_compile_options(-std=c++11)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  std_msgs
)

find_package(
    Qt5 REQUIRED COMPONENTS  Widgets
)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

catkin_package(
#  INCLUDE_DIRS include
#  LIBRARIES test_ros_qt
#  CATKIN_DEPENDS roscpp
#  DEPENDS system_lib
)

include_directories(
    include/test_node_qt
    include
    ${catkin_INCLUDE_DIRS}
    /usr/local/include
     /usr/include/pcl-1.7
      /usr/include/vtk-6.2
)

set(LIBS
        -lpcl_common
        -lpcl_search
        -lpcl_features
        -lpcl_segmentation
        -lpcl_recognition
        -lpcl_visualization
            -L/usr/lib/x86_64-linux-gnu/
            -L/usr/lib/x86_64-linux-gnu/
             -lboost_system
             -lboost_thread
         -lvtkRenderingCore-6.2
         -lvtkCommonDataModel-6.2
         -lvtkCommonMath-6.2
         -lvtkCommonCore-6.2
         -lvtkGUISupportQt-6.2
         Qt5::Widgets
)

set(SOURCES
  src/test_node.cpp
  src/mainwindow.cpp
)

set(FORMS
  src/mainwindow.ui
)

add_executable(${PROJECT_NAME}_node ${SOURCES} ${FORMS})
target_link_libraries(
    ${PROJECT_NAME}_node
    ${catkin_LIBRARIES} ${LIBS}
)

    我尝试了一下,好像不能直接find_package找到PCL之类的库,直接设置路径才能编译通过。

    最后,就是编译程序,运行结果如下:

图片14.jpg


    

    博主在这上面花了好几天时间,血泪之作。



上一篇:
下一篇: 没有了

首页 所有文章 机器人 计算机视觉 自然语言处理 机器学习 编程随笔 关于