Module 3/5 · Weeks 7–9 · 27 h

Obstacle avoidance and mapping

UAT 322 Artificial Intelligence and Autonomous Unmanned Aircraft Systems Integration Laboratory

About 90 minDraft, awaiting reviewLast updated 27 September 2026

Lesson

By the end of this module you will be able to

  1. Build an occupancy grid, inflate obstacles for aircraft size, and find a path with A*
  2. Calculate stopping distance with latency and compare it with sensor range
  3. Explain PX4 Collision Prevention and ArduPilot BendyRuler, with their limits
  4. Explain the principle of SLAM and evaluate a trajectory with ATE RMSE

Prerequisites: UAT 322 modules 1–2

Why this matters

An autonomous survey drone must answer three questions all the time: what is ahead, which way to go, and whether it can stop in time if something appears suddenly. Get any one wrong and the drone may hit a tree or a wall. This module practises the basic tools for all three questions, and how to measure how far the map and position the system builds can be trusted.

Occupancy grids and A*

An occupancy grid divides space into cells, each marked free or occupied. Proposed by Elfes (1989), the idea is still widely used because it merges data from many sensors into one table easily.

A drone is not a point, so obstacles must be inflated by the aircraft’s radius plus a safety margin before searching for a path. A* (Hart, Nilsson and Raphael, 1968) finds the shortest path by expanding the cell with the lowest , where is the cost so far and an estimate of the remaining distance. If never overestimates the true distance, A* is guaranteed to find the shortest path.

Example 1 Finding a path with A*

Each cell is 1 m wide, obstacles are inflated by 1 cell, and movement is in four directions.

import heapq

grid = ["............",
        "............",
        "....###.....",
        "....###.....",
        "....###..#..",
        ".........#..",
        "............",
        "............"]
ROWS, COLS = len(grid), len(grid[0])
start, goal = (6, 1), (2, 10)


def inflate(g, r=1):
    occ = {(i, j) for i in range(ROWS) for j in range(COLS) if g[i][j] == "#"}
    return {(i + a, j + b) for i, j in occ for a in range(-r, r + 1) for b in range(-r, r + 1)
            if 0 <= i + a < ROWS and 0 <= j + b < COLS}


def astar(blocked, s, g):
    h = lambda p: abs(p[0] - g[0]) + abs(p[1] - g[1])       # Manhattan distance never overestimates
    heap, came, cost, expanded = [(h(s), 0, s)], {s: None}, {s: 0}, 0
    while heap:
        _, c, p = heapq.heappop(heap)
        expanded += 1
        if p == g:
            break
        for d in ((1, 0), (-1, 0), (0, 1), (0, -1)):
            q = (p[0] + d[0], p[1] + d[1])
            if 0 <= q[0] < ROWS and 0 <= q[1] < COLS and q not in blocked and c + 1 < cost.get(q, 1e9):
                cost[q], came[q] = c + 1, p
                heapq.heappush(heap, (c + 1 + h(q), c + 1, q))
    path = [g]
    while came[path[-1]] is not None:
        path.append(came[path[-1]])
    return path[::-1], expanded


blocked = inflate(grid)
path, expanded = astar(blocked, start, goal)
print(f"path length {len(path) - 1} m, cells expanded {expanded}")
for i in range(ROWS):
    print("".join("S" if (i, j) == start else "G" if (i, j) == goal else "*" if (i, j) in path
                  else "#" if grid[i][j] == "#" else "+" if (i, j) in blocked else "." for j in range(COLS)))
path length 17 m, cells expanded 56
..*********.
..*+++++..*.
.**+###+..G.
.*.+###++++.
.*.+###++#+.
.*.++++++#+.
.S......+++.
............

# marks obstacles, + the inflation and * the path. A* avoids both obstacles and inflation. The path follows the grid in right angles, so real systems smooth it before sending it as setpoints.

