diff --git a/Cargo.lock b/Cargo.lock index d856251ef3f0eebd4ab6c2b13ce9d4cb2a56849f..2752c4dcb3a22131fc3f010d77865c764f992a0a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,7 +305,7 @@ dependencies = [ [[package]] name = "controller" -version = "1.3.1" +version = "1.3.2" dependencies = [ "bootloader-params", "build-support", diff --git a/README.md b/README.md index 7ea6953f1a42e61d6985752710e297a7e34e9095..adf602a59f507d8904f87e6e5493a8d051d00c96 100644 --- a/README.md +++ b/README.md @@ -240,10 +240,6 @@ then the right motor coefficients. - 0x21: K_I (4 bytes, or 2×4 bytes). Default value is 0x0000_0000 (0.01171875) - 0x22: K_D (4 bytes, or 2×4 bytes). Default value is 0x0000_0000 (0.0) -Changing the coefficients will take effect only when the controlled -mode is off, for example by setting the motors to standby mode. Even a -speed of (0, 0) in controlled mode will not use the new coefficients. - ## 0x26 PID I accumulator (R) In controlled mode, return the PID I accumulator for each wheel (left diff --git a/controller/Cargo.toml b/controller/Cargo.toml index a349615b2d6e0c795c07a89002fcdc84e4f3b0da..73e49798b7fd178bbcbe92f10f19fe4c60c2ed09 100644 --- a/controller/Cargo.toml +++ b/controller/Cargo.toml @@ -4,7 +4,7 @@ description = "Firmware for DC Motor Driver Hat DFR0592" authors.workspace = true edition.workspace = true license.workspace = true -version = "1.3.1" # Update in python/controller.py and tele0592/src/controller.rs as well +version = "1.3.2" # Update in python/controller.py and tele0592/src/controller.rs as well [[bin]] name = "controller-firmware" diff --git a/controller/src/logic/mod.rs b/controller/src/logic/mod.rs index 720f3193065ed10ffa0e2450ac2cc3a25e499bdb..c4e666b013fecc8ae4b2dbb043cd5d2d8b2986bf 100644 --- a/controller/src/logic/mod.rs +++ b/controller/src/logic/mod.rs @@ -134,10 +134,12 @@ fn process_command( &[CMD_PID_K_P, a, b, c, d] => { pid_control::LEFT_K_P.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_P.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); + pid_control::mark_updated(); } &[CMD_PID_K_P, a, b, c, d, e, f, g, h] => { pid_control::LEFT_K_P.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_P.store(i32::from_le_bytes([e, f, g, h]), Ordering::Relaxed); + pid_control::mark_updated(); } [CMD_PID_K_P] => { response @@ -150,10 +152,12 @@ fn process_command( &[CMD_PID_K_I, a, b, c, d] => { pid_control::LEFT_K_I.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_I.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); + pid_control::mark_updated(); } &[CMD_PID_K_I, a, b, c, d, e, f, g, h] => { pid_control::LEFT_K_I.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_I.store(i32::from_le_bytes([e, f, g, h]), Ordering::Relaxed); + pid_control::mark_updated(); } [CMD_PID_K_I] => { response @@ -166,10 +170,12 @@ fn process_command( &[CMD_PID_K_D, a, b, c, d] => { pid_control::LEFT_K_D.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_D.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); + pid_control::mark_updated(); } &[CMD_PID_K_D, a, b, c, d, e, f, g, h] => { pid_control::LEFT_K_D.store(i32::from_le_bytes([a, b, c, d]), Ordering::Relaxed); pid_control::RIGHT_K_D.store(i32::from_le_bytes([e, f, g, h]), Ordering::Relaxed); + pid_control::mark_updated(); } [CMD_PID_K_D] => { response diff --git a/controller/src/logic/pid_control.rs b/controller/src/logic/pid_control.rs index f2605e5ca367e7c58dc8ef565ff4482deb539f6f..babda74076dbeb8e18f582b3c92a7f9cf1d65481 100644 --- a/controller/src/logic/pid_control.rs +++ b/controller/src/logic/pid_control.rs @@ -18,10 +18,21 @@ pub static RIGHT_K_D: AtomicI32 = AtomicI32::new(0x00); // 0.0 static LEFT_INTEGRATED_ERROR: AtomicI32 = AtomicI32::new(0x00); static RIGHT_INTEGRATED_ERROR: AtomicI32 = AtomicI32::new(0x00); +// Set when the coefficients have been updated and the PID should +// be reset when the robot is idle. Starting with a `true` value +// ensure that the default coefficients will be loaded when the +// PID process starts. +static PID_UPDATED: AtomicBool = AtomicBool::new(true); + static CONTROLLED_MODE: AtomicBool = AtomicBool::new(false); static LEFT_SPEED: AtomicI16 = AtomicI16::new(0); static RIGHT_SPEED: AtomicI16 = AtomicI16::new(0); +/// Note that some PID coefficients have been updated +pub fn mark_updated() { + PID_UPDATED.store(true, Ordering::Relaxed); +} + pub fn disable_controlled_mode() { CONTROLLED_MODE.store(false, Ordering::Relaxed); } @@ -55,13 +66,8 @@ pub async fn controlled_mode() { let (mut left_pid, mut right_pid) = (Pid::<PidUnit>::default(), Pid::<PidUnit>::default()); loop { ticker.next().await; - let new_controlled_mode = CONTROLLED_MODE.load(Ordering::Relaxed); - if !new_controlled_mode { - controlled_mode = false; - continue; - } - if !controlled_mode { - controlled_mode = true; + if PID_UPDATED.load(Ordering::Relaxed) { + PID_UPDATED.store(false, Ordering::Relaxed); left_pid = Pid::new( PidUnit::from_raw(LEFT_K_P.load(Ordering::Relaxed)), PidUnit::from_raw(LEFT_K_I.load(Ordering::Relaxed)), @@ -73,10 +79,19 @@ pub async fn controlled_mode() { PidUnit::from_raw(RIGHT_K_D.load(Ordering::Relaxed)), ); relative = Relative::new(encoders); - // Wait for a full cycle when starting to avoid an - // insufficient number of ticks. + } + let old_controlled_mode = controlled_mode; + controlled_mode = CONTROLLED_MODE.load(Ordering::Relaxed); + if !controlled_mode { continue; } + if !old_controlled_mode { + left_pid.reset(); + right_pid.reset(); + LEFT_INTEGRATED_ERROR.store(0, Ordering::Relaxed); + RIGHT_INTEGRATED_ERROR.store(0, Ordering::Relaxed); + relative = Relative::new(encoders); + } let (left_ticks, right_ticks) = relative.ticks(encoders); let left_command = build_speed_command(&mut left_pid, &LEFT_SPEED, left_ticks); let right_command = build_speed_command(&mut right_pid, &RIGHT_SPEED, right_ticks);