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

Undefined reference to rclc_lifecycle functions #907

Closed
tnagyzambo opened this issue Apr 1, 2022 · 5 comments
Closed

Undefined reference to rclc_lifecycle functions #907

tnagyzambo opened this issue Apr 1, 2022 · 5 comments

Comments

@tnagyzambo
Copy link

tnagyzambo commented Apr 1, 2022

Issue template

  • Hardware description: Arduino Portenta H7
  • RTOS: mbedOS
  • Installation type: platformio
  • Version or commit hash: galactic

Steps to reproduce the issue

Attempt to compile minimal lifecycle example:

#include <micro_ros_arduino.h>

#include <rcl/error_handling.h>
#include <rcutils/logging_macros.h>

#include <lifecycle_msgs/msg/transition_description.h>
#include <lifecycle_msgs/msg/transition_event.h>
#include <lifecycle_msgs/srv/change_state.h>
#include <lifecycle_msgs/srv/get_available_states.h>
#include <lifecycle_msgs/srv/get_available_transitions.h>
#include <lifecycle_msgs/srv/get_state.h>

#include <rcl/error_handling.h>
#include <rcl/rcl.h>
#include <rclc/executor.h>
#include <rclc/rclc.h>

#include <rclc_lifecycle/rclc_lifecycle.h>

#define LED_PIN 13

#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);                               \
            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", __LINE__, (int)temp_rc);                             \
        }                                                                                                              \
    }

void error_loop() {
    while (1) {
        digitalWrite(LED_PIN, !digitalRead(LED_PIN));
        delay(100);
    }
}

int my_on_configure() {
    printf("  >>> lifecycle_node: on_configure() callback called.\n");
    return RCL_RET_OK;
}

int my_on_activate() {
    printf("  >>> lifecycle_node: on_activate() callback called.\n");
    return RCL_RET_OK;
}

int my_on_deactivate() {
    printf("  >>> lifecycle_node: on_deactivate() callback called.\n");
    return RCL_RET_OK;
}

int my_on_cleanup() {
    printf("  >>> lifecycle_node: on_cleanup() callback called.\n");
    return RCL_RET_OK;
}

int main() {
    byte arduino_mac[] = {0xAA, 0xBB, 0xCC, 0xEE, 0xDD, 0xFF};
    IPAddress arduino_ip(192, 168, 2, 2);
    IPAddress agent_ip(192, 168, 2, 1);
    set_microros_native_ethernet_udp_transports(arduino_mac, arduino_ip, agent_ip, 8090);

    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);

    delay(2000);

    rcl_allocator_t allocator = rcl_get_default_allocator();
    rclc_support_t support;
    rcl_ret_t rc;

    // create init_options
    rc = rclc_support_init(&support, 0, NULL, &allocator);
    if (rc != RCL_RET_OK) {
        printf("Error rclc_support_init.\n");
        return -1;
    }

    // create rcl_node
    rcl_node_t my_node;
    rc = rclc_node_init_default(&my_node, "lifecycle_node", "rclc", &support);
    if (rc != RCL_RET_OK) {
        printf("Error in rclc_node_init_default\n");
        return -1;
    }

    // make it a lifecycle node
    printf("creating lifecycle node...\n");
    rcl_lifecycle_state_machine_t state_machine_ = rcl_lifecycle_get_zero_initialized_state_machine();
    rclc_lifecycle_node_t lifecycle_node;
    rc = rclc_make_node_a_lifecycle_node(&lifecycle_node, &my_node, &state_machine_, &allocator, true);
    if (rc != RCL_RET_OK) {
        printf("Error in creating lifecycle node.\n");
        return -1;
    }

    // Executor
    rclc_executor_t executor;
    RCCHECK(rclc_executor_init(&executor,
                               &support.context,
                               4, // 1 for the node + 1 for each lifecycle service
                               &allocator));

    unsigned int rcl_wait_timeout = 1000; // in ms
    RCCHECK(rclc_executor_set_timeout(&executor, RCL_MS_TO_NS(rcl_wait_timeout)));

    // Register lifecycle services
    printf("registering lifecycle services...\n");
    RCCHECK(rclc_lifecycle_init_get_state_server(&lifecycle_node, &executor));
    RCCHECK(rclc_lifecycle_init_get_available_states_server(&lifecycle_node, &executor));
    RCCHECK(rclc_lifecycle_init_change_state_server(&lifecycle_node, &executor));

    // Register lifecycle service callbacks
    printf("registering callbacks...\n");
    rclc_lifecycle_register_on_configure(&lifecycle_node, &my_on_configure);
    rclc_lifecycle_register_on_activate(&lifecycle_node, &my_on_activate);
    rclc_lifecycle_register_on_deactivate(&lifecycle_node, &my_on_deactivate);
    rclc_lifecycle_register_on_cleanup(&lifecycle_node, &my_on_cleanup);

    // Run
    RCSOFTCHECK(rclc_executor_spin(&executor));

    // Cleanup
    printf("cleaning up...\n");
    rc = rclc_lifecycle_node_fini(&lifecycle_node, &allocator);
    rc += rcl_node_fini(&my_node);
    rc += rclc_executor_fini(&executor);
    rc += rclc_support_fini(&support);

    if (rc != RCL_RET_OK) {
        printf("Error while cleaning up!\n");
        return -1;
    }
    return 0;
}

