Periodic Data Reader

6 posts / 0 new
Last post
Offline
Last seen: 2 years 4 months ago
Joined: 09/08/2020
Posts: 26
Periodic Data Reader

I'm creating a Data Reader that reads and processes messages on the DDS bus periodically.  To do this I have a DataReader that depends on a DataListener.  I use on_data_available() from the DataListener.  Then I'm passing LoanedSamples back to my main method (that implements the reader/listener, and processes the LoanedSamples).  This main method runs every 1s.

 

I noticed in testing that if I publish at at faster rate (e.g. 3hz) than I'm subscribed (1hz), the on_data_available method runs a few times between every main method execution (and when main runs, it grabs the latest topic instance on the DDS bus - which makes sense).  However, if I'm reading the data periodically is a DataListener unnecessary?  Is there a cleaner way to implement a reader if I only read periodically and don't need to process new data instantaneously?  Looking to avoid unnecessary overhead if on_data_available() isn't needed.

main:

dds::sub::LoanedSamples<HelloWorld> loanedSamples;
hello_world_listener listener = hello_world_listener(&loanedSamples);

    dds::sub::DataReader<HelloWorld> reader(subscriber, topic, dds::sub::qos::DataReaderQos(), &listener);

    while(true) {
        std::cout << "Passing through samples..." << std::endl;
        for (auto sample : loanedSamples) {
            if (sample.info().valid()) {
                std::cout << sample.data() << std::endl;
            }
        }
        sleep(1);
    }

listener:

void hello_world_listener::on_data_available(dds::sub::DataReader<HelloWorld> &reader)
{
    std::cout << "on_data_available callback" << std::endl;

    //get data
    *m_loanedSamples = reader.take();
}

Kpsingh05's picture
Offline
Last seen: 2 years 3 months ago
Joined: 03/05/2020
Posts: 12

Hello Sharro

If you want to process the data at a fixed rate, irrespective of the publication rate. You may use time based filter QoS

The TIME_BASED_FILTER QosPolicy allows you to specify that data should not be delivered more than once per specified period for data-instances of a DataReader, regardless of how fast DataWriters are publishing new samples of the data-instance.

This QoS policy allows you to optimize resource usage (CPU and possibly network bandwidth) by only delivering the required amount of data to different DataReaders.

DataWriters may send data faster than needed by a DataReader. For example, a DataReader of sensor data that is displayed to a human operator in a GUI application does not need to receive data updates faster than a user can reasonably perceive changes in data values. This is often measure in tenths (0.1) of a second up to several seconds. However, a DataWriter of sensor information may have DataReaders that are processing the sensor information to control parts of the system and thus need new data updates in measures of hundredths (0.01) or thousandths (0.001) of a second.

 

<datareader_qos>
<!--
  Here we set a time-based filter with a minimum separation
                      of 2 seconds. That is, samples for every single instance
                      will be separated in time at least 2 seconds.  -->

<time_based_filter>
<minimum_separation>
<sec>1</sec>
<nanosec>0</nanosec>
</minimum_separation>
</time_based_filter>
</datareader_qos>

For details, you may refer https://community.rti.com/static/documentation/connext-dds/6.0.1/doc/manuals/connext_dds/html_files/RTI_ConnextDDS_CoreLibraries_UsersManual/Content/UsersManual/TIME_BASED_FILTER_QosPolicy.htm

Regards

KP Singh

Offline
Last seen: 2 years 4 months ago
Joined: 09/08/2020
Posts: 26

Thanks KP Singh I'll check into that filter.

 

If I add the TIME_BASED_FILTER QoS filter to the reader, would a valid way to read that data still be via the Listener's on_data_available() function?  Or would this be combining synchronous/asynchronous data reading unnecessarily?  Just want to mimize overhead and follow best practice for periodically reading from the bus.

Offline
Last seen: 2 years 11 months ago
Joined: 08/09/2017
Posts: 25

Hi Sharro,

An alternative option is to get rid of the listener and simply call take() directly from your main routine. This will get any samples that arrived since the last time you called take(). This is called "polling" and is one of the methods described in the docs.

If you really are just trying to process all the data once a second, then this is a simple way to accomplish it. The listener isn't necessary.

Hope this helps.

- Mike

Howard's picture
Offline
Last seen: 2 days 10 hours ago
Joined: 11/29/2012
Posts: 583

To add to Mike and KP suggestions...

1) if you only want to receive a subset of the data based on time, e.g., subsample the data, then the Time-based Filter QOS is certainly useful.  However, note that this means that you won't get all of the data that was sent, only a subset

2) on the other hand, if you want to process all of the data, but only want to process periodically, then Mike's suggestion of just calling DataReader::take() in your processing loop will work.  This may add an average of a 1/2 processing period delay of processing received samples.  But you said that you didn't have to process the data "instantaneously" which I take to mean as soon as it arrives.  So, using the polling method should be OK for you

 

Offline
Last seen: 2 years 4 months ago
Joined: 09/08/2020
Posts: 26

Thanks for the feedback.  Since I only need to evaluate the data periodically, I removed the DataListener and just used DataReader::take() in the processing loop.  This is working well.