Potential Field Module User Guide

This comprehensive guide covers the potential field path-planning tools in ManipulaPy, optimized for Python 3.10.12.

Note

This guide is written for Python 3.10.12 users and includes version-specific examples and performance tips.

Introduction to Potential Fields

Potential field methods treat the robot as a point moving under the influence of an artificial potential surface. The robot is β€œpulled” toward the goal by an attractive potential and β€œpushed” away from obstacles by repulsive potentials. By following the negative gradient of the combined field, the robot can find a collision-free path.

Key components:

  • Attractive potential draws the robot toward the goal.

  • Repulsive potential pushes the robot away from obstacles within an influence radius.

  • Gradient direction of steepest descent in the combined potential.

  • Collision checking rapid test whether a given configuration is in collision.

Mathematical Background

Let \(\mathbf{q} \in \mathbb{R}^n\) be the robot’s configuration (e.g., joint angles). Let \(\mathbf{q}_{\mathrm{goal}}\) be the goal configuration, and let \(\{\mathbf{o}_i \in \mathbb{R}^n\}\) be a set of obstacle points.

Attractive Potential

A common quadratic attractive potential:

\[U_{\mathrm{att}}(\mathbf{q}) = \frac{1}{2} k_{\mathrm{att}} \|\mathbf{q} - \mathbf{q}_{\mathrm{goal}}\|^2\]

where \(k_{\mathrm{att}} > 0\) is the attractive gain.

Repulsive Potential

An inverse-distance repulsive potential, active only within an influence distance \(d_0\):

\[\begin{split}U_{\mathrm{rep}}(\mathbf{q}) = \sum_{i} \begin{cases} \frac{1}{2} k_{\mathrm{rep}} \left(\frac{1}{d_i} - \frac{1}{d_0}\right)^2 & \text{if } d_i \leq d_0,\\ 0 & \text{if } d_i > d_0, \end{cases}\end{split}\]

where \(d_i = \|\mathbf{q} - \mathbf{o}_i\|\) and \(k_{\mathrm{rep}} > 0\).

Total Potential and Gradient

The combined potential:

\[U(\mathbf{q}) = U_{\mathrm{att}}(\mathbf{q}) + U_{\mathrm{rep}}(\mathbf{q}).\]

The control β€œforce” is the negative gradient:

\[\mathbf{F}(\mathbf{q}) = -\nabla U(\mathbf{q}) = -\nabla U_{\mathrm{att}}(\mathbf{q}) - \nabla U_{\mathrm{rep}}(\mathbf{q}).\]

Closed-form gradients:

\[\nabla U_{\mathrm{att}}(\mathbf{q}) = k_{\mathrm{att}} (\mathbf{q} - \mathbf{q}_{\mathrm{goal}}),\]
\[\nabla U_{\mathrm{rep}}(\mathbf{q}) = \sum_{i: d_i \leq d_0} k_{\mathrm{rep}} \left(\frac{1}{d_i} - \frac{1}{d_0}\right) \frac{1}{d_i^3} (\mathbf{q} - \mathbf{o}_i).\]

Class Reference

ManipulaPy provides two main classes in this module:

  • PotentialField Compute attractive & repulsive potentials and their gradients.

  • CollisionChecker Use URDF geometry to build convex hulls and test for self-collision.

Installation

Ensure required packages are installed:

pip install ManipulaPy[core] scipy urchin

Usage Examples

  1. Basic potential and gradient

import numpy as np
from ManipulaPy.potential_field import PotentialField

# Define goal and obstacles in configuration space
q_goal    = np.array([0.5, 0.2, -0.3])
obstacles = [np.array([0.1, 0.0, 0.0]), np.array([0.4, 0.1, -0.2])]

pf = PotentialField(
    attractive_gain=1.5,
    repulsive_gain=50.0,
    influence_distance=0.4
)

q = np.array([0.0, 0.0, 0.0])
U_att = pf.compute_attractive_potential(q, q_goal)
U_rep = pf.compute_repulsive_potential(q, obstacles)
grad  = pf.compute_gradient(q, q_goal, obstacles)

print(f"U_att = {U_att:.3f}, U_rep = {U_rep:.3f}")
print(f"Total gradient = {grad}")
  1. Collision checking

from ManipulaPy.potential_field import CollisionChecker

cc = CollisionChecker("robot.urdf")
q_test = np.array([0.1, -0.2, 0.3, 0.0, 0.0, 0.0])

if cc.check_collision(q_test):
    print("Configuration is in collision!")
else:
    print("Configuration is collision-free.")
  1. Gradient descent path planning

path = []
q = np.zeros(6)
for _ in range(100):
    grad = pf.compute_gradient(q, q_goal, obstacles)
    q    = q - 0.05*grad  # step size
    path.append(q.copy())
    if np.linalg.norm(q - q_goal) < 1e-3:
        break

print(f"Planned {len(path)} steps to goal")

Advanced Topics

Performance Tips

  • Vectorize obstacle list: stack obstacles into an \((m \times n)\) array and compute all distances at once for large \(m\).

  • Tune gains: high \(k_{\mathrm{rep}}\) produces stronger obstacle avoidance but may create local minima.

  • Cache gradient: if you repeatedly query similar \(\mathbf{q}\), memoize the result.

Combining with Trajectory Planning

You can integrate the gradient from PotentialField into your TrajectoryPlanning loop to adjust intermediate waypoints:

from ManipulaPy.path_planning import TrajectoryPlanning

planner = TrajectoryPlanning(robot, "robot.urdf", dynamics, joint_limits)
traj    = planner.joint_trajectory(q_start, q_goal, Tf=2.0, N=500, method=5)

for idx, q in enumerate(traj["positions"]):
    if cc.check_collision(q):
        grad = pf.compute_gradient(q, q_goal, obstacles)
        traj["positions"][idx] -= 0.01*grad

Troubleshooting

  • Zero repulsive gradient If your robot never β€œfeels” obstacles, check that influence_distance is larger than the minimum \(d_i\).

  • Local minima Potential fields can trap in local minima. Hybridize with RRT or rapidly-exploring random tree to escape.

  • Performance bottleneck For many obstacles, vectorize distance computations or implement a CUDA kernel (see CUDA Kernels guide).

References

  • Latombe, J.-C., Robot Motion Planning, Kluwer, 1991.

  • Khatib, O., β€œReal-time obstacle avoidance for manipulators and mobile robots,” IEEE IJRR, 1986.

  • urchin.urdf β€” URDF parser for Python (used for mesh loading and convex hulls).