Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LOC - Implement Navigator #33

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions lib/localisation/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ edition = "2021"

[dependencies]
nalgebra = "0.33.0"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
nalgebra = "0.33.0"
nalgebra = { version = "0.33.0", default-features = false }

See: https://nalgebra.org/docs/user_guide/wasm_and_embedded_targets/#compiling-without-standard-library

heapless = "0.8.0"
1 change: 1 addition & 0 deletions lib/localisation/src/control.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod navigator;
63 changes: 63 additions & 0 deletions lib/localisation/src/control/navigator.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use crate::filtering::kalman_filter::KalmanFilter;
use nalgebra::DVector;

pub struct Navigator {
displacement: f64,
velocity: f64,
acceleration: f64,
kalman_filter: KalmanFilter,
}

impl Navigator {
pub fn new(kalman_filter: KalmanFilter) -> Navigator {
Navigator {
displacement: 0.0,
velocity: 0.0,
acceleration: 0.0,
kalman_filter,
}
}

//Setters

pub fn set_displacement(&mut self, displacement: f64) {
self.displacement = displacement;
}

pub fn set_velocity(&mut self, velocity: f64) {
self.velocity = velocity;
}

pub fn set_acceleration(&mut self, acceleration: f64) {
self.acceleration = acceleration;
}

//Getters

pub fn get_displacement(&self) -> f64 {
self.displacement
}

pub fn get_velocity(&self) -> f64 {
self.velocity
}

pub fn get_acceleration(&self) -> f64 {
self.acceleration
}

pub fn run(&mut self) {}

pub fn update(&mut self) {

let control_input = DVector::from_column_slice(&[0.0]);
self.kalman_filter.predict(&control_input);

let measurement = DVector::from_column_slice(&[0.0,0.0]);
self.kalman_filter.update(&measurement);

self.set_displacement(self.kalman_filter.get_state()[0]);
self.set_velocity(self.kalman_filter.get_state()[1]);
self.set_acceleration(self.kalman_filter.get_state()[2]);
}
}
1 change: 1 addition & 0 deletions lib/localisation/src/filtering.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod kalman_filter;
144 changes: 144 additions & 0 deletions lib/localisation/src/filtering/kalman_filter.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use nalgebra::{DMatrix, DVector};

pub struct KalmanFilter {
// Current state estimate
state: DVector<f64>,

// Current error covariance
covariance: DMatrix<f64>,

// State transition matrix
transition_matrix: DMatrix<f64>,

// Control matrix
control_matrix: DMatrix<f64>,

// Observation matrix
observation_matrix: DMatrix<f64>,

// Process noise covariance
process_noise: DMatrix<f64>,

// Measurement noise covariance
measurement_noise: DMatrix<f64>,
}

impl KalmanFilter {
pub fn new(
initial_state: DVector<f64>,
initial_covariance: DMatrix<f64>,
transition_matrix: DMatrix<f64>,
control_matrix: DMatrix<f64>,
observation_matrix: DMatrix<f64>,
process_noise: DMatrix<f64>,
measurement_noise: DMatrix<f64>,
) -> Self {
KalmanFilter {
state: initial_state,
covariance: initial_covariance,
transition_matrix,
observation_matrix,
control_matrix,
process_noise,
measurement_noise,
}
}

// Predict
pub fn predict(&mut self, control_input: &DVector<f64>) {
// x_k = F * x_k-1 + B * u_k
self.state = &self.transition_matrix * &self.state + &self.control_matrix * control_input;

// P_k = F * P_k-1 * F^T + Q
self.covariance =
&self.transition_matrix * &self.covariance * self.transition_matrix.transpose()
+ &self.process_noise;
}

// Update
pub fn update(&mut self, measurement: &DVector<f64>) {
// y_k = z_k - H * x_k
let innovation = measurement - &self.observation_matrix * &self.state;

// S = H * P_k * H^T + R
let innovation_covariance =
&self.observation_matrix * &self.covariance * self.observation_matrix.transpose()
+ &self.measurement_noise;

// K = P_k * H^T * S^-1
let kalman_gain = &self.covariance
* self.observation_matrix.transpose()
* innovation_covariance
.try_inverse()
.expect("Failed to invert innovation covariance matrix");

self.state = &self.state + &kalman_gain * innovation;

let identity = DMatrix::<f64>::identity(self.state.nrows(), self.state.nrows());
self.covariance = (&identity - &kalman_gain * &self.observation_matrix) * &self.covariance;
}

pub fn get_state(&self) -> DVector<f64> {
self.state.clone()
}
}

#[cfg(test)]
mod tests {
use super::KalmanFilter;
use nalgebra::{DMatrix, DVector};

#[test]

fn test_kalman_filter() {
let initial_state = DVector::from_column_slice(&[0.0, 0.0]);
let initial_covariance = DMatrix::from_diagonal_element(2, 2, 500.0);

let transition_matrix = DMatrix::from_row_slice(2, 2, &[1.0, 0.25, 0.0, 1.0]);
let control_matrix = DMatrix::from_row_slice(2, 1, &[0.0313, 0.25]);
let observation_matrix = DMatrix::from_row_slice(1, 2, &[1.0, 0.0]);

let process_noise =
DMatrix::from_row_slice(2, 2, &[0.00000976562, 0.000078125, 0.000078125, 0.0625]);
let measurement_noise = DMatrix::from_diagonal_element(1, 1, 400.0);

let mut kalman_filter = KalmanFilter::new(
initial_state,
initial_covariance,
transition_matrix,
control_matrix,
observation_matrix,
process_noise,
measurement_noise,
);

let control_input = DVector::from_column_slice(&[0.0]);
kalman_filter.predict(&control_input);

let state = kalman_filter.get_state();
assert!((state - DVector::from_column_slice(&[0.0, 0.0])).norm() < 1e-2);

let h_values = DVector::from_column_slice(&[
6.43, 1.3, 39.43, 45.89, 41.44, 48.7, 78.06, 80.08, 61.77, 75.15, 110.39, 127.83,
158.75, 156.55, 213.32, 229.82, 262.8, 297.57, 335.69, 367.92, 377.19, 411.18, 460.7,
468.39, 553.9, 583.97, 655.15, 723.09, 736.85, 787.22,
]);

let a_values = DVector::from_column_slice(&[
39.81, 39.67, 39.81, 39.84, 40.05, 39.85, 39.78, 39.65, 39.67, 39.78, 39.59, 39.87,
39.85, 39.59, 39.84, 39.9, 39.63, 39.59, 39.76, 39.79, 39.73, 39.93, 39.83, 39.85,
39.94, 39.86, 39.76, 39.86, 39.74, 39.94,
]);

for i in 0..h_values.len() {
let measurement = DVector::from_column_slice(&[h_values[i]]);
kalman_filter.update(&measurement);

let control_input = DVector::from_column_slice(&[a_values[i] - 9.8]);
kalman_filter.predict(&control_input);
}

let final_state = kalman_filter.get_state();
assert!((final_state - DVector::from_column_slice(&[851.9, 223.2])).norm() < 0.5);
}
}
4 changes: 3 additions & 1 deletion lib/localisation/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#![no_std]
pub mod control;
pub mod filtering;
pub mod preprocessing;
3 changes: 3 additions & 0 deletions lib/localisation/src/preprocessing.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod accelerometer;
pub mod keyence;
pub mod optical;
Loading