micro-ROS/micro_ros_espidf_component

Code not building successfully and getting Linking issues if Middleware selected as XRCE-DDS

Closed this issue · 20 comments

Hi @pablogs9 ,

I am trying to build this idf component by selecting Middleware as XRCE-DDS in menuconfig instead of Embedded RTPS.

But ending up with below image undefined references to socketrinfo coonect freeaddrinfo etc issues. Could you please let me know if i am missing anything ?

image

thank you in advance.

Provide instructions for replicating this error

Hi @pablogs9

Here is the instruction to replicated this.

Step1 : Installed ESP-IDF Manually using below link
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/get-started/linux-macos-setup.html

Step2 : Cloned this micro_ros_espidf_component in to my esp/esp-idf/components folder.

Step3 : Updated cmakelist.txt of above component with below extra esp modules

image

Step4 : Opened Terminal given below commands to export esp-idf environment
cd esp/esp-idf
. ./export.sh

Step5: given below commands
cd components/micro_ros_idf_component/examples/int32_publisher
idf.py set-target esp32
idf.py menuconfig -----> this will open the window to select micro-ROS Middle ware i have selected Micro XRCE-DDS

image

    idf.py build 

this will replicate the above issue.

Could you please help in this ?

I guess that you are modifying somehow the network layer and it does not build in your environment.

Have you tried to follow the instructions here: https://github.com/micro-ROS/micro_ros_espidf_component#example

Hi @pablogs9

i have exactly followed the instruction from the link https://github.com/micro-ROS/micro_ros_espidf_component#example

with Middleware selecting as EmbeddedRTPS (Experimental) i am able to build successfully do the all the stuff.

But with Middleware selecting as [eProsima Micro XRCE-DDS] i am getting this linking issues.

Based on my understanding, with XRCE-DDS only I can enable Shared Memory , Multi Thread and Custom Transport functionalities.is it true ? correct me if am wrong .

could you please check once this error ?

Are you building with XRCE-DDS in a clean environment?

Because as you can see, all this component is correctly building for supported platforms: https://github.com/micro-ROS/micro_ros_espidf_component/actions/runs/3616844063

Hi @pablogs9

I used below commands to clean environment

idf.py fullclean
idf.py clean
idf.py clean-microros

after this only i started using

idf.py set-target esp32
idf.py menuconfig
idf.py build

but no luck same issue repeating.

Do i have to re-install ESP-IDF ? Is there any other components in ESP-IDF need to be cleared ?

i could see that these undefined function are in LWIP Component under lwip/include/lwip/sockets.h as below. header file is included properly but the undefined function are like below which are extern under a #ifdef __cplusplus macro and also function defined as static inline. could you please check is there anything wrong here ? please check image once

image

if i remove static and extern the above inline functions then i am ending up with multiple definitions again. not knowing why all these issues are coming.

based on my build issues apart from instruction in link https://github.com/micro-ROS/micro_ros_espidf_component#example some extra files also need to update. i have updated cmakelist.txt and esp32_toolchain.cmake.in with proper freertos path and components names ( esp_wifi , esp_netif , esp_eth)

could you please check for you is this component working directly without any issues with middleware XRCE-DDS with only above instruction ?

please help me with this.

if working could you please share your working workspace. it will be a great helpful for me to proceed on this microROS further.

Which version of ESP-IDF are you using?

Hi @pablogs9

the current ESP-IDF Version i am using is "ESP-IDF v5.1-dev-1840-gaad600c9ca-dirty".

is it the right version ? please let me know.

ok thank you for the info. let me downgrade my ESP-IDF version from 5.1 to v4.4 and I will check with that.

hi @pablogs9

Meanwhile i have few below queries could you please clarify ?

  1. In EmbeddedRTPS Mode . The functionalities like shared memory , multi thread and custom transport works ? because based on my understanding XRCE-DDS Client has these features to enable. what about in Embedded RTPS Case if want same functionalities ?

  2. In EmbeddedRTPS Mode can I run 2 tasks on single ESP32 parallelly one as publisher and other as subscriber ?

3.In EmbeddedRTPS Mode can I use custom transport like serial or something without UDP/IP Stack ?

It will be great helpful for me if you clarify these questions running in my mind so that I would like to try these

In EmbeddedRTPS Mode . The functionalities like shared memory , multi thread and custom transport works ? because based on my understanding XRCE-DDS Client has these features to enable. what about in Embedded RTPS Case if want same functionalities ?

No

In EmbeddedRTPS Mode can I run 2 tasks on single ESP32 parallelly one as publisher and other as subscriber ?

