1818#include <std_msgs/msg/string.h>
1919// #include <unistd.h> // for usleep
2020
21+ /* TODO
22+ - one timer for each publisher
23+ - finish after number of published /subscribed topics (command line argument and logic)
24+ - documentation
25+
26+
27+ Idea:
28+ - call spin_some() while (!testbench_finished() )
29+ - in timer increment # published topics
30+ - in subscription_callback count # received topics
31+ - testbench_finished() {
32+ bool finished_publish = true;
33+ bool finished_subscribed = true;
34+ if (num_pubs > 0) {
35+ for(unsigned int i=0; i< num_nodes && finished_publish;i++) {
36+ for(unsigned int p=0; p<nodes[n].num_pubs;p++){
37+ if (nodes[n].pubs[p].published_topics < num_topics) {
38+ finished_publish = false;
39+ break;
40+ }
41+ }
42+ }
43+
44+ if (num_subs > 0) {
45+ for(unsigned int i=0; i< num_nodes && finished_subscribed;i++) {
46+ for(unsigned int s=0; s<nodes[n].num_subs;s++){
47+ if (nodes[n].subs[s].received_topics < num_topics) {
48+ finished_publish = false;
49+ break;
50+ }
51+ }
52+ }
53+
54+
55+ vielleicht ist es besser, beim senden/empfangen direkt hochzuzählen
56+ wenn num < max => senden, sonst nicht mehr und Flag im Ergebnis-Vektor speichern
57+ nodes[i].subs[]
58+
59+ 1 globale variable - wird incrementiert, wenn ein teilnehmer fertig ist (fürs senden)
60+ publisher_finished++; => wenn max number of published topics erreicht wurde
61+ subscriber_finsihed++;
62+ dann ist der check ganz einfach:
63+
64+ // init
65+ unsigned int publisher_finished = 0;
66+ unsigned int subscriber_finished = 0;
67+
68+ // geht auch für den fall conf.num_pubs oder conf.num_subs==0
69+ int work_to_do() {}
70+ bool finished = false;
71+ if ((publisher_finished == conf.num_pubs) &&
72+ (subscriber_finished == conf.num_subs)
73+ )
74+ finished = true;
75+ }
76+ return !finished;
77+ }
78+
79+ while( work_to_do() )
80+ {
81+ executor.spin_some();
82+ }
83+ */
84+
2185/* helper data structure for rcl interface
2286 to save the node with its publishers and subscribers
2387*/
24-
2588typedef struct {
2689 rcl_node_t * rcl_node ; // rcl_node
2790 unsigned int id ; // node id
2891 unsigned int num_pubs ; // number of publishers
2992 unsigned int num_subs ; // number of subscribers
30- rcl_publisher_t * * pubs ; // list of publishers
31- unsigned int * pub_names ; // list of topic ids of the publishers
32- rcl_subscription_t * * subs ; // list of subscribers
93+ rcl_publisher_t * * pubs ; // list of publishers (length = num_pubs)
94+ rcl_timer_t * * timers ; // list of timers (length = num_pubs)
95+ unsigned int * pub_names ; // list of topic ids of the publishers (length = num_pubs)
96+ rcl_subscription_t * * subs ; // list of subscribers (length = num_subs)
3397 std_msgs__msg__String * * subs_msg ; // list of msgs of the subscribers
34- rcl_timer_t * timer ; // timer for publishers
3598} rcl_node_wrapper_t ;
3699
37100
@@ -202,7 +265,6 @@ static rcl_node_wrapper_t * nodes; // list of nodes
202265static unsigned int num_nodes ; // necessary in timer_callback
203266std_msgs__msg__String pub_msg ; // one message string for all publishers with a configured message length
204267
205-
206268/***************************** CALLBACKS ***********************************/
207269
208270
@@ -226,36 +288,40 @@ timer_callback(rcl_timer_t * timer, int64_t last_call_time)
226288 rcl_ret_t rc ;
227289 UNUSED (last_call_time );
228290 if (timer != NULL ) {
229- //printf("Timer: time since last call %d\n", (int) last_call_time);
230-
231- // find corresponding node and publish its messages
232- for (unsigned int n = 0 ; n < num_nodes ; n ++ ) {
233- //printf("Timer callback: searching timer in node %u\n", n);
234- if (nodes [n ].timer == timer ) {
235- for (unsigned int p = 0 ; p < nodes [n ].num_pubs ;p ++ ) {
236- rc = rcl_publish (nodes [n ].pubs [p ], & pub_msg , NULL );
291+ // printf("Timer: time since last call %d\n", (int) last_call_time);
292+
293+ // find corresponding timer and publish its messages
294+ // in each node n the list of publishers is mirrored by the list of timers:
295+ // the timer nodes[n].timers[i] corresponds to the publisher nodes[n].pubs[i]
296+ bool found = false;
297+ for (unsigned int n = 0 ; n < num_nodes && found == false; n ++ ) {
298+ // printf("Timer callback: searching timer in node %u\n", n);
299+ for (unsigned int i = 0 ; i < nodes [n ].num_pubs && found == false; i ++ ) {
300+ if (nodes [n ].timers [i ] == timer ) {
301+ found = true;
302+ rc = rcl_publish (nodes [n ].pubs [i ], & pub_msg , NULL );
303+
304+ // debug output
237305 if (rc != RCL_RET_OK ) {
238- printf ("Error publishing message node[%u].pub[%u]\n" , n , p );
306+ printf ("Error publishing message node[%u].pub[%u]\n" , n , i );
239307 } else {
240- printf ("node %u: published topic_%u\n" , nodes [n ].id , nodes [n ].pub_names [p ]);
308+ printf ("node %u: published topic_%u\n" , nodes [n ].id , nodes [n ].pub_names [i ]);
241309 }
242310 }
243- break ;
244311 }
245312 }
246313 } else {
247314 printf ("Error: timer_callback is NULL\n" );
248315 }
249316}
317+
250318/******************** MAIN PROGRAM *****************************************/
251- int main (int argc , const char * argv [])
252- {
319+ int main (int argc , const char * argv []) {
253320 rcl_ret_t rc ;
254321 conf_t conf ;
255322
256-
257323 ////////////////////////////////////////////////////////////////////////////
258- // Read configuration
324+ // Parse configuration
259325 ////////////////////////////////////////////////////////////////////////////
260326 if ( parse_args ( argc , argv , & conf ) != 0 ) {
261327 printf ("Error while parsing arguments.\n" );
@@ -277,7 +343,7 @@ int main(int argc, const char * argv[])
277343 }
278344
279345 ////////////////////////////////////////////////////////////////////////////
280- // Configure nodes
346+ // Configure rcl handles ( nodes, publishers, timers, subscriptions)
281347 ////////////////////////////////////////////////////////////////////////////
282348
283349 // create fixed strings for node_name and topic_name
@@ -307,26 +373,22 @@ int main(int argc, const char * argv[])
307373 nodes [n ].num_pubs = conf .nodes [n ]-> num_pubs ;
308374 nodes [n ].pubs = calloc ( conf .nodes [n ]-> num_pubs , sizeof (rcl_publisher_t * ));
309375 nodes [n ].pub_names = calloc ( conf .nodes [n ]-> num_pubs , sizeof (unsigned int ));
376+ nodes [n ].timers = calloc ( conf .nodes [n ]-> num_pubs , sizeof (rcl_timer_t * ));
310377
311378 for (unsigned int p = 0 ; p < conf .nodes [n ]-> num_pubs ; p ++ ) {
312379 snprintf (topic_name , TOPIC_NAME_SIZE , "topic_%u" , conf .nodes [n ]-> pub_names [p ]);
313380 printf (" ... publishes %s\n" , topic_name );
314-
381+ nodes [ n ]. pub_names [ p ] = conf . nodes [ n ] -> pub_names [ p ];
315382 nodes [n ].pubs [p ] = rcl_create_publisher_wrapper (nodes [n ].rcl_node ,
316383 init_obj .allocator , ROSIDL_GET_MSG_TYPE_SUPPORT (std_msgs , msg , String ),
317384 topic_name );
318- nodes [n ].pub_names [p ] = conf .nodes [n ]-> pub_names [p ];
319385 if (nodes [n ].pubs [p ] == NULL ) {
320386 printf ("Error: Could not create publisher %s.\n" , topic_name );
321387 return -1 ;
322- }
388+ }
389+ nodes [n ].timers [p ] = rcl_create_timer_wrapper (& init_obj ,
390+ RCL_MS_TO_NS (conf .period ), timer_callback );
323391 }
324-
325- // add one timer (to publish all messages of this node)
326- nodes [n ].timer = rcl_create_timer_wrapper (& init_obj ,
327- RCL_MS_TO_NS (conf .period ), timer_callback );
328- } else {
329- nodes [n ].timer = NULL ; // properly initialized, is expected in executor (see below)
330392 }
331393
332394 // add subscriptions
@@ -387,50 +449,66 @@ int main(int argc, const char * argv[])
387449 printf ("Error in rcle_let_executor_set_timeout." );
388450 }
389451
390- // add subscriptions and timers
391452 for (unsigned int n = 0 ; n < conf .num_nodes ; n ++ ){
392- for ( unsigned int s = 0 ; s < nodes [ n ]. num_subs ; s ++ ) {
393- rc = rcle_let_executor_add_subscription ( & exe , nodes [n ].subs [ s ], nodes [ n ]. subs_msg [ s ],
394- & subscriber_callback , ON_NEW_DATA );
453+ // add one timer per publisher
454+ for ( unsigned int p = 0 ; p < nodes [n ].num_pubs ; p ++ ) {
455+ rc = rcle_let_executor_add_timer ( & exe , nodes [ n ]. timers [ p ] );
395456 if (rc != RCL_RET_OK ) {
396- printf ("Error in rcle_let_executor_add_subscription node [%u] sub %u \n" , n , s );
457+ printf ("Error rcle_let_executor_add_timer: Could not add timer to executor: nodes [%u].timers[%u] \n" ,n , p );
397458 }
398459 }
399460
400- // when node has publishers then add the timer
401- if (nodes [n ].timer != NULL ) {
402- rc = rcle_let_executor_add_timer (& exe , nodes [n ].timer );
461+ // add subscription
462+ for (unsigned int s = 0 ; s < nodes [n ].num_subs ;s ++ ) {
463+ rc = rcle_let_executor_add_subscription (& exe , nodes [n ].subs [s ], nodes [n ].subs_msg [s ],
464+ & subscriber_callback , ON_NEW_DATA );
403465 if (rc != RCL_RET_OK ) {
404- printf ("Error rcle_let_executor_add_timer: Could not add timer to executor \n" );
466+ printf ("Error in rcle_let_executor_add_subscription node[%u] sub %u \n" , n , s );
405467 }
406468 }
407469 }
408-
409- // spin forever
470+ ////////////////////////////////////////////////////////////////////////////
471+ // Run RCL Executor
472+ ////////////////////////////////////////////////////////////////////////////
410473 rcle_let_executor_spin (& exe );
411474
412- // clean up
475+ ////////////////////////////////////////////////////////////////////////////
476+ // Clean up - free dynamically allocated memory
477+ ////////////////////////////////////////////////////////////////////////////
478+ /*
479+ // executor
413480 rc = rcle_let_executor_fini(&exe);
414-
415- /* TODO clean up
416- for (unsigned int i = 0 ; i < NUM_PUBLISHER; i++) {
417- rc = rcl_publisher_fini_wrapper(&init_obj, pubs[i], node0);
418- }
419481
420- for (unsigned int i = 0 ; i < NUM_SUBSCRIBER; i++) {
421- rc = rcl_subscription_fini_wrapper(&init_obj, subs[i], node0);
422- }
482+ // rcl handles
483+ for (unsigned int n = 0; n < conf.num_nodes; n++) {
484+ // delete memory of publishers and timers
485+ if ( conf.nodes[n]->num_pubs > 0) {
486+ for(unsigned int i = 0; i < conf.nodes[n]->num_pubs; i++) {
487+ rc = rcl_publisher_fini_wrapper(&init_obj, nodes[n].pubs[i], nodes[n].rcl_node);
488+ rc = rcl_timer_fini_wrapper(&init_obj, nodes[n].timers[i]);
489+ }
490+ free (nodes[n].pubs);
491+ free (nodes[n].pub_names);
492+ free (nodes[n].timers);
493+ }
423494
424- for (unsigned int i = 0 ; i < NUM_SUBSCRIBER; i++) {
425- init_obj.allocator->deallocate( subs_msg[i], init_obj.allocator->state);
495+ // delete memory of subscriptions
496+ if ( conf.nodes[n]->num_subs > 0) {
497+ for(unsigned int i = 0; i < conf.nodes[n]->num_subs; i++) {
498+ rc = rcl_subscription_fini_wrapper(&init_obj, nodes[n].subs[i], nodes[n].rcl_node);
499+ init_obj.allocator->deallocate(nodes[n].subs_msg[i], init_obj.allocator->state);
500+ }
501+ free(nodes[n].subs);
502+ free(nodes[n].subs_msg);
503+ }
504+ // delete memory of node
505+ rc = rcl_node_fini_wrapper(&init_obj, nodes[n].rcl_node);
426506 }
427-
428- rc = rcl_timer_fini_wrapper(&init_obj, timer1);
429- rc = rcl_node_fini_wrapper(&init_obj, node0);
430- rc = rcl_init_options_fini(&init_obj);
431- */
507+ free (pub_string);
508+ rc = rcl_init_fini_wrapper(&init_obj);
509+ free (nodes);
510+ // configuration object (command line arguments)
432511 configuration_fini( &conf);
433-
512+ */
434513 return 0 ;
435-
436- }
514+ }
0 commit comments