Robot Motion
Chapter 20PART VDynamics, Trajectories, and ConstraintsDifficulty: AdvancedEstimated reading time: 70 min

Nonholonomic Systems I — Controllability

A velocity constraint is not a configuration constraint. The Lie bracket is the exact bookkeeping of what wiggling buys, Chow's theorem says when the brackets span everything, Frobenius says when they never will, and the symmetric product carries the same test to Reach with a dead motor and Rusty with mass.

We know by experience, however, that this velocity constraint does not imply a constraint on configurations; the car can reach any position and orientation in the obstacle-free plane. In fact, the prevented sideways translation can be approximated by parallel-parking maneuvers.
Howie Choset, Kevin Lynch, Seth Hutchinson, George Kantor, Wolfram Burgard, Lydia Kavraki, and Sebastian ThrunPrinciples of Robot Motion (2005), Chapter 12

In this chapter

Hitch cannot slide sideways. Every reader also knows Hitch can end up half a metre to the left of where it started, parallel-parked, by wiggling. This chapter turns that folk knowledge into a theorem, and the theorem has a precise shape: a velocity constraint is not a configuration constraint, and the Lie bracket is the exact bookkeeping of what wiggling buys. Follow drive for a time ϵ\epsilon, then steer for ϵ\epsilon, then undo both in order. You do not return home. You are displaced by ϵ2\epsilon^2 in a direction neither input produces directly — the bracket [g1,g2][g_1, g_2] — plus a remainder of order ϵ3\epsilon^3 that this chapter measures rather than waves away.

Stack brackets until they span the tangent space and Chow's theorem says the system reaches everything nearby; stop short and Frobenius says it is trapped on a lower-dimensional leaf forever. That is the first half. The second half asks the same question of second-order systems — Reach with its third motor dead, Rusty with mass — where drift complicates the bookkeeping and the symmetric product of Lewis and Murray halves the work.

Everything here is analysis. Nothing in this chapter produces a plan; the catalogue of steering methods that cash these verdicts in is Chapter 21. Three honesty items the prose keeps throughout: the Lie algebra rank condition is necessary only for analytic fields; Sussmann's condition is sufficient, not necessary; and STLC for a second-order system is always a statement at rest.

The problem: sideways is forbidden, sideways is reachable

Tell Hitch "half a metre to the left, same heading". A holonomic ghost — the free-flying rectangle of Chapter 4 — slides there in a second. Hitch has two inputs, a speed and a steering rate, and no combination of them has a sideways component. Yet Hitch gets there, by spinning a little, driving a little, unspinning, undriving, fourteen times over.

t=0
Figure Hitch is asked for 0.5 m of pure sideways displacement. The purple ghost slides there in one second. Hitch repeats the loop spin → drive → unspin → undrive with ε = 0.19 rad: each loop buys ε sin ε ≈ ε² = 0.036 m sideways, so fourteen loops are needed — and each leaks ε(1 − cos ε) ≈ ε³/2 backward, the O(ε³) term the chapter keeps.

Two things in that picture are the whole chapter. The sideways gain per loop is quadratic in the wiggle amplitude, which is why parallel parking is slow and why a planner that only has the four-flow recipe would be a terrible planner. And the gain has a direction that neither input has — the Lie bracket of the two input fields, which is the one new mathematical object you need.

Building intuition

Wiggling has a direction

The loop below is Choset's equation (12.3): from x0x_0, follow g1g_1 for ϵ\epsilon, then g2g_2 for ϵ\epsilon, then −g1-g_1 for ϵ\epsilon, then −g2-g_2 for ϵ\epsilon. For the unicycle's drive and spin fields the four legs are exact — two arcs of length ϵ\epsilon and two spins of angle ϵ\epsilon — so the residue can be written in closed form and compared to the prediction ϵ2[g1,g2]\epsilon^2[g_1, g_2].

Three things to notice, each a theorem below.

There is no first-order term. Halve ϵ\epsilon and the residue drops by four, not two: the blue dot in the inset slides down a line of slope two. At ϵ=0.1\epsilon = 0.1 the loop from heading π/6\pi/6 moves Hitch by [0.005424,−0.008396,0][0.005424, -0.008396, 0] against the prediction ϵ2[g1,g2]=[0.005,−0.00866,0]\epsilon^2[g_1, g_2] = [0.005, -0.00866, 0]; the gap is 5.0×10−45.0 \times 10^{-4}, the O(ϵ3)O(\epsilon^3) remainder.

The direction is new. [g1,g2]=[sin⁡x3,−cos⁡x3,0]⊤[g_1, g_2] = [\sin x_3, -\cos x_3, 0]^\top is perpendicular to the heading — exactly the direction the no-slip constraint forbids. Two fields that cannot move you sideways produce a loop that does.

Brackets stack. Switch to the four-state car. Its inputs are speed and steering rate, and the first bracket g3=[g1,g2]g_3 = [g_1, g_2] only buys heading change — a car that can set its steering angle but has not yet driven has turned nothing. Loop g1g_1 with g3g_3 and the residue is sideways: the second-degree bracket g4=[g1,g3]g_4 = [g_1, g_3]. Hitch needs two rungs of brackets for the same direction the unicycle needed one, and that number — the degree at which the brackets fill the tangent space — is what the filtration counts.

Four words for four sets

"Controllable" is one word in linear systems theory and four in this chapter, because for a nonlinear system the shape of the reachable set matters: does it have interior, does it have interior without leaving a small ball, does it contain a neighbourhood of the start inside that ball?

With drive alone the reachable set is a curve — the integral curve of g1g_1 — and no controllability property holds. With drive and spin, controls in [−1,1]2[-1, 1]^2, the sampled set fills a blob with the start in its interior: small-time locally controllable. Flip to the forward-only, left-only control set U∈U+U \in \mathcal{U}^+ and the set keeps its interior but hugs the start's boundary — nothing is behind Hitch, because in small time the heading cannot swing past π/2\pi/2. That system is accessible, STLA and (in the open plane) controllable, yet not STLC. The macro adds [g1,g2][g_1, g_2] as if it were a third input, and sideways becomes first-order: the widget is pretending to be a system whose Lie algebra is spanned at degree one, which is what every steering method of Chapter 21 constructs by other means.

Rank is a property of the point

Choset's Example 12.1.7 is two innocent-looking fields on R3\mathbb{R}^3, g1=[x1cos⁡x3, x2sin⁡x3, 0]⊤g_1 = [x_1\cos x_3,\ x_2\sin x_3,\ 0]^\top and g2=∂/∂x3g_2 = \partial/\partial x_3, whose bracket has determinant x1x2x_1 x_2 against them.

Start anywhere off the coordinate planes and the system reaches a full three-dimensional neighbourhood. Start on the plane x1=0x_1 = 0 and g1g_1 loses its first component for good — the reachable set is a half-plane, and no sequence of controls ever leaves it. Start on the x3x_3-axis and it is a line. Nine leaves in all. A rank test at one configuration settles controllability there; the trailer's jackknife in Chapter 23 is the same lesson in a less innocent system.