Not sure, ask in the EmbeddedRTPS repo, this middleware is not maintained by us.

3.In EmbeddedRTPS Mode can I use custom transport like serial or something without UDP/IP Stack ?

AFAIK no

image

#162

HI @pablogs9

Thanks a lot .I did build with ESP4.4 Version then the build it is successful 👍 .

One more query below i have could you please help

I have tried merging individual publisher and subscriber into two 2 different RTOS Tasks in single Firmware.When i am running publisher and subscriber tasks are switching.

Publisher is publishing data but subscriber is halting at RCCCheck at rclc_support_init as below

image

could you please help if i am missing anything ?

Provide code for replicating this issue

here is the project main.c code. remaining everything is unchanged with respect to embedded RTPS Middleware.

please paste this code in your similar idf component with embedded RTPS project main.c and build

#include <string.h>
#include <stdio.h>
#include <unistd.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"

#include <uros_network_interfaces.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <std_msgs/msg/string.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include "sntp_example_main.h"

//#include <WiFi.h>
#include "time.h"

#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",__LINE__,(int)temp_rc);vTaskDelete(NULL);}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",__LINE__,(int)temp_rc);}}

rcl_publisher_t publisher;
rcl_subscription_t subscriber;
std_msgs__msg__String msg;
std_msgs__msg__String msg2;

time_t now;
struct tm timeinfo;

uint32_t t_sec;
uint32_t t_usec;
uint32_t t_msec;

uint32_t counter = 0;
#define ARRAY_LEN 200
   
void subscription_callback(const void * msgin)
{
	const std_msgs__msg__String * msg = (const std_msgs__msg__String *)msgin;
	time(&now);
	example_sntp_get_system_time(&t_sec,&t_usec);
	printf("Received: %s @ time : %ld  ,sec: %d , usec:%d \n", msg->data.data,now ,t_sec,t_usec);
}

void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
        
    time(&now);
    example_sntp_get_system_time(&t_sec,&t_usec);
	if (timer != NULL) {
	       sprintf(msg.data.data, "Hello from micro-ROS #%d", counter++);
		msg.data.size = strlen(msg.data.data);
		RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
		printf("Publishing: %s @ time: %ld ,sec: %d , msec:%d \n", msg.data.data,now,t_sec,t_msec);
	}
}

void micro_ros_task(void * arg)
{
       printf("initializing publisher.....\n");
	rcl_allocator_t allocator = rcl_get_default_allocator();
	rclc_support_t support;

	rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
	RCCHECK(rcl_init_options_init(&init_options, allocator));

	// create init_options
	RCCHECK(rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator));

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

	// create publisher
	RCCHECK(rclc_publisher_init_default(
		&publisher,
		&node,
		ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
		"freertos_int32_publisher"));

	// 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;
	RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
	RCCHECK(rclc_executor_add_timer(&executor, &timer));
	
	// Fill the array with a known sequence
	msg.data.data = (char * ) malloc(ARRAY_LEN * sizeof(char));
	msg.data.size = 0;
	msg.data.capacity = ARRAY_LEN;

	//msg.data = 0;
	 //init and get the time
  	////configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
  	//printLocalTime();

	while(1){
	       printf("publisher task running \n");
		rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
		//usleep(10000);
		vTaskDelay(100);
	}

	// free resources
	RCCHECK(rcl_publisher_fini(&publisher, &node));
	RCCHECK(rcl_node_fini(&node));

  	vTaskDelete(NULL);
}

void micro_ros_task_sub(void * arg)
{
	printf("initializing sbscriber.....\n");
	vTaskDelay(1000);
  	rcl_allocator_t allocator = rcl_get_default_allocator();
	rclc_support_t support;

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

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

	// create subscriber
	RCCHECK(rclc_subscription_init_default(
		&subscriber,
		&node,
		ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
		"freertos_int32_publisher"));

	// create executor
	rclc_executor_t executor = rclc_executor_get_zero_initialized_executor();
	RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
	RCCHECK(rclc_executor_add_subscription(&executor, &subscriber, &msg2, &subscription_callback, ON_NEW_DATA));
	
	msg.data.data = (char * ) malloc(ARRAY_LEN * sizeof(char));
	msg.data.size = 0;
	msg.data.capacity = ARRAY_LEN;

	 while(1){
	        printf("subscriber task running \n");
                rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
                //usleep(100000);
                vTaskDelay(100);
        }

  	//rclc_executor_spin(&executor);

	RCCHECK(rcl_subscription_fini(&subscriber, &node));
	RCCHECK(rcl_node_fini(&node));
}

