PDA

View Full Version : Plotting of QProcess output taking about 5 minutes to plot single value.



suhairkp
20th February 2017, 09:57
Hello all ,
I am new to Qt , i am designing a system which will receive values from sensors and Plot in GUI. I have complete C code for serial port setting and data Processing . By using Q Process i am running this C program and Plotting the Processed values .
My GUI contain a text Edit for displaying Proceeded output readings and widget for plotting processed values with respect to time . Output values and Plot are as expected . Device sending with 4800 Baud rate and with odd parity , which is set in C program .But its taking more than 5 Minutes to read and plot one value and taking more than 30 minutes to read and plot about 6 values . why it taking this much time to read ?

My Code is attached ...




ui->setupUi(this);
QVector<double> data_x(101), data_y(101);
timer.start();
init_port();
init_line_plot();
x_position = 0;
}

graphwidget::~graphwidget()
{
delete ui;
}
void graphwidget::init_port()
{
process = new QProcess(this);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(receive()));
process->start("./test2");

process->waitForStarted();
qDebug()<<"process error code:" <<process->error();


}
void graphwidget::init_line_plot()
{

ui->customPlot->addGraph();
// ui->customPlot->setMinimumSize(500,500);
ui->customPlot->xAxis->setLabel("t");
ui->customPlot->yAxis->setLabel("V");
ui->customPlot->axisRect()->setAutoMargins(QCP::msNone);
ui->customPlot->axisRect()->setMargins(QMargins(0,0,0,0));
}


void graphwidget::receive()
{
// recieves data as ASCII string
int datalength = 1000;
char data [1000];
int bytesRead =process->readLine(data, datalength);
data[bytesRead]='\0';

ui->textEdit->append(QString(data));

QTextStream out(stdout);
out << data << endl;
addDataPoint(atof(data));
}

void graphwidget::addDataPoint(double datapoint)
{
if (x_position>60)data_x.pop_front();
double ms = timer.elapsed();
data_x.push_back((double)ms/1000);
x_position++;
if (x_position>60) data_y.pop_front();
data_y.push_back(datapoint);

ui->customPlot->graph(0)->setData(data_x,data_y);
ui->customPlot->xAxis->grid()->setSubGridVisible(false);
ui->customPlot->yAxis->grid()->setSubGridVisible(false);
ui->customPlot->xAxis->grid()->setVisible(false);
ui->customPlot->yAxis->grid()->setVisible(false);
ui->customPlot->graph(0)->setPen(QPen(QColor(0,200,0)));
ui->customPlot->setBackground(Qt::black);

ui->customPlot->graph(0)->rescaleAxes();
ui->customPlot->replot();
}




please suggest necessary changes ........

d_stranz
20th February 2017, 21:28
data_x and data_y in line 2 are local stack variables (I assume this is your class constructor) and have no relationship to the variables of the same name you use later.

In line 56, you increment x_position. I don't see anywhere where you reset its value, so once it reaches 60, it will continue to increase.

Otherwise, there doesn't appear to be anything in the code you have posted which would cause such delays. I would write a test program that strips out everything except the communication between your sensors and your monitoring program and see if that is where the trouble starts. No GUI, no writing to files, no plotting, just qDebug() statements to write what you receive to the console. And run it in the debugger, of course.

suhairkp
21st February 2017, 05:53
k. But i tested same qt program with simple C program . it will just print 1,2,3,4,5,4,3,2,1... and no serial port setting in C program , it worked fine and giving continues output without delay .

Lesiok
21st February 2017, 07:49
k. But i tested same qt program with simple C program . it will just print 1,2,3,4,5,4,3,2,1... and no serial port setting in C program , it worked fine and giving continues output without delay .

So the problem is with the serial port. Why You don't use QSerialPort ?

suhairkp
21st February 2017, 08:15
Serial port is set in C program , so calling QProcess will set serial port . thats y not using Qserialport in Qt .Also , C program process the received signal from serial port and print output . this output is storing in byte array and using for plot .
I compiled C program from terminal and getting correct output in terminal . but Qt taking more time call QProcess and plot , don't getting idea where this delay occurring ...

d_stranz
21st February 2017, 16:32
I still think you need to break the problem down into the smallest piece possible, than add more features. I would start by writing a Qt program that simply starts the listener process, reads the output from your sensor and prints it using qDebug(). No printing it to a text edit, no logging to files, no plotting. At this point, you have no idea which step in this chain is going wrong, so eliminate everything except the first one: getting data successfully from the QProcess into your program. Once that seems to be working in the same way as your C program, then you know the communication works, so add the graphics and other features.

