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

Add fastrtps (Fast-DDS) as supported dds middleware #148

Open
wants to merge 14 commits into
base: main
Choose a base branch
from

Conversation

henriksod
Copy link
Contributor

@henriksod henriksod commented Jul 29, 2023

As requested in this discussion #145

This is an attempt to add Fast-DDS as a supported dds middleware to this repo. I am using versions compatible with ROS2 Humble.

Added repo dependencies:

  • foonathan_memory 0.7-3
  • fastcdr 1.1.0
  • fastrtps 2.6.2
  • rmw_fastrtps 6.2.3
  • rosidl_typesupport_fastrtps 2.2.1

I have added a build flag dds_vendor, which will be cyclonedds by default. It controls a switch in rmw_implementation.BUILD.bazel.
This is how you can set it to use fastdds instead:

# To use FastDDS, invoke Bazel with `--config=fastdds`.
build:fastdds --@com_github_mvukov_rules_ros2//ros2:dds_vendor=fastdds

@henriksod henriksod force-pushed the main branch 2 times, most recently from dda45f1 to 49ce3de Compare July 29, 2023 07:24
@henriksod
Copy link
Contributor Author

I tried to fix the typesupport generation in interfaces.bzl, but getting errors of detail__* and time__* files not generated. Typesupport for fastrtps doesn't have those.

)