void app_main(void)
{
#if defined(CONFIG_MICRO_ROS_ESP_NETIF_WLAN) || defined(CONFIG_MICRO_ROS_ESP_NETIF_ENET)
    ESP_ERROR_CHECK(uros_network_interface_initialize());
#endif
    time_t now;
    struct tm timeinfo;
    time(&now);
    localtime_r(&now, &timeinfo);
    // Is time set? If not, tm_year will be (1970 - 1900).
    if (timeinfo.tm_year < (2016 - 1900)) {

        printf("obtaining time \n");
        obtain_time();
        // update 'now' variable with current time
        time(&now);

    }
    printf("CUrrent time is %ld" ,now);
    xTaskCreate(micro_ros_task,
            "uros_task",
            CONFIG_MICRO_ROS_APP_STACK,
            NULL,
            CONFIG_MICRO_ROS_APP_TASK_PRIO,
            NULL);
    xTaskCreate(micro_ros_task_sub,
            "uros_task",
            CONFIG_MICRO_ROS_APP_STACK,
            NULL,
            CONFIG_MICRO_ROS_APP_TASK_PRIO,
            NULL);
       
}

You cannot init micro-ROS twice.

The recommended approach is:

  • to init micro-ROS in one task,
  • create two executors one for the timer and the other for the subscription
  • spin the executors in separate tasks and callbacks will execute in each task
  • ensure that both executors have mutual exclusion or try to enable UCLIENT_PROFILE_MULTITHREAD (nor sure if it will work out of the box with this component)

I'm closing since the initial issue is solved, feel free to open a new one if you have other problems

You cannot init micro-ROS twice.

The recommended approach is:

  • to init micro-ROS in one task,
  • create two executors one for the timer and the other for the subscription
  • spin the executors in separate tasks and callbacks will execute in each task
  • ensure that both executors have mutual exclusion or try to enable UCLIENT_PROFILE_MULTITHREAD (nor sure if it will work out of the box with this component)

Hi @pablogs9
Perfect !!!
Thank you so much .This is the great information . I will try this now. I hope it will work.

You cannot init micro-ROS twice.

The recommended approach is:

  • to init micro-ROS in one task,
  • create two executors one for the timer and the other for the subscription
  • spin the executors in separate tasks and callbacks will execute in each task
  • ensure that both executors have mutual exclusion or try to enable UCLIENT_PROFILE_MULTITHREAD (nor sure if it will work out of the box with this component)

Hi @pablogs9

I tried above steps first 3 points. 4th point i could not find in EmbeddedRTPS . publisher is publishing the data but subscriber call back is not happening.

Here is my restructured main.c code . could you please verify once and please help in why subscriber callback is not happening. any special condition do I need to meet ?

#include <string.h>
#include <stdio.h>
#include <unistd.h>

#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_system.h"

#include <uros_network_interfaces.h>
#include <rcl/rcl.h>
#include <rcl/error_handling.h>
#include <std_msgs/msg/string.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include "sntp_example_main.h"

//#include <WiFi.h>
#include "time.h"

#define RCCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Aborting.\n",LINE,(int)temp_rc);vTaskDelete(NULL);}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n",LINE,(int)temp_rc);}}

rcl_publisher_t publisher;
rcl_subscription_t subscriber;
std_msgs__msg__String msg;
std_msgs__msg__String msg2;

time_t now;
struct tm timeinfo;

uint32_t t_sec;
uint32_t t_usec;
uint32_t t_msec;

uint32_t counter = 0;
#define ARRAY_LEN 200

rclc_executor_t executor;
rclc_executor_t executor2;

void subscription_callback(const void * msgin)
{
const std_msgs__msg__String * msg = (const std_msgs__msg__String *)msgin;
//time(&now);
//example_sntp_get_system_time(&t_sec,&t_usec);
//printf("Received: %s @ time : %ld ,sec: %d , usec:%d \n", msg->data.data,now ,t_sec,t_usec);
printf("Received: %s \n", msg->data.data);
}

void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{

//time(&now);
//example_sntp_get_system_time(&t_sec,&t_usec);
if (timer != NULL) {
       sprintf(msg.data.data, "Hello from micro-ROS #%d", counter++);
	msg.data.size = strlen(msg.data.data);
	RCSOFTCHECK(rcl_publish(&publisher, &msg, NULL));
	//printf("Publishing: %s @ time: %ld ,sec: %d , msec:%d \n", msg.data.data,now,t_sec,t_msec);
	printf("Publishing: %s \n", msg.data.data);
}

}

