making a ros node from a qt thread - qt

I have a qt thread in my application which emits a Mat type image so that other threads can use it. the image is coming from camera by using VideoCapture Object of opencv library. now what i intend to do is getting this image from a rostopic, not from camera directly. in order to do that i must create a ros node in my thread and here i am stuck. is there anyone who has the experience to integrate ros node and qt?
here is my thread:
#include "../include/Ground_Station/camera.h"
#include <iostream>
using namespace std;
Camera::Camera()
{
}
void Camera::run()
{
VideoCapture cap;
cap.open(0);
while(1){
Mat image;
cap >> image;
cvtColor(image,image,CV_BGR2RGB);
emit ImgSignal(&image);
QThread::msleep(30);
}
}
and Camera.h:
#ifndef CAMERA_H
#define CAMERA_H
#include <QObject>
#include <QThread>
#include <QtCore>
#include <QtGui>
#include <image_transport/image_transport.h>
#include <cv_bridge/cv_bridge.h>
#include <ros/ros.h>
#include <opencv2/opencv.hpp>
using namespace cv;
class Camera: public QThread
{
Q_OBJECT
public:
Camera();
void run();
bool Stop = false;
signals:
void ImgSignal(Mat*);
private:
public slots:
};
#endif // THREAD_H

Basically, your executable file containing the main() function must be your ros node and your QT application at the same time. In your "main.cpp"
you call ros::init(...) and subscribe to the topic you want to listen to. Your subscriber callback function may convert the ros image to Mat and emmit an ImgSignal every time it is called. To do all that, I'd create a RosImageProvider class, something along the lines ..
class RosImageProvider: public QObject
{
Q_OBJECT
public:
void ImageSubscriberCallback(const sensor_msgs::Image::ConstPtr& img);
...
signals:
void ImgSignal(Mat*);
};

I encountred the same problem when dealing with TCP/IP connection from a ROS node within Qt and my solution was to inherit directly from the QThread object, thus when initializing the class, you initialize the ROS node and implement the work TODO in callbacks and the thread run() function.
So finally, my code looked something like this :
#ifndef INCLUDE_TCPHANDLER_HPP_
#define INCLUDE_TCPHANDLER_HPP_
#include <ros/ros.h>
#include <QThread>
#include <string>
class TCP_Handler : public QThread
{
Q_OBJECT
private:
int init_argc;
char** init_argv;
ros::Publisher cmd_control_publisher;
ros::Subscriber feedback_subscriber;
public:
TCP_Handler()
{}
virtual ~TCP_Handler(){}
/**
* #brief ROS methods
*
*/
inline bool init_ros()
{
int argc =0; char** argv = new char*();
ros::init(argc,argv,"tcp_handler");
ros::NodeHandle n;
cmd_control_publisher = n.advertise<robot_common::cmd_control>("cmd_control", 1000);
feedback_subscriber = n.subscribe<robot_common::feedback>("wifibot_pose", 4, &TCP_Handler::FeedbackCallback , this);
return true;
}
void FeedbackCallback(const robot_common::feedback::ConstPtr& pose)
{
//.....
}
/**
* #brief Threading methods
*
*/
virtual void init(int, std::string ip_addr = "127.0.0.1") = 0;
virtual void run() = 0;
virtual void stop() = 0;
/**
* #brief TCP methods (Server/Client have to implement these folks)
*
*/
virtual bool Send_data(char* data, int size) = 0;
virtual int Receive_data(char* in_data, int size) = 0;
virtual bool Open_connection() = 0;
virtual void Close_connection() = 0;
};
#endif /* INCLUDE_TCPHANDLER_HPP_ */
This code is just a template of a Qt-threaded-ROS node for TCP connction as I don't know your specific needs. feel free to build your own !
Cheers,

Related

Why is the Qt event loop left

