Issue with QSerialPort: Raspberry Pi - Arduino
-
Hey guys,
I'm currently trying to make a bi-directional Serial communication protocol between a Raspberry Pi and a custom Arduino microcontroller. The Arduino uses C and the Pi uses a Qt GUI with C++/XML. I based my program from the QSerialPort example in Qt Creator, and now runs in a separate thread to the rest of the program.
90% of the time it works perfectly, but every now and then, the Pi receives a "scrambled" command from the Arduino.
Example of correct message as QByteArray:
"<12,1,3,400,99,80,75>"Example of scrambled message as QByteArray:
"<12,1,3,400,99,1\x98""b\x82\xF2\xFE"Example of scrambled message as QString:
"<12,1,3,400,99,1�b���"Serial Port Init:
QSerialPort serial; serial.setPortName("ttyS0"); // GPIO serial.setBaudRate(QSerialPort::Baud9600); serial.setDataBits(QSerialPort::Data8); serial.setFlowControl(QSerialPort::NoFlowControl); serial.setParity(QSerialPort::NoParity); serial.setStopBits(QSerialPort::OneStop); // Is this correct? if (!serial.open(QIODevice::ReadWrite)) { qDebug() << "dispenseThread::run: ERROR: Cannot open serial port!"; qDebug() << serial.errorString(); }
Serial Port Read:
QByteArray responseData = serial.readAll(); while (serial.waitForReadyRead(10)) { responseData += serial.readAll(); } const QString response = QString::fromUtf8(responseData); QString readBuff = response; qDebug() << "QByteArray Buffer: " << responseData; qDebug() << "Const QString Buffer: " << response; qDebug() << "QString Buffer: " << readBuff;
Is this normal for Serial, in which case I need to verify each command has been sent successfully, or is there something wrong with the configuration or buffer?
Any help would be appreciated!
Thanks,
Ryan -
@Ryan-R
I must admit I too find this area confusing after years of attempting to understand(!), but are theQByteArray
contents you show really UTF-8??
https://doc.qt.io/qt-5/qstring.html#fromUtf8 :UTF-8 is a Unicode codec and can represent all characters in a Unicode string like QString. However, invalid sequences are possible with UTF-8 and, if any such are found, they will be replaced with one or more "replacement characters", or suppressed. These include non-Unicode sequences, non-characters, overlong sequences or surrogate codepoints encoded into UTF-8.
Separately, if some of these are "funny" characters I wouldn't rely on the visual output from
qDebug()
"looking" right. verify what is actually in the bad-looking positions in the strings? -
@Ryan-R said in Issue with QSerialPort: Raspberry Pi - Arduino:
while (serial.waitForReadyRead(10))
{
responseData += serial.readAll();
}This is probably the issue. You wait 10msecs before you add data to your output. If not all of the data sent, is transmitted, you get some garbage :)
Do you use any of the signals
QSerialPort
provides? -
You wait 10msecs before you add data to your output. If not all of the data sent, is transmitted, you get some garbage :)
How does that lead to "corruption"?
responseData
only holds bytes which have actually arrived, and knows the length, so how can that lead to "extra", rubbish characters? (Not that I know anything about how serial ports work, if that matters?!) I can see it might lead to not all characters having been received, but not extra characters? -
Hi,
The usual way to do serial communication is to establish a protocol so you can know when you have received a full frame of your data. Most of the time you have a start and end character or character sequence to determine the limits of your frame.
On the receiver end you cumulate the data in a buffer that you check regularly so you know when all the data required have arrived. Then you can extract that frame, process it and go on with your logic.
-
Thanks for the fast replies!
Do you mean something like this, or do you mean read the Serial Port character-by-character, looking for the open and close commands?
My open command is "<" and close command is ">".
while (serial.waitForReadyRead(10) && (!responseData.contains("<") && !responseData.contains(">"))) { responseData += serial.readAll(); }
Thanks,
Ryan -
The cumulation is correct but not the loop. Once you got the data, check for the frame. If not there, let your application live and the next time readyRead is fired, it will do the same and you might have there the complete frame. No need for a tight loop.