All lifecycle functions are undefined when attempting to build:

Processing portenta_h7_m7 (platform: ststm32; board: portenta_h7_m7; framework: arduino)
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Verbose mode can be enabled via `-v, --verbose` option
CONFIGURATION: https://docs.platformio.org/page/boards/ststm32/portenta_h7_m7.html
PLATFORM: ST STM32 (15.2.0) > Arduino Portenta H7 (M7 core)
HARDWARE: STM32H747XIH6 480MHz, 511.35KB RAM, 768KB Flash
DEBUG: Current (cmsis-dap) External (cmsis-dap, jlink, stlink)
PACKAGES: 
 - framework-arduino-mbed 2.6.1 
 - tool-dfuutil 1.9.200310 
 - toolchain-gccarmnoneeabi 1.70201.0 (7.2.1)
LDF: Library Dependency Finder -> https://bit.ly/configure-pio-ldf
LDF Modes: Finder ~ chain, Compatibility ~ soft
Found 32 compatible libraries
Scanning dependencies...
Dependency Graph
|-- <micro_ros_arduino> 2.0.4-galactic+sha.3660860
|   |-- <Ethernet> 1.0.0
|   |   |-- <SocketWrapper> 1.0
|   |-- <SPI>
|   |-- <WiFi> 1.0
|   |   |-- <SocketWrapper> 1.0
Building in release mode
Linking .pio/build/portenta_h7_m7/firmware.elf
.pio/build/portenta_h7_m7/src/main.cpp.o: In function `main':
main.cpp:(.text.startup.main+0xfc): undefined reference to `rclc_make_node_a_lifecycle_node(rclc_lifecycle_node_t*, rcl_node_t*, rcl_lifecycle_state_machine_t*, rcutils_allocator_t*, bool)'
main.cpp:(.text.startup.main+0x144): undefined reference to `rclc_lifecycle_init_get_state_server(rclc_lifecycle_node_t*, rclc_executor_t*)'
main.cpp:(.text.startup.main+0x154): undefined reference to `rclc_lifecycle_init_get_available_states_server(rclc_lifecycle_node_t*, rclc_executor_t*)'
main.cpp:(.text.startup.main+0x164): undefined reference to `rclc_lifecycle_init_change_state_server(rclc_lifecycle_node_t*, rclc_executor_t*)'
main.cpp:(.text.startup.main+0x17a): undefined reference to `rclc_lifecycle_register_on_configure(rclc_lifecycle_node_t*, int (*)())'
main.cpp:(.text.startup.main+0x182): undefined reference to `rclc_lifecycle_register_on_activate(rclc_lifecycle_node_t*, int (*)())'
main.cpp:(.text.startup.main+0x18a): undefined reference to `rclc_lifecycle_register_on_deactivate(rclc_lifecycle_node_t*, int (*)())'
main.cpp:(.text.startup.main+0x192): undefined reference to `rclc_lifecycle_register_on_cleanup(rclc_lifecycle_node_t*, int (*)())'
main.cpp:(.text.startup.main+0x1b2): undefined reference to `rclc_lifecycle_node_fini(rclc_lifecycle_node_t*, rcutils_allocator_t*)'
collect2: error: ld returned 1 exit status
*** [.pio/build/portenta_h7_m7/firmware.elf] Error 1
=============================================================================== [FAILED] Took 2.92 seconds ===============================================================================