I want a small program doing the following:
start a single-shot QTimer
when it times out, a QMessageBox is shown
if button "Continue" is clicked, the box is closed and the timer restarted
if button "Stop" is clicked, the box is closed and the application exited
The problem I have is that the event loop is left as soon as I hide the message box. The box is displayed only once. I reproduced my program in a console version and it runs as expected. Here is my code. Thanks in advance for your help.
main.c
#include <QtGui/QApplication>
#include "TimedDialog.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
TimedDialog dialog(&app, SLOT(quit()));
dialog.run();
return app.exec();
}
TimedDialog.h
#ifndef TIMED_DIALOG_H
#define TIMED_DIALOG_H
#include <QObject>
#include <QTimer>
class QMessageBox;
class QPushButton;
class QAbstractButton;
class TimedDialog : public QObject
{
Q_OBJECT
public:
TimedDialog(
QObject const * receiver,
char const * method);
~TimedDialog();
void run(void);
signals:
void stop(void);
private:
QMessageBox* _box;
QPushButton* _buttonContinue;
QPushButton* _buttonStop;
QTimer _timer;
static int const DELAY = 2 * 1000; // [ms]
private slots:
void onTimeout(void);
void onButtonClicked(QAbstractButton * button);
};
#endif
TimedDialog.cpp
#include <assert.h>
#include <QMessageBox>
#include <QPushButton>
#include "TimedDialog.h"
TimedDialog::TimedDialog(
QObject const * receiver,
char const * method)
: QObject(),
_box(0),
_buttonContinue(0),
_buttonStop(0),
_timer()
{
_box = new QMessageBox();
_box->setWindowModality(Qt::NonModal);
_box->setText("Here is my message!");
_buttonContinue = new QPushButton("Continue");
_box->addButton(_buttonContinue, QMessageBox::AcceptRole);
_buttonStop = new QPushButton("Stop");
_box->addButton(_buttonStop, QMessageBox::RejectRole);
_timer.setSingleShot(true);
assert(connect(&_timer, SIGNAL(timeout()), this, SLOT(onTimeout())));
assert(connect(_box, SIGNAL(buttonClicked(QAbstractButton *)), this, SLOT(onButtonClicked(QAbstractButton *))));
assert(connect(this, SIGNAL(stop()), receiver, method));
}
TimedDialog::~TimedDialog()
{
delete _box;
}
void TimedDialog::onTimeout(void)
{
_box->show();
}
void TimedDialog::onButtonClicked(QAbstractButton * button)
{
_box->hide();
if (button == _buttonContinue)
{
_timer.start(DELAY);
}
else
{
emit stop();
}
}
void TimedDialog::run(void)
{
_timer.start(DELAY);
}
The created timer is being set as singleshot, which has already called timeout.
If you look at QTimer source code for the call to start() you can see it states: -
If singleShot is true, the timer will be activated only once.
You could fix and simplify the code with the class function QTimer::singleShot

qt asynchron clients response gsoap

i am writing client server application using gsoap lib. the problem is that a have a heavy process function in my server.i want to when special client call this function, the server send message for this special client that "your answer is ready" when this client answer is ready. and its possible that multiple client call this function in same time.
is there any tool like asynchronAnswer in qt? and if not how can i handle it with qt or gsoap tools?
whats the true architect of handle this problems? using multi thread in client calling and wait for response in other thread or exactly call client by its ip in server or something better?
thanks,
You can try to use QWebSocket for this task. You have connected client list, if client send a request for "heavy process function", you are puting in thread pool, and sending replay to the specific client after calculations are done. In code it will be something like this:
server.h
#ifndef SERVER_H
#define SERVER_H
#include <QObject>
#include <QtWebSockets>
class Server : public QObject
{
Q_OBJECT
public:
explicit Server(QObject *parent = 0);
~Server();
signals:
void closed();
public slots:
private slots:
void onNewConnection();
void onMessage(QString message);
void onDisconnected();
private:
QWebSocketServer* m_pWebSocketServer;
QList<QWebSocket*> m_clients;
};
#endif // SERVER_H
server.cpp
#include <QThreadPool>
#include "server.h"
#include "heavytask.h"
Server::Server(QObject *parent) :
QObject(parent),
m_pWebSocketServer(new QWebSocketServer(QStringLiteral("Server"), QWebSocketServer::NonSecureMode, this))
{
if (m_pWebSocketServer->listen(QHostAddress::Any, 4000)) {
connect(m_pWebSocketServer, &QWebSocketServer::newConnection, this, &Server::onNewConnection);
connect(m_pWebSocketServer, &QWebSocketServer::closed, this, &Server::closed);
}
}
void Server::onNewConnection()
{
QWebSocket *pSocket = m_pWebSocketServer->nextPendingConnection();
connect(pSocket, &QWebSocket::textMessageReceived, this, &Server::onMessage);
connect(pSocket, &QWebSocket::disconnected, this, &Server::onDisconnected);
m_clients << pSocket;
}
void Server::onMessage(QString message)
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (message == "Start heavy process function in your server, please") {
HeavyTask* ht = new HeavyTask(pClient);
QThreadPool::globalInstance()->start(ht);
}
}
void Server::onDisconnected()
{
QWebSocket *pClient = qobject_cast<QWebSocket *>(sender());
if (pClient) {
m_clients.removeAll(pClient);
pClient->deleteLater();
}
}
Server::~Server()
{
m_pWebSocketServer->close();
qDeleteAll(m_clients.begin(), m_clients.end());
}
heavytask.h
#ifndef HEAVYTASK_H
#define HEAVYTASK_H
#include <QThreadPool>
#include <QRunnable>
#include <QWebSocket>
class HeavyTask : public QRunnable
{
public:
explicit HeavyTask(QWebSocket* client);
void run();
private:
QWebSocket* m_client;
};
#endif // HEAVYTASK_H
heavytask.cpp
#include "heavytask.h"
HeavyTask::HeavyTask(QWebSocket* client) : m_client(client)
{
}
void HeavyTask::run()
{
/*
Do your havy task;
*/
if (m_client != nullptr) {
if (m_client->isValid()) {
m_client->sendTextMessage("Your answer is ready!");
}
}
}
and main.cpp
#include <QCoreApplication>
#include "server.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Server server(&a);
QObject::connect(&server, &Server::closed, &a, &QCoreApplication::quit);
return a.exec();
}
Hope it'll be useful. (Not tasted at all, but compiling)

