feat(faderboard): implement pid controller
This commit is contained in:
parent
8c3625c8da
commit
d8527ce5e7
|
@ -2,6 +2,12 @@
|
||||||
# It is not intended for manual editing.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "az"
|
||||||
|
version = "1.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bare-metal"
|
name = "bare-metal"
|
||||||
version = "0.2.5"
|
version = "0.2.5"
|
||||||
|
@ -40,6 +46,12 @@ dependencies = [
|
||||||
"vcell",
|
"vcell",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bytemuck"
|
||||||
|
version = "1.16.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cast"
|
name = "cast"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -49,6 +61,12 @@ dependencies = [
|
||||||
"rustc_version 0.4.0",
|
"rustc_version 0.4.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cortex-m"
|
name = "cortex-m"
|
||||||
version = "0.7.7"
|
version = "0.7.7"
|
||||||
|
@ -81,6 +99,12 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crunchy"
|
||||||
|
version = "0.2.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "embedded-hal"
|
name = "embedded-hal"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -97,12 +121,72 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cortex-m",
|
"cortex-m",
|
||||||
"cortex-m-rt",
|
"cortex-m-rt",
|
||||||
|
"embedded-hal",
|
||||||
|
"fixed",
|
||||||
|
"fixed-macro",
|
||||||
"panic-halt",
|
"panic-halt",
|
||||||
"stm32f0xx-hal",
|
"stm32f0xx-hal",
|
||||||
"usb-device",
|
"usb-device",
|
||||||
"usbd-serial",
|
"usbd-serial",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed"
|
||||||
|
version = "1.27.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fc715d38bea7b5bf487fcd79bcf8c209f0b58014f3018a7a19c2b855f472048"
|
||||||
|
dependencies = [
|
||||||
|
"az",
|
||||||
|
"bytemuck",
|
||||||
|
"half",
|
||||||
|
"typenum",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed-macro"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1fd0c48af8cb14e02868f449f8a2187bd78af7a08da201fdc78d518ecb1675bc"
|
||||||
|
dependencies = [
|
||||||
|
"fixed",
|
||||||
|
"fixed-macro-impl",
|
||||||
|
"fixed-macro-types",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed-macro-impl"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c93086f471c0a1b9c5e300ea92f5cd990ac6d3f8edf27616ef624b8fa6402d4b"
|
||||||
|
dependencies = [
|
||||||
|
"fixed",
|
||||||
|
"paste",
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "fixed-macro-types"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "044a61b034a2264a7f65aa0c3cd112a01b4d4ee58baace51fead3f21b993c7e4"
|
||||||
|
dependencies = [
|
||||||
|
"fixed",
|
||||||
|
"fixed-macro-impl",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "half"
|
||||||
|
version = "2.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"crunchy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nb"
|
name = "nb"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
|
@ -124,6 +208,36 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
|
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "paste"
|
||||||
|
version = "1.0.15"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"version_check",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.86"
|
version = "1.0.86"
|
||||||
|
@ -231,6 +345,12 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typenum"
|
||||||
|
version = "1.17.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.12"
|
version = "1.0.12"
|
||||||
|
@ -260,6 +380,12 @@ version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "version_check"
|
||||||
|
version = "0.9.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "void"
|
name = "void"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
|
@ -8,6 +8,9 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.7.7"
|
cortex-m = "0.7.7"
|
||||||
cortex-m-rt = "0.7.3"
|
cortex-m-rt = "0.7.3"
|
||||||
|
embedded-hal = "0.2.7"
|
||||||
|
fixed = "1.27.0"
|
||||||
|
fixed-macro = "1.2.0"
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
||||||
stm32f0xx-hal = { git = "https://github.com/lujoga/stm32f0xx-hal.git", branch = "v0.18.0-backports", features = ["rt", "stm32f072", "stm32-usbd"] }
|
stm32f0xx-hal = { git = "https://github.com/lujoga/stm32f0xx-hal.git", branch = "v0.18.0-backports", features = ["rt", "stm32f072", "stm32-usbd"] }
|
||||||
usb-device = "0.2.9"
|
usb-device = "0.2.9"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
|
mod pid;
|
||||||
mod touch;
|
mod touch;
|
||||||
mod usb;
|
mod usb;
|
||||||
|
|
||||||
|
@ -8,6 +9,8 @@ use cortex_m_rt::entry;
|
||||||
|
|
||||||
use panic_halt as _;
|
use panic_halt as _;
|
||||||
|
|
||||||
|
use pid::{FixedI32, Pid, PidConfig};
|
||||||
|
|
||||||
use stm32f0xx_hal as hal;
|
use stm32f0xx_hal as hal;
|
||||||
|
|
||||||
use hal::adc::Adc;
|
use hal::adc::Adc;
|
||||||
|
@ -140,7 +143,17 @@ fn main() -> ! {
|
||||||
let touch = Touch::new(sys_cfg, p.EXTI, delay.clone());
|
let touch = Touch::new(sys_cfg, p.EXTI, delay.clone());
|
||||||
touch.enable();
|
touch.enable();
|
||||||
|
|
||||||
|
let pid_config = PidConfig::<false>::new()
|
||||||
|
.d_gain(FixedI32!(0))
|
||||||
|
.i_gain(FixedI32!(0))
|
||||||
|
.i_max(FixedI32!(0))
|
||||||
|
.i_min(FixedI32!(0))
|
||||||
|
.p_gain(FixedI32!(0.5));
|
||||||
|
let mut pid = Pid::new(&pid_config, 2048);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
usb.poll();
|
usb.poll();
|
||||||
|
|
||||||
|
let (_duty, _dir) = pid.update(0, 2048);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
use embedded_hal::digital::v2::PinState;
|
||||||
|
|
||||||
|
pub use fixed::types::I16F16 as FixedI32;
|
||||||
|
|
||||||
|
pub use fixed_macro::types::I16F16 as FixedI32;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub struct PidConfig<const FORWARD_HIGH: bool> {
|
||||||
|
d_gain: FixedI32,
|
||||||
|
i_gain: FixedI32,
|
||||||
|
i_max: FixedI32,
|
||||||
|
i_min: FixedI32,
|
||||||
|
p_gain: FixedI32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const FORWARD_HIGH: bool> PidConfig<FORWARD_HIGH> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
d_gain: FixedI32::ZERO,
|
||||||
|
i_gain: FixedI32::ZERO,
|
||||||
|
i_max: FixedI32::ZERO,
|
||||||
|
i_min: FixedI32::ZERO,
|
||||||
|
p_gain: FixedI32::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn d_gain(mut self, d_gain: FixedI32) -> Self {
|
||||||
|
self.d_gain = d_gain;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn i_gain(mut self, i_gain: FixedI32) -> Self {
|
||||||
|
self.i_gain = i_gain;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn i_max(mut self, i_max: FixedI32) -> Self {
|
||||||
|
self.i_max = i_max;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn i_min(mut self, i_min: FixedI32) -> Self {
|
||||||
|
self.i_min = i_min;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn p_gain(mut self, p_gain: FixedI32) -> Self {
|
||||||
|
self.p_gain = p_gain;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use inner::{Config, Dir};
|
||||||
|
|
||||||
|
pub struct Pid<'a, CONFIG, const FORWARD_HIGH: bool>
|
||||||
|
where
|
||||||
|
CONFIG: Config<FORWARD_HIGH> + Dir,
|
||||||
|
{
|
||||||
|
config: &'a CONFIG,
|
||||||
|
d_state: FixedI32,
|
||||||
|
i_state: FixedI32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, CONFIG, const FORWARD_HIGH: bool> Pid<'a, CONFIG, FORWARD_HIGH>
|
||||||
|
where
|
||||||
|
CONFIG: Config<FORWARD_HIGH> + Dir,
|
||||||
|
{
|
||||||
|
pub fn new(config: &'a CONFIG, initial_position: u16) -> Self {
|
||||||
|
Self {
|
||||||
|
config,
|
||||||
|
d_state: FixedI32::saturating_from_num(initial_position),
|
||||||
|
i_state: FixedI32::ZERO,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&mut self, error: i16, position: u16) -> (u16, PinState) {
|
||||||
|
let config = self.config.config();
|
||||||
|
let error = FixedI32::from_num(error);
|
||||||
|
let position = FixedI32::saturating_from_num(position);
|
||||||
|
|
||||||
|
let p = config.p_gain * error;
|
||||||
|
|
||||||
|
self.i_state = match self.i_state + error {
|
||||||
|
i if i > config.i_max => config.i_max,
|
||||||
|
i if i < config.i_min => config.i_min,
|
||||||
|
i => i,
|
||||||
|
};
|
||||||
|
|
||||||
|
let i = config.i_gain * self.i_state;
|
||||||
|
|
||||||
|
let d = config.d_gain * (self.d_state - position);
|
||||||
|
self.d_state = position;
|
||||||
|
|
||||||
|
let output = (p + i + d).round();
|
||||||
|
return (
|
||||||
|
output.abs().saturating_to_num::<u16>(),
|
||||||
|
self.config.dir(output),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod inner {
|
||||||
|
use embedded_hal::digital::v2::PinState;
|
||||||
|
|
||||||
|
use fixed::types::I16F16;
|
||||||
|
|
||||||
|
use super::PidConfig;
|
||||||
|
|
||||||
|
pub trait Config<const FORWARD_HIGH: bool> {
|
||||||
|
fn config(&self) -> &PidConfig<FORWARD_HIGH>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const FORWARD_HIGH: bool> Config<FORWARD_HIGH> for PidConfig<FORWARD_HIGH> {
|
||||||
|
fn config(&self) -> &PidConfig<FORWARD_HIGH> {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Dir {
|
||||||
|
fn dir(&self, output: I16F16) -> PinState;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dir for PidConfig<false> {
|
||||||
|
fn dir(&self, output: I16F16) -> PinState {
|
||||||
|
//! If FORWARD_HIGH is false, return PinState::High for reverse direction
|
||||||
|
PinState::from(output.is_negative())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Dir for PidConfig<true> {
|
||||||
|
fn dir(&self, output: I16F16) -> PinState {
|
||||||
|
//! If FORWARD_HIGH is true, return PinState::High for forward direction
|
||||||
|
PinState::from(output.is_positive())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue