Article
Robotics · Algorithms · ⏱ ~13 min read

RRT — Rapidly-Exploring Random Trees for Robot Path Planning

Sampling-based motion planning algorithms like RRT (LaValle 1998) and its optimal variant RRT* (Karaman & Frazzoli 2011) revolutionised robot motion planning by sidestepping the intractability of explicit configuration-space obstacle representation. Instead of building a complete roadmap, they incrementally grow a tree of valid configurations through random sampling — probabilistically complete and, in RRT*'s case, asymptotically optimal. They are now standard in robot arms, autonomous vehicles, and quadrotor planning.

1. Configuration Space

A robot's configuration q is a complete description of its state (joint angles, 6D pose, etc.). The configuration space C is the set of all possible configurations. C_free ⊂ C excludes configurations that collide with obstacles.

Example: 2-link arm in 2D q = (θ₁, θ₂) ∈ [0,2π]² (2D configuration space) C_free = all (θ₁,θ₂) where arm links don't intersect obstacles Point robot in 2D: q = (x, y) ∈ ℝ² C_obs = Minkowski sum of robot shape with obstacles → shrink robot to point, expand obstacles Motion planning problem: Find a continuous path γ: [0,1] → C_free such that γ(0) = q_start, γ(1) = q_goal

2. RRT Algorithm

RRT(q_start, q_goal, C, max_iter): T ← Tree with root q_start FOR i = 1 … max_iter: 1. q_rand ← SAMPLE(C_free) (uniform random in free space) 2. q_near ← NEAREST(T, q_rand) (nearest tree node by metric d) 3. q_new ← STEER(q_near, q_rand, Δq) (move from q_near toward q_rand by step Δq) 4. IF COLLISION_FREE(q_near → q_new): T.ADD_VERTEX(q_new) T.ADD_EDGE(q_near, q_new) IF d(q_new, q_goal) < ε_goal: RETURN path(q_start → q_new) RETURN FAILURE Key properties: Probabilistically complete: P(find path) → 1 as iter → ∞ NOT optimal: path quality depends on step size Δq and sampling Complexity: O(n log n) with kd-tree for NEAREST

3. Goal Bias and the Connect Variant

Goal bias: with probability p_goal, sample q_rand = q_goal directly Typical p_goal = 0.05–0.10 Effect: Creates a direct "pull" toward goal region, significantly reducing iterations to convergence in open spaces. Too high bias → poor exploration of narrow passages. RRT-Connect (Kuffner & LaValle 2000): Grow TWO trees: T_start (from q_start) and T_goal (from q_goal) Each iteration: extend T_start toward q_rand, then extend T_goal toward T_start's latest node. Connect when distance < ε. Advantage: fills space more efficiently, ~5-10× faster than RRT in typical environments.

4. RRT* — Asymptotic Optimality

RRT augments tree building with two extra steps: CHOOSE_PARENT (rewire to best parent): X_near ← all nodes within ball B(q_new, r) r = γ · (log(|T|) / |T|)^(1/d) (shrinking radius) Choose x_min = argmin_{x ∈ X_near} [cost(x) + d(x, q_new)] where collision check along (x_min → q_new) passes REWIRE (improve neighbours through q_new): FOR each x_near ∈ X_near: IF cost(q_new) + d(q_new, x_near) < cost(x_near): AND collision_free(q_new → x_near): reparent x_near to q_new Convergence: cost(path_RRT*) → cost_optimal as n → ∞ RRT (no rewiring): stuck at suboptimal path forever RRT*: monotonically improving cost as iterations increase

5. Informed RRT*

Once a feasible path of cost c_best is found, restrict sampling to the heuristically relevant region — the prolate hyperspheroid containing all configurations that could improve the current solution: Ellipsoid axes: a (major) = c_best / 2 b (minor) = √(c_best² − d(q_start, q_goal)²) / 2 Center = midpoint of q_start and q_goal Any point outside this ellipsoid cannot be on a shorter path. → Directed sampling dramatically focuses search on optimal path. Convergence benefit: RRT*: samples all of C_free uniformly → slow cost improvement Informed RRT*: as c_best → c_optimal, ellipsoid collapses to line → very fast last 20% of optimisation

6. Bidirectional RRT

RRT-Connect

Two trees grown simultaneously from start and goal. Each iteration expands one tree toward the other's latest node (greedy CONNECT). Fastest convergence for holonomic robots.

