RealTimeThreadAsyncBridge
The RealTimeThreadAsyncBridge DataSource allows asynchronously collecting data from RealTimeThreads.
It is typically used to collect data from a RealTimeThread and offer it to a non-real-time thread, for example for logging purposes. The data is collected asynchronously, which means that the RealTimeThread is not blocked while the data is being collected. The data is then offered to the non-real-time thread at a certain frequency (e.g. 100 Hz).
Note
Many DataSource components already offer a decoupling mechanism to collect data asynchronously, for example the FileWriterGAM.
Important
Since the data is collected asynchronously, it is good practice to use techniques that mitigate aliasing, such as latching, tracking minimum and maximum values, or collecting histograms.
In this example, a monitor thread asynchronously logs to the screen at a frequency of 1 Hz, without impacting the performance of the real-time thread, which is running at 100 Hz.
CPUs could have been allocated to different cores. 1 +States = {
2 Class = ReferenceContainer
3 +State1 = {
4 Class = RealTimeState
5 +Threads = {
6 Class = ReferenceContainer
7 +Thread1 = {
8 Class = RealTimeThread
9 CPUs = 0x1
10 Functions = {GAMPerfMonitor GAMTimer GAMReference GAMDisturbanceWaveform GAMMathDisturbance GAMFilterDisturbance GAMController GAMSpringMass GAMMathModel GAMMathPositionErr GAMStats GAMPatchForceDims GAMForceStats GAMHist GAMMathExpr GAMConversion GAMFilterMovingAvg GAMWriter}
11 }
12 +ThreadMonitor = {
13 Class = RealTimeThread
14 CPUs = 0x1
15 Functions = {GAMTimerM GAMDisplay}
16 }
17
18 }
19 }
20 }
RealTimeThreadAsyncBridge expects one thread to write data to it and one or more threads to read data from it.1 +RTThreadAsynch = {
2 Class = RealTimeThreadAsyncBridge
3 }
GAMWriter writes data into RTThreadAsynch. 1 +GAMWriter = {
2 Class = IOGAM
3 InputSignals = {
4 Time = {
5 DataSource = DDB1
6 Type = uint32
7 }
8 Thread1CycleTimeAverage = {
9 DataSource = DDB1
10 Type = uint32
11 }
12 Thread1CycleTimeMovingAverage = {
13 OutputSignals = {
14 Time = {
15 DataSource = RTThreadAsynch
16 Type = uint32
17 }
18 Thread1CycleTimeAverage = {
19 DataSource = RTThreadAsynch
20 Type = uint32
21 }
22 Thread1CycleTimeMovingAverage = {
GAMDisplay reads data directly from RTThreadAsynch. Note that GAMDisplay is executed by ThreadMonitor, which runs at 1 Hz, while GAMWriter is executed by ThreadProcess, which runs at 100 Hz. 1 +GAMDisplay = {
2 Class = IOGAM
3 InputSignals = {
4 Time = {
5 DataSource = RTThreadAsynch
6 Type = uint32
7 }
8 Thread1CycleTimeAverage = {
9 DataSource = RTThreadAsynch
10 Type = uint32
11 }
12 Thread1CycleTimeMovingAverage = {
13 OutputSignals = {
14 Time = {
15 DataSource = Display
16 Type = uint32
17 }
18 Thread1CycleTimeAverage = {
19 DataSource = Display
20 Type = uint32
21 }
22 Thread1CycleTimeMovingAverage = {
Running the application
Start the receiver application with:
./MARTeApp.sh -f ../Configurations/MassSpring/RTApp-MassSpring-49.cfg -l RealTimeLoader -s State1
Once the application is running, inspect the screen output and verify that it is running without any issues. The log should show entries similar to the following:
$ [Warning - Threads.cpp:185]: Failed to change the thread priority (likely due to insufficient permissions) [0/1887]
$ [Warning - Threads.cpp:173]: Requested a thread priority that is higher than the one supported by the selected policy - clipping to the maximum value supported by the policy.
$ [Warning - Threads.cpp:181]: Failed to change the thread priority (likely due to insufficient permissions)
$ [Information - RealTimeLoader.cpp:111]: Started application in state State1
$ [Information - MARTeApp.cpp:135]: Application starting
$ [Information - LoggerBroker.cpp:152]: Time [0:0]:1000000
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeAverage [0:0]:9999
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMovingAverage [0:0]:9999.400138
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMax [0:0]:10974
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMin [0:0]:9027
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeHistogram [0:10]:{ 0 0 0 0 0 0 0 0 0 0 0 }
$ [Information - LoggerBroker.cpp:152]: Thread1FreeTimeHistogram [0:10]:{ 0 0 0 0 0 0 0 0 0 0 0 }
$ [Information - LoggerBroker.cpp:152]: ForceMax [0:0]:30.000000
$ [Information - LoggerBroker.cpp:152]: ForceMin [0:0]:3.420744
$ [Information - LoggerBroker.cpp:152]: Time [0:0]:2000000
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeAverage [0:0]:9999
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMovingAverage [0:0]:9999.599456
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMax [0:0]:10889
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeMin [0:0]:9112
$ [Information - LoggerBroker.cpp:152]: Thread1CycleTimeHistogram [0:10]:{ 0 0 0 0 0 0 0 0 0 0 0 }
$ [Information - LoggerBroker.cpp:152]: Thread1FreeTimeHistogram [0:10]:{ 0 0 0 0 0 0 0 0 0 0 0 }
$ [Information - LoggerBroker.cpp:152]: ForceMax [0:0]:30.000000
$ [Information - LoggerBroker.cpp:152]: ForceMin [0:0]:3.420744