void micro_ros_task(void * arg)
{
printf("initializing init task.....\n");
//vTaskDelay(1000);
rcl_allocator_t allocator = rcl_get_default_allocator();
rclc_support_t support;

rcl_init_options_t init_options = rcl_get_zero_initialized_init_options();
RCCHECK(rcl_init_options_init(&init_options, allocator));

// create init_options
RCCHECK(rclc_support_init_with_options(&support, 0, NULL, &init_options, &allocator));

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

// create subscriber
RCCHECK(rclc_subscription_init_default(
	&subscriber,
	&node,
	ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
	"freertos_int32_publisher"));
	
  // create executor
executor2 = rclc_executor_get_zero_initialized_executor();
RCCHECK(rclc_executor_init(&executor2, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_subscription(&executor2, &subscriber, &msg2, &subscription_callback, ON_NEW_DATA));

// create publisher
RCCHECK(rclc_publisher_init_default(
	&publisher,
	&node,
	ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, String),
	"freertos_int32_publisher"));
    // create node2
//rcl_node_t node2;
//RCCHECK(rclc_node_init_default(&node2, "int32_subscriber_rclc", "", &support));

// 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 publisher executor

RCCHECK(rclc_executor_init(&executor, &support.context, 1, &allocator));
RCCHECK(rclc_executor_add_timer(&executor, &timer));

   


// Fill the array with a known sequence
msg.data.data = (char * ) malloc(ARRAY_LEN * sizeof(char));
msg.data.size = 0;
msg.data.capacity = ARRAY_LEN;

    msg2.data.data = (char * ) malloc(ARRAY_LEN * sizeof(char));
msg2.data.size = 0;
msg2.data.capacity = ARRAY_LEN;

//msg.data = 0;
 //init and get the time
////configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
//printLocalTime();

while(1){
       printf("init task running \n");
	//rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
	//usleep(10000);
	vTaskDelay(1000);
}

// free resources
//RCCHECK(rcl_publisher_fini(&publisher, &node));
//RCCHECK(rcl_node_fini(&node));
    printf("init task deleted \n");
vTaskDelete(NULL);

}

void micro_ros_task_pub(void * arg)
{
vTaskDelay(2000);
printf("initializing publisher task.....\n");

 while(1){
        //printf("publisher task running \n");
            rclc_executor_spin_some(&executor, RCL_MS_TO_NS(100));
            //usleep(100000);
            vTaskDelay(100);
    }

//rclc_executor_spin(&executor);

//RCCHECK(rcl_subscription_fini(&subscriber, &node));
//RCCHECK(rcl_node_fini(&node));
printf("publisher task deleted \n");
vTaskDelete(NULL);

}

void micro_ros_task_sub(void * arg)
{
vTaskDelay(1000);
printf("initializing sbscriber task.....\n");

 while(1){
       //  printf("subscriber task running \n");
            rclc_executor_spin_some(&executor2, RCL_MS_TO_NS(100));
            usleep(100000);
            vTaskDelay(100);
    }

//rclc_executor_spin(&executor);

//RCCHECK(rcl_subscription_fini(&subscriber, &node));
//RCCHECK(rcl_node_fini(&node));
printf("subscriber task deleted \n");
vTaskDelete(NULL);

}

void app_main(void)
{
#if defined(CONFIG_MICRO_ROS_ESP_NETIF_WLAN) || defined(CONFIG_MICRO_ROS_ESP_NETIF_ENET)
ESP_ERROR_CHECK(uros_network_interface_initialize());
#endif
//time_t now;
//struct tm timeinfo;
//time(&now);
//localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
//if (timeinfo.tm_year < (2016 - 1900)) {

 //   printf("obtaining time \n");
 //   obtain_time();
    // update 'now' variable with current time
 //   time(&now);

//}
//printf("CUrrent time is %ld" ,now);
xTaskCreate(micro_ros_task,
        "uros_task",
        CONFIG_MICRO_ROS_APP_STACK,
        NULL,
        CONFIG_MICRO_ROS_APP_TASK_PRIO,
        NULL);
xTaskCreate(micro_ros_task_pub,
        "uros_task",
        CONFIG_MICRO_ROS_APP_STACK,
        NULL,
        CONFIG_MICRO_ROS_APP_TASK_PRIO,
        NULL);
xTaskCreate(micro_ros_task_sub,
        "uros_task",
        CONFIG_MICRO_ROS_APP_STACK,
        NULL,
        CONFIG_MICRO_ROS_APP_TASK_PRIO,
        NULL);

}