Notation used in this chapter
SymbolMeaningNote
M, x∈M, nM,\ x \in M,\ nstate manifold, state, its dimensionM = 𝒬 for a kinematic system; M = T𝒬, x = (q, q̇) for a second-order one
TxM, TM, ω(x), ϕtg(x)T_xM,\ TM,\ \omega(x),\ \phi^g_t(x)tangent space, tangent bundle, a covector (one-form), the flow of g for time tω(x)ẋ = 0 is the negative form of a constraint
D=span(G), Dk, D‾, Lie(G)\mathcal{D} = \mathrm{span}(\mathcal{G}),\ \mathcal{D}_k,\ \overline{\mathcal{D}},\ \mathrm{Lie}(\mathcal{G})distribution, k-th step of the filtration, involutive closure, Lie algebra generatedChoset §12.1.2–12.1.3
[g1,g2]=∂g2∂xg1−∂g1∂xg2\lie{g_1}{g_2} = \tfrac{\partial g_2}{\partial x} g_1 - \tfrac{\partial g_1}{\partial x} g_2the Lie bracket (eq. 12.5)the sign under which the four-flow loop moves by +ε²[g₁, g₂]
g0, gi, u∈U⊂Rmg_0,\ g_i,\ u \in U \subset \R^mdrift field, control fields, control vector and setẋ = g₀ + Σ gᵢuᵢ (eq. 12.6)
U±, U+\mathcal{U}^\pm,\ \mathcal{U}^+control sets with the origin interior to the convex hull / merely spanning ℝᵐ[−1, 1]ᵐ and its vertices / [0, 1]ᵐ
RV(x,≤T)R^V(x, \le T)states reachable within time T without leaving the neighbourhood Vthe set the four notions are about
⟨v1,v2⟩=v1TM(q)v2, ∇Y1Y2, ⟨Y1:Y2⟩\langle v_1, v_2 \rangle = v_1\T M(q) v_2,\ \nabla_{Y_1}Y_2,\ \langle Y_1 : Y_2 \ranglekinetic-energy metric, covariant derivative, symmetric productChapter 17's Christoffel symbols, Choset's convention (no M⁻¹ inside Γ)
Yi(q), Sym(Y)Y_i(q),\ \mathrm{Sym}(\mathcal{Y})columns of M⁻¹(q)T(q); the symmetric closureinput fields on 𝒬, not on T𝒬
P=I−M−1AT(AM−1AT)−1A, Y~i=PYi, ∇~P = I - M^{-1}A\T(AM^{-1}A\T)^{-1}A,\ \tilde Y_i = PY_i,\ \tilde\nablaconstraint projection, constrained inputs and connectionChapter 17's projectionP
q=(x,y,ϕ,θ), L, γ; ψ, θ1=θ−ψ, dq = (x, y, \phi, \theta),\ L,\ \gamma;\ \psi,\ \theta_1 = \theta - \psi,\ dHitch: rear-axle position, steering angle, heading (Choset's ordering), wheelbase, steering limit; trailer heading, hitch angle, hitch lengthChapter 2 integrates ψ; Choset writes θ₁

The mathematics

Following Choset, the state space is a vector space M=RnM = \mathbb{R}^n throughout: every manifold in this book is locally diffeomorphic to Rn\mathbb{R}^n, and the price — angles wrap, so a heading coordinate is only a chart — is one this chapter pays knowingly. The global structure returns in Chapter 5's Manifold, which is where the planners of Part III live; here we differentiate, and differentiation is local.

Vector fields, flows, distributions

A vector field is a smooth map g:M→TMg : M \to TM with g(x)∈TxMg(x) \in T_xM — in coordinates, a column vector that depends on xx. Its flow ϕtg(x)\phi^g_t(x) solves x˙=g(x)\dot x = g(x) from xx for time tt, and the integral curve through xx is {ϕtg(x):t∈R}\{\phi^g_t(x) : t \in \mathbb{R}\}. A set G\mathcal{G} of fields generates the distribution D=span(G)\mathcal{D} = \mathrm{span}(\mathcal{G}), a linear subspace of TxMT_xM at each xx; it is regular if that subspace has the same dimension everywhere.

The unicycle's two fields, drive and spin, are the positive form of its distribution,

g1(x)=[cos⁡x3sin⁡x30],g2(x)=[001],D(x)={u1g1(x)+u2g2(x)},\htmlClass{term-robot}{g_1(x) = \begin{bmatrix}\cos x_3\\ \sin x_3\\ 0\end{bmatrix}},\qquad \htmlClass{term-robot}{g_2(x) = \begin{bmatrix}0\\ 0\\ 1\end{bmatrix}},\qquad \mathcal{D}(x) = \{u_1 g_1(x) + u_2 g_2(x)\},

and the no-slip constraint is its negative form: D(x)={x˙:ω(x)x˙=0}\mathcal{D}(x) = \{\dot x : \omega(x)\dot x = 0\} with the covector ω(x)=[−sin⁡x3, cos⁡x3, 0]\omega(x) = [-\sin x_3,\ \cos x_3,\ 0] (Choset eq. 12.1). A velocity constraint f(q,q˙)=0f(q, \dot q) = 0 that cannot be integrated to a configuration constraint is nonholonomic; the Pfaffian ones, a(q)q˙=0a(q)\dot q = 0, are the kind Chapter 17 handled with the projection PP, and the whole question of this chapter is whether they integrate.

The Lie bracket from the four-flow loop

DerivationExpanding the four flows to second order

Step 1 — one flow. Taylor-expand ϕϵg(x)\phi^g_\epsilon(x) in ϵ\epsilon: x˙=g(x)\dot x = g(x) and x¨=∂g∂xx˙=∂g∂xg\ddot x = \frac{\partial g}{\partial x}\dot x = \frac{\partial g}{\partial x}g, so ϕϵg(x)=x+ϵg(x)+ϵ22∂g∂x(x) g(x)+O(ϵ3)\phi^g_\epsilon(x) = x + \epsilon g(x) + \tfrac{\epsilon^2}{2}\frac{\partial g}{\partial x}(x)\,g(x) + O(\epsilon^3).

Step 2 — compose g2g_2 after g1g_1. Write x1=ϕϵg1(x0)x_1 = \phi^{g_1}_\epsilon(x_0). Then ϕϵg2(x1)=x1+ϵg2(x1)+ϵ22∂g2∂xg2+O(ϵ3)\phi^{g_2}_\epsilon(x_1) = x_1 + \epsilon g_2(x_1) + \tfrac{\epsilon^2}{2}\frac{\partial g_2}{\partial x}g_2 + O(\epsilon^3), and re-expanding g2(x1)g_2(x_1) at x0x_0 gives g2(x1)=g2(x0)+ϵ∂g2∂xg1(x0)+O(ϵ2)g_2(x_1) = g_2(x_0) + \epsilon\frac{\partial g_2}{\partial x}g_1(x_0) + O(\epsilon^2). The cross term ϵ2∂g2∂xg1\epsilon^2\frac{\partial g_2}{\partial x}g_1 appears; the self terms ϵ22∂gi∂xgi\tfrac{\epsilon^2}{2}\frac{\partial g_i}{\partial x}g_i are carried along.

Step 3 — compose −g1-g_1. The ϵg1\epsilon g_1 term cancels the one from step 1. Re-expanding −g1-g_1 at the current point produces −ϵ2∂g1∂x(g1+g2)-\epsilon^2\frac{\partial g_1}{\partial x}(g_1 + g_2) from the first-order displacement ϵ(g1+g2)\epsilon(g_1 + g_2) accumulated so far, and the self term +ϵ22∂g1∂xg1+\tfrac{\epsilon^2}{2}\frac{\partial g_1}{\partial x}g_1 from the flow of −g1-g_1 itself (the sign of gg enters twice). The two g1g_1-self contributions cancel: ϵ22−ϵ2+ϵ22=0\tfrac{\epsilon^2}{2} - \epsilon^2 + \tfrac{\epsilon^2}{2} = 0. What survives from this leg is −ϵ2∂g1∂xg2-\epsilon^2\frac{\partial g_1}{\partial x}g_2.

Step 4 — compose −g2-g_2. Likewise the ϵg2\epsilon g_2 term cancels, the g2g_2-self terms cancel, and the re-expansion of −g2-g_2 at a point displaced by ϵg2\epsilon g_2 (the g1g_1 displacement is gone) gives −ϵ2∂g2∂xg2+ϵ22∂g2∂xg2-\epsilon^2\frac{\partial g_2}{\partial x}g_2 + \tfrac{\epsilon^2}{2}\frac{\partial g_2}{\partial x}g_2, which together with step 2's ϵ22∂g2∂xg2\tfrac{\epsilon^2}{2}\frac{\partial g_2}{\partial x}g_2 sums to zero.

Step 5 — collect. Every first-order term and every self term is gone; the survivors are the two cross terms, ϵ2(∂g2∂xg1−∂g1∂xg2)\epsilon^2\big(\frac{\partial g_2}{\partial x}g_1 - \frac{\partial g_1}{\partial x}g_2\big) — the bracket.

The unicycle in closed form. Drive by ϵ\epsilon at heading x3x_3, spin by ϵ\epsilon, drive back by ϵ\epsilon at heading x3+ϵx_3 + \epsilon, spin back:

x(4ϵ)−x0=ϵ[cos⁡x3−cos⁡(x3+ϵ)sin⁡x3−sin⁡(x3+ϵ)0]=ϵ2[sin⁡x3−cos⁡x30]+ϵ32[cos⁡x3sin⁡x30]+O(ϵ4).x(4\epsilon) - x_0 = \epsilon\begin{bmatrix}\cos x_3 - \cos(x_3 + \epsilon)\\ \sin x_3 - \sin(x_3 + \epsilon)\\ 0\end{bmatrix} = \epsilon^2\begin{bmatrix}\sin x_3\\ -\cos x_3\\ 0\end{bmatrix} + \frac{\epsilon^3}{2}\begin{bmatrix}\cos x_3\\ \sin x_3\\ 0\end{bmatrix} + O(\epsilon^4).

The ϵ2\epsilon^2 term is [g1,g2][g_1, g_2]; the ϵ3/2\epsilon^3/2 term points along the heading, so the loop also drifts forward by half a cube — the leak the hook measures and the number w20.1 plots.

The linear case and the sign (Choset Problem 8). For g1=Axg_1 = Ax, g2=Bxg_2 = Bx equation (12.5) gives [g1,g2]=BAx−ABx=(BA−AB)x[g_1, g_2] = BAx - ABx = (BA - AB)x, the negative of the matrix commutator AB−BAAB - BA that the sister book's Lie-group chapter uses. The sign is immaterial for spans and determinants' zero sets, and material for the direction of the loop residue; the library keeps Choset's and pins it in a check.

The library computes the bracket by formula (12.5) from each field's Jacobian — analytic for every system of this chapter, a fourth-order central difference otherwise — and the check compares the finite-difference bracket with the hand formula to 10−910^{-9} at the micro-example's configuration. Two properties hold for every pair and triple of fields and are property-tested on seeded random polynomial fields: skew-symmetry [g1,g2]=−[g2,g1][g_1, g_2] = -[g_2, g_1] and the Jacobi identity [g1,[g2,g3]]+[g3,[g1,g2]]+[g2,[g3,g1]]=0[g_1,[g_2,g_3]] + [g_3,[g_1,g_2]] + [g_2,[g_3,g_1]] = 0.

Filtrations, the involutive closure, Frobenius

A Lie product of degree kk is a bracket expression in which the original fields appear kk times. The Lie algebra Lie(G)\mathrm{Lie}(\mathcal{G}) is the span of all Lie products of all degrees, built by Choset's recursion

G1=G,Gi+1=Gi∪{[gj,gk]:gj∈G1, gk∈Gi},Di=span(Gi),\mathcal{G}_1 = \mathcal{G},\qquad \mathcal{G}_{i+1} = \mathcal{G}_i \cup \{\lie{g_j}{g_k} : g_j \in \mathcal{G}_1,\ g_k \in \mathcal{G}_i\},\qquad \mathcal{D}_i = \mathrm{span}(\mathcal{G}_i),

whose span sequence D1⊆D2⊆⋯\mathcal{D}_1 \subseteq \mathcal{D}_2 \subseteq \cdots is the filtration of D1\mathcal{D}_1. If the filtration is regular, each step either raises the dimension or stops, so it terminates at a finite kk with Dk=Dk+1=⋯=D‾\mathcal{D}_k = \mathcal{D}_{k+1} = \cdots = \overline{\mathcal{D}}, the involutive closure; D\mathcal{D} is involutive if D=D‾\mathcal{D} = \overline{\mathcal{D}}. If all products vanish beyond some degree the algebra is nilpotent, which Chapter 21's chained forms exploit.

DerivationWhy involutive is exactly what integrates

Step 1 — necessity. If the fields of D\mathcal{D} are tangent to a submanifold NN, their flows stay in NN, so the four-flow loop stays in NN, so its residue ϵ2[g1,g2]+O(ϵ3)\epsilon^2[g_1, g_2] + O(\epsilon^3) is tangent to NN in the limit: the bracket lies in TN=DTN = \mathcal{D}. Involutive is forced.

Step 2 — sufficiency, in one picture. Choose mm independent fields of an involutive D\mathcal{D} near xx. Because their brackets stay in D\mathcal{D}, the fields can be re-combined (pointwise, by an invertible m×mm \times m matrix) into mm commuting fields, and commuting flows can be straightened into coordinate flows ∂/∂y1,…,∂/∂ym\partial/\partial y_1, \dots, \partial/\partial y_m by the inverse function theorem. The leaf through xx is then {ym+1=const,…,yn=const}\{y_{m+1} = \text{const}, \dots, y_n = \text{const}\}.

Step 3 — regularity and termination. If every Di\mathcal{D}_i is regular, dim⁡Di\dim \mathcal{D}_i is constant in xx and non-decreasing in ii, bounded by nn; so it strictly increases or the recursion stops, after at most n−dim⁡D1n - \dim\mathcal{D}_1 steps. Without regularity nothing bounds the degree a priori — the library runs to a stated maximum and reports a stall separately from a closure.

Step 4 — the planning consequence. A system whose closure has dimension k<nk < n at xx never leaves a kk-dimensional leaf: it is neither controllable nor accessible, and no amount of cleverness with the inputs changes that. The unicycle with drive only (k=1k = 1) is the canonical case.

Example 12.1.7, by the numbers. g1=[x1cos⁡x3,x2sin⁡x3,0]⊤g_1 = [x_1\cos x_3, x_2\sin x_3, 0]^\top, g2=∂3g_2 = \partial_3, [g1,g2]=[x1sin⁡x3,−x2cos⁡x3,0]⊤[g_1, g_2] = [x_1\sin x_3, -x_2\cos x_3, 0]^\top and det⁡[g1 g2 [g1,g2]]=x1x2\det[g_1\ g_2\ [g_1, g_2]] = x_1x_2. The library's larc returns STLC at (0.7,−1.1,0.4)(0.7, -1.1, 0.4), a two-dimensional leaf at (0,1.3,0.4)(0, 1.3, 0.4) — the ladder stays at (2,2,2,2,2)(2, 2, 2, 2, 2) through degree five — and a one-dimensional leaf on the x3x_3-axis. Nine leaves: a line, four half-planes, four quadrants (Choset Figure 12.9).

The Philip Hall basis. Skew-symmetry and Jacobi mean most products in Gi\mathcal{G}_i are redundant; the Hall basis chooses the smallest set at each degree. The library prunes only the trivial redundancies ([g,g]=0[g, g] = 0, [gj,gk]=−[gk,gj][g_j, g_k] = -[g_k, g_j] at degree two) and products that vanish identically near the test point, and never prunes a product merely because it is dependent at the point — Example 12.1.7 on a coordinate plane is exactly a field that is zero at xx with nonzero brackets. Exercise 6 asks for the Hall basis proper.

Control-affine systems and the four notions

Choset's class is the control-affine system

x˙=g0(x)+∑i=1mgi(x) ui,u∈U⊂Rm,\dot x = \htmlClass{term-obstacle}{g_0(x)} + \sum_{i=1}^m \htmlClass{term-robot}{g_i(x)}\,u_i,\qquad u \in U \subset \R^m,

with drift g0g_0 and independent control fields gig_i; driftless if g0=0g_0 = 0. Kinematic systems may be driftless; second-order ones never are, because the state carries the velocity and the velocity carries the configuration whether or not any input acts. Two classes of control set matter: U±\mathcal{U}^\pm, whose convex hull contains the origin in its interior (positive combinations reach every direction — the cube [−1,1]m[-1, 1]^m, or just its vertices), and the larger U+\mathcal{U}^+, which merely spans (the non-negative cube). A driftless system with U∈U±U \in \mathcal{U}^\pm is symmetric: every motion can be run backward.

Let RV(x,≤T)R^V(x, \le T) be the states reachable within time TT by trajectories that never leave the neighbourhood VV of xx. The system is, from xx:

  • controllable if every xgoal∈Mx_{goal} \in M is in RM(x,≤T)R^M(x, \le T) for some finite TT;
  • accessible if RM(x,≤T)R^M(x, \le T) contains a full nn-dimensional set for some TT;
  • small-time locally accessible (STLA) if RV(x,≤T)R^V(x, \le T) contains a full nn-dimensional set for every VV and every T>0T > 0;
  • small-time locally controllable (STLC) if RV(x,≤T)R^V(x, \le T) contains a neighbourhood of xx for every VV and TT.

STLC is the one planners want: a system STLC everywhere can follow any curve in MM arbitrarily closely, so it can thread any clutter a free-flying body can thread. The implications among the four, and the conditions on the ones that are only sometimes true, are Choset's Figure 12.12:

w20.4Controllability LadderFour properties, three unconditional implications, three conditional ones — and no Kalman rank test anywhere.
if all vector fields are analyticif symmetric (driftless, U ∈ U±)if M is connected and STLC holds everywhereaccessibleaccessiblecontrollablecontrollablesmall-time locally accessiblesmall-time locallyaccessiblesmall-time locally controllablesmall-time locallycontrollablesolid: always · dashed (blue): under the stated condition · after Choset, Figure 12.12

small-time locally controllable

R^V(x, ≤ T) contains a neighborhood of x for every V and T: the system can wiggle in every direction without leaving any ball.

separating example

Symmetric systems with the LARC (Chow); systems with drift at an equilibrium when every bad bracket is neutralized (Sussmann).

in the lab

Hitch with and without the trailer (ladder 2→3→4(→5)); the PBWT with two thrusters at rest; Reach's 2R on the Workbench.

The linearization of every nonholonomic system in this chapter fails the Kalman rank test, so none of these properties can be read off a linear model; the Lie algebra is the only tool, and even it decides STLC only under the conditions on the dashed arrows.

The linear double integrator is the warning. q¨=u\ddot q = u with ∣u∣≤1|u| \le 1 is "controllable" in the Kalman sense, yet it is STLC only from rest: at q˙≠0\dot q \ne 0 reaching a point behind you requires the velocity to change sign, and the velocity coordinate must leave any small VV first. For second-order systems STLC always means STLC at zero velocity, and the linearizations of the nonholonomic systems of this chapter fail the Kalman rank test outright — their controllability is inherently nonlinear.

Chow's theorem and Sussmann's refinement

DerivationBrackets as motions, and why bad ones are one-way

Step 1 — every Lie product is a motion. A degree-kk product is realized by nesting four-flow loops: [g1,[g1,g2]][g_1, [g_1, g_2]] is a loop whose second leg is itself a loop. The net motion is O(ϵk)O(\epsilon^k) in time O(ϵ)O(\epsilon) — slower by one power per degree, which is why parking into a space ϵ\epsilon longer than the car costs Θ(1/ϵ2)\Theta(1/\epsilon^2) reversals (Chapter 21).

Step 2 — full rank gives interior. If the products span TxMT_xM, there are nn independent motion directions available in arbitrarily small time inside arbitrarily small VV, and small combinations of them sweep an open set: STLA. For analytic fields the converse holds because an analytic system's reachable set is determined by all derivatives at xx, which is the Lie algebra.

Step 3 — symmetry gives both signs. Reverse every leg of a loop and the residue flips sign; for a symmetric system the reversed controls are available, so each bracket direction comes with both signs and the open set of step 2 can be centred on xx: STLC.

Step 4 — bad brackets. Write the loop for a bracket with its control amplitudes uiu_i explicit. A control appearing an even number of times contributes ui2u_i^2 to the net motion, so flipping uiu_i changes nothing: the direction can be followed one way only, like a drift. A bad bracket is a one-way direction. It is harmless if a faster motion (a good bracket of lower degree) can cancel it — the bad bracket is neutralized — and fatal otherwise.

Step 5 — the degree-one bad bracket. g0g_0 itself is bad (drift once, controls zero times) and there is nothing of lower degree to neutralize it, hence the hypothesis g0(x)=0g_0(x) = 0: Sussmann's theorem speaks only at equilibria.

Step 6 — from local to global. On a connected MM, STLC everywhere gives controllability: chain neighbourhoods along any curve. The converse fails — the forward-only unicycle is controllable in the open plane and STLC nowhere.

Choset's four counterexamples, each in the library. The one-way watch knob (accessible, controllable, STLA, not STLC). g0=[x22,0]⊤g_0 = [x_2^2, 0]^\top, g1=∂2g_1 = \partial_2: at the origin [g0,g1]=0[g_0, g_1] = 0 and [g1,[g0,g1]]=[2,0]⊤[g_1, [g_0, g_1]] = [2, 0]^\top is bad — sussmannStlc reports the LARC satisfied at degree three and a neutralization residual of exactly 11 (nothing of lower degree points along x1x_1), hence STLA only; indeed x1x_1 never decreases. The double integrator: STLC at (0.5,0)(0.5, 0), undecided at (0.5,0.3)(0.5, 0.3) because g0≠0g_0 \ne 0. The unicycle with U∈U+U \in \mathcal{U}^+: STLA by Chow, STLC unavailable because symmetry is unavailable.

For Hitch the verdict is the one Choset promises in §12.5.6 and the micro-example below computes: the car is STLC at every configuration with ∣ϕ∣<π/2|\phi| < \pi/2, whatever the steering limit γ\gamma. A car that can only turn left reaches every pose in the Lot that a normal car can — slowly.

Global controllability from recurrent drift

DerivationRecurrence supplies the backward motions symmetry would have

Step 1. The LARC gives forward local reachability: an open set of states is reached from any xx in short time (STLA).

Step 2. To move against the drift, wait: recurrence returns the unforced flow arbitrarily close to where it started, so a neighbourhood of any state is reached again later without controls, and forward-only motions plus waiting generate backward displacements too.

Step 3. Chain neighbourhoods along any path, as in the connected-and-STLC argument.

The example. g0=12[−x2,x1]⊤g_0 = \tfrac12[-x_2, x_1]^\top (circular orbits — WPPS), g1=∂1g_1 = \partial_1: [g0,g1]=[0,−12]⊤[g_0, g_1] = [0, -\tfrac12]^\top and det⁡[g1 [g0,g1]]=−12\det[g_1\ [g_0, g_1]] = -\tfrac12 everywhere, so the system is controllable, though STLC only at the origin where g0g_0 vanishes. The library returns STLA by the LARC and [0,−0.5][0, -0.5] for the bracket. The robotics case: energy-conserving drift on a compact configuration space is WPPS by Poincaré recurrence — a frictionless Reach on the horizontal Workbench (Exercise 1), a satellite on SO(3)SO(3) with a single body-fixed torque.

Second-order systems: the symmetric product

A simple mechanical control system is Chapter 17's standard form without potential terms, M(q)q¨+C(q,q˙)q˙=T(q)uM(q)\ddot q + C(q, \dot q)\dot q = T(q)u, so that with Yi(q)Y_i(q) the columns of M−1(q)T(q)M^{-1}(q)T(q),

q¨=−M−1(q)C(q,q˙)q˙+∑i=1mYi(q) ui.\ddot q = -M^{-1}(q)C(q, \dot q)\dot q + \sum_{i=1}^m \htmlClass{term-robot}{Y_i(q)}\,u_i .

One can lift this to M=TQM = T\mathcal{Q} with x=(q,q˙)x = (q, \dot q), g0=[q˙; −M−1Cq˙]g_0 = [\dot q;\ -M^{-1}C\dot q], gi=[0; Yi]g_i = [0;\ Y_i] and bracket away — correct, and twice the dimension it needs to be. The acceleration q¨\ddot q is not intrinsic (a free particle in polar coordinates has r¨≠0\ddot r \ne 0); the intrinsic acceleration is ∇q˙q˙=q¨+M−1q˙TΓq˙∈TqQ\nabla_{\dot q}\dot q = \ddot q + M^{-1}\dot q\T\Gamma\dot q \in T_q\mathcal{Q}, the coordinate acceleration with the centripetal term projected out, and the object that does the projecting is the covariant derivative of the kinetic-energy metric,

∇Y1Y2=∂Y2∂q Y1+M−1(q) Y1T Γ(q) Y2,⟨Y1:Y2⟩=∇Y1Y2+∇Y2Y1.\nabla_{Y_1}Y_2 = \frac{\partial Y_2}{\partial q}\,Y_1 + M^{-1}(q)\,\htmlClass{term-cobstacle}{Y_1\T\,\Gamma(q)\,Y_2}, \qquad \langle Y_1 : Y_2\rangle = \nabla_{Y_1}Y_2 + \nabla_{Y_2}Y_1 .

Γ\Gamma are Chapter 17's Christoffel symbols in Choset's convention (no M−1M^{-1} folded in; the amber term is the velocity-product form (Y1TΓY2)i=∑jkΓjkiY1,jY2,k(Y_1\T\Gamma Y_2)_i = \sum_{jk}\Gamma^i_{jk}Y_{1,j}Y_{2,k}). The equations of motion become ∇q˙q˙=∑Yiui\nabla_{\dot q}\dot q = \sum Y_i u_i — Newton's a=M−1fa = M^{-1}f with the right aa — and unforced motions are geodesics.

DerivationWhy the symmetric product halves the computation

Step 1 — the intrinsic acceleration. On S1⊂R2S^1 \subset \mathbb{R}^2 a point mass at angle θ\theta has q¨=θ¨[−sin⁡θ,cos⁡θ]⊤+θ˙2[−cos⁡θ,−sin⁡θ]⊤\ddot q = \ddot\theta[-\sin\theta, \cos\theta]^\top + \dot\theta^2[-\cos\theta, -\sin\theta]^\top. Only the θ¨\ddot\theta term is visible to an observer confined to the circle; the θ˙2\dot\theta^2 term keeps the mass on it. Subtracting the centripetal term is what M−1q˙TΓq˙M^{-1}\dot q\T\Gamma\dot q does in general coordinates.

Step 2 — the connection in coordinates. For a metric ⟨v1,v2⟩=v1TMv2\langle v_1, v_2\rangle = v_1\T M v_2 the Levi-Civita connection is ∇Y1Y2=∂Y2∂qY1+M−1Y1TΓY2\nabla_{Y_1}Y_2 = \frac{\partial Y_2}{\partial q}Y_1 + M^{-1}Y_1\T\Gamma Y_2, with the Christoffel symbols of Chapter 17's equation (10.9). Euclidean metric: Γ=0\Gamma = 0 and ∇Y1Y2\nabla_{Y_1}Y_2 is the directional derivative.

Step 3 — block-differentiate on TQT\mathcal{Q}. With g0=[q˙; −M−1q˙TΓq˙]g_0 = [\dot q;\ -M^{-1}\dot q\T\Gamma\dot q] and gi=[0; Yi(q)]g_i = [0;\ Y_i(q)], the Jacobian of gig_i has only a lower-left block ∂Yi/∂q\partial Y_i/\partial q, acting on the upper half of its argument — which is zero for every gjg_j, so [gi,gj]=0[g_i, g_j] = 0. For [g0,gi][g_0, g_i] the upper-right block of ∂g0/∂x\partial g_0/\partial x (the identity) hits YiY_i and gives the −Yi-Y_i in the configuration slot; the velocity slot is linear in q˙\dot q and vanishes at rest. For [gi,[g0,gj]][g_i, [g_0, g_j]] the velocity-product's second derivative in q˙\dot q survives at rest and is exactly M−1(YiTΓYj+YjTΓYi)M^{-1}(Y_i\T\Gamma Y_j + Y_j\T\Gamma Y_i), while the two ∂Y/∂q\partial Y/\partial q terms assemble the rest of ⟨Yi:Yj⟩\langle Y_i : Y_j\rangle.

Step 4 — the reading. Sym(Y)(q)\mathrm{Sym}(\mathcal{Y})(q) is the set of velocity directions reachable from rest; Lie(Sym(Y))(q)\mathrm{Lie}(\mathrm{Sym}(\mathcal{Y}))(q) the set of configuration directions. Sussmann's good/bad bookkeeping carries over verbatim because the lift makes g0g_0 appear once in every symmetric product.

Step 5 — in the library. liftToStateSpace builds the six-dimensional fields for the planar body with thrusters, and a check confirms the three identities numerically to 10−1210^{-12} against symmetricProduct on Q\mathcal{Q}.

The planar body with thrusters (Choset Example 12.4.3) — and Reach's free third link. Unit mass and inertia, Γ=0\Gamma = 0, Y1=[cos⁡q3,sin⁡q3,0]⊤Y_1 = [\cos q_3, \sin q_3, 0]^\top (thrust through the centre of mass), Y2=[−sin⁡q3,cos⁡q3,−d]⊤Y_2 = [-\sin q_3, \cos q_3, -d]^\top (the offset thruster). Then ⟨Y1:Y2⟩=[dsin⁡q3,−dcos⁡q3,0]⊤\langle Y_1 : Y_2\rangle = [d\sin q_3, -d\cos q_3, 0]^\top, rank 3: STLA from rest. The bad products are ⟨Y1:Y1⟩=0\langle Y_1 : Y_1\rangle = 0 and ⟨Y2:Y2⟩=2∇Y2Y2=2d Y1\langle Y_2 : Y_2\rangle = 2\nabla_{Y_2}Y_2 = 2d\,Y_1 — Choset prints dY1dY_1; the factor is immaterial — neutralized by Y1Y_1: STLC at rest, confirming the Lie-bracket computation of Example 12.3.4, where det⁡[g1⋯g6]=d4\det[g_1 \cdots g_6] = d^4. A single offset thruster gives rank(Y2 ⟨Y2:Y2⟩ ⟨Y2:⟨Y2:Y2⟩⟩)=3(Y_2\ \langle Y_2 : Y_2\rangle\ \langle Y_2 : \langle Y_2 : Y_2\rangle\rangle) = 3, STLA, with nothing to neutralize the bad products: Sussmann is silent, and the system is in fact controllable but not STLC (Choset Figure 12.14). Section "Putting it together" asks whether this body is Reach's third link when the third motor is dead; the honest answer is "kinematically, yes; dynamically, not quite".

The hopper (Example 12.4.4). M=diag(I,mq32,m)M = \mathrm{diag}(I, mq_3^2, m), Γ232=Γ322=mq3\Gamma^2_{23} = \Gamma^2_{32} = mq_3, Γ223=−mq3\Gamma^3_{22} = -mq_3, Y1=[1/I,−1/(mq32),0]⊤Y_1 = [1/I, -1/(mq_3^2), 0]^\top, Y2=[0,0,1/m]⊤Y_2 = [0, 0, 1/m]^\top. Angular momentum is conserved, so velocities fill at most two dimensions: ⟨Y1:Y1⟩=[0,0,−2/(m2q33)]⊤∈span(Y2)\langle Y_1 : Y_1\rangle = [0, 0, -2/(m^2q_3^3)]^\top \in \mathrm{span}(Y_2), the other products vanish, and Sym\mathrm{Sym} is two-dimensional (not STLA) while [Y1,Y2]=[0,−2/(m2q33),0]⊤[Y_1, Y_2] = [0, -2/(m^2q_3^3), 0]^\top completes Lie(Sym)\mathrm{Lie}(\mathrm{Sym}): STLEC and equilibrium controllable. The library reports exactly this, and that Sym(Y)=span(Y)\mathrm{Sym}(\mathcal{Y}) = \mathrm{span}(\mathcal{Y}) — the hopper is maximally reducible to a kinematic system, Chapter 21's Theorem 12.4.5.

Nonholonomic constraints through the projection

DerivationThe knife-edge: Rusty with mass, force and torque

Step 1 — the projection. M=diag(m,m,I)M = \mathrm{diag}(m, m, I), A=[sin⁡q3,−cos⁡q3,0]A = [\sin q_3, -\cos q_3, 0] (no sideways velocity), so PP has the upper block [cos⁡2q3sin⁡q3cos⁡q3sin⁡q3cos⁡q3sin⁡2q3]\begin{bmatrix}\cos^2 q_3 & \sin q_3\cos q_3\\ \sin q_3\cos q_3 & \sin^2 q_3\end{bmatrix} and a 11 in the corner: it projects planar velocity onto the heading.

Step 2 — the inputs. A force along q1q_1 and a torque about q3q_3: Y1=e1/mY_1 = e_1/m, Y2=e3/IY_2 = e_3/I, hence Y~1=[cos⁡2q3,sin⁡q3cos⁡q3,0]⊤/m\tilde Y_1 = [\cos^2 q_3, \sin q_3\cos q_3, 0]^\top/m — the forward force projected onto the heading — and Y~2=e3/I\tilde Y_2 = e_3/I.

Step 3 — the connection. Γ=0\Gamma = 0, so ∇Y~2Y~1=∂Y~1∂q3⋅1I=1mI[−sin⁡2q3,cos⁡2q3,0]⊤\nabla_{\tilde Y_2}\tilde Y_1 = \frac{\partial\tilde Y_1}{\partial q_3}\cdot\frac1I = \frac{1}{mI}[-\sin 2q_3, \cos 2q_3, 0]^\top and ∇Y~1Y~2=0\nabla_{\tilde Y_1}\tilde Y_2 = 0; projecting with PP gives ⟨Y~1:Y~2⟩=1mI[−sin⁡q3cos⁡q3,−sin⁡2q3,0]⊤=−tan⁡q3IY~1\langle\tilde Y_1 : \tilde Y_2\rangle = \frac{1}{mI}[-\sin q_3\cos q_3, -\sin^2 q_3, 0]^\top = -\frac{\tan q_3}{I}\tilde Y_1. Both self products vanish. So Sym(Y~)=span(Y~)=D\mathrm{Sym}(\tilde{\mathcal{Y}}) = \mathrm{span}(\tilde{\mathcal{Y}}) = \mathcal{D}: the knife-edge is maximally reducible — it is "secretly kinematic", the unicycle with velocity inputs, which is why Chapter 21 can steer it with Chapter 20's kinematic tools.

Step 4 — configurations. [Y~1,Y~2]=1mI[sin⁡2q3,−cos⁡2q3,0]⊤[\tilde Y_1, \tilde Y_2] = \frac{1}{mI}[\sin 2q_3, -\cos 2q_3, 0]^\top and det⁡[Y~1 Y~2 [Y~1,Y~2]]=cos⁡2q3/(m2I2)\det[\tilde Y_1\ \tilde Y_2\ [\tilde Y_1, \tilde Y_2]] = \cos^2 q_3/(m^2I^2), which vanishes at q3=±π/2q_3 = \pm\pi/2 — there the projected force Y~1\tilde Y_1 itself vanishes, and the distribution is not regular. One more bracket, [Y~2,[Y~1,Y~2]]=2mI2[cos⁡2q3,sin⁡2q3,0]⊤[\tilde Y_2, [\tilde Y_1, \tilde Y_2]] = \frac{2}{mI^2}[\cos 2q_3, \sin 2q_3, 0]^\top, gives det⁡[Y~2 [Y~1,Y~2] [Y~2,[Y~1,Y~2]]]=2/(m2I4)\det[\tilde Y_2\ [\tilde Y_1, \tilde Y_2]\ [\tilde Y_2, [\tilde Y_1, \tilde Y_2]]] = 2/(m^2I^4): STLCA and STLEC everywhere by Theorem 12.4.2.

In the library (with m=2m = 2, I=0.5I = 0.5 so the numbers are not all ones): every field above matches Choset's closed form to 10−910^{-9}, det⁡2=0.584984\det_2 = 0.584984 at q3=0.7q_3 = 0.7 against the formula's 0.5849840.584984, det⁡3=8.000000\det_3 = 8.000000; larc on the reduction {Y~1,Y~2}\{\tilde Y_1, \tilde Y_2\} at q3=π/2q_3 = \pi/2 returns rank 2 and "undecided" at degree two and STLC at degree three — the LARC refusing to certify the constrained system until it has the bracket that actually moves it.

The micro-example, by hand

Unicycle at x3=π/6x_3 = \pi/6. g1=[cos⁡x3,sin⁡x3,0]⊤=[0.8660,0.5,0]⊤g_1 = [\cos x_3, \sin x_3, 0]^\top = [0.8660, 0.5, 0]^\top, g2=e3g_2 = e_3. ∂g2/∂x=0\partial g_2/\partial x = 0, and ∂g1/∂x\partial g_1/\partial x has one nonzero column, ∂g1/∂x3=[−sin⁡x3,cos⁡x3,0]⊤\partial g_1/\partial x_3 = [-\sin x_3, \cos x_3, 0]^\top, so

[g1,g2]=−∂g1∂xg2=[sin⁡x3−cos⁡x30]=[0.5−0.8660250],det⁡[g1 g2 [g1,g2]]=det⁡[cos⁡x30sin⁡x3sin⁡x30−cos⁡x3010]=1.\lie{g_1}{g_2} = -\frac{\partial g_1}{\partial x}g_2 = \begin{bmatrix}\sin x_3\\ -\cos x_3\\ 0\end{bmatrix} = \begin{bmatrix}0.5\\ -0.866025\\ 0\end{bmatrix}, \qquad \det[g_1\ g_2\ \lie{g_1}{g_2}] = \det\begin{bmatrix}\cos x_3 & 0 & \sin x_3\\ \sin x_3 & 0 & -\cos x_3\\ 0 & 1 & 0\end{bmatrix} = 1 .

The exact loop with ϵ=0.1\epsilon = 0.1 moves [0.005424,−0.008396,0][0.005424, -0.008396, 0] against ϵ2[g1,g2]=[0.005,−0.008660,0]\epsilon^2[g_1, g_2] = [0.005, -0.008660, 0]; the gap, 5.0×10−45.0 \times 10^{-4}, is O(ϵ3)O(\epsilon^3) — half a cube is 5×10−45 \times 10^{-4} exactly.

Hitch's car (Choset eq. 12.34), q=(x,y,ϕ,θ)q = (x, y, \phi, \theta), L=1L = 1. g1=[cos⁡θ,sin⁡θ,0,1Ltan⁡ϕ]⊤g_1 = [\cos\theta, \sin\theta, 0, \tfrac1L\tan\phi]^\top, g2=e3g_2 = e_3. Then g3=[g1,g2]=−∂g1/∂ϕ=[0,0,0,−sec⁡2ϕ/L]⊤g_3 = [g_1, g_2] = -\partial g_1/\partial\phi = [0, 0, 0, -\sec^2\phi/L]^\top, and g4=[g1,g3]=−∂g1∂θ g3,θ=sec⁡2ϕL[−sin⁡θ,cos⁡θ,0,0]⊤g_4 = [g_1, g_3] = -\frac{\partial g_1}{\partial\theta}\,g_{3,\theta} = \frac{\sec^2\phi}{L}[-\sin\theta, \cos\theta, 0, 0]^\top, with det⁡[g1 g2 g3 g4]=−sec⁡4ϕ/L2\det[g_1\ g_2\ g_3\ g_4] = -\sec^4\phi/L^2. At q=0q = 0 the columns are e1,e3,−e4,e2e_1, e_3, -e_4, e_2 and the determinant is −1-1; the filtration climbs (2,3,4)(2, 3, 4) and the car is STLC by symmetry. At a generic configuration with L=2.6L = 2.6 the finite-difference g3,g4g_3, g_4 agree with these formulas to 10−1410^{-14}.

With the trailer, state (x,y,ϕ,θ,ψ)(x, y, \phi, \theta, \psi) and ψ˙=(v/d)sin⁡(θ−ψ)\dot\psi = (v/d)\sin(\theta - \psi), the ladder is (2,3,4,5)(2, 3, 4, 5): one more degree for one more coordinate, STLC again. The library finds the same ladder at hitch angle θ−ψ=π/2\theta - \psi = \pi/2 — the trailer's Lie algebra is full rank everywhere, as Laumond proved; the jackknife of Chapter 23 is not a loss of controllability, and the chart that does go singular at ±π/2\pm\pi/2 is Chapter 21's chained form.

The algorithm

Choset numbers none of these; the names match the Rust module.

Algorithmlie_bracket(g₁, g₂, x)CostO(n²) with analytic Jacobians; O(n²) field evaluations by differences
In
two vector fields with Jacobians (analytic, or fourth-order central differences at h = 10⁻³), a point x
Out
[g₁, g₂](x) = (∂g₂/∂x) g₁ − (∂g₁/∂x) g₂
  1. J1←∂g1/∂x (x)J_1 \leftarrow \partial g_1/\partial x\,(x), J2←∂g2/∂x (x)J_2 \leftarrow \partial g_2/\partial x\,(x) — analytic if the field has one, else 112h[f(x−2h)−8f(x−h)+8f(x+h)−f(x+2h)]\frac{1}{12h}[f(x - 2h) - 8f(x - h) + 8f(x + h) - f(x + 2h)] per column
  2. return J2 g1(x)−J1 g2(x)J_2\,g_1(x) - J_1\,g_2(x)
  3. as a field: the closure x↦x \mapsto step 2, whose own Jacobian falls back to differences of an exactly evaluated bracket — one difference level per nesting depth
Algorithmfiltration(𝒢, x, max_deg, tol) — Chow's testCost(m+1)^k products at degree k before pruning; rank by modified Gram–Schmidt
In
generators g₀ (if drift), g₁ … g_m; the test point; the highest degree; a relative rank tolerance
Out
dims = (dim 𝒟₁, dim 𝒟₂, …), every product with its generator counts and good/bad tag, a greedy basis, terminated / stalled flags
  1. G1←{g0,g1,…,gm}\mathcal{G}_1 \leftarrow \{g_0, g_1, \dots, g_m\} with counts eie_i; dims←[rank{g(x):g∈G1}]\mathrm{dims} \leftarrow [\mathrm{rank}\{g(x) : g \in \mathcal{G}_1\}]
  2. for deg⁡=2,…,max_deg\deg = 2, \dots, \text{max\_deg}: for each gj∈G1g_j \in \mathcal{G}_1 and each hh new at the previous degree, form [gj,h][g_j, h] (at degree 2 only j<kj < k); drop it if it vanishes at xx and at four probe points nearby; record counts =counts(h)+ej= \mathrm{counts}(h) + e_j and bad   ⟺  \iff counts0\mathrm{counts}_0 odd and all other counts even
  3. append rank\mathrm{rank} of all values so far to dims; stop early if the rank is nn or nothing new was formed (closure certain); otherwise continue — a stall is not a stop for a non-regular filtration
  4. return dims, products, a greedy independent subset, and stalled = trailing degrees without growth
Algorithmlarc(sys, x, max_deg) / sussmann_stlc(sys, x, max_deg)Costone filtration, plus one least-squares projection per bad bracket
In
a control-affine system (drift or null, controls, control-set class), a point, a degree budget
Out
Verdict ∈ { stlc-symmetric, stlc-sussmann, stla, confined(dim), undecided } with the filtration and, for Sussmann, every bad bracket's neutralization residual
  1. F←F \leftarrow filtration({g0,g1,… },x)(\{g_0, g_1, \dots\}, x)
  2. larc: if rank F=n\mathrm{rank}\,F = n: driftless and U∈U±U \in \mathcal{U}^\pm ⇒ stlc-symmetric, else stla; if FF terminated below nn or stalled two degrees ⇒ confined(rank); else undecided
  3. sussmann: require g0(x)=0g_0(x) = 0 and U∈U±U \in \mathcal{U}^\pm, else undecided
  4. k←k \leftarrow the least degree at which the good products alone have rank nn (none ⇒ stla if the LARC holds)
  5. for every bad product of degree j≤kj \le k: residual ←\leftarrow relative least-squares residual against the good products of degree <j< j; neutralized iff residual <10−6< 10^{-6}
  6. all neutralized ⇒ stlc-sussmann at degree kk; else stla with the offending brackets named
Algorithmlewis_murray(∇, 𝒴, q, max_deg, lie_deg, target)Costeach symmetric product is one Jacobian–vector product and one Christoffel form, O(n_𝒬³); then one Lie filtration of a basis of Sym
In
a connection (kinetic, or constrained P∇), input fields Y₁ … Y_m on 𝒬, a configuration, degree budgets, the velocity dimension to fill (n_𝒬, or n_𝒬 − k under constraints)
Out
MechVerdict ∈ { stlc, stla, stlec, stlca, confined, undecided }, dim Sym, dim Lie(Sym), maximally-reducible flag, bad products with residuals
  1. Sym←\mathrm{Sym} \leftarrow the recursion S1=YS_1 = \mathcal{Y}, Si+1=Si∪{⟨Yj:h⟩:Yj∈S1, h new in Si}S_{i+1} = S_i \cup \{\langle Y_j : h\rangle : Y_j \in S_1,\ h \text{ new in } S_i\} with j≤kj \le k at degree 2, counts added, bad iff all counts even; dims recorded at qq
  2. maximally reducible   ⟺  \iff dim⁡Sym(q)=dim⁡span(Y)(q)\dim\mathrm{Sym}(q) = \dim\mathrm{span}(\mathcal{Y})(q) (Theorem 12.4.5, for Chapter 21)
  3. neutralized   ⟺  \iff every bad product's residual against lower-degree good ones is <10−6< 10^{-6}
  4. if target =nQ= n_\mathcal{Q} and dim⁡Sym=nQ\dim\mathrm{Sym} = n_\mathcal{Q}: neutralized ⇒ stlc, else stla (Theorem 12.4.1)
  5. else L←L \leftarrow filtration of a basis of Sym (as fields) to lie_deg; dim⁡L=nQ\dim L = n_\mathcal{Q} and neutralized ⇒ stlec (and STLCC); dim⁡L=nQ\dim L = n_\mathcal{Q} alone ⇒ stlca; closed below ⇒ confined; else undecided (Theorem 12.4.2)

Implementation in Rust

The nonholonomic crate is introduced here; Chapter 21 adds steer/, lattice/, reduction/ and car_grid.rs to it. Brackets, filtrations and symmetric products are hand-rolled per the book's policy; nalgebra supplies the fixed-size vectors and the rank. The TypeScript port in web/lib/nonholonomic/ is the code behind every widget on this page.

crates/nonholonomic/src/field.rs
use nalgebra::{SMatrix, SVector};

/// A smooth vector field on a chart of an N-dimensional state manifold.
///
/// Brackets need Jacobians, so the trait carries one. The default is a
/// fourth-order central difference with a deliberately *large* step: a nested
/// bracket differentiates a bracket, and a difference of a difference loses
/// half its digits per level if h is tiny. Concrete systems override it with
/// the analytic Jacobian, which is what makes degree-4 products trustworthy.
pub trait VectorField<const N: usize> {
    fn eval(&self, x: &SVector<f64, N>) -> SVector<f64, N>;

    fn jacobian(&self, x: &SVector<f64, N>) -> SMatrix<f64, N, N> {
        central_difference(|y| self.eval(y), x, 1e-3)
    }
}

/// A borrowed or boxed field is still a field, so `Bracket(&g1, &g2)` needs no clones
/// and the filtration can bracket `Box<dyn VectorField<N>>` generators.
impl<const N: usize, F: VectorField<N> + ?Sized> VectorField<N> for &F {
    fn eval(&self, x: &SVector<f64, N>) -> SVector<f64, N> { (**self).eval(x) }
    fn jacobian(&self, x: &SVector<f64, N>) -> SMatrix<f64, N, N> { (**self).jacobian(x) }
}
impl<const N: usize, F: VectorField<N> + ?Sized> VectorField<N> for Box<F> {
    fn eval(&self, x: &SVector<f64, N>) -> SVector<f64, N> { (**self).eval(x) }
    fn jacobian(&self, x: &SVector<f64, N>) -> SMatrix<f64, N, N> { (**self).jacobian(x) }
}

/// ∂f/∂x by the 5-point stencil (f(x−2h) − 8f(x−h) + 8f(x+h) − f(x+2h)) / 12h, per column.
pub fn central_difference<const N: usize>(
    f: impl Fn(&SVector<f64, N>) -> SVector<f64, N>,
    x: &SVector<f64, N>,
    h: f64,
) -> SMatrix<f64, N, N> {
    let mut j = SMatrix::<f64, N, N>::zeros();
    for k in 0..N {
        let mut e = SVector::<f64, N>::zeros();
        e[k] = h;
        let col = (f(&(x - 2.0 * e)) - 8.0 * f(&(x - e)) + 8.0 * f(&(x + e)) - f(&(x + 2.0 * e))) / (12.0 * h);
        j.set_column(k, &col);
    }
    j
}

/// [g1, g2] = (∂g2/∂x) g1 − (∂g1/∂x) g2 — Choset eq. (12.5), same sign convention,
/// so the loop g1 → g2 → −g1 → −g2 moves by +ε²[g1, g2]. A `Bracket` is itself a
/// `VectorField`, so brackets nest: `Bracket(g1, Bracket(g1, g2))` is the car's g4.
pub struct Bracket<F, G>(pub F, pub G);

impl<const N: usize, F: VectorField<N>, G: VectorField<N>> VectorField<N> for Bracket<F, G> {
    fn eval(&self, x: &SVector<f64, N>) -> SVector<f64, N> {
        self.1.jacobian(x) * self.0.eval(x) - self.0.jacobian(x) * self.1.eval(x)
    }
}

/// Choset's unicycle (Example 12.1.3): drive and spin, with analytic Jacobians.
pub struct Drive;
pub struct Spin;

impl VectorField<3> for Drive {
    fn eval(&self, x: &SVector<f64, 3>) -> SVector<f64, 3> {
        SVector::<f64, 3>::new(x[2].cos(), x[2].sin(), 0.0)
    }
    fn jacobian(&self, x: &SVector<f64, 3>) -> SMatrix<f64, 3, 3> {
        let mut j = SMatrix::<f64, 3, 3>::zeros();
        j[(0, 2)] = -x[2].sin();
        j[(1, 2)] = x[2].cos();
        j
    }
}

impl VectorField<3> for Spin {
    fn eval(&self, _x: &SVector<f64, 3>) -> SVector<f64, 3> {
        SVector::<f64, 3>::new(0.0, 0.0, 1.0)
    }
    fn jacobian(&self, _x: &SVector<f64, 3>) -> SMatrix<f64, 3, 3> {
        SMatrix::<f64, 3, 3>::zeros()
    }
}

/// The four-flow loop of eq. (12.3) by RK4, returning x(4ε) − x₀ and the
/// prediction ε²[g1, g2](x₀); their difference is the O(ε³) remainder.
pub fn four_flow_loop<const N: usize>(
    g1: &impl VectorField<N>,
    g2: &impl VectorField<N>,
    x0: &SVector<f64, N>,
    eps: f64,
) -> (SVector<f64, N>, SVector<f64, N>) {
    let mut x = *x0;
    x = flow(g1, &x, eps);
    x = flow(g2, &x, eps);
    x = flow(g1, &x, -eps);
    x = flow(g2, &x, -eps);
    (x - x0, eps * eps * Bracket(g1, g2).eval(x0))
}

The filtration follows Choset's recursion literally, with the generator counts that make Sussmann's tagging a counting exercise.

crates/nonholonomic/src/filtration.rs
use nalgebra::SVector;

/// A Lie product with its provenance: which generators, how many times.
pub struct LieProduct<const N: usize> {
    pub field: Box<dyn VectorField<N>>,
    pub degree: usize,
    /// counts[i] = occurrences of generator i; index 0 is the drift when there is one.
    pub counts: Vec<usize>,
    pub value: SVector<f64, N>,
    /// Sussmann: bad iff the drift appears an odd number of times and every control an even number.
    pub bad: bool,
}

pub struct Filtration<const N: usize> {
    /// dim D₁, dim D₂, … — (2, 3, 4) for the car, (2, 3, 4, 5) with the trailer.
    pub dims: Vec<usize>,
    pub products: Vec<LieProduct<N>>,
    /// Full rank, or nothing left to bracket: the closure is certain.
    pub terminated: bool,
    /// Trailing degrees that added no dimension. A stall is reported, never used to stop:
    /// a non-regular filtration may pause and grow again (the knife-edge at q₃ = ±π/2).
    pub stalled: usize,
}

pub fn filtration<const N: usize>(
    fields: &[Box<dyn VectorField<N>>],
    x: &SVector<f64, N>,
    max_deg: usize,
    drift_index: Option<usize>,
    tol: f64,
) -> Filtration<N> {
    let m = fields.len();
    let mut products: Vec<LieProduct<N>> = (0..m)
        .map(|i| {
            let mut counts = vec![0; m];
            counts[i] = 1;
            LieProduct { field: fields[i].clone_box(), degree: 1, counts: counts.clone(),
                         value: fields[i].eval(x), bad: tag_bad(&counts, drift_index) }
        })
        .collect();
    let mut dims = vec![rank(products.iter().map(|p| p.value), tol)];
    let mut frontier: Vec<usize> = (0..m).collect();
    let mut terminated = false;

    for deg in 2..=max_deg {
        let mut fresh = Vec::new();
        for j in 0..m {
            for &h in &frontier {
                // Degree 2: [g_j, g_k] with j < k only — [g, g] = 0 and antisymmetry.
                if deg == 2 && j >= products[h].counts.iter().position(|&c| c == 1).unwrap() { continue; }
                let g = Bracket(fields[j].clone_box(), products[h].field.clone_box());
                if vanishes_near(&g, x) { continue; }          // identically zero, not merely at x
                let mut counts = products[h].counts.clone();
                counts[j] += 1;
                let bad = tag_bad(&counts, drift_index);
                fresh.push(LieProduct { value: g.eval(x), field: Box::new(g), degree: deg, counts, bad });
            }
        }
        let start = products.len();
        products.extend(fresh);
        frontier = (start..products.len()).collect();
        dims.push(rank(products.iter().map(|p| p.value), tol));
        if *dims.last().unwrap() == N || frontier.is_empty() { terminated = true; break; }
    }
    let stalled = dims.windows(2).rev().take_while(|w| w[0] == w[1]).count();
    Filtration { dims, products, terminated, stalled }
}

pub enum Verdict { StlcSymmetric { degree: usize }, StlcSussmann { degree: usize, neutralized: Vec<String> },
                   Stla { degree: usize }, Confined { dim: usize }, Undecided(String) }

/// Chow / LARC (Theorem 12.3.1) with the symmetry shortcut.
pub fn larc<const N: usize>(sys: &ControlAffine<N>, x: &SVector<f64, N>, max_deg: usize) -> Verdict {
    let f = filtration(&sys.generators(), x, max_deg, sys.drift_index(), 1e-7);
    let rank = *f.dims.last().unwrap();
    let degree = f.dims.iter().position(|&d| d == N).map_or(0, |i| i + 1);
    match (rank == N, sys.drift.is_none() && sys.control_set == ControlSet::PlusMinus) {
        (true, true) => Verdict::StlcSymmetric { degree },
        (true, false) => Verdict::Stla { degree },
        (false, _) if f.terminated || f.stalled >= 2 => Verdict::Confined { dim: rank },
        _ => Verdict::Undecided(format!("rank {rank} < {N} after degree {max_deg}")),
    }
}

/// Sussmann (Theorem 12.3.3) at an equilibrium: good brackets span, bad ones are
/// neutralized by lower-degree good ones (relative least-squares residual < 1e-6).
pub fn sussmann_stlc<const N: usize>(sys: &ControlAffine<N>, x: &SVector<f64, N>, max_deg: usize) -> Verdict {
    let Some(g0) = &sys.drift else { return larc(sys, x, max_deg) };
    if g0.eval(x).norm() > 1e-8 { return Verdict::Undecided("g0(x) ≠ 0: only equilibria".into()); }
    let f = filtration(&sys.generators(), x, max_deg, Some(0), 1e-7);
    let good_rank_at = |deg| rank(f.products.iter().filter(|p| !p.bad && p.degree <= deg).map(|p| p.value), 1e-7);
    let Some(k) = (1..=f.dims.len()).find(|&d| good_rank_at(d) == N) else {
        return Verdict::Stla { degree: f.dims.len() };
    };
    let mut neutralized = Vec::new();
    for p in f.products.iter().filter(|p| p.bad && p.degree <= k) {
        let lower: Vec<_> = f.products.iter().filter(|q| !q.bad && q.degree < p.degree).map(|q| q.value).collect();
        if relative_residual(&p.value, &lower) > 1e-6 { return Verdict::Stla { degree: k }; }
        neutralized.push(p.label());
    }
    Verdict::StlcSussmann { degree: k, neutralized }
}

The mechanical half imports Chapter 17's Model for MM, Γ\Gamma and the projection PP, and differentiates only the input fields.

crates/nonholonomic/src/mechanical.rs
use dynamics::{Model, Pfaffian};
use nalgebra::{SMatrix, SVector};

/// ∇_{Y1} Y2 = (∂Y2/∂q) Y1 + M⁻¹ Y1ᵀ Γ Y2, Choset's convention for Γ (no M⁻¹ inside).
pub fn covariant<const Q: usize>(
    y1: &dyn VectorField<Q>, y2: &dyn VectorField<Q>, model: &Model<Q>, q: &SVector<f64, Q>,
) -> SVector<f64, Q> {
    let gamma = model.christoffel(q);                       // Q slices of Q×Q
    let (v1, v2) = (y1.eval(q), y2.eval(q));
    let mut form = SVector::<f64, Q>::zeros();
    for i in 0..Q { form[i] = (v1.transpose() * gamma[i] * v2)[(0, 0)]; }
    y2.jacobian(q) * v1 + model.inertia(q).try_inverse().unwrap() * form
}

/// ⟨Y1 : Y2⟩ = ∇_{Y1}Y2 + ∇_{Y2}Y1; with a Pfaffian constraint, P ∇ in place of ∇ (eq. 12.22).
pub fn symmetric_product<const Q: usize>(
    y1: &dyn VectorField<Q>, y2: &dyn VectorField<Q>, model: &Model<Q>,
    constraint: Option<&Pfaffian<Q>>, q: &SVector<f64, Q>,
) -> SVector<f64, Q> {
    let s = covariant(y1, y2, model, q) + covariant(y2, y1, model, q);
    match constraint {
        None => s,
        Some(c) => dynamics::projection_p(&model.inertia(q), &c.a(q)) * s,
    }
}

/// Ỹ_i = P Y_i — the constrained inputs of §12.4.3.
pub fn constrained_inputs<const Q: usize>(
    inputs: &[Box<dyn VectorField<Q>>], constraint: &Pfaffian<Q>, model: &Model<Q>,
) -> Vec<Box<dyn VectorField<Q>>> {
    inputs.iter().map(|y| Box::new(Projected { y: y.clone_box(), constraint: constraint.clone(), model: model.clone() })
                       as Box<dyn VectorField<Q>>).collect()
}

pub enum MechVerdict { Stlc, Stla, Stlec, Stlca, Confined { dim: usize }, Undecided }

/// Theorems 12.4.1–12.4.2 from rest. `target` is n_Q, or n_Q − k under k constraints.
pub fn lewis_murray<const Q: usize>(
    inputs: &[Box<dyn VectorField<Q>>], model: &Model<Q>, constraint: Option<&Pfaffian<Q>>,
    q: &SVector<f64, Q>, max_deg: usize, lie_deg: usize, target: usize,
) -> MechVerdict {
    let sym = sym_closure(inputs, model, constraint, q, max_deg);  // same recursion, ⟨:⟩ for [,], j ≤ k at degree 2
    let neutralized = sym.products.iter().filter(|p| p.bad).all(|p| {
        let lower: Vec<_> = sym.products.iter().filter(|s| !s.bad && s.degree < p.degree).map(|s| s.value).collect();
        relative_residual(&p.value, &lower) < 1e-6
    });
    if target == Q && sym.rank == Q {
        return if neutralized { MechVerdict::Stlc } else { MechVerdict::Stla };
    }
    let lie = filtration(&sym.basis_fields(), q, lie_deg, None, 1e-7);
    match (*lie.dims.last().unwrap() == Q, neutralized, lie.terminated) {
        (true, true, _) => MechVerdict::Stlec,
        (true, false, _) => MechVerdict::Stlca,
        (false, _, true) => MechVerdict::Confined { dim: *lie.dims.last().unwrap() },
        _ => MechVerdict::Undecided,
    }
}

The worked example, printed

cargo run --example chow_car -p nonholonomic prints the micro-example and the lab's verdicts. Every line is reproduced by the TypeScript checks (npm run check, the nonholonomic: block) to the digits shown.

unicycle at x3 = pi/6:
  [g1, g2]               = [0.500000, -0.866025, 0.000000]      (hand formula: identical)
  loop residue, eps = 0.1 = [0.005424, -0.008396, 0.000000]
  eps^2 [g1, g2]          = [0.005000, -0.008660, 0.000000]      gap 5.00e-4 = O(eps^3)
  det[g1 g2 [g1,g2]]      = 1.000000
  log-log slope of |residue| over eps = 0.4 ... 0.025:  1.993  1.998  2.000  2.000

Hitch (eq. 12.34), L = 1, q = 0:
  columns  e1, e3, -e4, e2      det = -1.000000      dims = [2, 3, 4]      Verdict::StlcSymmetric
  generic q, L = 2.6:  |g3 - hand| = 0.0e+0   |g4 - hand| = 2.3e-15   det = -0.189977 = -sec^4(phi)/L^2
  with trailer (L = d = 1):  dims = [2, 3, 4, 5] at q = 0 and at hitch angle pi/2 — regular everywhere

Example 12.1.7:  interior StlcSymmetric;  half-plane Confined { dim: 2 } dims [2,2,2,2,2];  axis Confined { dim: 1 }

PBWT, d = 1.3, a_g = 0:  det[g1..g6] = 2.856100 = d^4;  at rest StlcSussmann, [g2,[g0,g2]] = 2d g1 neutralized (1.4e-15)
  u1 only: rank 2 (Confined);  u2 only: rank 6 at degree 6, det of Choset's six columns = -130.5169 = -16 d^8, Stla
  symmetric product: <Y1:Y2> = [d sin q3, -d cos q3, 0];  <Y2:Y2> = 2d Y1;  Lewis-Murray Stlc

knife-edge, m = 2, I = 0.5:  <Y~1:Y~2> = -(tan q3 / I) Y~1;  Sym = span (maximally reducible)
  det2 = 0.584984 = cos^2(q3)/(m^2 I^2) at q3 = 0.7;  det3 = 8.000000 = 2/(m^2 I^4);  Stlec
  reduction LARC at q3 = pi/2:  degree 2 rank 2 (undecided),  degree 3 StlcSymmetric dims [1,2,3]

Reach 3R, u3 = 0, a_g = 0, q = (0.3, 1.1, -0.5):  Sym dims 2 -> 3 (Stla);  bad <Y1:Y1> residual 0.105, <Y2:Y2> 0.048
  -> Lewis-Murray cannot certify STLC; STLKC does the planner's job in Chapter 21

Putting it together

The Integration lab drops the chapter's tests on the lab's three systems.

Hitch, with and without the trailer. larc(carSystem(2.6), q) at every configuration with ∣ϕ∣<γ=0.6|\phi| < \gamma = 0.6 returns STLC with the ladder (2,3,4)(2, 3, 4) — including ϕ=0.58\phi = 0.58 rad, hard against the steering stop, where Choset's remark that a car which can only turn one way reaches every pose becomes a number. With the trailer the ladder is (2,3,4,5)(2, 3, 4, 5) at hitch angle 00, at 0.80.8, and at π/2\pi/2. This is a deviation from the design brief, which expected the ladder to stall at ±π/2\pm\pi/2; the computation does not stall and the literature agrees (the one-trailer system is STLC everywhere). What is singular at θ1=±π/2\theta_1 = \pm\pi/2 is the trailer's velocity vcos⁡θ1v\cos\theta_1 and with it the chained-form coordinate change and the flat-output lift of Chapter 21 — the jackknife is a planning and dynamics failure, not a controllability one, and Chapter 23 will say so.

Reach's 3R with the third motor dead, horizontal Workbench. Choset's §12.5.7 says the free third link "is equivalent to the PBWT in zero gravity, except the thruster forces at the third joint are generated by the actuators at the first two joints". Kinematically that is right, and Chapter 21 drives the link like a car along its two decoupling fields. Dynamically the arm is not the free body: its two input fields Yi=(M−1[e1 e2])⋅iY_i = (M^{-1}[e_1\ e_2])_{\cdot i} carry the arm's inertia, and the Lewis–Murray test at q=(0.3,1.1,−0.5)q = (0.3, 1.1, -0.5) returns dim⁡Sym=3\dim\mathrm{Sym} = 3 (STLA from rest) with the bad products ⟨Y1:Y1⟩\langle Y_1 : Y_1\rangle and ⟨Y2:Y2⟩\langle Y_2 : Y_2\rangle outside span(Y)\mathrm{span}(\mathcal{Y}) — relative residuals 0.1050.105 and 0.0480.048. Sussmann's condition is sufficient, not necessary, so the arm may well be STLC; the test cannot say, and the chapter does not claim it. The design brief's expectation of a printed Stlc is therefore not met, and the honest line in its place is: STLA, with STLKC — hence STLEC — supplied by the kinematic reduction of the next chapter, which is exactly the property the switch-minimizing planner needs.

Rusty with mass, the knife-edge: maximally reducible, so everything Part III did with Rusty's kinematic model was legitimate for the dynamic one too, and STLEC everywhere once the degree-three bracket is admitted.

Which leaves the question this chapter cannot answer and the next one is about: controllable — with what controls? The four-flow loop is a proof, not a plan. Chapter 21 spends the controllability established here six different ways.

Exercises

  1. Foundation exerciseDifficulty 2 of 3Reach's 2R with one motor, on the horizontal Workbench

    Write Reach's 2R dynamics (Chapter 17, ag=0a_g = 0) in the control-affine form on T(T2)T(T^2) with u2=0u_2 = 0: g0=[q˙; −M−1Cq˙]g_0 = [\dot q;\ -M^{-1}C\dot q], g1=[0; M−1e1]g_1 = [0;\ M^{-1}e_1]. Argue that g0g_0 is WPPS from energy conservation on the compact T2T^2, attempt the LARC for Theorem 12.3.5 (the library's liftToStateSpace and larc will do the brackets), and explain why the arm is not controllable with u2∈Ru_2 \in \mathbb{R} but u1=0u_1 = 0.

  2. Foundation exerciseDifficulty 2 of 3The car's ladder, symbolically, and the trailer's extra rung

    Prove Choset's Problem 13 — the car (12.34) is STLC — by exhibiting the ladder (2,3,4)(2, 3, 4): compute g3=[g1,g2]g_3 = [g_1, g_2] and g4=[g1,g3]g_4 = [g_1, g_3] by hand and show det⁡[g1 g2 g3 g4]=−sec⁡4ϕ/L2\det[g_1\ g_2\ g_3\ g_4] = -\sec^4\phi/L^2. Then add the trailer with θ˙1=u1Ltan⁡ϕ−u1d1sin⁡θ1\dot\theta_1 = \tfrac{u_1}{L}\tan\phi - \tfrac{u_1}{d_1}\sin\theta_1 for the hitch angle θ1=θ−ψ\theta_1 = \theta - \psi, show one more degree is needed, and locate the configurations where g5=[g1,g4]g_5 = [g_1, g_4] loses its θ1\theta_1-component.

    det[g₁ g₂ g₃ g₄] for L = 1 at φ = π/4

  3. Conceptual exerciseDifficulty 2 of 3Predict the residue, then its error
    Predict first

    In the Parallel-Parker at ε = 0.2 with the unicycle pair, from heading π/6, the sideways (second) component of the exact residue is compared with ε²[g₁, g₂]₂ = −0.0346. Which is it?

  4. Conceptual exerciseDifficulty 2 of 3How far behind, how soon

    In the Reachable Set Grower switch to the forward-only control set U+\mathcal{U}^+ with both inputs. Find the smallest horizon TT for which a sampled state lies behind the start (x<0x < 0), and relate it to the turning radius (ρ=1\rho = 1 at unit speed and unit turn rate) and to the "controllable, not STLC" rung of the ladder.

  5. Practical exerciseDifficulty 2 of 3Reach's free third link as VectorField<6>

    Implement impl VectorField<6> for the planar body with thrusters of mass mm and inertia II (Choset Problems 14–16) with the analytic Jacobians, build Choset's g3…g6g_3 \dots g_6 with Bracket, and reproduce det⁡[g1⋯g6]=d4\det[g_1 \cdots g_6] = d^4 for m=I=1m = I = 1 in a test. Then show that sussmann_stlc returns StlcSussmann at rest only when ag=0a_g = 0.

  6. Practical exerciseDifficulty 3 of 3A Philip Hall basis, and a symbolic determinant (stretch)

    Replace Choset's recursion in filtration by a Philip Hall basis so that only the independent products of each degree are formed; benchmark bracket evaluations for the car-with-trailer to degree five against the current implementation. Then add a small symbolic backend (polynomials in cos⁡,sin⁡,tan⁡,sec⁡\cos, \sin, \tan, \sec of the state) so that the car's det⁡[g1 g2 g3 g4]=−sec⁡4ϕ/L2\det[g_1\ g_2\ g_3\ g_4] = -\sec^4\phi/L^2 is produced as an expression rather than a number.

