【问题标题】:ROS-Qt GUI - How to distribute the Threads?ROS-Qt GUI - 如何分配线程?
【发布时间】:2019-01-31 15:57:35
【问题描述】:

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

您可能会说,我在一般编程方面并不完全有经验,所以我的问题是,我的项目背后的基本概念是否对您有意义? 特别是我应该将 NodeHandle 和订阅者对象留在 MainWindow 中并从 MainWindow 构造函数设置订阅?

相关代码sn-ps:

主窗口.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();
}

【问题讨论】:

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


    【解决方案1】:

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

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

    在我看来,你应该把你的 NodeHandle 和 Subscriber 对象放到另一个类中,如果它们不直接属于 MainWindow,你应该使用这个类的一个对象作为 MainWindow 的成员。

    【讨论】:

    • 非常感谢您将我指向那篇文章,这真的很有见地。正如您所建议的,我想我会尝试将 NodeHandle 和 Subscriber 放在另一个类中!我想将回调函数放在同一个类中会有意义吗?
    • 我想是的,是的。始终尝试以有意义的方式组织班级成员,并且每个班级只有一项任务。
    • 我试过了,但是有很多问题。首先,回调确实属于 MainWindow,因为它们必须设置所有标签。将订阅者和 NH 放在另一个类中似乎不起作用:窗口仅在终止进程后打开,因此似乎没有多个线程?!我认为这可能会解决我遇到的烦人的分段错误问题,但无论如何我可能走错了路。非常感谢您的帮助!
    • 遗憾的是无法编辑上面的评论:我确实设法让它按照您发布的示例中描述的方式进行。不过,如前所述,我只将微调器放在“工人阶级”中。不幸的是,它并没有解决分段错误,但至少我现在正在以“正确”的方式进行操作!
    • 何时何地会出现 seg 错误?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2021-05-16
    相关资源
    最近更新 更多