Skip to content

Commit 2c4e4c6

Browse files
committed
Rust API: Add rustdoc examples to moteus-protocol public items
Add examples to key entry points: calculate/parse_arbitration_id, PositionCommand, StayWithinCommand, CurrentCommand, QueryFormat, QueryResult::parse, parse_frame, Value::to_f32, Mode::is_error. Cross-reference lesser-used types to the primary examples.
1 parent 59efe97 commit 2c4e4c6

File tree

5 files changed

+156
-0
lines changed

5 files changed

+156
-0
lines changed

lib/rust/moteus-protocol/src/command.rs

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,25 @@ impl Default for PositionFormat {
7575
///
7676
/// This is the primary control mode for moteus. All fields are optional;
7777
/// fields set to `None` will not be transmitted (using Ignore resolution).
78+
///
79+
/// # Examples
80+
///
81+
/// ```
82+
/// use moteus_protocol::CanFdFrame;
83+
/// use moteus_protocol::command::{PositionCommand, PositionFormat};
84+
///
85+
/// let mut frame = CanFdFrame::new();
86+
/// frame.arbitration_id = 0x8001;
87+
///
88+
/// // Build with the builder pattern -- fields are optional
89+
/// let cmd = PositionCommand::new()
90+
/// .position(0.5)
91+
/// .velocity(1.0)
92+
/// .maximum_torque(2.0);
93+
///
94+
/// cmd.serialize(&mut frame, &PositionFormat::default());
95+
/// assert!(frame.size > 0);
96+
/// ```
7897
#[non_exhaustive]
7998
#[derive(Debug, Clone, Default, Setters)]
8099
pub struct PositionCommand {
@@ -286,6 +305,8 @@ impl Default for VFOCFormat {
286305
}
287306

288307
/// Voltage-mode FOC command.
308+
///
309+
/// See [`PositionCommand`] for an example of building and serializing commands.
289310
#[non_exhaustive]
290311
#[derive(Debug, Clone, Setters)]
291312
pub struct VFOCCommand {
@@ -378,6 +399,19 @@ impl Default for CurrentFormat {
378399
}
379400

380401
/// DQ-axis current command.
402+
///
403+
/// # Examples
404+
///
405+
/// ```
406+
/// use moteus_protocol::CanFdFrame;
407+
/// use moteus_protocol::command::{CurrentCommand, CurrentFormat};
408+
///
409+
/// let mut frame = CanFdFrame::new();
410+
/// let cmd = CurrentCommand::new()
411+
/// .d_current(0.0)
412+
/// .q_current(0.5);
413+
/// cmd.serialize(&mut frame, &CurrentFormat::default());
414+
/// ```
381415
#[non_exhaustive]
382416
#[derive(Debug, Clone)]
383417
pub struct CurrentCommand {
@@ -469,6 +503,22 @@ impl Default for StayWithinFormat {
469503
}
470504

471505
/// Stay-within mode command.
506+
///
507+
/// Unlike [`PositionCommand`] which drives to a target, this mode keeps the
508+
/// servo within position bounds while applying minimal control effort.
509+
///
510+
/// # Examples
511+
///
512+
/// ```
513+
/// use moteus_protocol::CanFdFrame;
514+
/// use moteus_protocol::command::{StayWithinCommand, StayWithinFormat};
515+
///
516+
/// let mut frame = CanFdFrame::new();
517+
/// let cmd = StayWithinCommand::new()
518+
/// .lower_bound(-0.5)
519+
/// .upper_bound(0.5);
520+
/// cmd.serialize(&mut frame, &StayWithinFormat::default());
521+
/// ```
472522
#[non_exhaustive]
473523
#[derive(Debug, Clone, Default, Setters)]
474524
pub struct StayWithinCommand {
@@ -616,6 +666,8 @@ impl Default for ZeroVelocityFormat {
616666
}
617667

618668
/// Zero-velocity mode command.
669+
///
670+
/// See [`PositionCommand`] for an example of building and serializing commands.
619671
#[non_exhaustive]
620672
#[derive(Debug, Clone, Default, Setters)]
621673
pub struct ZeroVelocityCommand {

lib/rust/moteus-protocol/src/frame.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,22 @@ impl core::fmt::Debug for CanFdFrame {
182182
/// - bit 15 = reply expected flag
183183
/// - bits 14:8 = source (7 bits)
184184
/// - bits 7:0 = destination (8 bits)
185+
///
186+
/// # Examples
187+
///
188+
/// ```
189+
/// use moteus_protocol::{calculate_arbitration_id, parse_arbitration_id};
190+
///
191+
/// // Build an arbitration ID for source=0, dest=1, no prefix, reply expected
192+
/// let arb_id = calculate_arbitration_id(0, 1, 0, true);
193+
/// assert_eq!(arb_id, 0x8001);
194+
///
195+
/// // Parse it back
196+
/// let (source, dest, prefix) = parse_arbitration_id(arb_id);
197+
/// assert_eq!(source, 0);
198+
/// assert_eq!(dest, 1);
199+
/// assert_eq!(prefix, 0);
200+
/// ```
185201
pub fn calculate_arbitration_id(
186202
source: i8,
187203
destination: i8,
@@ -199,6 +215,17 @@ pub fn calculate_arbitration_id(
199215
///
200216
/// Returns (source, destination, can_prefix).
201217
/// This is the inverse of [`calculate_arbitration_id`].
218+
///
219+
/// # Examples
220+
///
221+
/// ```
222+
/// use moteus_protocol::parse_arbitration_id;
223+
///
224+
/// // Extract routing from a received frame's arbitration ID
225+
/// let (source, dest, prefix) = parse_arbitration_id(0x8100);
226+
/// assert_eq!(source, 1); // device 1 sent this
227+
/// assert_eq!(dest, 0); // addressed to us
228+
/// ```
202229
pub fn parse_arbitration_id(arb_id: u32) -> (i8, i8, u16) {
203230
let source = ((arb_id >> 8) & 0x7F) as i8;
204231
let destination = (arb_id & 0xFF) as i8;

lib/rust/moteus-protocol/src/mode.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ impl core::fmt::Display for Mode {
8383

8484
impl Mode {
8585
/// Returns `true` if the controller is in an error state.
86+
///
87+
/// # Examples
88+
///
89+
/// ```
90+
/// use moteus_protocol::Mode;
91+
///
92+
/// let mode = Mode::Position;
93+
/// assert!(mode.is_active());
94+
/// assert!(!mode.is_error());
95+
///
96+
/// let fault = Mode::Fault;
97+
/// assert!(fault.is_error());
98+
/// assert!(!fault.is_active());
99+
/// ```
86100
pub fn is_error(&self) -> bool {
87101
matches!(self, Mode::Fault | Mode::Timeout)
88102
}

lib/rust/moteus-protocol/src/multiplex.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,17 @@ impl Value {
394394
/// Integer minimum values (e.g., -128 for Int8) are mapped to NaN.
395395
/// Integer values are multiplied by the appropriate scaling factor.
396396
/// Float values are returned directly.
397+
///
398+
/// # Examples
399+
///
400+
/// ```
401+
/// use moteus_protocol::multiplex::Value;
402+
/// use moteus_protocol::scaling;
403+
///
404+
/// let raw = Value::Int16(5000);
405+
/// let position = raw.to_f32(&scaling::POSITION);
406+
/// assert!((position - 0.5).abs() < 0.001); // 5000 * 0.0001 = 0.5 rev
407+
/// ```
397408
pub fn to_f32(&self, scaling: &Scaling) -> f32 {
398409
use crate::scaling::{nanify_i16, nanify_i32, nanify_i8};
399410

@@ -467,6 +478,8 @@ pub enum Subframe<'a> {
467478
///
468479
/// Handles all opcode families: WRITE (0x00-0x0f), READ (0x10-0x1f),
469480
/// REPLY (0x20-0x2f), ERROR (0x30-0x31), STREAM (0x40-0x42), NOP (0x50).
481+
///
482+
/// See [`parse_frame`] for a convenience wrapper.
470483
pub struct FrameParser<'a> {
471484
data: &'a [u8],
472485
offset: usize,
@@ -786,6 +799,23 @@ impl<'a> Iterator for FrameParser<'a> {
786799
}
787800

788801
/// Creates a parser that iterates over all subframes in a multiplex protocol frame.
802+
///
803+
/// # Examples
804+
///
805+
/// ```
806+
/// use moteus_protocol::multiplex::{parse_frame, Subframe};
807+
///
808+
/// // A response frame with mode=10 (position) at register 0
809+
/// let data = [0x21, 0x00, 0x0a];
810+
/// for subframe in parse_frame(&data) {
811+
/// match subframe {
812+
/// Subframe::Register { register, value, .. } => {
813+
/// println!("Register 0x{:03x} = {:?}", register, value);
814+
/// }
815+
/// _ => {}
816+
/// }
817+
/// }
818+
/// ```
789819
pub fn parse_frame(data: &[u8]) -> FrameParser<'_> {
790820
FrameParser::new(data)
791821
}

lib/rust/moteus-protocol/src/query.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@ pub const MAX_EXTRA: usize = 16;
3030
///
3131
/// Specifies which registers to query and at what resolution.
3232
/// Setting a field to `Resolution::Ignore` means that register will not be queried.
33+
///
34+
/// # Examples
35+
///
36+
/// ```
37+
/// use moteus_protocol::Resolution;
38+
/// use moteus_protocol::query::QueryFormat;
39+
///
40+
/// // Default format queries position, velocity, torque, and q_current
41+
/// let default = QueryFormat::default();
42+
///
43+
/// // Comprehensive format includes all standard registers
44+
/// let full = QueryFormat::comprehensive();
45+
///
46+
/// // Or customize individual registers
47+
/// let mut custom = QueryFormat::default();
48+
/// custom.abs_position = Resolution::Float;
49+
/// custom.voltage = Resolution::Int16;
50+
/// ```
3351
#[non_exhaustive]
3452
#[derive(Debug, Clone)]
3553
pub struct QueryFormat {
@@ -267,6 +285,21 @@ pub struct ExtraValue {
267285
}
268286

269287
/// Result of parsing a query response.
288+
///
289+
/// # Examples
290+
///
291+
/// ```
292+
/// use moteus_protocol::CanFdFrame;
293+
/// use moteus_protocol::query::QueryResult;
294+
///
295+
/// // After receiving a response frame from the device...
296+
/// fn handle_response(frame: &CanFdFrame) {
297+
/// let result = QueryResult::parse(frame);
298+
/// if result.mode.is_error() {
299+
/// eprintln!("Fault code: {}", result.fault);
300+
/// }
301+
/// }
302+
/// ```
270303
#[non_exhaustive]
271304
#[derive(Debug, Clone, Default)]
272305
pub struct QueryResult {

0 commit comments

Comments
 (0)