Skip to content
Permalink
Browse files

feature: added BMP280 support for pressure altitude sensor. If pressure

altitude is available, send it in Ownship report and do not apply GNSS
delta to other traffic targets.
  • Loading branch information...
dndx committed Jul 28, 2018
1 parent 3228327 commit 1201c5b8adef9766acef26dcb86ab7af8a405f97
Showing with 378 additions and 19 deletions.
  1. +207 −0 Cargo.lock
  2. +3 −0 Cargo.toml
  3. +7 −0 src/main.rs
  4. +23 −0 src/processor/ownship.rs
  5. +53 −18 src/protocol/gdl90.rs
  6. +61 −0 src/sensor/barometer/bmp280.rs
  7. +17 −0 src/sensor/barometer/mod.rs
  8. +2 −0 src/sensor/mod.rs
  9. +3 −1 webui/index.html
  10. +2 −0 webui/js/index.js

Large diffs are not rendered by default.

@@ -22,3 +22,6 @@ ws = "0.7.1"
libc = "0.2.23"
inotify = "0.4.1"
icmp = "0.1.5"
i2csensors = "0.1.*"
i2cdev-bmp280 = "0.1.*"
i2cdev = "0.3.1"
@@ -25,6 +25,9 @@ extern crate serde_json;
extern crate time;
#[macro_use]
extern crate serde_derive;
extern crate i2cdev_bmp280;
extern crate i2csensors;
extern crate i2cdev;
extern crate icmp;
extern crate inotify;
extern crate libc;
@@ -51,6 +54,10 @@ fn main() {
p.link_sensor(g);
Some(())
});
sensor::barometer::bmp280::BMP280BaroProvider::new().and_then(&mut |b| {
p.link_sensor(b);
Some(())
});
sensor::sdr::es::ES::new().and_then(&mut |e| {
p.link_sensor(Box::new(e) as Box<Sensor>);
Some(())
@@ -27,6 +27,10 @@ pub struct Ownship {
pub lon: f32,
/// Height above WGS-84 ellipsoid if available, otherwise MSL in ft
pub altitude: i32,
/// Cabin pressure altitude in ft
pub pressure_altitude: Option<i32>,
/// Vertical speed
pub vs: Option<i32>,
/// NIC
pub nic: u8,
/// NACp
@@ -72,6 +76,25 @@ impl Processor for Ownship {

handle.push_data(Report::Ownship(*self));
}
SensorData::Baro(b) => {
let dt = 1_f32 / handle.get_frequency() as f32;
let vs_update_pct = 5_f32 / (5_f32 + dt);

if let Some(last_pres_alt) = self.pressure_altitude {
self.vs = Some(if let Some(vs) = self.vs {
(vs_update_pct * vs as f32
+ (1_f32 - vs_update_pct) * (b - last_pres_alt) as f32
/ (dt / 60_f32))
.round() as i32
} else {
0
});
}

self.pressure_altitude = Some(b);

handle.push_data(Report::Ownship(*self));
}
_ => {} // do nothing
}
}
@@ -57,6 +57,8 @@ pub struct GDL90 {
ownship_valid: bool,
heartbeat_counter: u32,
ownship_counter: u32,
/// true if Pressure altitude source exists
pres_alt_valid: bool,
}

impl Protocol for GDL90 {
@@ -73,13 +75,17 @@ impl Protocol for GDL90 {
self.ownship_counter = 0;
self.ownship_valid = o.valid;

if o.pressure_altitude.is_some() {
self.pres_alt_valid = true;
}

handle.push_data(GDL90::generate_ownship(o));
handle.push_data(GDL90::generate_ownship_geometric_altitude(o));
}
}
Report::Traffic(ref o) => {
// throttle for Target type is done at traffic processor
handle.push_data(GDL90::generate_traffic(o, clock));
handle.push_data(GDL90::generate_traffic(o, clock, self.pres_alt_valid));
}
Report::FISB(ref o) => handle.push_data(GDL90::generate_uplink(o)),
_ => {}
@@ -215,11 +221,14 @@ impl GDL90 {
buf[10] = lon3;

// altitude
// let alt = alt_to_gdl90(e.altitude as f32);
// buf[11] = ((alt & 0xFF0) >> 4) as u8;
// buf[12] = (((alt & 0x00F) << 4) | 0x09) as u8; // Airborne + True Track
buf[11] = 0xFF;
buf[12] = 0xF9; // Airborne + True Track
if let Some(alt) = e.pressure_altitude {
let alt = alt_to_gdl90(alt as f32);
buf[11] = ((alt & 0xFF0) >> 4) as u8;
buf[12] = (((alt & 0x00F) << 4) | 0x09) as u8; // Airborne + True Track
} else {
buf[11] = 0xFF;
buf[12] = 0xF9; // Airborne + True Track
}

buf[13] = (e.nic << 4) & 0xF0 | e.nacp & 0x0F;

@@ -245,7 +254,7 @@ impl GDL90 {
}
}

fn generate_traffic(e: &Target, clock: Instant) -> Payload {
fn generate_traffic(e: &Target, clock: Instant, pres_alt_valid: bool) -> Payload {
let mut buf = [0_u8; 28 + 2]; // incl CRC field

buf[0] = 0x14;
@@ -285,20 +294,26 @@ impl GDL90 {
// altitude
if let Some((alt, typ, i)) = e.altitude {
if (clock - i).as_secs() <= MAX_STALE_SECS {
// GDL90 wants pres altitude, try to calculate it from GNSS altitude
// if correction is available

let mut corrected_alt = alt;

// Note: GDL90 wants pressure altitude here,
// but FF currently uses MSL altitude from
// ownship geometric report when calculating altitude
// difference, this is to correct Baro altitude
// to MSL so that the calculation will be as accurate as possible
if typ == AltitudeType::Baro {
// if ownship pressure altitude is NOT available, use MSL and attempt to correct it
// using GNSS delta if needed
if !pres_alt_valid && typ == AltitudeType::Baro {
// GDL90 wants pres altitude, try to calculate it from GNSS altitude
// if correction is available

// Note: GDL90 wants pressure altitude here,
// but FF currently uses MSL altitude from
// ownship geometric report when calculating altitude
// difference, this is to correct Baro altitude
// to MSL so that the calculation will be as accurate as possible
if let Some(delta) = e.gnss_delta {
corrected_alt += delta;
}
} else if pres_alt_valid && typ == AltitudeType::GNSS {
if let Some(delta) = e.gnss_delta {
corrected_alt -= delta;
}
}

let alt = alt_to_gdl90(corrected_alt as f32);
@@ -444,6 +459,7 @@ impl GDL90 {
ownship_valid: false,
heartbeat_counter: 0,
ownship_counter: 0,
pres_alt_valid: false,
})
}
}
@@ -534,7 +550,7 @@ mod tests {
trfc.nacp = Some(9);
trfc.on_ground = Some(false);

let payload = GDL90::generate_traffic(&trfc, clock);
let payload = GDL90::generate_traffic(&trfc, clock, false);
let expected = [
0x7E, 0x14, 0x00, 0xA1, 0xB2, 0xC3, 0x1A, 0xD8, 0x3F, 0xA8, 0xDE, 0xAF, 0x23, 0xF9,
0x79, 0x04, 0x2F, 0xF0, 0x57, 0x03, 'e' as u8, 'a' as u8, 'T' as u8, 'E' as u8,
@@ -543,14 +559,33 @@ mod tests {

assert_eq!(payload.payload, &expected);

let payload = GDL90::generate_traffic(&trfc, clock, true);
let expected = [
0x7E, 0x14, 0x00, 0xA1, 0xB2, 0xC3, 0x1A, 0xD8, 0x3F, 0xA8, 0xDE, 0xAF, 0x21, 0x79,
0x79, 0x04, 0x2F, 0xF0, 0x57, 0x03, 'e' as u8, 'a' as u8, 'T' as u8, 'E' as u8,
'S' as u8, 'T' as u8, '1' as u8, '2' as u8, 0x00, 0xEA, 0xC4, 0x7E,
];

assert_eq!(payload.payload, &expected);

trfc.callsign = None;
let payload = GDL90::generate_traffic(&trfc, clock);
let payload = GDL90::generate_traffic(&trfc, clock, false);
let expected = [
0x7E, 0x14, 0x00, 0xA1, 0xB2, 0xC3, 0x1A, 0xD8, 0x3F, 0xA8, 0xDE, 0xAF, 0x23, 0xF9,
0x79, 0x04, 0x2F, 0xF0, 0x57, 0x03, 'e' as u8, 'a' as u8, '0' as u8, '1' as u8,
'2' as u8, '3' as u8, 0x00, 0x00, 0x00, 0x87, 0xEC, 0x7E,
];

assert_eq!(payload.payload, &expected);

trfc.altitude = Some((12375, AltitudeType::GNSS, clock));
let payload = GDL90::generate_traffic(&trfc, clock, true);
let expected = [
0x7E, 0x14, 0x00, 0xA1, 0xB2, 0xC3, 0x1A, 0xD8, 0x3F, 0xA8, 0xDE, 0xAF, 0x1E, 0xF9,
0x79, 0x04, 0x2F, 0xF0, 0x57, 0x03, 'e' as u8, 'a' as u8, '0' as u8, '1' as u8,
'2' as u8, '3' as u8, 0x00, 0x00, 0x00, 0x12, 0x2D, 0x7E,
];

assert_eq!(payload.payload, &expected);
}
}
@@ -0,0 +1,61 @@
// Pitot - a customizable aviation information receiver
// Copyright (C) 2017-2018 Datong Sun (dndx@idndx.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use i2cdev::linux::LinuxI2CDevice;
use i2cdev_bmp280::*;
use i2csensors::Barometer;
use pitot::handle::Pushable;
use sensor::{Sensor, SensorData};

const BMP280_I2C_ADDR: u16 = 0x76;
const I2C_DEV: &'static str = "/dev/i2c-1";
const SEA_LEVEL_QNH: f32 = 101.325;

pub struct BMP280BaroProvider {
bmp280: BMP280<LinuxI2CDevice>,
}

impl BMP280BaroProvider {
pub fn new() -> Option<Box<Sensor>> {
let i2c_device = LinuxI2CDevice::new(I2C_DEV, BMP280_I2C_ADDR).unwrap();

let settings = BMP280Settings {
compensation: BMP280CompensationAlgorithm::B64,
t_sb: BMP280Timing::ms0_5,
iir_filter_coeff: BMP280FilterCoefficient::Medium,
osrs_t: BMP280TemperatureOversampling::x1,
osrs_p: BMP280PressureOversampling::StandardResolution,
power_mode: BMP280PowerMode::NormalMode,
};

if let Ok(b) = BMP280::new(i2c_device, settings) {
Some(Box::new(Self { bmp280: b }))
} else {
info!("BMP280 not found!");
None
}
}
}

impl Sensor for BMP280BaroProvider {
fn run(&mut self, h: &mut Pushable<SensorData>) {
let pressure = self.bmp280.pressure_kpa().unwrap();

let altitude = 145366.45 * (1_f32 - (pressure / SEA_LEVEL_QNH).powf(0.190284));

h.push_data(SensorData::Baro(altitude.round() as i32))
}
}
@@ -0,0 +1,17 @@
// Pitot - a customizable aviation information receiver
// Copyright (C) 2017-2018 Datong Sun (dndx@idndx.com)
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

pub mod bmp280;
@@ -14,6 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

pub mod barometer;
pub mod gnss;
pub mod sdr;

@@ -29,6 +30,7 @@ pub enum SensorData {
GNSS(GNSSData),
Traffic(TrafficData),
FISB(FISBData),
Baro(i32),
}

/// A type for representing a sensor
@@ -17,7 +17,9 @@ <h1>Pitot Status</h1>
<b>Connection to Pitot: </b><span id="conn_stat">Disconnected</span><br>
<b>Latitude: </b><span id="lat">Unknown</span><br>
<b>Longitude: </b><span id="lon">Unknown</span><br>
<b>Altitude: </b><span id="alt">Unknown</span> ft<br>
<b>MSL Altitude: </b><span id="alt">Unknown</span> ft<br>
<b>Pressure Altitude: </b><span id="pres_alt">Unknown</span> ft<br>
<b>Vertical speed: </b><span id="vs">Unknown</span> fpm<br>
<b>Track: </b><span id="track">Unknown</span>&deg;<br>
<b>Ground speed: </b><span id="gs">Unknown</span> kts<br>
<b>Fix quality: </b><span id="fix_quality">Unknown</span> <span id="nacp"></span><br>
@@ -60,6 +60,8 @@
$('#track').text(m.track.toFixed(0));
$('#nacp').text('(' + nacp[m.nacp] + ')');
$('#gs').text(m.gs.toFixed(0));
$('#vs').text(m.vs);
$('#pres_alt').text(m.pressure_altitude);
break;
}
};

0 comments on commit 1201c5b

Please sign in to comment.
You can’t perform that action at this time.