Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multi Threading + Multi Node #795

Open
DwayneGit opened this issue Feb 20, 2023 · 6 comments
Open

Multi Threading + Multi Node #795

DwayneGit opened this issue Feb 20, 2023 · 6 comments

Comments

@DwayneGit
Copy link

DwayneGit commented Feb 20, 2023

Hello,

I am pretty new to micro-ROS and trying to create two nodes on separate cores.

I have been over the examples of of multi-threading and multiple nodes from the micro-ros demo examples but i have not seen anything on using those libraries here and there is nothing for this specific application.

I have managed to create the code below. it creates two nodes on the main thread and passes one node, the support, and allocator to core1 via queue to handle all the none shared initializations.

This is the closes i come to a working setup. the nodes seem to work fine except that you can not initialize subscribers or publishers on both nodes. so i would need to comment out rclc_timer_init_default for rclc_publisher_init_default to work. timers dont seem to be effect by this. It will abort with a RCL_RET_ERROR if both are attempted.

Please let me know what i am doing wrong or if this is even possible or if something isn't clear. Thank you

PS. I already recompiled the library with #define RMW_UXRCE_MAX_NODES 2

#include <stdio.h>
#include <rcl/rcl.h>
#include <rclc/rclc.h>
#include <rclc/executor.h>
#include <rcl/error_handling.h>
#include <std_msgs/msg/int32.h>
#include <std_msgs/msg/int16.h>
#include <geometry_msgs/msg/twist.h>
#include <rmw_microros/rmw_microros.h>

#include "pico/stdlib.h"
#include "pico/multicore.h"
#include "pico/util/queue.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\r",__LINE__,(int)temp_rc); return 1;}}
#define RCSOFTCHECK(fn) { rcl_ret_t temp_rc = fn; if((temp_rc != RCL_RET_OK)){printf("Failed status on line %d: %d. Continuing.\n\r",__LINE__,(int)temp_rc);}}

void timer_callback(rcl_timer_t * timer, int64_t last_call_time)
{
	printf("Last callback time: %ld\n\r",  last_call_time );
	if (timer != NULL) {
            /* publish */
	}
}

void subscription_callback(const void * msgin){}

#define FLAG_VALUE 123
queue_t node1_queue;

void core1_entry() {
    queue_node_req_t node1;
    rcl_timer_t timer;
    rclc_executor_t executor;
    
    multicore_fifo_push_blocking(FLAG_VALUE);

    uint32_t g = multicore_fifo_pop_blocking();
    if (g != FLAG_VALUE)
        printf("Hmm, that's not right on core 1!\n\r");
    else{
        queue_remove_blocking(&node1_queue, &node1);

        RCSOFTCHECK(rclc_executor_init(
            &executor,
            &node1.support.context, 
            1, 
            &node1.allocator
        ));

        RCSOFTCHECK(rclc_publisher_init_default(&pub, &node1.node, ROSIDL_GET_MSG_TYPE_SUPPORT(std_msgs, msg, Int16), "pub_node"));
        
        const unsigned int timer_period = RCL_MS_TO_NS(100);
        RCSOFTCHECK(rclc_timer_init_default(&timer, &node1.support, timer_period, timer_callback));
        RCSOFTCHECK(rclc_executor_add_timer(&executor, &timer));
        printf("Its all gone well on core 1!\n\r");

        rclc_executor_spin(&executor);

        RCSOFTCHECK(rclc_executor_fini(&executor));
        RCSOFTCHECK(rcl_publisher_fini(&pub, &node1.node));  
        RCSOFTCHECK(rcl_node_fini(&node1.node));
        RCSOFTCHECK(rcl_timer_fini(&timer));
    }
}

int main()
{
    rmw_uros_set_custom_transport(
		true,
		NULL,
		pico_serial_transport_open,
		pico_serial_transport_close,
		pico_serial_transport_write,
		pico_serial_transport_read
	);


    stdio_init_all();

    gpio_init(PICO_DEFAULT_LED_PIN);
    gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);

    gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
    gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

    queue_init(&node1_queue, sizeof(queue_node_req_t), 2);

    // // Turn off FIFO's - we want to do this character by character
    // uart_set_fifo_enabled(UART_ID, false);

    gpio_put(PICO_DEFAULT_LED_PIN, 1);

    rclc_support_t support;
    rcl_allocator_t allocator = rcl_get_default_allocator();
    RCCHECK(rclc_support_init(&support, 0, NULL, &allocator));

    multicore_launch_core1(core1_entry);
    uint32_t g = multicore_fifo_pop_blocking();

    if (g != FLAG_VALUE)
        printf("Hmm, that's not right on core 0!\n\r");
    else {
        rcl_node_t node0;
        RCCHECK(rclc_node_init_default(&node0, "node_1", "", &support));
        rcl_node_t node1;
        RCCHECK(rclc_node_init_default(&node1, "node_2", "", &support));
        
        multicore_fifo_push_blocking(FLAG_VALUE);
        printf("It's all gone well on core 0!\n\r");
        
        queue_node_req_t node_req = {node1, allocator, support};
        queue_add_blocking(&node1_queue, &node_req);
        
        rclc_executor_t executor;
        RCCHECK(rclc_executor_init( &executor, &support.context, 1,  &allocator ));

        rcl_subscription_t subscriber;
        geometry_msgs__msg__Twist twist_msg;
        RCCHECK(rclc_subscription_init_default( &subscriber, &node0, ROSIDL_GET_MSG_TYPE_SUPPORT(geometry_msgs, msg, Twist),  "cmd_vel" ));
        RCCHECK(rclc_executor_add_subscription( &executor, &subscriber, &twist_msg, &subscription_callback, ON_NEW_DATA ));

        rclc_executor_spin(&executor);

        RCCHECK(rcl_node_fini(&node0));
        RCCHECK(rclc_executor_fini(&executor));
        RCCHECK(rcl_subscription_fini(&subscriber, &node0));
        RCCHECK(rcl_publisher_fini(&pubFrontRightTicks, &node0));   
        RCCHECK(rclc_support_fini(&support))
    }

    return 0;
}
@pablogs9
Copy link
Member

Hello @DwayneGit multithreading is not supported in RPi Pico SDK, you need to implement lockings in middleware here: https://github.com/eProsima/Micro-XRCE-DDS-Client/blob/master/src/c/profile/multithread/multithread.c and rebuild the library with UCLIENT_PROFILE_MULTITHREADenabled in colcon.meta for Micro XRCE-DDS Client.

@DwayneGit
Copy link
Author

@pablogs9 Thanks for the reply! Not sure what you mean by "you need to implement lockings in middleware". Is there more that this file needs or is it just copying the file into my project since it seems that the library already has some connection to it like here: https://github.com/micro-ROS/micro_ros_raspberrypi_pico_sdk/blob/humble/libmicroros/include/uxr/client/profile/multithread/multithread.h

@pablogs9
Copy link
Member

In this file only locks for PLATFORM_NAME_FREERTOS, UCLIENT_PLATFORM_ZEPHYR, and UCLIENT_PLATFORM_POSIX are implemented. Does your platform support creating mutex somehow?

@DwayneGit
Copy link
Author

DwayneGit commented Feb 21, 2023

Yes. looks like the pico sdk does support mutex, lock and semaphore https://raspberrypi.github.io/pico-sdk-doxygen/group__pico__sync.html. So i guess i need to implement the contents of the multithread.c using the pico sdk library?

@pablogs9
Copy link
Member

That's it, it would be great if you open a PR to Micro XRCE-DDS Client with your changes

@DwayneGit
Copy link
Author

Sure, I'll get on that

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants