1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//! # Discrete PID Controller
//!
//! This library provides a discrete PID (Proportional-Integral-Derivative) controller in Rust.
//!
//! If is built around three core principles: **Simulink compliance**, **best-practice
//! discrete-time compliance** (based on the [Arduino PID Library](http://brettbeauregard.com/blog/2011/04/improving-the-beginners-pid-introduction/)),
//! and a **dual API** supporting both stateful and functional use.
//!
//! ## Features
//!
//! - Respects the best practices for PID control:
//! - Configurable and fully validated PID gains.
//! - Anti reset-windup: Bounded output and integral terms
//! - Optional derivative-on-measurement to mitigate derivative kick.
//! - Bumpless tuning and (de)activation
//!
//! - Explicit support for **discrete-time** control requirements:
//! - Configurable sampling time: _It's a no-op if the controller is called before one sampling period elapsed_.
//! - Support for low-pass filtering on the derivative term.
//!
//! - Numerical compliance with Simulink's PID block:
//! - Option to use a strict causal integrator to match Simulink's behavior.
//!
//! ## Platform Support
//! This crate supports `no_std` environments by default.
//! Enable the `std` feature for richer error messages and `std::time::Instant` support.
//!
//! ## Usage
//!
//! ### PID Controller
//!
//! The PID controller is simple, easy to use with its simple API, and **fast**.
//!
//! However, like most PID controllers it embeds mutable state inside the controller: The `compute`
//! method is not pure, and its output changes as the state of the integrator and filter changes.
//! The controller **must** be `mut`.
//!
//! ```rust
//! use discrete_pid::{pid, time};
//!
//! // The PID controller is automatically initialized at the first call
//! let mut pid = pid::PidController::new_uninit(pid::PidConfig::default());
//!
//! // Freely change the PID configuration
//! assert!(pid.config_mut().set_kp(2.0).is_ok());
//!
//! let pos_feedback = 1.0;
//! let pos_setpoint = 0.0;
//!
//! // Very thin wrappers over integral timestamps are provided for you
//! let new_timestamp = time::Millis(10);
//!
//! let output = pid.compute(pos_feedback, pos_setpoint, new_timestamp, None);
//!
//! ```
//!
//! ### Functional PID Controller
//!
//! The functional PID controller holds **no** mutable state.
//!
//! In exchange, the controller lets you explicitly manage the state of the controller and the
//! `compute` method is **functionally pure**, making it exceptionally easy to test and validate,
//! or to make thread-safe. If the PID configuration is final, the controller itself can be left
//! immutable as well.
//!
//! ```rust
//! use discrete_pid::{pid, time};
//!
//! let config = pid::PidConfigBuilder::default()
//! .kp(2.0)
//! .ki(0.2)
//! .build()
//! .expect("Invalid PID config");
//! let pid = pid::FuncPidController::new(config);
//!
//! // You can pre-initialize the PID context as well
//! let timestamp = time::Millis(10);
//! let steady_state_pos_feedback = 0.5;
//! let last_output = 0.01;
//! let mut context = pid::PidContext::<time::Millis, f64>::new(
//! timestamp,
//! steady_state_pos_feedback,
//! last_output,
//! );
//!
//! let pos_feedback = 1.0;
//! let pos_setpoint = 2.0;
//! let timestamp = time::Millis(11);
//! let vel_setpoint = 0.1; // Higher-order setpoint --- feedforward
//!
//! let (output, updated_context) = pid.compute(
//! context,
//! pos_feedback,
//! pos_setpoint,
//! timestamp,
//! vel_setpoint.into(),
//! );
//! ```
//!
//! ### Plugging in your Instant type
//!
//! Timekeeping is critical to our PID controller. We abstract over time representation using a
//! minimal [`InstantLike`](time::InstantLike) trait.
//!
//! While we provide [`Millis`](time::Millis), [`Micros`](time::Micros),
//! [`SecondsF64`](time::SecondsF64) and [`StdInstant`](time::StdInstant) (with `std` feature) wrappers over common
//! time representations, you can easily opt any time type into this framework as shown below:
//!
//! ``` rust
//! use core::time::Duration;
//! use discrete_pid::pid::{PidConfig, PidController};
//! use discrete_pid::time::InstantLike;
//!
//! #[derive(Copy, Clone)]
//! struct Time {
//! sec: i32,
//! nsec: i32,
//! }
//!
//! impl InstantLike for Time {
//! fn duration_since(&self, other: Self) -> Duration {
//! let sec = self.sec - other.sec;
//! let nsec = self.nsec - other.nsec;
//! Duration::new(sec as u64, nsec as u32)
//! }
//! }
//!
//! let timestamp = Time { sec: 1, nsec: 0 };
//! let mut pid = PidController::new(PidConfig::default(), timestamp, 0.0, 0.0);
//! ```
//!
//! ## License
//! This project is licensed under the [MIT License](../LICENSE).
extern crate std;
/// The main module for the PID controller library.
/// The module containing time-related utilities to support sampling time handling
;