dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
airspeed.c
Go to the documentation of this file.
1 
17 /*
18  * This program is free software; you can redistribute it and/or modify
19  * it under the terms of the GNU General Public License as published by
20  * the Free Software Foundation; either version 3 of the License, or
21  * (at your option) any later version.
22  *
23  * This program is distributed in the hope that it will be useful, but
24  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
25  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
26  * for more details.
27  *
28  * You should have received a copy of the GNU General Public License along
29  * with this program; if not, see <http://www.gnu.org/licenses/>
30  */
31 
39 #include "openpilot.h"
40 #include "physical_constants.h"
41 #include "atmospheric_math.h"
42 #include "coordinate_conversions.h"
43 
44 #include "modulesettings.h"
45 #include "gpsvelocity.h"
46 #include "airspeedsettings.h"
47 #include "gps_airspeed.h"
48 #include "homelocation.h"
49 #include "baroairspeed.h" // object that will be updated by the module
50 #include "airspeedactual.h" // object that will be updated by the module
51 #include "attitudeactual.h"
52 #include "positionactual.h"
53 
54 #include "baro_airspeed_etasv3.h"
55 #include "baro_airspeed_analog.h"
56 #include "pios_thread.h"
57 
58 // Private constants
59 #if defined (PIOS_INCLUDE_GPS)
60  #define GPS_AIRSPEED_PRESENT
61 #endif
62 
63 #if defined (PIOS_INCLUDE_MPXV5004) || defined (PIOS_INCLUDE_MPXV7002) || defined (PIOS_INCLUDE_ETASV3) || defined(PIOS_INCLUDE_ADC)
64  #define BARO_AIRSPEED_PRESENT
65 #endif
66 
67 #if defined (GPS_AIRSPEED_PRESENT) && defined (BARO_AIRSPEED_PRESENT)
68  #define STACK_SIZE_BYTES 700
69 #elif defined (GPS_AIRSPEED_PRESENT)
70  #define STACK_SIZE_BYTES 600
71 #elif defined (BARO_AIRSPEED_PRESENT)
72  #define STACK_SIZE_BYTES 550
73 #else
74  #define STACK_SIZE_BYTES 0
75  #define NO_AIRSPEED_SENSOR_PRESENT
76 #endif
77 
78 #define TASK_PRIORITY PIOS_THREAD_PRIO_LOW
79 
80 #define SAMPLING_DELAY_MS_FALLTHROUGH 50 //Fallthrough update at 20Hz. The fallthrough runs faster than the GPS to ensure that we don't miss GPS updates because we're slightly out of sync
81 
82 #define GPS_AIRSPEED_BIAS_KP 0.01f //Needs to be settable in a UAVO
83 #define GPS_AIRSPEED_BIAS_KI 0.01f //Needs to be settable in a UAVO
84 #define GPS_AIRSPEED_TIME_CONSTANT_MS 500.0f //Needs to be settable in a UAVO
85 
86 #define BARO_TEMPERATURE_OFFSET 5
87 
88 // Private types
89 
90 // Private variables
91 static struct pios_thread *taskHandle;
92 static bool module_enabled = false;
93 volatile bool gpsNew = false;
94 volatile bool settingsUpdated = true;
95 static uint8_t airspeedSensorType;
96 static uint16_t gpsSamplePeriod_ms;
97 static float tasFilterTau = 0.1f;
98 
99 #ifdef BARO_AIRSPEED_PRESENT
100 static int8_t airspeedADCPin = -1;
101 #endif
102 
103 // Private functions
104 static void airspeedTask(void *parameters);
105 void baro_airspeedGet(BaroAirspeedData *baroAirspeedData, uint32_t *lastSysTime, uint8_t airspeedSensorType, int8_t airspeedADCPin);
106 
111 int32_t AirspeedStart()
112 {
113 #if defined (NO_AIRSPEED_SENSOR_PRESENT)
114  return -1;
115 #endif
116 
117  //Check if module is enabled or not
118  if (module_enabled == false) {
119  return -1;
120  }
121 
122  // Start main task
124  TaskMonitorAdd(TASKINFO_RUNNING_AIRSPEED, taskHandle);
125  return 0;
126 }
127 
128 static void doSettingsUpdate()
129 {
130  AirspeedSettingsData settings;
131 
132  AirspeedSettingsGet(&settings);
133 
134  airspeedSensorType = settings.AirspeedSensorType;
135  gpsSamplePeriod_ms = settings.GPSSamplePeriod_ms;
136  tasFilterTau = settings.TASFilterTau;
137 
138 #if defined(PIOS_INCLUDE_MPXV7002)
139  if (airspeedSensorType==AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_DIYDRONESMPXV7002) {
140  PIOS_MPXV7002_UpdateCalibration(settings.ZeroPoint); //This makes sense for the user if the initial calibration was not good and the user does not wish to reboot.
141  }
142 #endif
143 #if defined(PIOS_INCLUDE_MPXV5004)
144  if (airspeedSensorType==AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_DIYDRONESMPXV5004) {
145  PIOS_MPXV5004_UpdateCalibration(settings.ZeroPoint);
146  }
147 #endif
148 }
149 
155 {
156  if (AirspeedSettingsInitialize() == -1) {
157  module_enabled = false;
158  return -1;
159  }
160 
161 #ifdef MODULE_Airspeed_BUILTIN
162  module_enabled = true;
163 #else
164  uint8_t module_state[MODULESETTINGS_ADMINSTATE_NUMELEM];
165  ModuleSettingsAdminStateGet(module_state);
166  if (module_state[MODULESETTINGS_ADMINSTATE_AIRSPEED] == MODULESETTINGS_ADMINSTATE_ENABLED) {
167  module_enabled = true;
168  } else {
169  module_enabled = false;
170  }
171 #endif
172 
173  if (!module_enabled)
174  return -1;
175 
176  if (BaroAirspeedInitialize() == -1) {
177  module_enabled = false;
178  return -1;
179  }
180 
181  if (AirspeedActualInitialize() == -1) {
182  module_enabled = false;
183  return -1;
184  }
185 
186 #ifdef BARO_AIRSPEED_PRESENT
187  // Get the analog pin
188  AirspeedSettingsAnalogPinGet((uint8_t *) &airspeedADCPin);
189  if (airspeedADCPin == AIRSPEEDSETTINGS_ANALOGPIN_NONE)
190  airspeedADCPin = -1;
191 #endif
192 
193  return 0;
194 }
196 
200 static void airspeedTask(void *parameters)
201 {
202  BaroAirspeedData airspeedData;
203  AirspeedActualData airspeedActualData;
204 
205 #ifdef BARO_AIRSPEED_PRESENT
206  float airspeedErrInt = 0;
207 
208 #ifdef GPS_AIRSPEED_PRESENT
209  uint32_t lastGPSTime = PIOS_Thread_Systime(); //Time since last GPS-derived airspeed calculation
210  uint32_t lastLoopTime = PIOS_Thread_Systime(); //Time since last loop
211  float airspeed_tas_baro = 0;
212 #endif
213 
214 #endif
215 
216  //GPS airspeed calculation variables
217 #ifdef GPS_AIRSPEED_PRESENT
218  GPSVelocityConnectCallbackCtx(UAVObjCbSetFlag, &gpsNew);
219  if (gps_airspeedInitialize() == -1) {
220  module_enabled = false;
221  return;
222  }
223 #endif
224 
225  AirspeedSettingsConnectCallbackCtx(UAVObjCbSetFlag, &settingsUpdated);
226 
227  // Main task loop
228  uint32_t lastSysTime = PIOS_Thread_Systime();
229 
230  // Get initial values of airspeed object
231  BaroAirspeedGet(&airspeedData);
232 
233  airspeedData.BaroConnected = BAROAIRSPEED_BAROCONNECTED_FALSE;
234 
235  while (1) {
236  if (settingsUpdated) {
237  settingsUpdated = false;
238 
240  }
241 
242 #ifdef BARO_AIRSPEED_PRESENT
243  if (airspeedSensorType != AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_GPSONLY) {
244  //Fetch calibrated airspeed from sensors
245  baro_airspeedGet(&airspeedData, &lastSysTime, airspeedSensorType, airspeedADCPin);
246 
247  //Calculate true airspeed, not taking into account compressibility effects
248  int16_t groundTemperature_10;
249  float groundTemperature;
250  float positionActual_Down;
251 
252  PositionActualDownGet(&positionActual_Down);
253  HomeLocationGroundTemperatureGet(&groundTemperature_10); // Gets tenths of degrees C
254  groundTemperature = groundTemperature_10/10; // Convert into degrees C
255  groundTemperature -= BARO_TEMPERATURE_OFFSET; //Do this just because we suspect that the board heats up relative to its surroundings. THIS IS BAD(tm)
256 
257  struct AirParameters air_STP = initialize_air_structure();
258  air_STP.air_temperature_at_surface = groundTemperature + CELSIUS2KELVIN;
259 
260  #ifdef GPS_AIRSPEED_PRESENT
261  //GPS present, so use baro sensor to filter TAS
262  airspeed_tas_baro =
263  cas2tas(airspeedData.CalibratedAirspeed, -positionActual_Down,
264  &air_STP) + airspeedErrInt * GPS_AIRSPEED_BIAS_KI;
265  #else
266  //No GPS, so TAS comes only from baro sensor
267  airspeedData.TrueAirspeed =
268  cas2tas(airspeedData.CalibratedAirspeed, -positionActual_Down,
269  &air_STP) + airspeedErrInt * GPS_AIRSPEED_BIAS_KI;
270  #endif
271  } else
272 #endif
273  { //Have to catch the fallthrough, or else this loop will monopolize the processor!
274  airspeedData.BaroConnected = BAROAIRSPEED_BAROCONNECTED_FALSE;
275  airspeedData.SensorValue = 12345;
276 
277  //Likely, we have a GPS, so let's configure the fallthrough at close to GPS refresh rates
279  }
280 
281 #ifdef GPS_AIRSPEED_PRESENT
282  float v_air_GPS = -1.0f;
283 
284  //Check if sufficient time has passed. This will depend on whether we have a pitot tube
285  //sensor or not. In the case we do, shoot for about once per second. Otherwise, consume GPS
286  //as quickly as possible.
287  #ifdef BARO_AIRSPEED_PRESENT
288  float delT = (lastSysTime - lastLoopTime) / 1000.0f;
289  lastLoopTime = lastSysTime;
290  if ( ((lastSysTime - lastGPSTime) > 1000 || airspeedSensorType==AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_GPSONLY)
291  && gpsNew && airspeedSensorType != AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_RAWANALOG) {
292  lastGPSTime = lastSysTime;
293  #else
294  if (gpsNew) {
295  #endif
296  gpsNew = false; //Do this first
297 
298  //Calculate airspeed as a function of GPS groundspeed and vehicle attitude. From "IMU Wind Estimation (Theory)", by William Premerlani
299  gps_airspeedGet(&v_air_GPS);
300  }
301 
302  //Use the GPS error to correct the airspeed estimate.
303  if (v_air_GPS > 0) { //We have valid GPS estimate...
304  airspeedData.GPSAirspeed = v_air_GPS;
305 
306  #ifdef BARO_AIRSPEED_PRESENT
307  if (airspeedData.BaroConnected==BAROAIRSPEED_BAROCONNECTED_TRUE) { //Check if there is an airspeed sensors present...
308  //Calculate error and error integral
309  float airspeedErr = v_air_GPS - airspeed_tas_baro;
310  airspeedErrInt += airspeedErr * delT;
311 
312  //Saturate integral component at 5 m/s
313  airspeedErrInt = airspeedErrInt >
314  (5.0f / GPS_AIRSPEED_BIAS_KI) ? (5.0f / GPS_AIRSPEED_BIAS_KI) : airspeedErrInt;
315  airspeedErrInt = airspeedErrInt <
316  -(5.0f / GPS_AIRSPEED_BIAS_KI) ? -(5.0f / GPS_AIRSPEED_BIAS_KI) : airspeedErrInt;
317 
318  //There's already an airspeed sensor, so instead correct it for bias with P correction. The I correction happened earlier in the function.
319  airspeedData.TrueAirspeed = airspeed_tas_baro + airspeedErr * GPS_AIRSPEED_BIAS_KP;
320 
321  /* Note:
322  This would be a good place to change the airspeed calibration, so that it matches the GPS computed values. However,
323  this might be a bad idea, as their are two degrees of freedom here: temperature and sensor calibration. I don't
324  know how to control for temperature bias.
325  */
326  } else
327  #endif
328  {
329  //...there's no airspeed sensor, so everything comes from GPS. In this
330  //case, filter the airspeed for smoother output
331  float alpha = gpsSamplePeriod_ms/(gpsSamplePeriod_ms + GPS_AIRSPEED_TIME_CONSTANT_MS); //Low pass filter.
332  airspeedData.TrueAirspeed = v_air_GPS*(alpha) + airspeedData.TrueAirspeed*(1.0f-alpha);
333 
334  //Calculate calibrated airspeed from GPS, since we're not getting it from a discrete airspeed sensor
335  int16_t groundTemperature_10;
336  float groundTemperature;
337  float positionActual_Down;
338 
339  PositionActualDownGet(&positionActual_Down);
340  HomeLocationGroundTemperatureGet(&groundTemperature_10); // Gets tenths of degrees C
341  groundTemperature = groundTemperature_10/10; // Convert into degrees C
342  groundTemperature -= BARO_TEMPERATURE_OFFSET; //Do this just because we suspect that the board heats up relative to its surroundings. THIS IS BAD(tm)
343 
344  struct AirParameters air_STP = initialize_air_structure();
345  air_STP.air_temperature_at_surface = groundTemperature + CELSIUS2KELVIN;
346 
347  airspeedData.CalibratedAirspeed = tas2cas(airspeedData.TrueAirspeed, -positionActual_Down, &air_STP);
348  }
349  }
350  #ifdef BARO_AIRSPEED_PRESENT
351  else if (airspeedData.BaroConnected==BAROAIRSPEED_BAROCONNECTED_TRUE) {
352  //No GPS velocity estimate this loop, so filter true airspeed data with baro airspeed
353  float alpha = delT/(delT + tasFilterTau); //Low pass filter.
354  airspeedData.TrueAirspeed = airspeed_tas_baro*(alpha) + airspeedData.TrueAirspeed*(1.0f-alpha);
355  }
356  #endif
357 #endif
358  //Set the UAVO
359  airspeedActualData.TrueAirspeed = airspeedData.TrueAirspeed;
360  airspeedActualData.CalibratedAirspeed = airspeedData.CalibratedAirspeed;
361  BaroAirspeedSet(&airspeedData);
362  AirspeedActualSet(&airspeedActualData);
363  }
364 }
365 
366 #ifdef BARO_AIRSPEED_PRESENT
367 void baro_airspeedGet(BaroAirspeedData *baroAirspeedData, uint32_t *lastSysTime, uint8_t airspeedSensorType, int8_t airspeedADCPin_dummy)
368 {
369  //Find out which sensor we're using.
370  switch (airspeedSensorType) {
371  case AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_DIYDRONESMPXV7002:
372  case AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_DIYDRONESMPXV5004:
373  case AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_RAWANALOG:
374  baro_airspeedGetAnalog(baroAirspeedData, lastSysTime, airspeedSensorType, airspeedADCPin);
375  break;
376  case AIRSPEEDSETTINGS_AIRSPEEDSENSORTYPE_EAGLETREEAIRSPEEDV3:
377  //Eagletree Airspeed v3
378  baro_airspeedGetETASV3(baroAirspeedData, lastSysTime, airspeedSensorType, airspeedADCPin);
379  break;
380  default:
381  baroAirspeedData->BaroConnected = BAROAIRSPEED_BAROCONNECTED_FALSE;
383  break;
384  }
385 }
386 #endif
387 
float cas2tas(float CAS, float altitude, struct AirParameters *air)
cas2tas calculate TAS from CAS and altitude. http://en.wikipedia.org/wiki/Airspeed ...
struct AirParameters initialize_air_structure()
initialize_air_structure Initializes the structure with standard-temperature-pressure values ...
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
#define STACK_SIZE_BYTES
Definition: airspeed.c:74
int32_t gps_airspeedInitialize()
Definition: gps_airspeed.c:63
#define BARO_TEMPERATURE_OFFSET
Definition: airspeed.c:86
MODULE_INITCALL(AirspeedInitialize, AirspeedStart)
#define TASK_PRIORITY
Definition: airspeed.c:78
static bool module_enabled
Definition: airspeed.c:92
float air_temperature_at_surface
Read airspeed from analog sensor.
void UAVObjCbSetFlag(const UAVObjEvent *objEv, void *ctx, void *obj, int len)
static struct pios_thread * taskHandle
Definition: airspeed.c:91
#define GPS_AIRSPEED_TIME_CONSTANT_MS
Definition: airspeed.c:84
void PIOS_MPXV5004_UpdateCalibration(uint16_t zeroPoint)
Calculate airspeed using GPS.
static uint8_t airspeedSensorType
Definition: airspeed.c:95
Airspeed module, reads temperature and pressure from BMP085.
void baro_airspeedGetETASV3(BaroAirspeedData *baroAirspeedData, uint32_t *lastSysTime, uint8_t airspeedSensorType, int8_t airspeedADCPin)
float tas2cas(float TAS, float altitude, struct AirParameters *air)
tas2cas calculate CAS from TAS and altitude. http://en.wikipedia.org/wiki/Airspeed ...
static volatile FlightStatsSettingsData settings
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
void PIOS_MPXV7002_UpdateCalibration(uint16_t zeroPoint)
static float tasFilterTau
Definition: airspeed.c:97
static void airspeedTask(void *parameters)
Definition: airspeed.c:200
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
#define SAMPLING_DELAY_MS_FALLTHROUGH
Definition: airspeed.c:80
void baro_airspeedGetAnalog(BaroAirspeedData *baroAirspeedData, uint32_t *lastSysTime, uint8_t airspeedSensorType, int8_t airspeedADCPin)
volatile bool gpsNew
Definition: airspeed.c:93
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
Header for Coordinate conversions library in coordinate_conversions.c.
int32_t AirspeedStart()
Definition: airspeed.c:111
tuple f
Definition: px_mkfw.py:81
static uint16_t gpsSamplePeriod_ms
Definition: airspeed.c:96
Includes PiOS and core architecture components.
int32_t AirspeedInitialize()
Definition: airspeed.c:154
static void doSettingsUpdate()
Definition: airspeed.c:128
volatile bool settingsUpdated
Definition: airspeed.c:94
static uint32_t lastSysTime
void gps_airspeedGet(float *v_air_GPS)
Definition: gps_airspeed.c:103
void baro_airspeedGet(BaroAirspeedData *baroAirspeedData, uint32_t *lastSysTime, uint8_t airspeedSensorType, int8_t airspeedADCPin)
#define GPS_AIRSPEED_BIAS_KI
Definition: airspeed.c:83
#define GPS_AIRSPEED_BIAS_KP
Definition: airspeed.c:82