From b0287c74226f4cae02e2a58b5bb3c19ed57712d7 Mon Sep 17 00:00:00 2001 From: Ihor Kalnytskyi Date: Sun, 22 Feb 2026 02:32:52 +0200 Subject: [PATCH] Add SetDuty control command SetDuty sets the target motor duty cycle in VESC, making it a core control mode for direct motor actuation workflows. --- README.md | 1 + src/command.rs | 9 +++++++++ tests/command.rs | 20 ++++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/README.md b/README.md index 6746dc8..4f7b3e3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,7 @@ application that needs to communicate with VESC motor controllers. |:----------:|-----------------------------------|--------| | `0` | `FwVersion` | ✅ | | `4` | `GetValues` | ✅ | +| `5` | `SetDuty` | ✅ | | `6` | `SetCurrent` | ✅ | | `7` | `SetCurrentBrake` | ✅ | | `8` | `SetRpm` | ✅ | diff --git a/src/command.rs b/src/command.rs index a977c67..a132677 100644 --- a/src/command.rs +++ b/src/command.rs @@ -43,6 +43,7 @@ pub enum DecodeError { enum CommandId { FwVersion = 0, GetValues = 4, + SetDuty = 5, SetCurrent = 6, SetCurrentBrake = 7, SetRpm = 8, @@ -58,6 +59,7 @@ impl TryFrom for CommandId { match value { id if id == CommandId::FwVersion as u8 => Ok(CommandId::FwVersion), id if id == CommandId::GetValues as u8 => Ok(CommandId::GetValues), + id if id == CommandId::SetDuty as u8 => Ok(CommandId::SetDuty), id if id == CommandId::SetCurrent as u8 => Ok(CommandId::SetCurrent), id if id == CommandId::SetCurrentBrake as u8 => Ok(CommandId::SetCurrentBrake), id if id == CommandId::SetRpm as u8 => Ok(CommandId::SetRpm), @@ -134,6 +136,9 @@ pub enum Command<'a> { /// Requests the complete set of telemetry data from the VESC. GetValues, + /// Sets the motor duty cycle ratio. Valid range is typically -1.0 to 1.0. + SetDuty(f32), + /// Sets the motor current in amperes. Positive values drive forward; /// negative values drive reverse. SetCurrent(f32), @@ -172,6 +177,10 @@ impl<'a> Command<'a> { Self::GetValues => { packer.pack_u8(CommandId::GetValues as u8)?; } + Self::SetDuty(duty) => { + packer.pack_u8(CommandId::SetDuty as u8)?; + packer.pack_f32(*duty, 100000.0)?; + } Self::SetCurrent(current) => { packer.pack_u8(CommandId::SetCurrent as u8)?; packer.pack_f32(*current, 1000.0)?; diff --git a/tests/command.rs b/tests/command.rs index c43dd7d..2c56bc6 100644 --- a/tests/command.rs +++ b/tests/command.rs @@ -18,6 +18,26 @@ fn encode_get_values() { assert_that!(buf[..size], eq([2, 1, 4, 64, 132, 3])); } +#[test] +fn encode_set_duty() { + let mut buf = [0u8; 16]; + + let size = vesc::encode(Command::SetDuty(0.0), &mut buf).unwrap(); + assert_that!(buf[..size], eq([2, 5, 5, 0, 0, 0, 0, 35, 87, 3])); + + let size = vesc::encode(Command::SetDuty(0.1), &mut buf).unwrap(); + assert_that!(buf[..size], eq([2, 5, 5, 0, 0, 39, 16, 174, 23, 3])); + + let size = vesc::encode(Command::SetDuty(0.57123), &mut buf).unwrap(); + assert_that!(buf[..size], eq([2, 5, 5, 0, 0, 223, 35, 50, 79, 3])); + + let size = vesc::encode(Command::SetDuty(-0.1), &mut buf).unwrap(); + assert_that!(buf[..size], eq([2, 5, 5, 255, 255, 216, 240, 212, 6, 3])); + + let size = vesc::encode(Command::SetDuty(-0.57123), &mut buf).unwrap(); + assert_that!(buf[..size], eq([2, 5, 5, 255, 255, 32, 221, 187, 161, 3])); +} + #[test] fn encode_set_current() { let mut buf = [0u8; 16];