so2nostd
Second-Order no_std Controller for Embedded Systems
so2nostd is a lightweight, high-performance no_std Rust crate implementing a discrete-time second-order (SO2) control system. Designed for embedded environments like MCUs (e.g., RP2040), it provides stable, physics-based dynamics using Euler integration.
GPL-2.0-or-later licensed to ensure community protection against privatization. Optimized for minimal footprint and maximal reliability.
Table of Contents
- Features
- Installation
- Quickstart
- Examples
- API Reference
- Performance & Optimization
- Testing
- License
- Contributing
π Features
- β
Pure
no_std: Zero standard library dependencies, perfect for bare-metal/RTOS. - β‘ Flexible Floating-Point:
f64(default, precision) orf32feature for memory-constrained devices. - π§ Size-Optimized Builds: Release profile with
opt-level=\"z\", LTO, stripping for tiny binaries. - π‘οΈ Robust & Safe: Handles
dt <= 0, numerical stability, real physics (acceleration from forces). - π Second-Order Dynamics: Natural frequency (
Ο_n), damping (ΞΆ), gain, setpoint tracking.
π οΈ Installation
Add to your Cargo.toml:
[]
= { = "https://github.com/jorgeandrecastro/so2nostd.git" }
f32 for embedded (e.g., Cortex-M):
= { = "https://github.com/jorgeandrecastro/so2nostd.git", = ["f32"] }
Build with optimizations:
π Quickstart
use So2Controller;
The system smoothly converges to the setpoint following SO2 dynamics without overshoot/divergence.
π Examples
1. Dynamic Setpoint Change (e.g., Motor Position Control)
let mut controller = new;
controller.set_target; // Ramp to 5.0
let output = controller.update;
controller.reset; // Reset for next cycle
2. Embedded Loop (no_std + RTOS)
Suitable for PID-like control in motor/servos, filters, etc.
π API Reference
| Method | Signature | Description |
|---|---|---|
new |
So2Controller::new(w_n: Float, zeta: Float, initial_value: Float, gain: Float) -> Self |
Creates controller. w_n: rad/s, zeta: damping (0.7 typical). |
update |
&mut self.update(input: Float, dt: Float) -> Float |
Updates state, returns new output. Safe for dt <= 0. |
set_target |
&mut self.set_target(target: Float) |
Updates setpoint. |
reset |
&mut self.reset(value: Float) |
Resets states to value. |
Type: Float = f64 (or f32 with feature).
Public fields: w_n, zeta (inspectable/tunable).
β‘ Performance & Optimization
- Binary Size: ~1-2KB (release, varies by Float).
- CPU: O(1) per update, no allocs/loops.
- Profile:
cargo build --releaseauto-appliesopt-level="z", LTO,panic=abort. - Ideal for 100-10kHz control loops on MCUs.
π§ͺ Testing
Includes unit tests for:
- Step response stability/convergence.
- Zero
dthandling.
Run: cargo test
βοΈ License
GPL-2.0-or-later Β© 2026 Jorge Andre Castro.
Free to use/modify/distribute, but derivatives must remain open-source GPL.
π€ Contributing
- Fork & PR to
main. - Follow Rustfmt:
cargo fmt. - Add tests for new features.
- Respect GPL: No proprietary forks.