Example: nav_rrt_planning_example

Path planning with the RRT planner in mrpt::nav::PlannerRRT_SE2_TPS, for a robot with arbitrary shape and kinematic constraints, in an obstacle map.

nav_rrt_planning_example screenshot

Modules: mrpt_config, mrpt_gui, mrpt_io, mrpt_maps, mrpt_serialization, mrpt_system | Requires: gui

C++ example source code:

/*                    _
                     | |    Mobile Robot Programming Toolkit (MRPT)
 _ __ ___  _ __ _ __ | |_
| '_ ` _ \| '__| '_ \| __|          https://www.mrpt.org/
| | | | | | |  | |_) | |_
|_| |_| |_|_|  | .__/ \__|     https://github.com/MRPT/mrpt/
               | |
               |_|

 Copyright (c) 2005-2026, Individual contributors, see AUTHORS file
 See: https://www.mrpt.org/Authors - All rights reserved.
 SPDX-License-Identifier: BSD-3-Clause
*/

#include <mrpt/config/CConfigFile.h>
#include <mrpt/gui/CDisplayWindow3D.h>
#include <mrpt/io/CCompressedInputStream.h>
#include <mrpt/maps/CSimpleMap.h>
#include <mrpt/nav.h>
#include <mrpt/random.h>
#include <mrpt/serialization/CArchive.h>
#include <mrpt/system/filesystem.h>  // directoryExists(), ...

#include <iostream>

using namespace mrpt;
using namespace mrpt::nav;
using namespace mrpt::maps;
using namespace std;

// Load example grid map
// MRPT_EXAMPLES_BASE_DIRECTORY provided via compile definition
string mySimpleMap(MRPT_DATA_DIR + string("/datasets/malaga-cs-fac-building.simplemap.gz"));
string myCfgFileName(
    MRPT_DATA_DIR + string("/config_files/navigation-ptgs/ptrrt_config_example1.ini"));

// ------------------------------------------------------
//              TestRRT1
// ------------------------------------------------------
void TestRRT1()
{
  mrpt::random::Randomize();

  // Load the gridmap:
  CSimpleMap simplemap;

  ASSERT_FILE_EXISTS_(mySimpleMap);

  std::cout << "Loading map...";
  {
    mrpt::io::CCompressedInputStream f(mySimpleMap);
    auto arch = mrpt::serialization::archiveFrom(f);
    arch >> simplemap;
  }
  std::cout << "Done! Number of sensory frames: " << simplemap.size() << "\n";

  // Set planner params:
  // ------------------------------
  mrpt::nav::PlannerRRT_SE2_TPS planner;

  // Parameters:
  planner.loadConfig(mrpt::config::CConfigFile(myCfgFileName));

  planner.params.maxLength = 2.0;
  planner.params.minDistanceBetweenNewNodes = 0.10;
  planner.params.minAngBetweenNewNodes = mrpt::DEG2RAD(20);
  planner.params.goalBias = 0.05;

  // Logging:
  planner.params.save_3d_log_freq = 0;  // 500; // save some iterations for debugging

  // End criteria:
  planner.end_criteria.acceptedDistToTarget = 0.25;
  planner.end_criteria.acceptedAngToTarget = 180.0_deg;  // 180d=Any orientation is ok
  planner.end_criteria.maxComputationTime = 15.0;
  planner.end_criteria.minComputationTime = 1.0;  // 0=accept first found acceptable solution

  // Init planner:
  // ------------------------------
  planner.initialize();

  // Set up planning problem:
  // ------------------------------
  PlannerRRT_SE2_TPS::TPlannerResult planner_result;
  PlannerRRT_SE2_TPS::TPlannerInput planner_input;

  // Start & goal:
  planner_input.start_pose = mrpt::math::TPose2D(0, 0, 0);
  planner_input.goal_pose = mrpt::math::TPose2D(-20, -30, 0);

  // Obstacles:
  planner_input.obstacles_points.loadFromSimpleMap(simplemap);
  const auto bbox = planner_input.obstacles_points.boundingBox();
  // Convert gridmap -> obstacle points:
  // gridmap.getAsPointCloud( planner_input.obstacles_points );

  // Workspace bounding box:
  planner_input.world_bbox_min = {bbox.min.x, bbox.min.y, -M_PI};
  planner_input.world_bbox_max = {bbox.max.x, bbox.max.y, +M_PI};

// size_t iters=0;
// Show results in a GUI and keep improving:
#if MRPT_HAS_WXWIDGETS
  mrpt::gui::CDisplayWindow3D win("Result", 1024, 800);
  while (win.isOpen())
#else
  for (size_t i = 0; i < 1; i++)
#endif
  {
    // Refine solution or start over:
    bool refine_solution = false;  // (iters++ % 5 != 0);

    // Start from scratch:
    if (!refine_solution) planner_result = PlannerRRT_SE2_TPS::TPlannerResult();

    // Do path planning:
    planner.solve(planner_input, planner_result);

    std::cout << "Found goal_distance: " << planner_result.goal_distance << "\n";
    std::cout << "Found path_cost: " << planner_result.path_cost << "\n";
    std::cout << "Acceptable goal nodes: " << planner_result.acceptable_goal_node_ids.size()
              << "\n";

#if MRPT_HAS_WXWIDGETS
    // Show result in a GUI:
    mrpt::viz::Scene::Ptr& scene = win.get3DSceneAndLock();

    scene->clear();

    PlannerRRT_SE2_TPS::TRenderPlannedPathOptions render_opts;
    render_opts.highlight_path_to_node_id = planner_result.best_goal_node_id;

    planner.renderMoveTree(*scene, planner_input, planner_result, render_opts);

    win.unlockAccess3DScene();
    win.repaint();
    win.waitForKey();
#endif
  }
}

int main([[maybe_unused]] int argc, [[maybe_unused]] char** argv)
{
  try
  {
    TestRRT1();
    return 0;
  }
  catch (exception& e)
  {
    std::cout << "MRPT exception caught: " << e.what() << "\n";
    return -1;
  }
  catch (...)
  {
    printf("Another exception!!");
    return -1;
  }
}