BiRRT*

Bidirectional + rewiring. Bridges the gap between the two trees via the "connection node", then applies RRT* rewiring to both. Asymptotically optimal.

LBTRRT

Lower-Bound Tree RRT maintains a lower-bound tree alongside the RRT tree. Provides anytime solution with guaranteed approximation ratio ε to optimal path length.

LQRRRT

Extends RRT to kinodynamic systems using LQR-generated local steering. Handles differential constraints (unicycle, car, drone dynamics) that simple segment steering cannot.

7. JavaScript Implementation

// RRT for a 2D point robot with circular obstacles
class RRT {
  constructor(start, goal, obstacles, bounds, {stepSize=20, goalBias=0.1, maxIter=5000}={}) {
    this.goal = goal; this.obstacles = obstacles; this.bounds = bounds;
    this.stepSize = stepSize; this.goalBias = goalBias; this.maxIter = maxIter;
    this.nodes = [start];         // {x, y, parentIdx}
    start.parentIdx = -1;
  }

  sample() {
    if (Math.random() < this.goalBias) return {...this.goal};
    return {
      x: this.bounds.minX + Math.random() * (this.bounds.maxX - this.bounds.minX),
      y: this.bounds.minY + Math.random() * (this.bounds.maxY - this.bounds.minY)
    };
  }

  nearest(q) {
    let best = 0, bestD = Infinity;
    for (let i = 0; i < this.nodes.length; i++) {
      const d = dist(this.nodes[i], q);
      if (d < bestD) { bestD = d; best = i; }
    }
    return best;
  }

  steer(from, to) {
    const d = dist(from, to);
    if (d <= this.stepSize) return {...to};
    const t = this.stepSize / d;
    return {x: from.x + t*(to.x-from.x), y: from.y + t*(to.y-from.y)};
  }

  collisionFree(a, b) {
    // Sample along segment, check each against obstacles
    const steps = Math.ceil(dist(a, b) / 5);
    for (let i = 0; i <= steps; i++) {
      const t = i / steps;
      const px = a.x + t*(b.x-a.x), py = a.y + t*(b.y-a.y);
      if (this.obstacles.some(o => dist({x:px,y:py}, o) <= o.r)) return false;
    }
    return true;
  }

  build() {
    for (let i = 0; i < this.maxIter; i++) {
      const q_rand = this.sample();
      const nearIdx = this.nearest(q_rand);
      const q_new = this.steer(this.nodes[nearIdx], q_rand);
      if (!this.collisionFree(this.nodes[nearIdx], q_new)) continue;
      q_new.parentIdx = nearIdx;
      this.nodes.push(q_new);
      if (dist(q_new, this.goal) < this.stepSize && this.collisionFree(q_new, this.goal))
        return this.extractPath(this.nodes.length - 1);
    }
    return null; // not found
  }

  extractPath(idx) {
    const path = [];
    while (idx !== -1) { path.unshift(this.nodes[idx]); idx = this.nodes[idx].parentIdx; }
    path.push(this.goal);
    return path;
  }
}

function dist(a, b) { return Math.hypot(a.x-b.x, a.y-b.y); }

// Usage:
const rrt = new RRT(
  {x:50, y:50},  {x:750, y:550},
  [{x:300, y:200, r:80}, {x:500, y:400, r: 100}],
  {minX:0, maxX:800, minY:0, maxY:600}
);
const path = rrt.build();
if (path) console.log(`Path found: ${path.length} waypoints`);

8. Variants and Applications

Industrial Arms

RRT in joint-angle space plans collision-free trajectories for 6-DOF manipulators. Configuration space is 6D, obstacles are complex swept volumes. MoveIt! uses OMPL (Open Motion Planning Library).

Autonomous Vehicles

Kinodynamic RRT with car kinematics (bicycle model) plans feasible paths. Combined with model-predictive control for tracking. Common in Apollo, Autoware open-source stacks.

Quadrotors

RRT* in SE(3) or 3D position space with polynomial trajectory smoothing. Combined with trajectory optimisation (CHOMP, TrajOpt) to satisfy dynamic feasibility constraints.

Surgical Robots

Concentric tube robots need configuration-space planning in 6D tube configurations, with collision checks against CT-derived anatomical models. Probabilistic roadmaps also used.

🗺️ Open Pathfinding →