How build and save map 3D reconstruction to use with nvblox nav2 ?
Hi @AMR_all
It’s pretty simple! There are services to load and save a map generated from nvblox ROS Topics and Services — isaac_ros_docs documentation
ROS Service | Interface | Description |
---|---|---|
~/save_ply |
nvblox_msgs/FilePath | Will save the mesh as the PLY (standard polygon file format, which can be viewed with MeshLab or CloudCompare) at the specified location. |
~/save_map |
nvblox_msgs/FilePath | Will serialize the entire map, including TSDF, ESDF, etc., at the given location. |
~/load_map |
nvblox_msgs/FilePath | Will overwrite the current map in the node with a map loaded from the given path. |
The commands to user are like below
ros2 service call /nvblox_node/save_ply nvblox_msgs/srv/FilePath "{file_path: '/home/USERNAME/super_cool_map.ply'}"
ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath "{file_path: '/home/USERNAME/super_cool_map.nvblx'}"
ros2 service call /nvblox_node/load_map nvblox_msgs/srv/FilePath "{file_path: '/home/USERNAME/super_cool_map.nvblx'}"
Best,
Raffaello
Hi @Raffaello
I have tried to save map and load it following above instructions.
what i do
- in first terminal , i run : ros2 launch nvblox_examples_bringup realsense_example.launch.py
mode:=dynamic - in second terminal and third terminal i do : ros2 service call /nvblox_node/save_ply nvblox_msgs/srv/FilePath “{file_path: '/workspaces/isaac_ros-dev/super_cool_map.ply}”
ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath “{file_path: ‘/workspaces/isaac_ros-dev/super_cool_map.nvblx’}”
But i get error as in terminal
admin@orinnano-desktop:/workspaces/isaac_ros-dev$ ros2 service call /nvblox_node/save_ply nvblox_msgs/srv/FilePath “{file_path: ‘/workspaces/isaac_ros-dev/super_cool_map.ply’}”
waiting for service to become available…
requester: making request: nvblox_msgs.srv.FilePath_Request(file_path=‘/workspaces/isaac_ros-dev/super_cool_map.ply’)
and
admin@orinnano-desktop:/workspaces/isaac_ros-dev$ ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath “{file_path: ‘/workspaces/isaac_ros-dev/super_cool_map.nvblx’}”
requester: making request: nvblox_msgs.srv.FilePath_Request(file_path=‘/workspaces/isaac_ros-dev/super_cool_map.nvblx’)
i have wait more than 10 min to complete this but, it was as it is. map duration was 5-10 seconds.
Please help me how to overcome this problem. I am stuck in this for 4 days. Thank you in advance.
Best,
Amar
I am having similar issues. Has this been resolved yet?
Hi @calebr2310
I forward your issue to the engineering, I keep you posted
Hi @calebr2310, can you please verify that your node is running correctly? If you can, please share the rosgraph, which may help.
Thank you in advance,
Raffaello
Hi @Raffaello ,
Sorry to say it doesn’t work in my case.
To build and save a 3D reconstruction map for use with nvblox nav2
, you need to set up Isaac ROS with the isaac-ros-vslam and isaac-ros-nvblox packages, which enable SLAM and 3D mapping integration. Capture sensor data using compatible cameras or LiDAR, process the data through nvblox to generate the map, and save the output in formats like .pcd
or .bin
. After saving the map, you can load it into nav2 for navigation purposes.
Hi @atmosphereswitchh ,
Thank you for your answer . the problem is i have followed the official guides and resources for nvblox, i setup both ros vslam and isaac ros nvblox i can make map but when i save map, it doesnt save , the terminal halt . Can you give me the command through which you can save map and load map in jetson orin with jetpack 6.
Thank you in advance
Hi @amarnath.m
The commands are the same ROS Topics and Services — isaac_ros_docs documentation
ROS Service | Interface | Description |
---|---|---|
~/save_ply |
nvblox_msgs/FilePath | Will save the mesh as the PLY (standard polygon file format, which can be viewed with MeshLab or CloudCompare) at the specified location. |
~/save_map |
nvblox_msgs/FilePath | Will serialize the entire map, including TSDF, ESDF, etc., at the given location. |
~/load_map |
nvblox_msgs/FilePath | Will overwrite the current map in the node with a map loaded from the given path. |
If you are working with Jetpack 6, you can follow the documentation related to Isaac ROS 3.1: Isaac ROS Nvblox — isaac_ros_docs documentation
You can always switch on the documentation from the version button:
Best,
Raffaello
I tried to save the map using this,
ros2 service call /nvblox_node/save_ply nvblox_msgs/srv/FilePath “{file_path: ‘/home/USERNAME/super_cool_map.ply’}”
ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath “{file_path: ‘/home/USERNAME/super_cool_map.nvblx’}”
ros2 service call /nvblox_node/load_map nvblox_msgs/srv/FilePath “{file_path: ‘/home/USERNAME/super_cool_map.nvblx’}”
it shows
waiting for service to become available…
requester: making request: nvblox_msgs.srv.FilePath_Request(file_path=‘home/workspaces/isaac_ros-dev/super_cool_map.ply’)
i waited for 15min, and even then the map was not saved
Hi @Raffaello,
I am experiencing the same issue with nvblox 3.2
It appears that calls to the save_map service take forever, and no map is actually being saved.
This issue arises when using the Bringup example in conjunction with Isaac Sim 4.5 on an x64 machine.
The sample functions correctly before invoking the save_map service.
I haven’t found any error messages in the logs (or no relevant messages at all), but I’m happy to provide a specific log if needed.
It’s worth noting that the service operates as expected in version 3.1.
Service call:
ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath "{file_path: '/workspaces/isaac_ros-dev/super_cool_map.nvblx'}"
nvblox launch:
ros2 launch nvblox_examples_bringup isaac_sim_example.launch.py
Up — same issue here.
I’ve tried both source installation and Debian packages — the result is the same.
Here’s the command I run:
/workspaces/isaac_ros-dev$ ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath "{file_path: '/workspaces/isaac_ros-dev/map_test.nvblx'}"
waiting for service to become available...
requester: making request: nvblox_msgs.srv.FilePath_Request(file_path='/workspaces/isaac_ros-dev/map_test.nvblx')
But nothing happens — the map is never saved, and there’s no error.
🐳 Using Docker installation (as per Isaac ROS setup).
Tried multiple examples, but saving and loading maps via nvblox
services simply doesn’t work.
❓ Can anyone share a working example or screenshot showing a successful call to the map saving services in nvblox
?
Any help appreciated 🙏
Solved! Maybe its not a best approach, but its worked! Thank you claude-3.7-sonnet powered by CursorIA
used some online PLY viewer to confirm that everything is working properly
Fix for Nvblox Map Save/Load Issue
I’ve thoroughly analyzed the nvblox code and identified the issue: the service calls to save and load maps are queued and processed in a background thread, but there’s likely a deadlock in the task execution mechanism. The saveMap and loadMap functions are waiting for task completion that never happens.
The Problem
-
When save_map is called, the request is added to the
file_path_service_queue_
-
The task is supposed to be picked up and executed by
processServiceRequestTaskQueue
-
The original service call waits indefinitely with
task->waitForTaskCompletion()
-
But something is preventing the task from being executed or completed
The Solution
Let’s make a direct save/load that bypasses the problematic task queue. we’ll fix the actual issue in the nvblox_node.cpp:
First let’s create a backup of the original file
cd /workspaces/isaac_ros-dev/src/isaac_ros_nvblox/nvblox_ros/src/lib/
cp nvblox_node.cpp nvblox_node.cpp.bak
Now create our patched version
Edit the nvblox_node.cpp file to fix the save/load methods:
/////////////////////
//Now, modify the savePly, saveMap, and loadMap functions (around line 1487) with this direct implementation:
void NvbloxNode::savePly(
const std::shared_ptr<nvblox_msgs::srv::FilePath::Request> request,
std::shared_ptr<nvblox_msgs::srv::FilePath::Response> response)
{
RCLCPP_INFO_STREAM(get_logger(), "Direct savePly call for file: " << request->file_path);
// Skip the task queue entirely and execute the save directly
// Create parent directory if needed
try {
std::filesystem::path p(request->file_path);
std::filesystem::create_directories(p.parent_path());
} catch (const std::exception& e) {
RCLCPP_WARN_STREAM(get_logger(), "Error creating directories: " << e.what());
}
// If we get a full path, then write to that path.
bool success = true;
if (ends_with(request->file_path, ".ply")) {
// Make sure the mesh is computed
static_mapper_->updateMesh(UpdateFullLayer::kYes);
success = io::outputMeshLayerToPly(
static_mapper_->mesh_layer(), request->file_path);
} else {
// If we get a partial path then output a bunch of stuff to a folder.
success &= io::outputVoxelLayerToPly(
static_mapper_->tsdf_layer(),
request->file_path + "/ros2_tsdf.ply");
success &= io::outputVoxelLayerToPly(
static_mapper_->esdf_layer(),
request->file_path + "/ros2_esdf.ply");
success &= io::outputMeshLayerToPly(
static_mapper_->mesh_layer(),
request->file_path + "/ros2_mesh.ply");
if (isDynamicMapping(params_.mapping_type)) {
success &= io::outputVoxelLayerToPly(
static_mapper_->freespace_layer(),
request->file_path + "/ros2_freespace.ply");
}
}
if (success) {
RCLCPP_INFO_STREAM(get_logger(), "Successfully saved PLY file(s) to " << request->file_path);
} else {
RCLCPP_ERROR_STREAM(get_logger(), "Failed to save PLY file(s) to " << request->file_path);
}
response->success = success;
}
void NvbloxNode::saveMap(
const std::shared_ptr<nvblox_msgs::srv::FilePath::Request> request,
std::shared_ptr<nvblox_msgs::srv::FilePath::Response> response)
{
RCLCPP_INFO_STREAM(get_logger(), "Direct saveMap call for file: " << request->file_path);
// Skip the task queue entirely and execute the save directly
std::string filename = request->file_path;
if (!ends_with(request->file_path, ".nvblx")) {
filename += ".nvblx";
}
// Create parent directory if needed
try {
std::filesystem::path p(filename);
std::filesystem::create_directories(p.parent_path());
} catch (const std::exception& e) {
RCLCPP_WARN_STREAM(get_logger(), "Error creating directories: " << e.what());
}
// Direct call to save function
response->success = static_mapper_->saveLayerCake(filename);
if (response->success) {
RCLCPP_INFO_STREAM(get_logger(), "Successfully saved map to file: " << filename);
} else {
RCLCPP_ERROR_STREAM(get_logger(), "Failed to save map to file: " << filename);
}
}
// Locate the loadMap function (around line 1576) and replace it with:
void NvbloxNode::loadMap(
const std::shared_ptr<nvblox_msgs::srv::FilePath::Request> request,
std::shared_ptr<nvblox_msgs::srv::FilePath::Response> response)
{
RCLCPP_INFO_STREAM(get_logger(), "Direct loadMap call for file: " << request->file_path);
// Skip the task queue entirely and execute the load directly
std::string filename = request->file_path;
if (!ends_with(request->file_path, ".nvblx")) {
filename += ".nvblx";
}
// Check if file exists
if (!std::filesystem::exists(filename)) {
RCLCPP_ERROR_STREAM(get_logger(), "Map file does not exist: " << filename);
response->success = false;
return;
}
// Direct call to load function
response->success = static_mapper_->loadMap(filename);
if (response->success) {
RCLCPP_INFO_STREAM(get_logger(), "Successfully loaded map from file: " << filename);
} else {
RCLCPP_ERROR_STREAM(get_logger(), "Failed to load map from file: " << filename);
}
}
/////////////////////////////////////////////////////////
Add this near the top of the file with the other includes
#include <filesystem>
Rebuild the package:
cd /workspaces/isaac_ros-dev
colcon build --packages-select nvblox_ros
source install/setup.bash
Execute saving/loading
ros2 service call /nvblox_node/save_ply nvblox_msgs/srv/FilePath "{file_path: '/workspaces/isaac_ros-dev/maps/super_cool_map.ply'}"
ros2 service call /nvblox_node/save_map nvblox_msgs/srv/FilePath "{file_path: '/workspaces/isaac_ros-dev/maps/super_cool_map.nvblx'}"
ros2 service call /nvblox_node/load_map nvblox_msgs/srv/FilePath "{file_path: '/workspaces/isaac_ros-dev/maps/super_cool_map.nvblx'}"
✅ It’s working, but I’m still not sure if this is the recommended fix long-term.
If anyone from NVIDIA or the community has a better suggestion — feel free to jump in!