Fixed some math bugs in the compass calcs, needle is now more accurate.
This commit is contained in:
		
							parent
							
								
									a77b3845e0
								
							
						
					
					
						commit
						26a1da2cb9
					
				
					 4 changed files with 38 additions and 22 deletions
				
			
		| 
						 | 
					@ -34,7 +34,7 @@ use microbit::{hal::twim, pac::twim0::frequency::FREQUENCY_A};
 | 
				
			||||||
use crate::calibration::calc_calibration;
 | 
					use crate::calibration::calc_calibration;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use independent_logic::{
 | 
					use independent_logic::{
 | 
				
			||||||
    heading_drawing::draw_heading,
 | 
					    heading_drawing::draw_constant_heading,
 | 
				
			||||||
    tilt_compensation::{
 | 
					    tilt_compensation::{
 | 
				
			||||||
        calc_attitude, calc_tilt_calibrated_measurement, heading_from_measurement, Heading,
 | 
					        calc_attitude, calc_tilt_calibrated_measurement, heading_from_measurement, Heading,
 | 
				
			||||||
        NedMeasurement,
 | 
					        NedMeasurement,
 | 
				
			||||||
| 
						 | 
					@ -77,7 +77,6 @@ fn main() -> ! {
 | 
				
			||||||
    sensor.set_accel_odr(AccelOutputDataRate::Hz10).unwrap();
 | 
					    sensor.set_accel_odr(AccelOutputDataRate::Hz10).unwrap();
 | 
				
			||||||
    let mut sensor = sensor.into_mag_continuous().ok().unwrap();
 | 
					    let mut sensor = sensor.into_mag_continuous().ok().unwrap();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    //TODO: re-callibrate with button.
 | 
					 | 
				
			||||||
    #[cfg(feature = "calibration")]
 | 
					    #[cfg(feature = "calibration")]
 | 
				
			||||||
    let mut calibration = calc_calibration(&mut sensor, &mut display, &mut timer);
 | 
					    let mut calibration = calc_calibration(&mut sensor, &mut display, &mut timer);
 | 
				
			||||||
    #[cfg(not(feature = "calibration"))]
 | 
					    #[cfg(not(feature = "calibration"))]
 | 
				
			||||||
| 
						 | 
					@ -98,28 +97,28 @@ fn main() -> ! {
 | 
				
			||||||
            #[cfg(debug_assertions)]
 | 
					            #[cfg(debug_assertions)]
 | 
				
			||||||
            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()
 | 
				
			||||||
        }
 | 
					        // }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        current_display.reset_matrix();
 | 
					        current_display.reset_matrix();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        let heading = calc_heading(&mut sensor, &calibration, &tilt_correction_enabled);
 | 
					        let heading = calc_heading(&mut sensor, &calibration, &tilt_correction_enabled);
 | 
				
			||||||
        draw_heading::<5, 5>(heading.0, &mut current_display);
 | 
					        draw_constant_heading::<5, 5>(heading, &mut current_display);
 | 
				
			||||||
        display.show(&mut timer, current_display.into(), DELAY)
 | 
					        display.show(&mut timer, current_display.into(), DELAY)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// board has forward in the y direction and right in the -x direction, and down in the -z. (ENU),  algs for tilt compensation
 | 
					/// 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
 | 
					/// need forward in +x and right in +y (this is known as the NED (north, east, down) cordinate
 | 
				
			||||||
/// system)
 | 
					/// system)
 | 
				
			||||||
/// also converts to f32
 | 
					/// also converts to f32
 | 
				
			||||||
pub fn enu_to_ned(measurement: Measurement) -> NedMeasurement {
 | 
					pub fn enu_to_ned(measurement: Measurement) -> NedMeasurement {
 | 
				
			||||||
    NedMeasurement {
 | 
					    NedMeasurement {
 | 
				
			||||||
        x: -measurement.y as f32,
 | 
					        x: -measurement.y as f32,
 | 
				
			||||||
        y: -measurement.x as f32,
 | 
					        y: measurement.x as f32,
 | 
				
			||||||
        z: -measurement.z as f32,
 | 
					        z: -measurement.z as f32,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -145,7 +144,7 @@ fn calc_heading(
 | 
				
			||||||
        ned_mag_data = calc_tilt_calibrated_measurement(ned_mag_data, &attitude);
 | 
					        ned_mag_data = calc_tilt_calibrated_measurement(ned_mag_data, &attitude);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //theta=0 at north, pi/-pi at south, pi/2 at east, and -pi/2 at west
 | 
					    //theta=0 at north, pi/-pi at south, pi/2 at east, and -pi/2 at west
 | 
				
			||||||
    let heading = heading_from_measurement(ned_mag_data);
 | 
					    let heading = heading_from_measurement(&ned_mag_data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[cfg(all(not(feature = "calibration"), debug_assertions))]
 | 
					    #[cfg(all(not(feature = "calibration"), debug_assertions))]
 | 
				
			||||||
    rprintln!(
 | 
					    rprintln!(
 | 
				
			||||||
| 
						 | 
					@ -154,9 +153,15 @@ fn calc_heading(
 | 
				
			||||||
        attitude.roll * (180.0 / PI),
 | 
					        attitude.roll * (180.0 / PI),
 | 
				
			||||||
        heading.0 * (180.0 / PI),
 | 
					        heading.0 * (180.0 / PI),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    rprintln!(
 | 
				
			||||||
 | 
					        "mag: x: {:<+16}, y: {:<+16}, z: {:<+16}",
 | 
				
			||||||
 | 
					        ned_mag_data.x,
 | 
				
			||||||
 | 
					        ned_mag_data.y,
 | 
				
			||||||
 | 
					        ned_mag_data.z
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
    #[cfg(all(not(feature = "calibration"), debug_assertions))]
 | 
					    #[cfg(all(not(feature = "calibration"), debug_assertions))]
 | 
				
			||||||
    rprintln!(
 | 
					    rprintln!(
 | 
				
			||||||
        "x: {:<+16}, y: {:<+16}, z: {:<+16}",
 | 
					        "acell: x: {:<+16}, y: {:<+16}, z: {:<+16}",
 | 
				
			||||||
        ned_acel_data.x,
 | 
					        ned_acel_data.x,
 | 
				
			||||||
        ned_acel_data.y,
 | 
					        ned_acel_data.y,
 | 
				
			||||||
        ned_acel_data.z
 | 
					        ned_acel_data.z
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,19 +1,22 @@
 | 
				
			||||||
use libm::{cosf, roundf, sinf};
 | 
					use libm::{cosf, roundf, sinf};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::line_drawing::{draw_line, FourQuadrantMatrix, Line, Point};
 | 
					use crate::line_drawing::{draw_line, FourQuadrantMatrix, Line, Point};
 | 
				
			||||||
 | 
					use crate::tilt_compensation::Heading;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn heading_to_line(heading: f32, square_size: usize) -> Line {
 | 
					fn heading_to_line(heading: Heading, square_size: usize) -> Line {
 | 
				
			||||||
    Line(
 | 
					    Line(
 | 
				
			||||||
        Point { x: 0, y: 0 },
 | 
					        Point { x: 0, y: 0 },
 | 
				
			||||||
        Point {
 | 
					        Point {
 | 
				
			||||||
            x: roundf((square_size as f32) * sinf(heading)) as isize,
 | 
					            x: roundf((square_size as f32) * sinf(heading.0)) as isize,
 | 
				
			||||||
            y: roundf((square_size as f32) * cosf(heading)) as isize,
 | 
					            y: roundf((square_size as f32) * cosf(heading.0)) as isize,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn draw_heading<const X: usize, const Y: usize>(
 | 
					// given the compass heading that the board '0' is facing,
 | 
				
			||||||
    heading: f32,
 | 
					// draws a line always pointing towards heading 0
 | 
				
			||||||
 | 
					pub fn draw_constant_heading<const X: usize, const Y: usize>(
 | 
				
			||||||
 | 
					    heading: Heading,
 | 
				
			||||||
    matrix: &mut FourQuadrantMatrix<{ X }, { Y }, u8>,
 | 
					    matrix: &mut FourQuadrantMatrix<{ X }, { Y }, u8>,
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    draw_line::<X, Y>(&heading_to_line(heading, X.min(Y)), matrix);
 | 
					    draw_line::<X, Y>(&heading_to_line(heading, X.min(Y)), matrix);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@ pub struct Heading(pub 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
 | 
				
			||||||
 | 
					    //Gp{xyz} is the acellerometer measurements.
 | 
				
			||||||
    let roll = atan2f(measurement.y, measurement.z);
 | 
					    let roll = atan2f(measurement.y, measurement.z);
 | 
				
			||||||
    let pitch = atanf(-measurement.x / (measurement.y * sinf(roll) + measurement.z * cosf(roll)));
 | 
					    let pitch = atanf(-measurement.x / (measurement.y * sinf(roll) + measurement.z * cosf(roll)));
 | 
				
			||||||
    Attitude { pitch, roll }
 | 
					    Attitude { pitch, roll }
 | 
				
			||||||
| 
						 | 
					@ -28,23 +29,30 @@ pub fn calc_tilt_calibrated_measurement(
 | 
				
			||||||
    attitde: &Attitude,
 | 
					    attitde: &Attitude,
 | 
				
			||||||
) -> NedMeasurement {
 | 
					) -> NedMeasurement {
 | 
				
			||||||
    //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
 | 
				
			||||||
 | 
					    // ø=roll,
 | 
				
			||||||
    let corrected_mag_y =
 | 
					    // θ=pitch,
 | 
				
			||||||
        mag_measurement.z * sinf(attitde.roll) - mag_measurement.y * cosf(attitde.roll);
 | 
					    // Bp{xyz} is magnometer readings,
 | 
				
			||||||
 | 
					    // V{xyz} is the magnometers constant hard-iron compnent, (currently taken care by micro:bits
 | 
				
			||||||
 | 
					    // library)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    let corrected_mag_x = mag_measurement.x * cosf(attitde.pitch)
 | 
					    let corrected_mag_x = mag_measurement.x * cosf(attitde.pitch)
 | 
				
			||||||
        + mag_measurement.y * sinf(attitde.pitch) * sinf(attitde.roll)
 | 
					        + mag_measurement.y * sinf(attitde.pitch) * sinf(attitde.roll)
 | 
				
			||||||
        + mag_measurement.z * sinf(attitde.pitch) * cosf(attitde.roll);
 | 
					        + mag_measurement.z * sinf(attitde.pitch) * cosf(attitde.roll);
 | 
				
			||||||
 | 
					    let corrected_mag_y =
 | 
				
			||||||
 | 
					        mag_measurement.y * cosf(attitde.roll) - mag_measurement.z * sinf(attitde.roll);
 | 
				
			||||||
 | 
					    let corrected_mag_z = -mag_measurement.x * sinf(attitde.pitch)
 | 
				
			||||||
 | 
					        + mag_measurement.y * cosf(attitde.pitch) * sinf(attitde.roll)
 | 
				
			||||||
 | 
					        + mag_measurement.z * cosf(attitde.pitch) * cosf(attitde.roll);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    NedMeasurement {
 | 
					    NedMeasurement {
 | 
				
			||||||
        x: corrected_mag_x,
 | 
					        x: corrected_mag_x,
 | 
				
			||||||
        y: corrected_mag_y,
 | 
					        y: corrected_mag_y,
 | 
				
			||||||
        z: 0.0,
 | 
					        z: corrected_mag_z,
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//0 is the top sector and positive is clockwise, negative is counterclockwise.
 | 
					//0 is the top sector and positive is clockwise, negative is counterclockwise.
 | 
				
			||||||
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))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue