MOONMCL motion control

API reference

Every public item

390 types, methods and values across 7 packages. The surface is read from pkg.generated.mbti and the notes from the source comments; the page is generated, so it cannot drift from the code.

Import a package directly, or import moonbitstack/moonmcl for the whole surface under one name.

linear

moonbitstack/moonmcl/linear

Dense linear algebra on plain arrays: a row-major Mat, a flat Vec, and the factorisations the control solvers are built on.

Types

structEigh#

pub struct Eigh { values : Vec vectors : Mat }
values
Vec
vectors
Mat

The eigenvalues and eigenvectors of a symmetric matrix.

values is ascending and vectors has the matching eigenvector in its matching column, so a * v[:, i] = values[i] * v[:, i].

fnEigh::to_repr#

pub fn Eigh::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structLu#

pub struct Lu { n : Int32 lower : Mat upper : Mat perm : Array[Int32] sign : Double }
n
Int32
lower
Mat
upper
Mat
perm
Array[Int32]
sign
Double

An LU factorisation with partial pivoting, perm * A = lower * upper, where lower is unit lower triangular and upper is upper triangular.

sign is the parity of the row swaps, so det = sign * product(upper). The factorisation is kept so that several right-hand sides can reuse it, which is what the estimators do inside a filter loop.

fnLu::det#

pub fn Lu::det(self : Lu) -> Double

The determinant of the factorised matrix.

fnLu::solve#

pub fn Lu::solve(self : Lu, b : Mat) -> Mat raise Refused

Solve a * x = b from a factorisation. b has one column per right-hand side; the result has the same width.

fnLu::to_repr#

pub fn Lu::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structMat#

pub struct Mat { rows : Int32 cols : Int32 data : FixedArray[Double] }
rows
Int32
cols
Int32
data
FixedArray[Double]

A dense matrix of Double in row-major order.

Element (i, j) lives at data[i * cols + j]. The arithmetic methods return new matrices; set is the only writer.

fnMat::add#

pub fn Mat::add(self : Mat, other : Mat) -> Mat

The elementwise sum. Both matrices must have the same shape.

fnMat::add_to#

pub fn Mat::add_to(self : Mat, i : Int32, j : Int32, value : Double) -> Unit

Add value to the entry at (i, j).

fnMat::apply#

pub fn Mat::apply(self : Mat, v : Vec) -> Vec

The product self * v.

fnMat::apply_transposed#

pub fn Mat::apply_transposed(self : Mat, v : Vec) -> Vec

The product v^T * self, a row vector times the matrix.

fnMat::approx#

pub fn Mat::approx(self : Mat, other : Mat, tolerance? : Double) -> Bool

Whether self and other agree entry by entry within tolerance.

fnMat::at#

pub fn Mat::at(self : Mat, i : Int32, j : Int32) -> Double?

The entry at (i, j), or None when the index is outside the matrix.

fnMat::augment#

pub fn Mat::augment(self : Mat, right : Mat) -> Mat

self with right appended on the right, so the result is rows x (cols + right.cols).

fnMat::block#

pub fn Mat::block( self : Mat, row? : Int32, col? : Int32, height? : Int32, width? : Int32, ) -> Mat

The height x width block whose top-left corner is (row, col).

fnMat::col#

pub fn Mat::col(self : Mat, j : Int32) -> Vec

The j-th column, copied out.

fnMat::diagonal#

pub fn Mat::diagonal(values : Vec) -> Mat

A diagonal matrix with values on the diagonal.

fnMat::filled#

pub fn Mat::filled(rows : Int32, cols : Int32, value : Double) -> Mat

A rows x cols matrix with every entry value.

fnMat::from_fixed#

pub fn Mat::from_fixed( rows : Int32, cols : Int32, data : FixedArray[Double], ) -> Mat

A matrix that takes over data without copying it. data holds the entries row by row.

fnMat::get#

pub fn Mat::get(self : Mat, i : Int32, j : Int32) -> Double

The entry at (i, j). An index outside the matrix aborts.

fnMat::identity#

pub fn Mat::identity(n : Int32) -> Mat

The n x n identity.

fnMat::is_finite#

pub fn Mat::is_finite(self : Mat) -> Bool

Whether every entry is finite.

fnMat::mul#

pub fn Mat::mul(self : Mat, other : Mat) -> Mat

The product self * other.

fnMat::negate#

pub fn Mat::negate(self : Mat) -> Mat

Every entry negated.

fnMat::of#

pub fn Mat::of(values : Array[Array[Double]]) -> Mat

A matrix whose rows are values; every row must have the same length.

fnMat::row#

pub fn Mat::row(self : Mat, i : Int32) -> Vec

The i-th row, copied out.

fnMat::scale#

pub fn Mat::scale(self : Mat, factor : Double) -> Mat

Every entry multiplied by factor.

fnMat::set#

pub fn Mat::set(self : Mat, i : Int32, j : Int32, value : Double) -> Unit

Overwrite the entry at (i, j).

fnMat::set_col#

pub fn Mat::set_col(self : Mat, j : Int32, values : Vec) -> Unit

Overwrite the j-th column with values.

fnMat::set_row#

pub fn Mat::set_row(self : Mat, i : Int32, values : Vec) -> Unit

Overwrite the i-th row with values.

fnMat::stack#

pub fn Mat::stack(self : Mat, below : Mat) -> Mat

self with below appended underneath, so the result is (rows + below.rows) x cols.

fnMat::sub#

pub fn Mat::sub(self : Mat, other : Mat) -> Mat

The elementwise difference. Both matrices must have the same shape.

fnMat::to_array_rows#

pub fn Mat::to_array_rows(self : Mat) -> Array[Array[Double]]

The rows copied into growable arrays, for output and test expectations.

fnMat::to_repr#

pub fn Mat::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

fnMat::to_string#

pub fn Mat::to_string(self : Mat) -> String

One line per row, each formatted like a Vec.

fnMat::trace#

pub fn Mat::trace(self : Mat) -> Double

The sum of the diagonal entries.

fnMat::transpose#

pub fn Mat::transpose(self : Mat) -> Mat

The transpose A^T.

fnMat::zeros#

pub fn Mat::zeros(rows : Int32, cols : Int32) -> Mat

An all-zero rows x cols matrix.

structQr#

pub struct Qr { q : Mat r : Mat }
q
Mat
r
Mat

An economy QR factorisation, a = q * r, with q of orthonormal columns and r upper triangular.

q has the same shape as a and r is square, which is the form the least-squares step and the UKF's square root need.

fnQr::to_repr#

pub fn Qr::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structVec#

pub struct Vec { data : FixedArray[Double] }
data
FixedArray[Double]

A dense vector of Double.

The storage is a fixed array, so a vector is cheap to pass around and a set writes through to it. Every arithmetic method returns a new vector; none of them mutate the receiver.

fnVec::add#

pub fn Vec::add(self : Vec, other : Vec) -> Vec

The elementwise sum. The two vectors must have the same length.

fnVec::approx#

pub fn Vec::approx(self : Vec, other : Vec, tolerance? : Double) -> Bool

Whether self and other agree entry by entry within tolerance.

fnVec::at#

pub fn Vec::at(self : Vec, i : Int32) -> Double?

The entry at i, or None when i is outside the vector.

fnVec::axpy#

pub fn Vec::axpy(self : Vec, factor : Double, other : Vec) -> Vec

self + factor * other, the operation a matrix-vector product accumulates with.

fnVec::clone#

pub fn Vec::clone(self : Vec) -> Vec

An independent copy.

fnVec::dot#

pub fn Vec::dot(self : Vec, other : Vec) -> Double

The inner product. The two vectors must have the same length.

fnVec::filled#

pub fn Vec::filled(len : Int32, value : Double) -> Vec

A vector of len copies of value.

fnVec::from_fixed#

pub fn Vec::from_fixed(data : FixedArray[Double]) -> Vec

A vector that takes over data without copying it.

fnVec::get#

pub fn Vec::get(self : Vec, i : Int32) -> Double

The entry at i. An index outside the vector aborts: it is a programming error, not input data.

fnVec::hadamard#

pub fn Vec::hadamard(self : Vec, other : Vec) -> Vec

The elementwise product. The two vectors must have the same length.

fnVec::is_empty#

pub fn Vec::is_empty(self : Vec) -> Bool

Whether the vector has no entries.

fnVec::is_finite#

pub fn Vec::is_finite(self : Vec) -> Bool

Whether every entry is finite.

fnVec::len#

pub fn Vec::len(self : Vec) -> Int32

The number of entries.

fnVec::linspace#

pub fn Vec::linspace(start : Double, stop : Double, len : Int32) -> Vec

A vector of len samples evenly spaced from start to stop inclusive. A single sample is start.

fnVec::max_abs#

pub fn Vec::max_abs(self : Vec) -> Double

The largest absolute entry, or zero for an empty vector.

fnVec::negate#

pub fn Vec::negate(self : Vec) -> Vec

Every entry negated.

fnVec::norm#

pub fn Vec::norm(self : Vec) -> Double

The Euclidean length.

fnVec::norm_squared#

pub fn Vec::norm_squared(self : Vec) -> Double

The sum of the squared entries.

fnVec::normalized#

pub fn Vec::normalized(self : Vec) -> Vec

The unit vector in the same direction; a zero vector is returned as it is.

fnVec::of#

pub fn Vec::of(values : ArrayView[Double]) -> Vec

A vector holding values.

fnVec::scale#

pub fn Vec::scale(self : Vec, factor : Double) -> Vec

Every entry multiplied by factor.

fnVec::set#

pub fn Vec::set(self : Vec, i : Int32, value : Double) -> Unit

Overwrite the entry at i.

fnVec::sub#

pub fn Vec::sub(self : Vec, other : Vec) -> Vec

The elementwise difference. The two vectors must have the same length.

fnVec::sum#

pub fn Vec::sum(self : Vec) -> Double

The sum of the entries.

fnVec::to_array#

pub fn Vec::to_array(self : Vec) -> Array[Double]

The entries copied into a growable array.

fnVec::to_repr#

pub fn Vec::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

fnVec::to_string#

pub fn Vec::to_string(self : Vec) -> String

The entries in [ a, b, c ] form, for output and test expectations.

fnVec::zeros#

