ROS2 Transition Strategy

Release tags can be templated, e.g., myprefix-:{version}, unless you mean something else.

Thanks for pointing that out @asherikov, you are right that the “Release tag” doesn’t have to strictly follow x.y.z. Here is the snippet from bloom:

Release Tag:
  :{version}
    This means that the release tag will match the :{version} tag.
    This can be further templated, for example: "foo-:{version}" or "v:{version}"
    
    This can describe any vcs reference. For git that means {tag, branch, hash},
    for hg that means {tag, branch, hash}, for svn that means a revision number.
    For tar this value doubles as the sub directory (if the repository is
    in foo/ of the tar ball, putting foo here will cause the contents of
    foo/ to be imported to upstream instead of foo itself).
  :{ask}
    This means the user will be prompted for the release tag on each release.
  :{none}
    For svn and tar only you can set the release tag to :{none}, so that
    it is ignored.  For svn this means no revision number is used.
  [':{version}']: :{version}

I’m not familiar with the internal workings of bloom, but is it possible that this templating feature is only for helping bloom find which git tag corresponds to version x.y.z? and then bloom still uses x.y.z internally and with the release repo. If this is the case, then I don’t think you’d be able to release a ROS1 version using the tag ros1-1.0.0, and a different ROS2 version using the tag ros2-1.0.0, since bloom sees them both as 1.0.0.

Does someone with more bloom experience/knowledge know if this is the case?

ROS1 and ROS2 packages are going to be on different tracks and end up in different rosdistros, e.g.,

1 Like

Thanks @asherikov, you are absolutely right, I was digging around and noticed @JWhitleyWork did the same thing with our pacmod3 driver release. Version 1.3.0 is released on both melodic and dashing using different release_tag prefixes.

Thanks for bringing this up, it’s good to know that release tag prefixes are a viable option for those who want to go that route.

All things considered, I think I’ve settled on the following:
RO2 versions will be versioned starting at 2000.x.x, but I will try to match the ROS1 version regarding functionality, so if the ROS1 version of some package was bumped to 4.3.0, then the ROS2 version of this package with the same/similar functionality will be 2004.3.0.
Even though we could use tag prefixes to release the same version number on both ROS1 and ROS2, I’m leaning towards a separate 2000.x.x version since the ROS1 and ROS2 code is completely different (different includes, ROS2 lifecycle management, etc). There may be different bug fixes or patches associated with these differences that could only apply to one of them, so it makes sense to me to version them separately.

Thanks everyone!

The problem is bigger than a specific tool like bloom. The package names in debian although the most obvious for many users is not likely to be a problem. This is because we won’t ever use the same distribution codename. So the output packages will never conflict.

The problem is when you start thinking about the actual codebase and your downstream users. If you have package foo tagged 1.0.0 for ros1 and a separate tag 1.0.0 for ros2 with different content. How is a downstream dependency supposed to differentiate them. Say they need to do an #ifdef in their code to manage a change between ROS 1 and ROS 2 versions that needs to be detectable in the code. It’s common to create logic which detects the version of a dependency and do one thing if it’s greater than x,y and a different thing if its lower. This logic will be broken if you use the same version series. Suddenly all the CMAKE logic needs to be able to parse more/different formats. And the package.xml parsing needs to be extended to support a random prefix.

Similarly it will cause major problems when you start doing things like writing up the changelogs for people to review. The changelog for foo 1.2 will be very confusing to be different than the changelog for foo 1.2 if they are different but released on different distros. Version number are typically designed to show equivalency. And when you’ve forked development for two different dependency bases there’s very little equivalency left. And when you start thinking about subsequent release say 1.2.1 are they expected to be equivalent as well with exactly the same patches? Thus again you’re actually in a new development series and should indicate so with a new release numbering series (major or minor).

In general we could make technical workarounds and add layer on layer of complexity to all of our toolchain. Or we could just stick with SemVer and our standard practices and create a new release series based on a major version. And not incur more complexity in all of our toolchain that will require maintenance and more non-standard behavior exceptions when trying to connect to many different packaging systems.

So at a high level I recommend picking a new release series which is high enough to give you space for any expected future releases in the previous cycles and go from there. 2000 is high, leaving space for over 1000 major version bumps on the EOL distribution is likely more than you need, but it’s clear. You could also just go a few up majors to leave potential space for future iterations. Playing games with release tags and formats breaks a lot of other assumptions. And once you’ve forked development, you have forked development it’s unlikely that things will remain in lockstep and persisting lockstep development is unlikely to be of large value to your downstream users as they too will have forked development.

3 Likes

I’ve been recently trying to rewrite a lot of ROS packages in a way that the same repo and branch works in both ROS1 and ROS2.

This is accomplished by conditionals in package.xml/CMakeLists.txt. Although you can use conditionals and have both ROS1 and ROS2 code live in the repo, I also wrote a library that allows you do use the same Python code for a ROS1 and ROS2 node:

An example of how it is used is my web-based visualization tool, ROSboard:

ROSboard can be cloned and used in either a catkin/ROS1 workspace OR a colcon/ROS2 workspace.

I’m also exploring creating a C++ analogue of the rospy2 library, i.e. roscpp2, that could allow the same C++ code to be used for ROS1 or ROS2.

Although I encourage people to move on to ROS2 way of doing things (rclcpp and rclpy) for new projects, I think such libraries like rospy2 (and maybe roscpp2 in the future) can be very helpful for things that specifically want to maintain compatibility with ROS1 and ROS2, e.g. hardware drivers, where the bulk of the logic is just a hardware interfacing logic and very little ROS logic, usually just a single publisher or single subscriber in many cases. In such cases it is extremely beneficial to not have to reproduce the hardware interfacing logic in multiple branches or repos and have to sync them every time you change something.

2 Likes