.. _enable-connext750-any-rmw: Enabling Connext 7.5.0 or Later with any ROS RMW ================================================ It is easy to enable compatibility with standalone |CONNEXT| 7.5.0 or later applications, even with non-Connext RMWs. This approach requires no changes to existing applications, and is configurable through simple XML changes. .. note:: These instructions are for using standalone |CONNEXT| applications with ROS 2 applications, regardless of the RMW used. This approach is ideal if you have an existing ROS 2 system that you cannot change, but you want to utilize the many features of |CONNEXT| in additional applications. Ensure these prerequisites: * **ROS 2 Kilted** It is recommended to use Ubuntu 24.04 (LTS) and `Debian packages `__ for installation, since this platform is referenced throughout the examples. Substitute your platform for ``x64Linux4gcc7.3.0`` throughout the examples if you are using another architecture. * **Existing ROS 2 application** The examples throughout this document are based on the `Writing a simple publisher and subscriber (C++) `__ and `Creating custom msg and serv files `__ (using the ``cpp_pubsub`` package with the generated Num type) ROS 2 tutorials. If you have your own existing application, you should substitute your own types and topic names throughout the examples. * **Connext 7.5.0 or later** Only your standalone |CONNEXT| applications must use |CONNEXT| 7.5.0 or later. That is, your ROS 2 application does not need to use the |CONNEXT| RMW at all or, if it does, the |CONNEXT| RMW can be any version, but your standalone |CONNEXT| application interoperating with your ROS 2 application must be 7.5.0 or later. You can purchase |CONNEXT| 7.5.0 (email sales@rti.com for more information) or `download a free version `__. .. _pubsub-connext750-rmw: Publisher/Subscriber Tutorial for Connext 7.5.0+ with any ROS RMW ----------------------------------------------------------------- 1. Create a new directory (outside of your ROS 2 workspace) called ``connext_ws``. 2. Navigate into the directory and copy the IDL file for your ROS 2 type into the newly created directory: .. code-block:: bash mkdir ~/connext_ws cd ~/connext_ws cp /install/tutorial_interfaces/share/tutorial_interfaces/msg/Num.idl . 3. Configure your |CONNEXT| environment (note: it is recommended to do this in a separate terminal from the one where you have configured your ROS 2 environment): .. code-block:: bash source /resource/scripts/rtisetenv_x64Linux4gcc7.3.0.bash 4. Generate your |CONNEXT| example application: .. code-block:: bash rtiddsgen -example x64Linux4gcc7.3.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_x64Linux4gcc7.3.0 7. In one terminal, run the |CONNEXT| subscriber: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/Num_subscriber 8. In another terminal, run the ROS 2 publisher: .. code-block:: bash ros2 run cpp_pubsub talker 9. Verify the |CONNEXT| subscriber does not receive data from the ROS 2 publisher: .. code-block:: text ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... ::tutorial_interfaces::msg::Num subscriber sleeping up to 1 sec... 10. Terminate both applications with Ctrl-C. 11. In one terminal, run the |CONNEXT| publisher: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/Num_publihser 12. In another terminal, run the ROS 2 subscriber: .. code-block:: bash ros2 run cpp_pubsub listener 13. Verify the ROS 2 subscriber does not receive data from the |CONNEXT| publisher (there will be no output). 14. Terminate both applications with Ctrl-C. 15. Open ``USER_QOS_PROFILES.xml`` and add the following to the `` tag: .. code-block:: xml dds.ros.enable_interoperability TRUE 16. Relaunch the |CONNEXT| subscriber application: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/Num_subscriber 17. Relaunch the ROS 2 publisher application: .. code-block:: bash ros2 run cpp_pubsub talker 18. Verify that the |CONNEXT| subscriber application now starts 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] 19. Terminate the applications. 20. In one terminal, run the |CONNEXT| publisher: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/Num_publisher 21. In another terminal, run the ROS 2 subscriber: .. code-block:: bash ros2 run cpp_pubsub listener 22. Verify the ROS 2 subscriber receives data: .. code-block:: text [INFO] [1738350344.675343878] [minimal_subscriber]: I heard: '1' [INFO] [1738350345.672977712] [minimal_subscriber]: I heard: '2' 23. Terminate both applications with Ctrl-C. Service/Client Tutorial for Connext 7.5.0+ with any ROS RMW ----------------------------------------------------------- 1. Create a new directory (outside of your ROS 2 workspace) called ``connext_ws``. 2. Copy the request/reply example from the RTI workspace into your new directory: .. code-block:: bash mkdir ~/connext_ws cd ~/connext_ws cp -r /7.5.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 (note: it is recommended to do this in a separate terminal from the one where you have configured your ROS 2 environment): .. code-block:: bash source /resource/scripts/rtisetenv_x64Linux4gcc7.3.0.bash 5. Navigate into ``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 x64Linux4gcc7.3.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 Prime 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 other DDS vendors. .. 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 Prime 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 and 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_x64Linux4gcc7.3.0`` to compile AddThreeInts code: .. code-block:: text ###################################################################### # makefile_Primes_x64Linux4gcc7.3.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.5.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 = x64Linux4gcc7.3.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/\(TARGET\_ARCH\) 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 \= AddThreeIntsRequester AddThreeIntsReplier 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_RequestReplyPrimes_x64Linux4gcc7.3.0 12. Launch the |CONNEXT| AddThreeInts Replier: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/AddThreeIntsReplier 13. Launch the ROS 2 client: .. code-block:: bash ros2 run cpp_srvcli client 1 2 3 14. Verify the |CONNEXT| application does not receive the request and the ROS 2 client does not receive a reply. |CONNEXT| output: .. code-block:: text AddThreeIntsReplier running (on domain 0) ROS 2 output: .. code-block:: text [INFO] [time] [rclcpp]: service not available, waiting again... [INFO] [time] [rclcpp]: service not available, waiting again... [INFO] [time] [rclcpp]: service not available, waiting again... [INFO] [time] [rclcpp]: service not available, waiting again... 15. Terminate the applications. Launch the |CONNEXT| AddThreeInts Requester: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/AddThreeIntsRequester 1 2 3 16. Launch the ROS 2 server: .. code-block:: bash ros2 run cpp_srvcli server 17. Verify the ROS 2 server does not receive a request and the |CONNEXT| application does not receive a reply. ROS 2 output: .. code-block:: text [INFO] [time] [rclcpp]: Ready to add three ints |CONNEXT| output: .. code-block:: text AddThreeIntsRequester: Sending a request to calculate the sum of 1, 2, 3 18. Enable ROS 2 interoperability by setting ``dds.ros.enable_interoperability`` in ``USER_QOS_PROFILES.xml``: .. code-block:: xml dds.ros.enable_interoperability TRUE 19. Launch the |CONNEXT| AddThreeInts Replier: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/AddThreeIntsReplier 20. Launch the ROS 2 client: .. code-block:: bash ros2 run cpp_srvcli client 1 2 3 21. Verify the request is received and processed: |CONNEXT| output: .. code-block:: text AddThreeIntsReplier running (on domain 0) Calculating sum of 1, 2, 3 Sent reply ROS 2 output: .. code-block:: bash [INFO] [time] [rclcpp]: Sum: 43 22. Terminate the applications. Launch the |CONNEXT| AddThreeInts Requester: .. code-block:: bash ./objs/x64Linux4gcc7.3.0/AddThreeIntsRequester 23. Launch the ROS 2 server: .. code-block:: bash ros2 run cpp_srvcli server 24. Verify the request is received and processed: ROS 2 output: .. code-block:: bash [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] |CONNEXT| output: .. code-block:: bash AddThreeIntsRequester: Sending a request to calculate the sum of 1, 2, 3 Received sum 6