pub fn Vec::zeros(len : Int32) -> Vec

A vector of len zeros.

Values

fncholesky#

pub fn cholesky(a : Mat) -> Mat raise Refused

The lower Cholesky factor of a symmetric positive-definite matrix a, so that a = l * l^T.

The factor is what the Kalman gain is solved with: a Cholesky solve costs half an LU solve and never needs pivoting for a covariance.

fncholesky_solve#

pub fn cholesky_solve(l : Mat, b : Mat) -> Mat raise Refused

Solve a * x = b given the lower Cholesky factor l of a. b has one column per right-hand side.

fndet#

pub fn det(a : Mat) -> Double raise Refused

The determinant of a square matrix.

fneigh#

pub fn eigh(a : Mat, sweeps? : Int32) -> Eigh raise Refused

The symmetric eigendecomposition of a by cyclic Jacobi rotations.

The rotations are stable for the covariance-shaped matrices this library hands it, and they need no shift strategy. Only the symmetric part of a is used, so a small skew from rounding does not matter. Raises Refused::Dimension when a is not square and Refused::Exceeded when the sweep limit is reached.

fnexpm#

pub fn expm(a : Mat, terms? : Int32) -> Mat raise Refused

The matrix exponential of a square matrix, by scaling and squaring followed by a truncated Taylor series.

This is what turns a continuous state matrix into a discrete one; the scaling keeps the series inside the range where twenty terms reach machine precision.

fninv#

pub fn inv(a : Mat) -> Mat raise Refused

The inverse of a square matrix.

fnlu#

pub fn lu(a : Mat) -> Lu raise Refused

Factorise a, a square matrix, into perm * a = lower * upper.

Raises Refused::Singular at the first column whose pivot is zero; Refused::Dimension when a is not square.

fnnorm#

pub fn norm(a : Mat) -> Double

The Frobenius norm of a matrix.

fnqr#

pub fn qr(a : Mat) -> Qr raise Refused

Factorise a as q * r with Householder reflections.

Raises Refused::Dimension when a has fewer rows than columns: an economy factorisation cannot represent that shape.

fnsolve#

pub fn solve(a : Mat, b : Mat) -> Mat raise Refused

Solve a * x = b for a square a.

fnsolve_vec#

pub fn solve_vec(a : Mat, b : Vec) -> Vec raise Refused

Solve a * x = b for a square a and a single right-hand side.

contract

moonbitstack/moonmcl/contract

The traits every algorithm is written against — Model, Controller, Estimator, Trajectory, Kinematics, Space, Validity and Planner — and the shared records that go with them.

Types

structBudget#

pub struct Budget { iterations : Int32 seconds : Double? }
iterations
Int32/ / The number of samples or iterations to draw before giving up.
seconds
Double?/ / A wall-clock limit in seconds, when the caller has a clock.

How long a planner may search.

fnBudget::to_repr#

pub fn Budget::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

enumDiscretize#

pub enum Discretize { Zoh ForwardEuler Tustin }

Which rule turns a continuous state matrix into a discrete one.

fnDiscretize::to_repr#

pub fn Discretize::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structDynamics#

pub struct Dynamics { f : (@linear.Vec, @linear.Vec, Double) -> @linear.Vec h : (@linear.Vec) -> @linear.Vec integrator : Integrator }
f
(@linear.Vec, @linear.Vec, Double) -> @linear.Vec
h
(@linear.Vec) -> @linear.Vec
integrator
Integrator

A nonlinear plant given as a derivative and an output map, integrated with a named rule.

The derivative is f(x, u, dt), taking the period as well because a plant may be defined for a fixed control period; the rule treats it as the vector field at x.

fnDynamics::new#

pub fn Dynamics::new( f? : (@linear.Vec, @linear.Vec, Double) -> @linear.Vec, h? : (@linear.Vec) -> @linear.Vec, integrator? : Integrator, ) -> Dynamics

A nonlinear plant from its derivative and its output map, integrated with RK4 unless told otherwise.

fnDynamics::observe#

pub fn Dynamics::observe(Self, @linear.Vec) -> @linear.Vec

fnDynamics::observe_jacobian#

pub fn Dynamics::observe_jacobian(Self, @linear.Vec) -> @linear.Mat

fnDynamics::step#

