Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
cloud_sensor.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2019 Gautier Hattenberger <gautier.hattenberger@enac.fr>
3 * Titouan Verdu <titouan.verdu@enac.fr>
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, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
34
35#include "generated/airframe.h"
36#include "state.h"
37#include "modules/core/abi.h"
38#include "pprzlink/messages.h"
41#include "math/pprz_stat.h"
42#include "modules/gps/gps.h"
44
45#ifndef SITL
48#endif
49
50// log to flight recorder by default
51#ifndef CLOUD_SENSOR_LOG_FILE
52#define CLOUD_SENSOR_LOG_FILE flightrecorder_sdlog
53#endif
54
55// max number of values received from cloud sensor
56#ifndef CLOUD_SENSOR_RAW_MAX
57#define CLOUD_SENSOR_RAW_MAX 16
58#endif
59
60// number of actual cloud sensor channels
61#ifndef CLOUD_SENSOR_NB
62#define CLOUD_SENSOR_NB 4
63#endif
64
65// offset inside the raw value array to get cloud sensor channels
66#ifndef CLOUD_SENSOR_OFFSET
67#define CLOUD_SENSOR_OFFSET 4
68#endif
69
70// threshold for cloud border
71#ifndef CLOUD_SENSOR_BORDER_THRESHOLD
72#define CLOUD_SENSOR_BORDER_THRESHOLD 0.05
73#endif
74
75// histeresis for cloud border
76#ifndef CLOUD_SENSOR_BORDER_HYSTERESIS
77#define CLOUD_SENSOR_BORDER_HYSTERESIS 0.01
78#endif
79
80// default cloud sensor channel for single detection
81#ifndef CLOUD_SENSOR_SINGLE_CHANNEL
82#define CLOUD_SENSOR_SINGLE_CHANNEL 1
83#endif
84
85// default coef for auto-threshold from background data
86#ifndef CLOUD_SENSOR_BACKGROUND_THRESHOLD_COEF
87#define CLOUD_SENSOR_BACKGROUND_THRESHOLD_COEF 2.f
88#endif
89
90// default coef for auto-hysteresis from background data
91#ifndef CLOUD_SENSOR_BACKGROUND_HYSTERESIS_COEF
92#define CLOUD_SENSOR_BACKGROUND_HYSTERESIS_COEF 0.5f
93#endif
94
95#ifndef CLOUD_SENSOR_CALIB_ALPHA
96#define CLOUD_SENSOR_CALIB_ALPHA 1.f
97#endif
98
99#ifndef CLOUD_SENSOR_CALIB_BETA
100#define CLOUD_SENSOR_CALIB_BETA 1.f
101#endif
102
103#ifndef CLOUD_SENSOR_CHANNEL_SCALE
104#define CLOUD_SENSOR_CHANNEL_SCALE 1.f
105#endif
106
107#ifndef CLOUD_SENSOR_TAU
108#define CLOUD_SENSOR_TAU 0.f
109#endif
110
111// Type of data
112#define CLOUD_RAW 0 // LWC value
113#define CLOUD_BORDER 1 // crossing border
114
115// don't report border detection by default
116#ifndef CLOUD_SENSOR_REPORT_BORDER_CROSSING
117#define CLOUD_SENSOR_REPORT_BORDER_CROSSING FALSE
118#endif
119
120// default frequencies of cloud sensor leds
121// blue, orange, iri1, iri2
122#ifndef CLOUD_SENSOR_LAMBDA
123#define CLOUD_SENSOR_LAMBDA { 505.f, 590.f, 840.f, 840.f }
124#endif
126
127// default calibration coefficient for Angstrom coef
128#ifndef CLOUD_SENSOR_ANGSTROM_COEF
129#define CLOUD_SENSOR_ANGSTROM_COEF { 1.f, 1.f, 1.f, 1.f }
130#endif
132
133// default calibration offset for Angstrom coef
134#ifndef CLOUD_SENSOR_ANGSTROM_OFFSET
135#define CLOUD_SENSOR_ANGSTROM_OFFSET { 1.f, 1.f, 1.f, 1.f }
136#endif
138
145struct LinReg {
148};
149
150// number of samples to compute the background caracteristics
151#ifndef CLOUD_SENSOR_BACKGROUND_NB
152#define CLOUD_SENSOR_BACKGROUND_NB 30
153#endif
154
165
177
182 int length; // init to 0
183 int current; // init to 0
184 float values[3]; // is a circular buffer size MUST be 3
185};
186
190static bool log_tagged;
193
205
206// handle precomputed LWC
207static float lwc_from_buffer(uint8_t *buf)
208{
209 int res = 0;
210 for (int i = 0; i < DL_PAYLOAD_COMMAND_command_length(buf); i++) {
211 res = res * 10 + DL_PAYLOAD_COMMAND_command(buf)[i];
212 }
213 float lwc = (float) res;
214 return lwc;
215}
216
217// send CLOUD_SENSOR message
218static void send_cloud_sensor_data(struct transport_tx *trans, struct link_device *dev)
219{
220 uint8_t nb = 1;
221 float * val = cloud_sensor.raw;
222 if (cloud_sensor.nb_raw > 0) {
223 nb = cloud_sensor.nb_raw;
224 }
226 &stateGetPositionLla_i()->lat,
227 &stateGetPositionLla_i()->lon,
228 &gps.hmsl,
229 &gps.tow,
231 nb, val);
232}
233
234#if CLOUD_SENSOR_REPORT_BORDER_CROSSING
235// send DC_SHOT message when crossing border
236static void border_send_shot_position(void)
237{
238 static int16_t border_point_nr = 0;
239 // angles in decideg
240 int16_t phi = DegOfRad(stateGetNedToBodyEulers_f()->phi * 10.0f);
241 int16_t theta = DegOfRad(stateGetNedToBodyEulers_f()->theta * 10.0f);
242 int16_t psi = DegOfRad(stateGetNedToBodyEulers_f()->psi * 10.0f);
243 // course in decideg
245 // ground speed in cm/s
247
250 &stateGetPositionLla_i()->lat,
251 &stateGetPositionLla_i()->lon,
252 &stateGetPositionLla_i()->alt,
253 &gps.hmsl,
254 &phi,
255 &theta,
256 &psi,
257 &course,
258 &speed,
259 &gps.tow);
260
262}
263#endif
264
265// test border crossing
266static void check_border(void)
267{
269#if CLOUD_SENSOR_REPORT_BORDER_CROSSING
271#endif
274#if CLOUD_SENSOR_REPORT_BORDER_CROSSING
276#endif
278 }
279}
280
281// send ABI message
288
289// init
291{
292 for (int i = 0; i < CLOUD_SENSOR_NB; i++) {
293 cloud_sensor.values[i] = 0.f;
296 cloud_sensor.background.std[i] = -1.f; // means invalid data or not ready
298 }
299 cloud_sensor.coef = 0.f;
302
304
305 cloud_sensor_compute_coef = CLOUD_SENSOR_COEF_SINGLE; // coef from single channel by default
312 cloud_sensor_background = 0.f; // this should be found during the flight
313
314 // Inittializing median filter
317
318 // Initializing low-pass filter (tau is in samples, not seconds)
320
321 log_tagged = false;
322}
323
329
332float median_filter_update(float new_sample, struct MedianFilter* filter) {
333
334 // Updating filter state
335 filter->values[filter->current] = new_sample;
336 filter->current++;
337 filter->current %= 3; // looping on 3 indexes
338
339 if (filter->length < 3) {
340 // Here we are still in an initialization step (we need at least 3
341 // sample to process a median value.
342 filter->length++;
343 return new_sample; // returning here bypassing the nominal process.
344 }
345
346 // Here we are in nominal processing. Finding the median value in
347 // filter.values.
348
349 if (filter->values[0] >= filter->values[1]) {
350 if (filter->values[0] < filter->values[2]) {
351 return filter->values[0];
352 }
353 else {
354 // here values[0] is the greatest value->
355 if (filter->values[1] >= filter->values[2]) {
356 return filter->values[1];
357 }
358 else {
359 return filter->values[2];
360 }
361 }
362 }
363 else {
364 if (filter->values[0] >= filter->values[2]) {
365 return filter->values[0];
366 }
367 else {
368 // here values[0] is the lowest value->
369 if (filter->values[1] <= filter->values[2]) {
370 return filter->values[1];
371 }
372 else {
373 return filter->values[2];
374 }
375 }
376 }
377
378 // we should never get here
379 return new_sample; // always return something just in case.
380}
381
398{
401
402 if (nb > 0) {
403 // new data
404 //float *values = pprzlink_get_DL_PAYLOAD_FLOAT_values(buf);
405 float values[nb];
406 //store values from Cloud_sensor
407 memcpy(values, pprzlink_get_DL_PAYLOAD_FLOAT_values(buf), nb*sizeof(float));
408 // copy raw values in cloud_sensor.raw
409 memcpy(cloud_sensor.raw, values, cloud_sensor.nb_raw * sizeof(float));
411
413 const uint8_t channel = CLOUD_SENSOR_SINGLE_CHANNEL; // short name for single channel
414 //Use values to make the filter processing
416 //copy filtered values in unused cloud_sensor.raw channel for feedback in GCS in rela time
418
419 // first check that frame is long enough
420 if (nb > CLOUD_SENSOR_OFFSET + channel) {
422 if (values[CLOUD_SENSOR_OFFSET + channel] > 1.f) { // FIXME stupid ack to remove 0 values during calibration
423 // store a list of raw values
425 cloud_sensor.background.raw[channel][idx++] = values[CLOUD_SENSOR_OFFSET + channel];
427 // raw value buffer is full
428 // compute the background as the mean of the list
429 // compute threshold as n-times the std of the list
432 // use the copy to be able to change the value by hand from settings
434 // set the threshold
437 // reset index
439 // end procedure
441 }
442 else {
443 cloud_sensor.background.idx = idx; // increment index
444 }
445 }
446 }
447 else {
448 // normal run
449 // compute coef from a single channel
451 // test border crossing and send data over ABI
452 check_border();
454 }
455 }
456 }
458 // compute angstrom coef from available channels
459 // first check that frame is long enough
460 if ((nb >= CLOUD_SENSOR_OFFSET + CLOUD_SENSOR_NB)) {
463 // store a list of raw values for all channels
464 for (int i = 0; i < CLOUD_SENSOR_NB; i++) {
466 }
467 idx++;
469 // raw value buffer is full
470 // compute the background as the mean of the list
471 for (int i = 0; i < CLOUD_SENSOR_NB; i++) {
474 }
475 // TODO compute some threshold and hysteresis
476 // reset index
478 // end procedure
480 }
481 else {
482 cloud_sensor.background.idx = idx; // increment index
483 }
484 }
485 else {
486 // normal run
487 for (int i = 0; i < CLOUD_SENSOR_NB; i++) {
488 float scaled = (values[CLOUD_SENSOR_OFFSET + i] - cloud_sensor.background.mean[i]) * angstrom_coef[i] + angstrom_offset[i];
489 cloud_sensor.values[i] = logf(scaled);
490 }
491
492 // compute coef with a linear regression from cloud sensor raw data
495 cloud_sensor.coef = angstrom; // That's it ????
496
497 // test border crossing and send data over ABI
498 check_border();
500 }
501 }
502 }
503 // else don't check border from sensor
504
505
506#if (defined CLOUD_SENSOR_LOG_FILE) && !(defined SITL)
507 // Log on SD card in flight recorder
508 if (CLOUD_SENSOR_LOG_FILE.file != NULL && *(CLOUD_SENSOR_LOG_FILE.file) != -1) {
509 if (log_tagged == false && GpsFixValid()) {
510 // write at least once ALIVE and GPS messages
511 // to log for correct extraction of binary data
513 // Log GPS for time reference
514 uint8_t foo_u8 = 0;
515 int16_t foo_16 = 0;
516 uint16_t foo_u16 = 0;
518 int32_t east = utm.east * 100;
519 int32_t north = utm.north * 100;
522 &gps.week, &gps.tow, &utm.zone, &foo_u8);
523 log_tagged = true;
524 }
526 }
527#endif
528
529 }
530}
531
533{
536
537 // get LWC from ground or external computer and apply filters
538 //cloud_sensor.coef = cloud_sensor_filtering(lwc_from_buffer(buf), &medianFilter0, &lowPassFilter0);
540
541 // test border crossing and send data over ABI
542 check_border();
544 }
545}
546
548{
550}
551
552
Main include for ABI (AirBorneInterface).
#define CLOUD_SENSOR_ID
static int16_t course[3]
uint32_t get_sys_time_usec(void)
Get the time in microseconds since startup.
float cloud_sensor_channel_scale
#define CLOUD_SENSOR_NB
void LWC_callback(uint8_t *buf)
float cloud_sensor_hysteresis
#define CLOUD_SENSOR_ANGSTROM_OFFSET
static struct MedianFilter medianFilter0
#define CLOUD_RAW
float cloud_sensor_threshold
struct Background background
structure for background parameters
static void send_data(uint32_t stamp)
static void check_border(void)
float values[CLOUD_SENSOR_NB]
preprocessed cloud sensor values
float median_filter_update(float new_sample, struct MedianFilter *filter)
Median filter function.
struct LinReg reg
linear regression parameters
uint8_t cloud_sensor_compute_background
float cloud_sensor_tau
#define CLOUD_SENSOR_CHANNEL_SCALE
#define CLOUD_SENSOR_ANGSTROM_COEF
#define CLOUD_SENSOR_BACKGROUND_HYSTERESIS_COEF
void cloud_sensor_init(void)
Init function.
static void send_cloud_sensor_data(struct transport_tx *trans, struct link_device *dev)
float cloud_sensor_filtering(float new_sample, struct MedianFilter *medianFilter, struct FirstOrderLowPass *lowPassFilter)
uint8_t cloud_sensor_compute_coef
Extern variables.
#define CLOUD_SENSOR_OFFSET
float cloud_sensor_background
#define CLOUD_SENSOR_BORDER_HYSTERESIS
#define CLOUD_SENSOR_TAU
void cloud_sensor_callback(uint8_t *buf)
End median filter function.
#define CLOUD_SENSOR_SINGLE_CHANNEL
void cloud_sensor_update_tau(float tau)
uint8_t idx
current index
#define CLOUD_SENSOR_BACKGROUND_NB
float mean[CLOUD_SENSOR_NB]
mean of the lists
#define CLOUD_SENSOR_BORDER_THRESHOLD
#define CLOUD_SENSOR_BACKGROUND_THRESHOLD_COEF
#define CLOUD_SENSOR_CALIB_ALPHA
static float angstrom_coef[]
float raw[CLOUD_SENSOR_RAW_MAX]
raw cloud sensor values
#define CLOUD_SENSOR_RAW_MAX
float var_lambda
variance of lambda
#define CLOUD_SENSOR_LOG_FILE
float raw[CLOUD_SENSOR_NB][CLOUD_SENSOR_BACKGROUND_NB]
lists of raw values
float lambda[CLOUD_SENSOR_NB]
list of sensor LED frequencies
static struct CloudSensor cloud_sensor
Local variables.
static float lambdas[]
float coef
scalar coeff related to cloud parameter (LWC, angstrom, extinction,...)
static float angstrom_offset[]
static float lwc_from_buffer(uint8_t *buf)
float cloud_sensor_calib_beta
#define CLOUD_SENSOR_LAMBDA
float values[3]
float std[CLOUD_SENSOR_NB]
std of the lists
uint8_t nb_raw
number of raw data in array
static struct FirstOrderLowPass lowPassFilter0
void cloud_sensor_report(void)
Report function.
bool inside_cloud
in/out status flag
#define CLOUD_BORDER
static bool log_tagged
float cloud_sensor_calib_alpha
#define CLOUD_SENSOR_CALIB_BETA
Structure used to compute the background and the threshold which is a list of raw data,...
Cloud sensor structure.
Structure used to compute the linear regression that provides the angstrom coefficient.
Median Filter structure.
Get data from Cloud Sensor.
#define CLOUD_SENSOR_COEF_ANGSTROM
#define CLOUD_SENSOR_COEF_SINGLE
#define Min(x, y)
Definition esc_dshot.c:109
struct GpsState gps
global GPS state
Definition gps.c:74
Device independent GPS code (interface)
uint32_t tow
GPS time of week in ms.
Definition gps.h:109
int32_t hmsl
height above mean sea level (MSL) in mm
Definition gps.h:94
#define GpsFixValid()
Definition gps.h:168
uint16_t week
GPS week.
Definition gps.h:108
uint8_t fix
status of fix
Definition gps.h:107
static struct FloatEulers * stateGetNedToBodyEulers_f(void)
Get vehicle body attitude euler angles (float).
Definition state.h:1306
static struct LlaCoor_i * stateGetPositionLla_i(void)
Get position in LLA coordinates (int).
Definition state.h:812
static struct UtmCoor_f * stateGetPositionUtm_f(void)
Get position in UTM coordinates (float).
Definition state.h:821
static float stateGetHorizontalSpeedNorm_f(void)
Get norm of horizontal ground speed (float).
Definition state.h:1076
static float stateGetHorizontalSpeedDir_f(void)
Get dir of horizontal ground speed (float).
Definition state.h:1085
Simple first order low pass filter with bilinear transform.
static void update_first_order_low_pass_tau(struct FirstOrderLowPass *filter, float tau, float sample_time)
Update time constant (tau parameter) for first order low pass filter.
static float update_first_order_low_pass(struct FirstOrderLowPass *filter, float value)
Update first order low pass filter state with a new value.
static void init_first_order_low_pass(struct FirstOrderLowPass *filter, float tau, float sample_time, float value)
Init first order low pass filter.
First order low pass filter structure.
uint8_t dl_buffer[MSG_SIZE]
Definition main_demo5.c:63
uint16_t foo
Definition main_demo5.c:58
#define PowerVoltage()
Definition nav.h:56
static uint32_t idx
Paparazzi floating point math for geodetic calculations.
float east
in meters
float north
in meters
position in UTM coordinates Units: meters
float covariance_f(float *arr1, float *arr2, uint32_t n_elements)
Compute the covariance of two arrays V(X) = E[(X-E[X])(Y-E[Y])] = E[XY] - E[X]E[Y] where E[X] is the ...
Definition pprz_stat.c:152
float mean_f(float *array, uint32_t n_elements)
Compute the mean value of an array (float)
Definition pprz_stat.c:122
float variance_f(float *array, uint32_t n_elements)
Compute the variance of an array of values (float).
Definition pprz_stat.c:139
Statistics functions.
struct pprzlog_transport pprzlog_tp
PPRZLOG transport structure.
Definition pprzlog_tp.c:29
Initialize pprzlog transport.
API to get/set the generic vehicle states.
static const struct usb_device_descriptor dev
Definition usb_ser_hw.c:74
uint16_t val[TCOUPLE_NB]
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.