|
| 1 | +# cbg-executor_ping-pong_cpp |
| 2 | + |
| 3 | +This package provides a small example for the use of the Callback-group-level Executor concept. |
| 4 | + |
| 5 | +The Callback-group-level Executor leverages the callback-group concept in rclcpp by introducing real-time profiles such as RT-CRITICAL and BEST-EFFORT in the callback-group API (i.e. [rclcpp/callback_group.hpp](https://github.com/microROS/rclcpp/blob/master/rclcpp/include/rclcpp/callback_group.hpp)). Each callback requiring specific real-time guarantees, when created, may therefore be associated with a dedicated callback group. With this in place, the Executor class and depending classes (e.g., for memory allocation) were enhanced to operate at a finer, callback-group-level granularity. |
| 6 | + |
| 7 | +This allows a single node to have callbacks with different real-time profiles assigned to different Executor instances – within one process. Thus, an Executor instance can be dedicated to one or few specific callback groups and the Executor’s thread (or threads) can be prioritized according to the real-time requirements of these groups. For example, all time-critical callbacks may be handled by an "RT-CRITICAL" Executor instance running at the highest scheduler priority. |
| 8 | + |
| 9 | +As a proof of concept, we implemented a small test bench in the present package *cbg-executor_ping-pong_cpp*. The test bench comprises a Ping node and a Pong node which exchange real-time and best-effort messages simultaneously with each other. Each class of messages is handled with a dedicated Executor, as illustrated in the following figure. |
| 10 | + |
| 11 | + |
| 12 | + |
| 13 | +The Ping node can be configured to send messages at a configured rate. The Pong node takes these ping messages and replies each of them. Before sending the reply, it can be configured to burn cycles (thereby varying the processor load) to simulate some message processing. We provide bash scripts to test intra-process and inter-process communication scenarios, wherein the nodes are co-located either in one process or two processes, respectively. These scripts also vary the message rates and processor loads. After each run, the Ping node outputs the measured throughput of real-time and best effort messages. |
| 14 | + |
| 15 | + |
| 16 | +## Running the test bench |
| 17 | + |
| 18 | +After building the test bench with [colcon](https://github.com/ros2/ros2/wiki/Colcon-Tutorial), the Ping and Pong nodes may be either started in one process or in two processes. Please note that the test bench requires sudo privileges to be able to change the thread priorities using `pthread_setschedparam(..)`. Start the executable by |
| 19 | + |
| 20 | +``` |
| 21 | +ros2 run cbg-executor_ping-pong_cpp ping-pong args... |
| 22 | +``` |
| 23 | + |
| 24 | +where `args...` are five or six arguments as follows: |
| 25 | + |
| 26 | +``` |
| 27 | +[type] [rt_ping_period_us] [be_ping_period_us] [rt_busyloop_us] [be_busyloop_us] [cpu_id] |
| 28 | +
|
| 29 | +type: determines the nodes included in this process: |
| 30 | + i: ping node only |
| 31 | + o: pong node only |
| 32 | + io: ping node and pong node |
| 33 | +
|
| 34 | +rt_ping_period_us: microseconds between publishing of ping messages by real-time thread |
| 35 | + in ping node |
| 36 | +be_ping_period_us: microseconds between publishing of ping messages by best-effort |
| 37 | + thread in ping node |
| 38 | +rt_busyloop_us: microseconds of computation by real-time thread in pong node before |
| 39 | + answering with pong |
| 40 | +be_busyloop_us: microseconds of computation by best-effort thread in pong node before |
| 41 | + answering with pong |
| 42 | +cpu_id (optional): pins both, real-time thread and best-effort thread, to the given cpu |
| 43 | +``` |
| 44 | + |
| 45 | +When using type `i`, a second process with type `o` has to be started simultaneously. |
| 46 | + |
| 47 | +The shell run\* scripts in this folder run various experiments in sequence. For pertinent results, we propose to use the [PREEMPT_RT patch](https://wiki.linuxfoundation.org/realtime/start) for the Linux kernel. |
| 48 | + |
| 49 | + |
| 50 | +## Implementation Details |
| 51 | + |
| 52 | +The algorithms of the Ping node and of the Pong node are factored out into classes [_PingSubNode_](include/PingSubNode.hpp) and [_PongSubNode_](include/PongSubNode.hpp) - configurable with regard to the real-time profile and the topic prefix. Thus, the Ping node contains two instances of the _PingSubNode_ and the Pong node contains two instances of _PongSubNode_. (And the test bench could be easily extended to more than two ping-pong paths.) |
| 53 | + |
| 54 | +The PingSubNode contains a timer for sending the ping messages and a subscription for the corresponding pong messages. Also, it records the number of messages being sent and received and measures the roundtrip time. |
| 55 | + |
| 56 | +The PongSubNode contains a subscription for the ping messages and a publisher for the corresponding pong messages. On receiving a ping message, it calls the `PongSubNode::burn_cpu_cycles()` functions to simulate a given processing time before replying with a pong. |
| 57 | + |
| 58 | +The Ping and Pong nodes, the two executors, etc. are composed and configured in the `main(..)` function of [main.cpp](main.cpp). This function also starts and ends the experiment for a predefined duration and prints out the throughput and latency statistics. |
0 commit comments