Skip to main content

piper-planner

piper-planner plans multiple continuous, time-parameterized joint trajectories for the standard AgileX Piper and Piper-X arms. It uses Pinocchio for kinematics, favors keeping a target in view during motion, and returns the best validated trace first while preserving useful trajectory diversity for data collection.

The package plans offline and does not connect to CAN, command a robot, or require LeKit.

Installation

Install the published package:

pip install piper-planner

Install a downloaded wheel:

pip install dist/piper_planner-0.1.2-py3-none-any.whl

Install directly from this monorepo:

pip install "piper-planner @ git+https://github.com/sorelferris/lekit.git@main#subdirectory=packages/piper_planner"

The package requires Python 3.10 or newer. CI currently verifies Python 3.10, 3.11, and 3.12 on Linux x86_64; other Python versions, operating systems, and architectures are unverified.

Basic usage

import numpy as np

from piper_planner import PiperTrajectoryPlanner, PlanningOptions, Pose

planner = PiperTrajectoryPlanner.for_model("piper")  # or "piper_x"

q0 = np.array([0.0, 0.8, -0.9, 0.0, 0.2, 0.0])
x1 = Pose.from_xyz_rpy([0.30, 0.05, 0.35, 0.0, 1.2, 0.0])

traces = planner.plan(
    q0=q0,
    x1=x1,
    observation_target=np.array([0.35, 0.05, 0.20]),
    options=PlanningOptions(num_traces=8, random_seed=7),
)

best = traces[0]
print(best.positions_rad.shape, best.timestamps_s[-1], best.score)

q0 contains the six measured joint angles immediately before planning, in SDK joint order and radians. The planner computes x0 = FK(q0); callers do not supply a separate starting pose.

x1 is the desired TCP pose in the Piper base frame. Positions are meters, Euler angles passed to Pose.from_xyz_rpy() are radians, and stored quaternions use normalized xyzw order.

Observation behavior

observation_target is either a three-element XYZ point in the base frame or None.

When a point is supplied, the planner treats visibility as a soft objective during the middle of the motion. Near the end, the TCP orientation smoothly fades back to the exact orientation in x1; the default fade begins at 80% path progress. When observation_target=None, orientation follows the start-to-target pose interpolation without an observation objective.

The default TcpAxisCameraModel treats the TCP local +Z axis as the camera viewing axis. This tcp_axis_proxy approximation is useful when camera extrinsics are unavailable, but it cannot guarantee that the target appears inside the physical image. A calibrated adapter is available from piper_planner.camera.CalibratedCameraModel when camera-to-TCP extrinsics and field of view are known. Pass it with PiperTrajectoryPlanner.for_model(..., camera_model=...).

Set the measured tool transform with the six-element tcp_offset argument. Incorrect TCP or camera calibration makes FK, gaze direction, and terminal pose refer to the wrong tool frame.

Results and diversity

Every returned JointTrace has immutable arrays:

  • timestamps_s: seconds, starting at zero;
  • positions_rad: shape (N, 6);
  • velocities_rad_s: shape (N, 6);
  • accelerations_rad_s2: shape (N, 6);
  • score, rank, and detailed TraceMetrics.

Only densely validated traces are returned. The list is sorted best first, so traces[0] is the globally best selected trajectory. Remaining entries are selected for spatial, joint-configuration, and timing diversity without displacing that best result.

Use a fixed non-negative random_seed for reproducible planning. Leave it as None to allow different candidate paths across calls.

Timing and errors

The default cooperative planning budget is three seconds. If time expires after at least one feasible trace is found, the planner returns available results and sets trace.metrics.planning_truncated=True. It may therefore return fewer than PlanningOptions.num_traces.

  • InvalidPlanningRequestError reports malformed or out-of-range requests.
  • KinematicModelError reports URDF or Pinocchio model failures.
  • NoFeasibleTrajectoryError reports that no candidate satisfied the hard constraints and includes per-stage failure counts.

Safety scope

The planner validates configured workspace, endpoint tolerance, joint limits, velocity, acceleration, jerk, and kinematic numerical health. It does not perform environment collision or self-collision checking. A returned trace is not a guarantee of collision-free or physically safe execution.

For first execution on hardware, clear and supervise the workspace, keep the emergency stop reachable, use conservative controller limits, execute the best trace first, and compare commanded and measured joints continuously.

Example

The included example requires no robot hardware and prints a ranked JSON summary:

uv run python examples/plan_trajectory.py \
  --robot-model piper_x \
  --seed 7 \
  --num-traces 2

Development and packaging

Run commands from packages/piper_planner:

uv sync --all-groups
uv run ruff check src tests examples scripts
uv run pytest -q
uv build
uv run twine check dist/*

The project uses an independent uv.lock. Downstream pip installations use the dependency constraints in pyproject.toml, not the lock file.

Releases use tags such as piper-planner-v0.1.2. The tag version must exactly match project.version; GitHub Actions then publishes with PyPI Trusted Publishing and no long-lived API token.

Licenses

The Python source is licensed under Apache-2.0; see LICENSE. Packaged URDF assets retain the separate license and provenance files under src/piper_planner/assets/. Apache-2.0 does not relicense those third-party assets.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

piper_planner-0.1.2.tar.gz (61.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

piper_planner-0.1.2-py3-none-any.whl (47.1 kB view details)

Uploaded Python 3

File details

Details for the file piper_planner-0.1.2.tar.gz.

File metadata

  • Download URL: piper_planner-0.1.2.tar.gz
  • Upload date:
  • Size: 61.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for piper_planner-0.1.2.tar.gz
Algorithm Hash digest
SHA256 74f78984e7b24cb996514852cffe4051037abe5ddd0314335bdcdddd681b5251
MD5 c81828c8f35ec166f4201d3e1704f796
BLAKE2b-256 eb74d0ab0f4a593cd0299a4e0f947a4a9d86d4bae55c94417f096976f6c77115

See more details on using hashes here.

Provenance

The following attestation bundles were made for piper_planner-0.1.2.tar.gz:

Publisher: piper-planner-publish.yml on sorelferris/lekit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file piper_planner-0.1.2-py3-none-any.whl.

File metadata

  • Download URL: piper_planner-0.1.2-py3-none-any.whl
  • Upload date:
  • Size: 47.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for piper_planner-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 ee6721322ec305eec44c75644a4f2ccd71c0eabbb3b1d4c7223fa4857271fe40
MD5 b94843ba676a0a4d27b3d528f2c5317b
BLAKE2b-256 f2fe0a605505127d4b7100cfd986d0021d51b7e7cf57d522b97188b2eda807a6

See more details on using hashes here.

Provenance

The following attestation bundles were made for piper_planner-0.1.2-py3-none-any.whl:

Publisher: piper-planner-publish.yml on sorelferris/lekit

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.1.3

2 files

This release

0.1.2 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page