References

  1. 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.1–12.4: the vector-field preliminaries, the four-flow derivation (eq. 12.3–12.5), Examples 12.1.1–12.1.8 and 12.4.3–12.4.4, 12.4.9, Theorems 12.3.1, 12.3.3, 12.3.5, 12.4.1–12.4.2, and Problems 1–29, which this chapter follows section by section. Chow's 1939 paper and the Lian–Wang–Fu recurrence theorem are cited there as refs. 112 and 289.

  2. Sussmann, H. J. (1987) A General Theorem on Local Controllability. SIAM Journal on Control and Optimization 25(1).doi:10.1137/0325011 (opens in a new tab)

    The good-and-bad-bracket sufficient condition for small-time local controllability at an equilibrium, stated here as Theorem 12.3.3 and implemented as sussmannStlc with explicit neutralization residuals.

  3. Lewis, A. D. and Murray, R. M. (1997) Configuration Controllability of Simple Mechanical Control Systems. SIAM Journal on Control and Optimization 35(3).doi:10.1137/S0363012995287155 (opens in a new tab)

    The symmetric product, the symmetric closure and the tests for STLA, STLC, STLCA, STLCC and equilibrium controllability from rest (Theorems 12.4.1–12.4.2), implemented as lewisMurray.

  4. Murray, R. M., Li, Z., and Sastry, S. S. (1994) A Mathematical Introduction to Robotic Manipulation. CRC Press.link to A Mathematical Introduction to Robotic Manipulation (opens in a new tab)

    Chapter 7's treatment of nonholonomic systems — distributions, Frobenius, Chow, the Philip Hall basis and chained forms — is the standard long-form companion to Choset's §12.1–12.3 and the source of Exercise 6.

  5. Bullo, F. and Lewis, A. D. (2005) Geometric Control of Mechanical Systems: Modeling, Analysis, and Design for Simple Mechanical Control Systems. Springer, Texts in Applied Mathematics 49.doi:10.1007/978-1-4899-7276-7 (opens in a new tab)

    The affine-connection formulation of mechanical control systems in full: covariant derivatives, the symmetric product, constrained connections, and the kinematic reductions Chapter 21 uses.

  6. Solà, J., Deray, J., and Atchuthan, D. (2018) A micro Lie theory for state estimation in robotics. arXiv:1812.01537.link to A micro Lie theory for state estimation in robotics (opens in a new tab)

    The bridge from this chapter's vector-field brackets to the sister book's matrix Lie groups: the Lie bracket of left-invariant fields on SE(2) is the matrix commutator (up to Choset's sign), which is why the four-flow residue of Hitch's drive and spin is the se(2) bracket of their generators.