'QMessageBox::critical' : none of the 4 overloads could convert all the argument types

I want to display an error message whenever my independent thread encounters the word "alert1" in a specific .txt file. But I get the above error inside the monitorForAlerts() inside mythread.cpp file. The line expectedly executes if I were to place it inside dialog.cpp. So I guess this is due to non-inheritance of this object. Can you please advise me how to solve this error for the given code?
Here is the code:
dialog.h
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include <QtCore>
#include "mythread.h"
namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
Q_OBJECT
public:
explicit Dialog(QWidget *parent = 0);
~Dialog();
public slots:
private:
Ui::Dialog *ui;
private slots:
void on_pushButton_clicked();
void on_pushButton_2_clicked();
};
#endif // DIALOG_H
mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QtCore>
#include <QDebug>
#include <QFile>
#include <Windows.h>
#include <QMessageBox>
#include <QTimer>
#define ALERTS_MESSAGE_STORAGE_PATH "E:\\QT1\\simpleGUIThread2\\simpleGUIThread2\\usbAlert.txt"
#define TIMER_VALUE 500
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
void run();
QString name;
void monitorForAlerts();
int exec();
public slots:
signals:
void testSignal(QString message);
public slots:
};
#endif // MYTHREAD_H
dialog.cpp
#include "dialog.h"
#include "ui_dialog.h"
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
}
Dialog::~Dialog()
{
delete ui;
}
void Dialog::on_pushButton_clicked()
{
ui->label->show();
}
void Dialog::on_pushButton_2_clicked()
{
ui->label->hide();
}
mythread.cpp
#include "mythread.h"
#include "dialog.h"
MyThread::MyThread(QObject *parent) :
QThread(parent)
{
}
void MyThread::run()
{
exec();
}
int MyThread::exec()
{
while(1)
{
monitorForAlerts();
emit(testSignal("hello world!!"));
sleep(1);
}
}
void MyThread::monitorForAlerts()
{
QString response = ALERTS_MESSAGE_STORAGE_PATH;
QFile resp(response);
resp.open(QIODevice::WriteOnly);
resp.close();
QFile resp1(response);
char buf[121];
char buf1[] = "alert1";
char buf2[] = "alert2";
resp1.open(QIODevice::ReadOnly);
while(resp1.size() == 0)
{
Sleep(3000);
}
qint64 lineLength = resp1.readLine(buf, sizeof(buf));
resp1.close();
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
}
if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
}
main.cpp
#include "dialog.h"
#include <QApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
w.show();
return a.exec();
}
LATEST UPDATE*********************************************************************
Hi Zlatomir,
I choose to take your 1st advice. I have created a signal that the thread will emit and connect it to a slot for QDialog. Please let me know if my understanding is correct, because I do not know where to implement the connect(), since the signal is declared in mythread.h and the slot in dialog.h. The connection type argument for connect is Qt::QueuedConnection, so that gui elements from another thread different than main-thread.
are NOT created. Is this statement correct? and where do I place this?
connect( mThread, SIGNAL(alertSignal(QString)), this, SLOT(alertSlot(QString)), Qt::QueuedConnection);
mythread.h
//....
signals:
void alertSignal(QString message);
//....
dialog.h
//....
public slots:
void alertSlot(QString message);
//....
mythread.cpp
//....
if(strcmp(buf,buf1) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 1!!";
emit(alertSignal("alert1"));
}
else if(strcmp(buf,buf2) == 0)
{
QFile::remove(ALERTS_MESSAGE_STORAGE_PATH);
qDebug()<<"warning 2!!";
emit(alertSignal("alert2"));
}
dialog.cpp
void Dialog::alertSlot(QString message)
{
if(strcmp(message, "alert1"))
QMessageBox::critical(this,tr("ERROR"),tr("Large change in illumination.\nPlease re-capture reference image.\n"));
else if(strcmp(message, "alert2"))
QMessageBox::critical(this,tr("ERROR"),tr("The camera position has been moved or an object is obscuring its view.\nPlease check the device.\n"));
}
Now if this were correct, how do i implement the connect() and in which file?
The first argument is the problem, in your case this is not a good argument, because there this is a pointer to a MyThread instance, and MyThread is not a QWidget (is not derived from QWidget).
To solve this you can show the QMessageBox::critical from a slot in mainwindow (the Dialog class in your code, there you pass the instance of main-window that is a QWidget) and connect that slot with a signal that you emit from your thread, make sure that the connection type argument for connect is Qt::QueuedConnection, so that you don't try to create gui elements from another thread different than main-thread.
Another option would be to validate the data before you start the second thread and to tell
the user that he needs to provide the right files.
LE: Also check the QThread's documentation for the recommended way to use the class, now it's recommended not to derive from QThread.
LE2 - answer to the update
That connect can be made where ever you can have the two instances that you want to connect, in your case main.cpp is a good place to connect those (don't forget to fully qualify the name for connect: QObject::connect):
//...
MyThread mThread1;
mThread1.name = "mThread1";
mThread1.start();
Dialog w;
QObject::connect( &mThread1, SIGNAL(alertSignal(QString)), &w, SLOT(alertSlot(QString)), Qt::QueuedConnection);
w.show();
//...

Qt emit signal and continue execution

I have something like that:
Prueba.h
#include <QObject>
class Prueba:public QObject
{
Q_OBJECT
private:
bool waiting;
public:
Prueba();
void test();
void fin();
signals:
void comenzo();
};
Prueba.cpp
#include "prueba.h"
#include <QDebug>
Prueba::Prueba()
{
waiting=true;
}
void Prueba::test()
{
qDebug()<<"Comenzando";
emit(comenzo());
while(waiting) {
qDebug()<<"Esperando";
}
qDebug()<<"Termino";
}
void Prueba::fin()
{
waiting=false;
}
Principal.h
#include <QObject>
#include "prueba.h"
class Principal:public QObject
{
Q_OBJECT
private:
Prueba * prueba;
public:
Principal();
private slots:
void processSignal();
};
Principal.cpp
#include <QDebug>
Principal::Principal()
{
prueba=new Prueba();
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()));
prueba->test();
}
void Principal::processSignal()
{
for(int i=0;i<1000;i++) {
qDebug()<<"Algo";
}
prueba->fin();
}
When I call prueba->test(), and it emit the signal "comenzo", Principal::proccessSignal is completely executed, and never enters to the cycle "while(waiting)". What I need to do for that the code inside the loop is executed?
My guess is your signal connection. By default Qt will execute your signal as a direct call to the slot the objects are in the same thread as you can see here:
QMetaObject::Connection QObject::connect(
const QObject * sender, const char * signal,
const char * method, Qt::ConnectionType type = Qt::AutoConnection) const
See Qt::ConnectionType here http://qt-project.org/doc/qt-5.0/qtcore/qt.html#ConnectionType-enum
So if you use
Qt::QueuedConnection
in your signal connection
connect(prueba,SIGNAL(comenzo()),SLOT(processSignal()), Qt::QueuedConnection);
It should work as expected. See
The slot is invoked when control returns to the event loop of the receiver's thread. The slot is executed in the receiver's thread.

