Added unit tests!!
This commit is contained in:
		
							parent
							
								
									501230e121
								
							
						
					
					
						commit
						3e29d8bc6a
					
				
					 15 changed files with 335 additions and 183 deletions
				
			
		
							
								
								
									
										31
									
								
								Cargo.toml
									
										
									
									
									
								
							
							
						
						
									
										31
									
								
								Cargo.toml
									
										
									
									
									
								
							| 
						 | 
					@ -1,28 +1,3 @@
 | 
				
			||||||
[package]
 | 
					[workspace]
 | 
				
			||||||
name = "led-compass"
 | 
					members = ["hardware_main", "independent_logic"]
 | 
				
			||||||
version = "0.1.0"
 | 
					resolver = "2"
 | 
				
			||||||
authors = ["Henrik Böving <hargonix@gmail.com>"]
 | 
					 | 
				
			||||||
edition = "2018"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.microbit-v2]
 | 
					 | 
				
			||||||
version = "0.12.0"
 | 
					 | 
				
			||||||
optional = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies.microbit]
 | 
					 | 
				
			||||||
version = "0.12.0"
 | 
					 | 
				
			||||||
optional = true
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[dependencies]
 | 
					 | 
				
			||||||
cortex-m = "0.7.3"
 | 
					 | 
				
			||||||
cortex-m-rt = "0.7.0"
 | 
					 | 
				
			||||||
rtt-target = { version = "0.3.1", features = ["cortex-m"] }
 | 
					 | 
				
			||||||
panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
 | 
					 | 
				
			||||||
lsm303agr = "0.2.2"
 | 
					 | 
				
			||||||
libm = "0.2.1"
 | 
					 | 
				
			||||||
embedded-hal = "0.2.6"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
[features]
 | 
					 | 
				
			||||||
v2 = ["microbit-v2"]
 | 
					 | 
				
			||||||
v1 = ["microbit"]
 | 
					 | 
				
			||||||
calibration=[]
 | 
					 | 
				
			||||||
default = ["v2"]
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										29
									
								
								hardware_main/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								hardware_main/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,29 @@
 | 
				
			||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "led-compass"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					authors = ["Henrik Böving <hargonix@gmail.com>"]
 | 
				
			||||||
 | 
					edition = "2018"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.microbit-v2]
 | 
				
			||||||
 | 
					version = "0.12.0"
 | 
				
			||||||
 | 
					optional = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies.microbit]
 | 
				
			||||||
 | 
					version = "0.12.0"
 | 
				
			||||||
 | 
					optional = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					cortex-m = "0.7.3"
 | 
				
			||||||
 | 
					cortex-m-rt = "0.7.0"
 | 
				
			||||||
 | 
					rtt-target = { version = "0.3.1", features = ["cortex-m"] }
 | 
				
			||||||
 | 
					panic-rtt-target = { version = "0.1.2", features = ["cortex-m"] }
 | 
				
			||||||
 | 
					lsm303agr = "0.2.2"
 | 
				
			||||||
 | 
					libm = "0.2.1"
 | 
				
			||||||
 | 
					embedded-hal = "0.2.6"
 | 
				
			||||||
 | 
					independent_logic = {path="../independent_logic"}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[features]
 | 
				
			||||||
 | 
					v2 = ["microbit-v2"]
 | 
				
			||||||
 | 
					v1 = ["microbit"]
 | 
				
			||||||
 | 
					calibration=[]
 | 
				
			||||||
 | 
					default = ["v2"]
 | 
				
			||||||
| 
						 | 
					@ -8,16 +8,13 @@ use calibration::Calibration;
 | 
				
			||||||
use cortex_m_rt::entry;
 | 
					use cortex_m_rt::entry;
 | 
				
			||||||
use lsm303agr::interface::I2cInterface;
 | 
					use lsm303agr::interface::I2cInterface;
 | 
				
			||||||
