diff --git a/ur_robot_driver/doc/real_time.md b/ur_robot_driver/doc/real_time.md
index c7d02207f..5bdbf0de4 100644
--- a/ur_robot_driver/doc/real_time.md
+++ b/ur_robot_driver/doc/real_time.md
@@ -1,10 +1,36 @@
# Setting up Ubuntu with a PREEMPT_RT kernel
In order to run the `universal_robot_driver`, we highly recommend to setup a ubuntu system with
-real-time capabilities. Especially with a robot from the e-Series the higher control frequency
-might lead to non-smooth trajectory execution if not run using a real-time-enabled system.
+(close-to) real-time capabilities. Especially with a robot from the e-Series the higher control frequency
+might lead to connection breakdowns if not run using a real-time-enabled system.
You might still be able to control the robot using a non-real-time system. This is, however, not recommended.
+For getting an almost real-time capable systems there are two methods available:
+
+1. A **lowlatency kernel** is a standard Linux kernel which is configured for more time-restricted
+ environments. See [this blog post series](https://ubuntu.com/blog/industrial-embedded-systems) for details.
+1. A **PREEMPT_RT-patched kernel** is a kernel that has been slightly modified in order to achieve a
+ more real-time capable system.
+
+After [doing some
+tests](https://github.com/fmauch/Universal_Robots_ROS_Driver/blob/master/ur_robot_driver/doc/real_time_benchmarking.md)
+we recommend using at least a lowlatency kernel for running the driver.
+
+## Lowlatency kernel
+
+Using a lowlatency kernel is definitively easier to setup then using a PREEMPT_RT kernel. In order
+to install a lowlatency kernel, simply run
+
+```bash
+sudo apt install linux-lowlatency
+```
+
+Then, continue with [setting up permissions](#setup-user-privileges-to-use-real-time-scheduling).
+
+## PREEMPT_RT patched kernel
+
+TODO: Bring this up-to-date. A current 5.xx kernel has a couple of more dependencies.
+
To get real-time support into a ubuntu system, the following steps have to be performed:
1. Get the sources of a real-time kernel
2. Compile the real-time kernel
@@ -12,7 +38,7 @@ To get real-time support into a ubuntu system, the following steps have to be pe
This guide will help you setup your system with a real-time kernel.
-## Preparing
+### Preparing
To build the kernel, you will need a couple of tools available on your system. You can install them
using
@@ -41,7 +67,7 @@ $ cd ${HOME}/rt_kernel_build
All future commands are expected to be run inside this folder. If the folder is different, the `$`
sign will be prefixed with a path relative to the above folder.
-## Getting the sources for a real-time kernel
+### Getting the sources for a real-time kernel
To build a real-time kernel, we first need to get the kernel sources and the real-time patch.
First, we must decide on the kernel version that we want to use. Above, we
@@ -67,7 +93,7 @@ $ xz -dk patch-4.14.139-rt66.patch.xz
$ xz -d linux-4.14.139.tar.xz
```
-### Verification
+#### Verification
Technically, you can skip this section, it is however highly recommended to verify the file
integrity of such a core component of your system!
@@ -133,7 +159,7 @@ Primary key fingerprint: 5BDF C45C 2ECC 5387 D50C E5EF DE09 8267 78A3 8521
Subkey fingerprint: ACF8 5F98 16A8 D5F0 96AE 1FD2 0129 F385 52C3 8DF1
```
-## Compilation
+### Compilation
Before we can compile the sources, we have to extract the tar archive and apply the patch
```bash
@@ -174,8 +200,9 @@ linux-4.14.139$ sudo apt install ../linux-headers-4.14.139-rt66_*.deb ../linux-i
```
## Setup user privileges to use real-time scheduling
-To be able to schedule threads with user privileges (what the driver will do) you'll have to change
-the user's limits by changing `/etc/security/limits.conf` (See [the manpage](https://manpages.ubuntu.com/manpages/bionic/man5/limits.conf.5.html) for details)
+No matter whether you use a lowlatency kernel or a PREEMPT_RT-patched kernel (or even a standard
+kernel) - in order to use FIFO-scheduling with user privileges (what the driver will do) you'll have to change
+the user's limits by changing `/etc/security/limits.conf` (See [the manpage](https://manpages.ubuntu.com/manpages/focal/man5/limits.conf.5.html) for details)
We recommend to setup a group for real-time users instead of writing a fixed username into the config
file:
@@ -213,31 +240,26 @@ $ awk -F\' '/menuentry |submenu / {print $1 $2}' /boot/grub/grub.cfg
menuentry Ubuntu
submenu Advanced options for Ubuntu
- menuentry Ubuntu, with Linux 4.15.0-62-generic
- menuentry Ubuntu, with Linux 4.15.0-62-generic (recovery mode)
- menuentry Ubuntu, with Linux 4.15.0-60-generic
- menuentry Ubuntu, with Linux 4.15.0-60-generic (recovery mode)
- menuentry Ubuntu, with Linux 4.15.0-58-generic
- menuentry Ubuntu, with Linux 4.15.0-58-generic (recovery mode)
- menuentry Ubuntu, with Linux 4.14.139-rt66
- menuentry Ubuntu, with Linux 4.14.139-rt66 (recovery mode)
-menuentry Memory test (memtest86+)
-menuentry Memory test (memtest86+, serial console 115200)
-menuentry Windows 7 (on /dev/sdc2)
-menuentry Windows 7 (on /dev/sdc3)
+ menuentry Ubuntu, with Linux 5.15.86-rt56
+ menuentry Ubuntu, with Linux 5.15.86-rt56 (recovery mode)
+ menuentry Ubuntu, with Linux 5.15.0-58-lowlatency
+ menuentry Ubuntu, with Linux 5.15.0-58-lowlatency (recovery mode)
+ menuentry Ubuntu, with Linux 5.15.0-58-generic
+ menuentry Ubuntu, with Linux 5.15.0-58-generic (recovery mode)
+menuentry Ubuntu
```
-From the output above, we'll need to generate a string with the pattern `"submenu_name>entry_name"`. In our case this would be
+From the output above, we'll need to generate a string with the pattern `"submenu_name>entry_name"`. In our case (for booting the PREEMPT_RT kernel) this would be
```
-"Advanced options for Ubuntu>Ubuntu, with Linux 4.14.139-rt66"
+"Advanced options for Ubuntu>Ubuntu, with Linux 5.15.86-rt56"
```
**The double quotes and no spaces around the `>` are important!**
With this, we can setup the default grub entry and then update the grub menu entries. Don't forget this last step!
```bash
-$ sudo sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 4.14.139-rt66"/' /etc/default/grub
+$ sudo sed -i 's/^GRUB_DEFAULT=.*/GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu, with Linux 5.15.86-rt56"/' /etc/default/grub
$ sudo update-grub
```
@@ -245,14 +267,6 @@ $ sudo update-grub
After having performed the above mentioned steps, reboot the PC. It should boot into the correct
kernel automatically.
-## Check for preemption capabilities
-Make sure that the kernel does indeed support real-time scheduling:
-
-```bash
-$ uname -v | cut -d" " -f1-4
-#1 SMP PREEMPT RT
-```
-
## Optional: Disable CPU speed scaling
Many modern CPUs support changing their clock frequency dynamically depending on the currently
requested computation resources. In some cases this can lead to small interruptions in execution.
diff --git a/ur_robot_driver/doc/real_time_benchmarking.md b/ur_robot_driver/doc/real_time_benchmarking.md
new file mode 100644
index 000000000..5106de63f
--- /dev/null
+++ b/ur_robot_driver/doc/real_time_benchmarking.md
@@ -0,0 +1,672 @@
+# How does the kernel and scheduling parameters affect the driver's performance?
+## System description
+In order to understand the different test scenarios it is important to understand the control flow
+and dependencies inside the driver's communication. For this see the following drawing:
+
+![control_flow](resources/control_flow.svg)
+
+Let's first have a look on the robot side. In the main thread we have the RTDE sender that sends
+real-time data from the robot in each cycle. Additionally, the ReverseInterface socket reads
+commands sent from an external source in each cycle. There it has a timeout of 2 milliseconds. If
+no data can be read, a `keepalive` counter is decreased by `1`. If the `keepalive` counter gets
+`0`, the connection is considered broken and the program stops all communication, stops the robot
+and shuts down (leaves the program node). By default the `keepalive_counter` is set to `1` in the
+ROS driver, meaning communication (and therefore the program) stops if no data could be received for
+the time since the last `read` call plus two milliseconds.
+
+On ROS side we have a producer thread that reads data from RTDE (which is a blocking operation,
+hence the separate thread). The main thread reads the data from the producer, generates control
+commands by updating the controller and finally sends back data to the ReverseInterface socket.
+Reading from the producer can be either done blocking (meaning to wait until there is new data
+available) or non-blocking in which case the controller update is being calculated on old data.
+
+From that structure we can see that it is mandatory to send motion commands to the robot in a very
+reliable and consistent frequency. The upper bound between two consecutive send operations would be
+the cycle time plus the 2 ms timeout. In case of an e-Series robot that would boil down to 4 ms
+(That being an upper bound that would probably already cause problems).
+
+The intention of the blocking read is to let the robot dictate the pace to make sure we always work
+on recent data.
+
+There are other threads involved in the driver and also in communication between the robot and the
+driver, but they don't directly participate in the actual control structure, hence they are left out
+here.
+
+In order to get things running smoothly we recommend using a real-time kernel with FIFO scheduling
+for the main thread and the producer thread.
+
+## Test description
+As a test system we used a shuttle PC with an Intel(R) Core(TM) i5-8500 CPU with 6 virtual cores. A
+direct network connection between the shuttle and the UR controller box was used to keep
+disturbances from network traffic to a minimum. We did not deactivate the CPU's frequency scaling,
+as this is probably not done on a default setup, as well.
+
+Each test was performed for 30 minutes, the period $t_n$ of each control cycle is recorded and saved,
+resulting in $N=3600$ samples. From this the median $\tilde{t}$, mean $\bar{t}$, minimum and maximum
+values are calculated, as well as a jitter and RMS error score.
+
+The jitter is calculated as
+
+$$j=\frac{\sum_{n=2}^N \left|t_n - t_{n-1}\right|}{N-1}$$
+
+and the RMS score is calculated as
+
+$$e_{rms}=\sqrt{\frac{1}{N} \sum_{n=1}^{N}\left(t_n - \bar{t} \right)^2}$$
+
+There are a number of parameters we can change throughout the tests:
+
+- stress / no stress on the system
+
+ *On a stressed system chances are higher that the CPU will be busy doing other stuff and therefore
+ delaying execution.*
+
+- FIFO scheduling (with high priority) vs. standard scheduling
+
+ *With FIFO scheduling threads with a high priority should be handled first if there are multiple
+ threads with work to do. In the tests we used the highest priority possible.*
+
+- CPU core affinity
+
+ *With setting a CPU affinity to a specific core, a thread will not be moved between different CPU
+ cores, which could introduce further delays.*
+
+- Blocking vs. non-blocking read
+
+ *As explained above, a blocking read might make the control thread wait longer than the actual
+ cycle time.*
+
+
+## Test results
+
+For our tests we restrict the parameter space to look at ten different combinations for each
+kernel:
+
+1. no stress, FIFO scheduling, CPU core affinity (to cores 1 and 3), blocking read
+1. no stress, FIFO scheduling, CPU core affinity (to cores 1 and 3), non-blocking read
+1. no stress, standard scheduling, no CPU core affinity, blocking read
+1. no stress, standard scheduling, no CPU core affinity, non-blocking read
+1. stress, FIFO scheduling, no CPU core affinity, blocking read
+1. stress, FIFO scheduling, no CPU core affinity, non-blocking read
+1. stress, FIFO scheduling, CPU core affinity (to cores 1 and 3), blocking read
+1. stress, FIFO scheduling, CPU core affinity (to cores 1 and 3), non-blocking read
+1. stress, standard scheduling, no CPU core affinity, blocking read
+1. stress, standard scheduling, no CPU core affinity, non-blocking read
+
+Below table lists the resulting data for each configuration. At the end of the document there are
+plots for each time configuration showing a more detailed picture.
+
+
+
+
ID
+
Stress
+
Scheduling/core
+
Blocking producer
+
Kernel
+
Cycle time [ms]
+
Jitter
+
$e_{rms}$
+
+
+
+
+
main producer
+
blocking
+
+
Median Min Max
+
+
+
+
+
+
1
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
PREEMPT_RT
+
2.0 1.19 2.78
+
0.08
+
0.06
+
+
+
2
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
PREEMPT_RT
+
2.02 2.0 2.45
+
0.03
+
0.02
+
+
+
3
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
block
+
PREEMPT_RT
+
2.0 0.01 13.87
+
0.08
+
0.06
+
+
+
4
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
PREEMPT_RT
+
2.06 2.0 16.36
+
0.03
+
0.08
+
+
+
5
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
PREEMPT_RT
+
2.0 0.01 6.04
+
0.03
+
0.03
+
+
+
6
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
PREEMPT_RT
+
2.0 2.0 2.35
+
0.0
+
0.0
+
+
+
7
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
block
+
PREEMPT_RT
+
2.0 0.38 3.63
+
0.04
+
0.04
+
+
+
8
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
non_block
+
PREEMPT_RT
+
2.0 2.0 2.36
+
0.0
+
0.0
+
+
+
9
+
stress
+
+ NONE/none
+ NONE/none
+
+
block
+
PREEMPT_RT
+
2.0 0.0 14.07
+
0.05
+
0.09
+
+
+
10
+
stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
PREEMPT_RT
+
2.06 2.0 4.29
+
0.01
+
0.02
+
+
+
11
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
lowlatency
+
2.0 0.01 3.21
+
0.11
+
0.07
+
+
+
12
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
lowlatency
+
2.02 2.0 2.27
+
0.03
+
0.03
+
+
+
13
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
block
+
lowlatency
+
2.0 0.01 46.23
+
0.08
+
0.16
+
+
+
14
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
lowlatency
+
2.08 2.0 44.54
+
0.03
+
0.08
+
+
+
15
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
lowlatency
+
2.0 0.01 11.01
+
0.03
+
0.03
+
+
+
16
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
lowlatency
+
2.0 2.0 2.28
+
0.0
+
0.0
+
+
+
17
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
block
+
lowlatency
+
2.0 1.62 2.4
+
0.03
+
0.02
+
+
+
18
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
non_block
+
lowlatency
+
2.0 2.0 2.29
+
0.0
+
0.0
+
+
+
19
+
stress
+
+ NONE/none
+ NONE/none
+
+
block
+
lowlatency
+
2.0 0.0 7.51
+
0.03
+
0.04
+
+
+
20
+
stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
lowlatency
+
2.05 2.0 10.44
+
0.01
+
0.03
+
+
+
21
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
standard
+
2.0 0.01 237.63
+
0.11
+
0.5
+
+
+
22
+
no_stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
standard
+
2.03 2.0 237.18
+
0.04
+
0.43
+
+
+
23
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
block
+
standard
+
2.0 0.01 14.04
+
0.08
+
0.07
+
+
+
24
+
no_stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
standard
+
2.09 2.01 11.71
+
0.03
+
0.03
+
+
+
25
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
block
+
standard
+
2.0 0.01 226.98
+
0.03
+
0.53
+
+
+
26
+
stress
+
+ FIFO/1
+ FIFO/3
+
+
non_block
+
standard
+
2.0 2.0 224.22
+
0.0
+
0.23
+
+
+
27
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
block
+
standard
+
2.0 0.01 223.82
+
0.03
+
0.56
+
+
+
28
+
stress
+
+ FIFO/none
+ FIFO/none
+
+
non_block
+
standard
+
2.0 2.0 225.51
+
0.0
+
0.33
+
+
+
29
+
stress
+
+ NONE/none
+ NONE/none
+
+
block
+
standard
+
2.0 0.0 117.19
+
0.05
+
0.41
+
+
+
30
+
stress
+
+ NONE/none
+ NONE/none
+
+
non_block
+
standard
+
2.05 2.0 40.06
+
0.01
+
0.16
+
+
+
+
+## Conclusion
+The plot below shows scatter plots of all the different combinations grouped by the kernel used.
+
+![box_plot](resources/plots/box_plot.png)
+
+The main conclusions drawn from this are:
+
+- Using a non-blocking read helps keeping cycle times closer to what they should be and has the
+ greatest impact on the jitter. (All odd configurations use a blocking read, while all even numbers
+ use a non-blocking read.)
+
+- Using a standard kernel without further measures introduces a lot of cycles with a longer cycle
+ time than the expected 2 ms. Using FIFO scheduling and CPU core affinity improves the situation
+ significantly, but there is still too little reliability in short cycle times.
+
+- Using a lowlatency kernel significantly reduces extremely long cycle times, a PREEMPT_RT reduces
+ them even further. However, using a real-time kernel alone also does not bring the desired
+ guaranteed cycle time of 2 ms.
+
+- Using FIFO scheduling (at least combined with a high thread priority) has the biggest impact on
+ keeping cycle times in the desired range on a stressed system. It seems to have a clear and strong
+ impact on all evaluated kernels.
+
+- At a first glance it seems odd that the non-stressed system on the lowlatency kernel shows higher
+ cycle times than the stressed system with the same configuration. We think that this is due to the
+ CPU frequency scaling being without any effect when the system is on full load already, anyway.
+
+### Operation recommendations
+In order to get the most stable experience we recommend using a PREEMPT_RT or at least lowlatency
+kernel combined with FIFO scheduling enabled to run the driver on. Since the lowlatency kernel is directly available using the standard
+Ubuntu repository, that's probably the easiest to setup.
+
+In order to activate FIFO scheduling for the driver, the user running the driver must be given the
+privileges to do so. For this, we recommend creating a separate usergroup and allow members of this
+group to setup the scheduling parameters. See the [real-time setup guide](https://github.com/UniversalRobots/Universal_Robots_ROS_Driver/blob/master/ur_robot_driver/doc/real_time.md) for details on this.
+
+## Individual Plots
+This section shows all cycle times in a time series and the cycle time histogram.
+
+
+
+ ### Configuration #1
+ ![no_stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series](resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png)
+ ![no_stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram](resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #2
+ ![no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series](resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png)
+ ![no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram](resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #3
+ ![no_stress_none_none_none_none_block_PREEMPT_RT_time_series](resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_time_series.png)
+ ![no_stress_none_none_none_none_block_PREEMPT_RT_histogram](resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #4
+ ![no_stress_none_none_none_none_non_block_PREEMPT_RT_time_series](resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png)
+ ![no_stress_none_none_none_none_non_block_PREEMPT_RT_histogram](resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #5
+ ![stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series](resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png)
+ ![stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram](resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #6
+ ![stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series](resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png)
+ ![stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram](resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #7
+ ![stress_fifo_none_fifo_none_block_PREEMPT_RT_time_series](resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_time_series.png)
+ ![stress_fifo_none_fifo_none_block_PREEMPT_RT_histogram](resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #8
+ ![stress_fifo_none_fifo_none_non_block_PREEMPT_RT_time_series](resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_time_series.png)
+ ![stress_fifo_none_fifo_none_non_block_PREEMPT_RT_histogram](resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #9
+ ![stress_none_none_none_none_block_PREEMPT_RT_time_series](resources/plots/stress_none_none_none_none_block_PREEMPT_RT_time_series.png)
+ ![stress_none_none_none_none_block_PREEMPT_RT_histogram](resources/plots/stress_none_none_none_none_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #10
+ ![stress_none_none_none_none_non_block_PREEMPT_RT_time_series](resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png)
+ ![stress_none_none_none_none_non_block_PREEMPT_RT_histogram](resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png)
+
+ ### Configuration #11
+ ![no_stress_fifo_1_fifo_3_block_lowlatency_time_series](resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_time_series.png)
+ ![no_stress_fifo_1_fifo_3_block_lowlatency_histogram](resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_histogram.png)
+
+ ### Configuration #12
+ ![no_stress_fifo_1_fifo_3_non_block_lowlatency_time_series](resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png)
+ ![no_stress_fifo_1_fifo_3_non_block_lowlatency_histogram](resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png)
+
+ ### Configuration #13
+ ![no_stress_none_none_none_none_block_lowlatency_time_series](resources/plots/no_stress_none_none_none_none_block_lowlatency_time_series.png)
+ ![no_stress_none_none_none_none_block_lowlatency_histogram](resources/plots/no_stress_none_none_none_none_block_lowlatency_histogram.png)
+
+ ### Configuration #14
+ ![no_stress_none_none_none_none_non_block_lowlatency_time_series](resources/plots/no_stress_none_none_none_none_non_block_lowlatency_time_series.png)
+ ![no_stress_none_none_none_none_non_block_lowlatency_histogram](resources/plots/no_stress_none_none_none_none_non_block_lowlatency_histogram.png)
+
+ ### Configuration #15
+ ![stress_fifo_1_fifo_3_block_lowlatency_time_series](resources/plots/stress_fifo_1_fifo_3_block_lowlatency_time_series.png)
+ ![stress_fifo_1_fifo_3_block_lowlatency_histogram](resources/plots/stress_fifo_1_fifo_3_block_lowlatency_histogram.png)
+
+ ### Configuration #16
+ ![stress_fifo_1_fifo_3_non_block_lowlatency_time_series](resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png)
+ ![stress_fifo_1_fifo_3_non_block_lowlatency_histogram](resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png)
+
+ ### Configuration #17
+ ![stress_fifo_none_fifo_none_block_lowlatency_time_series](resources/plots/stress_fifo_none_fifo_none_block_lowlatency_time_series.png)
+ ![stress_fifo_none_fifo_none_block_lowlatency_histogram](resources/plots/stress_fifo_none_fifo_none_block_lowlatency_histogram.png)
+
+ ### Configuration #18
+ ![stress_fifo_none_fifo_none_non_block_lowlatency_time_series](resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_time_series.png)
+ ![stress_fifo_none_fifo_none_non_block_lowlatency_histogram](resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_histogram.png)
+
+ ### Configuration #19
+ ![stress_none_none_none_none_block_lowlatency_time_series](resources/plots/stress_none_none_none_none_block_lowlatency_time_series.png)
+ ![stress_none_none_none_none_block_lowlatency_histogram](resources/plots/stress_none_none_none_none_block_lowlatency_histogram.png)
+
+ ### Configuration #20
+ ![stress_none_none_none_none_non_block_lowlatency_time_series](resources/plots/stress_none_none_none_none_non_block_lowlatency_time_series.png)
+ ![stress_none_none_none_none_non_block_lowlatency_histogram](resources/plots/stress_none_none_none_none_non_block_lowlatency_histogram.png)
+
+ ### Configuration #21
+ ![no_stress_fifo_1_fifo_3_block_standard_time_series](resources/plots/no_stress_fifo_1_fifo_3_block_standard_time_series.png)
+ ![no_stress_fifo_1_fifo_3_block_standard_histogram](resources/plots/no_stress_fifo_1_fifo_3_block_standard_histogram.png)
+
+ ### Configuration #22
+ ![no_stress_fifo_1_fifo_3_non_block_standard_time_series](resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_time_series.png)
+ ![no_stress_fifo_1_fifo_3_non_block_standard_histogram](resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_histogram.png)
+
+ ### Configuration #23
+ ![no_stress_none_none_none_none_block_standard_time_series](resources/plots/no_stress_none_none_none_none_block_standard_time_series.png)
+ ![no_stress_none_none_none_none_block_standard_histogram](resources/plots/no_stress_none_none_none_none_block_standard_histogram.png)
+
+ ### Configuration #24
+ ![no_stress_none_none_none_none_non_block_standard_time_series](resources/plots/no_stress_none_none_none_none_non_block_standard_time_series.png)
+ ![no_stress_none_none_none_none_non_block_standard_histogram](resources/plots/no_stress_none_none_none_none_non_block_standard_histogram.png)
+
+ ### Configuration #25
+ ![stress_fifo_1_fifo_3_block_standard_time_series](resources/plots/stress_fifo_1_fifo_3_block_standard_time_series.png)
+ ![stress_fifo_1_fifo_3_block_standard_histogram](resources/plots/stress_fifo_1_fifo_3_block_standard_histogram.png)
+
+ ### Configuration #26
+ ![stress_fifo_1_fifo_3_non_block_standard_time_series](resources/plots/stress_fifo_1_fifo_3_non_block_standard_time_series.png)
+ ![stress_fifo_1_fifo_3_non_block_standard_histogram](resources/plots/stress_fifo_1_fifo_3_non_block_standard_histogram.png)
+
+ ### Configuration #27
+ ![stress_fifo_none_fifo_none_block_standard_time_series](resources/plots/stress_fifo_none_fifo_none_block_standard_time_series.png)
+ ![stress_fifo_none_fifo_none_block_standard_histogram](resources/plots/stress_fifo_none_fifo_none_block_standard_histogram.png)
+
+ ### Configuration #28
+ ![stress_fifo_none_fifo_none_non_block_standard_time_series](resources/plots/stress_fifo_none_fifo_none_non_block_standard_time_series.png)
+ ![stress_fifo_none_fifo_none_non_block_standard_histogram](resources/plots/stress_fifo_none_fifo_none_non_block_standard_histogram.png)
+
+ ### Configuration #29
+ ![stress_none_none_none_none_block_standard_time_series](resources/plots/stress_none_none_none_none_block_standard_time_series.png)
+ ![stress_none_none_none_none_block_standard_histogram](resources/plots/stress_none_none_none_none_block_standard_histogram.png)
+
+ ### Configuration #30
+ ![stress_none_none_none_none_non_block_standard_time_series](resources/plots/stress_none_none_none_none_non_block_standard_time_series.png)
+ ![stress_none_none_none_none_non_block_standard_histogram](resources/plots/stress_none_none_none_none_non_block_standard_histogram.png)
diff --git a/ur_robot_driver/doc/resources/control_flow.svg b/ur_robot_driver/doc/resources/control_flow.svg
new file mode 100644
index 000000000..b1b4b1e3d
--- /dev/null
+++ b/ur_robot_driver/doc/resources/control_flow.svg
@@ -0,0 +1,198 @@
+
diff --git a/ur_robot_driver/doc/resources/plots/box_plot.png b/ur_robot_driver/doc/resources/plots/box_plot.png
new file mode 100644
index 000000000..a4fdc2fad
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/box_plot.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..0911b183d
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..1bba84b81
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_histogram.png
new file mode 100644
index 000000000..23df1a258
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_time_series.png
new file mode 100644
index 000000000..c72539818
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_histogram.png
new file mode 100644
index 000000000..598fca1f7
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_time_series.png
new file mode 100644
index 000000000..fdebd197b
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..6aabcbd0a
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..e8f25552d
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png
new file mode 100644
index 000000000..c35948d8f
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png
new file mode 100644
index 000000000..06372861d
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_histogram.png
new file mode 100644
index 000000000..fad95525a
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_time_series.png
new file mode 100644
index 000000000..2dd5b9805
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_fifo_1_fifo_3_non_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..259eb728b
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..dd9a70216
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_histogram.png
new file mode 100644
index 000000000..c2a673abf
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_time_series.png
new file mode 100644
index 000000000..8c4de9659
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_histogram.png
new file mode 100644
index 000000000..b69e994b8
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_time_series.png
new file mode 100644
index 000000000..9a321f809
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..3b083021f
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..4860b960b
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_histogram.png
new file mode 100644
index 000000000..5689929b5
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_time_series.png
new file mode 100644
index 000000000..50ef9158c
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_histogram.png
new file mode 100644
index 000000000..1dc3c9255
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_time_series.png
new file mode 100644
index 000000000..7e4743377
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/no_stress_none_none_none_none_non_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..e6478878e
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..ecef9a918
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_histogram.png
new file mode 100644
index 000000000..7f2c51c69
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_time_series.png
new file mode 100644
index 000000000..9a700cb43
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_histogram.png
new file mode 100644
index 000000000..922fd637a
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_time_series.png
new file mode 100644
index 000000000..c5dcaf263
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..99b939b88
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..325c0df60
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png
new file mode 100644
index 000000000..e3096ad6b
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png
new file mode 100644
index 000000000..06b8625ed
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_histogram.png
new file mode 100644
index 000000000..27c07489e
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_time_series.png
new file mode 100644
index 000000000..de4449344
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_1_fifo_3_non_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..27f56e7b9
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..e0d062059
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_histogram.png
new file mode 100644
index 000000000..e7fc8f1e7
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_time_series.png
new file mode 100644
index 000000000..c66764bdd
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_histogram.png
new file mode 100644
index 000000000..accdfe396
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_time_series.png
new file mode 100644
index 000000000..8ef5fc629
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..dc8817b9c
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..dd5cade1e
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_histogram.png
new file mode 100644
index 000000000..074cf2414
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_time_series.png
new file mode 100644
index 000000000..d06de2124
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_histogram.png
new file mode 100644
index 000000000..b37bbd12a
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_time_series.png
new file mode 100644
index 000000000..bbac9f0dc
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_fifo_none_fifo_none_non_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..fbbc6bca5
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..ab59d62d2
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_histogram.png
new file mode 100644
index 000000000..4fe97e4c4
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_time_series.png
new file mode 100644
index 000000000..4a4fa3054
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_histogram.png
new file mode 100644
index 000000000..bf47b99e3
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_time_series.png
new file mode 100644
index 000000000..fbc2ffe9d
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_block_standard_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png
new file mode 100644
index 000000000..8f05af1f7
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png
new file mode 100644
index 000000000..672f7c965
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_PREEMPT_RT_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_histogram.png
new file mode 100644
index 000000000..b638483f2
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_time_series.png
new file mode 100644
index 000000000..e4ab0fdf0
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_lowlatency_time_series.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_histogram.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_histogram.png
new file mode 100644
index 000000000..a80ac7c83
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_histogram.png differ
diff --git a/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_time_series.png b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_time_series.png
new file mode 100644
index 000000000..06d948c1b
Binary files /dev/null and b/ur_robot_driver/doc/resources/plots/stress_none_none_none_none_non_block_standard_time_series.png differ
diff --git a/ur_robot_driver/src/hardware_interface_node.cpp b/ur_robot_driver/src/hardware_interface_node.cpp
index 13bc08865..386e8d29b 100644
--- a/ur_robot_driver/src/hardware_interface_node.cpp
+++ b/ur_robot_driver/src/hardware_interface_node.cpp
@@ -45,6 +45,57 @@ void signalHandler(int signum)
exit(signum);
}
+bool setFiFoScheduling(pthread_t& thread, const int priority)
+{
+ struct sched_param params;
+ params.sched_priority = priority;
+ int ret = pthread_setschedparam(thread, SCHED_FIFO, ¶ms);
+ if (ret != 0)
+ {
+ switch (ret)
+ {
+ case EPERM:
+ {
+ ROS_ERROR_STREAM("Your system/user seems not to be setup for FIFO scheduling. We recommend using a lowlatency "
+ "kernel with FIFO scheduling. See "
+ "https://github.com/UniversalRobots/Universal_Robots_ROS_Driver/blob/master/ur_robot_driver/"
+ "doc/real_time.md for details.");
+ break;
+ }
+ default:
+
+ {
+ ROS_ERROR_STREAM("Unsuccessful in setting thread to FIFO scheduling with priority " << priority << ". "
+ << strerror(ret));
+ }
+ }
+ }
+ // Now verify the change in thread priority
+ int policy = 0;
+ ret = pthread_getschedparam(thread, &policy, ¶ms);
+ if (ret != 0)
+ {
+ ROS_ERROR("Couldn't retrieve scheduling parameters");
+ return false;
+ }
+
+ // Check the correct policy was applied
+ if (policy != SCHED_FIFO)
+ {
+ ROS_ERROR("Scheduling is NOT SCHED_FIFO!");
+ return false;
+ }
+ else
+ {
+ ROS_INFO_STREAM("SCHED_FIFO OK, priority " << params.sched_priority);
+ if (params.sched_priority != priority)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
int main(int argc, char** argv)
{
// Set up ROS.
@@ -60,57 +111,10 @@ int main(int argc, char** argv)
ur_driver::registerUrclLogHandler();
- std::ifstream realtime_file("/sys/kernel/realtime", std::ios::in);
- bool has_realtime = false;
- if (realtime_file.is_open())
- {
- realtime_file >> has_realtime;
- }
- if (has_realtime)
- {
- const int max_thread_priority = sched_get_priority_max(SCHED_FIFO);
- if (max_thread_priority != -1)
- {
- // We'll operate on the currently running thread.
- pthread_t this_thread = pthread_self();
-
- // struct sched_param is used to store the scheduling priority
- struct sched_param params;
-
- // We'll set the priority to the maximum.
- params.sched_priority = max_thread_priority;
-
- int ret = pthread_setschedparam(this_thread, SCHED_FIFO, ¶ms);
- if (ret != 0)
- {
- ROS_ERROR_STREAM("Unsuccessful in setting main thread realtime priority. Error code: " << ret);
- }
- // Now verify the change in thread priority
- int policy = 0;
- ret = pthread_getschedparam(this_thread, &policy, ¶ms);
- if (ret != 0)
- {
- std::cout << "Couldn't retrieve real-time scheduling paramers" << std::endl;
- }
-
- // Check the correct policy was applied
- if (policy != SCHED_FIFO)
- {
- ROS_ERROR("Main thread: Scheduling is NOT SCHED_FIFO!");
- }
- else
- {
- ROS_INFO("Main thread: SCHED_FIFO OK");
- }
-
- // Print thread scheduling priority
- ROS_INFO_STREAM("Main thread priority is " << params.sched_priority);
- }
- else
- {
- ROS_ERROR("Could not get maximum thread priority for main thread");
- }
- }
+ pthread_t this_thread = pthread_self();
+ const int max_thread_priority = sched_get_priority_max(SCHED_FIFO);
+ bool is_fifo = setFiFoScheduling(this_thread, max_thread_priority);
+ ROS_INFO_STREAM("The driver's control thread uses " << (is_fifo ? "" : "NO") << " FIFO scheduling");
// Set up timers
ros::Time timestamp;