Additional information

platformio.ini with fixed linker script:

# There are issues using platformio link against the static H7 uros library
# REFERENCE: https://github.com/micro-ROS/micro_ros_arduino/issues/774

[env:portenta_h7_m7]
platform = ststm32
board = portenta_h7_m7
framework = arduino
extra_scripts = fix_linker.py
monitor_speed = 9600
build_flags =
    -L ./.pio/libdeps/portenta_h7_m7/micro_ros_arduino/src/cortex-m7/fpv5-d16-softfp/
    -D TARGET_PORTENTA_H7_M7

lib_deps =
    https://github.com/micro-ROS/micro_ros_arduino

Not sure if it is helpful but running nm on libmicroros.a results in:

00000000 T rclc_lifecycle_change_state
00000000 T rclc_lifecycle_change_state_callback
00000000 T rclc_lifecycle_execute_callback
00000000 T rclc_lifecycle_get_available_states_callback
00000000 T rclc_lifecycle_get_state_callback
00000000 T rclc_lifecycle_init_change_state_server
00000000 T rclc_lifecycle_init_get_available_states_server
00000000 T rclc_lifecycle_init_get_state_server
00000000 T rclc_lifecycle_node_fini
00000000 T rclc_lifecycle_register_callback
00000000 T rclc_lifecycle_register_on_activate
00000000 T rclc_lifecycle_register_on_cleanup
00000000 T rclc_lifecycle_register_on_configure
00000000 T rclc_lifecycle_register_on_deactivate
00000000 T rclc_make_node_a_lifecycle_node
@pablogs9
Copy link
Member

pablogs9 commented Apr 1, 2022

rclc_lifecycle is not built in the micro-ROS library, check here

You can copy it to extra_packages folder and try to build it, but it is not tested nor validated in MCU environments. Maybe the maintainer @JanStaschulat can tell us more details.

@pablogs9 pablogs9 closed this as completed Apr 1, 2022
@tnagyzambo
Copy link
Author

tnagyzambo commented Apr 3, 2022

Thanks for the reply.

Unfortunately your suggestion does not work as there are package name conflicts.

ERROR:colcon:colcon build: Duplicate package names not supported:
- rclc_lifecycle:
  - extra_packages/rclc/rclc_lifecycle
  - uros/rclc/rclc_lifecycle

From my reading of the micro ros project website it suggests that this feature should be ready to use. Maybe there is a misunderstanding on my part. Since it seems that this is not limited to the Arduino library, is there a more appropriate place to continue this discussion?

@pablogs9
Copy link
Member

pablogs9 commented Apr 4, 2022

From my reading of the micro ros project website it suggests that this feature should be ready to use. Maybe there is a misunderstanding on my part. Since it seems that this is not limited to the Arduino library, is there a more appropriate place to continue this discussion?

The rclc repo

@pablogs9
Copy link
Member

pablogs9 commented Apr 5, 2022

Reopening until ros2/rclc#279 is merged and library is supported under C++ build

@pablogs9 pablogs9 reopened this Apr 5, 2022
@pablogs9
Copy link
Member

pablogs9 commented Apr 8, 2022

ros2/rclc#279 merged

@pablogs9 pablogs9 closed this as completed Apr 8, 2022
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