Move a ROS 2 project over
Needs first: Organize a larger workspace
Use this page to move an existing ROS 2 workspace (a src/ of packages built
with colcon, run with ros2 launch) to nano-ros, before you port the nodes
one by one.
nano-ros keeps the workspace and package vocabulary: a src/ of packages
with package.xml manifests, launch files in the ROS 2 schema, and the
ROS-shaped names of nodes, topics, services, actions and QoS. It changes the
setup boundary, because it targets embedded builds that have no shared
libraries and no runtime plugin loading:
| You have (ROS 2) | You get (nano-ros) |
|---|---|
a distro install, then rosdep install | the nros CLI, then nros setup <board> --rmw <rmw> |
colcon build | nros build <image>, which drives cmake, cargo or west |
ros2 launch pkg file, ros2 run | nros run <bringup>:<image>: the launch topology is compiled in |
RMW_IMPLEMENTATION=… at start-up | [system] rmw = "…" in the bringup’s system.toml, at build time |
package.xml | kept as it is |
.launch.xml, .launch.py | kept, in the bringup package; resolved at build time |
| message packages from the ament index | bindings generated under build/ by nros build |
find_package(rclcpp), ament_target_dependencies | kept: nano-ros’s own find modules and ament verbs |
The full account of the differences is in How nano-ros differs from ROS 2.
Before you start
- A ROS 2 Humble workspace that builds with
colcon build. - ROS 2 Humble installed. nano-ros generates its message bindings from it,
and its zenoh router is ROS 2’s
rmw_zenohd.
Steps
-
Install the CLI and provision the host, in place of the distro install and
rosdep:curl -fsSL https://raw.githubusercontent.com/NEWSLabNTU/nano-ros/main/scripts/install.sh | sh export PATH="$HOME/.nros/bin:$PATH" nros setup linux --rmw zenohFor a board, name it:
nros setup mps2-an385-freertos --rmw zenohfetches its cross compiler, emulator and SDK sources into~/.nros/sdk. Nothing is installed system-wide. -
Add a bringup package. It replaces the
ros2 launchcommand line: apackage.xml, asystem.toml, and your launch files underlaunch/:cd src nros new system my_robot_bringup --components talker_pkg,listener_pkgnros new system: scaffolded bringup pkg my_robot_bringup at …/src/my_robot_bringup (2 component(s))It writes a
[[component]]row per package withclass = "<pkg>::TODO"; set each to the node’s class. Move the launch files you run intomy_robot_bringup/launch/, replacing the generatedsystem.launch.xml. Stock XML launch files work as they are;.launch.pyfiles are resolved at build time too. -
State the backend and the target once, in the bringup’s
system.toml. These two lines replaceRMW_IMPLEMENTATIONand any cross-compile recipe:[system] name = "my_robot" rmw = "zenoh" # zenoh | cyclonedds | xrce [image.linux] board = "linux" [image.freertos] board = "mps2-an385-freertos" # the platform follows from the boardOn Linux,
ROS_DOMAIN_IDandNROS_LOCATORstill work at run time. On a board the same values come from the image row, because a board has no environment to read them from. -
Port the nodes. A C++ node keeps its source and its
CMakeLists.txt; see Port a C++ node. For a Rust or C node, the Tutorial shows the node package shapes. -
Build and run one image:
source /opt/ros/humble/setup.bash nros build linux nros run my_robot_bringup:linuxThe first build records the ROS 2 prefix, so later shells need not source ROS 2. A POSIX C++ workspace can still be built with
colcon buildfor its existing consumers. -
Check it from stock ROS 2:
export RMW_IMPLEMENTATION=rmw_zenoh_cpp ros2 topic echo /chatter std_msgs/msg/String --qos-reliability best_effort
Example
The whole move for a two-node project that ran as
ros2 launch my_robot system.launch.xml with Cyclone DDS:
my_robot_ws/
└── src/
├── talker_pkg/ # unchanged
├── listener_pkg/ # unchanged
└── my_robot_bringup/
├── package.xml
├── system.toml
└── launch/system.launch.xml # moved here, unchanged
# src/my_robot_bringup/system.toml
[system]
name = "my_robot"
rmw = "cyclonedds"
default_launch = "system.launch.xml"
[[component]]
pkg = "talker_pkg"
class = "talker_pkg::Talker"
name = "talker"
[[component]]
pkg = "listener_pkg"
class = "listener_pkg::Listener"
name = "listener"
[image.linux]
board = "linux"
nros setup linux --rmw cyclonedds
nros build linux
nros run my_robot_bringup:linux
Cyclone DDS needs no router, so this interoperates with rmw_cyclonedds_cpp
nodes directly.
If it doesn’t work
- Changing
RMW_IMPLEMENTATIONchanges nothing. The backend is compiled in. Edit[system] rmwand build again. - A stock ROS 2 node does not hear the image. The two use different domain IDs or QoS reliability, the ROS 2 side is on a different RMW, or no zenoh router runs. See Talk to ROS 2.
- A
<depend>stopsnros setup. It names something that is neither a workspace package, a message package, a system key nor a package your ROS install provides. Remove it or add the package. - The store keeps growing. Provisioning never overwrites.
nros toolchain listshows each entry and when it was last read, andnros toolchain gc --older-than 90dproposes what to remove; it removes nothing without--delete, and never an entry a pin names.
See also
- Port a C++ node.
- How nano-ros differs from ROS 2 and micro-ROS.
- Switch the RMW per image and Bridge between backends.