Module conreg::control::pid[][src]

Expand description

PID and PID-T1 Controller

The PID controller implementation is capable to run als PID controller or as PID-T1 controller (with a t1 delay)

Requirements

  • The PID controller should run on MCU (32 bit, w/o FPU)
  • The PID controller should also run as simulator on any arbitrary host including plotting of response diagrams

Design Decision

  1. Control loop is implemented as iterator
    • Ease of simulator integration
    • Ease of integration into ISR
    • Iterator end (None returned) allows switch of of actuator and stop simulation
  2. Use of no_std environment to meet limited MCU capabilities
  3. Fixed type on Iterator as i32 and fixed point arithmetics fast and appropriate for any 32-bit MCU; optimized for ISR’s with minimal operations can go up to 50 kHz ISR triggering rate
  4. Fixed and little sampling interval allows to pre-compute processing constants and speeds up sample processing
    • Allows to implementing difference quotients instead of more computing intensive z-transformation

Simulation example

In an std environment simulate the step response as and plot it

use std::iter;
use conreg::control::pid::PidController;
use conreg::control::pid_parameter::{PidParameterAdditive};

let mut actual = iter::repeat(0.0_f32); // This is what we measure
// This composes a step response input as target, i.e. what we want
let mut target_pre = iter::repeat(0.0_f32).take(10); // 10 samples before step
let mut target_post = iter::repeat(1.0_f32); // samples after the step
let mut target = target_pre.chain(target_post);

let p = PidParameterAdditive::new(1.0).set_integral(1.0);
let mut pid = PidController::<f32>::new(0.000_01).set(p);
println!("PidController: {:?}", pid);

let output = actual.zip(target)  // provide input tupel (actual, target)
    .map(|x| pid.control(x))  // run the controller
    .take(1000)  // Stop processing after 1000 samples
    // .plot()  // Plot the step response
    .collect::<Vec<f32>>();
println!("Result {:?}", output);

MCU example

On an embedded micro controller integrate the controller in a everlasting loop.

The example shows a PID-T1 controller as 32-bit fixed point implementation. It runs as at a sample rate of 20 kHz and the delay is 1 millisecond.

use std::iter;
use conreg::control::pid::PidController;
use conreg::control::pid_parameter::{PidParameterAdditive};

// Sensor that measures actual value - implements an iterator
let process = Sensor::new(); // does not compile

let setpoint = iter::repeat(500); // Setpoint desired value is injected as iterator
let input = process.zip(setpoint);

let p = PidParameterAdditive::new(1.0).set_integral(0.2).set_differential(0.4);
let mut pid = PidController::<i32>::new_with_t1(0.000_01, 0.000_1).set(p);

// Output device - consumes iterator
let mut actuator = Actuator::new(); // does not compile
let mut output = input.map(|x| pid.control(x));  // configure the controller processing
for value in output {
    // run ad infinitum
    actuator.set(value);
}

Structs

PidController