Skip to content

tesseract_robotics.tesseract_motion_planners_descartes

Descartes graph-based Cartesian planner.

Overview

Descartes solves dense Cartesian paths by building a graph of IK solutions and finding the optimal path through it. Best for industrial toolpaths (welding, milling) where every waypoint must be reached.

Python
from tesseract_robotics.tesseract_motion_planners_descartes import (
    DescartesMotionPlannerD,
    DescartesDefaultPlanProfileD,
    DescartesLadderGraphSolverProfileD,
)

DescartesMotionPlannerD

Python
from tesseract_robotics.tesseract_motion_planners_descartes import DescartesMotionPlannerD
from tesseract_robotics.tesseract_motion_planners import PlannerRequest

planner = DescartesMotionPlannerD("DescartesMotionPlannerTask")

request = PlannerRequest()
request.env = env
request.instructions = program
request.profiles = profiles

response = planner.solve(request)

DescartesMotionPlannerD is a tesseract_motion_planners.MotionPlanner: getName, solve, terminate, clear and clone are the base class's, and solve releases the GIL.

Profiles

DescartesDefaultPlanProfileD

Per-waypoint configuration.

Python
from tesseract_robotics.tesseract_motion_planners_descartes import DescartesDefaultPlanProfileD

profile = DescartesDefaultPlanProfileD()

# Target pose sampler settings
# Configure how many IK solutions to sample per waypoint

DescartesLadderGraphSolverProfileD

Solver configuration for the ladder graph.

Python
from tesseract_robotics.tesseract_motion_planners_descartes import DescartesLadderGraphSolverProfileD

profile = DescartesLadderGraphSolverProfileD()

# Graph construction and search settings

Both profiles compare by value (== compares every field, as the C++ operator== does) and are unhashable. DescartesMoveProfileD.createKey() and DescartesSolverProfileD.createKey() return the key every profile of that kind carries, the key ProfileDictionary looks up:

Python
assert DescartesDefaultMoveProfileD.createKey() == DescartesDefaultMoveProfileD().getKey()

Inspecting the samplers

The move profile's create* hooks return what the planner builds for one waypoint. str() on the waypoint sampler shows its working frame, TCP frame, target pose and TCP offset:

Python
sampler = DescartesDefaultMoveProfileD().createWaypointSampler(move, manip_info, env)
print(sampler)          # Working Frame: base_link, TCP Frame: tool0 ...
samples = sampler.sample()   # list[DescartesStateSampleD], one per IK solution

DescartesStateSampleD(state) builds a sample with cost 0, as DescartesStateSampleD(state, 0.0).

Tool-pose samplers

The functions behind DescartesDefaultMoveProfileD.target_pose_sample_* turn one tool pose into candidate poses, returned as a tesseract_common.VectorIsometry3d:

Function Samples
sampleFixed(tool_pose) the pose itself
sampleToolAxis(tool_pose, axis, resolution, minimum, maximum) rotations of the pose about axis
sampleToolXAxis / sampleToolYAxis / sampleToolZAxis(tool_pose, resolution, minimum, maximum) rotations about the tool's X / Y / Z axis

The angles run from minimum in steps of resolution while they do not exceed maximum (equal within tolerance counts), so both ends are included when the range is a whole number of steps:

Python
import numpy as np
from tesseract_robotics.tesseract_motion_planners_descartes import sampleToolZAxis

poses = sampleToolZAxis(tool_pose, resolution=np.pi / 2, minimum=-np.pi, maximum=np.pi / 2)
len(poses)  # 4: -pi, -pi/2, 0, pi/2

They are useful without the planner, for example to seed IK over a tool axis the process is indifferent to.

How It Works

  1. Sample waypoints: For each Cartesian waypoint, compute all IK solutions
  2. Build graph: Create nodes for each solution, edges between consecutive waypoints
  3. Edge costs: Based on joint motion between solutions
  4. Find path: Dijkstra's algorithm finds minimum-cost path
Text Only
Waypoint 1      Waypoint 2      Waypoint 3
    ○──────────────○──────────────○
    │              │              │
    ○──────────────○──────────────○
    │              │              │
    ○──────────────○──────────────○
   (IK solutions)

Use Cases

  • Welding: Dense linear paths with tool orientation constraints
  • Milling: Toolpaths from CAM software
  • Painting: Spray patterns with coverage requirements
  • Inspection: Camera positioning paths

Limitations

  • Computationally expensive: O(n × k²) where n=waypoints, k=IK solutions
  • Requires IK solutions: Won't work if waypoints are unreachable
  • No obstacle avoidance: Use with collision checking post-filter

Tips

  1. Use for dense Cartesian paths where every point matters
  2. Combine with TrajOpt for smoothing afterward
  3. Reduce waypoint density if planning is too slow
  4. Check reachability before planning - Descartes fails if any waypoint is unreachable

Auto-generated API Reference

tesseract_motion_planners_descartes Python bindings

DescartesPlanProfileD module-attribute

Python
DescartesPlanProfileD: TypeAlias = DescartesMoveProfileD

DescartesDefaultPlanProfileD module-attribute

Python
DescartesDefaultPlanProfileD: TypeAlias = DescartesDefaultMoveProfileD

DescartesStateD

values property writable

Python
values: Annotated[NDArray[float64], dict(shape=(None,), order=C)]

DescartesStateSampleD

state property writable

Python
state: DescartesStateD

cost property writable

Python
cost: float

DescartesEdgeEvaluatorD

__init__

Python
__init__() -> None

evaluate

Python
evaluate(start: DescartesStateD, end: DescartesStateD) -> tuple[bool, float]

Returns (is_valid, cost) for the edge between two states

DescartesWaypointSamplerD

__init__

Python
__init__() -> None

sample

Python
sample() -> list[DescartesStateSampleD]

Return the list of valid state samples for this waypoint

__str__

Python
__str__() -> str

DescartesStateEvaluatorD

__init__

Python
__init__() -> None

evaluate

Python
evaluate(solution: DescartesStateD) -> tuple[bool, float]

Returns (is_valid, cost) for a state

DescartesSolverProfileD

Bases: Profile

getKey

Python
getKey() -> int

createKey staticmethod

Python
createKey() -> int

The key every Descartes solver profile carries

DescartesLadderGraphSolverProfileD

Bases: DescartesSolverProfileD

num_threads property writable

Python
num_threads: int

Number of threads to use during planning (default: 1)

__hash__ class-attribute instance-attribute

Python
__hash__: None = None

__init__

Python
__init__() -> None

__eq__

Python
__eq__(arg: DescartesLadderGraphSolverProfileD) -> bool

__ne__

Python
__ne__(arg: DescartesLadderGraphSolverProfileD) -> bool

__init_subclass__ classmethod

Python
__init_subclass__(**kwargs: object) -> None

DescartesMoveProfileD

Bases: Profile

__init__

Python
__init__() -> None

getKey

Python
getKey() -> int

createKey staticmethod

Python
createKey() -> int

The key every Descartes move profile carries

createKinematicGroup

Python
createKinematicGroup(manip_info: ManipulatorInfo, env: Environment) -> tesseract_robotics.tesseract_kinematics._tesseract_kinematics.KinematicGroup

The kinematic group for manip_info's manipulator and IK solver

createWaypointSampler

Python
createWaypointSampler(move_instruction: MoveInstructionPoly, composite_manip_info: ManipulatorInfo, env: Environment) -> DescartesWaypointSamplerD

createEdgeEvaluator

Python
createEdgeEvaluator(move_instruction: MoveInstructionPoly, composite_manip_info: ManipulatorInfo, env: Environment) -> DescartesEdgeEvaluatorD

createStateEvaluator

Python
createStateEvaluator(move_instruction: MoveInstructionPoly, composite_manip_info: ManipulatorInfo, env: Environment) -> DescartesStateEvaluatorD

DescartesDefaultMoveProfileD

Bases: DescartesMoveProfileD

target_pose_fixed property writable

