Note
This branch ports the entire SlideSLAM stack from ROS1 Noetic to ROS2 Jazzy Jalisco (Ubuntu 24.04) — the latest ROS2 LTS. It is provided to help developers who want to use SlideSLAM with ROS2.
Note: this ROS2 port has not been as extensively tested or experimented with as the ROS1 version. If you want the version used to produce the results in our paper, or the most battle-tested setup, please use the master branch (ROS1 Noetic, Ubuntu 20.04). See Testing the ROS2 port at the end of this README for the full list of static and runtime checks we do run on this branch, and which runtime behaviors have not been verified end-to-end. For a detailed, per-package breakdown of everything that was migrated, the mechanical rules applied, and the open follow-up items, see ROS2_MIGRATION_REPORT.md at the root of this branch.
Issues and pull requests that improve the ROS2 port are very welcome.
This repository contains the source code for the project SlideSLAM: Sparse, Lightweight, Decentralized Metric-Semantic SLAM for Multi-Robot Navigation.
- More details can be found on the project website.
- Our paper is available on arXiv here.
- SlideSLAM
- Table of contents
- Use docker (recommended)
- Build from source (only if you do not want to use docker)
- Converting ROS1 bags to ROS2 (required before running demos)
- Run our demos (with processed data)
- Run on raw sensor data (RGBD or LiDAR bags)
- Troubleshoot
- Testing the ROS2 port
- Acknowledgement
- Citation
Install docker: https://docs.docker.com/desktop/install/linux/ubuntu/#install-docker-desktop
Pull the docker image:
docker pull xurobotics/slide-slam:ros2-jazzy
Note: the ros2-jazzy tag is a placeholder and may not yet be published on Docker Hub. Build it locally or update the tag once it is available.
Create the workspace (important)
mkdir -p ~/slideslam_docker_ws/src
cd ~/slideslam_docker_ws/src
Creating the workspace outside the docker helps you keep your files and changes within the workspace even if you delete the un-committed docker container.
Clone the repo:
git clone https://github.com/XuRobotics/SLIDE_SLAM.git
cd ~/slideslam_docker_ws/src/SLIDE_SLAM
chmod +x run_slide_slam_docker.sh
(Optional) Only if you need to run on LiDAR data, install Faster-LIO and LiDAR drivers:
cd ~/slideslam_docker_ws/src
git clone git@github.com:ouster-lidar/ouster_example.git && cd ouster_example && git checkout 43107a1 && cd ..
git clone git@github.com:XuRobotics/faster-lio
git clone git@github.com:KumarRobotics/ouster_decoder.git && cd ouster_decoder && git checkout d66b52d && cd ..
Find the CMakeLists.txt in ouster_decoder and comment out the last three lines (the ouster_viz) to avoid fmt issue
Run the docker image:
Important: Go to ./run_slide_slam_docker.sh, make sure the following three directories are correct
SlideSlamWs="/home/sam/slideslam_docker_ws"
should point to your workspace directory
SlideSlamCodeDir="/home/sam/slideslam_docker_ws/src/SLIDE_SLAM"
should point to your code directory where you cloned the repository
BAGS_DIR="/home/sam/bags"
should point to your bags (data) directory
Then run:
./run_slide_slam_docker.sh
Build the workspace:
source /opt/ros/jazzy/setup.bash
cd /opt/slideslam_docker_ws
colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release
Run the demos
source /opt/slideslam_docker_ws/install/setup.bash
Follow the instructions below to run the demos. Remember to commit your changes inside docker envirnoment to keep them (e.g. newly installed pkgs).
Type exit to exit the container.
You can re-enter the container, or enter the container from a new terminal by either
docker start slideslam_ros2 && docker exec -it slideslam_ros2 /bin/bash
or remove your docker container using the command
docker rm slideslam_ros2
before you run the docker image again.
Troubleshoot:
- If you do not see your code or bags inside docker, double check
run_slide_slam_docker.shfile to make sure you have your workspace and BAG folders mapped properly.
Install ROS2 Jazzy on Ubuntu 24.04
Please refer to this link for installing ROS2 Jazzy Jalisco.
Create your workspace under your preferred directory (e.g., we name this directory as ~/slideslam_ws):
cd ~
mkdir slideslam_ws
cd slideslam_ws
mkdir src
cd src
Then, pull the slideslam github repo:
git clone https://github.com/XuRobotics/SLIDE_SLAM.git
Install qhull 8.0.2:
Download from this link, extract (unzip) the file, then:
cd build
cmake ..
make install
If make install gives a permission error then try sudo make install
Install gtsam 4.0.3:
sudo add-apt-repository ppa:borglab/gtsam-release-4.0
sudo apt update
sudo apt install libgtsam-dev libgtsam-unstable-dev
sudo apt-get install libdw-dev
Install Sophus:
git clone https://github.com/strasdat/Sophus.git && \
cd Sophus && git checkout 49a7e1286910019f74fb4f0bb3e213c909f8e1b7 && \
mkdir build && cd build && \
cmake -DCMAKE_BUILD_TYPE=Release .. && make
sudo make install
Install fmt 8.0.0:
git clone https://github.com/fmtlib/fmt.git && \
cd fmt && git checkout 8.0.0 && \
mkdir build && cd build && \
cmake .. && make
sudo make install
ros_numpy replacement:
ros_numpy is not available in ROS2; the ros2_dev branch provides local helpers that wrap sensor_msgs_py.point_cloud2 instead. No extra package needs to be installed.
(Optional) Only if you need to run on LiDAR data, install Faster-LIO and LiDAR drivers:
sudo apt update
sudo apt-get install -y libgoogle-glog-dev
cd ~/slideslam_ws/src
git clone http://github.com/ouster-lidar/ouster_example.git && cd ouster_example && git checkout 43107a1 && cd ..
git clone https://github.com/XuRobotics/faster-lio.git
git clone https://github.com/KumarRobotics/ouster_decoder.git && cd ouster_decoder && git checkout d66b52d && cd ..
Find the CMakeLists.txt in ouster_decoder and comment out the last three lines (the ouster_viz) to avoid fmt issue
(Optional) Only if you need to run on RGBD data with YOLOv8, install the following:
pip install ultralytics==8.0.59
Install pip dependencies:
pip install "numpy>=1.24,<2.0"
pip install scikit-learn
pip install scipy
pip install open3d
pip install matplotlib
pip install pypcd4
pip install tf_transformations
Note: Ubuntu 24.04 ships Python 3.12, which is incompatible with the old numpy==1.22.3 pin used on the ROS1 branch — numpy>=1.24,<2.0 is the supported range. The original pypcd from dimatura/pypcd is also broken on Python 3.12, so we use the maintained pypcd4 fork instead. The Python nodes ported in this branch import tf_transformations, which is not part of the standard apt set.
Also install the apt-distributed tf_transformations package alongside the pip version (Jazzy ships its own python package via apt):
sudo apt install ros-jazzy-tf-transformations
- Install
tmuxfor running our demo experiments
sudo apt update
sudo apt install tmux
Build in release mode
source /opt/ros/jazzy/setup.bash
cd ~/slideslam_ws
colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release
Source your workspace using
source ~/slideslam_ws/install/setup.bash
Troubleshoot:
- If you have built GTSAM from source before, you need to remove everything related to gtsam/GTSAM in /usr/local by doing:
sudo rm -rf /usr/local/lib/cmake/*GTSAM*
sudo rm -rf /usr/local/include/gtsam
- If you have installed GTSAM using apt-get, remove them first, use this command `sudo apt remove --purge libgtsam*
All of our published demo / benchmark bags — the processed multi-robot bags used under Run our demos and the raw sensor bags used under Run on raw sensor data — were recorded under ROS1 Noetic and are distributed as legacy .bag files. ROS2 Jazzy's ros2 bag play cannot read ROS1 bags directly, so you must convert them once before running any of the demos on this branch.
We provide a small wrapper script that drives the standalone rosbags-convert tool:
# one-time install (no ROS1 required — the `rosbags` package is self-contained):
pip install rosbags
# convert a single .bag file:
./tools/convert_ros1_bags.sh /path/to/forest_robot1.bag
# or convert every .bag in a directory at once:
./tools/convert_ros1_bags.sh /path/to/bags/
By default the converted ROS2 bag is written next to the original as a directory (containing metadata.yaml + a .db3 sqlite3 file) with the same base name. Existing output directories are skipped, so the script is safe to re-run. See tools/convert_ros1_bags.sh for full options.
After conversion, point BAG_DIR in the tmux scripts (e.g. tmux_multi_robot_with_bags_forest.sh) at the directory containing the converted ROS2 bags, not the original .bag files.
Note: if the access to any of the links is lost, please contact the authors, and we will provide the data from our lab's NAS.
This section will guide you through running our demos with processed data. We provide processed data as legacy ROS1 .bag files that contain only the odometry and semantic measurements (i.e. object observations); you must convert them to ROS2 bag format first using tools/convert_ros1_bags.sh (see the Converting ROS1 bags to ROS2 section above). Running the entire pipeline containing object detection and the rest of SLAM for multiple robots simultaneously onboard one computer is computationally and memory intensive.
Note: Such tests can to a large degree replicate what would happen onboard the robot since when you run real world multi-robot experiment, each robot will only be responsible for processing its own data, and the processed data shared by the other robots in the form provided by here.
Please download the processed data bags from this link. This containes compact processed bags for forest and urban outdoor environments. Please use the right data with the right scripts as specified below.
- Intermittent communication between robot nodes at a fixed time interval.
- Multiple robots running on the same computer, and therefore, the computational load is going to be (num_robots multiplied by the computation load of each robot during actual experiment).
First, please refer to the section above and make sure you have everything built.
Option 1: Use our tmux script (recommended)
Source your workspace and go to the script folder inside the multi_robot_utils_launch package (using the source-tree path is more reliable than ros2 pkg prefix):
source ~/slideslam_ws/install/setup.bash
cd ~/slideslam_ws/src/SLIDE_SLAM/backend/multi_robot_utils_launch/script
Modify tmux_multi_robot_with_bags_forest.sh to set the BAG_DIR to where you downloaded the bags
Modify BAG_PLAY_RATE to your desired play rate (lower than 1.0 if you have a low-specification CPU)
Then make it executable if needed
chmod +x tmux_multi_robot_with_bags_forest.sh
Finally, execute this script
./tmux_multi_robot_with_bags_forest.sh
If you want to terminate this program, go to the last terminal window and press Enter to kill all the tmux sessions.
Option 2: If you prefer not to use this tmux script, please refer to the ros2 launch commands inside this tmux script and execute those commands by yourself.
To run the same above example with urban outdoor data, use the tmux_multi_robot_with_bags_parking_lot.sh script and repeat the above steps.
This section will guide you through running our code stack with raw sensor data. Our distributed raw bags are legacy ROS1 .bag files (10-100 GB each) — run tools/convert_ros1_bags.sh on them first (see the Converting ROS1 bags to ROS2 section above) so that ros2 bag play can replay them under ROS2 Jazzy.
Please download the LiDAR demo bags from this link. It is present inside the outdoor folder.
Please download the RGBD demo bags from this link. It is present inside the indoor folder.
Please download the KITTI benchmark processed bags from this link. It is present inside the kitti_bags folder.
Please download our trained RangeNet++ model from this link. It is currently named penn_smallest.zip. Follow the instructions in the Run our LiDAR data experiments section below on how to use this model.
Option 1: Use our tmux script (recommended)
Source your workspace and go to the script folder inside the multi_robot_utils_launch package (using the source-tree path is more reliable than ros2 pkg prefix):
source ~/slideslam_ws/install/setup.bash
cd ~/slideslam_ws/src/SLIDE_SLAM/backend/multi_robot_utils_launch/script
Modify tmux_single_indoor_robot.sh to set the BAG_DIR to where you downloaded the bags
Modify BAG_PLAY_RATE to your desired play rate (lower than 1.0 if you have a low-specification CPU)
Then make it executable if needed
chmod +x tmux_single_indoor_robot.sh
Finally, if you want to use Yolo-v8, execute this script
./tmux_single_indoor_robot.sh
IMPORTANT: If it is your first time to run this script, the front-end instance segmentation network will download the weights from the internet. This may take a while depending on your internet speed. Once this is finished, kill all the tmux sessions (see below) and re-run the script.
If you want to terminate this program, go to the last terminal window and press Enter to kill all the tmux sessions.
Option 2: If you prefer not to use this tmux script, please refer to the ros2 launch commands inside this tmux script and execute those commands by yourself, or using the detailed instructions found here.
Download the LiDAR semantic segmentation RangeNet++ model
(1) Download the model from the above link.
(2) Unzip the file and place the model in a location of your choice.
(3) Open the extracted model folder and make sure that there are no files inside having a .zip extension. If there are, then rename ALL OF THEM to remove the .zip extension. For example backbone.zip should be renamed to backbone
Option 1: Use our tmux script (recommended)
Make sure you edit the infer_node_params.yaml file present inside the scan2shape_launch/config folder and set the value of model_dir param to point to the path to the RangeNet++ model you downloaded in the previous step. Make sure to compelte the path with the / at the end.
Source your workspace and go to the script folder inside the multi_robot_utils_launch package (using the source-tree path is more reliable than ros2 pkg prefix):
source ~/slideslam_ws/install/setup.bash
cd ~/slideslam_ws/src/SLIDE_SLAM/backend/multi_robot_utils_launch/script
Modify tmux_single_outdoor_robot.sh to set the BAG_DIR to where you downloaded the bags
Modify BAG_PLAY_RATE to your desired play rate (lower than 1.0 if you have a low-specification CPU)
Then make it executable if needed
chmod +x tmux_single_outdoor_robot.sh
Finally, execute this script
./tmux_single_outdoor_robot.sh
If you want to terminate this program, go to the last terminal window and press Enter to kill all the tmux sessions.
Option 2: If you prefer not to use this tmux script, please refer to the ros2 launch commands inside this tmux script and execute those commands by yourself, or using the detailed instructions found here.
Option 1: Use our tmux script
Source your workspace and go to the script folder inside the multi_robot_utils_launch package (using the source-tree path is more reliable than ros2 pkg prefix):
source ~/slideslam_ws/install/setup.bash
cd ~/slideslam_ws/src/SLIDE_SLAM/backend/multi_robot_utils_launch/script
Modify tmux_single_outdoor_kitti.sh to set the BAG_DIR to where you downloaded the bags
Then make it executable if needed
chmod +x tmux_single_outdoor_kitti.sh
Finally, execute this script
./tmux_single_outdoor_kitti.sh
If you want to terminate this program, go to the last terminal window and press Enter to kill all the tmux sessions.
Rate of segmentation:
- When running on your own data, we recommend to throttle the segmentation topic (segmented point cloud or images) rate to 2-4 Hz to avoid computation delay in the front end, especially if you’re experiencing performance issues at higher rates. Please also update the
expected_segmentation_frequencyparameter in the correspondingprocess_cloud_node_*_params.yamlfile as well as thedesired_frequencyin theinfer_node_params.yamlto the actual rate of the topic.
The ros2_dev branch ships a static test suite under tests/ that future contributors can run to regression-check the port without needing a full ROS2 Jazzy build environment. The suite has three layers — a pure-bash static checker, a pytest mirror, and a runtime launch-graph smoke test. See tests/README.md for per-layer usage notes.
Current state (after the port + the review passes done on this branch): bash tests/static/check_ros2_port.sh reports 55 checks, 55 passed, 0 failed, 0 skipped.
Pure bash + ripgrep + awk. Runs anywhere with zero Python or ROS2 dependencies. 55 checks across 18 sections (A–R) verifying:
- A — no ROS1 C++ idioms in active source under
backend/sloam/andfrontend/object_modeller/(21 sub-checks). Verifies zero occurrences of:ros/ros.h,ros/package.h, old-style message includes (<pkg/Type.h>),tf/headers,nodelet/,pluginlib/,actionlib/,ros::NodeHandle,ros::Publisher,ros::Subscriber,ros::Time::now(),ros::Duration,ros::Rate,ros::init,ros::spin/spinOnce,ros::ok,ROS_INFO/WARN/ERROR/DEBUG/FATAL,nodelet::Nodelet,PLUGINLIB_EXPORT_CLASS,actionlib::. - B — no ROS1 Python idioms under
frontend/object_modeller/andfrontend/scan2shape/(6 sub-checks): noimport rospy/from rospy, norospy.*attribute access, no bareimport tf/from tf.*, noros_numpy, norospkg. - C — every
package.xmlacross all 5 ROS packages is format 3, declaresament_cmake/ament_python/rosidl_default_generatorsas buildtool, declares<build_type>in<export>, contains nocatkinormessage_generation/message_runtime. - D — every
CMakeLists.txtacross all 5 packages has nofind_package(catkin...), nocatkin_package(...), no${catkin_INCLUDE_DIRS}/${catkin_LIBRARIES}, noadd_message_files/add_service_files/add_action_files/generate_messages, and callsament_package()at the end. - E — launch file structure (4 sub-checks): no XML
*.launchfiles underbackend/orfrontend/, every*.launch.pyimportsLaunchDescription, every*.launch.pydefinesgenerate_launch_description, no.launch.pycontains a literal<launch>XML tag (half-converted file). - F — no camelCase
sloam_msgsfield accessors (msg.robotID,msg.treeModels,msg.labelXYZ, etc.) remain in any.cpp/.h/.hpp/.pyfile. The port renamed 25 fields from camelCase tosnake_caseto satisfyrosidl's naming rules; this check catches any accessor we forgot to update. The internal C++ structPoseMstPair::relativeRawOdomMotionis correctly preserved (not a ROS message field) via a word-boundary regex carve-out. - G — every
#include <sloam_msgs/msg/*.hpp>/<sloam_msgs/srv/*.hpp>/<sloam_msgs/action/*.hpp>and everyfrom sloam_msgs.msg import X/from sloam_msgs.srv import X/from sloam_msgs.action import Xresolves to a real.msg/.srv/.actionfile in thesloam_msgspackage, using the known snake_case ↔ UpperCamelCase mapping. - H — every file listed in every
install(PROGRAMS ...)block in everyCMakeLists.txtexists on disk relative to that CMakeLists. - I — no
nodelet_plugins.xmlremains anywhere in the repo. The ROS1 nodelet machinery was replaced byrclcpp_components::RCLCPP_COMPONENTS_REGISTER_NODE. - J — no XML
*.launchfiles remain anywhere outsidetools/andtests/. - K — within each
*.launch.pyfile, everyLaunchConfiguration('x')reference has a matchingDeclareLaunchArgument('x', ...)in the same file. Within-file check (does not followIncludeLaunchDescriptionchains). Exempts the ROS2-injected launch builtins (log_level,launch_prefix,use_sim_time, etc.). The awk reads each launch file as a single record so multi-lineDeclareLaunchArgument(\n 'name',\n ...)forms are matched correctly. - L — no hardcoded user-specific absolute paths (
/home/<user>/,/opt/slideslam_docker_ws,/opt/bags/,/root/) in any.cpp/.h/.hpp/.pysource file. Strips C and Python comments before matching. - M — every
Node(package='<local_pkg>', executable='<y>')call in every*.launch.pyresolves to either anadd_executable(<y> ...)target or aninstall(PROGRAMS .../<y>)entry in the target package'sCMakeLists.txt. Local packages aresloam,sloam_msgs,multi_robot_utils_launch,object_modeller,scan2shape_launch; external packages (tf2_ros,topic_tools,rviz2, third-party drivers, etc.) are skipped. - N — no raw
declare_parameter("key", ...)call appears in 2+ source files within the same package. ROS2 throwsrclcpp::exceptions::ParameterAlreadyDeclaredat runtime if the same parameter is declared twice on the same node, so this is a real hazard. The safe*_declare_or_get<T>(node, "key", default)wrapper family used throughoutbackend/sloam(in_declare_or_get,sn_declare_or_get,pr_declare_or_get, plaindeclare_or_get) is explicitly exempted — those wrappers guard withnode->has_parameter()before declaring, so multiple callers on the same key are safe. - O — every
#include <pkg/...>in a managed package's C/C++ sources resolves to a<depend>entry in that package'spackage.xml. System libraries (Eigen, Boost, PCL, GTSAM, Sophus, OpenCV, yaml-cpp, fmt, glog, tbb, gtest, POSIX headers) are exempt because they're pulled viafind_package+target_link_libraries, not<depend>.backend/sloam/clipper_semantic_object/is exempt entirely (vendored third-partyadd_subdirectory(), not a ROS package). - P — for every
Node(package='<managed>', parameters=[{...}])call in a*.launch.py, every literal dict key is declared in the target package's source viadeclare_parameter, thedeclare_or_get<T>wrapper family,get_param_or, ordeclare_parameter_if_not_declared. Catches the classic ROS2 silent-ignore bug where a launch file passes a parameter the target node never callsdeclare_parameteron.scan2shape_launchadditionally walksfrontend/scan2shape/script/because it installs scripts from that sibling directory. - Q — every
*.sh/*.bashunderbackend/,frontend/,tools/, andtests/passesbash -n(parse-only syntax check). Skipped cleanly whenbashis not onPATH. - R — for every
PathJoinSubstitution([FindPackageShare('<managed>'), 'seg', ...])in a*.launch.py, the resolved path exists in<managed>'s source tree. Catches launch files whose config / rviz / sub-launch path references went stale during the port (e.g., a renamed yaml that still has the old name in a launch file). External packages are skipped (we can't introspect their share/ tree), directory-only targets (no file extension) are skipped, andmsckf_calib.yamlis carved out because it's generated at first run by the upstream calibration tooling.
Run it with:
bash tests/static/check_ros2_port.sh # summary only
bash tests/static/check_ros2_port.sh --verbose # dump hit details on failures
Exits 0 if all 55 pass, non-zero otherwise. Exempted from every section: backend/sloam/clipper_semantic_object/ (vendored third-party CMake library) and frontend/scan2shape/rviz/.
Parallel encoding of the same checks as real pytest unit tests, for use in a future CI that has Python 3.10+ available. Uses only the standard library plus pytest — no ROS imports. The bash runner above is the authoritative layer; the pytest layer is useful when a build system needs structured pass/fail output.
pip install pytest
pytest tests/python -v
Runtime test that requires a working ROS2 Jazzy environment (source /opt/ros/jazzy/setup.bash). For every *.launch.py file under backend/ and frontend/, runs ros2 launch --print-description <abs_path> with a configurable per-file timeout (default 20s) and reports OK / FAIL / TIMEOUT per file. Using the direct-file-path form of ros2 launch means this test does NOT require the workspace to be built — only that ros2 itself is on PATH. Skips with exit code 77 (autotools-style) if ros2 is not installed, so CI runners without a ROS2 environment treat it as a skipped test rather than a failed one.
bash tests/integration/launch_smoke_test.sh
VERBOSE=1 bash tests/integration/launch_smoke_test.sh # dump per-file error output
LAUNCH_TIMEOUT=60 bash tests/integration/launch_smoke_test.sh
The following have not been verified end-to-end on ros2_dev:
colcon build --symlink-installsuccess on Ubuntu 24.04 + ROS2 Jazzy.- Runtime pub/sub, QoS, and message serialization.
- SLAM correctness on converted ROS2 bags.
- TF chain correctness across the multi-robot pipeline.
- Action handshakes for
ActiveLoopClosure/DetectLoopClosure. - End-to-end demo runs (forest, parking lot, indoor RGBD, KITTI).
See tests/integration/README.md for the concrete checklist of runtime tests future contributors should add.
We use GTSAM as the backend. We thank Guilherme Nardari for his contributions to this repository.
If you find our system or any of its modules useful for your academic work, we would appreciate it if you could cite our work as follows:
@article{liu2024slideslam,
title={Slideslam: Sparse, lightweight, decentralized metric-semantic slam for multi-robot navigation},
author={Liu, Xu and Lei, Jiuzhou and Prabhu, Ankit and Tao, Yuezhan and Spasojevic, Igor and Chaudhari, Pratik and Atanasov, Nikolay and Kumar, Vijay},
journal={arXiv preprint arXiv:2406.17249},
year={2024}
}