Виталий Антипов
Виталий АнтиповJuly 22, 2017, 7:26 a.m.

Передача данных из цикла С++ в QML

Здравствуйте! У меня следующая задача: с датчика mpu6050 передать данные ускорения восьми измерений подряд на ODROID XU4, вычислить СКЗ каждого измерения и последовательно передать их в QML в поле TextField. Ниже представленный код работает отлично, вот только в поле TextField отображается лишь СКЗ последнего измерения, а хотелось бы визуально наблюдать изменения от замера к замеру с перспективой построения графика в реальном времени. Прошу помощи.

 
main.cpp
#include <QQmlApplicationEngine>
#include <QApplication>
#include <QObject>
#include <QDebug>
#include <QQmlContext>
#include "dataport.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QLatin1String("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
    QObject* root = engine.rootObjects().first();
    dataport *port = new dataport(root);
    QObject::connect(root, SIGNAL(startSignal()), port, SLOT(start()));
    return app.exec();
}
 
dataport.h
#ifndef DATAPORT_H
#define DATAPORT_H

#include <QObject>
#include <QDebug>
#include <QTime>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#include <unistd.h>
#include <string.h>
#include <time.h>

#define I2C_SLAVE	0x0703
#define I2C_SMBUS	0x0720

#define I2C_SMBUS_READ	1
#define I2C_SMBUS_WRITE	0

#define I2C_SMBUS_QUICK		    0
#define I2C_SMBUS_BYTE		    1
#define I2C_SMBUS_BYTE_DATA	    2
#define I2C_SMBUS_WORD_DATA	    3
#define I2C_SMBUS_PROC_CALL	    4
#define I2C_SMBUS_BLOCK_DATA	    5
#define I2C_SMBUS_I2C_BLOCK_BROKEN  6
#define I2C_SMBUS_BLOCK_PROC_CALL   7	
#define I2C_SMBUS_I2C_BLOCK_DATA    8

#define I2C_SMBUS_BLOCK_MAX	    32	
#define I2C_SMBUS_I2C_BLOCK_MAX	32	

class dataport : public QObject
{
    Q_OBJECT

public:
    explicit dataport(QObject *parent = 0);

signals:
    //void sendToQml(QString skz);

public slots:
    void start();

private:
    QString dataX;
    int i,k,l;
    int16_t val1, val2;
    int accX;
    double massive[2048];
    double massiveX[2048];
    char ch1, ch2;
    double sumkv;
    double sum;
QString skz;

    union i2c_smbus_data
    {
      uint8_t   byte;
      uint16_t  word;
      uint8_t   block [I2C_SMBUS_BLOCK_MAX + 2] ;
    };

    struct i2c_smbus_ioctl_data
    {
      char                  read_write;
      uint8_t               command ;
      int                   size;
      union i2c_smbus_data  *data;
    };

    static inline int i2c_smbus_access (int fd, char rw, uint8_t command, int size, union i2c_smbus_data *data)
    {
      struct i2c_smbus_ioctl_data args ;

      args.read_write = rw ;
      args.command    = command ;
      args.size       = size ;
      args.data       = data ;
      return ioctl (fd, I2C_SMBUS, &args) ;
    }

    int i2c_smbus_read_byte_data(int fd, int reg)
    {
      union i2c_smbus_data data;

      if (i2c_smbus_access (fd, I2C_SMBUS_READ, reg, I2C_SMBUS_BYTE_DATA, &data))
        return -1 ;
      else
        return data.byte & 0xFF ;
    }

    void data_update (void);
    int system_init(void);

    const char *i2cHandleNode = "/dev/i2c-1";
    int i2c_fd = -1;

};

#endif // DATAPORT_H
 
