pub enum TuningPolicy {
Slew {
tau: f64,
},
Step,
StepUpGateDown {
rate_word: usize,
},
}Expand description
How the loop is to move an accepted value into effect. Carried here rather than in the loop so that a published schema can explain a slider’s behaviour without a second table.
Variants§
Slew
First-order slew toward the target over tau seconds. The parameter multiplies a
generally-nonzero state, so a step in it is a step in the torque.
Step
Applied whole on the cycle it arrives: either nothing nonzero is multiplied, or the product is bounded by the ripple the parameter exists to shape.
StepUpGateDown
Raised on the cycle it arrives, lowered no faster than the next order’s limit: the budget’s velocity at the acceleration in force, its acceleration at the jerk.
The generator re-plans continuously into a wider budget – it stores no plan, only
(p, v, a, target, limits) – but it clamps its stored velocity and acceleration into a
narrower one, on the next cycle’s re-anchoring and again at the end of every step
(Otg::set_limits says where). A velocity truncated by
dv in one cycle is dv / dt of acceleration in the command, which is an impulse
rather than a re-plan. Descending no faster than the next order holds each clamp to one
cycle of that order, which is the generator’s own bound.
LiveTuning::slew_toward runs the gate on the budget as a norm, and whoever hands the
generator its per-axis limits scales the gated value. That is the same walk: the scaling
is one positive factor per axis, so it carries the rate with it.
Fields
rate_word: usizeWhich word’s value in force the descent is measured at: the index into
LiveTuning::BOUNDS of the next order of the same budget, whose unit is this
word’s per second. Named here rather than left to the reader as “the next word”,
because a caller that watches a descent – descent, a published
schema, a panel drawing the ramp – would otherwise have to know that rule too, and
then there would be two of it.
Implementations§
Source§impl TuningPolicy
impl TuningPolicy
Sourcepub fn rate_word(self) -> Option<usize>
pub fn rate_word(self) -> Option<usize>
Which word of LiveTuning::to_words holds this one’s descent rate, for the gated
words; None for every other policy, which has no ramp.
Source§impl TuningPolicy
impl TuningPolicy
Sourcepub fn slew_gain(self, dt: f64) -> f64
pub fn slew_gain(self, dt: f64) -> f64
The fraction of the remaining gap one cycle of dt seconds closes: 1 - e^(-dt/tau)
for a slewed field, and 1 – the whole gap, on the cycle it arrives – for every other.
A non-positive dt or tau has no filter to run and takes the value whole.
Call it once per session, not per cycle: it holds the only exp on this path, and
LiveTuning::slew_gains is the form the loop wants.
Sourcepub fn remaining(self, elapsed: f64) -> f64
pub fn remaining(self, elapsed: f64) -> f64
The fraction of an accepted change still to go elapsed seconds after it was
accepted: 1 at acceptance, e^(-elapsed/tau) from there, and never negative. It counts
down; a caller showing the fraction already reached would draw every slew backwards.
Zero for Step, which is in force on the first cycle after it is accepted
and so has nothing left to report, and zero for StepUpGateDown,
which is that on the way up. A gated field on the way down is not a filter at all
but a ramp at the next order’s limit, and what is left of one is seconds rather than a
fraction of an elapsed time: descent is that half.
This is the loop’s filter read off a clock instead of a cycle counter: elapsed seconds
of dt cycles leave (1 - slew_gain(dt))^(elapsed/dt) of the gap. It needs
nothing from the realtime thread, which is why the tuning slot has one writer and no
reply.
use franka::robot::target_control::{LiveTuning, TuningPolicy, SLEW_TAU};
let policy = LiveTuning::BOUNDS[0].policy;
assert_eq!(policy, TuningPolicy::Slew { tau: SLEW_TAU });
assert_eq!(policy.remaining(0.0), 1.0);
// One time constant leaves 1/e of the change to come -- not the 1 - 1/e it has made.
assert!((policy.remaining(SLEW_TAU) - 0.367_879_441).abs() < 1e-9);
assert!(policy.remaining(3.0 * SLEW_TAU) < 0.05);
assert_eq!(TuningPolicy::Step.remaining(0.0), 0.0);Sourcepub fn descent(self, from: f64, to: f64, rate: f64) -> f64
pub fn descent(self, from: f64, to: f64, rate: f64) -> f64
How long, in seconds, a gated word takes to walk from from
down to to at rate units a second: the other half of
remaining, for the words that ramp rather than filter.
Zero for a raise, which is in force on the cycle it arrives, and zero for every other policy, which has no ramp. Infinite where the rate is not a rate: a word whose next order stands at zero never descends.
rate is the value in force of the word rate_word names —
read it off the table rather than from the field beside it, which is the rule this
method exists so that nobody writes down twice. The answer is exact while that word is
itself at rest; a descent whose rate is moving at the same time (both budget sliders
dragged at once) walks at whatever the rate word holds each cycle, and this is then the
estimate its value at the start implies.
use franka::robot::target_control::{LiveTuning, TuningPolicy};
// The translational budget's velocity descends at its own acceleration.
let velocity = LiveTuning::BOUNDS[19].policy;
let rate_word = velocity.rate_word().expect("the velocity budget is gated");
assert_eq!(LiveTuning::BOUNDS[rate_word].name, "budget");
assert_eq!(LiveTuning::BOUNDS[rate_word].index, Some(1));
// From 0.9 m/s to 0.3 m/s at the default 0.5 m/s^2 is 1.2 s of ramp.
assert!((velocity.descent(0.9, 0.3, 0.5) - 1.2).abs() < 1e-12);
// Raising is not a ramp, and neither is a stepped word.
assert_eq!(velocity.descent(0.3, 0.9, 0.5), 0.0);
assert_eq!(TuningPolicy::Step.descent(0.9, 0.3, 0.5), 0.0);Trait Implementations§
Source§impl Clone for TuningPolicy
impl Clone for TuningPolicy
Source§fn clone(&self) -> TuningPolicy
fn clone(&self) -> TuningPolicy
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreimpl Copy for TuningPolicy
Source§impl Debug for TuningPolicy
impl Debug for TuningPolicy
Source§impl PartialEq for TuningPolicy
impl PartialEq for TuningPolicy
Source§fn eq(&self, other: &TuningPolicy) -> bool
fn eq(&self, other: &TuningPolicy) -> bool
self and other values to be equal, and is used by ==.impl StructuralPartialEq for TuningPolicy
Auto Trait Implementations§
impl Freeze for TuningPolicy
impl RefUnwindSafe for TuningPolicy
impl Send for TuningPolicy
impl Sync for TuningPolicy
impl Unpin for TuningPolicy
impl UnsafeUnpin for TuningPolicy
impl UnwindSafe for TuningPolicy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
impl<T> Scalar for T
§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read more§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.