Telemetry Subscriber
Overview
The purpose of the Telemetry Subscriber is to receive samples published from one or more Telemetry Republishers for various DDS Topics, correlate these samples, and then write them into a shared memory queue for subsequent consumption by Data Tasks on the same node. Samples from the various DDS topics are correlated based on their sample ID, i.e. DDS samples with the same sample ID are matched together. The payloads for the matched samples are extracted and combined into a single, user-defined data structure using a user-supplied function, called the blender function. Each entry in the shared memory queue therefore contains data captured at the same loop cycle.
Since the topic data structure for the shared memory queue must be provided by the RTC Toolkit user,
it is not possible to have a fully working, pre-compiled and linked executable for the Telemetry
Subscriber.
The RTC Toolkit provides a template version of the Telemetry Subscriber in a library.
A working Telemetry Subscriber must be instantiated using the user-provided topic structure, and
compiled and linked against the librtctkTelemetrySubscriber.so library.
The idea is to provide an almost ready application that is a SRTC component and delivers all the boilerplate code for reading from DDS and correlating samples. The user then only needs to concentrate on defining the shared memory topic structure and a blender function that constructs the topic from correlated DDS samples.
The following section describes a Telemetry Subscriber that needs to be instantiated into an actual working application, how the application can be configured and how it is expected to behave.
Prerequisites
The Telemetry Subscriber library has the following external dependencies:
FastDDS - Provides the communication services (DDS implementation) to receive data from a Telemetry Republisher.
ipcq - Provides the shared memory queue into which correlated DDS samples are written for the downstream Data Tasks.
NUMA++ - This utility library is used to optionally control the NUMA node where shared memory is allocated, thread scheduling and pinning policies. This allows runtime performance optimisations.
If the RTC Toolkit has been successfully built with the Waf build system, the above dependencies should already be fulfilled.
It is assumed that the installation of the RTC Toolkit is performed into the INTROOT directory
and that the environment variable INTROOT is defined (see section Installation).
If this is not the case, any reference to INTROOT in the following sections needs to be properly
adjusted.
Although a Telemetry Subscriber is able to start with default settings for FastDDS, to properly use
any Telemetry Subscriber instance together with a Telemetry Republisher, one should use the dedicated
FastDDS XML QoS file supplied by the RTC Toolkit. The default file is telemDataPathDdsQos.xml
installed in $INTROOT/resource/config/rtctk/dds/. Actually the file can be put anywhere
under rtctk/dds/ in $CFGPATH. The file name can be set in the component’s configuration
dds_qos_file (see Configuration section for details).
Note
FASTDDS_DEFAULT_PROFILES_FILE environment variable shall not be used (set) and used in particular if the file that the variable points to contains the same QoS profiles.
In addition, the Telemetry Subscriber configuration must be prepared so that it uses the correct
profile that is defined in the XML file.
These configuration settings for dds_qos_profile are indicated in the
Configuration section below.
Customisation
The only customisation currently available for a Telemetry Subscriber instance is to specify the shared memory topic type and provide a blender function that will appropriately construct the shared memory super-topic from correlated input DDS samples. It is in fact mandatory to instantiate a Telemetry Subscriber with a user-supplied topic and blender method to get a working Telemetry Subscriber. It is also the user’s responsibility to ensure that the topic is the appropriate one, as expected by downstream Data Tasks, and that the blender function assembles the topic in shared memory from the individual DDS samples correctly.
The Blender Function
A function used to construct the user-defined topic in shared memory must be provided with the following signature:
// Signature as a normal function:
std::error_code Blender(const rtctk::telSub::DataSamplesView& dds_samples,
MyTopic& shm_sample) noexcept {
// ... user code goes here ...
}
// Signature as a lambda function:
auto blender = [](const rtctk::telSub::DataSamplesView& dds_samples,
MyTopic& shm_sample) noexcept -> std::error_code {
// ... user code goes here ...
}
Two alternative declarations are shown above, the first using the typical function declaration syntax and the second showing the blender function declared as a lambda. Choosing one style over the other is at the user’s discretion.
The first input argument must be the list of correlated DDS samples.
Refer to the API reference documentation for details about the structure of
DataSamplesView.
The second output argument must be the topic structure previously declared by the user. This is a reference to the region in the shared memory that the data should be written to.
The return type of the blender function must be an error code.
When the user topic structure has been successfully constructed it must return a zero or empty error
code, indicating success, e.g. return {};.
In the case that the topic could not be constructed an appropriate error code should be returned.
The suggested error code to use at the moment is std::errc::bad_message,
to indicate there is something wrong with the format of the DDS samples.
Note
The blender function must not throw any exceptions. Throwing an exception will cause the processing thread to call std::terminate, which will cause the Telemetry Subscriber component to abort. This means that all error conditions must be indicated by returning an appropriate error code. If any code is executed that could throw an exception, this must be caught in a try..catch block and converted to an error code instead. E.g. this includes functions like std::map::at which can throw std::out_of_range.
The code for the body of the blender function must be provided by the user,
since it will depend on the input DDS sample topics and the user provided shared memory topic
structure.
Typically this only involves copying the data from the DDS sample buffers to the correct location
within the shared memory.
In the most trivial case this can simply be a call to std::memcpy.
Note
Since the blender function is executed in the DDS reading thread, which is time critical, minimal amount of work should be performed in the blender function. Only basic sanity checks should be applied to the input data and the minimal code to copy the data into the shared memory topic should be provided. Any complex computation should be done in a Data Task.
Instantiation
To instantiate a Telemetry Subscriber with a user-defined super-topic, one needs to prepare a
custom application.
The minimal wscript build configuration file to instantiate an application called
myTelSub would be similar to the following:
from wtools.module import declare_cprogram
declare_cprogram(
target="myTelSub",
use="rtctk.reusableComponents.telSub.lib"
)
As can be seen, it only needs to depend on rtctk.reusableComponents.telSub.lib.
If the user-defined shared memory topic is defined in a separate module,
then this additional module would also have to be added to the use argument.
The entrypoint declaration for this example myTelSub application,
i.e. the contents of the main.cpp file,
should look similar to the following:
#include <rtctk/telSub/main.hpp>
#include "myTopic.hpp"
void RtcComponentMain(const rtctk::componentFramework::Args& args) {
auto blender = [](const rtctk::telSub::DataSamplesView& dds_samples,
MyTopic& shm_sample) noexcept -> std::error_code {
// ... user code for the blender goes here ...
return {};
};
rtctk::telSub::Main<MyTopic>(args, std::move(blender));
}
Since any Telemetry Subscriber is an SRTC component, we must declare the entrypoint with
RtcComponentMain, rather than with just int main(int argc, const char* argv[]).
We also rely on the template function rtctk::telSub::Main to perform the setup specific to a
Telemetry Subscriber and enter the processing loop.
Refer to the Customise a Telemetry Subscriber tutorial to see a complete working example of a Telemetry Subscriber instantiation.
Configuration
All Telemetry Subscriber components will accept the configuration parameters described in this
section.
These are all read from the Runtime Configuration Repository during initialisation when the
Init command is received.
The configuration parameters are divided into groups as indicated in the sections below. Optional parameters are indicated in the description.
DDS Parameters
Configuration Path |
Type |
Description |
|---|---|---|
|
|
(optional) DDS domain identifier to subscribe to. If not specified, domain id 0 is used. |
|
|
(optional) The name of the profile to use from the QoS configuration XML file.
If not specified, default |
|
|
(optional) Name of DDS QoS XML file. The file should be found in $CFGPATH under rtctk/dds/. If not specified the default name is used: telemDataPathDdsQos.xml. |
|
|
(optional) list of network interfaces to be used by DDS. If not specified any interface may be used. |
|
|
multicast_address to add to locator list for DDS. Can be empty string. The topic_name in the path needs to correspond to the dds_topic. This setting has to be present for each topic. |
The following is an example of the above configuration parameters in a YAML file:
static:
dds:
domain_id: !cfg.type:int32 123
qos_profile: !cfg.type:string RtcTk_Default_Profile
qos_file: !cfg.type:string telemDataPathDdsQos.xml
dds_topics: !cfg.type:vector_string
SlopesTopic:
multicast_address: !cfg.type:string 224.0.0.9
IntensitiesTopic:
multicast_address: !cfg.type:string ""
CommandsTopic:
multicast_address: !cfg.type:string "224.0.0.5"
Operational Logic Parameters
Configuration Path |
Type |
Description |
|---|---|---|
|
|
(optional) Delay in milliseconds before receiving the signal to stop writing to the shared memory queue and closing, i.e. destroying the shared memory writer. This provides an opportunity for the shared memory queue readers to detach gracefully. If not specified, the default value is 0 ms. |
|
|
(optional) Time in milliseconds to wait for receiving and correlating DDS input samples, before considering the operation to have timed out. If a timeout occurs, the error will be indicated, but the Telemetry Subscriber component will not enter the error state. If not specified, the default value is 100 ms. |
|
|
(optional) Time in milliseconds, which determines how often the monitoring thread wakes up to report errors from the processing thread. If not specified, the default value is 500 ms. |
|
(optional) Defines NUMA policies for the processing thread. |
|
|
(optional) Defines NUMA policies for the monitoring thread. |
|
|
|
(optional) Expects a specific sample_id increment (useful for sub-sampled telemetry topics). If not specified, the default value is 1. |
The following is an example of the above configuration parameters in a YAML file:
static:
close_detach_delay: !cfg.type:int32 1000
correlator_poll_timeout: !cfg.type:int32 200
monitor_report_interval: !cfg.type:int32 1000
processing_thread_policies:
cpu_affinity: !cfg.type:string "1-4"
scheduler_policy: !cfg.type:string Fifo
scheduler_priority: !cfg.type:int32 10
memory_policy_mode: !cfg.type:string Bind
memory_policy_nodes: !cfg.type:string "1-4"
monitoring_thread_policies:
# Monitoring thread is executed with lower priority
scheduler_policy: !cfg.type:string Other
scheduler_priority: !cfg.type:int32 -1
Commands
Telemetry Subscriber instances can be steered by sending commands to their provided CII MAL interfaces.
The set of commands is indicated in the following table, together with the expected behaviour:
Command |
Behaviour |
|---|---|
Init |
Constructs objects to read DDS input samples; constructs shared memory writer; spawns low level processing and monitoring threads; starts reading and correlating DDS samples (no publishing to SHM yet, plus read errors and timeouts are ignored). |
Exit |
Terminates the process. |
Stop |
Stops the initialisation procedure started by the Init command. |
Reset |
Resets the state of the component to the state before the Init command was received. This means that all DDS objects are destroyed, shared memory is released, and the processing and monitoring threads are also destroyed. |
Enable |
No particular actions are performed here. |
Disable |
No particular actions are performed here. |
Update |
Reloads dynamic component configuration. |
Run |
Requests transition to On::Operational::Running which:
Errors are counted and reported by the monitoring thread, but attempts to correlate and write to shared memory will continue. This means, errors lead to missing samples in the shared memory queue. |
Idle |
Requests transition to On::Operational::Idle which:
|
Errors
Not Operational
The main errors that can currently occur during component initialisation when it receives the
Init command are due to missing mandatory configuration parameters.
The following is an example of the log message for such an error when dds_topics is missing:
[13:52:21:730][ERROR][rtctk] Failed to load configuration from the Runtime Repository: Path '/tel_sub_1/static/dds_topics' does not exist.
[13:52:21:730][ERROR][rtctk] Activity.Initialising: failed, exception: Path '/tel_sub_1/static/dds_topics' does not exist.
For cases where the wrong data type was used in a type field in the YAML file,
the following example error message would be seen in the logs:
[00:02:49:597][ERROR][rtctk] Activity.Initialising: failed, exception: Wrong type used to read data point.
If the YAML file format is not correct, e.g. a value field has the wrong format,
the following example error message would be seen in the logs:
[00:03:54:061][ERROR][rtctk] Activity.Initialising: failed, exception: File '/home/eltdev/test_install/run/exampleTelSub/runtime_repo/tel_sub_1.yaml' has an invalid data format.
Operational
While the Telemetry Subscriber is running, the main sources of errors are:
DDS subscription.
Problem with received data samples.
If timeout errors occur, it may indicate that the DDS publisher is no longer working, or the timeout threshold is too low for the sample rate and needs to be adjusted (see Operational Logic Parameters). In such cases, the following error messages will be seen in the logs:
[13:49:59:480][ERROR][rtctk] Detected errors during wait for DDS: [Last error code = 10: Timeout Error. Total number of errors = 1]
If data is received but cannot be correlated because the sample id is wrong, it is indicated with the following log message:
[11:37:27:388][ERROR][rtctk] Unexpected Sample Id. Expected 9 but got 10 for topic 'example_topic'. Total number of errors = 43
In both cases, the Telemetry Subscriber attempts to auto-recover by resetting the correlator and starting over again.
Note
This automatic re-synchronisation leads to missing samples in the shared memory queue and should be avoided by carefully dimensioning the network and configuring the DDS QoS file.
For failures when writing to the shared memory queue, messages about “Detected errors in SHM Publisher” will be logged with the error code received from the sub-system, similar to the following:
[13:48:44:448][ERROR][rtctk] Detected errors in SHM Publisher: error code = 74: Bad message. [Total number of errors = 1]
When the blender function returns a non-default error_code, the last raised error_code will be logged with the following message:
[14:43:24:385][ERROR][rtctk] Detected errors in Blender: error code: 74: Bad message. [Total number of errors = 5]
Alerts
The following alerts are used in Telemetry Subscriber.
Note
Latched means that the alert will be set active if the respective problem occurs in the Running state.
The alert remains active until it is explicitly cleared together with other alerts using ClearAlerts command
or a Run -> Idle or Idle -> Run transition is made.
Alert Id |
Latched |
Description |
|---|---|---|
|
Yes |
Indicates a problem on the DDS subscription side, meaning problems to receive the telemetry data over DDS. |
|
Yes |
Indicates a problem when correlating the telemetry streams. |
|
Yes |
The blender function returned an error code. |
|
Yes |
Indicates a problem writing to shared memory (for example when the queue is closed). |
Component Metrics
For each Telemetry Subscriber the following performance counter metrics are periodically published
under the OLDB path COMPONENT_ID/metrics/counter/.
OLDB Path |
Type |
Description |
|---|---|---|
|
|
Estimated frequency of the processing loop [Hz]. |
|
|
Duration of DDS reception and correlation [us]. |
|
|
Number of DDS samples successfully received and correlated. |
|
|
Number of DDS reception errors. |
|
|
Number of correlation errors. |
|
|
Number of samples successfully blended and published to SHM. |
|
|
Number of SHM publication errors. |
|
|
Number of blender errors. |
|
|
Last sample id that was successfully published to SHM queue. |