dataport.cpp
#include "dataport.h"

    dataport::dataport(QObject *parent) : QObject(parent)
    {

    }

    void dataport::data_update(void)
    {
        if(ioctl(i2c_fd, I2C_SLAVE, 0x68) < 0)  {
            fprintf(stdout, "%s : ioctl I2C_SLAVE Setup Error!\n", __func__);
            return;
        }
        ch1 = i2c_smbus_read_byte_data(i2c_fd, 0x3b);
        ch2 = i2c_smbus_read_byte_data(i2c_fd, 0x3c);
        val1 = ch1<<8|ch2;
    }

    int dataport::system_init(void)
    {
        if((i2c_fd = open(i2cHandleNode, O_RDWR)) < 0)  {
            fprintf(stdout, "%s : %s Open Error!\n", __func__, i2cHandleNode);
            return  -1;
        }
        return  0;
    }

    void dataport::start()
    {
        QObject* textX1 = this->parent()->findChild<QObject*>("textX");
        if (system_init() < 0)
            {
                fprintf (stderr, "%s: System Init failed\n", __func__); fflush(stdout);
                //return -1;
            }
        for(l=0;l<8;l++){
QTime start = QTime::currentTime();
                   for(i=0;i<2048;i++){
                       usleep(70);
                        if(ioctl(i2c_fd, I2C_SLAVE, 0x68) < 0)  {
                            fprintf(stdout, "%s : ioctl I2C_SLAVE Setup Error!\n", __func__);
                            return;
                        }
                        ch1 = i2c_smbus_read_byte_data(i2c_fd, 0x3b);
                        ch2 = i2c_smbus_read_byte_data(i2c_fd, 0x3c);
                        val1 = ch1<<8|ch2;
                        massive[i]=val1;
                    }
qDebug()<< "time "<< start.elapsed();
sumkv = 0;
for(k=0;k<2048;k++){
    massiveX[k]=(fabs(massive[k]/16384) - 1)*9.81;
    sum = massiveX[k]*massiveX[k];
    sumkv = sumkv + sum;
}
            qDebug()<<massive[15];
            qDebug()<<massiveX[15];
            skz = QString::number(sqrt(sumkv/2048));///(l+1);
            qDebug()<<skz;
            textX1->setProperty("text",skz);
        }          
}
 
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
import QtCharts 2.0

ApplicationWindow {
    id: tex
    objectName: "tex"
    visible: true
    width: 640
    height: 480
    title: qsTr("TEST2")

signal startSignal()
    
    Button{
        text: "START"
        onClicked: startSignal()
    }

    TextField{
        id: textX
        objectName: "textX"
        width: parent.width/3
        height: parent.height/10
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: parent.top
    }
    Text {
        id: textXx
        objectName: "textXx"
        //text: qsTr("text")
    }
    ChartView{
        title: "SKZ"
        anchors.top: textX.bottom
        anchors.left: parent.left
        anchors.right: parent.right
        anchors.bottom: parent.bottom
        antialiasing: true       
    }
}
We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

5
Виталий Антипов
  • July 23, 2017, 12:56 a.m.

