Solved textfield updates intermittent 'garbage'
-
I have an Arduino connected via serial running the a simple sketch to return dummy data. this returns fine as shown by debug.
My LCD displays update fine until I use the zero button in TableSaw qml then it intermittently returns garbage output whilst ending up on the correct figure. I have no idea why?
Also I can't get the display to update again once I push the reset zero button...
Page2 doesn't have anything on it yet..
arduino sketch
#include <Cmd.h> float currentDistanceX = 0; float currentDistanceY = 0; void setup() { Serial.begin(9600); cmdInit(&Serial); cmdAdd("startX", start_x); cmdAdd("startY", start_y); cmdAdd("home", homing); cmdAdd("jog x", jog_x); Serial.println("Enter start and number"); } void loop() { cmdPoll(); } void start_x(int arg_cnt, char **args) { float distance = (cmdStr2Num(args[1], 10)); if ((distance > 0) && (distance < 1200)) { if(distance >= currentDistanceX) { for (int i = currentDistanceX; i < (distance+1); i++) { Serial.println(i); Serial.flush(); delay(200); } } else { for (int i = currentDistanceX; i > (distance-1); i--) { Serial.println(i); Serial.flush(); delay(200); } } currentDistanceX = distance; } else { Serial.println("Out of Range"); } } void start_y(int arg_cnt, char **args) { float distance = (cmdStr2Num(args[1], 10)); if ((distance > 0) && (distance < 1200)) { if(distance >= currentDistanceY) { for (int i = currentDistanceY; i < (distance+1); i++) { Serial.println(i); Serial.flush(); delay(200); } } else { for (int i = currentDistanceY; i > (distance-1); i--) { Serial.println(i); Serial.flush(); delay(200); } } currentDistanceY = distance; } else { Serial.println("Out of Range"); } } void homing(int arg_cnt, char **args) { Serial.println("homing x"); delay (2000); currentDistanceX = 0; Serial.println("homing y"); delay (2000); currentDistanceY = 0; Serial.println("homing complete"); } void jog_x (int arg_cnt, char **args) { Serial.print("Jogging"); delay (2000); Serial.print("Jog Off"); }
arduinoserial.h
#ifndef ARDUINOSERIAL_H #define ARDUINOSERIAL_H #include <QObject> #include <QSerialPort> class ArduinoSerial : public QObject { Q_OBJECT Q_PROPERTY(QString bladeHeightValue READ bladeHeightValue WRITE setBladeHeightValue NOTIFY bladeHeightValueChanged) Q_PROPERTY(QString bladeAngleValue READ bladeAngleValue WRITE setBladeAngleValue NOTIFY bladeAngleValueChanged) public: ArduinoSerial(); QString bladeHeightValue() const; QString bladeAngleValue() const; public slots: void startSerialPort(); // Starts the Open Serial Port Function void readSerial(); void setBladeHeightValue(const QString& value); void setBladeAngleValue(const QString& value); void closeSerialPort(); void writeSerial(QString dro, const QByteArray &data); signals: void serialPortOpen(); // Signal for sucessfully opening Serial Port void serialPortEror(); // Signal on not finding arduino in openSerialPort void bladeHeightValueChanged(); // Signal on data received from arduino void bladeAngleValueChanged(); // Signal on data received from arduino void homingComplete(); // Signal sent when arduino has finished homing private: QSerialPort *arduino; static const quint16 arduino_uno_vendor_id = 9025; static const quint16 arduino_uno_product_id = 67; QString arduino_port_name; bool arduino_is_available; QString m_bladeHeightValue; QString m_bladeAngleValue; QString droToSet; void openSerialPort(); }; #endif // ARDUINOSERIAL_H
arduinoserial.cpp
#include "arduinoserial.h" #include <QDebug> #include <QSerialPort> #include <QSerialPortInfo> ArduinoSerial::ArduinoSerial() { startSerialPort(); } QString ArduinoSerial::bladeHeightValue() const { return m_bladeHeightValue; } QString ArduinoSerial::bladeAngleValue() const { return m_bladeAngleValue; } void ArduinoSerial::startSerialPort() { this->openSerialPort(); } void ArduinoSerial::readSerial() { // Read data static QByteArray byteArray; byteArray += arduino->readAll(); //we want to read all message not only chunks if(!QString(byteArray).contains("\n")) return; //sanitize data QString data = QString( byteArray ).remove("\r").remove("\n"); byteArray.clear(); if(data == "homing complete") homingComplete(); // Print data qDebug() << "RECV: " << data; //remove command prompt from Arduno Cmd and only return Integers to LCD if(data.toInt()){ if(droToSet == "bladeHeight") { setBladeHeightValue(data); bladeHeightValueChanged(); } if(droToSet == "bladeAngle") { setBladeAngleValue(data); bladeAngleValueChanged(); } } else { return; } } void ArduinoSerial::setBladeHeightValue(const QString &value) { if (m_bladeHeightValue != value) { m_bladeHeightValue = value; bladeHeightValueChanged(); } } void ArduinoSerial::setBladeAngleValue(const QString &value) { if (m_bladeAngleValue != value) { m_bladeAngleValue = value; bladeAngleValueChanged(); } } void ArduinoSerial::closeSerialPort() { if(arduino->isOpen()){ arduino->close(); } qDebug() << "Seriol Port is closed"; } void ArduinoSerial::writeSerial(QString dro, const QByteArray &data) { if (dro == "bladeHeight") droToSet = "bladeHeight"; if (dro == "bladeAngle") droToSet = "bladeAngle"; if (dro == "fence") droToSet = "fence"; if (dro == "router") droToSet = "router"; arduino->write(data); qDebug() << (data) + " written to serial"; } void ArduinoSerial::openSerialPort() { /* * Identify the port the arduino uno is on. */ arduino = new QSerialPort; arduino_is_available = false; arduino_port_name = ""; // // For each available serial port 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_port_name = serialPortInfo.portName(); qDebug() << QString("Arduino Port Name: %1").arg(arduino_port_name); } } } /* * Open and configure the arduino port if available */ if(arduino_is_available){ qDebug() << "Found the arduino port...\n"; arduino->setPortName(arduino_port_name); arduino->setBaudRate(QSerialPort::Baud9600); arduino->setDataBits(QSerialPort::Data8); arduino->setFlowControl(QSerialPort::NoFlowControl); arduino->setParity(QSerialPort::NoParity); arduino->setStopBits(QSerialPort::OneStop); arduino->open(QSerialPort::ReadWrite); qDebug() << arduino->isOpen(); QObject::connect(arduino, SIGNAL(readyRead()), this, SLOT(readSerial())); serialPortOpen(); }else{ serialPortEror(); } }
main.cpp
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "arduinoserial.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; qmlRegisterType<ArduinoSerial>("arduino.serial", 1, 0, "ArduinoSerial"); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.VirtualKeyboard 2.3 import QtQuick.Controls 2.2 import arduino.serial 1.0 import QtQuick.Dialogs 1.2 import QtGraphicalEffects 1.0 import QtQuick.Controls.Styles 1.4 ApplicationWindow { id: root visible: true width: 800 height: 400 title: qsTr("Stack") FontLoader { id: lcdFont source: "lcd.ttf" } property real bladeHeight: 0 property real bladeAngle: 0 property real zeroBladeHeight: 0 property real zeroBladeAngle: 0 ArduinoSerial { id: typeFromArduinoSerial onSerialPortOpen: console.log("Serial Port Open") onSerialPortEror: serialErrorDialog.visible = true onBladeHeightValueChanged: bladeHeight = (bladeHeightValue/10) - zeroBladeHeight onBladeAngleValueChanged: bladeAngle = (bladeAngleValue/10) - zeroBladeAngle onHomingComplete: { } } MessageDialog { id: serialErrorDialog title: "Serial Port Error" icon: "Critical" informativeText: "Can't find arduino!" standardButtons: StandardButton.Ok modality: Qt.ApplicationModal onAccepted: Qt.quit(); } header: ToolBar { contentHeight: toolButton.implicitHeight ToolButton { id: toolButton text: stackView.depth > 1 ? "\u25C0" : "\u2630" font.pixelSize: Qt.application.font.pixelSize * 1.6 onClicked: { if (stackView.depth > 1) { stackView.pop() } else { drawer.open() } } } Label { text: stackView.currentItem.title anchors.centerIn: parent } } Drawer { id: drawer width: root.width * 0.66 height: root.height Column { anchors.fill: parent ItemDelegate { text: qsTr("Table Saw") width: parent.width onClicked: { stackView.push("TableSaw.qml") drawer.close() } } ItemDelegate { text: qsTr("Page 2") width: parent.width onClicked: { stackView.push("Page2.qml") drawer.close() } } } } StackView { id: stackView initialItem: "Home.qml" anchors.fill: parent } InputPanel { id: inputPanel z: 99 x: 0 y: root.height width: root.width states: State { name: "visible" when: inputPanel.active PropertyChanges { target: inputPanel y: root.height - inputPanel.height } } transitions: Transition { from: "" to: "visible" reversible: true ParallelAnimation { NumberAnimation { properties: "y" duration: 250 easing.type: Easing.InOutQuad } } } } }
home.qml
import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.VirtualKeyboard 2.3 import QtQuick.Controls 2.2 import arduino.serial 1.0 import QtQuick.Dialogs 1.2 import QtGraphicalEffects 1.0 import QtQuick.Controls.Styles 1.4 Page { width: 800 height: 400 title: qsTr("Home") Image { id: woodBackground source: "Images/wood_background.jpg" width: root.width height: root.height } FontLoader { id: lcdFont source: "lcd.ttf" } Label { id: welcomeLabel color: "#3115ae" text: "Woodworking Tool" font.family: "Courier" font.pixelSize: 60 font.bold: true anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter anchors.verticalCenterOffset: -120 } RoundButton { id: homeButton icon.source: "Images/home.png" icon.height: 100 icon.width: 100 anchors.centerIn: parent anchors.verticalCenterOffset: 40 onClicked: { typeFromArduinoSerial.writeSerial("home" + "\r") } } }
tablesaw.qml
import QtQuick 2.11 import QtQuick.Window 2.11 import QtQuick.VirtualKeyboard 2.3 import QtQuick.Controls 2.2 import arduino.serial 1.0 import QtQuick.Dialogs 1.2 import QtGraphicalEffects 1.0 import QtQuick.Controls.Styles 1.4 Page { width: root.width height: root.height title: qsTr("Table Saw") Binding { target: bladeHeightLCD property: 'text' value: root.bladeHeight } Binding { target: bladeAngleLCD property: 'text' value: root.bladeAngle } Image { id: woodBackground source: "Images/wood_background.jpg" width: root.width height: root.height } Column{ spacing: 50 Row { TextField { id: writeBladeHeight placeholderText: "Set Blade Height.." inputMethodHints: Qt.ImhDigitsOnly onAccepted: { typeFromArduinoSerial.writeSerial("bladeHeight", ("startX " + (parseFloat(text) + root.zeroBladeHeight)*10) + "\r") } onActiveFocusChanged: { writeBladeHeight.text = "" } } TextField { id: bladeHeightLCD readOnly: true width: 150 height: 40 background: Rectangle { width: bladeHeightLCD.width height: bladeHeightLCD.height radius: 20 color: "black" border.width: 1 border.color: "red" } color: "springgreen" font.family: lcdFont.name font.pixelSize: 50 font.letterSpacing: 5 } RoundButton { id: zeroBladeHeightButton text: "Zero" onClicked: { root.zeroBladeHeight = root.bladeHeight console.log(root.zeroBladeHeight); bladeHeightLCD.text = "0" } } RoundButton { id: unZeroBladeHeightButton text: "Reset Zero" onClicked: { root.zeroBladeHeight = 0 root.bladeHeight = root.bladeHeight - root.zeroBladeHeight } } } Row { TextField { id: writeBladeAngle placeholderText: "Set Blade Angle.." inputMethodHints: Qt.ImhDigitsOnly onAccepted: { typeFromArduinoSerial.writeSerial("bladeAngle", "startY " + ((parseFloat(text) + root.zeroBladeAngle)*10) + "\r") } onActiveFocusChanged: { writeBladeAngle.text = "" } } TextField { id: bladeAngleLCD readOnly: true width: 150 height: 40 background: Rectangle { width: bladeAngleLCD.width height: bladeAngleLCD.height radius: 20 color: "black" border.width: 1 border.color: "red" } color: "springgreen" text: "" font.family: lcdFont.name font.pixelSize: 50 font.letterSpacing: 5 } RoundButton { id: zeroTwo text: "Zero" onClicked: { root.zeroBladeAngle = root.bladeAngle bladeAngleLCD.text = root.bladeAngle console.log(zeroBladeAngle); bladeAngleLCD.text = "0" } } RoundButton { id: unZeroTwo text: "Reset Zero" onClicked: { root.zeroBladeAngle = 0 bladeAngleLCD.text = root.bladeAngle } } } } }
-
Hi,
You are likely breaking the binding when you push that button.
-
I have tried the following as well to force an update but nothing changes...
RoundButton { id: unZeroTwo text: "Reset Zero" onClicked: { root.zeroBladeAngle = 0 root.bladeAngle = root.bladeAngle - root.zeroBladeAngle } }
-
I managed to sort it.
onBladeHeightValueChanged: bladeHeight = ((bladeHeightValue/10) - zeroBladeHeight).toFixed(1)
The maths was messy when taking a number from serial such as 11 then dividing it by 10 to 1.1 and misusing a non-zero zeroBladeHeight number such as 1 it was giving 0.00001. Sorted by fixing result to 1 decimal place.
signal bladeHeightZeroed onBladeHeightZeroed: bladeHeightLCD.text = root.bladeHeight - root.newZeroBladeHeight signal bladeHeightUnZeroed onBladeHeightUnZeroed: bladeHeightLCD.text = root.bladeHeight
I added signals in main Page area of qml
RoundButton { id: zeroBladeHeightButton text: "Zero" onClicked: { root.newZeroBladeHeight = root.bladeHeight root.zeroBladeHeight += newZeroBladeHeight bladeHeightZeroed() } } RoundButton { id: unZeroBladeHeightButton text: "Reset Zero" onClicked: { root.bladeHeight = root.zeroBladeHeight root.zeroBladeHeight = 0 bladeHeightUnZeroed() }
Then called them in buttons to update display. Additional variable allowed me to stack zeroing and the reset