A grid of 8 rows and 12 columns. Pink cells are obstacles, orange cells the inflation around them for aircraft size, and blue cells the A* path from S at bottom left up to the top row and down to G, 17 cells long
Figure 1 Occupancy grid and A* path

Can it stop in time?

Stopping distance has two parts: the distance travelled during the latency before braking starts, and the braking distance, just as a driver must count the time before the foot reaches the brake pedal.

v, latency, decel, sensor_range = 5.0, 0.25, 3.0, 8.0   # m/s, s, m/s², m
reaction = v * latency
braking = v ** 2 / (2 * decel)
stop = reaction + braking
print(f"reaction {reaction:.2f} m + braking {braking:.2f} m = {stop:.2f} m (sensor range {sensor_range} m)")
v_max = (-latency + (latency**2 + 2 * sensor_range / decel) ** 0.5) * decel
print(f"highest speed that still stops within the sensor range: {v_max:.2f} m/s")
reaction 1.25 m + braking 4.17 m = 5.42 m (sensor range 8.0 m)
highest speed that still stops within the sensor range: 6.22 m/s
A horizontal bar on a distance axis from 0 to 9 metres. A yellow segment of 1.25 metres is the distance during latency and an orange segment of 4.17 metres the braking distance, stopping at 5.42 metres. A green dashed line at 8 metres is the sensor range
Figure 2 Stopping distance at 5 m/s, 0.25 s latency and 3 m/s² braking

At 5 m/s the drone stops within 5.42 m, less than the 8 m sensor range, but the highest speed that still stops in time is only about 6.2 m/s. In practice, allow more for wind, position error and objects the sensor may miss, such as power lines.

Avoidance in the flight controller

  • PX4 Collision Prevention works only in multicopter Position mode. It limits speed near obstacles, using distance data from a range sensor or from the companion computer via the OBSTACLE_DISTANCE message. The distance to keep is set with CP_DIST, whose default of −1 means disabled
  • ArduPilot offers several levels, from Simple avoidance that stops in front of obstacles, to BendyRuler, which finds a way around them (in Auto, Guided and RTL modes), and Dijkstra’s, which plans around known fences and exclusion zones

These systems depend entirely on sensors: if the sensor cannot see an object, the system cannot avoid it. They are an extra layer of protection, not a reason to fly close to obstacles.

SLAM and trajectory evaluation

SLAM (simultaneous localization and mapping) builds a map and locates the vehicle in it at the same time, for places without GNSS such as indoors or under bridges. Cadena et al. (2016) review the development of SLAM, and ORB-SLAM3 is an open library supporting monocular, stereo and visual–inertial set-ups.

A common quality measure is the absolute trajectory error (ATE) from the benchmark of Sturm et al. (2012): the RMSE of the distance between estimated and true positions. Zhang and Scaramuzza (2018) warn that the two trajectories must first be aligned in a common frame, and the alignment method must always be stated.

import numpy as np

truth = np.array([[0, 0], [1, 0], [2, 0], [3, 0], [4, 0], [5, 0]], dtype=float)
estimate = np.array([[0, 0], [1.1, 0.1], [2.1, 0.2], [3.2, 0.2], [4.2, 0.3], [5.3, 0.4]])
errors = np.linalg.norm(estimate - truth, axis=1)
print("error per pose (m):", np.round(errors, 2))
print(f"ATE RMSE {np.sqrt(np.mean(errors ** 2)):.3f} m, final drift {errors[-1]:.2f} m")
error per pose (m): [0.   0.14 0.22 0.28 0.36 0.5 ]
ATE RMSE 0.297 m, final drift 0.50 m

The error grows with distance, the signature of drift. The two sets here already share a frame, so no alignment is needed; real data must be aligned first.

Module lab