Asynchronously Run Console Output and GUI in Qt

I am working on building a GUI around a console application. I would like to be able to click a button to run the console app and show the console output inside of the GUI itself. How might I accomplish this? I am working in Linux.
You could also try QProcess. It provides a Qt interface to launching external processes, reading their I/O and waiting, or not, on their completion.
For your purpose, it sounds like you want the process to run asynchronously, so code might look like :
myprocessstarter.h :
#include <QObject>
#include <QProcess>
#include <QDebug>
class MyProcessStarter : public QObject
{
Q_OBJECT
public:
MyProcessStarter() : QObject() {};
void StartProcess();
private slots:
void readStandardOutput();
private:
QProcess *myProcess;
};
main.cpp:
#include "myprocessstarter.h"
void MyProcessStarter::StartProcess()
{
QString program = "dir";
QStringList arguments;
// Add any arguments you want to be passed
myProcess = new QProcess(this);
connect(myProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
myProcess->start(program, arguments);
}
void MyProcessStarter::readStandardOutput()
{
QByteArray processOutput;
processOutput = myProcess->readAllStandardOutput();
qDebug() << "Output was " << QString(processOutput);
}
void main(int argc, char** argv)
{
MyProcessStarter s;
s.StartProcess();
}
I wanted to do something similar in one of my applications. I redirected all output from the standard stream (cout) to my console window. To periodically read out the stream contents I use a timer loop. Works fine for me.
StdRedirector.cpp
#include "StdRedirector.h"
QMutex coutMutex;
void outcallback(const char* ptr, std::streamsize count, void* bufferString)
{
string *b = (string *) bufferString;
string t;
for (int i=0; i < count; i++)
{
if (ptr[i] == '\n')
{
t = t + "\n";
} else {
t = t + ptr[i];
}
}
coutMutex.lock();
*b = *b + t;
coutMutex.unlock();
}
void ConsoleWindow::updateTimer(void)
{
coutMutex.lock();
if (bufferString.size() > 0)
{
consoleBox->insertPlainText(QString(bufferString.c_str()));
bufferString.clear();
QScrollBar *sb = consoleBox->verticalScrollBar();
sb->setValue(sb->maximum());
}
coutMutex.unlock();
}
ConsoleWindow::ConsoleWindow(QWidget *parent) : QWidget(parent)
{
consoleBox = new QTextEdit(this);
consoleBox->setReadOnly(true);
stdRedirector = new StdRedirector<>(std::cout, outcallback, &bufferString);
QVBoxLayout *vb = new QVBoxLayout();
vb->addWidget(consoleBox);
vb->setMargin(0);
vb->setSpacing(0);
setLayout(vb);
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(updateTimer()));
timer->start(100);
}
ConsoleWindow::~ConsoleWindow()
{
delete stdRedirector;
}
StdRedirector.h
#ifndef STD_REDIRECTOR
#define STD_REDIRECTOR
#include <QWidget>
#include <QTextEdit>
#include <QString>
#include <QVBoxLayout>
#include <QTimer.h>
#include <QMutex>
#include <QScrollBar>
#include <iostream>
#include <string>
using namespace std;
template<class Elem = char, class Tr = std::char_traits<Elem>>
class StdRedirector : public std::basic_streambuf<Elem, Tr>
{
typedef void (*pfncb) ( const Elem*, std::streamsize _Count, void* pUsrData );
public:
StdRedirector(std::ostream& a_Stream, pfncb a_Cb, void* a_pUsrData) :
m_Stream(a_Stream),
m_pCbFunc(a_Cb),
m_pUserData(a_pUsrData)
{
m_pBuf = m_Stream.rdbuf(this);
}
~StdRedirector()
{
m_Stream.rdbuf(m_pBuf);
}
std::streamsize xsputn(const Elem* _Ptr, std::streamsize _Count)
{
m_pCbFunc(_Ptr, _Count, m_pUserData);
return _Count;
}
typename Tr::int_type overflow(typename Tr::int_type v)
{
Elem ch = Tr::to_char_type(v);
m_pCbFunc(&ch, 1, m_pUserData);
return Tr::not_eof(v);
}
protected:
std::basic_ostream<Elem, Tr>& m_Stream;
std::streambuf* m_pBuf;
pfncb m_pCbFunc;
void* m_pUserData;
};
class ConsoleWindow : public QWidget
{
Q_OBJECT
public:
ConsoleWindow(QWidget *parent = 0);
~ConsoleWindow();
public slots:
void updateTimer(void);
public:
QTextEdit *consoleBox;
StdRedirector<> *stdRedirector;
string bufferString;
};
#endif
The StdRedirector class is based on code from this forum post: http://www.qtforum.org/article/24554/displaying-std-cout-in-a-text-box.html
Take a look at the popen() function, it might do what you need.
Then you could pass the FILE * to a QTextStream and work in Qt style with it.
I suggest, rather than showing stdout in GUI, having own console output, which essentially means all messages you want to show to users you are sending to your own output.
This way you can have debug messages and such still available from console, wtih potential errors with connections and whatever that can happen and have fully controlled console output in GUI application. Of course this output can also be outputted to stdout so it is visible in console, but it also allows you to append a prefixs like WARNING LOG NOTICE NO_THIS_WENT_WRONG or whatever you want to show to users as your console entry.

Resources