ros2_cpp_binary(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, fastdds supports two modes per https://fast-dds.docs.eprosima.com/en/latest/fastdds/ros2/ros2.html#ros-2-using-fast-dds-middleware:

  • rmw_fastrtps_dynamic_cpp that can use introspection-based type-support that we already have. This one should be easy to integrate. cyclonedds rmw uses introspection-based type-support.
  • rmw_fastrtps_cpp that uses their custom type-support. This is involved as fastdds-specific IDL code generation needs to be implemented.

This is for rclc/rclcpp part, I think. I'm not 100% sure, should be checked, which type-support rclpy expects/can work with.

My take: as a first step, if it suits your needs, just integrate rmw_fastrtps_dynamic_cpp.

If we want to go with rmw_fastrtps_cpp then we will also need to use dds_vendor switch in IDL code-generation, to only generate what's necessary. This might get involved -- haven't studied what generated code fastdds needs.

Please let me know what you think.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will switch it to dynamic instead. I tried this before, but didn't have improving results. Let's see if I can make it work!

load("@com_github_mvukov_rules_ros2//ros2:cc_defs.bzl", "ros2_cpp_library")

string_flag(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move this and the two config settings to //ros2/BUILD.bazel. Where this is actually used is an implementation detail from user perspective, IMO.

@@ -45,11 +45,22 @@ jobs:
toolchain:
- "gcc"
- "clang"
dds_vendor:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CI changes are OK, but lets leave this for a follow-up. For instance, I have to check how much buildbuddy remote cache we use and not overspend on it.

Comment on lines 34 to 20
data = select(
{
":use_cyclonedds": ["@ros2_rmw_cyclonedds//:rmw_cyclonedds"],
":use_fastdds": ["@ros2_rmw_fastrtps//:rmw_fastrtps"],
},
no_match_error = "Unsupported dds vendor",
),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

@henriksod
Copy link
Contributor Author

Switched to rmw_fastrtps_dynamic_cpp.

Getting a new, a bit more descriptive error:

Executing tests from //ros2/test:generic_publisher_tests
-----------------------------------------------------------------------------
[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from TestGenericPublisher
[ RUN      ] TestGenericPublisher.WhenPublisherDeletedInThread_EnsureCleanNodeCleanup

>>> [rcutils|error_handling.c:108] rcutils_set_error_state()
This error state is being overwritten:

  'Unknown typesupport identifier, at external/ros2_rmw_fastrtps/rmw_fastrtps_dynamic_cpp/src/type_support_registry.cpp:93'

with this new error message:

  'create_publisher() failed to get message_type_support, at external/ros2_rmw_fastrtps/rmw_fastrtps_dynamic_cpp/src/publisher.cpp:181'

rcutils_reset_error() should be called after error handling to avoid this.
<<<
unknown file: Failure
C++ exception with description "failed to initialize rcl node: error not set, at external/ros2_rcl/rcl/src/rcl/publisher.c:116" thrown in the test body.
[  FAILED  ] TestGenericPublisher.WhenPublisherDeletedInThread_EnsureCleanNodeCleanup (5 ms)
[----------] 1 test from TestGenericPublisher (5 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (5 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] TestGenericPublisher.WhenPublisherDeletedInThread_EnsureCleanNodeCleanup

@mvukov
Copy link
Owner

mvukov commented Jul 29, 2023

Hi, this is somewhat likely related to #2 -- I suspect you'll need to patch rmw_fastrtps_dynamic_cpp in a similar way we patched rmw_cyclone_dds.

@henriksod
Copy link
Contributor Author

henriksod commented Jul 29, 2023

Aha! I actually just came to the exact same conclusion haha 😄

https://github.com/ros2/rmw_fastrtps/blob/b45e73500bc0a2056fdc31197a6f94434b327d55/rmw_fastrtps_dynamic_cpp/src/type_support_common.cpp#L32

== does not work for c strings. It passed when I used strcmp instead!

We should raise issues in the corresponding repos, if not done already.

@henriksod
Copy link
Contributor Author

@mvukov tests are passing and chatter example ran with fastdds 🚀

Copy link
Owner

@mvukov mvukov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I run tests, I get errors related to

==================== Test output for //ros2/test:test_rclcpp:
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  failed to initialize rcl init options: failed to load shared library 'external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so' due to dlopen error: external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so: undefined symbol: shm_open, at external/ros2_rcutils/src/shared_library.c:99, at external/ros2_rmw_implementation/rmw_implementation/src/functions.cpp:88, at external/ros2_rcl/rcl/src/rcl/init_options.c:75

Please check what shm_open expects and document it. Perhaps add SHM under a flag, like we do for iceoryx.

You should not manually edit repositories/ros2_repositories_impl.bzl, but edit repositories/ros2_repo_mappings.yaml and then run bazel run //repositories/private:resolver (if all up-to-date git diff must be empty for this the _impl.bzl file). If needed, you can override a package version from the yaml file.

Comment on lines 16 to 17
"EPROSIMA_INSTALLER": "OFF",
"EPROSIMA_BUILD": "OFF",
"EPROSIMA_BUILD_TESTS": "OFF",
"APPEND_PROJECT_NAME_TO_INCLUDEDIR": "OFF",
"BUILD_DOCUMENTATION": "OFF",
"CHECK_DOCUMENTATION": "OFF",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please alph-sort by keys.

Comment on lines 16 to 25
"SECURITY": "OFF",
"NO_TLS": "ON",
"SHM_TRANSPORT_DEFAULT": "ON",
"COMPILE_TOOLS": "OFF",
"INSTALL_TOOLS": "OFF",
"FASTDDS_STATISTICS": "OFF",
"COMPILE_EXAMPLES": "OFF",
"INSTALL_EXAMPLES": "OFF",
"BUILD_DOCUMENTATION": "OFF",
"CHECK_DOCUMENTATION": "OFF",
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please alph-sort by keys.

{
- return typesupport_identifier == rosidl_typesupport_introspection_c__identifier;
+ return !std::string(typesupport_identifier)
+ .compare(rosidl_typesupport_introspection_c__identifier);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would std::strcmp work if you would cast rosidl_typesupport_introspection_c__identifier to char*?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

strcmp works, I just wanted to use the same method as the patch for cyclonedds to be consistent

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As pointed out in ros2/rmw_cyclonedds#320, std::strcmp is a bit of an optimization and will avoid an extra mem. alloc. (Eventually we should also refactor the rwm_cyclonedds patch, but that's for a follow-up.)


ros2_cpp_library(
name = "rmw_fastrtps_shared_cpp",
srcs = glob([
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please split into hdrs and srcs.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think header files in src belong in srcs. They don't look like they're intended for downstream rules to #include directly.

repositories/rmw_fastrtps.BUILD.bazel Show resolved Hide resolved
ros2/BUILD.bazel Outdated
@@ -64,3 +66,25 @@ py_binary(
"@ros2cli//:ros2lifecycle",
],
)

# DDS vendor settings
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Obvious comments, please rm.


config_setting(
name = "use_fastdds",
flag_values = {":dds_vendor": "fastdds"},
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be fastdds_dynamic IMO.

@henriksod
Copy link
Contributor Author

When I run tests, I get errors related to

==================== Test output for //ros2/test:test_rclcpp:
terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
  what():  failed to initialize rcl init options: failed to load shared library 'external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so' due to dlopen error: external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so: undefined symbol: shm_open, at external/ros2_rcutils/src/shared_library.c:99, at external/ros2_rmw_implementation/rmw_implementation/src/functions.cpp:88, at external/ros2_rcl/rcl/src/rcl/init_options.c:75

Please check what shm_open expects and document it. Perhaps add SHM under a flag, like we do for iceoryx.

Strange, I do not get this error when running the tests. I will investigate a bit.

@henriksod
Copy link
Contributor Author

You should not manually edit repositories/ros2_repositories_impl.bzl, but edit repositories/ros2_repo_mappings.yaml and then run bazel run //repositories/private:resolver (if all up-to-date git diff must be empty for this the _impl.bzl file). If needed, you can override a package version from the yaml file.

I ran this command and then the urls were removed from the http_archive rules.

@henriksod
Copy link
Contributor Author

henriksod commented Jul 30, 2023

@mvukov fixed comments

bazelisk test //ros2/test:test_rclcpp --config=fastdds --@fastrtps//:enable_shm=True passes for me.

@mvukov
Copy link
Owner

mvukov commented Jul 30, 2023

You should not manually edit repositories/ros2_repositories_impl.bzl, but edit repositories/ros2_repo_mappings.yaml and then run bazel run //repositories/private:resolver (if all up-to-date git diff must be empty for this the _impl.bzl file). If needed, you can override a package version from the yaml file.

I ran this command and then the urls were removed from the http_archive rules.

OK, I will investigate this.

@henriksod
Copy link
Contributor Author

henriksod commented Jul 30, 2023

Strange, I am getting the same error as you when running a regular listener node with fastdds active:

[micro_ros_listener_example_task-2] terminate called after throwing an instance of 'rclcpp::exceptions::RCLError'
[micro_ros_listener_example_task-2]   what():  failed to initialize rcl init options: failed to load shared library 
'external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so' due to dlopen error: 
external/ros2_rmw_fastrtps/librmw_fastrtps_dynamic_cpp.so: undefined symbol: shm_open, at 
external/ros2_rcutils/src/shared_library.c:99, at 
external/ros2_rmw_implementation/rmw_implementation/src/functions.cpp:88, at 
external/ros2_rcl/rcl/src/rcl/init_options.c:75

It works when enabling shared memory transport, but not without...

@henriksod
Copy link
Contributor Author

henriksod commented Aug 1, 2023

@mvukov I have learned that we should link all binaries and tests (using e.g rosidl_typesupport_introspection_c and std_msgs, etc.) dynamically, see ros2/rmw_fastrtps#703.

This is because some pointers are shared between libraries and static linking creates separate object files which breaks this:
ros2/rmw_fastrtps#703 (comment)

linking dynamically means we do not need to patch this for example:
https://github.com/mvukov/rules_ros2/blob/main/repositories/patches/rmw_cyclonedds-fix-typesupport-conditions-bug.patch

@henriksod
Copy link
Contributor Author

henriksod commented Aug 1, 2023

Okay so this works

ros2_cpp_test(
    name = "generic_publisher_tests",
    srcs = ["generic_publisher_tests.cc"],
    linkstatic = False,
    idl_deps = [
        "@ros2_common_interfaces//:std_msgs",
    ],
    deps = [
        "@com_google_googletest//:gtest",
        "@ros2_rclcpp//:rclcpp",
    ],
)

since @ros2_common_interfaces//:std_msgs is loaded as a plugin.

However, it still doesnt work when @ros2_common_interfaces//:std_msgs is used as a cpp library for a node, e.g.:

ros2_cpp_binary(
    name = "publisher",
    srcs = ["publisher.cc"],
    linkstatic = False,
    deps = [
        "@ros2_common_interfaces//:cpp_std_msgs",
        "@ros2_rclcpp//:rclcpp",
    ],
)

I believe something is not correct with interface generation

@henriksod
Copy link
Contributor Author

henriksod commented Aug 1, 2023

Okay so this is strange,

When I run bazelisk run //chatter:chatter --config=fastdds without sestting linkstatic = False, it throws the same error about

'Unknown typesupport identifier, at external/ros2_rmw_fastrtps/rmw_fastrtps_dynamic_cpp/src/type_support_registry.cpp:93'

But if I do set linkstatic = False for both talker and listener, it works!

However, the test does not work, it throws the same error despite linkstatic = False:
bazelisk test //chatter:tests --config=fastdds

Could it be the extra dependency "@ros2_common_interfaces//:py_std_msgs",?

@mvukov
Copy link
Owner

mvukov commented Aug 1, 2023

I'm afraid linkstatic = False won't be sufficient, but, you can try out whether mechanism like in https://github.com/mvukov/rules_ros2/blob/main/repositories/class_loader.BUILD.bazel#L6 would work for rosidl_typesupport_introspection_*.

Interesting discussion in ros2/rmw_fastrtps#703. FWIW, my take: relying on dynamic linking for correction operation of the code if fragile. Are there other places where == -> strcmp could be applied?

@mvukov
Copy link
Owner

mvukov commented Sep 1, 2023

@henriksod Any plans to finish this up?

@henriksod
Copy link
Contributor Author

Sorry I haven't had time. Best to put it on hold if no one else wants to take it up.

@mvukov mvukov mentioned this pull request Nov 29, 2023
@brians-neptune
Copy link

I'm going to try finishing this up. I'm going to respond to comments in this PR, but I don't think I can push to henriksod's branch so I'll open a new PR from my fork.

I'm planning to use the strcmp patch approach instead of #185 to avoid blocking this on the discussion there.

@mvukov
Copy link
Owner

mvukov commented Apr 9, 2024

Now that #299 is merge I hope adding fastrtps support will be way easier.

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

Successfully merging this pull request may close these issues.

3 participants