Madahin's Dev

Micro-XRCE-DDS : CMake integration

- markdown

With a group of friends, we are planning to participate in a French competition named Coupe de France de robotique. Precisely, the 2022 edition. It is a competition aimed at amateurs whose goal is to build an autonomous robot who will need to complete some tasks. Obviously, these tasks change each year and are only revealed a few months before the beginning of the competition.

For now, our goal is to build a moving base with a minimum set of capters used in practically every others edition.

My current role in the project is to write the communication block that will be in charge of the dialogue between the microcontroller (nucleo-F446RE) and the brain (Raspberry Pi).

To ensure data integrity and ease of communication, we choose to use eProsima Micro XRCE-DDS, which come with a lot of freebies.

Since it was the first time I used Micro-XRCE, a lot of googling ensued. In hope of sparing some of you the pain of reading documentation, and because I thought it would be a nice exercice, I decided to write a series of articles about the basics of Micro-XRCE on a microcontroller: installation, serial communication and topic development.

Micro-XRCE and CMake

The first thing to do is to include Micro-XRCE in our project. Since we are using CMake, the integration should be relativly painless. Unfortunately, even though Micro-XRCE use some kind of superbuild paradigm, its use of ExternalProject make it really bothersome to use as a dependency.

To include it into the project, I used the magic of FetchContent. You can find more info about this feature on this really good article by Elias Daler.

Basically, the first thing you need to do is include the extension into your CMakeLists.txt:

include(FetchContent)

Then, you call FetchContent_Declare on each dependencies you want to include. I prefer to put the dependency version in a variable, for maintenance purpose:

set(dds-xrce_VERSION v2.0.0)
set(micro-cdr_VERSION v1.2.1)

FetchContent_Declare(
        micro-cdr
        GIT_REPOSITORY https://github.com/eProsima/Micro-CDR.git
        GIT_TAG        ${micro-cdr_VERSION}
)

FetchContent_Declare(
        dds-xrce
        GIT_REPOSITORY https://github.com/eProsima/Micro-XRCE-DDS-Client.git
        GIT_TAG        ${dds-xrce_VERSION}
)

As you can see, in addition to Micro-XRCE, I also included Micro-CDR. This is because since we are using FetchContent, Micro-XRCE superbuild wont download is own dependencies.

Next, we need to actually fetch our dependencies:

FetchContent_GetProperties(micro-cdr)
if(NOT micro-cdr_POPULATED)
    message(STATUS "Fetching Micro-SDR ${micro-cdr_VERSION}")
    FetchContent_Populate(micro-cdr)
    add_subdirectory(${micro-cdr_SOURCE_DIR} ${micro-cdr_BINARY_DIR} EXCLUDE_FROM_ALL)

    # Check config.h.in and set your variables here

    configure_file(${micro-cdr_SOURCE_DIR}/include/ucdr/config.h.in ${micro-cdr_SOURCE_DIR}/include/ucdr/config.h)
endif()

FetchContent_GetProperties(dds-xrce)
if(NOT dds-xrce_POPULATED)
    message(STATUS "Fetching DDS-XRCE ${dds-xrce_VERSION}")

    FetchContent_Populate(dds-xrce)
    add_subdirectory(${dds-xrce_SOURCE_DIR} ${dds-xrce_BINARY_DIR} EXCLUDE_FROM_ALL)

    # Check config.h.in and set your variables here

    configure_file(${dds-xrce_SOURCE_DIR}/include/uxr/client/config.h.in ${dds-xrce_SOURCE_DIR}/include/uxr/client/config.h)
endif()

Finally, we can add the sources to our project. Because we are using a microcontroller, there is a lot of things we don't want or that simply wont compile like network support (tcp/udp) or discovery. If your client run on a more linux-like system, you probably want to include every source file.

file(GLOB_RECURSE SOURCES
        "${micro-cdr_SOURCE_DIR}/src/*.*"
        "${dds-xrce_SOURCE_DIR}/src/c/core/*.*"
        "${dds-xrce_SOURCE_DIR}/src/c/util/*.*"
        "${dds-xrce_SOURCE_DIR}/src/c/profile/transport/serial/serial_protocol.c"
        "${dds-xrce_SOURCE_DIR}/src/c/profile/transport/serial/serial_transport.c"
        "${dds-xrce_SOURCE_DIR}/src/c/profile/transport/stream_framing/stream_framing_protocol.c"
)

On the next article, we will see how to use Micro-XRCE custom serial communication with DMA backed UART.