#[cfg(feature = "alloc")]
use rrtk::streams::converters::*;
#[cfg(feature = "alloc")]
use rrtk::streams::math::*;
#[cfg(feature = "alloc")]
use rrtk::*;
#[cfg(feature = "alloc")]
struct StreamPID {
int: Reference<dyn Getter<Quantity, ()>>,
drv: Reference<dyn Getter<Quantity, ()>>,
pro_float_maker: Reference<dyn Getter<f32, ()>>,
int_float_maker: Reference<dyn Getter<f32, ()>>,
drv_float_maker: Reference<dyn Getter<f32, ()>>,
output: SumStream<f32, 3, ()>,
}
#[cfg(feature = "alloc")]
impl StreamPID {
pub fn new(
input: Reference<dyn Getter<Quantity, ()>>,
setpoint: Quantity,
kp: Quantity,
ki: Quantity,
kd: Quantity,
) -> Self {
let time_getter = rc_ref_cell_reference(TimeGetterFromGetter::new(input.clone()));
let setpoint = rc_ref_cell_reference(ConstantGetter::new(time_getter.clone(), setpoint));
let kp = rc_ref_cell_reference(ConstantGetter::new(time_getter.clone(), kp));
let ki = rc_ref_cell_reference(ConstantGetter::new(time_getter.clone(), ki));
let kd = rc_ref_cell_reference(ConstantGetter::new(time_getter.clone(), kd));
let error = rc_ref_cell_reference(DifferenceStream::new(setpoint.clone(), input.clone()));
let int = rc_ref_cell_reference(IntegralStream::new(error.clone()));
let drv = rc_ref_cell_reference(DerivativeStream::new(error.clone()));
let int_zeroer = rc_ref_cell_reference(NoneToValue::new(
int.clone(),
time_getter.clone(),
Quantity::new(0.0, MILLIMETER),
));
let drv_zeroer = rc_ref_cell_reference(NoneToValue::new(
drv.clone(),
time_getter.clone(),
Quantity::new(0.0, MILLIMETER),
));
let kp_mul = rc_ref_cell_reference(ProductStream::new([
to_dyn!(Getter<Quantity, ()>, kp.clone()),
to_dyn!(Getter<Quantity, ()>, error.clone()),
]));
let pro_float_maker = rc_ref_cell_reference(QuantityToFloat::new(kp_mul));
let ki_mul = rc_ref_cell_reference(ProductStream::new([
to_dyn!(Getter<Quantity, ()>, ki.clone()),
to_dyn!(Getter<Quantity, ()>, int_zeroer.clone()),
]));
let int_float_maker = rc_ref_cell_reference(QuantityToFloat::new(ki_mul));
let kd_mul = rc_ref_cell_reference(ProductStream::new([
to_dyn!(Getter<Quantity, ()>, kd.clone()),
to_dyn!(Getter<Quantity, ()>, drv_zeroer.clone()),
]));
let drv_float_maker = rc_ref_cell_reference(QuantityToFloat::new(kd_mul));
let output = SumStream::new([
to_dyn!(Getter<f32, ()>, pro_float_maker.clone()),
to_dyn!(Getter<f32, ()>, int_float_maker.clone()),
to_dyn!(Getter<f32, ()>, drv_float_maker.clone()),
]);
Self {
int: to_dyn!(Getter<Quantity, ()>, int),
drv: to_dyn!(Getter<Quantity, ()>, drv),
pro_float_maker: to_dyn!(Getter<f32, ()>, pro_float_maker),
int_float_maker: to_dyn!(Getter<f32, ()>, int_float_maker),
drv_float_maker: to_dyn!(Getter<f32, ()>, drv_float_maker),
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.int.borrow_mut().update()?;
self.drv.borrow_mut().update()?;
self.pro_float_maker.borrow_mut().update()?;
self.int_float_maker.borrow_mut().update()?;
self.drv_float_maker.borrow_mut().update()?;
Ok(())
}
}
#[cfg(feature = "alloc")]
struct MyStream {
time: Time,
}
#[cfg(feature = "alloc")]
impl MyStream {
pub fn new() -> Self {
Self { time: Time(0) }
}
}
#[cfg(feature = "alloc")]
impl Getter<Quantity, ()> for MyStream {
fn get(&self) -> Output<Quantity, ()> {
Ok(Some(Datum::new(
self.time,
Quantity::from(self.time) * Quantity::new(0.5, MILLIMETER_PER_SECOND),
)))
}
}
#[cfg(feature = "alloc")]
impl Updatable<()> for MyStream {
fn update(&mut self) -> NothingOrError<()> {
self.time += Time(2_000_000_000);
Ok(())
}
}
#[cfg(feature = "alloc")]
fn main() {
const SETPOINT: Quantity = Quantity::new(5.0, MILLIMETER);
const KP: Quantity = Quantity::dimensionless(1.0);
const KI: Quantity = Quantity::dimensionless(0.01);
const KD: Quantity = Quantity::dimensionless(0.1);
println!("PID Controller using RRTK Streams");
println!(
"kp = {:?}; ki = {:?}; kd = {:?}",
KP.value, KI.value, KD.value
);
let input = to_dyn!(Getter<Quantity, ()>, rc_ref_cell_reference(MyStream::new()));
let mut stream = StreamPID::new(input.clone(), SETPOINT, KP, KI, KD);
stream.update().unwrap();
println!(
"time: {:?}; setpoint: {:?}; process: {:?}; command: {:?}",
stream.get().unwrap().unwrap().time.0,
SETPOINT.value,
input.borrow().get().unwrap().unwrap().value.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.");
}