Skip to content

Commit 9240ced

Browse files
committed
rclc executor with trigger condition - started
Signed-off-by: Staschulat Jan <jan.staschulat@de.bosch.com>
1 parent 75be606 commit 9240ced

1 file changed

Lines changed: 79 additions & 2 deletions

File tree

  • _docs/tutorials/core/programming_rcl_rclc

‎_docs/tutorials/core/programming_rcl_rclc/index.md‎

Lines changed: 79 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,90 @@ return 0;
420420
This completes the example. The source code can be found in [rclc-examples/example_executor_convenience.c](https://github.com/micro-ROS/rclc-examples/example_executor_convenience.c).
421421
422422
#### Example 2: Triggered rclc_executor
423+
Sesor fusion is the first step in robotic applications when multiple sensor are used to improve localization precision. These sensors can have different frequencies, for example, a high frequency IMU sensor and a low frequency laser scanner. One way is to trigger execution upon arrival of a laser scan and only then evaluate the most recent data from the aggregated IMU data.
423424
424-
rclc_example_trigger
425+
This example demonstrates the additional feature of the rclc executor to trigger the execution of callbacks based on the availability of input data.
426+
427+
We setup one executor with two publishers, one with 100ms and one with 1000ms period. Then we setup one executor for two subsciptions. Their callbacks shall both be executed if the message of the publisher with the lower frequency arrives.
428+
429+
You learn in this tutorial
430+
- how to write custom-defined trigger conditions
431+
- how to run multiple executors
432+
- how to setup communication objects only using rcl API
433+
434+
We start with the necessary includes for string and int messages as well as the rclc executor:
435+
```C
436+
#include <stdio.h>
437+
#include <unistd.h>
438+
#include <std_msgs/msg/string.h>
439+
#include <std_msgs/msg/int32.h>
440+
#include <rclc/executor.h>
441+
```
442+
Then, global variables are defined, which are initialized in main and also used in the callbacks:
443+
```C
444+
rcl_publisher_t my_pub;
445+
rcl_publisher_t my_int_pub;
446+
std_msgs__msg__String sub_msg;
447+
std_msgs__msg__Int32 pub_int_msg;
448+
int pub_int_value;
449+
std_msgs__msg__Int32 sub_int_msg;
450+
int pub_string_value;
451+
```
452+
For the custom-defined trigger conditions, the type `pub_trigger_object_t` and the type `sub_trigger_object_t` are defined.
453+
```C
454+
typedef struct
455+
{
456+
rcl_timer_t * timer1;
457+
rcl_timer_t * timer2;
458+
} pub_trigger_object_t;
459+
460+
typedef struct
461+
{
462+
rcl_subscription_t * sub1;
463+
rcl_subscription_t * sub2;
464+
} sub_trigger_object_t;
465+
```
466+
The executor for the publishers, shall publish when any of corresponding timers for the publishers is ready. That is the or-logic. You could also use the predefined `rclc_executor_trigger_any` trigger condition, but this example shows, how you can write your own trigger conditions.
467+
468+
In principle the condition gets a list of handles, the length of this list, and the pre-defined condition type, in this case we expect `pub_trigger_object_t`. First, the parameter `obj` is cased to this type (`comm_obj`). Then, each element of the handle list is checked for new data (or a timer is ready) by evaluating the field `handles[i].data_available` and its handle pointer is compared to the pointer of the communicatoin object. If at least one timer is ready, then the trigger condition returns true.
469+
```C
470+
bool pub_trigger(rclc_executor_handle_t * handles, unsigned int size, void * obj)
471+
{
472+
if (handles == NULL) {
473+
printf("Error in pub_trigger: 'handles' is a NULL pointer\n");
474+
return false;
475+
}
476+
if (obj == NULL) {
477+
printf("Error in pub_trigger: 'obj' is a NULL pointer\n");
478+
return false;
479+
}
480+
pub_trigger_object_t * comm_obj = (pub_trigger_object_t *) obj;
481+
bool timer1 = false;
482+
bool timer2 = false;
483+
//printf("pub_trigger ready set: ");
484+
for (unsigned int i = 0; i < size; i++) {
485+
if (handles[i].data_available == true) {
486+
void * handle_ptr = rclc_executor_handle_get_ptr(&handles[i]);
487+
if (handle_ptr == comm_obj->timer1) {
488+
timer1 = true;
489+
}
490+
if (handle_ptr == comm_obj->timer2) {
491+
timer2 = true;
492+
}
493+
}
494+
}
495+
if (timer1 || timer2) {
496+
return true;
497+
} else {
498+
return false;
499+
}
500+
}
501+
```
425502
426503
The source code can be found in [rclc-examples/example_executor_trigger.c](https://github.com/micro-ROS/rclc-examples/example_executor_trigger.c).
427504
428505
429-
#### Example 2: Sense-plan-act pipeline in mobile robotics
506+
#### Example 3: Sense-plan-act pipeline in mobile robotics
430507
431508
A common design paradigm in mobile robotics is a control loop, consisting of several phases: A sensing phase to aquire sensor data, a plan phase for localization and path planning and an actuation-phase to steer the mobile robot. Of course, more phases are possible, here these three phases shall serve as an example.
432509
Such a processing pipeline is shown in Figure 1.

0 commit comments

Comments
 (0)