use lsm303agr::mode::MagContinuous;
 | 
					use lsm303agr::mode::MagContinuous;
 | 
				
			||||||
 | 
					use lsm303agr::{AccelOutputDataRate, Lsm303agr, MagOutputDataRate, Measurement};
 | 
				
			||||||
use microbit::hal::{gpiote::Gpiote, Twim};
 | 
					use microbit::hal::{gpiote::Gpiote, Twim};
 | 
				
			||||||
use microbit::pac::TWIM0;
 | 
					use microbit::pac::TWIM0;
 | 
				
			||||||
use panic_rtt_target as _;
 | 
					use panic_rtt_target as _;
 | 
				
			||||||
use rtt_target::{rprintln, rtt_init_print};
 | 
					use rtt_target::{rprintln, rtt_init_print};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
mod calibration;
 | 
					mod calibration;
 | 
				
			||||||
mod led;
 | 
					 | 
				
			||||||
mod tilt_compensation;
 | 
					 | 
				
			||||||
mod line_drawing;
 | 
					 | 
				
			||||||
mod heading_drawing;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
use microbit::{display::blocking::Display, hal::Timer};
 | 
					use microbit::{display::blocking::Display, hal::Timer};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,14 +24,14 @@ use microbit::{hal::twi, pac::twi0::frequency::FREQUENCY_A};
 | 
				
			||||||
#[cfg(feature = "v2")]
 | 
					#[cfg(feature = "v2")]
 | 
				
			||||||
use microbit::{hal::twim, pac::twim0::frequency::FREQUENCY_A};
 | 
					use microbit::{hal::twim, pac::twim0::frequency::FREQUENCY_A};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use lsm303agr::{AccelOutputDataRate, Lsm303agr, MagOutputDataRate};
 | 
					 | 
				
			||||||
