# so2nostd
[](https://www.gnu.org/licenses/gpl-2.0)
[](https://docs.rs/so2nostd)
[](https://github.com/jorgeandrecastro/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](#features)
- [Installation](#installation)
- [Quickstart](#quickstart)
- [API Reference](#api-reference)
- [Performance & Optimization](#performance--optimization)
- [Testing](#testing)
- [License](#license)
## π Features
- β
**Pure `no_std`**: Zero standard library dependencies, perfect for bare-metal/RTOS.
- β‘ **Flexible Floating-Point**: `f64` (default) or `f32` feature for memory-constrained devices.
- π§ **Size-Optimized**: Compatible with `opt-level="z"`, LTO, and `strip = true`.
- π‘οΈ **Numerical Safety**: Handles `dt <= 0`, NaN/Inf, and prevents divergence.
- π **Physics-Based SO2**: Models natural frequency (`Ο_n`), damping ratio (`ΞΆ`), and static gain.
- π― **Setpoint Tracking**: Smooth convergence toward `setpoint`.
- βοΈ **Optional Safety Limits**: `max_velocity` and `max_acceleration` for embedded safety constraints.
## π οΈ Installation
Add to your `Cargo.toml`:
```toml
[dependencies]
so2nostd = { git = "https://github.com/jorgeandrecastro/so2nostd.git" }
f32 for embedded (e.g., Cortex-M):
so2nostd = { git = "https://github.com/jorgeandrecastro/so2nostd.git", features = ["f32"] }
Build with optimizations:
cargo build --release
π Quickstart
use so2nostd::So2Controller;
fn main() {
// Ο_n=10 rad/s, ΞΆ=0.7 (underdamped), initial=0.0, gain=1.0
let mut controller = So2Controller::new(10.0, 0.7, 0.0, 1.0);
controller.set_target(1.0); // Desired setpoint
controller.set_max_velocity(0.5); // Optional velocity limit
controller.set_max_acceleration(10.0); // Optional acceleration limit
let dt = 0.01; // 10ms timestep
// Run controller update loop
for _ in 0..100 {
let output = controller.update(0.0, dt);
// output smoothly approaches setpoint following SO2 dynamics
}
}
π API Reference
| `new` | `So2Controller::new(w_n: Float, zeta: Float, initial_value: Float, gain: Float) -> Self` | Creates a new controller instance. |
| `update` | `&mut self.update(input: Float, dt: Float) -> Float` | Updates system state toward `setpoint`. Safe for dt <= 0. |
| `set_target` | `&mut self.set_target(target: Float)` | Updates the internal setpoint. |
| `reset` | `&mut self.reset(value: Float)` | Resets states (`y`, `y_prev`, `setpoint`) to `value`. |
| `set_max_velocity` | `&mut self.set_max_velocity(max_v: Float)` | Optional: clamps max velocity. |
| `set_max_acceleration` | `&mut self.set_max_acceleration(max_a: Float)` | Optional: clamps max acceleration. |
Type: Float = f64 (default) or f32 with feature flag.
Public fields: w_n, zeta, setpoint, gain (inspectable/tunable).
β‘ Performance & Optimization
Binary Size: Minimal, optimized with opt-level="z", LTO, strip = true.
CPU Cost: Constant time O(1) per update.
Memory: Stack-only, zero allocation.
Ideal for 100β10kHz control loops on MCUs.
π§ͺ Testing
Includes tests for:
Step response stability and convergence.
Zero/negative dt handling.
Setpoint tracking and safety limit enforcement.
Run:
cargo test -- --nocapture
βοΈ License
GPL-2.0-or-later Β© 2026 Jorge Andre Castro.
Free to use, modify, and distribute. Any derivative works must also be GPL-2.0-or-later.