Arduino analog input to QT Gauge.
-
wrote on 30 May 2017, 15:10 last edited by
Hi Guys,
Thanks for reading this, and helping if you can, I was racing recently and as you do in a car you've built you push it to far ad you blow an engine, Ive been using a little bit of QT embedded for home projects such as jazzy thermostats ect so I thought this would be a good opportunity to try and build a digital indication of a few essential readings.
What I'm trying to do is take an analog signal from an Arduino 0-5v, receive it through serial and display it on a rotating gauge, the second tab on the screen shows an LCD value of which ive got working fine reading other peoples examples and testing for myself.
Cheers again for any help.
QT += core gui serialport greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = 300zx TEMPLATE = app DEFINES += QT_DEPRECATED_WARNINGS SOURCES += main.cpp\ dialog.cpp \ qcgaugewidget.cpp HEADERS += dialog.h \ qcgaugewidget.h FORMS += dialog.ui
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QSerialPort> #include <QByteArray> #include "C:/Users/Stephn/Documents/300zx/qcgaugewidget.h" namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); ~Dialog(); private slots: void analogRead2(); void updateLCD1oilpress(QString); void updateLCD2oilpressraw(QString); void updateoilpressgauge(QString); private: Ui::Dialog *ui; QSerialPort *arduino; static const quint16 arduino_uno_vendor_id = 0x1a86; static const quint16 arduino_uno_product_id = 0x7523; QByteArray serialData; QString serialBuffer; QString parsed_data; double temperature_value; QcGaugeWidget * mSpeedGauge; QcNeedleItem *mSpeedNeedle; }; #endif // DIALOG_H
#include "dialog.h" #include "ui_dialog.h" #include <QSerialPort> #include <QSerialPortInfo> #include <string> #include <QDebug> #include <QMessageBox> Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); ui->oilpress_LCD1->display("----"); ui->oilpressraw_LCD2->display("----"); mSpeedGauge = new QcGaugeWidget; mSpeedGauge->addBackground(99); QcBackgroundItem *bkg1 = mSpeedGauge->addBackground(92); bkg1->clearrColors(); bkg1->addColor(0.1,Qt::black); bkg1->addColor(1.0,Qt::white); QcBackgroundItem *bkg2 = mSpeedGauge->addBackground(88); bkg2->clearrColors(); bkg2->addColor(0.1,Qt::gray); bkg2->addColor(1.0,Qt::darkGray); mSpeedGauge->addArc(55); mSpeedGauge->addDegrees(65)->setValueRange(0,80); mSpeedGauge->addColorBand(50); mSpeedGauge->addValues(80)->setValueRange(0,80); mSpeedGauge->addLabel(70)->setText("Km/h"); QcLabelItem *lab = mSpeedGauge->addLabel(40); lab->setText("0"); mSpeedNeedle = mSpeedGauge->addNeedle(60); mSpeedNeedle->setLabel(lab); mSpeedNeedle->setColor(Qt::white); mSpeedNeedle->setValueRange(0,80); mSpeedGauge->addBackground(7); mSpeedGauge->addGlass(88); ui->verticalLayout->addWidget(mSpeedGauge); arduino = new QSerialPort(this); serialBuffer = ""; parsed_data = ""; temperature_value = 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(); } } } /* * Open and configure the arduino port if available */ if(arduino_is_available){ qDebug() << "Found the arduino port...\n"; arduino->setPortName(arduino_uno_port_name); arduino->open(QSerialPort::ReadOnly); arduino->setBaudRate(QSerialPort::Baud115200); arduino->setDataBits(QSerialPort::Data8); arduino->setFlowControl(QSerialPort::NoFlowControl); arduino->setParity(QSerialPort::NoParity); arduino->setStopBits(QSerialPort::OneStop); 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."); } } Dialog::~Dialog() { if(arduino->isOpen()){ arduino->close(); // Close the serial port if it's open. } delete ui; } void Dialog::analogRead2() { QByteArray serialData = arduino->readLine(); QString temp1 = QString::fromStdString(serialData.toStdString()); qDebug() << temp1; Dialog::updateLCD1oilpress(temp1); Dialog::updateLCD2oilpressraw(temp1); Dialog::updateoilpressgauge(temp1) } void Dialog::updateLCD1oilpress(QString sensor_reading) { // update the value displayed on the lcdNumber ui->oilpress_LCD1->display(sensor_reading); } void Dialog::updateLCD2oilpressraw(QString sensor_reading) { // update the value displayed on the lcdNumber ui->oilpressraw_LCD2->display(sensor_reading); } void Dialog::updateoilpressgauge(QString sensor_reading) { ui->mSpeedgauge->display(sensor_reading); }
#include "dialog.h" #include <QApplication> #include <QWidget> #include <QCoreApplication> #include <QFile> #include <QString> #include <QDebug> #include <QTextStream> void read(QString filename) { QFile file(filename); if(!file.open(QFile::ReadOnly | QFile::Text)) { qDebug() << " Could not open the file for reading"; return; } QTextStream in(&file); QString myText = in.readAll(); // put QString into qDebug stream qDebug() << myText; file.close(); } int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget widget(0); Dialog w; w.setWindowTitle("300zx"); w.setFixedSize(500,400); w.show(); return a.exec(); }
-
Hi and welcome to devnet,
What kind of help are you looking for ?
-
wrote on 31 May 2017, 09:45 last edited by
Thank you for the welcome,
So for an LCD display I would add,
private slots: void analogRead2(); void updateLCD1oilpress(QString); // in the dialog.h
connect(arduino, SIGNAL(readyRead()), this, SLOT(analogRead2())); // in the dialog.cpp void Dialog::analogRead2() { QByteArray serialData = arduino->readLine(); QString temp1 = QString::fromStdString(serialData.toStdString()); qDebug() << temp1; Dialog::updateLCD1oilpress(temp1); } void Dialog::updateLCD1oilpress(QString sensor_reading) { // update the value displayed on the lcdNumber ui->oilpress_LCD1->display(sensor_reading); } // in the dialog.cpp
Id like to know how I would update the needle rotation with the value on the LCD screen.
So for 1v it would rotate 15 degrees, 2 volts it would rotate 30 degrees for instance.
-
Why are you going through all these transformation ? QString has a constructor taking a QByteArray ?
Then you need to parse the data you received and with that update the gauge.
You might be interested by the CirculaGauge element.
-
wrote on 1 Jun 2017, 21:01 last edited by
Thank you for your reply, ive continued some research today and came up quite well apart from the updating of the gauge needle.
void Dialog::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_bar = (0.008) * (parsed_data.toDouble()); oil_pressure_volt = (0.0048) * (parsed_data.toDouble()); qDebug() << "Pressure: " << oil_pressure_volt << "\n"; Dialog::updateOilPressure(parsed_data); } } void Dialog::updateOilPressure(QString sensor_reading) { ui->oilpress_LCD1->display(oil_pressure_bar); ui->oilpressraw_LCD2->display(oil_pressure_volt); mSpeedNeedle->setDegreeRange(oil_pressure_bar); }
I did as you said and parsed the data, I managed to get a raw voltage reading from the sensor, and then converted it to pressure. But when I tried to update the needle rotation, I failed.
-
What exactly fails ?
-
wrote on 5 Jun 2017, 20:23 last edited by
Thank you for your help, it turns out all I had to do was restart QT Creator.
I'm not stuck on another problem and could I ask for your help?
Ive removed the C++ gauge example and replaced it with a simple QML gauge, I would like to take my serial signal and place it in the needleAngle slot.
Could you tell me the best way to do this as my code seems to emit a lot of errors.
*.proQT += core gui serialport qml QT += quick greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = 300zx TEMPLATE = app DEFINES += QT_DEPRECATED_WARNINGS SOURCES += main.cpp\ dialog.cpp HEADERS += dialog.h FORMS += dialog.ui DISTFILES += \ main.qml \ QtQuickViewManager/View.pri \ QtQuickViewManager/README.md \ oiltemp.qml include(./QtQuickViewManager/View.pri) RESOURCES += \ resource.qrc QML_IMPORT_PATH =
*.h
#ifndef DIALOG_H #define DIALOG_H #include <QDialog> #include <QSerialPort> #include <QByteArray> namespace Ui { class Dialog; } class Dialog : public QDialog { Q_OBJECT public: explicit Dialog(QWidget *parent = 0); ~Dialog(); signals: void oil_pressure_bar(QVariant num); public slots: void analogRead2(); void analogRead3(); void updateOilPressure(QString); void updateOilTemperature(QString); void needleAngle(QVariant num); private: Ui::Dialog *ui; 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; }; #endif // DIALOG_H
*.cpp
#include "dialog.h" #include "ui_dialog.h" #include <QSerialPort> #include <QSerialPortInfo> #include <string> #include <QDebug> #include <QMessageBox> #include <QQuickView> #include <QQmlApplicationEngine> #include <QtQuickWidgets/QQuickWidget> Dialog::Dialog(QWidget *parent) : QDialog(parent), ui(new Ui::Dialog) { ui->setupUi(this); setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint); ui->oilpress_LCD1->display("-------"); ui->oilpressraw_LCD2->display("-------"); ui->oiltemp_LCD1->display("-------"); ui->oiltempraw_LCD2->display("-------"); QQuickView *view = new QQuickView(); QWidget *container = QWidget::createWindowContainer(view, this); container->setMinimumSize(250, 250); container->setMaximumSize(250, 250); container->setFocusPolicy(Qt::TabFocus); view->setSource(QUrl("qrc:/new/prefix1/main.qml")); ui->verticalLayout->addWidget(container); *italicised text* auto Dialog = new QDialog(this); auto quickWidget = new QQuickWidget(QUrl("main.qml"), this); auto Rectangle = quickWidget->rootObject(); // Connect C++ signal to QML slot QObject::connect(Dialog, SIGNAL(oil_pressure_bar(QVariant num)),Rectangle, SLOT(needleAngle(QVariant num))); arduino = new QSerialPort(this); serialBuffer = ""; parsed_data = ""; oil_pressure_volt = 0.0; //oil_pressure_bar = 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(); } } } /* * Open and configure the arduino port if available */ 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())); QObject::connect(arduino, SIGNAL(readyRead()), this, SLOT(analogRead3())); }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."); } } Dialog::~Dialog() { if(arduino->isOpen()){ arduino->close(); // Close the serial port if it's open. } delete ui; } void Dialog::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_bar = (0.008) * (parsed_data.toDouble()); oil_pressure_volt = (0.0048) * (parsed_data.toDouble()); qDebug() << "Pressure: " << oil_pressure_volt << "\n"; Dialog::updateOilPressure(parsed_data); } } void Dialog::updateOilPressure(QString sensor_reading) { //ui->oilpress_LCD1->display(oil_pressure_bar); ui->oilpressraw_LCD2->display(oil_pressure_volt); }
main.cpp
#include "dialog.h" #include <QApplication> #include <QWidget> #include <QCoreApplication> #include <QFile> #include <QString> #include <QDebug> #include <QTextStream> #include <ViewManagement.h> #include <QGuiApplication> #include <QScopedPointer> #include <QQmlApplicationEngine> #include <QSerialPort> #include <QSerialPortInfo> #include <QObject> void read(QString filename) { QFile file(filename); if(!file.open(QFile::ReadOnly | QFile::Text)) { qDebug() << " Could not open the file for reading"; return; } QTextStream in(&file); QString myText = in.readAll(); // put QString into qDebug stream qDebug() << myText; file.close(); } int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget widget(0); Dialog w; w.setWindowTitle("Temperature Sensor Reading"); w.setFixedSize(800,480); w.show(); return a.exec(); }
*.qml
import QtQuick 2.1 import QtQuick.Controls 2.0 import QtQuick.Extras 1.4 import QtSensors 5.7 Rectangle { id: gauge width: 500 height: 250 property alias btnMinus: btnMinus property alias needle: needle property alias btnPlus: btnPlus property double needleAngle: 0; Image { id: background x: 0 y: 0 width: 250 height: 250 source: "Img/background.png" Image { id: needle x: 92 y: 121 width: 150 height: 8 source: "Img/needle.png" transform: Rotation {origin.x: 35; origin.y: 5; angle: needleAngle} smooth: true } Button { id: btnPlus x: 8 y: 192 width: 50 height: 50 text: qsTr("+") onClicked: needleAngle +=10 } Button { id: btnMinus x: 192 y: 192 width: 50 height: 50 text: qsTr("-") onClicked: needleAngle -=10 } } }
And again any help and advice would be much appreciated.
-
What errors is it emitting ?
-
wrote on 6 Jun 2017, 06:54 last edited by
C:\Users\Stephn\Documents\300zx\dialog.cpp:37: error: no matching function for call to 'Dialog::connect(QDialog*&, const char*, QQuickItem*&, const char*)'
QObject::connect(Dialog, SIGNAL(oil_pressure_bar(QVariant)),Rectangle, SLOT(needleAngle(QVariant)));
^This is the error I'm getting. much appreciated.
-
You are trying to connect classes. You have to connect instances of these classes.
-
wrote on 7 Jun 2017, 21:19 last edited by StevieGardiner 6 Jul 2017, 21:22
And by classes you mean "dialog" when I should be connecting " updatedoilpress"?
And instead of "Rectangle" I should be connecting Rotation"?Also would this QObject::Connect be the easiest and simplest way of connecting a C++ signal (analogread2, oil_press_bar) to a QML Slot (Neeedle, needleAngle)?
-
You'd have to search for the objects you are interest in in your engine and then connect them.
By the way, why not make this dialog also with QtQuick ?
-
wrote on 7 Jun 2017, 21:42 last edited by
Ok so id search for the instances, I can google how to do that.
What are the benefits of using QtQuick, over my method?
-
That was just curiosity. Nothing wrong in mixing both. If you go with a QtQuick only GUI you should be able to drop the dependency on the QtWidgets module which makes your application lighter weight.
-
wrote on 14 Jun 2017, 20:01 last edited by
Hi,
I took your advice and used the cpp for serial data collection and the qml for the GUI, but I'm having a problem with this error.
C:\Users\Stephn\Documents\nissan300zx\serialport.h:50: error: 'double SerialPort::oil_pressure_volt' conflicts with a previous declaration
double oil_pressure_volt;
^I know that the code is duplicating names, but id like to read that name in Q_Property and then send it to QML.
#ifndef SERIALPORT_H #define SERIALPORT_H #include <QObject> #include <QQuickItem> #include <QSerialPort> #include <QSerialPortInfo> #include <QByteArray> class SerialPort : public QObject { Q_OBJECT Q_PROPERTY(QString oil_pressure_volt READ oil_pressure_volt WRITE set_oil_pressure_volt NOTIFY oil_pressure_volt_Changed) public: SerialPort(QObject *parent = 0); SerialPort(QString); QString oil_pressure_volt() const { return m_oil_pressure_volt; } public slots: void analogRead2(); void updateOilPressure(QString); void set_oil_pressure_volt(QString 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(QString 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; QString m_oil_pressure_volt; }; #endif // SERIALPORT_H
Could I rename the oil_pressure_volt in the CPP
void SerialPort::updateOilPressure(QString sensor_reading) { //oil_pressure_volt(double) = data; }
-
Why are you declaring a oil_pressure_volt property QString then the matching variable as double and still use QString everywhere ?
-
wrote on 15 Jun 2017, 07:44 last edited by
Sorry, that was me trying different ideas out.
#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 This is the error, C:\Users\Stephn\Documents\nissan300zx\serialport.h:48: error: 'double SerialPort::oil_pressure_volt' conflicts with a previous declaration double oil_pressure_volt; ^
-
wrote on 16 Jun 2017, 11:47 last edited by
Hi, So after making a few suggested changes I cant now display a "0" on my qml text field, I think this zero is the first reading of the analogRead 2.
I changed to this in the main.
engine.rootContext()->setContextProperty("serialport", &serialport);
and this in the header.
Q_PROPERTY( double oilPressureVoltage MEMBER m_oil_pressure_volt WRITE set_oil_pressure_volt NOTIFY oil_pressure_volt_Changed )
I think I need to add some code into a string,
#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 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
-
Can you how how you are using that class in QML ?
-
wrote on 17 Jun 2017, 04:27 last edited by
yes its...
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 TextEdit { id: textEdit text: SerialPort.newValue verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignCenter } } and...
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
SerialPort serialport;
qmlRegisterType<SerialPort>("SerialPortlib", 1, 0, "SerialPort");
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));return app.exec();
1/25