use tilt_compensation::Heading;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
use crate::calibration::calc_calibration;
 | 
					use crate::calibration::calc_calibration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::led::{direction_to_led, theta_to_direction};
 | 
					use independent_logic::{
 | 
				
			||||||
use crate::tilt_compensation::{
 | 
					    led::{direction_to_led, theta_to_direction},
 | 
				
			||||||
    calc_attitude, calc_tilt_calibrated_measurement, heading_from_measurement, swd_to_ned,
 | 
					    tilt_compensation::{
 | 
				
			||||||
 | 
					        calc_attitude, calc_tilt_calibrated_measurement, heading_from_measurement, Heading,
 | 
				
			||||||
 | 
					        NedMeasurement,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const DELAY: u32 = 100;
 | 
					const DELAY: u32 = 100;
 | 
				
			||||||
| 
						 | 
					@ -87,7 +84,7 @@ fn main() -> ! {
 | 
				
			||||||
            channel_button_b.reset_events();
 | 
					            channel_button_b.reset_events();
 | 
				
			||||||
            rprintln!("Calibration: {:?}", calibration);
 | 
					            rprintln!("Calibration: {:?}", calibration);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if channel_button_a.is_event_triggered(){
 | 
					        if channel_button_a.is_event_triggered() {
 | 
				
			||||||
            //toggles the bool.
 | 
					            //toggles the bool.
 | 
				
			||||||
            tilt_correction_enabled ^= true;
 | 
					            tilt_correction_enabled ^= true;
 | 
				
			||||||
            channel_button_a.reset_events()
 | 
					            channel_button_a.reset_events()
 | 
				
			||||||
| 
						 | 
					@ -102,9 +99,22 @@ fn main() -> ! {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// board has forward in the y direction and right in the -x direction, and down in the -z. (ENU),  algs for tilt compensation
 | 
				
			||||||
 | 
					/// need forward in +x and right in +y (this is known as the NED (north, east, down) cordinate
 | 
				
			||||||
 | 
					/// system)
 | 
				
			||||||
 | 
					/// also converts to f32
 | 
				
			||||||
 | 
					pub fn swd_to_ned(measurement: Measurement) -> NedMeasurement {
 | 
				
			||||||
 | 
					    NedMeasurement {
 | 
				
			||||||
 | 
					        x: -measurement.y as f32,
 | 
				
			||||||
 | 
					        y: -measurement.x as f32,
 | 
				
			||||||
 | 
					        z: -measurement.z as f32,
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn calc_heading(
 | 
					fn calc_heading(
 | 
				
			||||||
    sensor: &mut Lsm303agr<I2cInterface<Twim<TWIM0>>, MagContinuous>,
 | 
					    sensor: &mut Lsm303agr<I2cInterface<Twim<TWIM0>>, MagContinuous>,
 | 
				
			||||||
    mag_calibration: &Calibration, tilt_correction_enabled: &bool
 | 
					    mag_calibration: &Calibration,
 | 
				
			||||||
 | 
					    tilt_correction_enabled: &bool,
 | 
				
			||||||
) -> Heading {
 | 
					) -> Heading {
 | 
				
			||||||
    while !(sensor.mag_status().unwrap().xyz_new_data
 | 
					    while !(sensor.mag_status().unwrap().xyz_new_data
 | 
				
			||||||
        && sensor.accel_status().unwrap().xyz_new_data)
 | 
					        && sensor.accel_status().unwrap().xyz_new_data)
 | 
				
			||||||
							
								
								
									
										9
									
								
								independent_logic/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								independent_logic/Cargo.toml
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,9 @@
 | 
				
			||||||
 | 
					[package]
 | 
				
			||||||
 | 
					name = "independent_logic"
 | 
				
			||||||
 | 
					version = "0.1.0"
 | 
				
			||||||
 | 
					edition = "2021"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[dependencies]
 | 
				
			||||||
 | 
					libm = "0.2.1"
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
 | 
					#![allow(unused)]
 | 
				
			||||||
use core::f32::consts::PI;
 | 
					use core::f32::consts::PI;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::line_drawing::{draw_line, FourQuadrantMatrix, Line, Point, UPoint};
 | 
					use crate::line_drawing::{draw_line, FourQuadrantMatrix, Line, Point, UPoint};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
struct Sector {
 | 
					struct Sector {
 | 
				
			||||||
    total_sectors: usize,
 | 
					    total_sectors: usize,
 | 
				
			||||||
    sector: usize,
 | 
					    sector: usize,
 | 
				
			||||||
| 
						 | 
					@ -36,3 +37,17 @@ pub fn draw_heading<const X: usize, const Y: usize>(
 | 
				
			||||||
    draw_line::<X, Y>(&heading_to_line(heading, X.min(Y)), &mut ret);
 | 
					    draw_line::<X, Y>(&heading_to_line(heading, X.min(Y)), &mut ret);
 | 
				
			||||||
    ret
 | 
					    ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn sectors() {
 | 
				
			||||||
 | 
					        assert_eq!(heading_to_sector(4,0.0).sector, 0);
 | 
				
			||||||
 | 
					        assert_eq!(heading_to_sector(4,PI/2.0).sector, 1);
 | 
				
			||||||
 | 
					        assert_eq!(heading_to_sector(4,-PI/2.0).sector, 3);
 | 
				
			||||||
 | 
					        assert_eq!(heading_to_sector(4,PI).sector, 2);
 | 
				
			||||||
 | 
					        assert_eq!(heading_to_sector(4,-PI).sector, 2);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										5
									
								
								independent_logic/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								independent_logic/src/lib.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,5 @@
 | 
				
			||||||
 | 
					#![no_std]
 | 
				
			||||||
 | 
					pub mod heading_drawing;
 | 
				
			||||||
 | 
					pub mod line_drawing;
 | 
				
			||||||
 | 
					pub mod tilt_compensation;
 | 
				
			||||||
 | 
					pub mod led;
 | 
				
			||||||
							
								
								
									
										249
									
								
								independent_logic/src/line_drawing.rs
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										249
									
								
								independent_logic/src/line_drawing.rs
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,249 @@
 | 
				
			||||||
 | 
					use core::{
 | 
				
			||||||
 | 
					    mem::swap,
 | 
				
			||||||
 | 
					    ops::{Index, IndexMut},
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct Point {
 | 
				
			||||||
 | 
					    pub x: isize,
 | 
				
			||||||
 | 
					    pub y: isize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Point {
 | 
				
			||||||
 | 
					    /// converts a point (representing a point on a 4 quadrant grid with positive xy in the
 | 
				
			||||||
 | 
					    /// top-right) into a upoint (representing a point on a 1 quadrant grid with the origin in the
 | 
				
			||||||
 | 
					    /// top-left corner). Returns none if the resulting point would have either number negative.
 | 
				
			||||||
 | 
					    pub fn to_upoint(self, zero_coord: &UPoint) -> Option<UPoint> {
 | 
				
			||||||
 | 
					        Some(UPoint {
 | 
				
			||||||
 | 
					            x: zero_coord.x.checked_add_signed(self.x)?,
 | 
				
			||||||
 | 
					            y: zero_coord.y.checked_add_signed(-self.y)?,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct UPoint {
 | 
				
			||||||
 | 
					    pub x: usize,
 | 
				
			||||||
 | 
					    pub y: usize,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl UPoint {
 | 
				
			||||||
 | 
					    /// converts a upoint (representing a point on a 1 quadrant grid with the origin in the
 | 
				
			||||||
 | 
					    /// top-left corner) into a point( representing a point on a 4 quadrant grid with positive xy
 | 
				
			||||||
 | 
					    /// in the top-right)
 | 
				
			||||||
 | 
					    pub fn to_point(self, zero_coord: &UPoint) -> Point {
 | 
				
			||||||
 | 
					        Point {
 | 
				
			||||||
 | 
					            x: -(zero_coord.x as isize - self.x as isize),
 | 
				
			||||||
 | 
					            y: zero_coord.y as isize - self.y as isize,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// A matrix that allows negative co-oordinates. Will panic if referencing out of bounds, just like
 | 
				
			||||||
 | 
					/// a nomral matrix.
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct FourQuadrantMatrix<const X: usize, const Y: usize, T> {
 | 
				
			||||||
 | 
					    matrix: [[T; X]; Y],
 | 
				
			||||||
 | 
					    pub zero_coord: UPoint,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<const X: usize, const Y: usize, T> FourQuadrantMatrix<{ X }, { Y }, T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    T: Copy,
 | 
				
			||||||
 | 
					    T: Default,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pub fn new(zero_coord: UPoint) -> FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
				
			||||||
 | 
					        FourQuadrantMatrix {
 | 
				
			||||||
 | 
					            matrix: [[T::default(); X]; Y],
 | 
				
			||||||
 | 
					            zero_coord,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, const X: usize, const Y: usize> IndexMut<Point> for FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
				
			||||||
 | 
					    fn index_mut(&mut self, index: Point) -> &mut Self::Output {
 | 
				
			||||||
 | 
					        let upoint = index
 | 
				
			||||||
 | 
					            .to_upoint(&self.zero_coord)
 | 
				
			||||||
 | 
					            .expect("would result in negative unsigned coordinate!");
 | 
				
			||||||
 | 
					        &mut self.matrix[upoint.y][upoint.x]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, const X: usize, const Y: usize> Index<Point> for FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
				
			||||||
 | 
					    type Output = T;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn index(&self, index: Point) -> &Self::Output {
 | 
				
			||||||
 | 
					        let upoint = index
 | 
				
			||||||
 | 
					            .to_upoint(&self.zero_coord)
 | 
				
			||||||
 | 
					            .expect("would result in negative unsigned coordinate!");
 | 
				
			||||||
 | 
					        &self.matrix[upoint.y][upoint.x]
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T, const X: usize, const Y: usize> From<FourQuadrantMatrix<{ X }, { Y }, T>> for [[T; X]; Y] {
 | 
				
			||||||
 | 
					    fn from(value: FourQuadrantMatrix<{ X }, { Y }, T>) -> Self {
 | 
				
			||||||
 | 
					        value.matrix
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct Line(pub Point, pub Point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//no boxes here!
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub struct ULine(pub UPoint, pub UPoint);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Renders a line into a matrix of pixels.
 | 
				
			||||||
 | 
					pub fn draw_line<const X: usize, const Y: usize>(
 | 
				
			||||||
 | 
					    line: &Line,
 | 
				
			||||||
 | 
					    matrix: &mut FourQuadrantMatrix<{ X }, { Y }, u8>,
 | 
				
			||||||
 | 
					) {
 | 
				
			||||||
 | 
					    let mut line = *line;
 | 
				
			||||||
 | 
					    let steep = (line.0.x - line.1.x).abs() < (line.0.y - line.1.x).abs();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if steep {
 | 
				
			||||||
 | 
					        swap(&mut line.0.x, &mut line.0.y);
 | 
				
			||||||
 | 
					        swap(&mut line.1.x, &mut line.1.y);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if line.0.x > line.1.x {
 | 
				
			||||||
 | 
					        swap(&mut line.0.x, &mut line.1.x);
 | 
				
			||||||
 | 
					        swap(&mut line.0.y, &mut line.1.y)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    let dx = line.1.x - line.0.x;
 | 
				
			||||||
 | 
					    let dy = line.1.y - line.0.y;
 | 
				
			||||||
 | 
					    let derror2 = dy.abs() * 2;
 | 
				
			||||||
 | 
					    let mut error2 = 0;
 | 
				
			||||||
 | 
					    let mut y = line.0.y;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for x in line.0.x..=line.1.x {
 | 
				
			||||||
 | 
					        if steep {
 | 
				
			||||||
 | 
					            matrix[Point { x: y, y: x }] = 1;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            matrix[Point { x, y }] = 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        error2 += derror2;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if error2 > dx {
 | 
				
			||||||
 | 
					            y += if line.1.y > line.0.y { 1 } else { -1 };
 | 
				
			||||||
 | 
					            error2 -= dx * 2
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[cfg(test)]
 | 
				
			||||||
 | 
					mod tests {
 | 
				
			||||||
 | 
					    use super::*;
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn point_upoint_conv() {
 | 
				
			||||||
 | 
					        let zero_coord = UPoint { x: 2, y: 2 };
 | 
				
			||||||
 | 
					        let point = Point { x: -1, y: -1 };
 | 
				
			||||||
 | 
					        let upoint = point.to_upoint(&zero_coord).unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(upoint, UPoint { x: 1, y: 3 });
 | 
				
			||||||
 | 
					        assert_eq!(upoint.to_point(&zero_coord), point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let point = Point { x: -2, y: 1 };
 | 
				
			||||||
 | 
					        let upoint = point.to_upoint(&zero_coord).unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(upoint, UPoint { x: 0, y: 1 });
 | 
				
			||||||
 | 
					        assert_eq!(upoint.to_point(&zero_coord), point);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        let point = Point { x: 2, y: 2 };
 | 
				
			||||||
 | 
					        let upoint = point.to_upoint(&zero_coord).unwrap();
 | 
				
			||||||
 | 
					        assert_eq!(upoint, UPoint { x: 4, y: 0 });
 | 
				
			||||||
 | 
					        assert_eq!(upoint.to_point(&zero_coord), point);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn four_quadrant_matrix() {
 | 
				
			||||||
 | 
					        let mut canvas: FourQuadrantMatrix<5, 5, u8> =
 | 
				
			||||||
 | 
					            FourQuadrantMatrix::new(UPoint { x: 2, y: 2 });
 | 
				
			||||||
 | 
					        canvas[Point { x: 0, y: 0 }] = 1;
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            <FourQuadrantMatrix<5, 5, u8> as Into<[[u8; 5]; 5]>>::into(canvas),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        canvas[Point { x: -2, y: 1 }] = 1;
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            <FourQuadrantMatrix<5, 5, u8> as Into<[[u8; 5]; 5]>>::into(canvas),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [1, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 0]
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn diagonal_unsigned_line() {
 | 
				
			||||||
 | 
					        let mut canvas: FourQuadrantMatrix<5, 5, u8> =
 | 
				
			||||||
 | 
					            FourQuadrantMatrix::new(UPoint { x: 0, y: 4 });
 | 
				
			||||||
 | 
					        draw_line(
 | 
				
			||||||
 | 
					            &Line(Point { x: 0, y: 0 }, Point { x: 4, y: 4 }),
 | 
				
			||||||
 | 
					            &mut canvas,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            <FourQuadrantMatrix<5, 5, u8> as Into<[[u8; 5]; 5]>>::into(canvas),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 1],
 | 
				
			||||||
 | 
					                [0, 0, 0, 1, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 1, 0, 0, 0],
 | 
				
			||||||
 | 
					                [1, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn diagonal_signed_line() {
 | 
				
			||||||
 | 
					        let mut canvas: FourQuadrantMatrix<5, 5, u8> =
 | 
				
			||||||
 | 
					            FourQuadrantMatrix::new(UPoint { x: 2, y: 2 });
 | 
				
			||||||
 | 
					        draw_line(
 | 
				
			||||||
 | 
					            &Line(Point { x: -2, y: -2 }, Point { x: 2, y: 2 }),
 | 
				
			||||||
 | 
					            &mut canvas,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            <FourQuadrantMatrix<5, 5, u8> as Into<[[u8; 5]; 5]>>::into(canvas),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                [0, 0, 0, 0, 1],
 | 
				
			||||||
 | 
					                [0, 0, 0, 1, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 1, 0, 0, 0],
 | 
				
			||||||
 | 
					                [1, 0, 0, 0, 0],
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #[test]
 | 
				
			||||||
 | 
					    fn cross_signed_line() {
 | 
				
			||||||
 | 
					        let mut canvas: FourQuadrantMatrix<5, 5, u8> =
 | 
				
			||||||
 | 
					            FourQuadrantMatrix::new(UPoint { x: 2, y: 2 });
 | 
				
			||||||
 | 
					        draw_line(
 | 
				
			||||||
 | 
					            &Line(Point { x: 0, y: -2 }, Point { x: 0, y: 2 }),
 | 
				
			||||||
 | 
					            &mut canvas,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        draw_line(
 | 
				
			||||||
 | 
					            &Line(Point { x: -2, y: 0 }, Point { x: 2, y: 0 }),
 | 
				
			||||||
 | 
					            &mut canvas,
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					        assert_eq!(
 | 
				
			||||||
 | 
					            <FourQuadrantMatrix<5, 5, u8> as Into<[[u8; 5]; 5]>>::into(canvas),
 | 
				
			||||||
 | 
					            [
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [1, 1, 1, 1, 1],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					                [0, 0, 1, 0, 0],
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,5 +1,4 @@
 | 
				
			||||||
use libm::{atan2f, atanf, cosf, sinf};
 | 
					use libm::{atan2f, atanf, cosf, sinf};
 | 
				
			||||||
use lsm303agr::Measurement;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct Attitude {
 | 
					pub struct Attitude {
 | 
				
			||||||
| 
						 | 
					@ -18,18 +17,6 @@ pub struct NedMeasurement {
 | 
				
			||||||
//theta=0 at south, pi/-pi at north, pi/2 at east, and -pi/2 at west (current)
 | 
					//theta=0 at south, pi/-pi at north, pi/2 at east, and -pi/2 at west (current)
 | 
				
			||||||
pub struct Heading(pub f32);
 | 
					pub struct Heading(pub f32);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// board has forward in the y direction and right in the -x direction, and down in the -z. (ENU),  algs for tilt compensation
 | 
					 | 
				
			||||||
/// need forward in +x and right in +y (this is known as the NED (north, east, down) cordinate
 | 
					 | 
				
			||||||
/// system)
 | 
					 | 
				
			||||||
/// also converts to f32
 | 
					 | 
				
			||||||
pub fn swd_to_ned(measurement: Measurement) -> NedMeasurement {
 | 
					 | 
				
			||||||
    NedMeasurement {
 | 
					 | 
				
			||||||
        x: -measurement.y as f32,
 | 
					 | 
				
			||||||
        y: -measurement.x as f32,
 | 
					 | 
				
			||||||
        z: -measurement.z as f32,
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub fn calc_attitude(measurement: &NedMeasurement) -> Attitude {
 | 
					pub fn calc_attitude(measurement: &NedMeasurement) -> Attitude {
 | 
				
			||||||
    //based off of: https://www.nxp.com/docs/en/application-note/AN4248.pdf
 | 
					    //based off of: https://www.nxp.com/docs/en/application-note/AN4248.pdf
 | 
				
			||||||
    let roll = atan2f(measurement.y, measurement.z);
 | 
					    let roll = atan2f(measurement.y, measurement.z);
 | 
				
			||||||
| 
						 | 
					@ -62,3 +49,5 @@ pub fn calc_tilt_calibrated_measurement(
 | 
				
			||||||
pub fn heading_from_measurement(measurement: NedMeasurement) -> Heading {
 | 
					pub fn heading_from_measurement(measurement: NedMeasurement) -> Heading {
 | 
				
			||||||
    Heading(atan2f(-measurement.y, measurement.x))
 | 
					    Heading(atan2f(-measurement.y, measurement.x))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//I have no freaking clue how to test this...
 | 
				
			||||||
| 
						 | 
					@ -1,129 +0,0 @@
 | 
				
			||||||
use core::{mem::swap, ops::Index, ops::IndexMut};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					 | 
				
			||||||
pub struct Point {
 | 
					 | 
				
			||||||
    pub x: isize,
 | 
					 | 
				
			||||||
    pub y: isize,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Point {
 | 
					 | 
				
			||||||
    /// converts a point (representing a point on a 4 quadrant grid) into a upoint (representing a
 | 
					 | 
				
			||||||
    /// point on a 1 quadrant grid with the origin in the bottom-left corner). Returns none if
 | 
					 | 
				
			||||||
    /// the resulting point would have either number negative.
 | 
					 | 
				
			||||||
    pub fn to_upoint(self, zero_coord: &UPoint) -> Option<UPoint> {
 | 
					 | 
				
			||||||
        Some(UPoint {
 | 
					 | 
				
			||||||
            x: zero_coord.x.checked_add_signed(self.x)?,
 | 
					 | 
				
			||||||
            y: zero_coord.y.checked_add_signed(self.y)?,
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					 | 
				
			||||||
pub struct UPoint {
 | 
					 | 
				
			||||||
    pub x: usize,
 | 
					 | 
				
			||||||
    pub y: usize,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl UPoint {
 | 
					 | 
				
			||||||
    /// converts a upoint (representing a point on a 1 quadrant grid with the origin in the
 | 
					 | 
				
			||||||
    /// bottom-left corner) into a point( representing a point on a 4 quadrant grid)
 | 
					 | 
				
			||||||
    pub fn to_point(self, zero_coord: &UPoint) -> Point {
 | 
					 | 
				
			||||||
        Point {
 | 
					 | 
				
			||||||
            x: zero_coord.x as isize - self.x as isize,
 | 
					 | 
				
			||||||
            y: zero_coord.y as isize - self.y as isize,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// A matrix that allows negative co-oordinates. Will panic if referencing out of bounds, just like
 | 
					 | 
				
			||||||
/// a nomral matrix.
 | 
					 | 
				
			||||||
pub struct FourQuadrantMatrix<const X: usize, const Y: usize, T> {
 | 
					 | 
				
			||||||
    matrix: [[T; X]; Y],
 | 
					 | 
				
			||||||
    pub zero_coord: UPoint,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<const X: usize, const Y: usize, T> FourQuadrantMatrix<{ X }, { Y }, T>
 | 
					 | 
				
			||||||
where
 | 
					 | 
				
			||||||
    T: Copy,
 | 
					 | 
				
			||||||
    T: Default,
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    pub fn new(zero_coord: UPoint) -> FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
					 | 
				
			||||||
        FourQuadrantMatrix {
 | 
					 | 
				
			||||||
            matrix: [[T::default(); X]; Y],
 | 
					 | 
				
			||||||
            zero_coord,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T, const X: usize, const Y: usize> IndexMut<Point> for FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
					 | 
				
			||||||
    fn index_mut(&mut self, index: Point) -> &mut Self::Output {
 | 
					 | 
				
			||||||
        let upoint = index
 | 
					 | 
				
			||||||
            .to_upoint(&self.zero_coord)
 | 
					 | 
				
			||||||
            .expect("would result in negative unsigned coordinate!");
 | 
					 | 
				
			||||||
        &mut self.matrix[upoint.x][upoint.y]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T, const X: usize, const Y: usize> Index<Point> for FourQuadrantMatrix<{ X }, { Y }, T> {
 | 
					 | 
				
			||||||
    type Output = T;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn index(&self, index: Point) -> &Self::Output {
 | 
					 | 
				
			||||||
        let upoint = index
 | 
					 | 
				
			||||||
            .to_upoint(&self.zero_coord)
 | 
					 | 
				
			||||||
            .expect("would result in negative unsigned coordinate!");
 | 
					 | 
				
			||||||
        &self.matrix[upoint.x][upoint.y]
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl<T, const X: usize, const Y: usize> From<FourQuadrantMatrix<{ X }, { Y }, T>> for [[T; X]; Y] {
 | 
					 | 
				
			||||||
    fn from(value: FourQuadrantMatrix<{ X }, { Y }, T>) -> Self {
 | 
					 | 
				
			||||||
        value.matrix
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					 | 
				
			||||||
pub struct Line(pub Point, pub Point);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//no boxes here!
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy)]
 | 
					 | 
				
			||||||
pub struct ULine(pub UPoint, pub UPoint);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Renders a line into a matrix of pixels.
 | 
					 | 
				
			||||||
pub fn draw_line<const X: usize, const Y: usize>(
 | 
					 | 
				
			||||||
    line: &Line,
 | 
					 | 
				
			||||||
    matrix: &mut FourQuadrantMatrix<{ X }, { Y }, u8>,
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
    let mut line = *line;
 | 
					 | 
				
			||||||
    let steep = (line.0.x - line.1.x).abs() < (line.0.y - line.1.x).abs();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if steep {
 | 
					 | 
				
			||||||
        swap(&mut line.0.x, &mut line.0.y);
 | 
					 | 
				
			||||||
        swap(&mut line.1.x, &mut line.1.y);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if line.0.x > line.1.x {
 | 
					 | 
				
			||||||
        swap(&mut line.0.x, &mut line.1.x);
 | 
					 | 
				
			||||||
        swap(&mut line.0.y, &mut line.1.y)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    let dx = line.1.x - line.0.x;
 | 
					 | 
				
			||||||
    let dy = line.1.y - line.0.y;
 | 
					 | 
				
			||||||
    let derror2 = dy.abs() * 2;
 | 
					 | 
				
			||||||
    let mut error2 = 0;
 | 
					 | 
				
			||||||
    let mut y = line.0.y;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    for x in line.0.x..=line.1.x {
 | 
					 | 
				
			||||||
        if steep {
 | 
					 | 
				
			||||||
            matrix[Point { x: y, y: x }] = 1;
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            matrix[Point { x, y }] = 1;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        error2 += derror2;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if error2 > dx {
 | 
					 | 
				
			||||||
            y += if line.1.y > line.0.y { 1 } else { -1 };
 | 
					 | 
				
			||||||
            error2 -= dx * 2
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue