PDA

View Full Version : How to use QSerialPort for double thread



nistar
18th November 2015, 14:12
I need a serial port for read camera, and other serial port for write control command.
Now I can read frame, but can't write command to serial port.
And the error: QSocketNotifier: Can only be used with threads started with QThread.


ViSP and UEyeOpenCV(camera) are Third-party libraries.


/*****main.cpp*****/
#include <iostream>
#include "UEyeOpenCV.hpp"
#include "opencv2/opencv.hpp"
#include <servocontroller.h>

#include <visp/vpFeatureBuilder.h>
#include <visp/vpFeatureDepth.h>
#include <visp/vpFeaturePoint.h>
#include <visp/vpHomogeneousMatrix.h>
#include <visp/vpPlot.h>
#include <visp/vpServo.h>
#include <visp/vpVelocityTwistMatrix.h>
#include <visp/vpDot2.h>
#include <visp/vpDisplay.h>
#include <visp/vpImageIo.h>
#include <visp/vpImageTools.h>
#include <visp/vpDisplayOpenCV.h>
#include <visp/vpConfig.h>
#include <visp/vpRobotCamera.h>

int main(){
/* set undistort */
cv::FileStorage fs("out_camera_data.xml", cv::FileStorage::READ);
cv::Mat cameraMatrix, distCoeffs;
fs["Camera_Matrix"] >> cameraMatrix;
fs["Distortion_Coefficients"] >> distCoeffs;
std::cout << "camera matrix: " << cameraMatrix << std::endl
<< "distortion coeffs: " << distCoeffs << std::endl;
cv::Mat image;

/* open camera */
UeyeOpencvCam cam = UeyeOpencvCam(752,480);

/* define a wondow of image*/
vpImage<unsigned char> I(480, 752); // Create a gray level image
cv::Mat grayFrame;
vpDisplayOpenCV d;
d.init(I, 0, 0, "Visual servoing on dot");

/* set dot*/
vpDot2 blob;
blob.setGraphics(true);
blob.setGraphicsThickness(2);
vpImagePoint germ;
bool init_done = false;

/* set com*/
unsigned short zoom=1500;
ServoController com;
com.ServoController::createSerialPort();
com.setTarget(zoom*4);

while(true) {
cv::Mat frame= cam.getFrame();
cv::cvtColor(frame,grayFrame, CV_BGR2GRAY);
cv::undistort(grayFrame,image,cameraMatrix,distCoe ffs);
cv::Mat image2;
cv::flip(image,image2,-1);
vpImageConvert::convert(image2, I);
vpDisplay::display(I);

if (! init_done) {
vpDisplay::displayText(I, vpImagePoint(10,10), "Click in the blob to initialize the tracker", vpColor::red);
if (vpDisplay::getClick(I, germ, false)) {
blob.initTracking(I, germ);
init_done = true;
}
}
else {
blob.track(I);
vpImagePoint mcog;
mcog=blob.getCog();
int x=mcog.get_i();
if (x<240){
zoom=zoom+10;
com.setTarget(zoom*4);
cv::waitKey(33);
}
else{
zoom=zoom-10;
com.setTarget(zoom*4);
cv::waitKey(33);
}
}
vpDisplay::flush(I);
}
}



//servocontroller.h
/*****servocontroller.h*****/
#ifndef SERVOCONTROLLER_H
#define SERVOCONTROLLER_H

#include <string>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <termios.h>
#include <QDebug>
#include <QString>

class ServoController
{
public:
virtual ~ServoController();
void createSerialPort();
void setTarget( unsigned short target );

private:
static const unsigned short mMinChannelValue = 4000;
static const unsigned short mMaxChannelValue = 8000;
unsigned short target;
unsigned char channelNumber;
QSerialPort* myCom;
QByteArray command;
};

#endif // SERVOCONTROLLER_H



/*****servocontroller.cpp*****/
#include "servocontroller.h"
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>
#include <iostream>

void ServoController::createSerialPort()
{
myCom= new QSerialPort();
myCom->setPortName("/dev/ttyACM0");
myCom->open(QIODevice::WriteOnly);
myCom->setBaudRate(9600);
myCom->setDataBits(QSerialPort::Data8);
myCom->setParity(QSerialPort::NoParity);
myCom->setStopBits(QSerialPort::OneStop);
myCom->setFlowControl(QSerialPort::NoFlowControl);
}

ServoController::~ServoController()
{
myCom->close();
}

void ServoController::setTarget(unsigned short target )
{
if (target<mMinChannelValue ){
target=mMinChannelValue;
}
if(target>mMaxChannelValue){
target=mMaxChannelValue;
}

command.resize(4);
command[0]=0x84;
command[1]=0x01;
command[2]=(char)(target & 0x7F);
command[3]=(char)((target >> 7) & 0x7F);
myCom-> QSerialPort::write(command);
}


HEADERS += \
UEyeOpenCV.hpp \
servocontroller.h

SOURCES += \
main.cpp \
ueyeopencv.cpp \
servocontroller.cpp

# important
# library of QSerialport
QT += serialport

# library of OpenCV
INCLUDEPATH += /usr/local/include \
/usr/local/include/opencv \
/usr/local/include/opencv2
LIBS += /usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_imgproc.so

# library of UEye
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../../../usr/lib/release/ -lueye_api
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../../../usr/lib/debug/ -lueye_api
else:unix: LIBS += -L$$PWD/../../../../usr/lib/ -lueye_api
INCLUDEPATH += $$PWD/../../../../usr/include
DEPENDPATH += $$PWD/../../../../usr/include

# libreria de ViSP
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/../../ViSP-build-release/lib/x86_64-linux-gnu/release/ -lvisp
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/../../ViSP-build-release/lib/x86_64-linux-gnu/debug/ -lvisp
else:unix: LIBS += -L$$PWD/../../ViSP-build-release/lib/x86_64-linux-gnu/ -lvisp
INCLUDEPATH += $$PWD/../../ViSP-build-release/lib/x86_64-linux-gnu
DEPENDPATH += $$PWD/../../ViSP-build-release/lib/x86_64-linux-gnu

Vikram.Saralaya
18th November 2015, 14:38
The Qt documentation says:

Note: The serial port is always opened with exclusive access (that is, no other process or thread can access an already opened serial port).

The serial port read in your case probably happens in a separate thread.. You need to make sure read and write happens in the same thread in which you open the port. Hope that helps..

Regards
Vikram

anda_skoa
18th November 2015, 15:36
My guess is that the problem is your missing Q(Core/Ui)Application instance.
So the main thread is not "adopted" as a QThread and thus lacks the necessary event dispatcher for socketnotifier's event handling.

Cheers,
_

nistar
18th November 2015, 15:54
The Qt documentation says:


The serial port read in your case probably happens in a separate thread.. You need to make sure read and write happens in the same thread in which you open the port. Hope that helps..

Regards
Vikram

But how to do it?
I think that my program use only one thread.

Added after 15 minutes:


My guess is that the problem is your missing Q(Core/Ui)Application instance.
So the main thread is not "adopted" as a QThread and thus lacks the necessary event dispatcher for socketnotifier's event handling.

Cheers,
_

Make a widgets project?

anda_skoa
18th November 2015, 16:00
Make a widgets project?

If you don't have any Qt UI then you don't need a widgets project.
But you need an instance of QCoreApplication (or on of its subclasses) and run its event loop (by calling its exec() function).

Just try to start with an empty main() function.
Then creating and configuring the QSerialPort instance.
Then maybe trying to write a fixed command.

When that works, add the original code instead of the test QSerialDevice code.

Cheers,
_

Vikram.Saralaya
18th November 2015, 16:02
Try replacing QT += serialport with QT += core serialport in the pro file

nistar
18th November 2015, 16:05
My guess is that the problem is your missing Q(Core/Ui)Application instance.
So the main thread is not "adopted" as a QThread and thus lacks the necessary event dispatcher for socketnotifier's event handling.

Cheers,
_

O, I do it.
Only make a application project, and copy the code.

Thanks