DEV Community

Cover image for Global Navigation + Gradient Path Planning
Jorge Martin
Jorge Martin

Posted on

1

Global Navigation + Gradient Path Planning

This is the blog of the P4-RM, where I programmed the behavior of a taxi based on Gradient Path Planning.

Objetive

The objective of this practice was to program the behavior of a taxi using gradient path planning, which generates a cost map and moves following the path of least cost until reaching a target.

Coding

Libraries

  • This library provides access to mathematical functions and constants.
import math
Enter fullscreen mode Exit fullscreen mode
  • This library provides functions for working in domain of linear algebra, fourier transform, matrices and arrays.
import numpy as np
Enter fullscreen mode Exit fullscreen mode

Implementation

Cost Map

The creation of the cost map consists of three distinct functions: one that creates the simple cost map, another that uses this same cost map to expand the obstacles and penalize the taxi for getting too close to them, and a third function that normalizes the costs.

Cost Map

MAP_URL = '/resources/exercises/global_navigation/images/cityLargenBin.png'
city_map = GUI.getMap(MAP_URL)

def normalize_cost(cost_grid, robot_map, target_map):
    ... 
    normalized_grid = np.full_like(cost_grid, np.inf)
    normalized_grid[finite_mask] = (cost_grid[finite_mask] / max_cost) * 255

    return normalized_grid

def show_cost(target_map, robot_map, city_map):
    cost_grid = np.full(city_map.shape, np.inf)
    cost_grid[target_map[0], target_map[1]] = 0
    queue = [(target_map[0], target_map[1])]

    ...

    # Normalize
    normalized_grid = normalize_cost(cost_grid, robot_map, target_map)
    return normalized_grid

def expand_obstacle(cost_grid, city_map, cushion_size=3, cushion_cost=255):
    ...

    return expanded_grid
Enter fullscreen mode Exit fullscreen mode

Navigation

The car navigates based on the gradient, it obtains the cost map and analyzes its 8 neighboring cells. These neighbors can range from unreachable (not expanded or obstacles) to cells with varying costs. Among the latter, the taxi will move toward the cell with the lowest cost. This makes the navigation semi-reactive.

Cost map sim

def navigate_to_target(cost_grid, robot_map, target_map):
    ...

    while robot_map != target_map:
        # Neighbors of the robot
        neighbors = [(robot_map[0] - 1, robot_map[1]), (robot_map[0] + 1, robot_map[1]),
                     (robot_map[0], robot_map[1] - 1), (robot_map[0], robot_map[1] + 1),
                     (robot_map[0] - 1, robot_map[1] - 1), (robot_map[0] + 1, robot_map[1] + 1),
                     (robot_map[0] - 1, robot_map[1] + 1), (robot_map[0] + 1, robot_map[1] - 1)]

        ...

        next_step = min(valid_neighbors, key=lambda x: cost_grid[x[0], x[1]])

        ...
        next_grid = GUI.gridToWorld((next_step[1], next_step[0]))

        while distance > 0.3:
            ...
            target_grid_x, target_grid_y = next_grid
            direction = math.atan2(distance_y, distance_x)
            angle_diff = math.atan2(math.sin(direction - robot_orientation), math.cos(direction - robot_orientation))

            linear_speed = 6 if abs(angle_diff) < 0.2 else 0
            angular_speed = 0 if abs(angle_diff) < 0.2 else angle_diff * 2

            HAL.setV(linear_speed)
            HAL.setW(angular_speed)
        ...

        robot_map = next_step
Enter fullscreen mode Exit fullscreen mode

Difficulties

  • One of the main problems I encountered was during navigation. There were times when two adjacent cells had the same cost or were surrounded by higher-cost cells, which caused the robot to get stuck in a constant loop. I solved this by prohibiting the robot from returning to a previous cell.
  • Another problem I encountered was that when converting from world to grid, the x and y coordinates were inverted, as x referred to the columns and y to the rows.

Logbook

  • Day 1: Test the world and implement conversions from world coordinates to grid.
  • Day 2: Create a simple cost map.
  • Day 3: Enhance the cost map by expanding obstacles.
  • Day 4: Normalize the cost map and finalize its generation when it reaches the taxi.
  • Day 5: Implement navigation.

Functionality

Simple test


(In case the video doesn´t play try this link: https://youtu.be/wn9l0Gxg-0M)

Test long ride

I placed the first target in the bottom-left corner and the second one in the top-right corner to observe the taxi's behavior during a very long ride.


(In case the video doesn´t play try this link: https://youtu.be/45cWqGK-cH4)

Changing target in the middle of the ride

The taxi reaches the first target before changing to the next one.


(In case the video doesn´t play try this link: https://youtu.be/hGz6yQENSe0)

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay