#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::rc::Rc;
#[cfg(feature = "alloc")]
use core::cell::RefCell;
#[cfg(feature = "alloc")]
use rrtk::streams::converters::*;
#[cfg(feature = "alloc")]
use rrtk::streams::math::*;
#[cfg(feature = "alloc")]
use rrtk::*;
#[cfg(feature = "alloc")]
struct StreamPID {
output: SumStream<f32, 3, Box<dyn Getter<f32, ()>>, ()>,
}
#[cfg(feature = "alloc")]
impl StreamPID {
pub fn new(
input: Rc<RefCell<dyn Getter<f32, ()>>>,
setpoint: f32,
kp: f32,
ki: f32,
kd: f32,
) -> Self {
let time_getter = Rc::new(RefCell::new(TimeGetterFromGetter::new(input.clone(), ())));
let setpoint = ConstantGetter::new(time_getter.clone(), setpoint);
let kp = ConstantGetter::new(time_getter.clone(), kp);
let ki = ConstantGetter::new(time_getter.clone(), ki);
let kd = ConstantGetter::new(time_getter.clone(), kd);
let error = Rc::new(RefCell::new(DifferenceStream::new(setpoint, input.clone())));
let int = Rc::new(RefCell::new(IntegralStream::new(Rc::clone(&error))));
let drv = Rc::new(RefCell::new(DerivativeStream::new(Rc::clone(&error))));
let int_zeroer = NoneToValue::new(int.clone(), time_getter.clone(), 0.0);
let drv_zeroer = NoneToValue::new(drv.clone(), time_getter.clone(), 0.0);
let kp_mul = Product2::new(kp, error.clone());
let ki_mul = Product2::new(ki, int_zeroer);
let kd_mul = Product2::new(kd, drv_zeroer);
let output = SumStream::new([
Box::new(kp_mul) as Box<dyn Getter<f32, ()>>,
Box::new(ki_mul) as Box<dyn Getter<f32, ()>>,
Box::new(kd_mul) as Box<dyn Getter<f32, ()>>,
]);
Self { output: output }
}
}
#[cfg(feature = "alloc")]
impl Getter<f32, ()> for StreamPID {
fn get(&self) -> Output<f32, ()> {
self.output.get()
}
}
#[cfg(feature = "alloc")]
impl Updatable<()> for StreamPID {
fn update(&mut self) -> NothingOrError<()> {
self.output.update()?;
Ok(())
}
}
#[cfg(feature = "alloc")]
struct MyStream {
time: Time,
}
#[cfg(feature = "alloc")]
impl MyStream {
pub fn new() -> Self {
Self { time: Time::ZERO }
}
}
#[cfg(feature = "alloc")]
impl Getter<f32, ()> for MyStream {
fn get(&self) -> Output<f32, ()> {
Ok(Some(Datum::new(
self.time,
self.time.as_seconds_f32() * 0.5,
)))
}
}
#[cfg(feature = "alloc")]
impl Updatable<()> for MyStream {
fn update(&mut self) -> NothingOrError<()> {
self.time += Time::from_nanoseconds(2_000_000_000);
Ok(())
}
}
#[cfg(feature = "alloc")]
fn main() {
const SETPOINT: f32 = 5.0;
const KP: f32 = 1.0;
const KI: f32 = 0.01;
const KD: f32 = 0.1;
println!("PID Controller using RRTK Streams");
println!("kp = {:?}; ki = {:?}; kd = {:?}", KP, KI, KD);
let input = Rc::new(RefCell::new(MyStream::new())) as Rc<RefCell<dyn Getter<f32, ()>>>;
let mut stream = StreamPID::new(input.clone(), SETPOINT, KP, KI, KD);
stream.update().unwrap();
println!(
"time: {:?}; setpoint: {:?}; process: {:?}; command: {:?}",
stream.get().unwrap().unwrap().time.as_nanoseconds(),
SETPOINT,
input.borrow().get().unwrap().unwrap().value,
stream.get().unwrap().unwrap().value
);
for _ in 0..6 {
input.borrow_mut().update().unwrap();
stream.update().unwrap();
println!(
"time: {:?}; setpoint: {:?}; process: {:?}; command: {:?}",
stream.get().unwrap().unwrap().time,
SETPOINT,
input.borrow().get().unwrap().unwrap().value,
stream.get().unwrap().unwrap().value
);
}
}
#[cfg(not(feature = "alloc"))]
fn main() {
println!(
"Enable the `alloc` feature to run this example.\nAssuming you're using Cargo, add the `--features alloc` flag to your command."
);
}