Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. For multiple sensors in RS485 hub, send and receive data cyclically
Forum Updated to NodeBB v4.3 + New Features

For multiple sensors in RS485 hub, send and receive data cyclically

Scheduled Pinned Locked Moved Solved General and Desktop
9 Posts 4 Posters 652 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • Y Offline
    Y Offline
    Yandong Luo
    wrote on 13 Mar 2021, 15:45 last edited by
    #1

    Hi, I have some issues with reading and sending data for multi-sensors in an RS485 hub 16 port. In my project, I need to send and read data from multiple different sensors at the same time and show it on the screen. The frequency of these sensors is all at 10 Hz. I need to send commands according to the protocol and wait for the return of the data.

    1. I use QtConcurrent::run() to Send commands and wait for data coming continuously in a loop for each sensor. But I found when I sending these commands in parallel can easily cause sending failures. I seem to have to send them at a sufficiently long interval each time to guarantee the success of the sending. I know this may be caused by too fast writing to the serial port. Send these instructions at the same point in time. So are there any solutions that can solve it?

    timeout.png

    1. I am very entangled in whether to put the read data in a separate thread for processing, or to put the read data and send commands in the same thread (waiting for instructions after sending). If put them into different threads, I feel this part of the processing will be more troublesome when the received data is incomplete or missing, or when the data is classified according to different sensors.
    // Each sensor starts a thread
    QtConcurrent::run(port,&Serial_Service::SendReceiveData,Button_Index,Type_Index,ID.toInt());
    
    void Serial_Service::loopSendRecive(int Reader_Index, int Type_Index, int ID)
    {
        // According to the different type of sensors, getting the command to send
        QByteArray TxBuffer = Update_Send_Data(Type_Index,ID);
    
        m_isCanRead[Reader_Index-1] = true;
    
        // start loop
        while(m_isCanRead[Reader_Index-1])
        {
            m_lock.lock();
    
            //send the data
            const qint64 bytesWritten = port->write(TxBuffer);
    
            qApp->processEvents();
    
            if(!port->waitForBytesWritten())
            {
                qDebug()<<QString("serial write failed because: %1").arg(port->errorString());
            }
            // wait for the data coming and processing
            ulong use_time = waitforData(Reader_Index,Type_Index,ID);
            m_lock.unlock();
    
            QThread::msleep(100);
        }
    }
    
    ulong Serial_Service::waitforData(int Reader_Index, int Type_Index, int ID)
    {
        // different sensors have different Frame;
        QByteArray startOfFrame;
    
        int Read_Length = 0;
    
        switch (Type_Index) {
        case HCA726S:{
            startOfFrame = QByteArray::fromHex("68");
            Read_Length = 16;
            break;
        }
        case LVDT_SENSORS:{
            startOfFrame = QByteArray::fromHex("01");
            qDebug()<<"LVDT";
            Read_Length = 9;
            break;
        }
        case TORQUE_SENSORS:{
            startOfFrame = QByteArray::fromHex("BB");
            Read_Length = 10;
            break;
        }
        }
    
        QByteArray responseData;
    
        // Sometimes the code will block here, I don’t know why this happens
        if(port->bytesAvailable() != -1)
        {
            while(port->bytesAvailable()==0)
            {
                QThread::msleep(5);
            }
            // if data can be read
            if(port->bytesAvailable()!=0)
            {
                QByteArray temp = port->read(1);
    
                // Find the start of the frame
                while (temp != startOfFrame) {
                    temp = port->read(1);
                }
                responseData.clear();
    
                responseData.append(temp);
    
                // If the data is incomplete, wait for the data
                while(port->bytesAvailable()<Read_Length-1)
                {
                    QThread::msleep(5);
                }
    
                responseData.append(port->read(Read_Length-1));
    
                emit Send_Data_to_Process(responseData,Reader_Index);
            }
        }
    }
    
    1 Reply Last reply
    0
    • C Online
      C Online
      Christian Ehrlicher
      Lifetime Qt Champion
      wrote on 13 Mar 2021, 16:07 last edited by
      #2

      Why using threads in the first place for no reason? Don't use them but signals and slots and all your problems and locking stuff can be thrown away.

      Qt Online Installer direct download: https://download.qt.io/official_releases/online_installers/
      Visit the Qt Academy at https://academy.qt.io/catalog

      1 Reply Last reply
      4
      • Y Offline
        Y Offline
        Yandong Luo
        wrote on 15 Mar 2021, 04:27 last edited by
        #3

        Thank you so much for your suggestion. I have modified the code according to your suggestion and deleted all unnecessary threads. Now I put the serial port sending in a continuous looping thread, and the response of the button is just to add the command to be sent, and reading the data through readyRead(). But there are still some issues.

        1. When sending multiple different commands, it seems that partial data loss. But when sending the same commands, this will happen.

        2. Would it be a good choice to use asynchronous sending? I have referred to the asynchronous sending tutorial. But how to achieve asynchronous sending in a loop?

        button click

        if(Component_List[i].Button_Read->text() == tr("Read"))
        {
              Component_List[i].Button_Read->setText("Stop");
               port->SetRequest(Type_Index,ID.toInt());
        }
        

        Add command

        void Serial_Service::SetRequest(int Type_Index, int ID)
        {
            QByteArray request = Update_Send_Data(Type_Index, ID);
            // get the command and append it to the QByteArrayList
            m_writeData.append(request);
            m_bRunThread = true;
        }
        

        The thread of sending

        void Serial_Service::loopSend()
        {
            m_bRunThread = true;
            while(m_bRunThread)
            {
                if(!m_writeData.isEmpty())
                {
                    qDebug()<<"The length of write data:"<<m_writeData.length();
                    for(int i=0;i<m_writeData.length();i++)
                    {
                        qint64 bytesWritten = port->write(m_writeData[i]);
                        qDebug()<<"index i: "<<i<<"write data:"<<m_writeData[i].toHex();
                        if (!port->waitForBytesWritten(5000)) {
                            qDebug() << QObject::tr("Operation timed out or an error occurred for port %1, error: %2").arg(port->portName()).arg(port->errorString()) << endl;
                        }
                        // Without this line, sending multiple different commands will not succeed
                        QThread::msleep(1);
                    }
                    qDebug()<<QString(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
                    QThread::msleep(Interval);
                }
            }
        }
        

        Reading

        connect(port, SIGNAL(readyRead()), this, SLOT(RecieveData()));
        
        void Serial_Service::RecieveData()
        {
                static QByteArray Rx_buffer;
                Rx_buffer.append(port->readAll());
                qDebug()<<"Rx_buffer:"<<Rx_buffer.toHex();
        }
        

        Snipaste_2021-03-15_12-24-53.png

        jsulmJ 1 Reply Last reply 15 Mar 2021, 06:25
        0
        • Y Yandong Luo
          15 Mar 2021, 04:27

          Thank you so much for your suggestion. I have modified the code according to your suggestion and deleted all unnecessary threads. Now I put the serial port sending in a continuous looping thread, and the response of the button is just to add the command to be sent, and reading the data through readyRead(). But there are still some issues.

          1. When sending multiple different commands, it seems that partial data loss. But when sending the same commands, this will happen.

          2. Would it be a good choice to use asynchronous sending? I have referred to the asynchronous sending tutorial. But how to achieve asynchronous sending in a loop?

          button click

          if(Component_List[i].Button_Read->text() == tr("Read"))
          {
                Component_List[i].Button_Read->setText("Stop");
                 port->SetRequest(Type_Index,ID.toInt());
          }
          

          Add command

          void Serial_Service::SetRequest(int Type_Index, int ID)
          {
              QByteArray request = Update_Send_Data(Type_Index, ID);
              // get the command and append it to the QByteArrayList
              m_writeData.append(request);
              m_bRunThread = true;
          }
          

          The thread of sending

          void Serial_Service::loopSend()
          {
              m_bRunThread = true;
              while(m_bRunThread)
              {
                  if(!m_writeData.isEmpty())
                  {
                      qDebug()<<"The length of write data:"<<m_writeData.length();
                      for(int i=0;i<m_writeData.length();i++)
                      {
                          qint64 bytesWritten = port->write(m_writeData[i]);
                          qDebug()<<"index i: "<<i<<"write data:"<<m_writeData[i].toHex();
                          if (!port->waitForBytesWritten(5000)) {
                              qDebug() << QObject::tr("Operation timed out or an error occurred for port %1, error: %2").arg(port->portName()).arg(port->errorString()) << endl;
                          }
                          // Without this line, sending multiple different commands will not succeed
                          QThread::msleep(1);
                      }
                      qDebug()<<QString(QDateTime::currentDateTime().toString("hh:mm:ss.zzz"));
                      QThread::msleep(Interval);
                  }
              }
          }
          

          Reading

          connect(port, SIGNAL(readyRead()), this, SLOT(RecieveData()));
          
          void Serial_Service::RecieveData()
          {
                  static QByteArray Rx_buffer;
                  Rx_buffer.append(port->readAll());
                  qDebug()<<"Rx_buffer:"<<Rx_buffer.toHex();
          }
          

          Snipaste_2021-03-15_12-24-53.png

          jsulmJ Offline
          jsulmJ Offline
          jsulm
          Lifetime Qt Champion
          wrote on 15 Mar 2021, 06:25 last edited by
          #4

          @Yandong-Luo said in For multiple sensors in RS485 hub, send and receive data cyclically:

          while(m_bRunThread)

          You're blocking event loop.
          Is Serial_Service running in its own thread?
          Why don't you use QTimer to send data periodically instead of using an event loop blocking loop?

          https://forum.qt.io/topic/113070/qt-code-of-conduct

          Y 1 Reply Last reply 15 Mar 2021, 07:30
          3
          • jsulmJ jsulm
            15 Mar 2021, 06:25

            @Yandong-Luo said in For multiple sensors in RS485 hub, send and receive data cyclically:

            while(m_bRunThread)

            You're blocking event loop.
            Is Serial_Service running in its own thread?
            Why don't you use QTimer to send data periodically instead of using an event loop blocking loop?

            Y Offline
            Y Offline
            Yandong Luo
            wrote on 15 Mar 2021, 07:30 last edited by
            #5

            @jsulm Really thanks for your suggestion. I now use QTimer instead of using an event loop blocking loop. But when two or more different commands are sent continuously, the returned data is messy, wrong, or incomplete. I tested, if I set a sufficient sleep interval (about 50 milliseconds) between each command, all returned data will return to normal. But this sleep time will affect the simultaneous reading of these sensors. As the data to be sent increases, these sleep times will gradually accumulate.

            In other words, how can I send multiple requests to an RS485 hub at the same time as possible and get the correct data?

            jsulmJ 1 Reply Last reply 15 Mar 2021, 07:34
            0
            • Y Yandong Luo
              15 Mar 2021, 07:30

              @jsulm Really thanks for your suggestion. I now use QTimer instead of using an event loop blocking loop. But when two or more different commands are sent continuously, the returned data is messy, wrong, or incomplete. I tested, if I set a sufficient sleep interval (about 50 milliseconds) between each command, all returned data will return to normal. But this sleep time will affect the simultaneous reading of these sensors. As the data to be sent increases, these sleep times will gradually accumulate.

              In other words, how can I send multiple requests to an RS485 hub at the same time as possible and get the correct data?

              jsulmJ Offline
              jsulmJ Offline
              jsulm
              Lifetime Qt Champion
              wrote on 15 Mar 2021, 07:34 last edited by
              #6

              @Yandong-Luo said in For multiple sensors in RS485 hub, send and receive data cyclically:

              how can I send multiple requests to an RS485 hub at the same time as possible and get the correct data?

              I suggest to implement a protocol: you send one request and wait for a response from the receiver, then you send next request. You simply can't send two requests at the "same time".

              https://forum.qt.io/topic/113070/qt-code-of-conduct

              Y 1 Reply Last reply 16 Mar 2021, 14:59
              4
              • jsulmJ jsulm
                15 Mar 2021, 07:34

                @Yandong-Luo said in For multiple sensors in RS485 hub, send and receive data cyclically:

                how can I send multiple requests to an RS485 hub at the same time as possible and get the correct data?

                I suggest to implement a protocol: you send one request and wait for a response from the receiver, then you send next request. You simply can't send two requests at the "same time".

                Y Offline
                Y Offline
                Yandong Luo
                wrote on 16 Mar 2021, 14:59 last edited by
                #7

                @jsulm Thanks for your help!

                JoeCFDJ 1 Reply Last reply 16 Mar 2021, 16:57
                0
                • Y Yandong Luo
                  16 Mar 2021, 14:59

                  @jsulm Thanks for your help!

                  JoeCFDJ Offline
                  JoeCFDJ Offline
                  JoeCFD
                  wrote on 16 Mar 2021, 16:57 last edited by
                  #8

                  @Yandong-Luo You may send a lot of requests one after another quickly. But you may cache the return data( push them into a queue and process them one after another).

                  1 Reply Last reply
                  0
                  • Y Offline
                    Y Offline
                    Yandong Luo
                    wrote on 19 Mar 2021, 01:17 last edited by
                    #9

                    Serenity I appreciate all of your diligent work in helping me solve my problem. Finally, I adopted the scheme from Juslm. I implement a protocol: I send one request and wait for a response from the receiver, then I send the next request. The time required for each sending and receiving is about 40ms.

                    1 Reply Last reply
                    1

                    1/9

                    13 Mar 2021, 15:45

                    • Login

                    • Login or register to search.
                    1 out of 9
                    • First post
                      1/9
                      Last post
                    0
                    • Categories
                    • Recent
                    • Tags
                    • Popular
                    • Users
                    • Groups
                    • Search
                    • Get Qt Extensions
                    • Unsolved