Sorted reading on multiple inputs by order of timestamps
When implementing and executing data fusion algorithms in a multithreaded or even distributed environment, one of the difficulties is to maintain time coherency and make sure the data fusion will operate on data according to their measurement dates and not their dates of availability at the fusion stage (as the different streams may have been subject to different latencies due to pre-processing, communication, etc.)
Several strategies exist in RTMaps to read data from multiple inputs. The four basic strategies are the following:
- Asynchronous or Reactive: the component reacts every time new data arrives on any input;
- Triggered: the component reacts every time new data arrives on the first input, then re-samples available data on the other inputs
- Resampling: the component executes periodically and samples its input data;
- Resynchronizer: the component executes every time data samples with equal (or close) timestamps are available on all inputs.
This tutorial deals with an additional, advanced strategy that sorts samples by order of timestamps under constraint of maximum latency (and hence preserves time coherency though operating in a multi-thread, multi-process or even distributed architecture). Here is how to create a component using this strategy with the Windows and Linux wizards.
Creating the component
Start the component creation wizard by clicking Tools > RTMaps 4 > New RTMaps Module. In the wizard window that pops up, enter your component's name and select "Inherits from:" SortedStartReadingComponent Template. Click OK to create the component.
Open a terminal and call the wizard with the following command: rtmaps_sdk_wizard -c PackageName ComponentName. The wizard will ask you the type of component to create. Enter the number corresponding to the "Sorted Reader based component" and hit enter.
Implementing the component
The Sorted Reader works with a superclass called MAPSSortedStartReadingComponent. This class implements the sorting and your component inherits from it.
Your newly created component has the usual Birth, Core and Death methods. Note that the superclass's implementation is called in these callbacks. But you will also notice a new method in your component: HandleNewElement. This method is an additional callback that will be called each time a data sample has been sorted by the superclass. This callback is where you should program your component's logic.
The principle of the sorting is that the superclass performs a Reactive reading to get all incoming data. It assumes that timestamps on any given input are increasing. When the component receives a sample s, it waits to receive data of greater timestamp on the other inputs. This validates sample s and HandleNewElement is then called on this sample.
The component has a max_latency property. This is the maximum latency that you accept for a data sample. When a data sample's latency exceeds this maximum, HandleNewElement is called with the is_late parameter set to true.
When the current sample could not be sorted in the order of timestamps, HandleNewElement is called with the is_unsorted parameter set to true, and the unsorted_samples_count output is incremented. This can happen when the sample arrived too late and its timestamp is older than the ones of other already processed samples. Many unsorted samples can mean that the latency parameter is too small.