1212//! pid.p(10.0, 100.0);
1313//!
1414//! // Input a measurement with an error of 5.0 from our setpoint
15+ //!
16+ //! #[cfg(feature = "dt")]
1517//! let output = pid.next_control_output(10.0, 1.0);
18+ //! #[cfg(not(feature = "dt"))]
19+ //! let output = pid.next_control_output(10.0);
1620//!
1721//! // Show that the error is correct by multiplying by our kp
1822//! assert_eq!(output.output, 50.0); // <--
1923//! assert_eq!(output.p, 50.0);
2024//!
2125//! // It won't change on repeat; the controller is proportional-only
26+ //!
27+ //! #[cfg(feature = "dt")]
2228//! let output = pid.next_control_output(10.0, 1.0);
29+ //! #[cfg(not(feature = "dt"))]
30+ //! let output = pid.next_control_output(10.0);
31+ //!
2332//! assert_eq!(output.output, 50.0); // <--
2433//! assert_eq!(output.p, 50.0);
2534//!
2635//! // Add a new integral term to the controller and input again
2736//! pid.i(1.0, 100.0);
37+ //!
38+ //! #[cfg(feature = "dt")]
2839//! let output = pid.next_control_output(10.0, 1.0);
40+ //! #[cfg(not(feature = "dt"))]
41+ //! let output = pid.next_control_output(10.0);
2942//!
3043//! // Now that the integral makes the controller stateful, it will change
3144//! assert_eq!(output.output, 55.0); // <--
3447//!
3548//! // Add our final derivative term and match our setpoint target
3649//! pid.d(2.0, 100.0);
50+ //! #[cfg(feature = "dt")]
3751//! let output = pid.next_control_output(15.0, 1.0);
52+ //! #[cfg(not(feature = "dt"))]
53+ //! let output = pid.next_control_output(15.0);
3854//!
3955//! // The output will now say to go down due to the derivative
4056//! assert_eq!(output.output, -5.0); // <--
@@ -79,7 +95,10 @@ impl<T: PartialOrd + num_traits::Signed + Copy> Number for T {}
7995/// p_controller.p(10.0, 100.0);
8096///
8197/// // Get first output
98+ /// #[cfg(feature = "dt")]
8299/// let p_output = p_controller.next_control_output(400.0, 1.0);
100+ /// #[cfg(not(feature = "dt"))]
101+ /// let p_output = p_controller.next_control_output(400.0);
83102/// ```
84103///
85104/// This controller would give you set a proportional controller to `10.0` with a target of `15.0` and an output limit of `100.0` per [output](Self::next_control_output) iteration. The same controller with a full PID system built in looks like:
@@ -92,7 +111,10 @@ impl<T: PartialOrd + num_traits::Signed + Copy> Number for T {}
92111/// full_controller.p(10.0, 100.0).i(4.5, 100.0).d(0.25, 100.0);
93112///
94113/// // Get first output
114+ /// #[cfg(feature = "dt")]
95115/// let full_output = full_controller.next_control_output(400.0, 1.0);
116+ /// #[cfg(not(feature = "dt"))]
117+ /// let full_output = full_controller.next_control_output(400.0);
96118/// ```
97119///
98120/// This [`next_control_output`](Self::next_control_output) method is what's used to input new values into the controller to tell it what the current state of the system is. In the examples above it's only being used once, but realistically this will be a hot method. Please see [ControlOutput] for examples of how to handle these outputs; it's quite straight forward and mirrors the values of this structure in some ways.
@@ -141,7 +163,11 @@ pub struct Pid<T: Number> {
141163/// pid.p(10.0, 100.0).i(1.0, 100.0).d(2.0, 100.0);
142164///
143165/// // Input an example value and get a report for an output iteration
166+ /// #[cfg(feature = "dt")]
144167/// let output = pid.next_control_output(26.2456, 1.0);
168+ /// #[cfg(not(feature = "dt"))]
169+ /// let output = pid.next_control_output(26.2456);
170+ ///
145171/// println!("P: {}\nI: {}\nD: {}\nFinal Output: {}", output.p, output.i, output.d, output.output);
146172/// ```
147173#[ derive( Debug , PartialEq , Eq ) ]
@@ -210,6 +236,7 @@ where
210236 self
211237 }
212238
239+ #[ cfg( feature = "dt" ) ]
213240 /// Given a new measurement and dt, calculates the next [control output](ControlOutput).
214241 ///
215242 /// # Panics
@@ -259,6 +286,55 @@ where
259286 }
260287 }
261288
289+ #[ cfg( not( feature = "dt" ) ) ]
290+ /// Given a new measurement, calculates the next [control output](ControlOutput).
291+ ///
292+ /// # Panics
293+ ///
294+ /// - If a setpoint has not been set via `update_setpoint()`.
295+ pub fn next_control_output ( & mut self , measurement : T ) -> ControlOutput < T > {
296+ // Calculate the error between the ideal setpoint and the current
297+ // measurement to compare against
298+ let error = self . setpoint - measurement;
299+
300+ // Calculate the proportional term and limit to it's individual limit
301+ let p_unbounded = error * self . kp ;
302+ let p = apply_limit ( self . p_limit , p_unbounded) ;
303+
304+ // Mitigate output jumps when ki(t) != ki(t-1).
305+ // While it's standard to use an error_integral that's a running sum of
306+ // just the error (no ki), because we support ki changing dynamically,
307+ // we store the entire term so that we don't need to remember previous
308+ // ki values.
309+ self . integral_term = self . integral_term + error * self . ki ;
310+
311+ // Mitigate integral windup: Don't want to keep building up error
312+ // beyond what i_limit will allow.
313+ self . integral_term = apply_limit ( self . i_limit , self . integral_term ) ;
314+
315+ // Mitigate derivative kick: Use the derivative of the measurement
316+ // rather than the derivative of the error.
317+ let d_unbounded = -match self . prev_measurement . as_ref ( ) {
318+ Some ( prev_measurement) => measurement - * prev_measurement,
319+ None => T :: zero ( ) ,
320+ } * self . kd ;
321+ self . prev_measurement = Some ( measurement) ;
322+ let d = apply_limit ( self . d_limit , d_unbounded) ;
323+
324+ // Calculate the final output by adding together the PID terms, then
325+ // apply the final defined output limit
326+ let output = p + self . integral_term + d;
327+ let output = apply_limit ( self . output_limit , output) ;
328+
329+ // Return the individual term's contributions and the final output
330+ ControlOutput {
331+ p,
332+ i : self . integral_term ,
333+ d,
334+ output,
335+ }
336+ }
337+
262338 /// Resets the integral term back to zero, this may drastically change the
263339 /// control output.
264340 pub fn reset_integral_term ( & mut self ) {
@@ -283,6 +359,32 @@ mod tests {
283359 use super :: Pid ;
284360 use crate :: ControlOutput ;
285361
362+ /// Macro to call Pid::next_control_output() with the correct signature
363+ #[ cfg( feature = "dt" ) ]
364+ macro_rules! pid_next_control_output {
365+ ( $self: ident, $measurement: expr, $dt: expr) => {
366+ $self. next_control_output( $measurement, $dt)
367+ } ;
368+ ( $self: ident, $measurement: expr) => {
369+ // If the dt feature is enabled, we call the function with dt = 1.0
370+ #[ cfg( feature = "dt" ) ]
371+ $self. next_control_output( $measurement, 1.0 )
372+ } ;
373+ }
374+
375+ /// Macro to call Pid::next_control_output() with the correct signature
376+ #[ cfg( not( feature = "dt" ) ) ]
377+ macro_rules! pid_next_control_output {
378+ ( $self: ident, $measurement: expr, $dt: expr) => {
379+ // If the dt feature is not enabled, we ignore the dt argument
380+ $self. next_control_output( $measurement)
381+ } ;
382+ ( $self: ident, $measurement: expr) => {
383+ #[ cfg( feature = "dt" ) ]
384+ $self. next_control_output( $measurement)
385+ } ;
386+ }
387+
286388 /// Proportional-only controller operation and limits
287389 #[ test]
288390 fn proportional ( ) {
@@ -291,11 +393,11 @@ mod tests {
291393 assert_eq ! ( pid. setpoint, 10.0 ) ;
292394
293395 // Test simple proportional
294- assert_eq ! ( pid . next_control_output ( 0.0 , 1.0 ) . output, 20.0 ) ;
396+ assert_eq ! ( pid_next_control_output! ( pid , 0.0 , 1.0 ) . output, 20.0 ) ;
295397
296398 // Test proportional limit
297399 pid. p_limit = 10.0 ;
298- assert_eq ! ( pid . next_control_output ( 0.0 , 1.0 ) . output, 10.0 ) ;
400+ assert_eq ! ( pid_next_control_output! ( pid , 0.0 , 1.0 ) . output, 10.0 ) ;
299401 }
300402
301403 /// Derivative-only controller operation and limits
@@ -305,14 +407,14 @@ mod tests {
305407 pid. p ( 0.0 , 100.0 ) . i ( 0.0 , 100.0 ) . d ( 2.0 , 100.0 ) ;
306408
307409 // Test that there's no derivative since it's the first measurement
308- assert_eq ! ( pid . next_control_output ( 0.0 , 1.0 ) . output, 0.0 ) ;
410+ assert_eq ! ( pid_next_control_output! ( pid , 0.0 , 1.0 ) . output, 0.0 ) ;
309411
310412 // Test that there's now a derivative
311- assert_eq ! ( pid . next_control_output ( 5.0 , 1.0 ) . output, -10.0 ) ;
413+ assert_eq ! ( pid_next_control_output! ( pid , 5.0 , 1.0 ) . output, -10.0 ) ;
312414
313415 // Test derivative limit
314416 pid. d_limit = 5.0 ;
315- assert_eq ! ( pid . next_control_output ( 10.0 , 1.0 ) . output, -5.0 ) ;
417+ assert_eq ! ( pid_next_control_output! ( pid , 10.0 , 1.0 ) . output, -5.0 ) ;
316418 }
317419
318420 /// Integral-only controller operation and limits
@@ -322,26 +424,26 @@ mod tests {
322424 pid. p ( 0.0 , 100.0 ) . i ( 2.0 , 100.0 ) . d ( 0.0 , 100.0 ) ;
323425
324426 // Test basic integration
325- assert_eq ! ( pid . next_control_output ( 0.0 , 1.0 ) . output, 20.0 ) ;
326- assert_eq ! ( pid . next_control_output ( 0.0 , 1.0 ) . output, 40.0 ) ;
327- assert_eq ! ( pid . next_control_output ( 5.0 , 1.0 ) . output, 50.0 ) ;
427+ assert_eq ! ( pid_next_control_output! ( pid , 0.0 , 1.0 ) . output, 20.0 ) ;
428+ assert_eq ! ( pid_next_control_output! ( pid , 0.0 , 1.0 ) . output, 40.0 ) ;
429+ assert_eq ! ( pid_next_control_output! ( pid , 5.0 , 1.0 ) . output, 50.0 ) ;
328430
329431 // Test limit
330432 pid. i_limit = 50.0 ;
331- assert_eq ! ( pid . next_control_output ( 5.0 , 1.0 ) . output, 50.0 ) ;
433+ assert_eq ! ( pid_next_control_output! ( pid , 5.0 , 1.0 ) . output, 50.0 ) ;
332434 // Test that limit doesn't impede reversal of error integral
333- assert_eq ! ( pid . next_control_output ( 15.0 , 1.0 ) . output, 40.0 ) ;
435+ assert_eq ! ( pid_next_control_output! ( pid , 15.0 , 1.0 ) . output, 40.0 ) ;
334436
335437 // Test that error integral accumulates negative values
336438 let mut pid2 = Pid :: new ( -10.0 , 100.0 ) ;
337439 pid2. p ( 0.0 , 100.0 ) . i ( 2.0 , 100.0 ) . d ( 0.0 , 100.0 ) ;
338- assert_eq ! ( pid2 . next_control_output ( 0.0 , 1.0 ) . output, -20.0 ) ;
339- assert_eq ! ( pid2 . next_control_output ( 0.0 , 1.0 ) . output, -40.0 ) ;
440+ assert_eq ! ( pid_next_control_output! ( pid2 , 0.0 , 1.0 ) . output, -20.0 ) ;
441+ assert_eq ! ( pid_next_control_output! ( pid2 , 0.0 , 1.0 ) . output, -40.0 ) ;
340442
341443 pid2. i_limit = 50.0 ;
342- assert_eq ! ( pid2 . next_control_output ( -5.0 , 1.0 ) . output, -50.0 ) ;
444+ assert_eq ! ( pid_next_control_output! ( pid2 , -5.0 , 1.0 ) . output, -50.0 ) ;
343445 // Test that limit doesn't impede reversal of error integral
344- assert_eq ! ( pid2 . next_control_output ( -15.0 , 1.0 ) . output, -40.0 ) ;
446+ assert_eq ! ( pid_next_control_output! ( pid2 , -15.0 , 1.0 ) . output, -40.0 ) ;
345447 }
346448
347449 /// Checks that a full PID controller's limits work properly through multiple output iterations
@@ -350,11 +452,11 @@ mod tests {
350452 let mut pid = Pid :: new ( 10.0 , 1.0 ) ;
351453 pid. p ( 1.0 , 100.0 ) . i ( 0.0 , 100.0 ) . d ( 0.0 , 100.0 ) ;
352454
353- let out = pid . next_control_output ( 0.0 , 1.0 ) ;
455+ let out = pid_next_control_output ! ( pid , 0.0 , 1.0 ) ;
354456 assert_eq ! ( out. p, 10.0 ) ; // 1.0 * 10.0
355457 assert_eq ! ( out. output, 1.0 ) ;
356458
357- let out = pid . next_control_output ( 20.0 , 1.0 ) ;
459+ let out = pid_next_control_output ! ( pid , 20.0 , 1.0 ) ;
358460 assert_eq ! ( out. p, -10.0 ) ; // 1.0 * (10.0 - 20.0)
359461 assert_eq ! ( out. output, -1.0 ) ;
360462 }
@@ -365,25 +467,25 @@ mod tests {
365467 let mut pid = Pid :: new ( 10.0 , 100.0 ) ;
366468 pid. p ( 1.0 , 100.0 ) . i ( 0.1 , 100.0 ) . d ( 1.0 , 100.0 ) ;
367469
368- let out = pid . next_control_output ( 0.0 , 1.0 ) ;
470+ let out = pid_next_control_output ! ( pid , 0.0 , 1.0 ) ;
369471 assert_eq ! ( out. p, 10.0 ) ; // 1.0 * 10.0
370472 assert_eq ! ( out. i, 1.0 ) ; // 0.1 * 10.0
371473 assert_eq ! ( out. d, 0.0 ) ; // -(1.0 * 0.0)
372474 assert_eq ! ( out. output, 11.0 ) ;
373475
374- let out = pid . next_control_output ( 5.0 , 1.0 ) ;
476+ let out = pid_next_control_output ! ( pid , 5.0 , 1.0 ) ;
375477 assert_eq ! ( out. p, 5.0 ) ; // 1.0 * 5.0
376478 assert_eq ! ( out. i, 1.5 ) ; // 0.1 * (10.0 + 5.0)
377479 assert_eq ! ( out. d, -5.0 ) ; // -(1.0 * 5.0)
378480 assert_eq ! ( out. output, 1.5 ) ;
379481
380- let out = pid . next_control_output ( 11.0 , 1.0 ) ;
482+ let out = pid_next_control_output ! ( pid , 11.0 , 1.0 ) ;
381483 assert_eq ! ( out. p, -1.0 ) ; // 1.0 * -1.0
382484 assert_eq ! ( out. i, 1.4 ) ; // 0.1 * (10.0 + 5.0 - 1)
383485 assert_eq ! ( out. d, -6.0 ) ; // -(1.0 * 6.0)
384486 assert_eq ! ( out. output, -5.6 ) ;
385487
386- let out = pid . next_control_output ( 10.0 , 1.0 ) ;
488+ let out = pid_next_control_output ! ( pid , 10.0 , 1.0 ) ;
387489 assert_eq ! ( out. p, 0.0 ) ; // 1.0 * 0.0
388490 assert_eq ! ( out. i, 1.4 ) ; // 0.1 * (10.0 + 5.0 - 1.0 + 0.0)
389491 assert_eq ! ( out. d, 1.0 ) ; // -(1.0 * -1.0)
@@ -402,8 +504,8 @@ mod tests {
402504
403505 for _ in 0 ..5 {
404506 assert_eq ! (
405- pid_f32 . next_control_output ( 0.0 , 1.0 ) . output,
406- pid_f64 . next_control_output ( 0.0 , 1.0 ) . output as f32
507+ pid_next_control_output! ( pid_f32 , 0.0 , 1.0 ) . output,
508+ pid_next_control_output! ( pid_f64 , 0.0 , 1.0 ) . output as f32
407509 ) ;
408510 }
409511 }
@@ -420,8 +522,8 @@ mod tests {
420522
421523 for _ in 0 ..5 {
422524 assert_eq ! (
423- pid_i32 . next_control_output ( 0 , 1 ) . output,
424- pid_i8 . next_control_output ( 0i8 , 1i8 ) . output as i32
525+ pid_next_control_output! ( pid_i32 , 0 , 1 ) . output,
526+ pid_next_control_output! ( pid_i8 , 0i8 , 1i8 ) . output as i32
425527 ) ;
426528 }
427529 }
@@ -432,7 +534,7 @@ mod tests {
432534 let mut pid = Pid :: new ( 10.0 , 100.0 ) ;
433535 pid. p ( 1.0 , 100.0 ) . i ( 0.1 , 100.0 ) . d ( 1.0 , 100.0 ) ;
434536
435- let out = pid . next_control_output ( 0.0 , 1.0 ) ;
537+ let out = pid_next_control_output ! ( pid , 0.0 , 1.0 ) ;
436538 assert_eq ! ( out. p, 10.0 ) ; // 1.0 * 10.0
437539 assert_eq ! ( out. i, 1.0 ) ; // 0.1 * 10.0
438540 assert_eq ! ( out. d, 0.0 ) ; // -(1.0 * 0.0)
@@ -441,7 +543,7 @@ mod tests {
441543 pid. setpoint ( 0.0 ) ;
442544
443545 assert_eq ! (
444- pid . next_control_output ( 0.0 , 1.0 ) ,
546+ pid_next_control_output! ( pid , 0.0 , 1.0 ) ,
445547 ControlOutput {
446548 p: 0.0 ,
447549 i: 1.0 ,
@@ -457,7 +559,7 @@ mod tests {
457559 let mut pid = Pid :: new ( 10.0f32 , -10.0 ) ;
458560 pid. p ( 1.0 , -50.0 ) . i ( 1.0 , -50.0 ) . d ( 1.0 , -50.0 ) ;
459561
460- let out = pid . next_control_output ( 0.0 , 1.0 ) ;
562+ let out = pid_next_control_output ! ( pid , 0.0 , 1.0 ) ;
461563 assert_eq ! ( out. p, 10.0 ) ;
462564 assert_eq ! ( out. i, 10.0 ) ;
463565 assert_eq ! ( out. d, 0.0 ) ;
0 commit comments