Using RTI Connext DDS on the NVIDIA Jetson Nano
Preface: The vast majority of this article was extracted from a White Paper that RTI's Don Gochenour originally authored. Don is a Senior Application Engineer with extensive knowledge in embedded systems and RTI's products. Don is located on the East coast of the US.
Introduction
This content piece illustrates how to cross-compile a basic DDS HelloWorld application on a Linux host and run it on the Jetson Nano embedded target.
This will be illustrated on DDS Professional (6.0.1) and DDS Micro (3.0.2) --- the steps are very similar.
Content is broken into the following sections:
NVIDIA Jetson Nano
Preparing the Target
Preparing the Development Host
Using Connext DDS Professional 6.0.1
Installing the Target Libraries
Generating an Example Application and Type Support Code
Updating the Generated Makefile
Building the Example Application
Using Connext DDS Micro 3.0.2
Adding a Toolchain File
Building the Libraries
Generating an Example Application and Type Support Code
Building the Example Application
Note: It is also possible to build directly on the target rather than cross-compiling on a host and downloading to the target, as described in this article. See the following community article for details: How do I create a Connext DDS application with RTI Code Generator and build it on my ARM-embedded target?
NVIDIA Jetson Nano
The Jetson Nano Developer Kit is a development board based on a quad-core ARM Cortex-A57 (CPU) and an NVIDIA Maxwell with 128 NVIDIA CUDA cores (GPU).
While the CPU puts the Nano in a class similar to the Raspberry Pi 3B, the Maxwell GPU makes the Jetson a useful board to use in AI applications such as vision recognition.
Preparing the Target
It is assumed you have programmed the Jetson with the standard Ubuntu 18.04 JetPack Image as described in the Jetson Getting Started Guides. The steps should be the same as on other operating systems such as Raspian.
Preparing the Development Host
Because cross-development for the ARM architecture is usually easiest on Linux, this document discusses the steps required when working with an Ubuntu 18.04 host.
Before any software--either applications or libraries--can be compiled for the Nano, we will need to install an appropriate ARM toolchain on the host. ARM itself maintains a site where you can download a GNU Toolchain for the A-profile Architecture.
As mentioned previously, the Nano is based on the Cortex-A57, so at the time of this writing, the appropriate toolchain would be the gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz package. Download this package and extract it to the location of your choice, as shown below. In this document, we will assume /opt as the target location:
$tar -xJf gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu.tar.xz -C /opt
Using Connext DDS Professional 6.0.1
The following assumptions are made:
Connext DDS Professional 6.0.1 is already installed on your host
The $NDDSHOME environment variable is set to your Connext DDS Professional 6.0.1 installation directory
$NDDSHOME/bin is included in your PATH
Installing the Target Libraries
With Connext DDS Professional 6.0.1 already on the host, the only additional RTI package that needs to be installed is a set of libraries appropriate for targets running Linux on ARMv8. While none of the standard, downloadable libraries were designed explicitly for the Jetson Nano, the target-armv8Linux4.4gcc5.4.0 libraries will work; the appropriate *.rtipkg file is available in the Download section of the RTI Support Portal - https://support.rti.com/. In order to download RTI packages, you must have an account on the support portal and you must be licensed for the architecture of interest; otherwise the packages will not be visible to you.
Generating an Example Application and Type Support Code
We will create an IDL and example application to demonstrate a working build. In this example, consider a simple IDL file named my_type.idl, with the following contents:
my_type.idl
|
Type support code, example application source, and the Makefile necessary to build the example can be created with the following command. Note that this generated example uses C++11 and STL’s std::vector.
$ cd /path/to/your/project/dir
$ $NDDSHOME/bin/rtiddsgen -ppDisable -language C++11 -create typefiles -create examplefiles -create makefiles -platform armv8Linux4.4gcc5.4.0 -unboundedSupport -alwaysUseStdVector ./my_type.idl
Updating the Generated Makefile
After completing the previous step, the project directory is now populated with the source, header, and XML files, as well as a makefile named makefile_my_type_armv8Linux4.4gcc5.4.0. Opening this file in an editor, you will see a block of code similar to that shown below:
ifndef COMPILER
COMPILER = g++
endif
COMPILER_FLAGS = -std=c++0x
ifndef LINKER
LINKER = g++
endif
The COMPILER and LINKER variables need to be set to match the ARM toolchain binaries instead of the default gcc/g++ binaries on the host, which target the native architecture of the host. There are a few different ways to point Make to the proper compiler and linker:
Pass the values of these variables on the command line when calling make.
Make sure that the desired compiler and linker is found first in your PATH environment variable.
Modify the makefile.
In this case, we will choose #3: modify the makefile.
This choice is made based on the fact that we plan to build this application only for the armv8Linux4.4gcc5.4.0 architecture. Make the following change to the makefile:
ifndef COMPILER
COMPILER = /opt/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
endif
COMPILER_FLAGS = -std=c++0x
ifndef LINKER
LINKER = /opt/gcc-arm-9.2-2019.12-x86_64-aarch64-none-linux-gnu/bin/aarch64-none-linux-gnu-g++
endif
Additionally, the default linker arguments need to be changed. In previous versions of glibc, libnsl was provided as part of glibc itself, but this is no longer true in recent versions, such as the one used by the ARM toolchain in this document. In fact, Connext DDS has no dependency on this library and enhancement request PLATFORMS-1764 exists to track the removal of the -lnsl reference from the generated makefiles. In the current release, we can fix this manually in makefile_my_type_armv8Linux4.4gcc5.4.0 by simply making the following change:
From this:
SYSLIBS = -lnsl -ldl -lm -lpthread -lrt
To this:
SYSLIBS = -ldl -lm -lpthread -lrt
Building the Example Application
From your project directory, call make as shown below:
$ make -f makefile_my_type_armv8Linux4.4gcc5.4.0
The cross-compiled my_type_publisher and my_type_subscriber files can now be moved to the target and run.
Using Connext DDS Micro 3.0.2
The Micro product is delivered as source, thus the product libraries must be built before any user application can link against them. Micro supports CMake builds, and also supports targeting Linux in general, so making the leap to Linux on the Cortex-A57 is painless. In this document, the name of the architecture (are libraries) will be armv8Linux4gcc921.
The following assumptions are made:
Connext DDS Micro 3.0.2 is already installed on your host
CMake® is installed on your host and is in your $PATH
The $RTIMEHOME environment variable is set to your Micro 3.0.2 installation directory
Adding a Toolchain File
Out of the box, the Micro 3.0.2 release supports building for a number of CPU/OS combinations under CMake, but Linux on armv8 (the underlying architecture of the A57) is not one of them. This can be fixed by creating and adding a single file to the Micro installation.
In the $RTIMEHOME/resource/cmake/architectures directory you will see a number of *.tc files; these are CMake toolchain files that let the build system know where to find the appropriate C and C++ compilers for a given architecture (among other things.) Because it doesn’t exist yet, we need to create a file in this directory called armv8Linux4gcc921.tc. Create that file and give it the following contents:
armv8Linux4gcc921.tc
|
Building the Libraries
With the newly created toolchain file in place, building the Micro platform libraries is simple. Use the following three commands: (1) change to the Micro installation directory, (2) build the Debug version of the libraries, and (3) build the Release libraries.
$ cd $RTIMEHOME
$ ./resource/scripts/rtime-make --target armv8Linux4gcc921 --name armv8Linux4gcc921 -G "Unix Makefiles" --build --config Debug $
./resource/scripts/rtime-make --target armv8Linux4gcc921 --name armv8Linux4gcc921 -G "Unix Makefiles" --build --config Release
Generating an Example Application and Type Support Code
We will create an IDL and an example application to demonstrate a working build. In this example, consider a simple IDL file named my_type.idl and with the following contents:
my_type.idl
|
Type support code, example application source, and the CMake files necessary to build the example can be created with the following command. Note that this example uses C++, with namespaces.
$ cd /path/to/your/project/dir
$ $RTIMEHOME/rtiddsgen/scripts/rtiddsgen -micro -language C++ -namespace -create typefiles -create examplefiles -create makefiles ./my_type.idl
Building the Example Application
The previous step--generating the source code and CMake files--did not create anything that is platform specific. Now that those files exist, we can build the user project, specifying the architecture for which we want to target (armv8Linux4gcc921 in this case.)
The following command builds an executable linked against the Release configuration of the Micro libraries:
$ $RTIMEHOME/resource/scripts/rtime-make --config Release --build --name armv8Linux4gcc921 --target armv8Linux4gcc921 --source-dir . -G "Unix Makefiles" --delete
Inspecting one of the executables produced confirms that it is intended for the correct architecture:
$ file objs/armv8Linux4gcc921/my_type_publisher
my_type_publisher: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 3.7.0, with debug_info, not stripped
The cross-compiled binaries my_type_publisher and my_type_subscriber files can now be moved to the target and executed.