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

Feature request: C++ support #126

Open
JanStaschulat opened this issue Jul 15, 2021 · 9 comments
Open

Feature request: C++ support #126

JanStaschulat opened this issue Jul 15, 2021 · 9 comments
Assignees
Labels
enhancement New feature or request

Comments

@JanStaschulat
Copy link
Contributor

JanStaschulat commented Jul 15, 2021

We have received a number of requests to provide a C++ API for micro-ROS. Therefore we would like to discuss how to develop a C++ API for micro-ROS as a community effort. The default rclcpp API uses dynamic memory allocation (STL containers) which is problematic for micro-controllers due to memory framentation and potentially allocating more memory than available. Completely re-writing rclcpp would be a large effort, therefore we see two basic strategies:

  • A) a replacement of rclcpp with a minimal feature set without dynamic memory allocation
  • B) thin C++ layer on top of rclc.

The decision might also depend on the requirements for such a C++ API. So please feel free to join the next EWG meeting on 27th July 2021 to share your opinion:
https://discourse.ros.org/t/ros-2-embedded-wg-meetings/15460

You are also welcome to comment here below.

@JanStaschulat JanStaschulat changed the title C++ support Feature request: C++ support Jul 17, 2021
@ros-discourse
Copy link

This issue has been mentioned on ROS Discourse. There might be relevant details there:

https://discourse.ros.org/t/ros-2-embedded-wg-meetings/15460/20

@JanStaschulat
Copy link
Contributor Author

JanStaschulat commented Jul 27, 2021

micro_rclcpp: a C++ API for micro-ROS
The following table compares a potential C++ API for micro-ROS, called micro_rclcpp with the existing rclcpp API. It consists of a number of C++ wrapper functions and uses the rclc package.

Feature rclcpp micro_rclcpp
Message type conversion Message types need to converted from C++ template type
argument to rosid_typesupport_t type in RCL.
Example for Subscription:
rclcpp::create_subscription()
rclcpp::create_subscription_factory()
rosidl_runtime_cpp::get_message_type_support_handle()
similar approach can be used
Callback function pointers no restrictions for function pointers



Message type in parameter declaration
Only static member functions and capture-less lamda. There is also an article about how use member functions as C-function pointers
only void * parameter for message type
Message data types staticly and dynamically allocated message variables (e.g. std::String and other STL containers) dynamic memory allocation shall be avoided, std::String and STL-containers are not supported. This is not a restriction of mirco_rclcpp but a requirement of programming on a micro-controller.
Alternative: cxx::string in iceoryx
Node Concept Subscriptions, publishers, timers etc. are added to a Node RCLC does not have a Nodeconcept. Subscriptions, publishers, timers are added directly to the Executor. One option would be to add a Node type in which the Executoris initialized and you can call Node.spin()

Alternative:
Full C++ Implementation with Executor has the

Benefits:

  • full support of callback function pointers and message type in function parameter

Limitations:

  • no dynamicly allocated message types

Summary micro_rclcpp

Benefits:

  • support for C++ API for Publishers, Subscribers, Timers, Services/Clients, guard conditions Nodes, real-time executor
  • thin layer with C++ wrapper functions on top of RCLC

Limitations:

  • callback function pointers: only static member functions, capture-less lambda expressions
  • callback function signature: no message types but only void * as argument possible
  • no dynamicly allocated message types supported (STL containers, e.g. std::String)

@JanStaschulat
Copy link
Contributor Author

JanStaschulat commented Jul 27, 2021

Questionnaire to micro-ROS users

  • Where do you see the benefit of a C++ API for micro-ROS?
  • Are the limitations/restrictions described above acceptable for your application?
  • To which extend could you contribute (code development, reviewer, testing)?
  • Which other features are interesting for you?

Looking forward to your feedback. Thank you.

@JanStaschulat JanStaschulat self-assigned this Jul 28, 2021
@JanStaschulat JanStaschulat added the enhancement New feature or request label Jul 28, 2021
@BrettRD
Copy link
Contributor

BrettRD commented Aug 18, 2021

This thread is looking a little sparse, I missed the meeting but I'll throw my opinion in

I've normally avoided C++ for microcontrollers because of how easy it is to accidentally pull in std:: types that enthusiastically re-allocate memory.

Arduino in relies heavily on std::string and permits concatenation and deep copy; It's often ok even if it's not desired for performance.
If I were teaching with ROS on microcontrollers, I would appreciate an API that is more more congruent with the Arduino flavour.
A Node would allow some neat namespacing tools, and would make sense as a tidy top-level C++ object to handle entity destruction.

I would like to see more type-safety in RCLC; it's getting tedious writing endless functions that take only void* arguments. C++ templates are a good way of giving compile-time type-safety to the user. I think a templated wrapper could lead to some more type-names being migrated back to RCLC, which would be good for readability.

I'd really really want to see strongly-typed callbacks, and I would make extensive use of std::bind to make very sure I can use callback context pointers to carry this pointers for non-static class member functions. I would also make PRs to tweak callback argument order to make such hacks more seamless.

RCL offers allocation pointers and defined allocator structs, I'd personally default those to no-allocation, but I would want to see the custom-allocator feature of RCL exposed in micro_rclcpp as it is in rclcpp because of the zero-cost abstractions it offers.

Tangentially, I'm also interested in a Rust wrapper but that might be easier to build from scratch.

@ros-discourse
Copy link

This issue has been mentioned on ROS Discourse. There might be relevant details there:

https://discourse.ros.org/t/ros-2-embedded-wg-meetings/15460/22

@JanStaschulat
Copy link
Contributor Author

JanStaschulat commented Sep 21, 2021

Example for C++ type support:

  • defining a subscription with a C++ message type (like std_msgs::msg::String)
  • using ROS 2 message type in callback (instead of void *)

Demonstrated in rclc_examples/example_pingpong: #199

@bjv-capra
Copy link

Hi

I was not able to make my mic work during today's meeting, so I'll add my few cents here.
One has to avoid using almost all STL containers, std::array can be used with no risks. Even when exceptions are disabled, one can use at() with no more risks than the usual when working with arrays.
This added with all the benefits of type-safety, templates, and more. The overhead introduced by C++ can be substantial, however, from my point of view, it's none compared to the benefits.

We already work having wrappers on top of rclc or rcl depending on the use, and our biggest "struggle" is that we saw ourselves forced to make singletons to somehow get access to a class method during a callback (this was basically solved with the introduction of the context pointer).

Regarding RUST, it's interesting, but far from being mature enough to use it on product development.

@JanStaschulat
Copy link
Contributor Author

JanStaschulat commented Sep 28, 2021

@bjv-capra Thank you for your feedback. Regarding the access to class members, as you mentioned, we have now subscriptions with context pointers. Apart from access to class members (which should be solved), I see as main development points:

  • typesupport (using rosidl_typesupport_handle functions from rclcpp and factoring out those on rclc)
  • wrappers in Executor to call C++ type-safe callbacks from rclc (using context pointer) - as in the very simple ping-pong example on_update_wrapper() using in creating a subscription here. The message type should be templated, of course.

@ros-discourse
Copy link

This issue has been mentioned on ROS Discourse. There might be relevant details there:

https://discourse.ros.org/t/microxrce-dds-on-ardupilot/29972/8

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants