Виталий Антипов
Виталий АнтиповJuly 22, 2017, 5:26 p.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, 10:56 a.m.

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

    Evgenii Legotckoi
    • July 23, 2017, 7:44 p.m.

    День добрый.

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

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

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

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

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

        А то я тут внимательно присмотрелся к коду, и у меня возник вопрос. Почему выставление значения происходит только в конце метода start... По мне так, так там только один раз вызывается qDebug() ...
          Виталий Антипов
          • July 25, 2017, 10: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
            Ua

            Qt - Test 001. Signals and slots

            • Result:84points,
            • Rating points4
            Ua

            Qt - Test 001. Signals and slots

            • Result:42points,
            • Rating points-8
            ОК

            Qt - Test 001. Signals and slots

            • Result:47points,
            • Rating points-6
            Last comments
            ИМ
            Игорь МаксимовNov. 22, 2024, 9:51 p.m.
            Django - Tutorial 017. Customize the login page to Django Добрый вечер Евгений! Я сделал себе авторизацию аналогичную вашей, все работает, кроме возврата к предидущей странице. Редеректит всегда на главную, хотя в логах сервера вижу запросы на правильн…
            Evgenii Legotckoi
            Evgenii LegotckoiOct. 31, 2024, 11:37 p.m.
            Django - Lesson 064. How to write a Python Markdown extension Добрый день. Да, можно. Либо через такие же плагины, либо с постобработкой через python библиотеку Beautiful Soup
            A
            ALO1ZEOct. 19, 2024, 5:19 p.m.
            Fb3 file reader on Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
            ИМ
            Игорь МаксимовOct. 5, 2024, 4:51 p.m.
            Django - Lesson 064. How to write a Python Markdown extension Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
            d
            dblas5July 5, 2024, 8: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
            f
            firstlunoxodFeb. 15, 2025, 1:46 p.m.
            Рисование на QGraphicsScene при зажатой кнопке мыши Подскажите, пожалуйста! Как данный класс можно дополнить, чтобы созданные объекты можно было перемещать мышкой по сцене?
            Дмитрий
            ДмитрийFeb. 3, 2025, 4:24 p.m.
            Создание deb-пакета. Как создать ярлык на рабочем столе после установки собственного deb-пакета? Всем привет. Сделал свой deb-пакет с программой. Всё устанавливается и работает. Ставлю по пути /usr/bin/my_application. Как для пользователя при установке пакета сразу создать ярлык на раб…
            NW
            Nayo WaiJan. 30, 2025, 7:22 p.m.
            не запускается компьютер!!! Не запускается компьютер (точнее работает блок , но сам монитор вообще жесть)В общем я ничего с интернета не скачивала в последнее время. На компе никаких левых пр…
            n
            nklyJan. 3, 2025, 12:52 p.m.
            Нужно запретить перемещение только некоторых итемов, остальные перемещать можно. Вопрос решен. Узнать QModelIndex элемента на который мы перетаскиваем другой элемент, можно с помощью функции indexAt(event->position().toPoint()) представления QTreeViev вызываемой в переопр…
            M
            MarselAug. 17, 2023, 12:26 a.m.
            OAuth2.0 через VK, получение email Спасибо большое за помощь и простите за то что отнял время своей невнимательностью.

            Follow us in social networks