Potential Field Module User Guide — ManipulaPy 1.1.0 Documentation
Description: This comprehensive guide covers the potential field path-planning tools in ManipulaPy, optimized for Python 3.10.12. Introduction to Potential Fields: Potential field methods treat the robot as a p...

# 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}")

2. 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.")

3. 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).