Python
target_pose_fixed: bool

target_pose_sample_axis property writable

Python
target_pose_sample_axis: Annotated[NDArray[float64], dict(shape=3, order=C)]

target_pose_sample_resolution property writable

Python
target_pose_sample_resolution: float

target_pose_sample_min property writable

Python
target_pose_sample_min: float

target_pose_sample_max property writable

Python
target_pose_sample_max: float

manipulator_ik_solver property writable

Python
manipulator_ik_solver: str

allow_collision property writable

Python
allow_collision: bool

enable_collision property writable

Python
enable_collision: bool

vertex_contact_manager_config property writable

Python
vertex_contact_manager_config: ContactManagerConfig

vertex_collision_check_config property writable

Python
vertex_collision_check_config: CollisionCheckConfig

enable_edge_collision property writable

Python
enable_edge_collision: bool

edge_contact_manager_config property writable

Python
edge_contact_manager_config: ContactManagerConfig

edge_collision_check_config property writable

Python
edge_collision_check_config: CollisionCheckConfig

use_redundant_joint_solutions property writable

Python
use_redundant_joint_solutions: bool

debug property writable

Python
debug: bool

__hash__ class-attribute instance-attribute

Python
__hash__: None = None

__init__

Python
__init__() -> None

__eq__

Python
__eq__(arg: DescartesDefaultMoveProfileD) -> bool

__ne__

Python
__ne__(arg: DescartesDefaultMoveProfileD) -> bool

__init_subclass__ classmethod

Python
__init_subclass__(**kwargs: object) -> None

DescartesMotionPlannerD

Bases: MotionPlanner

__init__

Python
__init__(name: str) -> None

cast_DescartesSolverProfileD

Python
cast_DescartesSolverProfileD(profile: DescartesLadderGraphSolverProfileD) -> tesseract_robotics.tesseract_command_language._tesseract_command_language.Profile

Cast DescartesLadderGraphSolverProfileD to Profile for use with ProfileDictionary

cast_DescartesMoveProfileD

Python
cast_DescartesMoveProfileD(profile: DescartesMoveProfileD) -> tesseract_robotics.tesseract_command_language._tesseract_command_language.Profile

Cast a DescartesMoveProfileD (including Python subclasses) to Profile for use with ProfileDictionary

cast_DescartesPlanProfileD

Python
cast_DescartesPlanProfileD(profile: DescartesMoveProfileD) -> tesseract_robotics.tesseract_command_language._tesseract_command_language.Profile

Cast a DescartesMoveProfileD to Profile (legacy alias of cast_DescartesMoveProfileD)

sampleToolAxis

Python
sampleToolAxis(tool_pose: Isometry3d, axis: Annotated[NDArray[float64], dict(shape=3, order=C)] | Sequence[float], resolution: float, minimum: float, maximum: float) -> tesseract_robotics.tesseract_common._tesseract_common.VectorIsometry3d

Given a tool pose create samples from [minimum, maximum] around the provided axis.

sampleToolXAxis

Python
sampleToolXAxis(tool_pose: Isometry3d, resolution: float, minimum: float, maximum: float) -> tesseract_robotics.tesseract_common._tesseract_common.VectorIsometry3d

Given a tool pose create samples from [minimum, maximum] around the x axis.

sampleToolYAxis

Python
sampleToolYAxis(tool_pose: Isometry3d, resolution: float, minimum: float, maximum: float) -> tesseract_robotics.tesseract_common._tesseract_common.VectorIsometry3d

Given a tool pose create samples from [minimum, maximum] around the y axis.

sampleToolZAxis

Python
sampleToolZAxis(tool_pose: Isometry3d, resolution: float, minimum: float, maximum: float) -> tesseract_robotics.tesseract_common._tesseract_common.VectorIsometry3d

Given a tool pose create samples from [minimum, maximum] around the z axis.

sampleFixed

Python
sampleFixed(tool_pose: Isometry3d) -> tesseract_robotics.tesseract_common._tesseract_common.VectorIsometry3d

This will return the tool pose as the only sample.