.. _enable-connext770-connext-rmw: Enabling Connext 7.7.0+ with Connext RMW ========================================= The *Connext* RMW, starting with the Lyrical release, has been optimized to allow for seamless integration with standalone *Connext* applications, with no additional configuration required. This is an ideal solution if you can update all applications in your ecosystem to *Connext* release 7.7.0+. This chapter introduces two tutorials designed to demonstrate how standalone *Connext* applications work with ROS 2 applications using *Connext* 7.7.0+ with *Connext* RMW. Before you begin ---------------- Before walking through the *Connext* RMW tutorials, ensure your system meets the following prerequisites: * The ROS 2 lyrical release is installed and the environment configured. See :ref:`ros-installation`. The following tutorials reference Ubuntu 26.04 (LTS); we recommend using this Linux distribution and installing via `Debian packages `__. If you are using a different architecture, substitute your platform for ``x64Linux4gcc8.5.0`` in the following examples. * An existing ROS 2 application that you can modify is available. The following exercises are based on the `Writing a simple publisher and subscriber (C++) `__ and `Creating custom msg and serv files `__ ROS 2 tutorials. You should complete both because the types and applications generated from these ROS 2 guides are used in the following *Connect* RMW examples. If you have your own existing application, substitute your types and topic names instead. * *Connext* 7.7.0+ and the *Connext* RMW are installed. The *Connext* installation provides the libraries needed by the *Connext* RMW. See :ref:`ros-connextrmw-install` for details. .. _pubsub-connext770-connext-rmw: Publisher/subscriber tutorial for Connext 7.7.0+ with Connext RMW ----------------------------------------------------------------- This tutorial demonstrates *Connext* application interoperability with ROS 2 using simple publisher and subscriber applications. This exercise is based on the `Writing a simple publisher and subscriber (C++) `__ ROS 2 tutorial, modified to use the *Connext* RMW. 1. Outside of your ROS 2 workspace, create a new directory named ``connext_ws.`` 2. Copy the IDL file for your ROS 2 ``msg`` type into the new directory: .. code-block:: bash cp /install/tutorial_interfaces/share/tutorial_interfaces/msg/Num.idl . 3. Configure your *Connext* environment (do not use the terminal where you configured your ROS 2 environment): .. code-block:: bash source /resource/scripts/rtisetenv_x64Linux4gcc8.5.0.bash 4. Generate your *Connext* example application: .. code-block:: bash rtiddsgen -example x64Linux4gcc8.5.0 -language c++11 Num.idl 5. Edit `Num_publisher.cxx` and `Num_subscriber.cxx` to set the topic name to “topic”: .. code-block:: c++ dds::topic::Topic< ::tutorial_interfaces::msg::Num> topic(participant, "topic"); 6. Compile your *Connext* application: .. code-block:: bash make -f makefile_x64Linux4gcc8.5.0 7. In one terminal, run the *Connext* subscriber: .. code-block:: bash ./objs/x64Linux4gcc8.5.0/Num_subscriber 8. In another terminal, run the ROS 2 publisher with the *Connext* RMW: .. code-block:: bash RMW_IMPLEMENTATION=rmw_connextdds ros2 run cpp_pubsub talker 9. Verify that the *Connext* subscriber application begins receiving data from the ROS 2 publisher application: .. code-block:: text ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... [num: 0] ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... [num: 1] ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... [num: 2] ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... [num: 3] Service/client tutorial for Connext 7.7.0+ with Connext RMW ----------------------------------------------------------- This tutorial demonstrates *Connext* 7.7.0+ application interoperability with ROS 2 using a simple service and client application. This exercise is based on the `Creating custom msg and serv files `__ ROS 2 tutorial, but modified to use the *Connext* RMW. 1. Outside of your ROS 2 workspace, create a new directory named ``connext_ws``. 2. Copy the request/reply example from the RTI workspace into your new directory: .. code-block:: bash cp -r /7.7.0/examples/connext_dds/c++11/hello_world_request_reply . 3. Copy the ROS 2 IDL into the source directory in the copied example: .. code-block:: bash cp /install/tutorial_interfaces/share/tutorial_interfaces/srv/AddThreeInts.idl hello_world_request_reply/src/ 4. Configure your *Connext* environment (do not use the terminal where you configured your ROS 2 environment): .. code-block:: bash source /resource/scripts/rtisetenv_x64Linux4gcc8.5.0.bash 5. Navigate to ``hello_world_request_reply/src`` and generate new type files using ``AddThreeInts.idl``: .. code-block:: bash cd hello_world_request_reply/src rtiddsgen -create typefiles -platform x64Linux4gcc8.5.0 -language c++11 AddThreeInts.idl 6. Make a copy of ``PrimeNumberRequester.cxx`` named ``AddThreeIntsRequester.cxx`` and a copy of ``PrimeNumberReplier.cxx`` named ``AddThreeIntsReplier.cxx``: .. code-block:: bash cp PrimeNumberRequester.cxx AddThreeIntsRequester.cxx cp PrimeNumberReplier.cxx AddThreeIntsReplier.cxx 7. Open ``AddThreeIntsRequester.cxx`` and make the following changes to use the ``AddThreeInts`` type instead of the ``primes`` type: .. note:: ``require_matching_service_on_send_request`` must be set to false in the ``RequesterParams``, and ``requester.wait_for_service`` cannot be used when seeking interoperability with ROS 2 applications as they may not include support for ``related_datareader_key`` and ``related_datawriter_key``. .. code-block:: c++ /****************************************************************************/ /* (c) Copyright, Real-Time Innovations, All rights reserved. */ /* */ /* Permission to modify and use for internal purposes granted. */ /* This software is provided "as is", without warranty, express or implied. */ /* */ /****************************************************************************/ #include "AddThreeInts.hpp" // generated support for the request and reply types #include // full request-reply API #include // for sleep() #include // Logger to configure logging verbosity class AddThreeIntsRequesterExample { private: dds::domain::DomainParticipant participant; public: explicit AddThreeIntsRequesterExample(int domain_id) : participant( domain_id, dds::core::QosProvider::Default().participant_qos("RequestReplyExampleProfiles::ParticipantExampleProfile")) { } void run_example(int x, int y, int z) { const auto max_wait = dds::core::Duration::from_secs(20); // Create the Requester with the participant, a service name (which has // be the same as the one used in the Replier) and optionally a QoS // profile (defined in USER_QOS_PROFILES.xml). rti::request::RequesterParams requester_params(participant); auto qos_provider = dds::core::QosProvider::Default(); requester_params.service_name("add_three_ints"); requester_params.require_matching_service_on_send_request(false); rti::request::Requester requester( requester_params); // Wait for a service to be available sleep(2); // Send the request auto request_id = requester.send_request(tutorial_interfaces::srv::AddThreeInts_Request(x, y, z)); // Receive replies bool in_progress = true; while (in_progress) { auto replies = requester.receive_replies(max_wait); // When receive_replies times out, // it returns an empty reply collection if (replies.length() == 0) { throw std::runtime_error("Timed out waiting for replies"); return; } // Print the prime numbers we receive for (const auto& reply : replies) { if (!reply.info().valid()) { continue; } std:: cout << "Received sum " << reply.data().sum() << std::endl; } } } }; int requester_main(int x, int y, int z, int domain_id) { std::cout << "AddThreeIntsRequester: Sending a request to calculate the " << "sum of " << x << ", " << y << ", " << z << std::endl; try { AddThreeIntsRequesterExample(domain_id).run_example(x, y, z); } catch (const std::exception& ex) { std::cout << "Exception: " << ex.what() << std::endl; return -1; } return 0; } #if !(defined(RTI_VXWORKS) && !defined(__RTP__)) && !defined(RTI_PSOS) int main(int argc, char *argv[]) { int domain_id = 0; int x, y, z; if (argc < 4) { std::cout << "AddThreeIntsRequester" << std::endl << "Sends a request to calculate the sum" << std::endl << "Parameters: [=0]" << std::endl; return -1; } x = atoi(argv[1]); y = atoi(argv[2]); z = atoi(argv[3]); if (argc > 4) { domain_id = atoi(argv[4]); } return requester_main(x, y, z, domain_id); } #endif 8. Open ``AddThreeIntsReplier.cxx`` and make the following changes to use the ``AddThreeInts`` type instead of the ``primes`` type: .. code-block:: c++ /****************************************************************************/ /* (c) Copyright, Real-Time Innovations, All rights reserved. */ /* */ /* Permission to modify and use for internal purposes granted. */ /* This software is provided "as is", without warranty, express or implied. */ /* */ /****************************************************************************/ #include "AddThreeInts.hpp" // generated support for the request and reply types #include // full request-reply API #include // Logger to configure logging verbosity #include class AddThreeIntsReplierExample { private: dds::domain::DomainParticipant participant; public: explicit AddThreeIntsReplierExample(int domain_id) : participant( domain_id, dds::core::QosProvider::Default().participant_qos("RequestReplyExampleProfiles::ParticipantExampleProfile")) { } private: void calculate_and_send_sum( rti::request::Replier replier, const rti::sub::LoanedSample& request) { int64_t a = static_cast(request.data().a()); int64_t b = static_cast(request.data().b()); int64_t c = static_cast(request.data().c()); tutorial_interfaces::srv::AddThreeInts_Response reply; reply.sum() = a + b + c;; replier.send_reply(reply, request.info()); } public: void run_example() { // Create the Replier with the participant, a service name and // optionally a QoS profile (defined in USER_QOS_PROFILES.xml). auto qos_provider = dds::core::QosProvider::Default(); rti::request::ReplierParams replier_params(participant); replier_params.service_name("add_three_ints"); rti::request::Replier replier( replier_params); // Receive requests and process them const auto MAX_WAIT = dds::core::Duration::from_secs(20); auto requests = replier.receive_requests(MAX_WAIT); while (requests.length() > 0) { // end the requester when no requests // received in MAX_WAIT for (const auto& request : requests) { if (!request.info().valid()) { continue; } std::cout << "Calculating sum of " << request.data().a() << ", " << request.data().b() << ", " << request.data().c() << std::endl; calculate_and_send_sum(replier, request); std::cout << "Sent reply" << std::endl; } requests = replier.receive_requests(MAX_WAIT); } } }; int replier_main(int domain_id) { rti::config::Logger::instance().verbosity( rti::config::Verbosity::WARNING); std::cout << "AddThreeIntsReplier running (on domain " << domain_id << ")" << std::endl; try { AddThreeIntsReplierExample(domain_id).run_example(); } catch (const std::exception& ex) { std::cout << "Exception: " << ex.what() << std::endl; return -1; } return 0; } #if !(defined(RTI_VXWORKS) && !defined(__RTP__)) && !defined(RTI_PSOS) int main(int argc, char *argv[]) { int domain_id = 0; if (argc > 1) { domain_id = atoi(argv[1]); } return replier_main(domain_id); } #endif 9. Modify ``USER_QOS_PROFILES.xml`` to include a *DomainParticipant* QoS profile. Also remove the existing snippets that set the Durability on the reader and writer (otherwise the endpoints may be incompatible with the ROS 2 endpoints): .. code-block:: xml 10. Modify ``make/makefile_RequestReplyPrimes_x64Linux4gcc8.5.0`` to compile ``AddThreeInts`` code: .. code-block:: makefile ###################################################################### # makefile_Primes_x64Linux4gcc8.5.0# # (c) Copyright, Real-Time Innovations, 2012. All rights reserved. # RTI grants Licensee a license to use, modify, compile, and create # derivative works of the software solely for use with RTI Connext DDS. # Licensee may redistribute copies of the software provided that all such # copies are subject to this license. The software is provided "as is", # with no warranty of any type, including any warranty for fitness for # any purpose. RTI is under no obligation to maintain or support the # software. RTI shall not be liable for any incidental or consequential # damages arising out of the use or inability to use the software. # # # This makefile was automatically generated by RTI Code Generator (rtiddsgen) # version 4.4.0. # # # Note: This makefile is only meant to build our example applications and # may require alterations to build on your system. # # This makefile assumes that your build environment is already correctly # configured. (For example, the correct version of your compiler and # linker should be in your PATH.) ###################################################################### SOURCE_DIR = src/ TARGET_ARCH = x64Linux4gcc8.5.0 #TOOLSROOT = # Set the location of the toolchain #COMPILERSYSROOT = $(TOOLSROOT)/build/tmp/sysroots/genericx86-64 #COMPILER_PATH = $(TOOLSROOT)/build/tmp/sysroots/x86_64-linux/usr/bin/x86_64-wrs-linux ifndef COMPILER COMPILER = $(COMPILER_PATH)$(GCC_PREFIX)g++ endif COMPILER_FLAGS = -m64 -Wall $(ADDITIONAL_COMPILER_FLAGS) -std=c++14 ifndef LINKER LINKER = $(COMPILER_PATH)$(GCC_PREFIX)g++ endif LINKER_FLAGS = -m64 $(ADDITIONAL_LINKER_FLAGS) SYSLIBS = -ldl -lm -lpthread -lrt -no-pie -rdynamic DEFINES = -DRTI_UNIX -DRTI_LINUX -DRTI_64BIT ifndef DEBUG DEBUG=0 endif ifeq ($(DEBUG),1) COMPILER_FLAGS += -g -O0 LINKER_FLAGS += -g DEBUG_SFX = d else DEBUG_SFX = endif ifndef SHAREDLIB SHAREDLIB=0 endif ifeq ($(SHAREDLIB),1) SHAREDLIB_SFX = STATIC_LIBRARIES = else SHAREDLIB_SFX = z DEFINES += -DRTI_STATIC endif INCLUDES = -I. -I$(NDDSHOME)/include -I$(NDDSHOME)/include/ndds -I$(NDDSHOME)/include/ndds/hpp LIBS = -L$(NDDSHOME)/lib/x86_64Linux \ LIBS += -lrticonnextmsgcpp2$(SHAREDLIB_SFX)$(DEBUG_SFX) LIBS += -lnddscpp2$(SHAREDLIB_SFX)$(DEBUG_SFX) -lnddsc$(SHAREDLIB_SFX)$(DEBUG_SFX) -lnddscore$(SHAREDLIB_SFX)$(DEBUG_SFX) \ \ $(STATIC_LIBRARIES) $(SYSLIBS) CDRSOURCES = AddThreeInts.idl SOURCES = $(SOURCE_DIR)AddThreeIntsPlugin.cxx $(SOURCE_DIR)AddThreeInts.cxx COMMONSOURCES = $(notdir $(SOURCES)) EXEC = AddThreeIntsReplier AddThreeIntsRequester DIRECTORIES = objs.dir objs/$(TARGET_ARCH).dir COMMONOBJS = $(COMMONSOURCES:%.cxx=objs/$(TARGET_ARCH)/%.o) # We actually stick the objects in a sub directory to keep your directory clean. $(TARGET_ARCH) : $(DIRECTORIES) $(COMMONOBJS) \ $(EXEC:%=objs/$(TARGET_ARCH)/%.o) \ $(EXEC:%=objs/$(TARGET_ARCH)/%) objs/$(TARGET_ARCH)/% : objs/$(TARGET_ARCH)/%.o $(LINKER) $(LINKER_FLAGS) -o $@ $@.o $(COMMONOBJS) $(LIBS) objs/$(TARGET_ARCH)/%.o : $(SOURCE_DIR)%.cxx $(SOURCE_DIR)AddThreeInts.hpp $(COMPILER) $(COMPILER_FLAGS) -o $@ $(DEFINES) $(INCLUDES) -c $< # # Uncomment these lines if you want the support files regenerated when idl # file is modified # # # $(SOURCE_DIR)PrimesPlugin.cxx $(SOURCE_DIR)Primes.cxx \ # $(SOURCE_DIR)Primes.hpp $(SOURCE_DIR)PrimesPlugin.hpp $(SOURCE_DIR)application.hpp : \ # $(SOURCE_DIR)Primes.idl # $(NDDSHOME)/bin/rtiddsgen $(SOURCE_DIR)Primes.idl -replace -language C++11 # # Here is how we create those subdirectories automatically. %.dir : @echo "Checking directory $*" @if [ ! -d $* ]; then \ echo "Making directory $*"; \ mkdir -p $* ; \ fi; 11. Compile the ``AddThreeInts`` Requester and Replier: .. code-block:: bash make -f make/makefile_x64Linux4gcc8.5.0 12. Launch the *Connext* ``AddThreeInts`` Replier: .. code-block:: bash ./objs/x64Linux4gcc8.5.0/AddThreeIntsReplier 13. Launch the ROS 2 client with the *Connext* RMW: .. code-block:: bash RMW_IMPLEMENTATION=rmw_connextdds ros2 run cpp_srvcli client 41 1 1 14. Verify the request is received and processed. - *Connext* output: .. code-block:: text AddThreeIntsReplier running (on domain 0) Calculating sum of 41, 1, 1 Sent reply - ROS 2 output: .. code-block:: text [INFO] [time] [rclcpp]: Sum: 43 15. Terminate the applications, then launch the *Connext* ``AddThreeInts`` Requester: .. code-block:: bash ./objs/x64Linux4gcc8.5.0/AddThreeIntsRequester 41 1 1 16. Launch the ROS 2 server with the *Connext* RMW: .. code-block:: bash RMW_IMPLEMENTATION=rmw_connextdds ros2 run cpp_srvcli server 17. Verify the request is received and processed. - *Connext* output: .. code-block:: text AddThreeIntsRequester: Sending a request to calculate the sum of 1, 2, 3 Received sum 6 - ROS 2 output: .. code-block:: text [INFO] [time] [rclcpp]: Ready to add three ints [INFO] [time] [rclcpp]: Incoming request a: 1 b: 2 c: 3 [INFO] [time] [rclcpp]: sending back response: [6]