What’s the best approach for reusing software components between ROS1 and ROS2? I understand the basic concept of tearing out ROS1/ROS2 specific code, and reusing underlying implementation, but how does this work in terms of a build/release story.
Are we expecting to end up with a 2 of everything? rviz2, xacro2?
Are we are going to have separate distros ROS1-only and ROS2-only on the buildfarm? How do you create a package-level dependency between a package in a ROS2 distro and a package in a ROS1 distro?
Would it be possible to build one set of sources in both ROS1 and ROS2 distros? I imagine this would involve something along the lines of https://github.com/ros2/ros2/wiki/catment
First I want to mention that the following answers only describe the current state. While we have gained some experience with migrating code we have not yet settled on one (or multiple) specific strategies which we feel comfortable to “officially recommend”. Therefore this can still change in the future.
Currently the ROS 1 and ROS 2 packages are released into separate ROS distros. Since both distros have their own namespace (e.g. both have packages with the same name) it is not straight forward to have dependencies between a ROS 2 package and a ROS 1 package as you have notices for the ros1_bridge. E.g. on the CMake level it is necessary to identify each package uniquely by its name which is not the case across both ROS versions. Therefore the bridge uses CMake config files only for ROS 2 packages and falls back to pkg-config for ROS 1 packages.
Currently the ROS 1 buildfarm and ROS 2 buildfarm are separate instances. But that is more due to keeping things easy to manage. E.g. the ROS 2 Jenkins uses ARM hardware rather than relying on QEMU. Both build.ros.org as well as build.ros2.org are using the same underlying logic provided by ros_buildfarm. Currently the ROS 2 buildfarm doesn’t have doc / devel / PR jobs but those will be added in the future. But more needs to be done i order for the ros_buildfarm to be able to use ament as well as support Mac OS and Windows nodes.
Regarding the question if “it be possible to build one set of sources in both ROS1 and ROS2 distros” that is rather difficult to answer. It highly depends on what the sources are doing / using. If you rely on roscpp in ROS 1 and therefore need to use rclcpp in ROS 2 there are significant changes in the API. Maybe you even want to switch from using nodelets in ROS 1 to using components in ROS 2. Using the same source for both will likely require a lot of conditional code. I am not sure if that is manageable / desired. Two separate branches which are different in these regards might be easier to manage as well as easier to read. That being said this should be possible after all - it only depends how much of the differences between the two system you are willing to “abstract” in your code base.
catment was only a brief prototype which hasn’t been continued since then and has many cases where it currently doesn’t work. While it would be convenient to have such an API abstraction a package can easily update its CMake code and use either build system conditionally. Not pretty but doable for now. The decision if we spend more effort into a CMake API shim (which I describe as a ROS 2 package named catkin which provides the same API as the ROS 1 package but uses ament_cmake internally) depends on the path for migration. As mentioned above we haven’t settled on that yet which path(s) to recommend.
We have considered providing an API shim to mimic “some” ROS 1 API and implementing it under the hood with ROS 2. But significant effort has been put into it so far since there seem to be several difficulties with that approach. But maybe something like that can make it easier in the future to reuse existing ROS 1 code with ROS 2.
I am likely not answering your questions well. There is still a lot of work necessary to figure out the coexistence between ROS 1 and ROS 2 and potential migration paths. Neither hasn’t received the necessary attention in the past. Hopefully that will change in the future since I think these are all questions which are crucial before considering a first (non-beta) release of ROS 2.
Thanks for that brain dump, it’s definitely helpful to know what direction you’re going in.
The idea of a CMake ‘catkin’ API shim in ament is very attractive, if only to have a standard DRY implementation.
After some more thought, I suppose common (ROS agnostic) C++ code would best be placed in a pure CMake package, that could be built as a dependency in either a ROS1 or a ROS2 distro. Really, that approach could suffice for anything other than interface packages (_msgs), which is why ros1_bridge needs special macros and patched release repos.
Not sure how the story would work for python. Forgive my ignorance of python packaging - a ‘pure’ package in that case would just be a setuptools setup.py type of thing? Is there any way to make a package that would ‘build’ (be referenceable as a dependency/end up on the PYTHONPATH) in both a ROS1 and ROS2 distro?
We have started looking into ROS2 and like many aspects. We had planned to rework some of our packages with a core software library and thin ROS wrapper (similar to nodelets/MoveIt/Tf) usage, but one issue that has been a stumbling block for us is that we use ROS messages as basic data types and prefer to pass const pointers for most of our data handling.
It seems that ROS2 uses the ROS1-style message generators, but the output headers are placed in different locations making it difficult to have common source files that can be built for either ROS1 or ROS2.
Is it possible to have a common header generation scheme so either ROS1 or ROS2 puts the headers and Python class files into a “common” location relative to the include paths based on package setups?
In ROS 2 pure Python packages (using setuptools) are already supported. In ROS 1 that is not the case. In ROS 1 the setup.py file is being invoked from within CMake and some features (like entry points are not available at the moment. But it should be possible to add support for something like that in ROS 1 (there is no technical reason why that wouldn’t be feasible).
The rational why the include path of the generated C++ message code is different is to allow writing dual homed applications. E.g. the ros1_bridge needs to access the C++ message definitions for ROS 1 as well as ROS 2 in the same source file. If the generated files would have the same include path that would not be possible.
It would be possible to generate additional headers which could then be added optionally to the INCLUDE_DIR. Those headers could than be used to access the message types using the same include path. But we haven’t spend any time towards that.
That makes sense short term for bridge, but is problematic for long term code maintenance. For the basic data type, I would think they should be the same with the only difference would be the serialization operators.
Would it be possible to define a base class with data type, and then a specific derived class that overrides the serialization for ROS1 and ROS2 usage? For internal code, you’d only need to pass the base data type around.
With this model, you could then put the specific derived classes in separate paths for your bridge. Only the top level middleware specific wrapper would need to know about the derived serialization wrappers.
I don’t think the ros1_bridge is “short term”. I expect it to be around and useful “forever” since there will likely always be users which use the benefits of both system and want to bridge between them.
First of all this would imply that the message classes share a common base class (requiring changes to ROS 1). It would also require the base class to have a vtable (and least for the destructor). And the functionality in the base class would be dictated by the lowest common denominator since it needs to be available in both ROS version (currently ROS 2 has additional features like default values for fields). And at the end of the day the code creating the messages still needs to decide which subclass it wants to instantiate. Some a user who only wants to use one system (ROS 1 or ROS 2) that is a lot of overhead which I don’t think is reasonable. It also couples the two versions in a way that separately evolving them will be difficult / impossible. If we want to introduce a fancy new feature to .msg files in ROS 2 it will also be necessary to do the same in ROS 1. This is one of the things we strongly want to avoid since stability and robustness is very important to the ROS 1 community.
This discussion and the points raised remind me of the old discussions about the strategy regarding ROS2 development and its relation to ROS1, so for conetext and completness I would like to link to http://wiki.ros.org/sig/NextGenerationROS/StrategyReview, which summarizes some of the points, on also has pointers to some of the preceeding discussions. I am posting this without any personal valuation either way. While it does not necessarily paint a perfectly balanced picture, and some of the dicussions are maybe also obscurred by heated personal arguments, I still believe that there are some valid points contained.
I interpret it such that the main fear from people that have argued for a different strategy to develop ROS2 is that there will not be a viable (in terms of necessary maintenance effort) path for large-scale migration and coexistence of code bases in ROS1 and ROS2, and that the advance of ROS2 might lead to the biggest disruption of the ROS community yet, by effectivly splitting it up in 2 communities, those who go on to only use ROS2, and those, that are “stuck” with ROS1.
So I guess the community should hopefully come up with ways to make sure that this does not happen (where this thread is part of such an effort).
‘Hopefully’? Everybody hopes that, of course. But if you say hopefully, whose decision is that if not yours? Whose decision was it in the past not to give this the necessary attention, if not yours?