This repository contains the code for Terra: Hierarchical Terrain-Aware 3D Scene Graph for Task-Agnostic Outdoor Mapping
- Terra
- Table of Contents
- Paper
- Setup
- Datasets and Metric Mapping
- Building Terra
- Task-Execution with Terra
Preprint Citation:
C. R. Samuelson, A. Austin, S. Knoop, B. Romrell, G. R. Slade, T. W. McLain, and J. G. Mangelson, “Terra: Hierarchical Terrain-Aware 3D Scene Graph for Task-Agnostic Outdoor Mapping,” Sept 2025. [Online]. Available: https://arxiv.org/abs/2509.19579
Accepted to ICRA 2026. Citation Pending.
- Docker
- NVIDIA GPU
Our repository is designed for ROS 2 Humble. To handle dependency issues, our repository is built in Docker using the following container.
First pull our Terra docker container
docker pull frostlab/ros2_terra:latest
xhost +local:dockerStart the container in your terminal
docker run --rm -it --gpus all --net host -v /tmp/.X11-unix:/tmp/.X11-unix -v <path/to/terra_repo>:/docker_ros2_ws/src/terra -v <ros2_bags_folder>:/<ros2_bags_folder> -e DISPLAY=$DISPLAY frostlab/ros2_terraBuild and source the ros2 repository
tmux
cd docker_ros2_ws
colcon build --symlink-install --cmake-args -DCMAKE_BUILD_TYPE=Release
source install/setup.bash
The ros launch code uses LIO-SAM to build the metric map, extracts and saves relevant data in the dataset folder structure below.
Dataset folder structure
my_dataset
├── global_pc
| ├── global_pc_{timestamp}.npy
| ├── ...
├── camera1_images
| ├── cam1_img_{timestamp}.jpg
| ├── ...
├── lidar_pc
| ├── lidar_pc_{timestamp}.npy
| ├── ...
├── transformations_lidar2cam1
| ├── transform_lidar_to_cam1_{timestamp}.npy
| ├── ...
├── transformations_lidar2global
| ├── transform_lidar_to_map_{timestamp}.npy
| └── ...
Simulation: Business Campus Dataset
- Download the dataset: Dense 1/8 (3.30 GB), Sparse 1/3 (1.66 GB), and Sparse Full (13.34 GB).
- These links enable downloading the extracted metric data from each rosbag collected in HoloOcean.
- Can extract subfolders into a single dataset folder with:
unzip holoocean_<dataset-name>.zip -d holoocean_<dataset-name> - Make sure the location of this downloaded metric data has been volumed into the docker container.
- Download the simulated YOLO model here.
- After unzipping, the model is located in:
holo_3cls_nano_stepsz25_256imgsz_500epochs/weights/best.pt. - Identify your container name in a terminal with:
docker ps - Copy the model into the container with:
docker cp <yolo_folder_location>/holo_3cls_nano_stepsz25_256imgsz_500epochs/weights/best.pt <container_name>:/holoocean_3cls.pt
- After unzipping, the model is located in:
- Given this metric data, proceed to Building Terra.
Real-World: South Campus Dataset
- Download the dataset (in progress)
- Put the rosbag in the volumed
ros2_bags_folderso you can access it in the docker container - Copy the contents of the
config/south_campus/liosam_params.yamlfile to replace the contents in theparams.yamlfile in theLIO-SAM/configfolder - Update the
config/south_campus/params.yamlto match the correctrosbag_pathandsave_folder. - Now to build the metric point cloud map with LIO-SAM and save the data into our folder structure, run
ros2 launch terra_ros build_metric_map_south_campus.launch.pyCustom Datasets
If you have a ROS 2 bag of your Ouster OS1-128 LiDAR and RGB Camera data, then do the following to run LIO-SAM:
- Edit the
params.yamlfile in theLIO-SAM/configfolder to match your LiDAR and IMU ros topics as well as the extrinsic transformation between the two. - Copy the contents
config/rviz2.rvizfile to replace therviz2.rvizfile in theLIO-SAM/configfolder. - Update the
params.yamlros parameters interra_ros/configfor your dataset and rosbag - Now to build the metric point cloud map with LIO-SAM and save the data into our folder structure, run
ros2 launch terra_ros build_metric_map_multicam_rate.launch.py params_file:=<path_to_updated_params_file>.yamlChange into the Terra repo in container with: cd /docker_ros2_ws/src/terra
Building Metric-Semantic Map (MS Map)
Provided that you have all the data saved in the file structure shown above, you can build the metric-semantic map (ms map) as follows:
- Update the
terra/config/<dataset_name>/msmap.yamlarguments to match the saved data folder path and YOLO terrain model location.- We provide different msmap yaml files showing capabilities of handling more than 1 camera image data as well as using YOLOE for datasets where you don't have a trained YOLO terrain model.
- Run the MS Map code with the correct yaml filepath as an argument as follows:
python3 -m terra.ms_map --params=terra/config/<dataset_name>/msmap.yamlNote: This will take a while to process at about 1 second per lidar-image pair.
To visualize the resulting MS Map, we have provided a helper script where you just need to pass in the filepath to your saved data folder. Each different semantic CLIP id will have a different color. For example:
python3 -m terra.visualize_msmap --data_folder=/data/folder --output_folder=/directory/to/ms_map/output --num_terrain=3 --pt_size=2.0Building Region and Place Layers from MS Map
With the results saved from MS Map, you can build the terrain-aware places and region layers of the 3DSG as follows:
- Update the
terra/config/<dataset_name>/build_terra.yamlarguments to match the saved MS Map files location and other relevant arguments. - Run Build Terra code with your updated yaml file as an argument as follows:
python3 -m terra.build_terra --params=/path/to/build_terra.yamlTo visualize the resulting 3D Scene Graph, run:
python3 -m terra.visualize_terra --terra_3dsg=/path/to/saved/terra_nxgraph.pkl --global_pc=/folder/path/to/global_pc/ --num_terrains=num_terrains --view_json=view.json- The arguments are defined as:
terra_3dsg: Path to the saved 3DSG.- Note:
build_terra.pysaves a terra_nxgraph.pkl and a Terra.pkl file. The first is just the nx.Graph 3DSG object and the latter is our Terra 3DSG class. This is asking for the first one.
- Note:
global_pc: Path to the folder that contains all of the global point clouds saved from the metric mapping step.num_terrains: Integer of the number of terrains used by the YOLO modelview_json: (Optional) Saved json file to tell Open3D to display the 3DSG at a certain angle and distance.
Object Retrieval Tasks
To perform object retrieval tasks with the Terra 3DSG saved from Building Terra, is done as follows:
- Modify the
object_retrieval.yamlfile for as many object retrieval tasks of interest as well as other parameters described below. - Run the object retrieval task as follows:
python3 -m terra.object_retrieval_task --params=/path/to/object_retrieval.yaml- YAML parameters are defined as:
terra: Path to the saved Terra 3DSG.- Note:
build_terra.pysaves a terra_3dsg.pkl and a Terra.pkl file. The first is just the nx.Graph 3DSG object and the latter is our Terra 3DSG class. This is asking for the latter.
- Note:
object_tasks: YAML list of object tasksprediction_method: Pass a string of the method to use from the following [ms_avg, ms_max, 3dsg]. These methods are explained in detail in the paper. (Default:ms_avg)alpha: Threshold to determine whether an object is task relevant (i.e. if its cosine-similarity score is abovealphathen it is task-relevant). (Default:0.23)
Region Monitoring Tasks
To perform region monitoring tasks with the Terra 3DSG saved from Building Terra, is done as follows:
- Modify the
region_querying.yamlfile for as many region monitoring tasks of interest as well as other parameters described below. - Run the region monitoring task as follows:
python3 -m terra.region_querying_task --params=/path/to/region_querying.yaml- YAML parameters are defined as:
terra: Path to the saved Terra 3DSG.- Note:
build_terra.pysaves a terra_3dsg.pkl and a Terra.pkl file. The first is just the nx.Graph 3DSG object and the latter is our Terra 3DSG class. This is asking for the latter.
- Note:
region_tasks: YAML list of region monitoring tasksprediction_method: Pass a string of the method to use from the following [max, thresh, mix, aib]. These methods are explained in detail in the paper. (Default:max)alpha: Threshold to determine whether a region is task relevant (i.e. if its cosine-similarity score is abovealphathen it is task-relevant). Only used for methods [thresh, mix, aib]. (Default:0.23)k: Parameter for selecting the top-K task relevant regions. Only used for methods [max, mix]. (Default:1)
Terrain-Aware Path Planning to Destination Query
To perform path planning to a destination query, do the following:
- Modify the
path_panning.yamlfile based on your destination query and the terrain preferences - Run the path planning task as follows:
python3 -m terra.path_planning_task --params=/path/to/path_planning.yaml- YAML parameters are defined as;
terra: Path to the saved Terra 3DSG.- Note:
build_terra.pysaves a terra_3dsg.pkl and a Terra.pkl file. The first is just the nx.Graph 3DSG object and the latter is our Terra 3DSG class. This is asking for the latter.
- Note:
terrain_preferences: List the terrain indices that arepreferredandforbiddenbased on the terrain input and ordering used inbuild_terra.yaml. Thepenaltiesare defined by each terrain index and an associated weight.queries:destination: String explaining the destination querystart: (Optional) string explaining start location. If not used, default's to start being the first place node in the graph
prediction_method: Pass a string of the method to use from the following [ms_avg, ms_max, 3dsg_avg, 3dsg_max, ms_medoid, ms_trim]. These methods are explained in detail in the paper. (Default:ms_avg)alpha: Threshold to determine whether an object is task relevant (i.e. if its cosine-similarity score is abovealphathen it is task-relevant). (Default:0.23)
