stepper-motion
A configuration-driven stepper motor motion control library for Rust, designed for embedded systems with no_std support.
Features
- 📁 Configuration-Driven: Define motor parameters and trajectories in TOML files
- 🔧 Embedded-Ready: Full
no_stdsupport withembedded-hal 1.0integration - ⚡ Asymmetric Motion Profiles: Independent acceleration and deceleration rates
- 🎯 Named Trajectories: Execute movements by name with registry-based lookup
- 📐 Type-Safe Units: Physical quantities with compile-time unit checking
- 🛡️ Mechanical Constraints: Automatic validation against hardware limits
- 📍 Absolute Position Tracking: i64 step-based position management
- 🔄 Backlash Compensation: Configurable mechanical play compensation
Installation
Add to your Cargo.toml:
[]
= "0.1"
Feature Flags
| Feature | Default | Description |
|---|---|---|
std |
✓ | Standard library support, TOML file loading |
alloc |
Heap allocation without full std | |
defmt |
defmt formatting for embedded debugging |
|
async |
Async executor support (planned) |
For no_std environments:
[]
= { = "0.1", = false, = ["alloc"] }
Quick Start
1. Create a Configuration File
# motion.toml
[]
= "Pan Axis"
= 200
= 16
= 4.0
= 180.0
= 360.0
= false
= 0.5
[]
= -180.0
= 180.0
= "reject"
[]
= "pan_axis"
= 0.0
= 50
[]
= "pan_axis"
= 90.0
= 100
= 360.0
= 180.0 # Asymmetric: slower decel
2. Load and Use in Your Application
use ;
// Load configuration (requires `std` feature)
3. Manual Motor Control (Builder Pattern)
use ;
// Create motor with explicit parameters
let motor = new
.name
.step_pin
.dir_pin
.delay
.steps_per_revolution
.microsteps
.gear_ratio
.max_velocity
.max_acceleration
.backlash_steps // Optional: backlash compensation
.build?;
println!;
println!;
// Move to absolute position
let moving_motor = motor.move_to?;
// Execute step-by-step
while moving_motor.is_moving
let idle_motor = moving_motor.finish;
Architecture
┌─────────────────────────────────────────────────────┐
│ stepper-motion │
├─────────────────────────────────────────────────────┤
│ config/ │ TOML parsing, validation │
│ ├── motor.rs │ MotorConfig, limits │
│ ├── trajectory.rs│ TrajectoryConfig (asymmetric) │
│ ├── mechanical.rs│ MechanicalConstraints │
│ ├── limits.rs │ SoftLimits, LimitPolicy │
│ └── units.rs │ Degrees, Steps, Microsteps │
├─────────────────────────────────────────────────────┤
│ motor/ │ Hardware abstraction │
│ ├── driver.rs │ StepperMotor<STEP,DIR,DELAY,S> │
│ ├── builder.rs │ Builder pattern construction │
│ ├── state.rs │ Type-state: Idle, Moving, etc. │
│ └── position.rs │ Position tracking (i64 steps) │
├─────────────────────────────────────────────────────┤
│ motion/ │ Motion planning │
│ ├── profile.rs │ MotionProfile (trapezoidal) │
│ └── executor.rs │ Step pulse generation │
├─────────────────────────────────────────────────────┤
│ trajectory/ │ Named trajectory management │
│ └── registry.rs │ TrajectoryRegistry │
└─────────────────────────────────────────────────────┘
Motion Profiles
Symmetric Trapezoidal
velocity
▲
max ┤ ┌───────┐
│ / \
│ / \
└─/─────────────\────► time
accel cruise decel
(same rate for both)
Asymmetric Trapezoidal
velocity
▲
max ┤ ┌───────┐
│ /│ │\
│ / │ │ \
└─/──┴───────┴──\───► time
fast slow
accel decel
Set different rates in TOML:
[]
= "pan_axis"
= 90.0
= 100
= 720.0 # Fast acceleration
= 180.0 # Gentle deceleration
Or using percent-based values (relative to motor max):
[]
= "pan_axis"
= 45.0
= 75 # 75% of motor's max velocity
= 100 # 100% of motor's max acceleration
Mechanical Constraints
Define hardware limits to prevent damage:
[]
= "Servo Axis"
= 200
= 32
= 5.0 # 5:1 reduction gearbox
= 360.0
= 720.0
= 0.5 # Compensate 0.5° backlash on reversal
[]
= -360.0
= 360.0
= "reject" # or "clamp"
Limit Policies
reject: Return error if target position exceeds limitsclamp: Automatically constrain target to nearest limit
Unit Conversions
The library automatically handles conversions:
let constraints = motor.constraints;
// Configuration values → internal steps
println!;
println!;
println!;
Examples
Run the included examples:
# Basic motor control with mechanical constraints demonstration
# Configuration-driven operation with named trajectories
# Multi-motor system demonstration
Type-State Safety
The motor uses Rust's type system to enforce valid state transitions:
// Motor starts in Idle state
let motor: = builder.build?;
// move_to() transitions to Moving state
let moving: = motor.move_to?;
// Can only call step() or finish() on Moving motor
while moving.is_moving
// finish() transitions back to Idle
let motor: = moving.finish;
Minimum Supported Rust Version (MSRV)
Rust 1.70.0 or later (required for embedded-hal 1.0).
no_std Usage
For embedded systems without standard library:
use ;
// Embed configuration at compile time
const CONFIG_TOML: &str = include_str!;
Contributing
Contributions are welcome! Please read the CHANGELOG for version history.
Development
# Run all tests (46 tests: 25 unit + 21 integration)
# Check no_std compatibility
# Run clippy
# Format code
# Run examples
License
Licensed under either of:
- Apache License, Version 2.0 (LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
- MIT license (LICENSE-MIT or http://opensource.org/licenses/MIT)
at your option.