ROS-Qt GUI - 如何分配线程?
ROS-Qt GUI - How to distribute the Threads?
我正在使用 C++ Qt GUI 来远程控制 ROS 机器人。我读到 ros::spin()
命令应该在单独的线程中发出,所以我基本上有从 QMainWindow
派生的常用 MainWindow,其构造函数设置 GUI 元素,使订阅者对象订阅各自的主题(例如 image_transport::Subscriber
用于 sensor_msgs/Image
个主题)并且还启动了另一个线程。为此,我从 QThread
派生了一个 "RosThread" class,它除了在 RosThread::run()
被调用时启动一个 ros:MultiThreadedSpinner
之外什么都不做。
您可能会说,我在一般编程方面经验不足,所以我的问题是,我的项目背后的基本概念对您来说是否有意义?
特别是我应该将 NodeHandle 和订阅者对象留在 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();
}
实际上,QThread 并不打算这样使用。看看this blog article and this example.
但无论如何,我建议使用标准的 C++ 线程。
将 std::unique_ptr<std::thread> thread;
添加到您的 MainWindow class 而不是 RosThread
对象。
要启动线程,请使用 thread.reset(new std::thread([](){ static ros::MultiThreadedSpinner spinner; spinner.spin(); });
。智能指针 std::unique_ptr
将自动删除线程对象,尽管您不应该忘记在 resetting/destroying 您的 std::unique_ptr
对象之前使用 std::thread::join()
或 std::thread::detach()
。
另一种解决方案是将 ros::MultiThreadedSpinner
对象放入您的 MainWindow class 并使用 thread.reset(new std::thread(&ros::MultiThreadedSpinner::spin, spinner));
.
创建一个 std::thread
在我看来,如果 NodeHandle 和 Subscriber 对象不直接属于 MainWindow,您应该将它们放入另一个 class 并使用此 class 的对象作为 MainWindow 的成员。
我正在使用 C++ Qt GUI 来远程控制 ROS 机器人。我读到 ros::spin()
命令应该在单独的线程中发出,所以我基本上有从 QMainWindow
派生的常用 MainWindow,其构造函数设置 GUI 元素,使订阅者对象订阅各自的主题(例如 image_transport::Subscriber
用于 sensor_msgs/Image
个主题)并且还启动了另一个线程。为此,我从 QThread
派生了一个 "RosThread" class,它除了在 RosThread::run()
被调用时启动一个 ros:MultiThreadedSpinner
之外什么都不做。
您可能会说,我在一般编程方面经验不足,所以我的问题是,我的项目背后的基本概念对您来说是否有意义? 特别是我应该将 NodeHandle 和订阅者对象留在 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();
}
实际上,QThread 并不打算这样使用。看看this blog article and this example.
但无论如何,我建议使用标准的 C++ 线程。
将 std::unique_ptr<std::thread> thread;
添加到您的 MainWindow class 而不是 RosThread
对象。
要启动线程,请使用 thread.reset(new std::thread([](){ static ros::MultiThreadedSpinner spinner; spinner.spin(); });
。智能指针 std::unique_ptr
将自动删除线程对象,尽管您不应该忘记在 resetting/destroying 您的 std::unique_ptr
对象之前使用 std::thread::join()
或 std::thread::detach()
。
另一种解决方案是将 ros::MultiThreadedSpinner
对象放入您的 MainWindow class 并使用 thread.reset(new std::thread(&ros::MultiThreadedSpinner::spin, spinner));
.
std::thread
在我看来,如果 NodeHandle 和 Subscriber 对象不直接属于 MainWindow,您应该将它们放入另一个 class 并使用此 class 的对象作为 MainWindow 的成员。