Skip to main content

TuningPolicy

Enum TuningPolicy 

Source
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.

Fields

§tau: f64

The time constant, s.

§

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: usize

Which 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

Source

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

Source

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.

Source

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);
Source

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

Source§

fn clone(&self) -> TuningPolicy

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Copy for TuningPolicy

Source§

impl Debug for TuningPolicy

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl PartialEq for TuningPolicy

Source§

fn eq(&self, other: &TuningPolicy) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl StructuralPartialEq for TuningPolicy

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Scalar for T
where T: 'static + Clone + PartialEq + Debug,

§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.