ROS-Qt GUI-如何分配线程?

时间:2019-01-31 15:57:35

标签: c++ multithreading qt user-interface ros

我正在使用C ++ Qt GUI来远程控制ROS机器人。我已经读过ros::spin()命令应该在单独的线程中发出,所以我基本上有了从QMainWindow派生的常用MainWindow,其构造函数设置了GUI元素,使Subscriber Objects订阅了各自的主题(例如,image_transport::Subscriber主题为sensor_msgs/Image),并且还启动了另一个线程。为此,我从QThread派生了一个“ RosThread”类,除了调用ros:MultiThreadedSpinner时启动RosThread::run()之外,它什么也没做。

您可能会说,总体上我对编程没有完全的经验,所以我的问题是,我的项目背后的基本概念对您有意义吗? 尤其应该将NodeHandle和Subscriber对象留在MainWindow中,并从MainWindow构造函数中设置订阅吗?

相关代码段:

mainwindow.cpp:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), itLeft(nh), itArm(nh)
{
    //subscribe to cameras
    imageSubLeft = itLeft.subscribe("/camera_1/image_raw", 1000, &MainWindow::camCallbackLeft, this);
    imageSubArm = itArm.subscribe("/camera_2/image_raw", 1000, &MainWindow::camCallbackArm, this);

    pagestack = new QStackedWidget;

    page1 = new QWidget;
    grid = new QGridLayout;
    page1->setLayout(grid);
    pagestack->addWidget(page1);

    labelLeft = new QLabel;
    labelMid = new QLabel;

    grid->addWidget(labelLeft, 0, 0);
    grid->addWidget(labelMid, 0, 1);

    this->startSpinThread(); //starts the seperate Thread where run() is executed
    this->setCentralWidget(pagestack);
    this->setWindowState(Qt::WindowMaximized);
    this->setMinimumSize(1024, 768);
}    

MainWindow::~MainWindow(){}    
void MainWindow::camCallbackLeft(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::camCallbackArm(const sensor_msgs::Image::ConstPtr &msg){/*some code*/}
void MainWindow::closeEvent(QCloseEvent *event){/*some code*/}  

void MainWindow::startSpinThread()
{
    if(rosSpin.isRunning())
    {
        return;
    }
    //rosSpin is an Object of the of QThread derived class
    rosSpin.start();
}

rosthread.h:

#ifndef ROSTHREAD_H
#define ROSTHREAD_H
#include <ros/ros.h>
#include <QThread>


class RosThread : public QThread
{
    Q_OBJECT
public:
    RosThread();

protected:
    void run();

private:
    ros::MultiThreadedSpinner spinner;
};

#endif // ROSTHREAD_H

rosthread.cpp:

#include "rosthread.h"

RosThread::RosThread()
{

}

void RosThread::run() {
    spinner.spin();
}

main.cpp:

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

int main(int argc, char **argv)
{
  ros::init(argc, argv, "gui_node");

  QApplication app (argc, argv);
  MainWindow *win = new MainWindow();
  win->show();

  return app.exec();
}

1 个答案:

答案 0 :(得分:0)

实际上,不打算以这种方式使用QThread。看看this blog articlethis example

但是无论如何,我还是建议使用标准的C ++线程。 将std::unique_ptr<std::thread> thread;添加到您的MainWindow类中,而不要添加RosThread对象。 要启动线程,请使用thread.reset(new std::thread([](){ static ros::MultiThreadedSpinner spinner; spinner.spin(); });。智能指针std::unique_ptr将自动删除线程对象,尽管您不要忘记在重置/销毁std::thread::join()对象之前使用std::thread::detach()std::unique_ptr。 另一种解决方案是将ros::MultiThreadedSpinner对象放入您的MainWindow类,并使用std::thread创建一个thread.reset(new std::thread(&ros::MultiThreadedSpinner::spin, spinner));

我认为,应该将NodeHandle和Subscriber对象放到另一个类中,如果它们不直接属于MainWindow,则将该类的对象用作MainWindow的成员。