Skip to main content

OutputLimit

Struct OutputLimit 

Source
pub struct OutputLimit {
    pub min: Float,
    pub max: Float,
}
Expand description

Optional control output clamp.

Use this to match the command range of the real actuator, for example 0.0..1.0 for normalized heater power or -1.0..1.0 for a bidirectional motor command. The controller still reports the unsaturated value in its update output, which is useful during tuning.

Fields§

§min: Float

Minimum allowed controller output.

§max: Float

Maximum allowed controller output.

Implementations§

Source§

impl OutputLimit

Source

pub const fn new(min: Float, max: Float) -> Self

Creates a new output clamp.

Examples found in repository?
examples/second_order_position.rs (line 11)
3fn main() -> Result<(), ladrc_no_std::ConfigError> {
4    let dt = 0.001;
5    let target_position = 1.0;
6
7    let config = LadrcSecondOrderConfig::from_bandwidth(
8        dt, 2.0, // one unit of command gives roughly +2 position-units/s^2
9        12.0, 60.0,
10    )
11    .with_output_limit(OutputLimit::new(-5.0, 5.0));
12
13    let mut controller = LadrcSecondOrder::new(config)?;
14    let mut position = 0.0;
15    let mut velocity = 0.0;
16    let mut control = 0.0;
17
18    for step in 0..5_000 {
19        let out = controller.update(target_position, position);
20        control = out.control;
21
22        let load_disturbance = if step > 2_000 { -0.8 } else { 0.0 };
23        let acceleration = -1.2 * velocity - 4.0 * position + 2.0 * control + load_disturbance;
24
25        velocity += dt * acceleration;
26        position += dt * velocity;
27    }
28
29    println!("target position: {target_position:.3}");
30    println!("final position:  {position:.3}");
31    println!("final velocity:  {velocity:.3}");
32    println!("final command:   {control:.3}");
33
34    Ok(())
35}
More examples
Hide additional examples
examples/first_order_temperature.rs (line 11)
3fn main() -> Result<(), ladrc_no_std::ConfigError> {
4    let dt = 0.01;
5    let target_temperature = 55.0;
6
7    let config = LadrcFirstOrderConfig::from_bandwidth(
8        dt, 2.0, // one unit of heater command gives roughly +2 C/s initially
9        0.8, 4.0,
10    )
11    .with_output_limit(OutputLimit::new(0.0, 1.0));
12
13    let mut controller = LadrcFirstOrder::new(config)?;
14    let mut temperature = 20.0;
15    let ambient = 20.0;
16    let mut control = 0.0;
17
18    for step in 0..6_000 {
19        let out = controller.update(target_temperature, temperature);
20        control = out.control;
21
22        let open_window_disturbance = if step > 3_000 { -0.35 } else { 0.0 };
23        let plant_cooling = -0.04 * (temperature - ambient);
24        let plant_heating = 2.0 * control;
25
26        temperature += dt * (plant_cooling + plant_heating + open_window_disturbance);
27    }
28
29    println!("target temperature: {target_temperature:.2} C");
30    println!("final temperature:  {temperature:.2} C");
31    println!("final command:      {:.1} %", control * 100.0);
32
33    Ok(())
34}
examples/variable_period_position.rs (line 8)
3fn main() -> Result<(), ladrc_no_std::ConfigError> {
4    let nominal_dt = 0.001;
5    let target_position = 1.0;
6
7    let config = LadrcSecondOrderConfig::from_bandwidth(nominal_dt, 2.0, 12.0, 60.0)
8        .with_output_limit(OutputLimit::new(-5.0, 5.0));
9
10    let mut controller = LadrcSecondOrder::new(config)?;
11    let mut now_ms = 0_u64;
12    let mut position = 0.0;
13    let mut velocity = 0.0;
14    let mut control = 0.0;
15
16    controller.reset_at_millis(now_ms, position);
17
18    let poll_periods_ms = [1_u64, 2, 1, 1, 2];
19
20    for step in 0..5_000 {
21        let actual_dt_ms = poll_periods_ms[step % poll_periods_ms.len()];
22        let actual_dt = actual_dt_ms as f32 * 0.001;
23        now_ms += actual_dt_ms;
24
25        let out = controller.update_at_millis(now_ms, target_position, position)?;
26        control = out.control;
27
28        let load_disturbance = if step > 2_000 { -0.8 } else { 0.0 };
29        let acceleration = -1.2 * velocity - 4.0 * position + 2.0 * control + load_disturbance;
30
31        velocity += actual_dt * acceleration;
32        position += actual_dt * velocity;
33    }
34
35    println!("target position: {target_position:.3}");
36    println!("final position:  {position:.3}");
37    println!("final velocity:  {velocity:.3}");
38    println!("final command:   {control:.3}");
39    println!("final time:      {:.3} s", now_ms as f32 * 0.001);
40
41    Ok(())
42}
Source

pub fn apply(self, value: Float) -> Float

Applies the clamp to value.

Trait Implementations§

Source§

impl Clone for OutputLimit

Source§

fn clone(&self) -> OutputLimit

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 OutputLimit

Source§

impl Debug for OutputLimit

Source§

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

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

impl PartialEq for OutputLimit

Source§

fn eq(&self, other: &OutputLimit) -> 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 OutputLimit

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

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.