pub fn Dynamics::step(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

fnDynamics::step_jacobian#

pub fn Dynamics::step_jacobian(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Mat

fnDynamics::to_repr#

pub fn Dynamics::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

enumIntegrator#

pub enum Integrator { Euler Midpoint Rk4 }

How Dynamics integrates its derivative.

fnIntegrator::to_repr#

pub fn Integrator::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structSample#

pub struct Sample { position : Double velocity : Double acceleration : Double jerk : Double }
position
Double/ / Position, in metres for a linear axis and radians for a joint.
velocity
Double/ / First derivative of the position.
acceleration
Double/ / Second derivative of the position.
jerk
Double/ / Third derivative of the position.

One instant of a single-axis motion, with every derivative a drive may need.

The jerk is what separates a smooth profile from a trapezoid: a drive that bounds it never excites the resonance the way a step in acceleration does.

fnSample::new#

pub fn Sample::new( position? : Double, velocity? : Double, acceleration? : Double, jerk? : Double, ) -> Sample

A sample from its four derivatives.

fnSample::still#

pub fn Sample::still(position : Double) -> Sample

A sample that is not moving.

fnSample::to_repr#

pub fn Sample::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structStateSpace#

pub struct StateSpace { a : @linear.Mat b : @linear.Mat c : @linear.Mat d : @linear.Mat dt : Double? }
a
@linear.Mat
b
@linear.Mat
c
@linear.Mat
d
@linear.Mat
dt
Double?

A linear time-invariant plant, x' = a x + b u, y = c x + d u.

With dt set the record is already discrete and step applies a x + b u once; without it the record is continuous and step integrates over the period it is given. A discrete record is what the Kalman filter and the model-predictive controller want; a continuous one is what a plant model in physical units looks like.

fnStateSpace::continuous#

pub fn StateSpace::continuous( a? : @linear.Mat, b? : @linear.Mat, c? : @linear.Mat, d? : @linear.Mat, ) -> StateSpace raise @linear.Refused

A continuous plant.

fnStateSpace::discrete#

pub fn StateSpace::discrete( a? : @linear.Mat, b? : @linear.Mat, c? : @linear.Mat, d? : @linear.Mat, dt? : Double, ) -> StateSpace raise @linear.Refused

A plant already discretised at dt seconds.

fnStateSpace::discretize#

pub fn StateSpace::discretize( self : StateSpace, dt? : Double, discretize? : Discretize, ) -> StateSpace raise @linear.Refused

The same plant discretised at dt seconds.

A record that is already discrete is returned unchanged when the periods agree and refused when they do not: resampling would need the original continuous plant, which the record no longer carries.

fnStateSpace::is_discrete#

pub fn StateSpace::is_discrete(self : StateSpace) -> Bool

Whether the record is already discrete.

fnStateSpace::observe#

pub fn StateSpace::observe(Self, @linear.Vec) -> @linear.Vec

fnStateSpace::observe_jacobian#

pub fn StateSpace::observe_jacobian(Self, @linear.Vec) -> @linear.Mat

fnStateSpace::step#

pub fn StateSpace::step(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

fnStateSpace::step_jacobian#

pub fn StateSpace::step_jacobian(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Mat

fnStateSpace::to_repr#

pub fn StateSpace::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

Traits

traitController#

pub(open) trait Controller { fn update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec fn reset(Self) -> Unit }
update
fn update(The input for one control period of dt seconds.
reset
fn reset(Self) -> UnitDrop the accumulated state (an integrator, a stored derivative) and start again from the next measurement.

A feedback law: the input to apply for a reference and a measurement.

The combinators in control (cascade, saturation, rate limiting) take any &Controller, so a controller written outside this library composes the same way the ones here do.

traitEstimator#

pub(open) trait Estimator { fn predict(Self, @linear.Vec, Double) -> Unit fn correct(Self, @linear.Vec) -> Unit raise @linear.Refused fn state(Self) -> @linear.Vec fn covariance(Self) -> @linear.Mat }
predict
fn predict(Self, u : @linear.Vec, dt : Double) -> UnitPropagate the estimate and its covariance by dt seconds under u.
correct
fn correct(Self, z : @linear.Vec) -> Unit raise @linear.RefusedFold in the measurement z.
state
fn state(Self) -> @linear.VecThe current state estimate.
covariance
fn covariance(Self) -> @linear.MatThe current state covariance.

A state estimator: propagate on the input, then fold in a measurement.

The two steps are separate because a sensor does not always deliver on every control period; a caller that has no measurement that cycle calls predict alone.

traitKinematics#

pub(open) trait Kinematics { fn forward(Self, @linear.Vec) -> @linear.Vec fn inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused fn jacobian(Self, @linear.Vec) -> @linear.Mat = _ }
forward
fn forward(Self, q : @linear.Vec) -> @linear.VecThe task-space pose for the joint values q.
inverse
fn inverse(Self, x : @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.RefusedThe joint values that reach the pose x. seed starts an iterative solve; without it the model picks its own starting point.
jacobian
fn jacobian(Self, q : @linear.Vec) -> @linear.Mat = _d forward / d q, the task-space rows by the joint columns.

A mechanism: joint values to a task-space pose, and back.

Both spaces are plain Vecs so that one contract covers a two-wheel base and a six-axis arm; a model that has typed joint values offers them alongside.

traitModel#

pub(open) trait Model { fn step(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec fn observe(Self, @linear.Vec) -> @linear.Vec fn step_jacobian(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Mat = _ fn observe_jacobian(Self, @linear.Vec) -> @linear.Mat = _ }
step
fn step(Self, x : @linear.Vec, u : @linear.Vec, dt : Double) -> @linear.VecThe state after dt seconds from x under the held input u.
observe
fn observe(Self, x : @linear.Vec) -> @linear.VecThe measurement a sensor produces for the state x.
step_jacobian
fn step_jacobian(Self, x : @linear.Vec, u : @linear.Vec, dt : Double) -> @linear.Mat = _d step / d x, an n x n matrix for an n-state.
observe_jacobian
fn observe_jacobian(Self, x : @linear.Vec) -> @linear.Mat = _d observe / d x, an m x n matrix for an n-state and an m-output.

A plant: how the state moves under an input, and what a sensor sees.

step and observe are the model. step_jacobian and observe_jacobian have default implementations built on them by central differences, so a plant that gives only the two functions works with the extended Kalman filter, the unscented Kalman filter and the particle filter as it is.

traitPlanner#

pub(open) trait Planner { fn plan(Self, @linear.Vec, @linear.Vec, Budget) -> Array[@linear.Vec] raise @linear.Refused }
plan
fn plan(Self, start : @linear.Vec, goal : @linear.Vec, budget : Budget) -> Array[The path, including both ends, or Refused::Exceeded when the budget runs out and Refused::Unreachable when the search space is exhausted.

A planner: a start, a goal and a budget, out comes a path of states from the start to the goal.

traitSpace#

pub(open) trait Space { fn sample(Self, &@moonbitstack/moonrand/contract.Rng) -> @linear.Vec fn distance(Self, @linear.Vec, @linear.Vec) -> Double fn interpolate(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec }
sample
fn sample(Self, rng : &@rand.Rng) -> @linear.VecA state drawn from the space's own bounds, using rng.
distance
fn distance(Self, a : @linear.Vec, b : @linear.Vec) -> DoubleThe distance between two states, in the space's own metric.
interpolate
fn interpolate(Self, a : @linear.Vec, b : @linear.Vec, t : Double) -> @linear.VecThe state t of the way from a to b, with t in [0, 1]. A planner relies on it staying on a feasible connection, not merely on a straight line.

A state space a planner can search: where to draw random states, how far apart two are, and how to walk between them.

A vehicle model implements this with its (x, y, heading) states and its own steering primitives, which is what lets a sampling planner plan a Dubins path without knowing what Dubins is.

traitTrajectory#

pub(open) trait Trajectory { fn duration(Self) -> Double fn sample(Self, Double) -> Sample }
duration
fn duration(Self) -> DoubleThe length of the motion in seconds.
sample
fn sample(Self, t : Double) -> SampleThe state at t seconds from the start.

A single-axis motion profile: a duration, and the state at any time in it.

Sampling outside [0, duration] is defined rather than refused: before the start the motion is held at its first sample and after the end at its last, so a caller can run a clock past the end without a branch.

traitValidity#

pub(open) trait Validity { fn valid(Self, @linear.Vec) -> Bool fn motion(Self, &Space, @linear.Vec, @linear.Vec) -> Bool = _ }
valid
fn valid(Self, x : @linear.Vec) -> BoolWhether the state x is free.
motion
fn motion(Self, space : &Space, a : @linear.Vec, b : @linear.Vec) -> Bool = _Whether the motion from a to b stays free. The default walks the space's own interpolation in motion_samples steps and checks each point, which is right for a space whose interpolation cannot cut a corner.

Which states and motions a motion planner may use.

Collision checking lives here, so the planners stay free of geometry.

control

moonbitstack/moonmcl/control

Feedback: the PID family and its combinators, LQR and its integral form, the iterative LQR, a box-constrained MPC, the two geometric path followers, computed torque, impedance and a barrier filter.

Types

enumAntiWindup#

pub enum AntiWindup { Off Conditional BackCalculation }

How a PID stops its integrator while the output is saturated.

fnAntiWindup::to_repr#

pub fn AntiWindup::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structCascade#

pub struct Cascade { stages : Array[&@contract.Controller] }
stages
Array[&@contract.Controller]

Controllers in series: the output of one stage is the reference of the next.

A cascade is how a current loop inside a velocity loop inside a position loop is written. The measurement vector carries one entry per stage, so stage i is handed measurement[i].

fnCascade::new#

pub fn Cascade::new(stages? : Array[&@contract.Controller]) -> Cascade

A cascade of the given stages, outermost first.

fnCascade::reset#

pub fn Cascade::reset(Self) -> Unit

fnCascade::update#

pub fn Cascade::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structCbfConfig#

pub struct CbfConfig { iterations : Int32 tolerance : Double }
iterations
Int32
tolerance
Double

The knobs of the control-barrier-function filter.

iterations bounds the alternating projection. The filter is exact when it converges, and the bound is there so a pathological gradient cannot stall a control period.

fnCbfConfig::to_repr#

pub fn CbfConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structComputedTorque#

pub struct ComputedTorque { inertia : (@linear.Vec) -> @linear.Mat gravity : (@linear.Vec) -> @linear.Vec kp : Double kd : Double }
inertia
(@linear.Vec) -> @linear.Mat
gravity
(@linear.Vec) -> @linear.Vec
kp
Double
kd
Double

A computed-torque law: the inertia and gravity of the mechanism plus a proportional-derivative correction in joint space.

inertia and gravity are supplied by the caller because the mass matrix of a mechanism belongs to the mechanism, not to the controller; a model that has them can pass them straight in, and a model that does not can pass an identity and get plain joint-space feedback.

fnComputedTorque::effort#

pub fn ComputedTorque::effort( self : ComputedTorque, q? : @linear.Vec, qd? : @linear.Vec, q_desired? : @linear.Vec, qd_desired? : @linear.Vec, qdd_desired? : @linear.Vec, ) -> @linear.Vec raise @linear.Refused

The effort that tracks the desired joint motion.

fnComputedTorque::inertia_of#

pub fn ComputedTorque::inertia_of( self : ComputedTorque, q? : @linear.Vec, ) -> @linear.Mat

The inertia alone, for a caller that wants the model part without the loop.

fnComputedTorque::new#

pub fn ComputedTorque::new( inertia? : (@linear.Vec) -> @linear.Mat, gravity? : (@linear.Vec) -> @linear.Vec, kp? : Double, kd? : Double, ) -> ComputedTorque raise @linear.Refused

A computed-torque law with the given gains.

fnComputedTorque::to_repr#

pub fn ComputedTorque::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structFeedforward#

pub struct Feedforward { velocity : Double acceleration : Double }
velocity
Double
acceleration
Double

A velocity- and acceleration-feedforward term on the reference trajectory.

A feedforward does not close a loop: it removes the lag the feedback would otherwise have to work off by itself. On a servo that follows a planned trajectory the velocity gain dominates and the acceleration gain covers the inertia.

fnFeedforward::command#

pub fn Feedforward::command( self : Feedforward, desired : @contract.Sample, ) -> Double

The command for a reference sample: the gains applied to its derivatives.

fnFeedforward::new#

pub fn Feedforward::new( velocity? : Double, acceleration? : Double, ) -> Feedforward raise @linear.Refused

A feedforward from its two gains. A negative gain is refused.

fnFeedforward::to_repr#

pub fn Feedforward::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structFeedforwardRunner#

pub struct FeedforwardRunner { feedforward : Feedforward mut previous_reference : Double mut previous_velocity : Double mut primed : Bool }
feedforward
Feedforward

A feedforward driven by the reference sequence: the velocity and the acceleration are differenced from the references it is handed.

fnFeedforwardRunner::new#

pub fn FeedforwardRunner::new(feedforward? : Feedforward) -> FeedforwardRunner

A runner for a feedforward.

fnFeedforwardRunner::reset#

pub fn FeedforwardRunner::reset(Self) -> Unit

fnFeedforwardRunner::update#

pub fn FeedforwardRunner::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structIlqrConfig#

pub struct IlqrConfig { iterations : Int32 tolerance : Double control : Output regularisation : Double state_weight : Double input_weight : Double }
iterations
Int32
tolerance
Double
control
Output
regularisation
Double
state_weight
Double
input_weight
Double

The knobs of the iterative LQR.

state_weight and input_weight are the diagonal weights of the quadratic cost: every state deviation costs state_weight / 2 per unit squared and every input input_weight / 2. regularisation is added to the input Hessian so a direction the model cannot move stays solvable.

fnIlqrConfig::to_repr#

pub fn IlqrConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structImpedance#

pub struct Impedance { mass : Double damping : Double stiffness : Double mut position : @linear.Vec mut velocity : @linear.Vec }
mass
Double
damping
Double
stiffness
Double

An impedance controller: a mass-spring-damper between the tool and the target, with the contact force measured rather than modelled.

The rendered position follows the admittance m x'' = f_ext - d x' - k (x - x_d) and the effort returned is the spring-damper wrench at that position, so a tool pushed off its target yields and then returns.

fnImpedance::effort#

pub fn Impedance::effort( self : Impedance, target? : @linear.Vec, external? : @linear.Vec, dt? : Double, ) -> @linear.Vec

The wrench to command for one period.

fnImpedance::new#

pub fn Impedance::new( mass? : Double, damping? : Double, stiffness? : Double, start? : @linear.Vec, ) -> Impedance raise @linear.Refused

An impedance from its three parameters and the starting position.

fnImpedance::position#

pub fn Impedance::position(self : Impedance) -> @linear.Vec

The rendered position, which is where the tool actually is under a contact force.

fnImpedance::to_repr#

pub fn Impedance::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structIntegralLqr#

pub struct IntegralLqr { gain : @linear.Mat state_dim : Int32 output : @linear.Mat dt : Double mut integral : @linear.Vec }
gain
@linear.Mat
state_dim
Int32
output
@linear.Mat
dt
Double

An LQR with an integral of the output error appended to the state.

The extra state is what removes a constant disturbance's offset: the proportional part of an LQR leaves a standing error when the plant is pushed by a bias, and the integrator integrates that error away. The integral acts on the output c x, not on the whole state, because integrating a state the input cannot reach independently would leave the augmented plant unstabilisable.

fnIntegralLqr::gain#

pub fn IntegralLqr::gain(self : IntegralLqr) -> @linear.Mat

The gain matrix over [state; integral].

fnIntegralLqr::reset#

pub fn IntegralLqr::reset(Self) -> Unit

fnIntegralLqr::update#

pub fn IntegralLqr::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structLqr#

pub struct Lqr { gain : @linear.Mat }
gain
@linear.Mat

A linear-quadratic regulator: the infinite-horizon gain for a discrete plant and quadratic weights.

The control law is u = -k (x - reference), so a regulator that drives the plant to a setpoint is the same object as the one that drives it to zero.

fnLqr::gain#

pub fn Lqr::gain(self : Lqr) -> @linear.Mat

The gain matrix, for a caller that applies it itself.

fnLqr::reset#

pub fn Lqr::reset(Self) -> Unit

fnLqr::update#

pub fn Lqr::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structMpc#

pub struct Mpc { model : @contract.StateSpace state_weight : @linear.Mat input_weight : @linear.Mat config : MpcConfig mut previous : @linear.Vec }
model
@contract.StateSpace
state_weight
@linear.Mat
input_weight
@linear.Mat
config
MpcConfig

A receding-horizon controller for a discrete linear plant with box limits on the input and on its rate of change.

The prediction is condensed into one quadratic program over the stacked inputs, which is what makes the period predictable: the matrices are built and factorised once per call, and the solve is a fixed number of ADMM iterations rather than a search whose length depends on the active set.

fnMpc::control#

pub fn Mpc::control( self : Mpc, state? : @linear.Vec, target? : @linear.Vec, ) -> @linear.Vec raise @linear.Refused

The command for this period, after which the horizon shifts by one.

fnMpc::new#

pub fn Mpc::new( model? : @contract.StateSpace, state_weight? : @linear.Mat, input_weight? : @linear.Mat, config? : MpcConfig, ) -> Mpc raise @linear.Refused

A model-predictive controller for model at the given weights.

The plant must be discrete: a continuous record would need the period it is to be discretised at, which the controller cannot guess.

structMpcConfig#

pub struct MpcConfig { horizon : Int32 iterations : Int32 penalty : Double input : Output rate : Output }
horizon
Int32
iterations
Int32
penalty
Double
input
Output
rate
Output

The knobs of the model-predictive controller.

penalty is the ADMM step of the quadratic program, input the box on the command and rate the box on its change per second. iterations bounds the solve, so a period can never take longer than the budget says.

fnMpcConfig::to_repr#

pub fn MpcConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structOutput#

pub struct Output { low : Double high : Double }
low
Double
high
Double

An inclusive band [low, high] for one scalar.

fnOutput::to_repr#

pub fn Output::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structPid#

pub struct Pid { config : PidConfig mut integral : Double mut previous_input : Double mut derivative : Double mut primed : Bool }
config
PidConfig

A proportional-integral-derivative controller.

The integrator, the previous derivative input and the filtered derivative are the only state; reset clears them so a loop can start from rest.

fnPid::command#

pub fn Pid::command( self : Pid, reference? : Double, measurement? : Double, dt? : Double, ) -> Double

The output for one period of a scalar loop.

fnPid::integral#

pub fn Pid::integral(self : Pid) -> Double

The integrator value, which is what an anti-windup scheme acts on and what a test asserts when the loop sits in saturation.

fnPid::new#

pub fn Pid::new(config? : PidConfig) -> Pid

A PID from a configuration.

fnPid::reset#

pub fn Pid::reset(Self) -> Unit

fnPid::update#

pub fn Pid::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structPidConfig#

pub struct PidConfig { kp : Double ki : Double kd : Double weight_p : Double weight_d : Double derivative_on_measurement : Bool anti_windup : AntiWindup tracking_time : Double filter : Double output : Output }
kp
Double
ki
Double
kd
Double
weight_p
Double
weight_d
Double
derivative_on_measurement
Bool
anti_windup
AntiWindup
tracking_time
Double
filter
Double
output
Output

Every number a PID uses that is not one of its three gains.

weight_p and weight_d are the setpoint weights of the standard form: the proportional term acts on weight_p * reference - measurement and the derivative on weight_d * reference - measurement. A weight of zero takes the reference out of that term, which is what "derivative on measurement" means; derivative_on_measurement does exactly that for the derivative without the caller having to reason about the weight.

filter is the fraction of the raw derivative kept each period: 1 is no filtering, 0.1 smooths heavily. Values outside (0, 1] are read as 1.

fnPidConfig::to_repr#

pub fn PidConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structPursuit#

pub struct Pursuit { lookahead : Double wheelbase : Double }
lookahead
Double
wheelbase
Double

The steering a pure-pursuit follower asks for.

The follower looks a fixed distance ahead on the path, which is what makes it stable at speed: a short lookahead cuts corners and oscillates, a long one turns early. The returned angle is the one that puts the rear axle on an arc through the lookahead point.

fnPursuit::steering#

pub fn Pursuit::steering( self : Pursuit, pose? : @linear.Vec, path? : ArrayView[@linear.Vec], ) -> Double raise @linear.Refused

The steering angle that puts the vehicle on the lookahead point.

fnPursuit::to_repr#

pub fn Pursuit::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structQpConfig#

pub struct QpConfig { iterations : Int32 penalty : Double tolerance : Double }
iterations
Int32
penalty
Double
tolerance
Double

The knobs of the box-constrained quadratic program.

penalty is the ADMM step; too small and the dual converges slowly, too large and the primal oscillates. Twice the largest diagonal of h is the usual choice for a well-scaled problem.

fnQpConfig::to_repr#

pub fn QpConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structRateLimited#

pub struct RateLimited { inner : &@contract.Controller rate : Double mut previous : Double }
inner
&@contract.Controller
rate
Double

A controller whose output may not change faster than rate per second.

The limit applies to the first entry of the command, which is the one a single-drive loop carries; a higher-dimensional command passes through the slowest component.

fnRateLimited::new#

pub fn RateLimited::new( inner? : &@contract.Controller, rate? : Double, ) -> RateLimited raise @linear.Refused

A rate-limit wrapper. A rate that is not positive is refused.

fnRateLimited::reset#

pub fn RateLimited::reset(Self) -> Unit

fnRateLimited::update#

pub fn RateLimited::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structRiccati#

pub struct Riccati { gain : @linear.Mat cost : @linear.Mat }
gain
@linear.Mat
cost
@linear.Mat

The solution of a discrete algebraic Riccati equation: the stabilising gain and the cost-to-go matrix it came with.

fnRiccati::to_repr#

pub fn Riccati::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structSaturating#

pub struct Saturating { inner : &@contract.Controller output : Output }
inner
&@contract.Controller
output
Output

A controller whose output is clamped into a band.

fnSaturating::new#

pub fn Saturating::new( inner? : &@contract.Controller, output? : Output, ) -> Saturating

A saturation wrapper.

fnSaturating::output#

pub fn Saturating::output(self : Saturating) -> Output

The band, exposed so a caller can read back the limit it set.

fnSaturating::reset#

pub fn Saturating::reset(Self) -> Unit

fnSaturating::update#

pub fn Saturating::update(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

structStanley#

pub struct Stanley { gain : Double wheelbase : Double soft : Double }
gain
Double
wheelbase
Double
soft
Double

The steering a Stanley follower asks for.

The law is the heading error plus a term that grows with the distance from the path: the first brings the vehicle parallel, the second brings it back on. soft stands in for the speed in the usual atan(k e / v), so the follower does not need a speed input.

fnStanley::steering#

pub fn Stanley::steering( self : Stanley, pose? : @linear.Vec, path? : ArrayView[@linear.Vec], ) -> Double raise @linear.Refused

The steering angle from the heading error and the cross-track error.

fnStanley::to_repr#

pub fn Stanley::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

Values

fnbox_qp#

pub fn box_qp( h? : @linear.Mat, f? : @linear.Vec, lower? : @linear.Vec, upper? : @linear.Vec, config? : QpConfig, ) -> @linear.Vec raise @linear.Refused

The minimiser of 0.5 z' h z + f' z inside the box [lower, upper].

ADMM rather than an active-set method: the horizon of a predictive controller is re-solved every period with the same h, so a method whose cost per iteration is one triangular solve and one clamp keeps the period short, and there is no active set to warm start.

fncbf_filter#

pub fn cbf_filter( nominal? : @linear.Vec, gradient? : @linear.Vec, drift? : Double, barrier? : Double, alpha? : Double, lower? : @linear.Vec, upper? : @linear.Vec, config? : CbfConfig, ) -> @linear.Vec

The safe input closest to the nominal one.

The barrier h is the one the caller computed for the current state; gradient is d h / d u, drift is d h / d t without the input, and alpha is the class-K gain that decides how hard the filter pushes towards a larger barrier. The result satisfies drift + gradient * u + alpha * barrier >= 0 inside the box, or the closest point to that set when the box and the half-space do not meet.

Dykstra's alternating projection rather than plain alternation: plain alternation lands on a point of the intersection but not on the nearest one, and the whole point of a safety filter is to change the command as little as possible.

fnclamp_scalar#

pub fn clamp_scalar(value : Double, low : Double, high : Double) -> Double

Clamp into an inclusive band.

fndare#

pub fn dare( a? : @linear.Mat, b? : @linear.Mat, q? : @linear.Mat, r? : @linear.Mat, iterations? : Int32, tolerance? : Double, ) -> Riccati raise @linear.Refused

Solve the discrete algebraic Riccati equation for (a, b) at the weights (q, r) by iterating the Riccati recursion to a fixed point.

The recursion is monotone from p = q, so it converges to the stabilising solution without a Schur decomposition. A system that cannot be stabilised does not converge, and the iteration says so with Refused::Exceeded rather than returning a gain that would drive it further away.

fnilqr#

pub fn ilqr( model? : &@contract.Model, start? : @linear.Vec, goal? : @linear.Vec, controls? : Array[@linear.Vec], dt? : Double, config? : IlqrConfig, ) -> Array[@linear.Vec] raise @linear.Refused

The input sequence that drives start to goal over the horizon the initial guess fixes.

The initial guess gives the horizon, the control dimension and the region the solve starts in; the returned sequence has the same length. The backward pass uses the model's state Jacobian and a central difference for the input one, because a plant contract only promises the former.

fnintegral_lqr#

pub fn integral_lqr( a? : @linear.Mat, b? : @linear.Mat, c? : @linear.Mat, q? : @linear.Mat, r? : @linear.Mat, integral_weight? : @linear.Mat, dt? : Double, iterations? : Int32, tolerance? : Double, ) -> IntegralLqr raise @linear.Refused

The integral LQR for a discrete (a, b) pair with outputs c, accumulating the output error at dt seconds.

fnlqr#

pub fn lqr( a? : @linear.Mat, b? : @linear.Mat, q? : @linear.Mat, r? : @linear.Mat, iterations? : Int32, tolerance? : Double, ) -> Lqr raise @linear.Refused

The infinite-horizon LQR for a discrete (a, b) pair. An element of r that is not positive is refused: it would let the input be free.

fnpid_gains#

pub fn pid_gains( kp? : Double, ki? : Double, kd? : Double, ) -> PidConfig raise @linear.Refused

A PID configuration from the three gains. A negative gain is refused: a loop with a negative proportional gain is unstable by construction, and refusing it here names the mistake where it is made.

estimation

moonbitstack/moonmcl/estimation

State estimation: the linear Kalman filter, its extended and unscented forms over any plant, a particle filter, the one-dimensional trackers and the backward smoothing pass.

Types

structAlphaBetaGamma#

pub struct AlphaBetaGamma { alpha : Double beta : Double gamma : Double mut position : Double mut velocity : Double mut acceleration : Double }
alpha
Double
beta
Double
gamma
Double

An alpha-beta-gamma tracker: position, velocity and acceleration of one axis from a position measurement.

The three gains trade noise against lag the way a Kalman filter does with a fixed model: alpha corrects the position, beta the velocity and gamma the acceleration. The preset is the critically damped set for a steady-state model of a constant acceleration.

fnAlphaBetaGamma::new#

pub fn AlphaBetaGamma::new( alpha? : Double, beta? : Double, gamma? : Double, position? : Double, ) -> AlphaBetaGamma raise @linear.Refused

A tracker with the given gains and starting position.

fnAlphaBetaGamma::to_repr#

pub fn AlphaBetaGamma::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

fnAlphaBetaGamma::update#

pub fn AlphaBetaGamma::update( self : AlphaBetaGamma, measurement? : Double, dt? : Double, ) -> @contract.Sample

The state after folding in one position measurement.

structComplementary#

pub struct Complementary { alpha : Double mut angle : Double }
alpha
Double

A complementary filter for one angle: the gyro is trusted for the fast motion, the measurement for the slow drift.

alpha is the fraction of the integrated rate kept each period. At 0.98 with a period of a hundredth of a second the time constant is about half a second, which is the usual balance for a hobby-grade inertial sensor.

fnComplementary::angle#

pub fn Complementary::angle(self : Complementary) -> Double

The current angle.

fnComplementary::new#

pub fn Complementary::new( alpha? : Double, angle? : Double, ) -> Complementary raise @linear.Refused

A complementary filter with the given blend and starting angle.

fnComplementary::to_repr#

pub fn Complementary::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

fnComplementary::update#

pub fn Complementary::update( self : Complementary, rate? : Double, measurement? : Double, dt? : Double, ) -> Double

The corrected angle after one period.

structExtendedKalman#

pub struct ExtendedKalman { model : &@moonbitstack/moonmcl/contract.Model process : @linear.Mat measurement : @linear.Mat mut state : @linear.Vec mut covariance : @linear.Mat }
model
&@contract.Model
process
@linear.Mat
measurement
@linear.Mat

An extended Kalman filter: the linear recursion with the Jacobians the model supplies, whether analytically or by the contract's default differences.

fnExtendedKalman::correct#

pub fn ExtendedKalman::correct(Self, @linear.Vec) -> Unit raise @linear.Refused

fnExtendedKalman::covariance#

pub fn ExtendedKalman::covariance(Self) -> @linear.Mat

fnExtendedKalman::new#

pub fn ExtendedKalman::new( model? : &@contract.Model, process? : @linear.Mat, measurement? : @linear.Mat, state? : @linear.Vec, covariance? : @linear.Mat, ) -> ExtendedKalman raise @linear.Refused

An extended Kalman filter for any plant that implements the model contract.

fnExtendedKalman::predict#

pub fn ExtendedKalman::predict(Self, @linear.Vec, Double) -> Unit

fnExtendedKalman::state#

pub fn ExtendedKalman::state(Self) -> @linear.Vec

fnExtendedKalman::to_repr#

pub fn ExtendedKalman::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structKalman#

pub struct Kalman { model : @moonbitstack/moonmcl/contract.StateSpace process : @linear.Mat measurement : @linear.Mat mut state : @linear.Vec mut covariance : @linear.Mat }
model
@contract.StateSpace
process
@linear.Mat
measurement
@linear.Mat

A linear Kalman filter for a discrete state-space plant.

fnKalman::correct#

pub fn Kalman::correct(Self, @linear.Vec) -> Unit raise @linear.Refused

fnKalman::covariance#

pub fn Kalman::covariance(Self) -> @linear.Mat

fnKalman::new#

pub fn Kalman::new( model? : @contract.StateSpace, process? : @linear.Mat, measurement? : @linear.Mat, state? : @linear.Vec, covariance? : @linear.Mat, ) -> Kalman raise @linear.Refused

A Kalman filter for model with the given noise covariances and prior.

fnKalman::predict#

pub fn Kalman::predict(Self, @linear.Vec, Double) -> Unit

fnKalman::state#

pub fn Kalman::state(Self) -> @linear.Vec

structParticleFilter#

pub struct ParticleFilter { model : &@moonbitstack/moonmcl/contract.Model process : @linear.Mat measurement : @linear.Mat mut particles : Array[@linear.Vec] mut weights : Array[Double] rng : &@moonbitstack/moonrand/contract.Rng }
model
&@contract.Model
process
@linear.Mat
measurement
@linear.Mat
rng
&@rand_contract.Rng

A particle filter over any plant that implements the model contract.

The particles are drawn around the prior at construction and then carried by the model itself, so the filter never assumes the state distribution stays Gaussian. Resampling is systematic and only runs when the effective sample size falls below half the cloud, which keeps the diversity a plain resample-every-step filter loses.

fnParticleFilter::correct#

pub fn ParticleFilter::correct(Self, @linear.Vec) -> Unit raise @linear.Refused

fnParticleFilter::covariance#

pub fn ParticleFilter::covariance(Self) -> @linear.Mat

fnParticleFilter::new#

pub fn ParticleFilter::new( model? : &@contract.Model, process? : @linear.Mat, measurement? : @linear.Mat, state? : @linear.Vec, covariance? : @linear.Mat, rng? : &@rand_contract.Rng, samples? : Int32, ) -> ParticleFilter raise @linear.Refused

A particle filter with samples particles drawn around state.

fnParticleFilter::particles#

pub fn ParticleFilter::particles(self : ParticleFilter) -> Array[@linear.Vec]

The particles, for a caller that plots the cloud.

fnParticleFilter::predict#

pub fn ParticleFilter::predict(Self, @linear.Vec, Double) -> Unit

fnParticleFilter::state#

pub fn ParticleFilter::state(Self) -> @linear.Vec

fnParticleFilter::to_repr#

pub fn ParticleFilter::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

fnParticleFilter::weights#

pub fn ParticleFilter::weights(self : ParticleFilter) -> Array[Double]

The weight of each particle.

structUnscentedConfig#

pub struct UnscentedConfig { alpha : Double beta : Double kappa : Double }
alpha
Double
beta
Double
kappa
Double

The spread of the sigma points in the unscented transform.

alpha sets how far the points sit from the mean, beta folds in the knowledge that the distribution is Gaussian, and kappa is the usual secondary scaling. The preset is the one the reference implementations use.

fnUnscentedConfig::to_repr#

pub fn UnscentedConfig::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structUnscentedKalman#

pub struct UnscentedKalman { model : &@moonbitstack/moonmcl/contract.Model process : @linear.Mat measurement : @linear.Mat mut state : @linear.Vec mut covariance : @linear.Mat config : UnscentedConfig }
model
&@contract.Model
process
@linear.Mat
measurement
@linear.Mat
config
UnscentedConfig

An unscented Kalman filter.

fnUnscentedKalman::correct#

pub fn UnscentedKalman::correct(Self, @linear.Vec) -> Unit raise @linear.Refused

fnUnscentedKalman::covariance#

pub fn UnscentedKalman::covariance(Self) -> @linear.Mat

fnUnscentedKalman::new#

pub fn UnscentedKalman::new( model? : &@contract.Model, process? : @linear.Mat, measurement? : @linear.Mat, state? : @linear.Vec, covariance? : @linear.Mat, config? : UnscentedConfig, ) -> UnscentedKalman raise @linear.Refused

An unscented Kalman filter for any plant that implements the model contract.

fnUnscentedKalman::predict#

pub fn UnscentedKalman::predict(Self, @linear.Vec, Double) -> Unit

fnUnscentedKalman::state#

pub fn UnscentedKalman::state(Self) -> @linear.Vec

fnUnscentedKalman::to_repr#

pub fn UnscentedKalman::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

Values

fnrts#

pub fn rts( states? : Array[@linear.Vec], covariances? : Array[@linear.Mat], transitions? : Array[@linear.Mat], process? : @linear.Mat, ) -> (Array[@linear.Vec], Array[@linear.Mat]) raise @linear.Refused

The Rauch-Tung-Striebel smoother: the forward filter's estimates refined by a backward pass over the same record.

states and covariances are the filtered estimates, transitions the state matrices between consecutive steps, and process the process covariance. The result is the smoothed state and covariance at every step, whose covariances are never larger than the filtered ones.

trajectory

moonbitstack/moonmcl/trajectory

Single-axis motion: the trapezoid and the jerk-limited profile, polynomials, a natural cubic spline, a clamped B-spline, and the synchroniser that runs several axes on one clock.

Types

structBSpline#

pub struct BSpline { degree : Int32 control : Array[Double] knots : Array[Double] duration : Double }
degree
Int32
control
Array[Double]
knots
Array[Double]
duration
Double

A clamped uniform B-spline over a control polygon.

The curve is pulled towards the control points without passing through them, which is what makes it the profile for a path that only has to be smooth. The first and last control points are interpolated, so it starts and ends where the polygon does.

fnBSpline::duration#

pub fn BSpline::duration(Self) -> Double

fnBSpline::sample#

pub fn BSpline::sample(Self, Double) -> @contract.Sample

fnBSpline::to_repr#

pub fn BSpline::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structCubicSpline#

pub struct CubicSpline { times : Array[Double] positions : Array[Double] curvatures : Array[Double] }
times
Array[Double]
positions
Array[Double]
curvatures
Array[Double]

A natural cubic spline through time-stamped positions, continuous in velocity and acceleration, with zero curvature at both ends.

fnCubicSpline::duration#

pub fn CubicSpline::duration(Self) -> Double

fnCubicSpline::sample#

pub fn CubicSpline::sample(Self, Double) -> @contract.Sample

fnCubicSpline::to_repr#

pub fn CubicSpline::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structPolynomial#

pub struct Polynomial { coefficients : Array[Double] duration : Double }
coefficients
Array[Double]
duration
Double

A polynomial in time, position = sum(coefficients[i] * t^i).

A polynomial is the profile to reach for when the boundary conditions are the whole requirement: it matches a position, a velocity and an acceleration at both ends exactly, and it does not care about a jerk limit on the way.

fnPolynomial::duration#

pub fn Polynomial::duration(Self) -> Double

fnPolynomial::sample#

pub fn Polynomial::sample(Self, Double) -> @contract.Sample

fnPolynomial::to_repr#

pub fn Polynomial::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structScurve#

pub struct Scurve { distance : Double sign : Double duration : Double phases : Array[Double] jerks : Array[Double] starts : Array[(Double, Double, Double)] }
distance
Double
sign
Double
duration
Double
phases
Array[Double]
jerks
Array[Double]
starts
Array[(Double, Double, Double)]

A jerk-limited S-curve.

fnScurve::duration#

pub fn Scurve::duration(Self) -> Double

fnScurve::sample#

pub fn Scurve::sample(Self, Double) -> @contract.Sample

structSynced#

pub struct Synced { axes : Array[&@contract.Trajectory] duration : Double }
axes
Array[&@contract.Trajectory]
duration
Double

Several single-axis profiles run together.

Axes are slowed by sampling them on a stretched clock: axis i is sampled at t * duration_i / duration, and its velocity and acceleration are scaled by the same factor and its square. The path is preserved, the timing is not.

fnSynced::axis_sample#

pub fn Synced::axis_sample( self : Synced, index : Int32, t : Double, ) -> @contract.Sample

One axis sampled on the common clock, with its derivatives scaled back to the axis's own time.

fnSynced::duration#

pub fn Synced::duration(Self) -> Double

fnSynced::new#

pub fn Synced::new( axes? : Array[&@contract.Trajectory], ) -> Synced raise @linear.Refused

A synchronised set from axes that already have a duration.

fnSynced::sample#

pub fn Synced::sample(Self, Double) -> @contract.Sample

fnSynced::sample_all#

pub fn Synced::sample_all( self : Synced, t : Double, ) -> Array[@contract.Sample]

Every axis sampled at the same instant.

fnSynced::to_repr#

pub fn Synced::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structTrapezoid#

pub struct Trapezoid { distance : Double v_max : Double a_max : Double start_velocity : Double end_velocity : Double duration : Double ramp_time : Double cruise_time : Double peak_velocity : Double sign : Double }
distance
Double
v_max
Double
a_max
Double
start_velocity
Double
end_velocity
Double
duration
Double
ramp_time
Double
cruise_time
Double
peak_velocity
Double
sign
Double

A trapezoidal velocity profile: accelerate, cruise, decelerate.

It is the cheapest profile that respects a velocity and an acceleration limit, and the one that puts a step in the acceleration at each corner. The boundary velocities may be anything up to the peak the distance allows.

fnTrapezoid::duration#

pub fn Trapezoid::duration(Self) -> Double

fnTrapezoid::sample#

pub fn Trapezoid::sample(Self, Double) -> @contract.Sample

fnTrapezoid::to_repr#

pub fn Trapezoid::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

Values

fnb_spline#

pub fn b_spline( control? : ArrayView[Double], degree? : Int32, duration? : Double, ) -> BSpline raise @linear.Refused

A clamped B-spline of degree over control, running for duration seconds.

fncubic#

pub fn cubic( start? : Double, end? : Double, start_velocity? : Double, end_velocity? : Double, duration? : Double, ) -> Polynomial raise @linear.Refused

A cubic from one boundary state to another over duration.

A cubic matches the two positions and the two velocities exactly; its acceleration jumps at both ends, which is what a drive without a jerk limit does anyway.

fncubic_spline#

pub fn cubic_spline( knots? : ArrayView[(Double, Double)], ) -> CubicSpline raise @linear.Refused

A natural cubic spline through (time, position) knots, which must be ordered in time.

fnquintic#

pub fn quintic( start? : Double, end? : Double, start_velocity? : Double, start_acceleration? : Double, end_velocity? : Double, end_acceleration? : Double, duration? : Double, ) -> Polynomial raise @linear.Refused

A quintic from one boundary state to another over duration.

A quintic also matches the two accelerations, so the acceleration is continuous with whatever profile came before and whatever comes after.

fnscurve#

pub fn scurve( distance? : Double, v_max? : Double, a_max? : Double, j_max? : Double, start_velocity? : Double, start_acceleration? : Double, end_velocity? : Double, end_acceleration? : Double, ) -> Scurve raise @linear.Refused

An S-curve over distance with the given limits and boundary conditions.

The start and end accelerations are folded into the first and last ramp, so a motion that is already accelerating keeps its acceleration instead of spending time on coming back to zero. A boundary acceleration outside the limit is refused, and so is a boundary velocity against the direction of travel or above the velocity limit: none of those has a jerk-limited profile that starts from it.

fntrapezoid#

pub fn trapezoid( distance? : Double, v_max? : Double, a_max? : Double, start_velocity? : Double, end_velocity? : Double, ) -> Trapezoid raise @linear.Refused

A trapezoid over distance with the given limits and boundary velocities.

The boundary velocities are read along the direction of travel: a negative distance with a start velocity of -0.5 means the axis is already moving the way it will go. A velocity against the direction of travel is refused, since the profile would have to reverse inside itself.

planning

moonbitstack/moonmcl/planning

Motion planning: the sampling planners over any state space, the Dubins and Reeds-Shepp car spaces, the two local planners, and the bridge to the graph package's grid searches.

Types

structDubins#

pub struct Dubins { turning_radius : Double extent : Double }
turning_radius
Double
extent
Double

A Dubins car.

fnDubins::distance#

pub fn Dubins::distance(Self, @linear.Vec, @linear.Vec) -> Double

fnDubins::interpolate#

pub fn Dubins::interpolate(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

fnDubins::new#

pub fn Dubins::new( turning_radius? : Double, extent? : Double, ) -> Dubins raise @linear.Refused

A Dubins car with the given radius. extent is the half width of the box the space samples from.

fnDubins::path#

pub fn Dubins::path( self : Dubins, start? : @linear.Vec, goal? : @linear.Vec, ) -> DubinsPath raise @linear.Refused

The shortest Dubins path between two (x, y, heading) poses.

fnDubins::paths#

pub fn Dubins::paths( self : Dubins, start? : @linear.Vec, goal? : @linear.Vec, ) -> Array[DubinsPath] raise @linear.Refused

Every word that joins the two poses, in word order.

A car whose words are all drawn is a car the reader can compare; the callers that only want to drive one take path.

fnDubins::sample#

pub fn Dubins::sample(Self, &@moonbitstack/moonrand/contract.Rng) -> @linear.Vec

fnDubins::to_repr#

pub fn Dubins::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structDubinsPath#

pub struct DubinsPath { word : DubinsWord lengths : (Double, Double, Double) length : Double origin : @linear.Vec radius : Double }
word
DubinsWord
lengths
(Double, Double, Double)
length
Double
origin
@linear.Vec
radius
Double

The Dubins path between two poses: the word and the length of each of its three pieces.

fnDubinsPath::at#

pub fn DubinsPath::at(self : DubinsPath, distance : Double) -> @linear.Vec

The pose at distance travelled along the path.

fnDubinsPath::to_repr#

pub fn DubinsPath::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

enumDubinsWord#

pub enum DubinsWord { Lsl Lsr Rsl Rsr Rlr Lrl }

One of the six Dubins words: three pieces, each a left arc, a right arc or a straight line.

fnDubinsWord::to_repr#

pub fn DubinsWord::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structDynamicWindow#

pub struct DynamicWindow { max_velocity : Double min_velocity : Double max_rotation : Double max_acceleration : Double max_rotation_acceleration : Double resolution_velocity : Double resolution_rotation : Double predict : Double clearance : Double margin : Double heading_weight : Double clearance_weight : Double velocity_weight : Double }
max_velocity
Double
min_velocity
Double
max_rotation
Double
max_acceleration
Double
max_rotation_acceleration
Double
resolution_velocity
Double
resolution_rotation
Double
predict
Double
clearance
Double
margin
Double
heading_weight
Double
clearance_weight
Double
velocity_weight
Double

The dynamic window approach: sample the velocities the drives can reach in one period, roll each one forward, and keep the best by heading, clearance and speed.

fnDynamicWindow::command#

pub fn DynamicWindow::command( self : DynamicWindow, pose? : @linear.Vec, velocity? : @linear.Vec, goal? : @linear.Vec, obstacles? : ArrayView[@linear.Vec], dt? : Double, ) -> @linear.Vec raise @linear.Refused

The best velocity pair for the current pose towards goal, avoiding obstacles, which are points.

fnDynamicWindow::to_repr#

pub fn DynamicWindow::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

enumGridSearch#

pub enum GridSearch { Dijkstra AStar Jps ThetaStar }

Which search a grid query runs.

fnGridSearch::to_repr#

pub fn GridSearch::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structGridSpace#

pub struct GridSpace { grid : @grid.Grid resolution : Double }
grid
@graph_grid.Grid
resolution
Double

A grid used as a planning space, so a sampling planner can search a lattice.

fnGridSpace::distance#

pub fn GridSpace::distance(Self, @linear.Vec, @linear.Vec) -> Double

fnGridSpace::interpolate#

pub fn GridSpace::interpolate(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

fnGridSpace::motion#

pub fn GridSpace::motion(Self, &@moonbitstack/moonmcl/contract.Space, @linear.Vec, @linear.Vec) -> Bool

fnGridSpace::new#

pub fn GridSpace::new( grid : @graph_grid.Grid, resolution? : Double, ) -> GridSpace raise @linear.Refused

A space whose states are grid cells scaled by resolution.

fnGridSpace::sample#

pub fn GridSpace::sample(Self, &@moonbitstack/moonrand/contract.Rng) -> @linear.Vec

fnGridSpace::valid#

pub fn GridSpace::valid(Self, @linear.Vec) -> Bool

structInformedRrtStar#

pub struct InformedRrtStar { space : &@moonbitstack/moonmcl/contract.Space validity : &@moonbitstack/moonmcl/contract.Validity step : Double goal_bias : Double neighbourhood : Double rng : &@moonbitstack/moonrand/contract.Rng }
space
&@contract.Space
validity
&@contract.Validity
step
Double
goal_bias
Double
neighbourhood
Double
rng
&@rand_contract.Rng

An RRT* that only samples where a path shorter than the best one could still run: the ellipse whose foci are the start and the goal.

fnInformedRrtStar::new#

pub fn InformedRrtStar::new( space? : &@contract.Space, validity? : &@contract.Validity, step? : Double, goal_bias? : Double, neighbourhood? : Double, seed? : Int32, ) -> InformedRrtStar raise @linear.Refused

An informed RRT* seeded from the best path found so far.

fnInformedRrtStar::plan#

pub fn InformedRrtStar::plan(Self, @linear.Vec, @linear.Vec, @moonbitstack/moonmcl/contract.Budget) -> Array[@linear.Vec] raise @linear.Refused

structPotentialField#

pub struct PotentialField { attraction : Double repulsion : Double influence : Double step : Double }
attraction
Double
repulsion
Double
influence
Double
step
Double

An artificial potential field: attraction to the goal, repulsion from the obstacles.

fnPotentialField::command#

pub fn PotentialField::command( self : PotentialField, position? : @linear.Vec, goal? : @linear.Vec, obstacles? : ArrayView[@linear.Vec], ) -> @linear.Vec

The velocity command for this step, as a two-dimensional motion.

fnPotentialField::to_repr#

pub fn PotentialField::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structPrm#

pub struct Prm { space : &@moonbitstack/moonmcl/contract.Space validity : &@moonbitstack/moonmcl/contract.Validity samples : Int32 neighbours : Int32 connection : Double rng : &@moonbitstack/moonrand/contract.Rng }
space
&@contract.Space
validity
&@contract.Validity
samples
Int32
neighbours
Int32
connection
Double
rng
&@rand_contract.Rng

A probabilistic roadmap.

fnPrm::new#

pub fn Prm::new( space? : &@contract.Space, validity? : &@contract.Validity, samples? : Int32, neighbours? : Int32, connection? : Double, seed? : Int32, ) -> Prm raise @linear.Refused

A roadmap with the given sample count and connection radius.

fnPrm::plan#

pub fn Prm::plan(Self, @linear.Vec, @linear.Vec, @moonbitstack/moonmcl/contract.Budget) -> Array[@linear.Vec] raise @linear.Refused

structReedsShepp#

pub struct ReedsShepp { turning_radius : Double extent : Double }
turning_radius
Double
extent
Double

A Reeds-Shepp car.

fnReedsShepp::candidates#

pub fn ReedsShepp::candidates( self : ReedsShepp, start? : @linear.Vec, goal? : @linear.Vec, ) -> Array[ReedsSheppPath] raise @linear.Refused

Every word that joins the two poses, shortest first.

A word that cannot reach the goal returns no parameters at all, so the list holds only the ones that do; the shortest of them shares its length with any other candidate of the same total.

fnReedsShepp::distance#

pub fn ReedsShepp::distance(Self, @linear.Vec, @linear.Vec) -> Double

fnReedsShepp::interpolate#

pub fn ReedsShepp::interpolate(Self, @linear.Vec, @linear.Vec, Double) -> @linear.Vec

fnReedsShepp::new#

pub fn ReedsShepp::new( turning_radius? : Double, extent? : Double, ) -> ReedsShepp raise @linear.Refused

A Reeds-Shepp car with the given radius. extent is the half width of the box the space samples from.

fnReedsShepp::path#

pub fn ReedsShepp::path( self : ReedsShepp, start? : @linear.Vec, goal? : @linear.Vec, ) -> ReedsSheppPath raise @linear.Refused

The shortest path between two (x, y, heading) poses, reversing as needed.

fnReedsShepp::sample#

pub fn ReedsShepp::sample(Self, &@moonbitstack/moonrand/contract.Rng) -> @linear.Vec

fnReedsShepp::to_repr#

pub fn ReedsShepp::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structReedsSheppPath#

pub struct ReedsSheppPath { word : ReedsSheppWord segments : Array[ReedsSheppSegment] length : Double origin : @linear.Vec radius : Double }
word
ReedsSheppWord/ / The word the path spells.
segments
Array[ReedsSheppSegment]/ / The pieces, in the order the car drives them.
length
Double/ / The total length, in metres.
origin
@linear.Vec
radius
Double

A Reeds-Shepp path: the word it spells, its pieces, and the pose it starts from.

fnReedsSheppPath::at#

pub fn ReedsSheppPath::at( self : ReedsSheppPath, distance : Double, ) -> @linear.Vec

The pose at distance travelled along the path: an arc turns around its own centre, a straight runs along the heading, and backing up moves the car the other way without changing which way it faces.

fnReedsSheppPath::cusps#

pub fn ReedsSheppPath::cusps(self : ReedsSheppPath) -> Int32

How many times the path changes direction.

fnReedsSheppPath::to_repr#

pub fn ReedsSheppPath::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structReedsSheppSegment#

pub struct ReedsSheppSegment { turn : Double forward : Double length : Double }
turn
Double/ / 1 for a left arc, -1 for a right one, 0 for a straight.
forward
Double/ / 1 when the car drives forward along the piece, -1 when it backs up.
length
Double/ / The length of the piece, in metres.

One straight or curved piece of a Reeds-Shepp path.

fnReedsSheppSegment::to_repr#

pub fn ReedsSheppSegment::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

enumReedsSheppWord#

pub enum ReedsSheppWord { LpSpLp RpSpRp LmSmLm RmSmRm LpSpRp RpSpLp LmSmRm RmSmLm LpRmLp RpLmRp LmRpLm RmLpRm LpRmLm RpLmRm LmRpLp RmLpRp LpRpLm RpLpRm LmRmLp RmRmLp LpRpLmRm RpLpRmLm LmRmLpRp RmRmLpLp LpRmLmRp RpLmRmLp LmRpLpRm RmLpRpLm LpRmSmLm RpLmSmRm LmRpSpLp RmLpSpRp LpRmSmRm RpLmSmLm LmRpSpRp RmLpSpLp LpSpRmLm RpSpLmRm LmSmRpLp RmSmLpRp LpSpLpRm RpSpRpLm LmSmLmRp RmSmRmLp LpRmSmLmRp RpLmSmRmLp LmRpSpLpRm RmLpSpRpLm }

One of the forty-eight reversable-car path words.

fnReedsSheppWord::code#

pub fn ReedsSheppWord::code(self : ReedsSheppWord) -> Int32

The position of a word in the enumeration: family times four plus variant.

A family is one set of segment formulas and a variant is one of the four frames it is applied in, so the pair is all the table a word needs.

fnReedsSheppWord::of_code#

pub fn ReedsSheppWord::of_code(code : Int32) -> ReedsSheppWord?

The word a code names, or None outside the forty-eight.

fnReedsSheppWord::to_repr#

pub fn ReedsSheppWord::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structRrt#

pub struct Rrt { space : &@moonbitstack/moonmcl/contract.Space validity : &@moonbitstack/moonmcl/contract.Validity step : Double goal_bias : Double rng : &@moonbitstack/moonrand/contract.Rng }
space
&@contract.Space
validity
&@contract.Validity
step
Double
goal_bias
Double
rng
&@rand_contract.Rng

A rapidly-exploring random tree.

step is the length of the edge a new sample is allowed to reach, and goal_bias the chance that a sample is the goal itself rather than a random state. The generator is seeded from the planner, so a run replays exactly.

fnRrt::new#

pub fn Rrt::new( space? : &@contract.Space, validity? : &@contract.Validity, step? : Double, goal_bias? : Double, seed? : Int32, ) -> Rrt raise @linear.Refused

An RRT that extends by step and steers to the goal once every 1 / goal_bias samples.

fnRrt::plan#

pub fn Rrt::plan(Self, @linear.Vec, @linear.Vec, @moonbitstack/moonmcl/contract.Budget) -> Array[@linear.Vec] raise @linear.Refused

structRrtConnect#

pub struct RrtConnect { space : &@moonbitstack/moonmcl/contract.Space validity : &@moonbitstack/moonmcl/contract.Validity step : Double rng : &@moonbitstack/moonrand/contract.Rng }
space
&@contract.Space
validity
&@contract.Validity
step
Double
rng
&@rand_contract.Rng

An RRT grown from both ends at once: the two trees take turns reaching for each other, which closes a narrow passage far faster than one tree alone.

fnRrtConnect::new#

pub fn RrtConnect::new( space? : &@contract.Space, validity? : &@contract.Validity, step? : Double, seed? : Int32, ) -> RrtConnect raise @linear.Refused

A bidirectional RRT.

fnRrtConnect::plan#

pub fn RrtConnect::plan(Self, @linear.Vec, @linear.Vec, @moonbitstack/moonmcl/contract.Budget) -> Array[@linear.Vec] raise @linear.Refused

structRrtStar#

pub struct RrtStar { space : &@moonbitstack/moonmcl/contract.Space validity : &@moonbitstack/moonmcl/contract.Validity step : Double goal_bias : Double neighbourhood : Double rng : &@moonbitstack/moonrand/contract.Rng }
space
&@contract.Space
validity
&@contract.Validity
step
Double
goal_bias
Double
neighbourhood
Double
rng
&@rand_contract.Rng

An RRT that rewires the tree as it grows, so the path converges on the shortest one inside the budget.

fnRrtStar::new#

pub fn RrtStar::new( space? : &@contract.Space, validity? : &@contract.Validity, step? : Double, goal_bias? : Double, neighbourhood? : Double, seed? : Int32, ) -> RrtStar raise @linear.Refused

An RRT* with a rewiring radius.

fnRrtStar::plan#

pub fn RrtStar::plan(Self, @linear.Vec, @linear.Vec, @moonbitstack/moonmcl/contract.Budget) -> Array[@linear.Vec] raise @linear.Refused

Values

fnfamily_words#

pub fn family_words(family : Int32) -> Array[ReedsSheppWord]

The words of the family family, in variant order.

fngrid_path#

pub fn grid_path( grid : @graph_grid.Grid, start? : Int32, goal? : Int32, search? : GridSearch, ) -> Array[Int32] raise @linear.Refused

The shortest path between two grid cells, as node indices, from the grid package's own search.

kinematics

moonbitstack/moonmcl/kinematics

Mechanisms: the wheeled bases and their steering, the n-link planar arm with a damped inverse, the delta cell, the SCARA and the gantry.

Types

structAckermann#

pub struct Ackermann { wheelbase : Double track : Double }
wheelbase
Double
track
Double

An Ackermann steering base: the inner and outer front wheels turn by different angles about a common centre.

fnAckermann::angles#

pub fn Ackermann::angles( self : Ackermann, curvature? : Double, ) -> (Double, Double, ) -> Unit

The inner and outer steering angles for a curvature: the wheel on the inside of the turn has to turn further, by the angle its shorter radius demands.

fnAckermann::forward#

pub fn Ackermann::forward(Self, @linear.Vec) -> @linear.Vec

fnAckermann::inverse#

pub fn Ackermann::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnAckermann::jacobian#

pub fn Ackermann::jacobian(Self, @linear.Vec) -> @linear.Mat

fnAckermann::new#

pub fn Ackermann::new( wheelbase? : Double, track? : Double, ) -> Ackermann raise @linear.Refused

An Ackermann base with the given wheelbase and track.

fnAckermann::to_repr#

pub fn Ackermann::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structBicycle#

pub struct Bicycle { wheelbase : Double }
wheelbase
Double

A bicycle model: the joint space is (speed, steering angle) and the task space the body twist (vx, vy, omega).

fnBicycle::curvature#

pub fn Bicycle::curvature(self : Bicycle, steering? : Double) -> Double

The curvature a steering angle gives.

fnBicycle::forward#

pub fn Bicycle::forward(Self, @linear.Vec) -> @linear.Vec

fnBicycle::inverse#

pub fn Bicycle::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnBicycle::jacobian#

pub fn Bicycle::jacobian(Self, @linear.Vec) -> @linear.Mat

fnBicycle::new#

pub fn Bicycle::new(wheelbase? : Double) -> Bicycle raise @linear.Refused

A bicycle with the given wheelbase.

fnBicycle::steering#

pub fn Bicycle::steering(self : Bicycle, curvature? : Double) -> Double

The steering angle a curvature needs.

fnBicycle::to_repr#

pub fn Bicycle::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structDelta#

pub struct Delta { base_radius : Double platform_radius : Double upper_arm : Double lower_arm : Double }
base_radius
Double
platform_radius
Double
upper_arm
Double
lower_arm
Double

A delta robot: three parallel arms from a fixed base to a moving platform.

The joint space is the three upper-arm angles measured from horizontal and the task space the platform centre (x, y, z) under the base.

fnDelta::elbows#

pub fn Delta::elbows(self : Delta, q : @linear.Vec) -> Array[@linear.Vec]

The three elbows, in the base frame, for the upper-arm angles q.

A drawing of the cell needs the elbows as well as the platform, and the cell already computes them to solve its own forward map.

fnDelta::forward#

pub fn Delta::forward(Self, @linear.Vec) -> @linear.Vec

fnDelta::inverse#

pub fn Delta::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnDelta::jacobian#

pub fn Delta::jacobian(Self, @linear.Vec) -> @linear.Mat

fnDelta::new#

pub fn Delta::new( base_radius? : Double, platform_radius? : Double, upper_arm? : Double, lower_arm? : Double, ) -> Delta raise @linear.Refused

A delta cell with the given geometry.

fnDelta::to_repr#

pub fn Delta::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structDifferential#

pub struct Differential { wheel_radius : Double track : Double }
wheel_radius
Double
track
Double

A two-wheel differential drive.

track is the distance between the wheels and wheel_radius the radius of each. The joint space is (omega_left, omega_right) in radians per second and the task space (v, omega) in metres and radians per second.

fnDifferential::advance#

pub fn Differential::advance( self : Differential, pose? : @linear.Vec, twist? : @linear.Vec, dt? : Double, ) -> @linear.Vec

The pose after driving twist for dt seconds.

The arc is integrated exactly: a straight chord would cut the corner of every turn, and the error grows with the square of the period.

fnDifferential::forward#

pub fn Differential::forward(Self, @linear.Vec) -> @linear.Vec

fnDifferential::inverse#

pub fn Differential::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnDifferential::jacobian#

pub fn Differential::jacobian(Self, @linear.Vec) -> @linear.Mat

fnDifferential::new#

pub fn Differential::new( wheel_radius? : Double, track? : Double, ) -> Differential raise @linear.Refused

A differential drive with the given wheel radius and track width.

fnDifferential::to_repr#

pub fn Differential::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structGantry#

pub struct Gantry { track : Double }
track
Double

A gantry: two motors drive one gantry axis from either end, so the pair sets the position and the tilt of the beam.

The joint space is (x, y_left, y_right, z) and the task space (x, y, z, tilt), where y is the middle of the beam and tilt the angle the difference between its ends makes.

fnGantry::forward#

pub fn Gantry::forward(Self, @linear.Vec) -> @linear.Vec

fnGantry::inverse#

pub fn Gantry::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnGantry::jacobian#

pub fn Gantry::jacobian(Self, @linear.Vec) -> @linear.Mat

fnGantry::new#

pub fn Gantry::new(track? : Double) -> Gantry raise @linear.Refused

A gantry with the given beam length.

fnGantry::to_repr#

pub fn Gantry::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structMecanum#

pub struct Mecanum { wheel_radius : Double half_length : Double half_width : Double }
wheel_radius
Double
half_length
Double
half_width
Double

A four-wheel mecanum base. The joint space is the four wheel speeds in the order front left, front right, rear left, rear right, and the task space the body twist (vx, vy, omega).

fnMecanum::forward#

pub fn Mecanum::forward(Self, @linear.Vec) -> @linear.Vec

fnMecanum::inverse#

pub fn Mecanum::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnMecanum::jacobian#

pub fn Mecanum::jacobian(Self, @linear.Vec) -> @linear.Mat

fnMecanum::new#

pub fn Mecanum::new( wheel_radius? : Double, half_length? : Double, half_width? : Double, ) -> Mecanum raise @linear.Refused

A mecanum base with the given wheel radius and half extents.

fnMecanum::to_repr#

pub fn Mecanum::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structOmnidirectional#

pub struct Omnidirectional { wheel_radius : Double radius : Double angles : Array[Double] }
wheel_radius
Double
radius
Double
angles
Array[Double]

An omnidirectional base with three or more driven wheels on a circle.

The wheels are mounted tangentially, so each one drives along theta and the map from twist to wheel speeds is one row per wheel. With three wheels it inverts exactly; with more the inverse is the least-squares one, which spreads the effort over the wheels that can help.

fnOmnidirectional::forward#

pub fn Omnidirectional::forward(Self, @linear.Vec) -> @linear.Vec

fnOmnidirectional::inverse#

pub fn Omnidirectional::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnOmnidirectional::jacobian#

pub fn Omnidirectional::jacobian(Self, @linear.Vec) -> @linear.Mat

fnOmnidirectional::new#

pub fn Omnidirectional::new( wheel_radius? : Double, radius? : Double, angles? : ArrayView[Double], ) -> Omnidirectional raise @linear.Refused

An omnidirectional base whose wheel i sits at angles[i] radians on a circle of radius.

fnOmnidirectional::to_repr#

pub fn Omnidirectional::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structPlanarArm#

pub struct PlanarArm { lengths : Array[Double] }
lengths
Array[Double]

A planar chain of n links. The joint space is the joint angles and the task space the (x, y) of the tip.

fnPlanarArm::forward#

pub fn PlanarArm::forward(Self, @linear.Vec) -> @linear.Vec

fnPlanarArm::inverse#

pub fn PlanarArm::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnPlanarArm::jacobian#

pub fn PlanarArm::jacobian(Self, @linear.Vec) -> @linear.Mat

fnPlanarArm::jacobian_analytic#

pub fn PlanarArm::jacobian_analytic( self : PlanarArm, q : @linear.Vec, ) -> @linear.Mat

The analytic Jacobian of the arm at the joint angles q: how far the tip moves for a small change in each joint.

Link k and everything outboard of it turn with joint k, so column k is that joint's direction rotated by the total angle up to k, scaled by the reach still in front of it. Kinematics::jacobian defaults to a central difference; this is the same matrix in closed form.

fnPlanarArm::new#

pub fn PlanarArm::new( lengths? : ArrayView[Double], ) -> PlanarArm raise @linear.Refused

A planar arm with the given link lengths.

fnPlanarArm::solve#

pub fn PlanarArm::solve( self : PlanarArm, target? : @linear.Vec, seed? : @linear.Vec, iterations? : Int32, damping? : Double, tolerance? : Double, ) -> @linear.Vec raise @linear.Refused

The joint angles that put the tip on target, by damped least squares.

The damping is what makes the solve usable near a singularity: without it the Jacobian's inverse blows up and the joint velocities with it, which on a real arm is a torque the drive cannot deliver. damping is the square of the smallest singular value the solve allows.

fnPlanarArm::to_repr#

pub fn PlanarArm::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.

structScara#

pub struct Scara { upper_arm : Double forearm : Double vertical : Double }
upper_arm
Double
forearm
Double
vertical
Double

A SCARA arm: two revolute joints about the vertical axis and one prismatic joint along it.

fnScara::forward#

pub fn Scara::forward(Self, @linear.Vec) -> @linear.Vec

fnScara::inverse#

pub fn Scara::inverse(Self, @linear.Vec, seed? : @linear.Vec) -> @linear.Vec raise @linear.Refused

fnScara::jacobian#

pub fn Scara::jacobian(Self, @linear.Vec) -> @linear.Mat

fnScara::new#

pub fn Scara::new( upper_arm? : Double, forearm? : Double, vertical? : Double, ) -> Scara raise @linear.Refused

A SCARA with the two link lengths and the vertical stroke.

fnScara::to_repr#

pub fn Scara::to_repr(self) -> @debug.Repr

The @debug.Debug representation of this value.