Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
airspeed_ms45xx_i2c.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2014 Freek van Tienen <freek.v.tienen@gmail.com>
3  * 2014 Felix Ruess <felix.ruess@gmail.com>
4  *
5  * This file is part of paparazzi
6  *
7  * paparazzi is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2, or (at your option)
10  * any later version.
11  *
12  * paparazzi is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with paparazzi; see the file COPYING. If not, write to
19  * the Free Software Foundation, 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22 
28 #include "std.h"
29 #include "mcu_periph/i2c.h"
32 #include "modules/core/abi.h"
33 
34 #include "mcu_periph/uart.h"
35 #include "pprzlink/messages.h"
37 
38 #if PERIODIC_TELEMETRY
40 #endif
41 
42 /* Enable ABI sending */
43 #ifndef AIRSPEED_MS45XX_SEND_ABI
44 #define AIRSPEED_MS45XX_SEND_ABI true
45 #endif
46 
49 #ifndef MS45XX_I2C_DEV
50 #define MS45XX_I2C_DEV i2c2
51 #endif
52 
55 #ifndef MS45XX_I2C_ADDR
56 #define MS45XX_I2C_ADDR 0x50
57 #endif
58 
62 #ifndef MS45XX_PRESSURE_OUTPUT_TYPE_InH2O
63 #define MS45XX_PRESSURE_OUTPUT_TYPE_InH2O 0
64 #endif
65 
70 #ifndef MS45XX_PRESSURE_RANGE
71 #define MS45XX_PRESSURE_RANGE 1
72 #endif
73 
76 #ifndef MS45XX_PRESSURE_TYPE
77 #define MS45XX_PRESSURE_TYPE 0
78 #endif
79 
82 #ifndef USE_AIRSPEED_LOWPASS_FILTER
83 #define USE_AIRSPEED_LOWPASS_FILTER TRUE
84 #endif
85 
90 #ifndef MS45XX_OUTPUT_TYPE
91 #define MS45XX_OUTPUT_TYPE 0
92 #endif
93 
95 #define InH2O_TO_PA 249.08891
96 
98 #define PSI_TO_PA 6894.75729
99 
100 #if MS45XX_PRESSURE_OUTPUT_TYPE_InH2O
101 #define OutputPressureToPa InH2O_TO_PA
102 #else
103 #define OutputPressureToPa PSI_TO_PA
104 #endif
105 
106 #if MS45XX_OUTPUT_TYPE == 0
107 /* Offset and scaling for OUTPUT TYPE A:
108  * p_raw = (0.8*16383)/ (Pmax - Pmin) * (pressure - Pmin) + 0.1*16383
109  * For differential sensors Pmax = MS45XX_PRESSURE_RANGE = -Pmin.
110  *
111  * p_diff = (p_raw - 0.1*16383) * 2*RANGE/(0.8*16383) - RANGE
112  * p_diff = p_raw * 2*RANGE/(0.8*16383) - (RANGE + (0.1 * 16383) * 2*RANGE/(0.8*16383)
113  * p_diff = p_raw * 2*RANGE/(0.8*16383) - (1.25 * RANGE)
114  * p_diff = (p_raw - offset) * scale
115  * then convert to Pascal
116  */
117 #ifndef MS45XX_PRESSURE_SCALE
118 #define MS45XX_PRESSURE_SCALE (2 * MS45XX_PRESSURE_RANGE / (0.8 * 16383) * OutputPressureToPa)
119 #endif
120 #ifndef MS45XX_PRESSURE_OFFSET
121 #define MS45XX_PRESSURE_OFFSET (16383 / 2)
122 #endif
123 #else /* Can still be improved using another if statment with MS45XX_PRESSURE_TYPE etc. */
124 /* Offset and scaling for OUTPUT TYPE B:
125  * p_raw = (0.9*16383)/ (Pmax - Pmin) * (pressure - Pmin) + 0.05*16383
126  */
127 #ifndef MS45XX_PRESSURE_SCALE
128 #define MS45XX_PRESSURE_SCALE (MS45XX_PRESSURE_RANGE/(0.9*16383)*OutputPressureToPa)
129 #endif
130 #ifndef MS45XX_PRESSURE_OFFSET
131 #define MS45XX_PRESSURE_OFFSET (0.05*16383)
132 #endif
133 #endif
134 
140 
141 
142 
147 #ifdef MS45XX_AIRSPEED_SCALE
148 PRINT_CONFIG_MSG("MS45XX changed air density. PS: Use MS45XX_PRESSURE_SCALE to calibrate the MS45XX.");
149 #endif
150 
151 #define MS45XX_RHO_DIV_2 1.6327
152 
153 
157 #ifndef MS45XX_LOWPASS_TAU
158 #define MS45XX_LOWPASS_TAU 0.15
159 #endif
160 
161 struct AirspeedMs45xx ms45xx;
162 static struct i2c_transaction ms45xx_trans;
163 #ifdef USE_AIRSPEED_LOWPASS_FILTER
165 #endif
166 
167 #if PREFLIGHT_CHECKS
168 /* Preflight checks */
170 static struct preflight_check_t ms45xx_i2c_pfc;
171 
172 static void ms45xx_preflight(struct preflight_result_t *result) {
173  if(ms45xx.offset_set) {
174  preflight_success(result, "Airspeed sensor succesfully nulled (MS45XX)");
175  } else {
176  preflight_error(result, "Airspeed sensor not nulled (MS45XX)");
177  }
178 }
179 #endif // PREFLIGHT_CHECKS
180 
181 static void ms45xx_downlink(struct transport_tx *trans, struct link_device *dev)
182 {
183  uint8_t dev_id = MS45XX_SENDER_ID;
184  float temp = ((float)ms45xx.temperature) * 0.1f;
185  pprz_msg_send_AIRSPEED_RAW(trans,dev,AC_ID,
186  &dev_id,
187  &ms45xx.raw_p,
189  &ms45xx.pressure,
190  &temp,
191  &ms45xx.airspeed);
192 }
193 
194 void ms45xx_i2c_init(void)
195 {
196  ms45xx.pressure = 0.;
197  ms45xx.temperature = 0;
198  ms45xx.airspeed = 0.;
199  ms45xx.raw_p = 0;
204  ms45xx.offset_set = false;
205 
207  // setup low pass filter with time constant and 100Hz sampling freq
208 #ifdef USE_AIRSPEED_LOWPASS_FILTER
210  MS45XX_I2C_PERIODIC_PERIOD, 0);
211 #endif
212 
213 #if PERIODIC_TELEMETRY
214  register_periodic_telemetry(DefaultPeriodic, PPRZ_MSG_ID_AIRSPEED_RAW, ms45xx_downlink);
215 #endif
216 
217  /* Register preflight checks */
218 #if PREFLIGHT_CHECKS
219  preflight_check_register(&ms45xx_i2c_pfc, ms45xx_preflight);
220 #endif
221 }
222 
223 
225 {
226  ms45xx.lowpass_tau = new_tau;
227 #ifdef USE_AIRSPEED_LOWPASS_FILTER
229  MS45XX_I2C_PERIODIC_PERIOD, get_butterworth_2_low_pass(&ms45xx_filter));
230 #endif
231 }
232 
233 
235 {
236  // Initiate next read
239  }
240 }
241 
242 #define AUTOSET_NB_MAX 200
243 
245 {
246  static int autoset_nb = 0;
247  static float autoset_offset = 0.f;
248 
249  /* Check if transaction is succesfull */
251 
252  /* 2 MSB of data are status bits, 0 = good data, 2 = already fetched, 3 = fault */
253  uint8_t status = (0xC0 & ms45xx_trans.buf[0]) >> 6;
254 
255  if (status == 0) {
256  /* 14bit raw pressure */
257  uint16_t p_raw = 0x3FFF & (((uint16_t)(ms45xx_trans.buf[0]) << 8) | (uint16_t)(ms45xx_trans.buf[1]));
258  ms45xx.raw_p = p_raw;
259 
260  /* 11bit raw temperature, 5 LSB bits not used */
261  uint16_t temp_raw = 0xFFE0 & (((uint16_t)(ms45xx_trans.buf[2]) << 8) |
262  (uint16_t)(ms45xx_trans.buf[3]));
263  temp_raw = temp_raw >> 5;
264 
265  /* Reject any values that are the absolute minimum or maximums these
266  can happen due to gnd lifts or communication errors on the bus */
267  if(p_raw == 0x3FFF || p_raw == 0 || temp_raw == 0x7FF || temp_raw == 0) {
269  return;
270  }
271 
272  /* For type Diff
273  * Output is proportional to the difference between Port 1 and Port 2. Output
274  * swings positive when Port 1> Port 2. Output is 50% of total counts
275  * when Port 1=Port 2.
276  * For type Gauge
277  * p_out = (p_raw - offset) * scale
278  */
279 
280  float p_out = (p_raw - ms45xx.pressure_offset) * ms45xx.pressure_scale;
281 
282  /* 0 = -50degC, 20147 = 150degC
283  * ms45xx_temperature in 0.1 deg Celcius
284  */
285  ms45xx.temperature = ((uint32_t)temp_raw * 2000) / 2047 - 500;
286 
287  // if(electrical.vboard != 0) {
288  // float volt_diff = electrical.vboard - 5.0f;
289  // Bound(volt_diff, -0.7f, 0.5f);
290 
291  // p_out -= 65.0f * volt_diff;
292  // ms45xx.temperature -= 8.87f * volt_diff;
293  // }
294 #ifdef USE_AIRSPEED_LOWPASS_FILTER
296 #else
297  ms45xx.pressure = p_out;
298 #endif
299 
300  if (ms45xx.autoset_offset) {
301  if (autoset_nb < AUTOSET_NB_MAX) {
302  autoset_offset += p_raw;
303  autoset_nb++;
304  } else {
305  ms45xx.pressure_offset = autoset_offset / (float)autoset_nb;
306  autoset_offset = 0.f;
307  autoset_nb = 0;
308  ms45xx.autoset_offset = false;
309  ms45xx.offset_set = true;
310  }
311  }
312 
313  // Send (differential) pressure via ABI
314  #if AIRSPEED_MS45XX_SEND_ABI
315  AbiSendMsgBARO_DIFF(MS45XX_SENDER_ID, ms45xx.pressure);
316 
317  // Send temperature as float in deg Celcius via ABI
318  float temp = ms45xx.temperature / 10.0f;
319 
320  AbiSendMsgTEMPERATURE(MS45XX_SENDER_ID, temp);
321  #endif
322 
323  // Compute airspeed
324  float sign = 1.0f;
325  if (ms45xx.pressure < 0.0f) {
326  sign = -1.0f;
327  }
329 
330  }
331 
332  // Set to done
334  } else if (ms45xx_trans.status == I2CTransFailed) {
335  // Just retry if failed
337  }
338 }
Main include for ABI (AirBorneInterface).
#define MS45XX_SENDER_ID
#define MS45XX_LOWPASS_TAU
Time constant for second order Butterworth low pass filter Default of 0.15 should give cut-off freq o...
#define MS45XX_RHO_DIV_2
Quadratic scale factor for indicated airspeed.
#define MS45XX_PRESSURE_RANGE
MS45xx pressure range in PSI or InH2O The sensor is available in many ranges, the datasheet of your p...
void ms45xx_i2c_event(void)
#define MS45XX_OUTPUT_TYPE
MS45xx output Type.
void ms45xx_i2c_periodic(void)
#define MS45XX_I2C_DEV
Default I2C device.
#define MS45XX_I2C_ADDR
Sensor I2C slave address (existing defaults 0x50, 0x6C and 0x8C)
void airspeed_ms45xx_i2c_change_tau(float new_tau)
struct AirspeedMs45xx ms45xx
static void ms45xx_downlink(struct transport_tx *trans, struct link_device *dev)
#define MS45XX_PRESSURE_TYPE
Pressure Type 0 = Differential, 1 = Gauge note there are theoretical more types than 2,...
#define MS45XX_PRESSURE_OFFSET
static struct i2c_transaction ms45xx_trans
static Butterworth2LowPass ms45xx_filter
#define AUTOSET_NB_MAX
#define MS45XX_PRESSURE_SCALE
void ms45xx_i2c_init(void)
Airspeed driver for the MS45xx pressure sensor via I2C.
float pressure_scale
Scaling factor from raw measurement to Pascal.
bool autoset_offset
Set offset value from current filtered value.
float pressure_offset
Offset in Pascal.
uint16_t raw_p
Raw pressure.
bool offset_set
Offset is set once.
bool pressure_type
Pressure type Differential of Gauge.
float pressure
(differential) pressure in Pascal
int16_t temperature
Temperature in 0.1 deg Celcius.
float lowpass_tau
Time constant for low pass filter.
float airspeed
Airspeed in m/s estimated from (differential) pressure.
volatile uint8_t buf[I2C_BUF_LEN]
Transaction buffer With I2C_BUF_LEN number of bytes.
Definition: i2c.h:122
enum I2CTransactionStatus status
Transaction status.
Definition: i2c.h:126
bool i2c_receive(struct i2c_periph *p, struct i2c_transaction *t, uint8_t s_addr, uint16_t len)
Submit a read only transaction.
Definition: i2c.c:334
@ I2CTransSuccess
transaction successfully finished by I2C driver
Definition: i2c.h:57
@ I2CTransFailed
transaction failed
Definition: i2c.h:58
@ I2CTransDone
transaction set to done by user level
Definition: i2c.h:59
I2C transaction structure.
Definition: i2c.h:93
Architecture independent I2C (Inter-Integrated Circuit Bus) API.
PRINT_CONFIG_MSG("USE_INS_NAV_INIT defaulting to TRUE")
Simple first order low pass filter with bilinear transform.
static float get_butterworth_2_low_pass(Butterworth2LowPass *filter)
Get current value of the second order Butterworth low pass filter.
static void init_butterworth_2_low_pass(Butterworth2LowPass *filter, float tau, float sample_time, float value)
Init a second order Butterworth filter.
static float update_butterworth_2_low_pass(Butterworth2LowPass *filter, float value)
Update second order Butterworth low pass filter state with a new value.
Second order low pass filter structure.
static float sign(float x)
sign function
Definition: nav_fish.c:232
uint8_t status
PRINT_CONFIG_VAR(ONELOOP_ANDI_FILT_CUTOFF)
void preflight_error(struct preflight_result_t *result, const char *fmt,...)
Register a preflight error used inside the preflight checking functions.
void preflight_success(struct preflight_result_t *result, const char *fmt,...)
Register a preflight success used inside the preflight checking functions.
void preflight_check_register(struct preflight_check_t *check, preflight_check_f func)
Register a preflight check and add it to the linked list.
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98