ROS和QT混合编程

ROS和QT混合编程

    • 1.使用的软件
    • 2.准备工作
    • 3.新建QT的相关文件
    • 4.修改main.cpp
    • 5.文件示例
      • 5.1 main.cpp
      • 5.2 qttest.h
      • 5.3 qttest.cpp
      • 5.4 CMakeLists.txt
      • 5.5 package.xml
      • 5.6 源代码
    • 6 写在最后

1.使用的软件

  1. Qt5全家桶套餐,具体安装方法可见博客;
  2. QT的带ROS插件版本,下载地址;
  3. ROS。

2.准备工作

需要一个工作空间、ros包,为了方便后面教程的铺开,做一个示例如下:
工作空间:

mkdir -p ~/catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace
cd ..
catkin_make

在src目录下新建一个ros包,如:

catkin_create_pkg qt_ros roscpp std_msgs


在这个包下面任意一个文件夹,个人喜欢用ros文件夹,在里面先添加一个不为空的文件,比如main.cpp(原因在于qt creator不识别空的文件夹……)。

#include 

int main(int argc, char *argv[])
{
    return 0;
}

文件的结构如下:
ROS和QT混合编程_第1张图片

3.新建QT的相关文件

使用QT creator打开工作空间。(这个网上教程很多)

在qt_ros包的ros文件夹上,右键选择Add New...,然后选择Qt的Qt Designer Form Class

ROS和QT混合编程_第2张图片

然后在Choose a Form Template下选择Main Window(也可已选择其他,按照需求),其他的不用修改直接Next:

ROS和QT混合编程_第3张图片

就可设置类的名字,在这里只需要修改Class name即可,其他的会自动修改:
ROS和QT混合编程_第4张图片

之后一路Next即可,就会进入到如下的界面,然后就可以开始编程了。

ROS和QT混合编程_第5张图片

最后的到的结构如下:
ROS和QT混合编程_第6张图片

4.修改main.cpp

刚刚新建的main.cpp只是为了让目录能够被Qt Creator识别到,现在需要修改它,以便结合QT的程序进行编程。

#include "qttest.h"
#include 

int main(int argc, char *argv[])
{
    ros::init(argc, argv, "qt_ros_node");
    QApplication a(argc, argv);
    QtTest w;
    w.show();

    return a.exec();
}

5.文件示例

结合ROS和Qt的编程需要注意到,QT有自己的循环机制,ROS也有一套循环机制,不能冲突了,所以需要使用QT的定时器来进行ROS消息的刷新。示例代码如下:

5.1 main.cpp

参考前一小节。

5.2 qttest.h

#ifndef QTTEST_H
#define QTTEST_H

#include 
#include 
#include 

// ros
#include 
#include 

namespace Ui
{
class QtTest;
}

class QtTest : public QMainWindow
{
    Q_OBJECT

public:
    explicit QtTest(QWidget *parent = nullptr);
    ~QtTest();

    void timerLoop();
    void exampleCallback(const std_msgs::Int16Ptr &msg);

private:
    Ui::QtTest *ui;


    // ros
    ros::NodeHandle n_;
    ros::Subscriber example_sub_;
    ros::Publisher example_pub_;

    QTimer *mpTimer;
};

#endif // QTTEST_H

5.3 qttest.cpp

#include "qttest.h"
#include "ui_qttest.h"

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

   example_sub_ = n_.subscribe("/qt_ros/example1", 1, &QtTest::exampleCallback, this);
   example_pub_ = n_.advertise<std_msgs::Int16>("/qt_ros/example2", 1);

   // 定时器相关初始化
   mpTimer = new QTimer(this);
   mpTimer->setInterval(20); // 单位毫秒
   connect(mpTimer, &QTimer::timeout, this, &QtTest::timerLoop);// 定时器信号槽函数
   mpTimer->start();
}

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


void QtTest::timerLoop()
{
   std_msgs::Int16 info;
   info.data = 10;
   example_pub_.publish(info);
   ros::spinOnce();
}

void QtTest::exampleCallback(const std_msgs::Int16Ptr &msg)
{
   qDebug() << msg->data;
}

5.4 CMakeLists.txt

cmake_minimum_required(VERSION 2.8.3)
project(qt_ros)


add_compile_options(-std=c++11)

find_package(catkin REQUIRED COMPONENTS
 roscpp
 std_msgs
)

######################
## QT configuration ##
######################

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

find_package(Qt5 COMPONENTS Core Gui Widgets Charts REQUIRED)

###################################
## catkin specific configuration ##
###################################
catkin_package()

###########
## Build ##
###########

include_directories(
# include
 ${catkin_INCLUDE_DIRS}
)

###########
## Build ##
###########

add_executable(qt_ros_node ros/main.cpp ros/qttest.cpp ros/qttest.ui)
target_link_libraries(qt_ros_node ${catkin_LIBRARIES} Qt5::Core Qt5::Gui Qt5::Widgets Qt5::Charts)

5.5 package.xml


<package format="2">
 <name>qt_rosname>
 <version>1.0.0version>
 <description>The qt_ros packagedescription>

 <maintainer email="[email protected]">emotionskymaintainer>

 <license>TODOlicense>

 <buildtool_depend>catkinbuildtool_depend>
 <depend>roscppdepend>
 <depend>std_msgsdepend>

package>

5.6 源代码

原单线程代码
多线程实现的代码
说明:单线程版本的代码就是博客中这样的代码实现,也没有什么可关注学习的,在本人的git仓库中已经进行了移除。对应的,给出了多线成版本的实现,但是由于本人已经逃离了机器人这个行业,所以这个代码也就是随手写了一下,并没有进行调试,如有需要,还请自行进行调试解决bug。

6 写在最后

对于本博客中给出的这种混合编程的方法在处理的效率上是很难尽人意的,毕竟是同步的方式进行实现,更优的处理是使用多线程的方式进行实现。使用 QThread创建一个线程,将ROS的循环部分放到这个线程中进行处理,并且使用QT的信号与槽的方式进行ROS所在线程主线程(也就是界面)进行数据交互,这样的处理好处是保证了ROS的实时,毕竟QT界面的循环是很慢的……
由于博主已经脱离了ROS开发这个圈子,这部分的代码实现也就一直没写,QT的多线程开发也不是什么难事,网络上很多……
(或许某天有捣鼓的心情再来写一下也不一定,笑哭)

你可能感兴趣的:(软件使用,ubuntu开发,c++,linux)