You might also try using QProcess:readAllStandardOutput() to get all of the available data at once instead of using readLine(). Use QByteArray::data() or QByteArray::constData() to get the NULL-terminated C string it contains. This way you do not have to worry about the buffer size or whether you have read it all.

suhairkp
23rd February 2017, 12:06
k . sir. I am testing it without plot . in my above code , it displaying "process error code : 2 " in Application output area of Qt Creator , when output gui display open and saying " Qprocess : Destroyed while process is still running ". when i changed process->waitForStarted from process->waitForFinished , it show that "process error code : 5 "

Lesiok
23rd February 2017, 13:29
Once again : why You use external program to read data from serial port ? Why You don't do it in Qt program ?

suhairkp
23rd February 2017, 14:46
I have complete C code for processing different sensor value . there are 4 sensors and it takes about two years to complete this C code . this system working perfectly using frame buffer . Now i want to design GUI using Qt . If i am going to write complete code in Qt , sometime it will take more time . To reduce this time , i am using Q Process .

Added after 16 minutes:

I tested Code without plotting. Output of QProces is reading using QProcess:readAllStandardOutput() and qDebug() will print output .



ui->setupUi(this)
init_port();
}

graphwidget::~graphwidget()
{
delete ui;
}
void graphwidget::init_port()
{
process = new QProcess(this);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(receive()));
process->start("./test2");

process->waitForReadyRead();
qDebug()<<"process error code:" <<process->error();
}

void graphwidget::receive()
{
QString data = process ->readAllStandardoutput();
qDebug << data ;

QTextStream out(stdout);
out << data << endl;
}


it also displaying "process error code : 2" and taking more time to print .After 4 minutes , it print about 50 values then stopped . I googled about process error code , didn't get any details about .

Lesiok
23rd February 2017, 15:24
Just look in the Qt documentation (http://doc.qt.io/qt-5/qprocess.html#ProcessError-enum): a value of 2 means The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again..

jefftee
24th February 2017, 04:54
Is your C program writing its output to stdout or stderr and are you reading the correct channel? Look at QProcess:setProcessChannelMode and perhaps use QProcess::MergedChannels if you want both stdout and stderr to be merged, etc.

Since you are timing out waiting to read output from the C program, perhaps your C program is writing its output to stderr?

suhairkp
24th February 2017, 05:31
Just look in the Qt documentation (http://doc.qt.io/qt-5/qprocess.html#ProcessError-enum): a value of 2 means The last waitFor...() function timed out. The state of QProcess is unchanged, and you can try calling waitFor...() again..

is it is by adding waitFor...() many times?

Added after 5 minutes:


Is your C program writing its output to stdout or stderr and are you reading the correct channel? Look at QProcess:setProcessChannelMode and perhaps use QProcess::MergedChannels if you want both stdout and stderr to be merged, etc.

Since you are timing out waiting to read output from the C program, perhaps your C program is writing its output to stderr?
i used printf to write output from Qprocess. so i used QProcess::readAllStandardoutput().

jefftee
24th February 2017, 07:55
i used printf to write output from Qprocess. so i used QProcess::readAllStandardoutput().
And do you have a newline at the end of your output and are you flushing stdout like so: fflush(stdout)?

suhairkp
24th February 2017, 14:27
s. each output values are in new line . but not flushing stdout.

d_stranz
24th February 2017, 18:30
process->start("./test2");

So if you open a terminal window, cd to this directory, and execute "./test2", you see the expected output immediately in the terminal window? No delay at all?

suhairkp
25th February 2017, 05:16
s... getting currect output without delay in terminal , but QProcess taking more time to print out.

jefftee
25th February 2017, 07:50
I just noticed that the initial code you posted seems to omit the function definition that should preceed line 1. It would appear that this is your graphwidget constructor, which I presume is based on QObject and probably allocated on the stack in main.

In that same constructor, you are starting the timer and executing those init* methods, which then actually creates and starts your QProcess, all before you have started the message loop.

I would recommend that you take the processing logic out of the constructor and put into a separate init method, so that you execute the initialization *after* your graphwidget object is fully constructed and then you can being your processing.

For example, add a slot to graphwidget named init() or whatever you want to name it, then make the following changes to graphwidget (untested):


graphwidget::graphwidget(QObject *parent)
{
ui->setupUi(this);
x_position = 0;
QTimer::singleShot(0, this, SLOT(init));
}

void graphwidget::init()
{
timer.start();
init_port();
init_line_plot();
}

This way, your graphwidget will be completely constructed and the singleshot timer will execute your init routine as soon as the event loop is started, etc. While I can't guarantee this is your problem, it's easy to try...