Nonholonomic Systems II — Steering Cars, Trailers, and Underactuated Systems
Chapter 20 proved Hitch can reach every pose; this chapter is the catalog of ways to actually get there — Brockett's sinusoids and chained forms, gradient steering, differential flatness, Dubins and Reeds–Shepp words, Choset's CAR GRID SEARCH and its descendants (state lattices, hybrid A*), forward-propagation trees and Kinodynamic RRT*, and Reach's dead third joint driven like a car along decoupling vector fields.
This implies that it is possible to parallel-park your car into any parking space ϵ > 0 longer than your car.
In this chapter
Chapter 20 proved that Hitch can reach every pose in the Lot. It did not say how, and the proof's own recipe — nested four-flow loops — is a terrible plan: each loop of amplitude buys of sideways motion, so a small sideways correction costs a great many reversals. This chapter is the catalog of better answers, and its one idea is that every steering method is a different way of spending the controllability you already own. You can solve an optimal-control problem exactly (Dubins, Reeds–Shepp). You can change coordinates until the brackets become a ladder you climb with sinusoids (chained forms). You can push on the Jacobian of the end-state map until the error vanishes (gradient steering). You can find two coordinates from which the whole state is read off by differentiation (flatness). Or you can let a search integrate the dynamics forward and never invert anything at all — Barraquand and Latombe's CAR GRID SEARCH, and the kinodynamic trees that descend from it.
None of these methods is "the" way to park a car, and the chapter's widgets are built to make that visible: one query, six fares. Exact methods ignore obstacles; search methods stop in a goal region; flat polynomials ignore the steering limit; sinusoids ignore everything except the chained coordinates and swing the trailer past jackknife. The second half of the chapter is about how today's autonomous vehicles recombine these pieces — state lattices and hybrid A* are Algorithm 22 with lattice-consistent primitives, one continuous state per cell, Reeds–Shepp shots and a dual heuristic; Kinodynamic RRT* is RRT* with an exact optimal-control steer. It ends with Reach's third motor switched off and the dead link driven like a car.
Honesty items kept throughout: Algorithm 22 is resolution complete, not exact; Reeds–Shepp and Algorithm 22 paths have curvature jumps a real steering actuator cannot follow; flatness handles neither control bounds nor obstacles without numerical optimization; forward propagation is metric-sensitive and offers no optimality without an exact steer; the decoupled planner stops at every switch and so forfeits global time-optimality; and the cusp count for tight parking is a theorem, not a bug.
The problem: same destination, six fares
Hitch is at the south curb of the Lot, heading east. Bay 3 is up and to the left. Three copies of Hitch leave at once.
The three paths are all correct, and all different, because each one answers a different question. The Reeds–Shepp path is the shortest path for a car that may reverse; it has a cusp because stopping and backing up is free in its cost. The flat-output path is the simplest polynomial consistent with the two poses; it never stops, but nothing in its derivation stops it from asking for more steering than Hitch has. The tree path is the first thing a randomized search found by simulating Hitch; it is jittery and does not end exactly on the goal, but it is the only one of the three that looked at the pillars while planning. Chapter 20's controllability theorem guaranteed all three exist. It said nothing about which one you want, and the rest of this chapter is about making that choice deliberately.
Building intuition
One query, several optimality criteria
Start with the flagship. Hitch now pulls its trailer, and the scoreboard grows a column the planners were never asked about: how far the trailer swings.
Three observations, each a section below.
The trailer is a hidden cost. With the trailer on, the chained-form sinusoids reach the bay exactly — in the car's chained coordinates — while the trailer, simply towed along, swings far past . The sinusoid method steers the four-state car; it does not know the trailer exists. The flat-output method with the trailer is different in kind: its flat output is the trailer's axle, so the trailer is parked by construction and the car's motion is derived from it.
Exactness and obstacle-awareness trade off. The Reeds–Shepp word and the sinusoids land on the goal pose to round-off and do not look at the pillars. Turn "obstacles" on and the third method becomes Algorithm 22, which looks at everything and stops anywhere within m and rad of the goal. Exact steering is an obstacle-free subroutine; search is how obstacles enter.
Control bounds are where each method is weakest. The flat planner's red is the curvature its polynomial asks for, not what Hitch can do. The sinusoids ask for rad of steering on the default query — twice Hitch's limit. Only the methods built from full-lock arcs (Reeds–Shepp, Algorithm 22) respect by construction.
Shortest paths have words
The shortest path between two poses of a car with a minimum turning radius is a short word in three letters: and for full-lock arcs, for straight. Forward-only (Dubins), six words suffice; allowed to reverse (Reeds–Shepp), a handful of families with cusps join them.
The tint is the synthesis: for the goal heading on the slider, every point of the plane is colored by the family of its shortest path. Drag the goal along a boundary and the word flips — but the length in the readout moves continuously, because the optimal length is a continuous function of the goal even though the optimal word is not. Toggle "Dubins only" and compare: near the start, behind it and beside it, the forward-only car pays enormously (a loop of nearly ) for what the Reeds–Shepp car does with one cusp. The Reeds–Shepp length is never longer — the chapter's check confirms it on 400 random pairs — and reversing is not a Dubins word run backward: the reversing words are new words.
State from a curve
Here is a planner with no differential equation in it.
Drag the curve. Hitch is placed on it by differentiation alone: its heading is the curve's tangent, its steering angle is of the wheelbase times the curve's curvature. Nothing was integrated. That is differential flatness: the car has two outputs — the rear-axle midpoint — from which state and inputs are algebraic functions of finitely many derivatives. Turn on the trailer and the flat output moves to the trailer's axle; now the car's position is a derivative away (the trailer tangent tells you where the hitch is) and its steering is two more. Make a corner tight and part of the curve turns red: the curve is still a perfectly good flat output, but it asks for more curvature than , and flatness alone has no way to say no.
A tree without a steering function
Every planner so far needed to invert the car — find controls that go from here to there. Choset's §7.5.1 points out that a tree planner needs much less: a way to propagate a state forward under a control.
With one sampled control per extension the tree drifts; with eight it reaches. Push the heading weight up and the tree spends its effort matching headings of random samples instead of covering the Lot — the planner is only as good as its notion of "near", and the metric is a tuning knob, not a derived quantity. Turn on Kinodynamic RRT* and the tree changes model: rewiring compares the cost of reaching a node through two different parents, which needs the exact optimal cost between two states. For the kinematic car that is the Reeds–Shepp length; for Hitch's dynamic model nobody has a closed form, which is why the toggle switches systems rather than pretending.
Grid search, then and now
Barraquand and Latombe's 1990s answer to car planning among obstacles was a best-first search over six motion primitives — full left, straight, full right, forward and reverse — with an occupancy grid on to stop it revisiting. Today's planners in autonomous vehicles are recognizably the same algorithm.
The left panel is a state lattice: the primitives were built so that every motion ends exactly on a lattice state, so the search is plain A* on a graph. The right panel is hybrid A*: the states float freely as in Algorithm 22, each grid cell keeps the best one, and every few expansions the planner tries an analytic Reeds–Shepp "shot" to the goal (the dashed purple fans are shots that hit something). Coarsen the grid: the lattice, whose primitives must land on coarse lattice points, takes long detours; hybrid A* barely notices because its states are continuous. Neither is new; both are Algorithm 22 plus a named change.
Driving a dead joint
The last widget leaves the Lot. Reach's three-link arm lies flat on the Workbench with its third motor switched off.
The free third link cannot be torqued. Chapter 20 showed the arm is nevertheless accessible from rest, and Choset's §12.5.7 shows how to use that: there are two motions the dead link can perform at any speed — sliding along its own length, and rotating about its center of percussion, the one point on the link that a force at the joint perpendicular to the link leaves momentarily unaccelerated. Drive with those two (forward and reverse each) and the link behaves like a car with four actions. The planner is Algorithm 22 with cost "number of switches"; the execution is Chapter 18's time-optimal scaling, segment by segment, coming to rest at every switch. In the inset one torque bar is always full.
| Symbol | Meaning | Note |
|---|---|---|
| minimum turning radius; inputs of the reduced car (Choset eq. 12.35) | |ω| ≤ |v|/ρ; Hitch: L = 2.6 m, γ = 0.6 rad, ρ = 3.80 m | |
| CAR GRID SEARCH actions: full left / right / straight, forward / reverse | Choset Alg. 22 | |
| Reeds–Shepp alphabet: arc, straight, cusp, arc of angle a, quarter arc; normalized segment lengths | arcs in radians, straights in units of ρ | |
| chained-form coordinates and inputs | Choset §12.5.1–12.5.2 | |
| finite control parameterization, end-state map, end-state error | §12.5.4 | |
| flat outputs and the maps x = φ(y, ẏ, …), u = ψ_u(y, ẏ, …) | Choset writes ψ for the input map; here ψ is the trailer heading, so the input map is ψ_u | |
| trailer heading, hitch angle, hitch length | Chapter 2 integrates ψ; d = 2.5 m | |
| decoupling vector fields, a set of them, kinematic inputs | §12.4.2 | |
| goal region of Alg. 22; forward propagation of ẋ = f(x, u) | §12.5.6, §7.5.1 |
The mathematics
Throughout, the steering problem is: given and , find controls driving the system from one to the other, ignoring obstacles. It is exactly what PRM and RRT call a local planner. Choset splits the state of many systems into shape variables, driven directly by the inputs, and fiber variables, which change only when the shape variables move around closed loops — the astronaut who reorients by cycling her arms. Every exact method below is a way to engineer the right loop.
Brockett's sinusoids
The simplest system with a fiber is Choset's (12.23):
with , and . Shape , fiber .
DerivationPontryagin for the fiber
- Hamiltonian. .
- Stationarity. gives and .
- Adjoint. : , , .
- Close the loop. Differentiate step 2: and — a rotation of at rate , which integrates to the quadrature sinusoids.
- Return the shape. requires a whole number of periods: . Then for every , so pick . With , and : negative for , positive for .
So to move the fiber by choose and any on the circle of radius
, at cost ; the library's steerBrockett
returns that circle's point on the -axis, and integrating (12.23) under it lands on
to round-off. The unicycle is this system in disguise: with Choset's
the unicycle's becomes — check it: . The heading is a shape variable, the position along the heading is the other, and the sideways offset is the fiber. Brockett's cost is not a physical one for a car, which is Choset's own caveat.
Chained form and the sinusoid ladder
Generalize to states and two inputs (Choset eq. 12.28):
DerivationWhy the k-th cycle touches only x_{k+2} and above
- The ladder. , because is constant and the only entry of depending on is the third. Inductively , so and spans — Chapter 20's lieBracket confirms the signs to better than at a random point for .
- Linearity in the initial state. Given , the chain is linear. A contribution of to is with — a polynomial in , and , so every such contribution returns.
- The forced part. What remains is driven by . Each pass down the chain multiplies by and integrates; by the product-to-sum identities a frequency- signal multiplied times by a frequency- one contains a zero-frequency (DC) term only at the -th multiplication, i.e. in . States above also drift, which is why the ladder is climbed upward.
- The constant. Tracking the DC coefficient through the multiplications gives (Murray and Sastry's computation). The check runs the five-state ladder to and finds every cycle's increment equal to (12.31) to better than — integration error, not formula error.
Hitch's four-state car has a chained form too (Murray and Sastry):
where the primes are coordinates in a chart rotated by an angle . In the original chart the transformation is singular at — which is exactly where a parking query into a north-facing bay ends. The library sets to the bisector of the start and goal headings, so both ends sit inside ; inside the motion never reaches by construction. On w21.1's default query, , two sinusoid cycles land on the goal in chained coordinates to better than — with three cusps and a peak steering angle of rad, twice what Hitch can do. The method is exact in its coordinates and blind to everything else. Car-and-trailer systems with any number of trailers also have chained forms (Sørdalen's result, Choset ref. 393), at the price of coordinate changes that blow up at the jackknife.
Gradient steering, and the cross-link to Chapter 19
Exact methods need structure. Choset's §12.5.4 needs only a simulator: parameterize the control history by a finite vector (here, piecewise-constant on equal intervals of for the reduced car), call the end-state map, and descend the error .
DerivationDescent, rank, and the generic loop
- Descent. With , , so the step decreases the error unless .
- Rank. If then is injective and forces : the only stationary point is the goal. Any error direction is correctable by a small change of .
- The singular control. At every column of is a first-order variation — a combination of and at — so and the sideways error is invisible. A driftless system retraces itself under a control followed by its time-reversed negative, so appending such a pair changes nothing about where the car ends and everything about the Jacobian.
For a pure sideways move of m from rest the library's steerGradient finds rank at ,
appends a two-piece generic loop (rank ), and then needs backtracking gradient steps to bring
below — slow, because the sideways direction is a bracket direction and the Jacobian's
singular value along it is small; Chapter 20's reappears as conditioning. Hand the same
end-state map to Chapter 19's Levenberg–Marquardt — §12.5.3's
"nonlinear optimization", with no re-derivation needed — and five iterations reach round-off. Choset's two
caveats carry over unchanged: a good initial guess is required, and nothing guarantees convergence; here
the generic loop is the initial guess that makes it work.
Differential flatness
DerivationHeading from the tangent, steering from curvature, the car from the trailer
- Heading. No slip means the rear axle's velocity points along the body: . Read and off ; the sign of is a choice that must stay consistent with (Choset's warning: and give the same atan).
- Turn rate and curvature. , the cross product over speed squared; is that over speed cubed, and the front-wheel geometry gives .
- The trailer. By (12.36)–(12.37) the trailer axle moves along the trailer's heading, so when is the trailer axle; the hitch — the car's rear axle — sits at . Differentiate: and , where is step 2 applied to and needs .
- Apply steps 1–2 to . The car's heading needs (two derivatives of ), its steering (four). One more pair of derivatives per body: "differentiate once more per trailer". Every formula divides by a speed, so the lift is singular wherever the flat output stops.
Choset's Example 12.5.1 fits , between and ; the library's Hermite fit with unit end speed returns exactly those polynomials. At : , , , so
, and for wheelbase the steering angle is rad (). At the curve inflects and exactly. The chapter's check goes one step further: it takes the controls read off a quintic flat output, integrates the true car (and car-with-trailer) ODE forward from the lifted initial state, and finds the integrated state agreeing with the lifted one along the whole trajectory to better than . Flatness is not an approximation.
What it is not, either, is a planner with constraints. A polynomial of minimal degree has no freedom left to respect or avoid a pillar; extra coefficients plus a numerical optimizer can, and Choset calls that "a topic of current research". On w21.1's trailer query the trailer-axle quintic asks for rad and clips an obstacle.
Shortest paths: Dubins and Reeds–Shepp
DerivationFrom Pontryagin to six words, and LSL in closed form
- Bang-bang or singular. Minimize time with , , . The Hamiltonian is linear in , so sits at (bang) except on intervals where its switching function vanishes identically (singular), which forces .
- Arcs and straights. Optimal paths are concatenations of full-lock arcs and straights — exactly CAR GRID SEARCH's primitives, which is why Algorithm 22 loses nothing essential by discretizing the steering.
- Case analysis. Reeds and Shepp's argument bounds the number of segments and the arc angles between cusps, leaving the nine families; with forced there are no cusps and only and remain — Dubins' six words.
- Normalize. Put the start at the origin, the goal at with , and measure both headings from the bearing of the goal: , .
- LSL. The start's left circle has center , the goal's . Two equal circles turning the same way are joined by their external tangent, parallel to and of the same length: , which expands to the boxed formula. The tangent's direction is ; the first arc turns from to it (), the last from it to (), both taken mod .
- The other five. Reflect (, headings negated) and LSL becomes RSR. Reverse time and read the word backward and LSR and RSL swap; the internal tangent replaces the external one for the mixed words ( for LSR, infeasible when negative), and three mutually tangent circles give and , infeasible when the circles are more than apart.
The micro-example. , , . The start's left circle is centered at , the goal's at ; the centers are apart along direction , so has , , and length . By integration: after the first arc Hitch is at heading ; the straight adds ; the last arc about ends at heading . The others are longer — , , — and is infeasible. Reeds–Shepp returns the same : here a cusp cannot help.
Reeds–Shepp by symmetry. Nobody codes forty-eight formulas. Reeds and Shepp's §8 gives a handful of base formulas — , , , , , , , — and three symmetries of the normalized goal generate the rest:
Time-flip negates every segment (), reflect swaps and , backwards reads the
word right to left. The library evaluates eleven base formulas (four of them backwards readings) under
the four flip/reflect combinations — forty-four evaluations, the construction OMPL's
ReedsSheppStateSpace uses. Several base formulas leave the sign of their last segment free, so the
forty-four evaluations cover the forty-eight words; the module does not prove that itself, and the check
tests the two consequences that would fail if it were false. On 400 seeded pairs, every one of the 2,700
candidate words integrates to its goal to round-off (worst error ), and the shortest Reeds–Shepp length never
exceeds the shortest Dubins length (Dubins paths are Reeds–Shepp candidates, so a missing family or a
mistyped formula would show up as a violation). All nine families appear among the optimal words. The
Reeds–Shepp length is also symmetric — — because reversing time maps a path to
a path; that is what makes it a metric on , and the reason PRM can use it as an undirected local
planner while a Dubins-steered PRM needs directed edges.
Local planners with the topological property
DerivationSTLC, the topological property, and compactness
- The topological property (Choset Fig. 12.28). For every ball there is a ball such that the local planner's path from to any stays inside . Reeds–Shepp has it because the car is STLC and the shortest path between close poses is short: its length is in the sub-Riemannian sense, so it cannot wander far.
- Uniformity. The free-flying path is compact and at positive clearance from obstacles; by compactness one works along its whole length.
- Bisection terminates. Halve the parameter interval until consecutive samples are within ; each Reeds–Shepp piece then stays in a -ball around a free configuration, hence is free.
- PRM. Chapter 11's completeness proof covered the path with a chain of balls and needed only that the local planner connects samples in consecutive balls; it never used that the planner's path is a straight line, nor that it is symmetric. The cusp count: each reversal of a car of length in a slot of length gains of sideways motion (Chapter 20's bracket), so a fixed sideways offset needs of them.
The library implements both: ReedsSheppLocal and DubinsLocal satisfy Chapter 11's Steer<Pose2>
interface (symmetric and not, respectively), and pathTransform is Laumond's bisection. Their price is
the next honesty item: the curvature jumps at every arc–straight junction, so either the steering wheel
turns instantaneously, the car stops at each junction, or execution has error. Smoothed primitives —
clothoids, or flat-output polynomials — are the standard repair.
CAR GRID SEARCH
DerivationTermination, optimality, and the bucketed OPEN list
- Termination. A node is expanded only if its cell has not been marked; there are cells, so at most expansions and children. The step must be long enough to leave the current cell, and the goal region must be larger than a cell — otherwise the search can loop inside a cell or jump over the goal.
- Best-first on integer costs is Dijkstra. With nonnegative integer , every edge cost is a nonnegative integer, and popping the cheapest open node is Chapter 6's Dijkstra on the tree. Testing the goal at pop time (line 4), not at generation, is what makes the returned path the cheapest one: Choset's Fig. 12.25 has a node in the goal region waiting in OPEN behind a cheaper one.
- Constant-time insertion. Integer costs index an array of FIFO buckets; insertion is an append, and the pop scans forward from the lowest non-empty bucket, which only ever moves up.
- Full lock suffices. By the Pontryagin argument of the previous section, optimal paths between cusps are full-lock arcs and straights; Barraquand and Latombe show more — that any -cusp path is approximable by a -cusp full-lock path — so minimizing cusps with loses nothing to the discretization of steering.
Choset's description includes two practicalities the implementation keeps. The occupancy grid is checked
when a node is popped (line 7), so a cell can be reached several times but expanded once; and with a
trailer the grid gains a fourth axis for the hitch angle, the trailer's change over one action being
"numerically integrated, or stored in a lookup table" — here by Chapter 2's Hitch.step, whose RK4
trailer integration is the lookup table computed on demand. On the Lot's reverse-parking query the
search with and the search with both find a 20-step path with one cusp; the
second expands half as many nodes, because the cusp penalty prunes every branch that reverses early.
Choset's remark that the planner "actually runs faster in cluttered spaces because the obstacles prune the
search tree" is the same effect from the other side.
Forward propagation
DerivationA tube, a chain of cross-sections, and the Voronoi bias
- A tube. Take a feasible trajectory reaching the interior of with clearance. Lipschitz continuity of in (and continuity in ) gives a tube of nearby trajectories: from any state within of the -th waypoint, some open set of controls lands within of the next.
- Cross-sections. Discretize the trajectory into steps of and ball around each waypoint.
- One step has positive probability. If the tree has a node in , an extension succeeds in placing one in with probability at least : the random sample lands in the Voronoi region of that node with positive probability (Chapter 12's bias), and some sampled control falls in the open good set with positive probability.
- Chain. The event "progress from to within extensions" fails with probability at most ; multiply over stages and let .
- What the proof never used. Symmetry of the edge relation, reflexivity, or any ability to steer to a state — the theorem holds for the asymmetric, forward-only relation "some drives to in ".
Two honesty items follow from the proof. The constant depends on the metric through step 3 — a metric that ranks a node with the wrong heading as "near" wastes extensions, which is the w21.5 slider — and nothing in the proof bounds path quality. On the Lot query from w21.1, Hitch's dynamic model (acceleration and steering-rate inputs, speed and steering angle in the state) with best-of-eight controls and s first lands in the goal region at extension 106 for seed 21, and re-running the simulator on the stored controls reproduces every state bit for bit. Time can be added to the state to handle moving obstacles (Choset ref. 195); the theorem does not change.
Kinodynamic RRT*: optimality needs a steer
Chapter 13's RRT* is asymptotically optimal because its rewiring step asks, for a node near a new node , whether reaching through is cheaper — a question about the exact optimal cost and the trajectory achieving it. Forward propagation cannot answer it. Webb and van den Berg's Kinodynamic RRT* answers it for linear dynamics with cost : for a fixed arrival time the minimum-energy cost is
and the free final time is . For the planar double integrator with each axis gives and with , . From to with the library finds s at cost , and integrating the closed-form optimal control lands on the target to round-off. For the reduced kinematic car the exact steer is Reeds–Shepp, which is what w21.5's toggle uses; Hitch's dynamic model has neither, and Exercise 6 asks you to linearize it about rest and use the LQR edge anyway.
Kinematic reductions and decoupling vector fields
Chapter 20 left Reach's dead-motor arm with an uncomfortable verdict: accessible from rest, with Lewis–Murray unable to certify STLC. §12.4.2 changes the question from "can it get anywhere?" to "can I plan it like a kinematic system?".
DerivationWhy V and ∇_V V must both be actuated
- Substitute. Along , (Choset 12.16–12.17).
- Covariant form. .
- Feasibility for all speed profiles. The left side must equal for some , for every and independently: the term forces , the term forces . Conversely, both memberships let you solve for .
- Finding them. Write and solve for the -orthogonal complement of span — quadratic equations in the . Then plan in and time-scale each segment with Chapter 18.
For the planar body with thrusters Choset finds (translation along the thrust line) and (rotation about the center of percussion at distance ), with and ; but , so is not decoupling (Example 12.4.8). For the 3R arm with the free third link is that body, its "thrusters" the forces joints 1 and 2 apply at joint 3. The two decoupling fields are translation along link 3 and rotation about its center of percussion with respect to joint 3, at distance
for Choset's Table 12.1 robot. In joint coordinates both are built through the inverse of the Jacobian of joint 3's position. The check evaluates Theorem 12.4.7 numerically with Chapter 20's kinetic-energy connection at three configurations: both fields pass with residuals below ; rotation about the center of mass fails (it is not even in span() — a rotation about the COM needs a torque the dead joint cannot supply); and the sum of the two fails the second condition, exactly as for the free body.
Modern descendants: lattices and hybrid A*
Choset's chapter ends in 2005 with Algorithm 22 and PRM-with-Reeds–Shepp. The planners that parked the DARPA Urban Challenge vehicles, and their successors, are those two ideas recombined, with three deltas:
- Lattice-consistent primitives (state lattices, Pivtoraiko, Knepper and Kelly). Choose primitives that start and end exactly on lattice states — grid points times a set of headings — so the search graph is a real graph and A* runs unchanged. The library builds them with this chapter's Dubins solver: for each start heading and each category (straight, ±45°, ±90°, lane change), the cheapest Dubins path to a lattice endpoint whose total turning equals the heading change. The cost of exactness is that the start and goal must be lattice states.
- One continuous state per cell (hybrid A*, Dolgov, Thrun, Montemerlo and Diebel). Keep Algorithm 22's free-running continuous configurations and its occupancy grid, but let each cell hold the cheapest state that reached it rather than the first.
- Analytic expansions and a dual heuristic (hybrid A*). Every expansions try a Reeds–Shepp shot from the popped state straight to the goal and accept it if it is free — the PRM local planner, inside the search. Order OPEN by : each term is a lower bound on the true cost, so their maximum is too. (The library's 2-D table is scaled by , the worst octile-to-Euclidean ratio, to keep it admissible.)
On the Lot, reversing into bay 3 from to at m resolution with the dual heuristic: the six-primitive state lattice expands 298 states and returns a m path with three cusps; hybrid A* with a shot every ten expansions expands 161, fires seventeen shots, and returns m with three cusps, ending exactly on the goal. Both are at least the obstacle-blind Reeds–Shepp distance, m. Hybrid A* is not optimal (the cell pruning discards states that might have led to cheaper paths) and the lattice is optimal only over its primitives; w21.3 lets you watch both trade-offs.
The algorithm
- In
- start q_start, goal region G(q_goal), action set {L±, S±, R±}, step Δ, grid resolution d, integer weights (a, b, c), MAXTREESIZE, collision checker
- Out
- a path of actions from q_start into G(q_goal), or FAILURE
- initialize the tree and the bucket array OPEN with at cost 0
- while OPEN is not empty and MAXTREESIZE:
- first node of the lowest non-empty bucket; remove it
- if : return SUCCESS and the path root →
- if the cell of in the grid is not marked:
- mark it
- for each action : integrate for arc length (Hitch.step, with the trailer if hitched) to , checking the footprint at substeps
- if the motion is free: add under ; cost cost; append to that cost's bucket
- return FAILURE
- In
- chained-form start and goal in ℝⁿ, optional amplitude cap
- Out
- n − 1 control phases on unit time and the integrated trace
- phase 0: , , constant on
- for : ; with the sign of on ; if exceeds the cap, clamp it and set
- apply , for unit time and integrate
- for Hitch's car: map poses to in the chart rotated to the heading bisector, and back
- In
- start and goal, initial parameter vector (zero by default), tolerance, a seeded RNG for generic loops
- Out
- u^p with ‖f(x_start, u^p) − x_goal‖ < ε, or the iterate where the line search stalled
- if rank : append a generic loop (random pieces, then the same pieces reversed and negated)
- repeat until : by central differences;
- if : append another generic loop and continue
- double , then halve it until ; accept
- (§12.5.3 variant: hand and to Chapter 19's levenbergMarquardt)
- In
- a simulator prop(x, u, Δt), a control sampler, a state sampler with goal bias, a metric, controls per extension k
- Out
- a tree whose root-to-goal branch is a list of (control, Δt) pairs that re-integrates exactly
- tree
- for : goal sample with probability , else uniform
- for : sample ; propagate for in substeps, discarding at the first collision
- keep the free endpoint closest to ; add it with its control and segment
- if any state of the segment is in : return the branch
- In
- start and goal poses, cell size, heuristic (Euclidean, RS, or max(RS, 2-D)), shot period N, heading bins
- Out
- arc primitives followed by one Reeds–Shepp shot, ending exactly at q_goal
- push ; best per cell except the start's
- while OPEN not empty: pop the lowest ; if its cell is closed, continue; close it
- every -th expansion: RS shot to ; if free, return path to here + shot
- for each of (arc length just long enough to leave the cell and, at full lock, the heading bin — otherwise a turning child ties with its straight sibling in the same cell and is pruned): integrate, check, compute the child's cell
- if the cell is open and best of that cell: record it, push with
- In
- decoupling primitives (translate ±, rotate ± about the center of percussion), link-3 start and goal poses, IK with a fixed elbow, collision and singularity margin
- Out
- a switch-minimizing sequence of decoupling segments and its time-optimal, rest-to-rest execution
- best-first over link-3 poses with a occupancy grid; children by the four primitives, valid if IK exists with margin and the whole arm is free
- cost (number of switches, number of steps) compared lexicographically; goal tested at pop
- merge equal consecutive primitives into segments
- for each segment: path by IK; Chapter 18's time scaling of the two actuated rows from rest to rest (the third row is identically zero along a decoupling path)
Implementation in Rust
The nonholonomic crate of Chapter 20 gains a steer/ directory, car_grid.rs, lattice/ and
reduction.rs; forward propagation gets its own crate, kinodynamic, which owns the Propagate trait
Chapter 14's preview borrowed. The TypeScript port in web/lib/nonholonomic/ — dubins.ts,
reeds-shepp.ts, chained.ts, gradient.ts, flat.ts, car-grid.ts, lattice.ts, kinodynamic.ts,
reduction.ts, steer.ts, park.ts — is the code behind every widget on this page, and its
__checks_ch21__.ts pins every number in the prose.
use manifold::SE2;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Word { LSL, RSR, LSR, RSL, RLR, LRL }
/// Dubins shortest path for the reduced car (Choset eq. 12.35). Segment lengths are
/// normalized by ρ — arcs in radians, the straight in units of ρ — so the closed forms
/// are scale-free; every word returned is checked by integration in the tests.
#[derive(Clone, Copy, Debug)]
pub struct DubinsPath { pub word: Word, pub segs: [f64; 3], pub rho: f64 }
impl DubinsPath {
pub fn len(&self) -> f64 { self.rho * self.segs.iter().sum::<f64>() }
}
fn mod2pi(a: f64) -> f64 { a.rem_euclid(std::f64::consts::TAU) }
/// Start at the origin, goal at (d, 0): headings measured from the bearing of the goal.
fn normalize(q0: &SE2, q1: &SE2, rho: f64) -> (f64, f64, f64) {
let (dx, dy) = (q1.x - q0.x, q1.y - q0.y);
let bearing = dy.atan2(dx);
(dx.hypot(dy) / rho, mod2pi(q0.theta - bearing), mod2pi(q1.theta - bearing))
}
/// LSL: the two left circles and their external tangent (Derivation 5, step 5).
fn lsl(d: f64, a: f64, b: f64) -> Option<[f64; 3]> {
let p2 = 2.0 + d * d - 2.0 * (a - b).cos() + 2.0 * d * (a.sin() - b.sin());
if p2 < 0.0 { return None; }
let th = (b.cos() - a.cos()).atan2(d + a.sin() - b.sin());
Some([mod2pi(-a + th), p2.sqrt(), mod2pi(b - th)])
}
pub fn dubins_shortest_path(q0: &SE2, q1: &SE2, rho: f64) -> Option<DubinsPath> {
let (d, a, b) = normalize(q0, q1, rho);
// RSR, LSR, RSL, RLR, LRL follow from LSL by reflection (L <-> R, headings negated)
// and by reading the word backward; each has its own feasibility test.
[(Word::LSL, lsl(d, a, b)), (Word::RSR, rsr(d, a, b)), (Word::LSR, lsr(d, a, b)),
(Word::RSL, rsl(d, a, b)), (Word::RLR, rlr(d, a, b)), (Word::LRL, lrl(d, a, b))]
.into_iter()
.filter_map(|(word, s)| s.map(|segs| DubinsPath { word, segs, rho }))
.min_by(|x, y| x.len().total_cmp(&y.len()))
}use manifold::SE2;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Steer { L, S, R }
/// A signed segment: arcs in radians, straights in units of ρ; negative means reverse.
#[derive(Clone, Copy, Debug)]
pub struct Seg { pub steer: Steer, pub len: f64 }
/// The three symmetries of the normalized goal (x, y, φ). Time-flip negates every
/// segment, reflect swaps L and R; "backwards" (applied separately) reads the word
/// right to left. Eleven base formulas under these four maps: 44 evaluations that
/// cover the 48 Reeds–Shepp words.
const SYMMETRIES: [(f64, f64, f64, bool, bool); 4] = [
(1.0, 1.0, 1.0, false, false), // base
(-1.0, 1.0, -1.0, true, false), // time-flip
(1.0, -1.0, -1.0, false, true), // reflect
(-1.0, -1.0, 1.0, true, true), // both
];
pub fn reeds_shepp_candidates(x: f64, y: f64, phi: f64) -> Vec<Vec<Seg>> {
let mut out = Vec::new();
for &(sx, sy, sp, flip, refl) in &SYMMETRIES {
let sign = if flip { -1.0 } else { 1.0 };
let word = |w: [Steer; 3], l: [f64; 3]| -> Vec<Seg> {
w.iter().zip(l).map(|(&s, len)| Seg {
steer: if refl { s.mirrored() } else { s },
len: sign * len,
}).collect()
};
if let Some((t, u, v)) = lp_sp_lp(sx * x, sy * y, sp * phi) {
out.push(word([Steer::L, Steer::S, Steer::L], [t, u, v]));
}
if let Some((t, u, v)) = lp_sp_rp(sx * x, sy * y, sp * phi) {
out.push(word([Steer::L, Steer::S, Steer::R], [t, u, v]));
}
// … L+R-L (and its backwards reading), the two CCCC, the four CCSC, the CCSCC.
}
out
}
/// The shortest word in world units, or None (never, for ρ > 0).
pub fn reeds_shepp_shortest_path(q0: &SE2, q1: &SE2, rho: f64) -> Option<(Vec<Seg>, f64)> {
let local = q0.inverse() * *q1; // goal in the start's frame
reeds_shepp_candidates(local.x / rho, local.y / rho, local.theta)
.into_iter()
.map(|w| { let l = rho * w.iter().map(|s| s.len.abs()).sum::<f64>(); (w, l) })
.min_by(|a, b| a.1.total_cmp(&b.1))
}
impl Steer {
fn mirrored(self) -> Self { match self { Steer::L => Steer::R, Steer::R => Steer::L, Steer::S => Steer::S } }
}use std::collections::VecDeque;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Action { Lp, Sp, Rp, Lm, Sm, Rm }
/// Integer weights: OPEN becomes an array of FIFO buckets indexed by cost (Choset's
/// "one-dimensional array with cost as the index"), so insertion is O(1).
#[derive(Clone, Copy, Debug)]
pub struct GridSearchCost { pub a: u32, pub b: u32, pub c: u32 }
pub struct Node<C> { pub q: C, pub parent: Option<usize>, pub action: Option<Action>, pub cost: u32 }
/// C Alg. 22, generic over the car model so the trailer is one type away.
pub fn car_grid_search<C: CarModel>(
car: &C, q_start: C::Config, goal: &GoalRegion<C::Config>, step: f64,
cells_per_dim: usize, cost: GridSearchCost, cs: &dyn collide::Collision<C::Config>,
max_tree: usize,
) -> Result<Vec<(C::Config, Action)>, Failure> {
let mut tree = vec![Node { q: q_start, parent: None, action: None, cost: 0 }];
let mut open: Vec<VecDeque<usize>> = vec![VecDeque::from([0])];
let mut occupied = vec![false; car.cells(cells_per_dim)]; // d³, or d⁴ with a trailer
let mut lowest = 0usize;
while tree.len() < max_tree {
// Line 3: the first node of the lowest non-empty bucket.
while lowest < open.len() && open[lowest].is_empty() { lowest += 1; }
let Some(id) = open.get_mut(lowest).and_then(|b| b.pop_front()) else { break };
let q = tree[id].q.clone();
// Line 4: the goal is tested when popped, which is what makes the path cost-optimal.
if goal.contains(&q) { return Ok(path_to(&tree, id)); }
// Lines 7-8: expand each cell once.
let cell = car.cell_of(&q, cells_per_dim);
if std::mem::replace(&mut occupied[cell], true) { continue; }
for act in Action::ALL {
let (q_new, sweep) = car.integrate(&q, act, step);
if !sweep.iter().all(|s| cs.is_free(s)) { continue; } // line 11
let prev = tree[id].action;
let c = tree[id].cost + cost.a
+ if prev.is_some_and(|p| p.steer() != act.steer()) { cost.b } else { 0 }
+ if prev.is_some_and(|p| p.dir() != act.dir()) { cost.c } else { 0 };
if open.len() <= c as usize { open.resize_with(c as usize + 1, VecDeque::new); }
open[c as usize].push_back(tree.len());
lowest = lowest.min(c as usize);
tree.push(Node { q: q_new, parent: Some(id), action: Some(act), cost: c });
}
}
Err(Failure::TreeExhausted { size: tree.len() })
}use rand::Rng;
use rand_pcg::Pcg64;
/// §7.5.1: planning with a simulator instead of a steer.
pub trait Propagate {
type State: Clone;
type Control: Clone;
fn propagate(&self, x: &Self::State, u: &Self::Control, dt: f64) -> Self::State; // RK4 inside
fn sample_control(&self, rng: &mut Pcg64) -> Self::Control;
}
pub struct KinoRrt<P: Propagate> {
pub sys: P,
pub controls_per_extend: usize,
pub dt: f64,
pub substeps: usize,
pub goal_bias: f64,
nodes: Vec<(P::State, Option<(usize, P::Control)>)>,
}
impl<P: Propagate> KinoRrt<P> {
pub fn plan(
&mut self, x_start: P::State, goal: &dyn Fn(&P::State) -> bool, n: usize,
sample: &dyn Fn(&mut Pcg64) -> P::State, metric: &dyn Fn(&P::State, &P::State) -> f64,
is_free: &dyn Fn(&P::State) -> bool, rng: &mut Pcg64,
) -> Option<Vec<(P::Control, f64)>> {
self.nodes = vec![(x_start, None)];
for _ in 0..n {
let x_rand = sample(rng);
// The metric is the planner's only notion of "near" — and its most sensitive knob.
let near = (0..self.nodes.len())
.min_by(|&a, &b| metric(&self.nodes[a].0, &x_rand).total_cmp(&metric(&self.nodes[b].0, &x_rand)))?;
let mut best: Option<(P::State, P::Control, f64)> = None;
for _ in 0..self.controls_per_extend {
let u = self.sys.sample_control(rng);
let h = self.dt / self.substeps as f64;
let mut x = self.nodes[near].0.clone();
let mut free = true;
for _ in 0..self.substeps {
x = self.sys.propagate(&x, &u, h);
if !is_free(&x) { free = false; break; }
}
let d = metric(&x, &x_rand);
if free && best.as_ref().is_none_or(|b| d < b.2) { best = Some((x, u, d)); }
}
let Some((x_new, u, _)) = best else { continue };
self.nodes.push((x_new.clone(), Some((near, u))));
if goal(&x_new) { return Some(self.controls_to(self.nodes.len() - 1)); }
}
None
}
}use nalgebra::{SMatrix, SVector};
/// Theorem 12.4.7: V is decoupling iff V ∈ span(Y) and ∇_V V ∈ span(Y).
pub fn is_decoupling<const Q: usize>(
v: &dyn VectorField<Q>, inputs: &[&dyn VectorField<Q>],
model: &dynamics::Model<Q>, q: &SVector<f64, Q>, tol: f64,
) -> bool {
let y: Vec<SVector<f64, Q>> = inputs.iter().map(|f| f.eval(q)).collect();
let vq = v.eval(q);
// ∇_V V = (∂V/∂q) V + M⁻¹ (Vᵀ Γ V), Chapter 17's Christoffel symbols, Choset's convention.
let nabla = v.jacobian(q) * vq + model.mass_matrix(q).try_inverse().unwrap()
* model.christoffel_form(q, &vq, &vq);
relative_residual(&vq, &y) < tol && relative_residual(&nabla, &y) < tol
}
/// Reach 3R with u₃ = 0: rotation of link 3 about its center of percussion with respect
/// to joint 3, at k = (I₃ + m₃r₃²)/(m₃r₃) — 0.205 m for Choset's Table 12.1 robot.
pub fn rotate_about_percussion(arm: &PlanarArm<3>) -> impl VectorField<3> + '_ {
let k = arm.percussion_distance();
move |q: &SVector<f64, 3>| {
let a = q.sum(); // link 3's absolute heading
let j: SMatrix<f64, 2, 2> = arm.joint3_jacobian(q); // ∂(x_J3, y_J3)/∂(q₁, q₂)
let r = j.try_inverse().unwrap() * SVector::<f64, 2>::new(k * a.sin(), -k * a.cos());
SVector::<f64, 3>::new(r[0], r[1], 1.0 - r[0] - r[1])
}
}The worked example, printed
fn main() {
let q0 = SE2::new(0.0, 0.0, 0.0);
let q1 = SE2::new(3.0, 3.0, std::f64::consts::FRAC_PI_2);
for p in dubins_all(&q0, &q1, 1.0) {
println!("{:?} t={:.6} p={:.6} q={:.6} len={:.6}", p.word, p.segs[0], p.segs[1], p.segs[2], p.len());
}
let best = dubins_shortest_path(&q0, &q1, 1.0).unwrap();
let end = best.integrate(&q0);
println!("integrate(LSL) -> ({:.6}, {:.6}, {:.6})", end.x, end.y, end.theta);
let (rs, len) = reeds_shepp_shortest_path(&q0, &q1, 1.0).unwrap();
println!("reeds-shepp: {} len={:.6}", word_string(&rs), len);
}LSL t=0.785398 p=2.828427 q=0.785398 len=4.399223
LSR t=0.927295 p=4.000000 q=5.639684 len=10.566979
RSL t=5.639684 p=4.000000 q=0.927295 len=10.566979
LRL t=3.141593 p=4.712389 q=3.141593 len=10.995574
RSR t=5.497787 p=5.656854 q=5.497787 len=16.652429
integrate(LSL) -> (3.000000, 3.000000, 1.570796)
reeds-shepp: L+S+L+ len=4.399223t=0.25 y=(0.250000, 0.156250) theta=0.844154 v=1.505199 omega=1.324138 kappa=0.879709 phi(L=1)=0.721491
t=0.50 y=(0.500000, 0.500000) theta=0.982794 v=1.802776 omega=0.000000 kappa=0.000000 phi(L=1)=0.000000percussion distance k = 0.205000 m
plan: T- 0.240 | R+ 1.100 | T+ 0.390 | R- 0.200 (3 switches)
time-optimal, rest to rest: 0.151 + 0.157 + 0.230 + 0.050 = 0.589 s
max |tau3| along every segment: 0 (to finite-difference accuracy); one actuator saturated at every node#[test] fn reproduces_micro_example() asserts the first two blocks to ;
tests/words_integrate.rs draws 400 seeded pose pairs and asserts that every Dubins and Reeds–Shepp word
integrates to its endpoint within and that Euclidean Reeds–Shepp Dubins length. The
dead-joint example cannot reproduce Choset's s, because his Fig. 12.33 path is drawn but not
given numerically; it reproduces his structure — four decoupling segments, one actuator always
saturated — on the query of w21.6.
Putting it together
The Integration lab is park_six_ways live: Hitch with its 2.5 m trailer, from into bay 3,
every planner of the chapter, one scoreboard (seed 21; the trailer is simulated along each path, or
produced by the method itself for the trailer-axle flat planner and Algorithm 22's trailer extension).
| method | length (m) | cusps | max (rad) | clearance (m) | ends |
|---|---|---|---|---|---|
| Reeds–Shepp (obstacle-blind) | 7.37 | 1 | 0.62 | 0.10 | exactly on the goal |
| flat-output quintic, trailer axle | 9.19 | 0 | 1.03 | collides | exactly; up to 1.39 rad |
| chained-form sinusoids | 27.89 | 3 | 2.39 | collides | exactly, in chained coordinates |
| CAR GRID SEARCH (Alg. 22, trailer grid) | 7.20 | 0 | 0.63 | 0.11 | inside m, rad |
| hybrid A* (car), trailer towed | 7.37 | 1 | 0.62 | 0.10 | exactly (its RS shot) |
| forward-propagation RRT, dynamic car | 6.85 | 0 | 0.66 | 0.13 | inside m, rad |
Read it as a summary of the chapter. Here the query is open enough that hybrid A*'s first shot is already free, so it is the Reeds–Shepp path; Algorithm 22 finds a slightly shorter path only because it is allowed to stop half a metre short. The flat planner's single smooth curve is the only one built around the trailer, and it is also the one that asks for more steering than Hitch has. The sinusoids are exact in the coordinates where they are exact and absurd everywhere else: the trailer swings to rad, a jackknife, because the chained form of the four-state car simply does not contain it. The forward-propagated tree is the shortest because its goal is a region — the honest comparison is the column on the right.
Two more experiments belong to the lab. The failure button: shrink the bay until Hitch is only a little shorter than it and run Algorithm 22 with ; the number of cusps in the solution grows as the slack shrinks, as Choset's theorem says it must, and no planner in this chapter can beat that — it is a property of the car, paid in Chapter 20's currency of brackets. The randomized pillar: in w21.1 turn obstacles on and re-roll the seed; a third pillar lands in the open floor, the obstacle-blind methods start reporting collisions, and Algorithm 22 routes around it. Chapter 23 reuses the trailer flat-output planner and the lattice for its jackknife tour, and Chapter 22 learns hybrid A*'s heuristic from data.
The sister book's motion-planning chapter previewed the Dubins dial and sketched hybrid A* for a car under uncertainty; this chapter is the derivation and the tested implementation behind both.
Exercises
- Foundation exerciseDifficulty 2 of 3RSL from LSL, and when CCC can never win
Derive the closed form from by reflection and reversal, and show where makes it infeasible. Then prove that for no word is optimal — note that words can still be feasible there.
- Foundation exerciseDifficulty 2 of 3Chained forms are flat
Prove that every chained-form system is flat with as flat outputs (Choset Problem 25) and give and explicitly for . Relate to Hitch's trailer flat output when the car-with-trailer is put in chained form.
- Conceptual exerciseDifficulty 1 of 3Predict the word, then dragPredict first
In the Reeds–Shepp Atlas with ρ = 1, start (0, 0, 0) and goal (2, −1, 0): which word is the shortest Dubins path, and does allowing cusps (Reeds–Shepp) shorten it?
Length of the shortest path to (2, −1, 0) at ρ = 1
- Conceptual exerciseDifficulty 2 of 3Make the sinusoids swing and the flat planner fail
In w21.1 with the trailer on, place the bay so that the sinusoid planner's trailer swing exceeds rad while the flat planner stays under ; then make the flat planner fail (its steering demand over rad) by lowering the end-speed slider. Say where control constraints enter each method.
- Practical exerciseDifficulty 2 of 3CAR GRID SEARCH with a trailer, and the jackknife guard
Implement the trailer extension of
car_grid_searchwith a lookup table of per primitive (indexed by the hitch angle at the start of the motion, Choset §12.5.6), check it against integration on three seeded queries, and add the jackknife guard as pruning. Measure the expansions it saves. - Practical exerciseDifficulty 3 of 3Kinodynamic RRT* for Hitch's dynamic model (stretch)
Implement
KinoRrtStarfor Hitch's dynamic model linearized about rest (Webb and van den Berg: fixed-final-state, free-final-time LQR edges), compare its cost curve withKinoRrt(best of 8) over 20 seeds, then swap the LQR edge forsteer_flatand report which assumption each connection violates.
References
- Choset, H., Lynch, K. M., Hutchinson, S., Kantor, G., Burgard, W., Kavraki, L. E., and Thrun, S. (2005) Principles of Robot Motion: Theory, Algorithms, and Implementations. MIT Press.link to Principles of Robot Motion: Theory, Algorithms, and Implementations (opens in a new tab)
Chapter 12, §12.4.2 and §12.5 (Brockett's sinusoids, chained forms, gradient steering, flatness, cars and trailers, Algorithm 22, kinematic reductions, Table 12.1) and §7.5.1 (control-based planning), followed section by section. The Souères–Laumond synthesis and the Sussmann–Tang reduction of the Reeds–Shepp list are its refs. 395 and 402.
- Dubins, L. E. (1957) On Curves of Minimal Length with a Constraint on Average Curvature, and with Prescribed Initial and Terminal Positions and Tangents. American Journal of Mathematics 79(3).doi:10.2307/2372560 (opens in a new tab)
The six-word result for the forward-only car: the CSC/CCC words implemented in dubins.ts and pinned by the micro-example.
- Reeds, J. A. and Shepp, L. A. (1990) Optimal Paths for a Car That Goes Both Forwards and Backwards. Pacific Journal of Mathematics 145(2).doi:10.2140/pjm.1990.145.367 (opens in a new tab)
The forty-eight words and the §8 base formulas that reeds-shepp.ts evaluates under the time-flip and reflect symmetries.
- Murray, R. M. and Sastry, S. S. (1993) Nonholonomic Motion Planning: Steering Using Sinusoids. IEEE Transactions on Automatic Control 38(5).doi:10.1109/9.277235 (opens in a new tab)
Chained forms, the sinusoid ladder of eq. (12.31), and the chained coordinates of the kinematic car used by steerCarSinusoids.
- Fliess, M., Lévine, J., Martin, P., and Rouchon, P. (1995) Flatness and Defect of Non-linear Systems: Introductory Theory and Examples. International Journal of Control 61(6).doi:10.1080/00207179508921959 (opens in a new tab)
Differential flatness, with the car and the car with trailers among its examples — Choset's refs. 152–153 and the basis of flat.ts.
- Barraquand, J. and Latombe, J.-C. (1993) Nonholonomic Multibody Mobile Robots: Controllability and Motion Planning in the Presence of Obstacles. Algorithmica 10.doi:10.1007/BF01891837 (opens in a new tab)
The grid search over full-lock primitives with a cusp-weighted cost that Choset presents as Algorithm 22, including the trailer extension.
- Laumond, J.-P., Jacobs, P. E., Taïx, M., and Murray, R. M. (1994) A Motion Planner for Nonholonomic Mobile Robots. IEEE Transactions on Robotics and Automation 10(5).doi:10.1109/70.326564 (opens in a new tab)
The omnidirectional-to-nonholonomic path transformation by recursive Reeds–Shepp bisection (pathTransform) and the topological property behind its completeness.
- LaValle, S. M. and Kuffner, J. J. (2001) Randomized Kinodynamic Planning. International Journal of Robotics Research 20(5).doi:10.1177/02783640122067453 (opens in a new tab)
Forward-propagation RRTs for systems with differential constraints — the KinoRrt of this chapter and the metric-sensitivity discussion.
- Bullo, F. and Lynch, K. M. (2001) Kinematic Controllability for Decoupled Trajectory Planning in Underactuated Mechanical Systems. IEEE Transactions on Robotics and Automation 17(4).doi:10.1109/70.954753 (opens in a new tab)
Decoupling vector fields, Theorem 12.4.7 and kinematic controllability, with the 3R arm whose third joint is unactuated.
- Pivtoraiko, M., Knepper, R. A., and Kelly, A. (2009) Differentially Constrained Mobile Robot Motion Planning in State Lattices. Journal of Field Robotics 26(3).doi:10.1002/rob.20285 (opens in a new tab)
State lattices with lattice-consistent primitives: delta 1 of the chapter's three deltas from Algorithm 22.
- Dolgov, D., Thrun, S., Montemerlo, M., and Diebel, J. (2010) Path Planning for Autonomous Vehicles in Unknown Semi-structured Environments. International Journal of Robotics Research 29(5).doi:10.1177/0278364909359210 (opens in a new tab)
Hybrid A*: continuous states in a discrete grid, analytic Reeds–Shepp expansions and the dual heuristic — deltas 2 and 3.
- Webb, D. J. and van den Berg, J. (2013) Kinodynamic RRT*: Asymptotically Optimal Motion Planning for Robots with Linear Dynamics. IEEE International Conference on Robotics and Automation (preprint arXiv:1205.5088).link to Kinodynamic RRT*: Asymptotically Optimal Motion Planning for Robots with Linear Dynamics (opens in a new tab)
The fixed-final-state, free-final-time optimal edge that turns RRT* into a kinodynamic planner; the double-integrator closed form in kinodynamic.ts.
- Karaman, S. and Frazzoli, E. (2011) Sampling-based Algorithms for Optimal Motion Planning. International Journal of Robotics Research 30(7).doi:10.1177/0278364911406761 (opens in a new tab)
RRT* and its asymptotic optimality, which Chapter 13 proves and Kinodynamic RRT* inherits once the steer is exact.
