Sign in

    sensor_driver

    Comprehensive motion sensor driver library with accelerometer, gyroscope, magnetometer support, sensor fusion algorithms (Complementary, Kalman, Madgwick), and gesture recognition for motion control applications

    sensor
    motion
    imu
    accelerometer
    gyroscope
    magnetometer
    sensor-fusion
    kalman-filter
    quaternion
    orientation
    gesture
    robotics
    motion-control
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    11 months ago
    Downloads
    29

    No dependencies

    #Motion Sensor Driver for MoonBit

    A comprehensive motion sensor driver library implementing accelerometer, gyroscope, and magnetometer sensor fusion for motion control applications.

    #Features

    #Sensor Drivers

    • Accelerometer - Measures linear acceleration with calibration support
    • Gyroscope - Tracks angular velocity with drift compensation
    • Magnetometer - Detects magnetic field for compass heading

    #Sensor Fusion Algorithms

    • Complementary Filter - Simple and efficient orientation estimation
    • Kalman Filter - Optimal state estimation with noise modeling
    • Madgwick Filter - Gradient descent AHRS algorithm

    #Motion Detection

    • Free fall detection
    • Impact/shock detection
    • Shake gesture recognition
    • Tilt detection (pitch/roll)
    • Rotation detection
    • Movement tracking

    #Key Capabilities

    • Quaternion-based 3D orientation
    • Euler angle conversion (roll, pitch, yaw)
    • Tilt-compensated compass heading
    • Calibration for all sensors
    • Gesture recognition system

    #Installation

    moon add maria/sensor_driver

    Or add to your moon.mod.json:

    { "deps": { "maria/sensor_driver": "0.1.0" } }

    #Quick Start

    let config = SensorConfig::default()
    let controller = MotionController::new(config)

    // Update with sensor readings (typically called at 100Hz)
    let state = controller.update(
    accel_raw, // Vec3: accelerometer (m/s²)
    gyro_raw, // Vec3: gyroscope (rad/s)
    mag_raw, // Vec3: magnetometer (μT)
    timestamp, // Int64: milliseconds
    dt, // Double: seconds
    )

    // Get orientation
    let (roll, pitch, yaw) = controller.get_euler_degrees()

    // Detect gestures
    match controller.detect_gesture() {
    Shaking => println("Device is shaking!")
    FreeFall => println("Free fall!")
    Impact(force) => println("Impact: \{force}")
    Tilting(p, r) => println("Tilted")
    Rotating(speed) => println("Rotating")
    Stationary => ()
    }

    // Get compass heading
    let heading = controller.get_heading_degrees()

    #Documentation

    #Hardware Support

    Works with standard IMU sensors:
    • MPU6050, MPU9250 (accel + gyro)
    • LSM6DS3, LSM9DS1 (9-axis IMU)
    • BNO055 (all-in-one IMU)

    #Performance

    • Complementary filter: ~0.1ms per update
    • Recommended sample rate: 100-200Hz
    • Memory: ~1KB per controller instance

    #License

    Apache-2.0

    #Author

    Built with MoonBit

    AccelCalibration

    pub(all) struct AccelCalibration {
    offset : Vec3
    scale : Vec3
    gravity : Double
    }

    Accelerometer calibration data

    AccelCalibration::default

    Create default calibration (no offset, unity scale, Earth's gravity)

    AccelReading

    pub(all) struct AccelReading {
    data : Vec3
    timestamp : Int64
    }

    Accelerometer reading (m/s²)
    impl Eq for AccelReading

    Accelerometer

    pub struct Accelerometer {
    calibration : AccelCalibration
    last_reading : AccelReading
    raw_readings : Array[Vec3]
    config : SensorConfig
    }

    Accelerometer driver

    Accelerometer::add_calibration_sample

    fn Accelerometer::add_calibration_sample(self : Accelerometer, raw : Vec3) -> Unit

    Add raw sample for calibration

    Accelerometer::calibrate

    fn Accelerometer::calibrate(self : Accelerometer) -> Unit

    Calibrate accelerometer using collected samples Assumes the sensor is stationary during calibration

    Accelerometer::detect_impact

    fn Accelerometer::detect_impact(self : Accelerometer) -> Double?

    Detect impact/shock

    Accelerometer::detect_shake

    fn Accelerometer::detect_shake(_self : Accelerometer, recent_readings : ArrayView[AccelReading]) -> Bool

    Detect shake motion using acceleration variance

    Accelerometer::get_gravity

    fn Accelerometer::get_gravity(self : Accelerometer) -> Vec3

    Get gravity vector from acceleration

    Accelerometer::get_linear_acceleration

    fn Accelerometer::get_linear_acceleration(self : Accelerometer, gravity : Vec3) -> Vec3

    Calculate linear acceleration (remove gravity component)

    Accelerometer::get_tilt

    fn Accelerometer::get_tilt(self : Accelerometer) -> (Double, Double)

    Calculate tilt angles (pitch and roll) from gravity

    Accelerometer::is_freefall

    fn Accelerometer::is_freefall(self : Accelerometer) -> Bool

    Detect if device is in free fall

    Accelerometer::new

    Create new accelerometer

    Accelerometer::read

    fn Accelerometer::read(self : Accelerometer, raw : Vec3, timestamp : Int64) -> AccelReading

    Read accelerometer data

    ComplementaryFilter

    pub struct ComplementaryFilter {
    orientation : Quaternion
    alpha : Double
    }

    Complementary filter for sensor fusion

    ComplementaryFilter::get_orientation

    fn ComplementaryFilter::get_orientation(self : ComplementaryFilter) -> Quaternion

    Get current orientation

    ComplementaryFilter::new

    fn ComplementaryFilter::new(alpha : Double) -> ComplementaryFilter

    Create new complementary filter

    ComplementaryFilter::update

    fn ComplementaryFilter::update(self : ComplementaryFilter, accel : Vec3, gyro : Vec3, mag : Vec3, dt : Double) -> Quaternion

    Update orientation using complementary filter

    Gesture

    pub enum Gesture {
    Stationary
    Shaking
    Tilting(Double, Double)
    Rotating(Double)
    FreeFall
    Impact(Double)
    }

    Gesture types for motion detection
    impl Eq for Gesture
    impl Show for Gesture

    GyroCalibration

    pub(all) struct GyroCalibration {
    bias : Vec3
    drift_rate : Vec3
    }

    Gyroscope calibration data

    GyroCalibration::default

    Create default gyro calibration

    GyroReading

    pub(all) struct GyroReading {
    data : Vec3
    timestamp : Int64
    }

    Gyroscope reading (rad/s)
    impl Eq for GyroReading
    impl Show for GyroReading

    Gyroscope

    pub struct Gyroscope {
    calibration : GyroCalibration
    last_reading : GyroReading
    integrated_angle : Vec3
    raw_readings : Array[Vec3]
    config : SensorConfig
    }

    Gyroscope driver

    Gyroscope::add_calibration_sample

    fn Gyroscope::add_calibration_sample(self : Gyroscope, raw : Vec3) -> Unit

    Add raw sample for calibration

    Gyroscope::apply_lowpass_filter

    fn Gyroscope::apply_lowpass_filter(self : Gyroscope, previous : Vec3, alpha : Double) -> Vec3

    Low-pass filter for gyro data

    Gyroscope::calibrate

    fn Gyroscope::calibrate(self : Gyroscope) -> Unit

    Calibrate gyroscope by measuring bias when stationary

    Gyroscope::detect_rotation_type

    fn Gyroscope::detect_rotation_type(self : Gyroscope) -> (String, Double)?

    Detect specific rotation gesture

    Gyroscope::get_angular_velocity

    fn Gyroscope::get_angular_velocity(self : Gyroscope) -> Vec3

    Get current angular velocity

    Gyroscope::get_rotation_quaternion

    fn Gyroscope::get_rotation_quaternion(self : Gyroscope, dt : Double) -> Quaternion

    Get rotation quaternion from angular velocity

    Gyroscope::integrate

    fn Gyroscope::integrate(self : Gyroscope, dt : Double) -> Vec3

    Integrate angular velocity to get rotation angle

    Gyroscope::is_rotating

    fn Gyroscope::is_rotating(self : Gyroscope, threshold : Double) -> Bool

    Detect rotation around any axis

    Gyroscope::new

    fn Gyroscope::new(config : SensorConfig) -> Gyroscope

    Create new gyroscope

    Gyroscope::read

    fn Gyroscope::read(self : Gyroscope, raw : Vec3, timestamp : Int64) -> GyroReading

    Read gyroscope data

    Gyroscope::reset_integration

    fn Gyroscope::reset_integration(self : Gyroscope) -> Unit

    Reset integrated angle

    KalmanFilter

    pub struct KalmanFilter {
    orientation : Quaternion
    error_covariance : Double
    process_noise : Double
    measurement_noise : Double
    }

    Simplified Kalman filter for orientation

    KalmanFilter::get_orientation

    fn KalmanFilter::get_orientation(self : KalmanFilter) -> Quaternion

    Get current orientation

    KalmanFilter::new

    fn KalmanFilter::new(process_noise : Double, measurement_noise : Double) -> KalmanFilter

    Create new Kalman filter

    KalmanFilter::update

    fn KalmanFilter::update(self : KalmanFilter, accel : Vec3, gyro : Vec3, mag : Vec3, dt : Double) -> Quaternion

    Update Kalman filter

    MadgwickFilter

    pub struct MadgwickFilter {
    orientation : Quaternion
    beta : Double
    }

    Madgwick filter (gradient descent orientation filter)

    MadgwickFilter::get_orientation

    fn MadgwickFilter::get_orientation(self : MadgwickFilter) -> Quaternion

    Get current orientation

    MadgwickFilter::new

    fn MadgwickFilter::new(beta : Double) -> MadgwickFilter

    Create new Madgwick filter

    MadgwickFilter::update

    fn MadgwickFilter::update(self : MadgwickFilter, accel : Vec3, gyro : Vec3, mag : Vec3, dt : Double) -> Quaternion

    Update Madgwick filter

    MagCalibration

    pub(all) struct MagCalibration {
    hard_iron : Vec3
    soft_iron : Array[Double]
    }

    Magnetometer calibration data

    MagCalibration::default

    Create default magnetometer calibration

    MagReading

    pub(all) struct MagReading {
    data : Vec3
    timestamp : Int64
    }

    Magnetometer reading (μT - microtesla)
    impl Eq for MagReading
    impl Show for MagReading

    Magnetometer

    pub struct Magnetometer {
    calibration : MagCalibration
    last_reading : MagReading
    raw_readings : Array[Vec3]
    config : SensorConfig
    }

    Magnetometer driver

    Magnetometer::add_calibration_sample

    fn Magnetometer::add_calibration_sample(self : Magnetometer, raw : Vec3) -> Unit

    Add raw sample for calibration

    Magnetometer::apply_declination

    fn Magnetometer::apply_declination(self : Magnetometer, declination : Double) -> Double

    Calculate magnetic declination offset

    Magnetometer::calibrate_simple

    fn Magnetometer::calibrate_simple(self : Magnetometer) -> Unit

    Simple hard-iron calibration (offset only)

    Magnetometer::detect_interference

    fn Magnetometer::detect_interference(self : Magnetometer) -> Bool

    Detect magnetic interference

    Magnetometer::get_field_strength

    fn Magnetometer::get_field_strength(self : Magnetometer) -> Double

    Get field strength

    Magnetometer::get_heading

    fn Magnetometer::get_heading(self : Magnetometer) -> Double

    Calculate heading (yaw) from magnetometer Returns angle in radians from magnetic north

    Magnetometer::get_magnetic_field

    fn Magnetometer::get_magnetic_field(self : Magnetometer) -> Vec3

    Get magnetic field vector

    Magnetometer::get_tilt_compensated_heading

    fn Magnetometer::get_tilt_compensated_heading(self : Magnetometer, pitch : Double, roll : Double) -> Double

    Calculate tilt-compensated heading

    Magnetometer::new

    Create new magnetometer

    Magnetometer::read

    fn Magnetometer::read(self : Magnetometer, raw : Vec3, timestamp : Int64) -> MagReading

    Read magnetometer data

    MotionController

    pub struct MotionController {
    accel : Accelerometer
    gyro : Gyroscope
    mag : Magnetometer
    filter : ComplementaryFilter
    state : MotionState
    recent_accels : Array[AccelReading]
    max_history : Int
    }

    Motion controller integrating all sensors

    MotionController::add_calibration_sample

    fn MotionController::add_calibration_sample(self : MotionController, accel_raw : Vec3, gyro_raw : Vec3, mag_raw : Vec3) -> Unit

    Add calibration samples for all sensors

    MotionController::calibrate

    fn MotionController::calibrate(self : MotionController) -> Unit

    Calibrate all sensors

    MotionController::detect_gesture

    fn MotionController::detect_gesture(self : MotionController) -> Gesture

    Detect current gesture

    MotionController::get_euler_angles

    fn MotionController::get_euler_angles(self : MotionController) -> (Double, Double, Double)

    Get orientation as Euler angles (roll, pitch, yaw) in radians

    MotionController::get_euler_degrees

    fn MotionController::get_euler_degrees(self : MotionController) -> (Double, Double, Double)

    Get orientation as Euler angles in degrees

    MotionController::get_heading

    fn MotionController::get_heading(self : MotionController) -> Double

    Get compass heading in radians

    MotionController::get_heading_degrees

    fn MotionController::get_heading_degrees(self : MotionController) -> Double

    Get compass heading in degrees

    MotionController::get_state

    Get current motion state

    MotionController::is_moving

    fn MotionController::is_moving(self : MotionController) -> Bool

    Detect if device is moving

    MotionController::new

    Create new motion controller

    MotionController::reset

    fn MotionController::reset(self : MotionController) -> Unit

    Reset sensor fusion

    MotionController::update

    fn MotionController::update(self : MotionController, accel_raw : Vec3, gyro_raw : Vec3, mag_raw : Vec3, timestamp : Int64, dt : Double) -> MotionState

    Update all sensors and state

    MotionState

    pub(all) struct MotionState {
    acceleration : Vec3
    angular_velocity : Vec3
    magnetic_field : Vec3
    orientation : Quaternion
    timestamp : Int64
    }

    Motion state combining all sensor data
    impl Show for MotionState

    MotionState::new

    Create initial motion state

    Quaternion

    pub(all) struct Quaternion {
    w : Double
    x : Double
    y : Double
    z : Double
    }

    Quaternion for 3D rotation
    impl Eq for Quaternion
    impl Show for Quaternion

    Quaternion::from_axis_angle

    fn Quaternion::from_axis_angle(axis : Vec3, angle : Double) -> Quaternion

    Create quaternion from axis and angle (in radians)

    Quaternion::identity

    fn Quaternion::identity() -> Quaternion

    Create identity quaternion

    Quaternion::multiply

    fn Quaternion::multiply(self : Quaternion, other : Quaternion) -> Quaternion

    Quaternion multiplication

    Quaternion::normalize

    fn Quaternion::normalize(self : Quaternion) -> Quaternion

    Normalize quaternion

    Quaternion::to_euler

    fn Quaternion::to_euler(self : Quaternion) -> (Double, Double, Double)

    Convert quaternion to Euler angles (roll, pitch, yaw in radians)

    SensorConfig

    pub(all) struct SensorConfig {
    accel_range : Double
    gyro_range : Double
    mag_range : Double
    sample_rate : Int
    }

    Sensor configuration
    impl Eq for SensorConfig

    SensorConfig::default

    fn SensorConfig::default() -> SensorConfig

    Default sensor configuration

    Vec3

    pub(all) struct Vec3 {
    x : Double
    y : Double
    z : Double
    }

    3D Vector for sensor data
    impl Eq for Vec3
    impl Show for Vec3

    Vec3::add

    fn Vec3::add(self : Vec3, other : Vec3) -> Vec3

    Vector addition

    Vec3::cross

    fn Vec3::cross(self : Vec3, other : Vec3) -> Vec3

    Cross product

    Vec3::dot

    fn Vec3::dot(self : Vec3, other : Vec3) -> Double

    Dot product

    Vec3::magnitude

    fn Vec3::magnitude(self : Vec3) -> Double

    Vector magnitude

    Vec3::new

    fn Vec3::new(x : Double, y : Double, z : Double) -> Vec3

    Create a new 3D vector

    Vec3::normalize

    fn Vec3::normalize(self : Vec3) -> Vec3

    Normalize vector

    Vec3::scale

    fn Vec3::scale(self : Vec3, scalar : Double) -> Vec3

    Scalar multiplication

    Vec3::sub

    fn Vec3::sub(self : Vec3, other : Vec3) -> Vec3

    Vector subtraction

    Vec3::zero

    fn Vec3::zero() -> Vec3

    Zero vector

    fib

    fn fib(n : Int) -> Int64

    sum

    fn sum(data~ : Array[Int], start? : Int, length? : Int) -> Int

    data is a labelled argument without default value having type Array[Int] start is an optional labelled argument with default value 0 having type Int length is an optional labelled argument without default value having type Option[Int]