PDA

View Full Version : Arduino serial input qml display text, conflict of previous declaration error.



StevieGardiner
15th June 2017, 10:30
Hi Guys,

Ive been working on a project trying to read the analog input from an Arduino board through serial, then display this on a qml gui in text form first and then move onto a rotating gauge.

I completed the process using qdebug at each step, so I'm reading the input until I come to the Q_PROPERTY stage and I get this error.


C:\Users\Stephn\Documents\nissan300zx\serialport.h :48: error: 'double SerialPort::oil_pressure_volt' conflicts with a previous declaration
double oil_pressure_volt;
^


#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <QObject>
#include <QQuickItem>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QByteArray>

class SerialPort : public QObject
{
Q_OBJECT
Q_PROPERTY(double oil_pressure_volt READ oil_pressure_volt WRITE set_oil_pressure_volt NOTIFY oil_pressure_volt_Changed)

public:
SerialPort(QObject *parent = 0);
SerialPort(QString);

double oil_pressure_volt() const
{
return m_oil_pressure_volt;
}

public slots:
void analogRead2();
void updateOilPressure(QString);

void set_oil_pressure_volt(double oil_pressure_volt)
{
if (m_oil_pressure_volt == oil_pressure_volt)
return;

m_oil_pressure_volt = oil_pressure_volt;
emit oil_pressure_volt_Changed(oil_pressure_volt);
}

signals:

void oil_pressure_volt_Changed(double oil_pressure_volt);

private:
QSerialPort *arduino;
static const quint16 arduino_uno_vendor_id = 0x2341;
static const quint16 arduino_uno_product_id = 0x0001;
QByteArray serialData;
QString serialBuffer;
QString parsed_data;
double oil_pressure_volt;

double m_oil_pressure_volt;
};

#endif // SERIALPORT_H

much appreciated for any help you can give me.

d_stranz
15th June 2017, 22:11
The Q_PROPERTY macro defines the member variable oil_pressure_volt for you. Line 48 is adding a duplicate definition and thus causing the error. Delete that line. Get rid of m_oil_pressure_volt also, since it is just a duplicate of the property.

You would confuse yourself less if you didn't use the name "oil_pressure_volt" everywhere. C++ doesn't care what the argument names are, so in the set method, use "newValue" or something like that. Likewise in your definition of the signal.

If you want the -name- of the property that is exposed to QML to be something different from the member variable name, then use the MEMBER form of Q_PROPERTY:



Q_PROPERTY( double oilPressureVoltage MEMBER m_oil_pressure_volt WRITE set_oil_pressure_volt NOTIFY oil_pressure_volt_Changed )


You will refer to it as "oilPressureVoltage" from QML.

StevieGardiner
16th June 2017, 09:10
Much appreciated for clarifying that... and after adding your code and trying I still couldn't see anything in the main.qml.

I'm using the "double oil_pressure_volt" in my serialport.cpp code below, it takes my 10 bit analog input and turns it into a voltage reading. Would I be better doing the conversion in the qml?


int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
SerialPort serialport;
qmlRegisterType<SerialPort>("SerialPortlib", 1, 0, "SerialPort");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();


class SerialPort : public QObject
{
Q_OBJECT
Q_PROPERTY( double oilPressureVoltage MEMBER m_oil_pressure_volt WRITE set_oil_pressure_volt NOTIFY oil_pressure_volt_Changed )

public:
SerialPort(QObject *parent = 0);
SerialPort(QString);

public slots:
void analogRead2();
void updateOilPressure(QString);

void set_oil_pressure_volt(double oilPressureVoltage)
{
if (m_oilPressureVoltage == oilPressureVoltage)
return;

m_oilPressureVoltage = oilPressureVoltage;
emit oil_pressure_volt_Changed(oilPressureVoltage);
}

signals:

void oil_pressure_volt_Changed(double oilPressureVoltage);

private:
QSerialPort *arduino;
static const quint16 arduino_uno_vendor_id = 0x2341;
static const quint16 arduino_uno_product_id = 0x0001;
QByteArray serialData;
QString serialBuffer;
QString parsed_data;
double oil_pressure_volt;
double m_oilPressureVoltage;
};

#endif // SERIALPORT_H


void SerialPort::analogRead2()
{
QStringList buffer_split = serialBuffer.split(",");
if(buffer_split.length() < 3)
{
serialData = arduino->readAll();
serialBuffer = serialBuffer + QString::fromStdString(serialData.toStdString());
serialData.clear();
}else{
serialBuffer = "";
qDebug() << buffer_split << "\n";
parsed_data = buffer_split[1];
oil_pressure_volt = (0.0048) * (parsed_data.toDouble());
qDebug() << "Pressure: " << oil_pressure_volt << "\n";
}


import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Extras 1.4
import QtQuick.Controls 2.0
import SerialPortlib 1.0

Window {
id: gauge
visible: true
width: 640
height: 480

TextField {
id: textField
x: 250
y: 280
text: SerialPort.oilPressureVoltage
}
}

Lesiok
16th June 2017, 10:06
First change line
oil_pressure_volt = (0.0048) * (parsed_data.toDouble()); to
set_oil_pressure_volt((0.0048) * (parsed_data.toDouble()));
P.S. Try to figure out why.

StevieGardiner
16th June 2017, 11:18
Hi Lesiok, thanks for you help, I changed this line with nothing still in the qml.

StevieGardiner
16th June 2017, 14:07
An update guys, after changing to this in the main.cpp, I managed to display a "0" which I think is the first reading from the analogRead2, then the rest is the voltage.


engine.rootContext()->setContextProperty("serialport", &serialport);

I would think id need to add this code to a loop, and advice guys is much appreciated.


void set_oil_pressure_volt(double oilPressureVoltage)
{
if (m_oilPressureVoltage != oilPressureVoltage)
return;

m_oilPressureVoltage = oilPressureVoltage;
emit oil_pressure_volt_Changed(oilPressureVoltage);
}

Lesiok
16th June 2017, 14:29
How is SerialPort::analogRead2() activated ?

StevieGardiner
16th June 2017, 14:46
By the QObject::Connect on line 43


#include "serialport.h"
#include <QSerialPort>
#include <QSerialPortInfo>
#include <string>
#include <QDebug>
#include <QQuickView>
#include <QQmlApplicationEngine>
#include <QApplication>
#include <QtQuickWidgets/QQuickWidget>

SerialPort::SerialPort(QObject *parent)
{
arduino = new QSerialPort(this);

serialBuffer = "";
parsed_data = "";
oil_pressure_volt = 0.0;

bool arduino_is_available = false;
QString arduino_uno_port_name;

foreach(const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()){
// check if the serialport has both a product identifier and a vendor identifier
if(serialPortInfo.hasProductIdentifier() && serialPortInfo.hasVendorIdentifier()){
// check if the product ID and the vendor ID match those of the arduino uno
if((serialPortInfo.productIdentifier() == arduino_uno_product_id)
&& (serialPortInfo.vendorIdentifier() == arduino_uno_vendor_id)){
arduino_is_available = true; // arduino uno is available on this port
arduino_uno_port_name = serialPortInfo.portName();
}
}
}

if(arduino_is_available){
qDebug() << "Found the arduino port...\n";
arduino->setPortName(arduino_uno_port_name);
arduino->open(QSerialPort::ReadOnly);
arduino->setBaudRate(QSerialPort::Baud57600);
arduino->setDataBits(QSerialPort::Data8);
arduino->setFlowControl(QSerialPort::NoFlowControl);
arduino->setParity(QSerialPort::NoParity);
arduino->setStopBits(QSerialPort::OneStop);
QObject::connect(arduino, SIGNAL(readyRead()), this, SLOT(analogRead2()));

}else{
qDebug() << "Couldn't find the correct port for the arduino.\n";
//QMessageBox::information(this, "Serial Port Error", "Couldn't open serial port to arduino.");
}

}
void SerialPort::analogRead2()
{
QStringList buffer_split = serialBuffer.split(",");
if(buffer_split.length() < 3)
{
serialData = arduino->readAll();
serialBuffer = serialBuffer + QString::fromStdString(serialData.toStdString());
serialData.clear();
}else{
serialBuffer = "";
qDebug() << buffer_split << "\n";
parsed_data = buffer_split[1];
oil_pressure_volt = (0.0048) * (parsed_data.toDouble());
//set_oil_pressure_volt((0.0048) * (parsed_data.toDouble()));
qDebug() << "Pressure: " << oil_pressure_volt << "\n";
}
}

void SerialPort::updateOilPressure(QString sensor_reading)
{

}

Lesiok
16th June 2017, 14:59
And on qDebug you have a series of messages "Pressure: ...." ?
BTW : I see that you have not figured out why it should be line 64 and not 63. Line 63 changes oil_pressure_volt but not generate signal oil_pressure_volt_Changed.

StevieGardiner
16th June 2017, 15:33
Yes on qDebug, this is so I could see the input in *.cpp
I just tried again by applying line 64 and commenting out line 63, and the qml still shows "0"

I think I need to apply a loop somewhere,

Lesiok
16th June 2017, 15:38
I'm not using QML so I don't know how to use signal oil_pressure_volt_Changed in QML.

StevieGardiner
16th June 2017, 16:51
No worries mate, thank you for helping.

d_stranz
16th June 2017, 20:12
TextField {
id: textField
x: 250
y: 280
text: SerialPort.oilPressureVoltage
}


As with Lesiok, I'm not a QML expert either, but doesn't a TextField expect to receive a string type for the value of its "text" property? You're assigning a double to it. If it doesn't do an automatic type conversion of double to a printable representation (i.e. a string), then that could be where your unchanging "0" comes from.

You could test this by hard-coding a value on your C++ side (e.g. fix m_oilPressureVoltage at some known value and never change it, but continue to emit the signals as if you had). If you don't see -your- value on the QML side, then either the type conversion isn't happening or the signal still isn't getting picked up.

P. S. I see you're still confusing yourself by reusing the same names for variables all over the place. The name of the argument in your definition of set_oil_pressure_volt does not have to be the same as the property name. Use something different and unique (like "newVoltage") so when you look at the name "oilPressureVoltage" you know immediately it refers to the symbolic name of the Q_PROPERTY. Likewise, "newVoltage" only appears as the name of an argument to a class method and nowhere else, so it can't be confused either.

You may think this ridiculously pedantic, but from long experience I can tell you that if you need to go back to this code sometime later, you'll be thankful you chose unique, non-reused names because the first thing you'll have to do is re-learn what the code does because you'll have forgotten. It also can help you avoid days of debugging when you decide to rename something and the find and replace does -all- of them, including the ones it shouldn't have.

StevieGardiner
18th June 2017, 01:40
Hi Gents,

I tried with this with no joy,

import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Extras 1.4
import QtQuick.Controls 2.0
import SerialPortlib 1.0

Window {
visible: true
width: 640
height: 480
id: gauge

SerialPort{
OnOil_pressure_volt_Changed:(console.log(newValue) );
}
}

d_stranz
18th June 2017, 18:32
Sorry, but not knowing much QML beyond the basics, I don't have a clue what this code is supposed to do, or even if it is correct. C++, fine, but I have not yet made the treacherous crossing over into QMLandia and confronted the formidable beasts that dwell there.

It should be dead simple for you to implement a basic and purely C++ GUI for testing purposes. It eliminates one significant variable from the mix - get the communications working in C++, then map that GUI onto QML.