Lab: obstacle avoidance in SITL

  1. Change the map in Example 1 to include a narrow gap, then try inflation of 0, 1 and 2 cells, recording when the path changes or cannot be found.
  2. Enable Collision Prevention in PX4 SITL with a simulated range sensor, set CP_DIST, and fly towards a wall in Position mode, recording where the drone actually stops.
  3. Vary speed and latency in the stopping-distance formula and compare with the SITL results.
  4. Using the trajectory data set prepared by the instructor, calculate ATE RMSE and explain the alignment used.
  5. Conclude the highest safe speed for the training drone’s sensor, with your assumptions.

Common mistakes

Watch out

  • Not inflating obstacles for aircraft size, so paths graze obstacles and propellers strike
  • Forgetting latency in stopping distance and counting only braking
  • Assuming Collision Prevention is already on, when it is off by default
  • Believing the sensor sees everything, although wires, glass and thin branches may be missed
  • Reporting ATE without stating the alignment

Summary

  • An occupancy grid represents space as cells; inflate obstacles for aircraft size before path finding
  • A* expands the cell with the lowest and finds the shortest path when never overestimates
  • Stopping distance is latency distance plus braking distance, and must be less than sensor range with a margin
  • PX4 and ArduPilot have built-in avoidance, but it depends on sensors and must be enabled
  • SLAM builds a map and localises at once, and is evaluated with ATE after alignment

Check your understanding

  1. In A*, if and , what is for that cell?
  2. At 4 m/s with 0.5 s latency and 2 m/s² braking, what is the stopping distance?
  3. Why must obstacles be inflated before path finding?
  4. What does the PX4 default CP_DIST = −1 mean?
  5. Position errors at three poses are 0, 3 and 4 m. What is the ATE RMSE?
Answers
  1. m
  2. The drone has size; its centre must stay at least its radius plus a margin from obstacles
  3. Collision Prevention is disabled
  4. m

Key formulas

A* cost
Stopping distance
ATE RMSE

Key references

  1. Elfes, A. (1989). Using occupancy grids for mobile robot perception and navigation. Computer, 22(6), 46–57. link
  2. Hart, P. E., Nilsson, N. J., & Raphael, B. (1968). A formal basis for the heuristic determination of minimum cost paths. IEEE Transactions on Systems Science and Cybernetics, 4(2), 100–107. link
  3. PX4 Autopilot. Collision prevention. PX4 user guide (main). link
  4. ArduPilot Dev Team. Object avoidance. ArduPilot Copter documentation. link
  5. Cadena, C., Carlone, L., Carrillo, H., Latif, Y., Scaramuzza, D., Neira, J., Reid, I., & Leonard, J. J. (2016). Past, present, and future of simultaneous localization and mapping: Toward the robust-perception age. IEEE Transactions on Robotics, 32(6), 1309–1332. link
  6. Campos, C., Elvira, R., Gómez Rodríguez, J. J., Montiel, J. M. M., & Tardós, J. D. (2021). ORB-SLAM3: An accurate open-source library for visual, visual–inertial, and multimap SLAM. IEEE Transactions on Robotics, 37(6), 1874–1890. link
  7. Sturm, J., Engelhard, N., Endres, F., Burgard, W., & Cremers, D. (2012). A benchmark for the evaluation of RGB-D SLAM systems. In 2012 IEEE/RSJ International Conference on Intelligent Robots and Systems (pp. 573–580). link
  8. Zhang, Z., & Scaramuzza, D. (2018). A tutorial on quantitative trajectory evaluation for visual(-inertial) odometry. In 2018 IEEE/RSJ International Conference on Intelligent Robots and Systems (pp. 7244–7251). link

Further reading

Study the assigned knowledge units in advance, review media and take the module quiz

In class / field

Intensive lab and field practice recorded in a lab notebook

Learning evidence: Lab notebook signed by the instructor

Module quiz

This is a formative self-check, not a graded exam

Knowledge domain: Control, autopilot and navigation · Automation, robotics and swarms · Delivery, indoor operations and warehousing · Sensors and embedded systems