Tutorial#
This tutorial walks through the full workflow with the cie_sample_application package: launch a sample
application under CallbackIsolatedExecutor, generate a thread configuration template, apply scheduling
parameters, and verify the result.
It assumes you have already installed the packages and
granted CAP_SYS_NICE to
the thread configurator. The sample application is available from apt:
The configurator is run interactively in a terminal below, which corresponds to the setcap option. If
you set it up as a systemd service instead, start the service in place of the Terminal 1 command in
Step 4.
Sample Application#
SampleNode (node name sample_node, namespace /sample_space/sample_subspace) has three
MutuallyExclusive CallbackGroups, each getting its own OS thread under CallbackIsolatedExecutor:
- a 3000 ms timer (
timer_callback, publishes ontopic_out) - a 1333 ms timer (
timer_callback2, publishes ontopic_out2) - a subscription on
topic_in
It also spawns a non-ROS worker thread named sample_non_ros_thread via
spawn_non_ros2_thread (see Non-ROS Threads).
Step 1: Launch the Application#
This starts component_container_callback_isolated and loads SampleNode into it. You should see
interleaved log messages from the two timer callbacks, each printing its own thread ID (tid), plus
periodic messages from the non-ROS worker thread. Stop it with Ctrl+C for now.
Step 2: Generate a Template#
Start the prerun node before launching the application:
# Terminal 1: prerun node
ros2 launch cie_thread_configurator thread_configurator.launch.xml prerun:=true
# Terminal 2: the sample application
ros2 launch cie_sample_application sample_node.launch.xml
Wait until the prerun log output settles (all CallbackGroups discovered), then press Ctrl+C in
Terminal 1. A template.yaml is created in the current directory. Its CallbackGroup IDs are generated
automatically and look like this (the default group's id, listing every parameter service, is long and
abbreviated here):
hardware_info:
cpu_family: 6
cpu_max_mhz: 2101.0000
cpu_min_mhz: 800.0000
frequency_boost: enabled
model: 85
model_name: Intel(R) Xeon(R) Silver 4216 CPU @ 2.10GHz
threads_per_core: 1
callback_groups:
# default group: parameter services + /parameter_events (full id generated by prerun)
- id: /sample_space/sample_subspace/sample_node@Service(.../describe_parameters)@Service(...)@Subscription(/parameter_events)
affinity: ~
policy: SCHED_OTHER
nice: 0
- id: /sample_space/sample_subspace/sample_node@Subscription(/sample_space/sample_subspace/topic_in)
affinity: ~
policy: SCHED_OTHER
nice: 0
- id: /sample_space/sample_subspace/sample_node@Timer(1333000000)
affinity: ~
policy: SCHED_OTHER
nice: 0
- id: /sample_space/sample_subspace/sample_node@Timer(3000000000)
affinity: ~
policy: SCHED_OTHER
nice: 0
non_ros_threads:
- id: sample_non_ros_thread
affinity: ~
policy: SCHED_OTHER
nice: 0
Then stop the sample application (Ctrl+C).
Tip
Always use the IDs from your own generated template.yaml. The exact strings depend on the node's
namespace, topic names, and parameter services, so do not hand-write them from this example.
Step 3: Edit the Configuration#
Copy and edit the template to assign real-time priorities. Here we give the faster (1333 ms) timer the higher priority, pin the two timers to separate cores, and leave everything else on the default scheduler:
callback_groups:
- id: /sample_space/sample_subspace/sample_node@Timer(1333000000)
policy: SCHED_FIFO
priority: 90
affinity:
- 0
- id: /sample_space/sample_subspace/sample_node@Timer(3000000000)
policy: SCHED_FIFO
priority: 80
affinity:
- 1
non_ros_threads:
- id: sample_non_ros_thread
policy: SCHED_OTHER
nice: 0
CallbackGroups you do not list keep the default CFS scheduling.
Step 4: Launch with the Configuration#
Start the configurator before the application:
# Terminal 1: configurator
ros2 launch cie_thread_configurator thread_configurator.launch.xml config_file:=sample_config.yaml
# Terminal 2: the sample application
ros2 launch cie_sample_application sample_node.launch.xml
The configurator logs each CallbackGroup as it applies the configuration. It keeps running afterward and re-applies the configuration automatically if the application restarts.
Step 5: Verify#
While the application is running, inspect the thread scheduling with ps:
PID TID CLS RTPRIO PSR COMMAND
429255 429255 TS - 9 component_conta
429255 429257 TS - 8 component_conta
429255 429268 FF 90 0 component_conta <-- 1333 ms timer
429255 429269 FF 80 1 component_conta <-- 3000 ms timer
429255 429270 TS - 15 component_conta <-- other groups (CFS)
CLSshows the scheduling class:FF=SCHED_FIFO,TS=SCHED_OTHER(CFS).RTPRIOshows the real-time priority;PSRshows the CPU the thread last ran on.- Threads without
RTPRIOare unconfigured groups and internal threads.
You can also inspect individual threads:
See the YAML Specification for all available configuration options.