Попробовал через QQmlContext - результат тот же. В console.log("skz = ", skz) вижу что данные в qml приходят как задумано, но обновление текста в TextField происходит только после окончания работы функции. И при попытке цикл выполнить в qml даже с насильным textX.update() не приводит к желаемому результату.

    Evgenii Legotckoi
    • July 23, 2017, 9:44 a.m.

    День добрый.

    Под QQmlContext , подразумеваете, что регистрировали dataport в контексте QML , и через Connections устанавливали обработчик для сигнала sendToQml ? Как вариант данные могут обрабатываться очень быстро, и вы просто не успеваете заметить изменения.
    Вообще, применение сигнала sendToQml считаю наиболее оптимальным вариантом для этого User Case.

    Если говорить о том, что изменения происходят после выполнения функции, то возможно, что это из-за очереди слотов. Установка данных в QML тоже осуществляется через сигнал/слотовые соединения.
    Как вариант, можете сначала сделать буфер подготовленных данных, а потом уже их выкидывать через таймер, но мне кажется это несколько не правильным. Всё-таки работа с embedded, в котором обычно любые задержки критичны...
      Виталий Антипов
      • July 23, 2017, 2:43 p.m.

      Да, сигнально-слотовое соединение построил по вашим урокам. Таймер через qDebug показывает, что на взятие 2048 сигналов с датчика уходит 1000 мс. qDebug совместно с console.log из QML показывают новые данные раз в секунду как и задумано, не заметить изменения как-то сложно.

      Пару месяцев назад делал проект с Arduino и соответственно работал с буфером. Вот там приходящие данные сразу обновлялись в QML, трехмерная визуализация работала хорошо, но как вы правильно заметили возникли проблемы с временем - временные интервалы были абсолютно не стабильны, и если для визуализации не страшно, то для расчетов неприемлемо.
      Погуглив, четкого ответа не нашел. Некоторые предлагают в цикл подсунуть QApplication::processEvents(), другие говорят что это не хорошо. Завтра попробую.

        А вы не пробовали вставлять сигнал или выставление text через setProperty внутри цикла, где забираете значения с шины данных?

        А то я тут внимательно присмотрелся к коду, и у меня возник вопрос. Почему выставление значения происходит только в конце метода start... По мне так, так там только один раз вызывается qDebug() ...
          Виталий Антипов
          • July 25, 2017, 12:08 a.m.
          • (edited)

          У меня в главный цикл (цикл количества измерений) вложены два последовательных (цикл сбора данных и цикл обработки данных). setProperty (или emit sendToQml в случае использования context) вызывается в конце главного цикла.

          Я тут почитал немного про синхронные и асинхронные потоки и понял что так все и задумано (для безопасности потоков). Пока не закончится основной цикл ничего в интерфейсе не обновляется (хоть данные и передаются). И тут 2 варианта - либо использовать наглое прерывание цикла qApp->processEvents() (я проверил - работает), либо разложить код на два потока и управлять ими используя QThread (так правильнее и надежнее). Как разберусь с управлением потоков - выложу код.

            Comments

            Only authorized users can post comments.
            Please, Log in or Sign up
            d
            • dsfs
            • April 26, 2024, 4:56 a.m.

            C ++ - Test 004. Pointers, Arrays and Loops

            • Result:80points,
            • Rating points4
            d
            • dsfs
            • April 26, 2024, 4:45 a.m.

            C++ - Test 002. Constants

            • Result:50points,
            • Rating points-4
            d
            • dsfs
            • April 26, 2024, 4:35 a.m.

            C++ - Test 001. The first program and data types

            • Result:73points,
            • Rating points1
            Last comments
            k
            kmssrFeb. 8, 2024, 6:43 p.m.
            Qt Linux - Lesson 001. Autorun Qt application under Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
            Qt WinAPI - Lesson 007. Working with ICMP Ping in Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
            EVA
            EVADec. 25, 2023, 10:30 a.m.
            Boost - static linking in CMake project under Windows Ошибка LNK1104 часто возникает, когда компоновщик не может найти или открыть файл библиотеки. В вашем случае, это файл libboost_locale-vc142-mt-gd-x64-1_74.lib из библиотеки Boost для C+…
            J
            JonnyJoDec. 25, 2023, 8:38 a.m.
            Boost - static linking in CMake project under Windows Сделал всё по-как у вас, но выдаёт ошибку [build] LINK : fatal error LNK1104: не удается открыть файл "libboost_locale-vc142-mt-gd-x64-1_74.lib" Хоть убей, не могу понять в чём дел…
            G
            GvozdikDec. 18, 2023, 9:01 p.m.
            Qt/C++ - Lesson 056. Connecting the Boost library in Qt for MinGW and MSVC compilers Для решения твой проблемы добавь в файл .pro строчку "LIBS += -lws2_32" она решит проблему , лично мне помогло.
            Now discuss on the forum
            G
            George13May 4, 2024, 4:13 p.m.
            добавить qlineseries в функции Всем доброго времени суток! Товарищи, помогите, юному падавану обуздать QChart, уже неделю пытаюсь сам решить проблему, в интернете подходящих статей не нашел:) Проблема в следующем:…
            PS
            Peter SonMay 3, 2024, 5:57 p.m.
            Best Indian Food Restaurant In Cincinnati OH Ready to embark on a gastronomic journey like no other? Join us at App india restaurant and discover why we're renowned as the Best Indian Food Restaurant In Cincinnati OH . Whether y…
            Evgenii Legotckoi
            Evgenii LegotckoiMay 2, 2024, 2:07 p.m.
            Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Добрый день. По моему мнению - да, но то, что будет касаться вызовов к функционалу Андроида, может создать огромные трудности.
            IscanderChe
            IscanderCheApril 30, 2024, 4:22 a.m.
            Во Flask рендер шаблона не передаётся в браузер Доброе утро! Имеется вот такой шаблон: <!doctype html><html> <head> <title>{{ title }}</title> <link rel="stylesheet" href="{{ url_…
            G
            GarApril 22, 2024, 5:46 a.m.
            Clipboard Как скопировать окно целиком в clipb?

            Follow us in social networks