ROS-Qt GUI - Как распределить потоки? - PullRequest
0 голосов
/ 31 января 2019

Я работаю над C ++ Qt GUI для удаленного управления роботом ROS.Я читал, что команда ros::spin() должна быть выполнена в отдельном потоке, поэтому у меня есть обычное MainWindow, производное от QMainWindow, конструктор которого устанавливает элементы GUI, заставляет объекты подписчика подписываться на их соответствующие темы (например, * 1003).* для sensor_msgs/Image тем), а также запускает другую тему.Для этого я извлек класс RosThread из QThread, который ничего не делает, кроме запуска ros:MultiThreadedSpinner при вызове RosThread::run().

Как вы, вероятно, можете сказать, я не очень разбираюсь в программировании в целом, поэтому мой вопрос в том, имеет ли смысл основная концепция моего проекта для вас?Особенно я должен оставить 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();
}

1 Ответ

0 голосов
/ 01 февраля 2019

На самом деле, QThread не предназначен для использования таким образом.Взгляните на эту статью блога и этот пример .

Но в любом случае я бы предложил стандартные потоки 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...