micro_ros_setup icon indicating copy to clipboard operation
micro_ros_setup copied to clipboard

rcl_executor_spin stuck on freeRTOS

Open N-K1998 opened this issue 1 year ago • 5 comments

Issue template

  • Hardware description: STM
  • RTOS: freeRTOS
  • Installation type:
  • Version or commit hash: iron

I am trying to define a pub/sub node on microros. Using the following code the execution stops at rclc_executor_spin. Is there something wrong with the initialization?

/* timer callback */
void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
	(void) last_call_time;
	if (timer != NULL) {
		RCSOFTCHECK(rcl_publish(&publisher, &pub_msg, NULL));
		printf("Publishing: %d\n", pub_msg.data);
		pub_msg.data++;
	}
}

static void microros_thread_custom( void *pvParameters ){
	// set custom transport
	rmw_uros_set_custom_transport(
		false, // Framing disable here
		(void *) NULL, // transport->args
		shm_transport_open,
		shm_transport_close,
		shm_transport_write,
		shm_transport_read);

	// Get empty allocator to define a custom one
	rcl_allocator_t custom_allocator = rcutils_get_zero_initialized_allocator();
	rclc_support_t support;

	// Set custom allocation methods for freeRTOS
	custom_allocator.allocate = microros_allocate;
	custom_allocator.deallocate = microros_deallocate;
	custom_allocator.reallocate = microros_reallocate;
	custom_allocator.zero_allocate =  microros_zero_allocate;

	// Set default allocator to custom
	if (!rcutils_set_default_allocator(&custom_allocator)){
		printf("# Setting custom allocator as default: FAILED\r\n");
		return;
	}

	// get the default allocator
	rcl_allocator_t allocator = rcl_get_default_allocator();

	// create init_options
	RCCHECK(rclc_support_init(&support, 0, NULL, &allocator)); // argc:0, argv: NULL

	// create node
	rcl_node_t node;
	RCCHECK(rclc_node_init_default(&node, "int32_publisher_subscriber_rclc", "", &support));

	// topics
	const char * pub_topic_name = "freeRTOS_publisher";
	const char * sub_topic_name = "linux_publisher";

	// create publisher
	RCCHECK(rclc_publisher_init_default(
		&publisher,
		&node,
		ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
		pub_topic_name)); // topic name

	// create subscriber
	RCCHECK(rclc_subscription_init_default(
		&subscriber,
		&node,
		ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int32),
		sub_topic_name));

	// create timer,
	rcl_timer_t timer;
	const unsigned int timer_timeout = 1000;
	RCCHECK(rclc_timer_init_default(
		&timer,
		&support,
		RCL_MS_TO_NS(timer_timeout),
		timer_callback));


	// create executor
	rclc_executor_t executor = rclc_executor_get_zero_initialized_executor();
	unsigned int num_handles = 1 + 1; // 1 timer + 1 sub callback
	RCCHECK(rclc_executor_init(&executor, &support.context, num_handles, &allocator));
	RCCHECK(rclc_executor_add_timer(&executor, &timer));
	RCCHECK(rclc_executor_add_subscription(&executor, &subscriber, &sub_msg, &subscription_callback, ON_NEW_DATA)); // sub

	pub_msg.data = 0;

	RCCHECK(rclc_executor_spin(&executor));

	// fini functions
	RCCHECK(rcl_subscription_fini(&subscriber, &node));
	RCCHECK(rcl_publisher_fini(&publisher, &node));
	RCCHECK(rcl_node_fini(&node));
	RCCHECK(rcl_timer_fini(&timer));

	return;
}

N-K1998 avatar Sep 28 '23 15:09 N-K1998

Avoid using rclc_executor_spin in embedded systems, it can freeze your scheduler.

Use this approach:

while(1){
   delay execution for letting other tasks to run
   spin some the rclc executor
}

pablogs9 avatar Sep 29 '23 06:09 pablogs9

Just a question. If I define a custom transport in the microros thread task like this:

static void microros_thread_custom( void *pvParameters ){
	// set custom transport
	rmw_uros_set_custom_transport(
		false, // Framing disable here
		(void *) NULL, // transport->args
		shm_transport_open,
		shm_transport_close,
		shm_transport_write,
		shm_transport_read);
	// whatever code
	
}

And then in the transport_read i call a blocking task operation like:

size_t shm_transport_read(struct uxrCustomTransport* transport, uint8_t* buf, size_t len, int timeout, uint8_t* err){
        // Whatever
        vTaskDelay(x10second);
        // Whatever
}

Does this operation affect the execution of the main thread? The main thread won't execute until the end of the delay inside the read or will it normally continue its execution?

N-K1998 avatar Sep 29 '23 09:09 N-K1998

yes, if you block in the read operation it will block the spin.

pablogs9 avatar Sep 29 '23 09:09 pablogs9

And also the main thread that has set the custom transport?

N-K1998 avatar Sep 29 '23 09:09 N-K1998

no, the read operation happens inside the spin, so only is blocked the task that runs the spin.

pablogs9 avatar Sep 29 '23 09:09 pablogs9