Виталий Антипов
Виталий Антипов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
            AD

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

            • Result:50points,
            • Rating points-4
            m

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

            • Result:80points,
            • Rating points4
            m

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

            • Result:20points,
            • Rating points-10
            Last comments
            ИМ
            Игорь МаксимовNov. 22, 2024, 10:51 p.m.
            Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
            Evgenii Legotckoi
            Evgenii LegotckoiNov. 1, 2024, 12:37 a.m.
            Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
            A
            ALO1ZEOct. 19, 2024, 6:19 p.m.
            Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
            ИМ
            Игорь МаксимовOct. 5, 2024, 5:51 p.m.
            Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
            d
            dblas5July 5, 2024, 9:02 p.m.
            QML - Lesson 016. SQLite database and the working with it in QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
            Now discuss on the forum
            Evgenii Legotckoi
            Evgenii LegotckoiJune 25, 2024, 1:11 a.m.
            добавить qlineseries в функции Я тут. Работы оень много. Отправил его в бан.
            t
            tonypeachey1Nov. 15, 2024, 5:04 p.m.
            google domain [url=https://google.com/]domain[/url] domain [http://www.example.com link title]
            NSProject
            NSProjectJune 4, 2022, 1:49 p.m.
            Всё ещё разбираюсь с кешем. В следствии прочтения данной статьи. Я принял для себя решение сделать кеширование свойств менеджера модели LikeDislike. И так как установка evileg_core для меня не была возможна, ибо он писался…
            9
            9AnonimOct. 25, 2024, 7:10 p.m.
            Машина тьюринга // Начальное состояние 0 0, ,<,1 // Переход в состояние 1 при пустом символе 0,0,>,0 // Остаемся в состоянии 0, двигаясь вправо при встрече 0 0,1,>…

            Follow us in social networks