Paparazzi UAS  v5.18.0_stable
Paparazzi is a free software Unmanned Aircraft System.
formation.c
Go to the documentation of this file.
1 
5 #define FORMATION_C
6 
7 #include "multi/formation.h"
8 
9 #include "std.h"
10 #include "state.h"
11 
13 
16 
17 #include "generated/flight_plan.h" // SECURITY_HEIGHT
18 
21 
23 float form_prox;
31 
33 
34 #ifndef FORM_CARROT
35 #define FORM_CARROT 2.
36 #endif
37 
38 #ifndef FORM_POS_PGAIN
39 #define FORM_POS_PGAIN 0.
40 #endif
41 
42 #ifndef FORM_SPEED_PGAIN
43 #define FORM_SPEED_PGAIN 0.
44 #endif
45 
46 #ifndef FORM_COURSE_PGAIN
47 #define FORM_COURSE_PGAIN 0.
48 #endif
49 
50 #ifndef FORM_ALTITUDE_PGAIN
51 #define FORM_ALTITUDE_PGAIN 0.
52 #endif
53 
54 #ifndef FORM_PROX
55 #define FORM_PROX 20.
56 #endif
57 
58 #ifndef FORM_MODE
59 #define FORM_MODE 0
60 #endif
61 
62 int formation_init(void)
63 {
64  int i;
65  for (i = 0; i < NB_ACS; ++i) { formation[i].status = UNSET; }
66 
67  leader_id = 0;
75  old_cruise = V_CTL_AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE;
76  old_alt = ground_alt + SECURITY_HEIGHT;
77  return false;
78 }
79 
80 int add_slot(uint8_t _id, float slot_e, float slot_n, float slot_a)
81 {
82  if (_id != AC_ID && ti_acs_id[_id] == 0) { return false; } // no info for this AC
83  DOWNLINK_SEND_FORMATION_SLOT_TM(DefaultChannel, DefaultDevice, &_id, &form_mode, &slot_e, &slot_n, &slot_a);
85  formation[ti_acs_id[_id]].east = slot_e;
86  formation[ti_acs_id[_id]].north = slot_n;
87  formation[ti_acs_id[_id]].alt = slot_a;
88  return false;
89 }
90 
91 int start_formation(void)
92 {
93  uint8_t i;
94  uint8_t ac_id = AC_ID;
95  for (i = 0; i < NB_ACS; ++i) {
96  if (formation[i].status == IDLE) { formation[i].status = ACTIVE; }
97  }
98  uint8_t active = ACTIVE;
99  DOWNLINK_SEND_FORMATION_STATUS_TM(DefaultChannel, DefaultDevice, &ac_id, &leader_id, &active);
100  // store current cruise and alt
103  return false;
104 }
105 
106 int stop_formation(void)
107 {
108  uint8_t i;
109  uint8_t ac_id = AC_ID;
110  for (i = 0; i < NB_ACS; ++i) {
111  if (formation[i].status == ACTIVE) { formation[i].status = IDLE; }
112  }
113  uint8_t idle = IDLE;
114  DOWNLINK_SEND_FORMATION_STATUS_TM(DefaultChannel, DefaultDevice, &ac_id, &leader_id, &idle);
115  // restore cruise and alt
117  old_cruise = V_CTL_AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE;
119  old_alt = ground_alt + SECURITY_HEIGHT;
120  return false;
121 }
122 
123 
125 {
126  static uint8_t _1Hz = 0;
127  uint8_t nb = 0, i;
128  float hspeed_dir = stateGetHorizontalSpeedDir_f();
129  float ch = cosf(hspeed_dir);
130  float sh = sinf(hspeed_dir);
131  form_n = 0.;
132  form_e = 0.;
133  form_a = 0.;
135  form_speed_n = form_speed * ch;
136  form_speed_e = form_speed * sh;
137 
138  if (AC_ID == leader_id) {
141  }
142 
143  // broadcast info
144  uint8_t ac_id = AC_ID;
146  DOWNLINK_SEND_FORMATION_STATUS_TM(DefaultChannel, DefaultDevice, &ac_id, &leader_id, &status);
147  if (++_1Hz >= 4) {
148  _1Hz = 0;
149  DOWNLINK_SEND_FORMATION_SLOT_TM(DefaultChannel, DefaultDevice, &ac_id, &form_mode,
150  &formation[ti_acs_id[AC_ID]].east,
151  &formation[ti_acs_id[AC_ID]].north,
152  &formation[ti_acs_id[AC_ID]].alt);
153  }
154  if (formation[ti_acs_id[AC_ID]].status != ACTIVE) { return false; } // AC not ready
155 
156  // get leader info
157  struct EnuCoor_f *leader_pos = acInfoGetPositionEnu_f(leader_id);
160  // leader not ready or not in formation
161  return false;
162  }
163 
164  // compute slots in the right reference frame
165  struct slot_ form[NB_ACS];
166  float cr = 0., sr = 1.;
167  if (form_mode == FORM_MODE_COURSE) {
168  cr = cosf(acInfoGetCourse(leader_id));
169  sr = sinf(acInfoGetCourse(leader_id));
170  }
171  for (i = 0; i < NB_ACS; ++i) {
172  if (formation[i].status == UNSET) { continue; }
173  form[i].east = formation[i].east * sr - formation[i].north * cr;
174  form[i].north = formation[i].east * cr + formation[i].north * sr;
175  form[i].alt = formation[i].alt;
176  }
177 
178  struct EnuCoor_f *my_pos = stateGetPositionEnu_f();
179  // compute control forces
180  for (i = 0; i < NB_ACS; ++i) {
181  if (ti_acs[i].ac_id == AC_ID) { continue; }
182  struct EnuCoor_f *ac = acInfoGetPositionEnu_f(ti_acs[i].ac_id);
183  struct EnuCoor_f *ac_speed = acInfoGetVelocityEnu_f(ti_acs[i].ac_id);
184 
185  float delta_t = Max((int)(gps.tow - acInfoGetItow(ti_acs[i].ac_id)) / 1000., 0.);
186  if (delta_t > FORM_CARROT) {
187  // if AC not responding for too long
188  formation[i].status = LOST;
189  continue;
190  } else {
191  // compute control if AC is ACTIVE and around the same altitude (maybe not so useful)
192  formation[i].status = ACTIVE;
193  if (ac->z > 0 && fabs(my_pos->z - ac->z) < form_prox) {
194  form_e += (ac->x + ac_speed->x * delta_t - my_pos->x) - (form[i].east - form[ti_acs_id[AC_ID]].east);
195  form_n += (ac->y + ac_speed->y * delta_t - my_pos->y) - (form[i].north - form[ti_acs_id[AC_ID]].north);
196  form_a += (ac->z + ac_speed->z * delta_t - my_pos->z) - (form[i].alt - form[ti_acs_id[AC_ID]].alt);
198  //form_speed_e += ac->gspeed * sinf(ac->course);
199  //form_speed_n += ac->gspeed * cosf(ac->course);
200  ++nb;
201  }
202  }
203  }
204  uint8_t _nb = Max(1, nb);
205  form_n /= _nb;
206  form_e /= _nb;
207  form_a /= _nb;
209  //form_speed_e = form_speed_e / (nb+1) - stateGetHorizontalSpeedNorm_f() * sh;
210  //form_speed_n = form_speed_n / (nb+1) - stateGetHorizontalSpeedNorm_f() * ch;
211 
212  // set commands
214 
215  // altitude loop
216  float alt = 0.;
217  if (AC_ID == leader_id) {
218  alt = nav_altitude;
219  } else {
220  alt = leader_pos->z - form[ti_acs_id[leader_id]].alt;
221  }
222  alt += formation[ti_acs_id[AC_ID]].alt + coef_form_alt * form_a;
223  flight_altitude = Max(alt, ground_alt + SECURITY_HEIGHT);
224 
225  // carrot
226  if (AC_ID != leader_id) {
227  float dx = form[ti_acs_id[AC_ID]].east - form[ti_acs_id[leader_id]].east;
228  float dy = form[ti_acs_id[AC_ID]].north - form[ti_acs_id[leader_id]].north;
229  desired_x = leader_pos->x + NOMINAL_AIRSPEED * form_carrot * sinf(acInfoGetCourse(leader_id)) + dx;
230  desired_y = leader_pos->y + NOMINAL_AIRSPEED * form_carrot * cosf(acInfoGetCourse(leader_id)) + dy;
231  // fly to desired
233  desired_x = leader_pos->x + dx;
234  desired_y = leader_pos->y + dy;
235  // lateral correction
236  //float diff_heading = asin((dx*ch - dy*sh) / sqrt(dx*dx + dy*dy));
237  //float diff_course = leader->course - hspeed_dir;
238  //NormRadAngle(diff_course);
239  //h_ctl_roll_setpoint += coef_form_course * diff_course;
240  //h_ctl_roll_setpoint += coef_form_course * diff_heading;
241  }
242  //BoundAbs(h_ctl_roll_setpoint, h_ctl_roll_max_setpoint);
243 
244  // speed loop
245  if (nb > 0) {
246  float cruise = V_CTL_AUTO_THROTTLE_NOMINAL_CRUISE_THROTTLE;
247  cruise += coef_form_pos * (form_n * ch + form_e * sh) + coef_form_speed * form_speed;
248  Bound(cruise, V_CTL_AUTO_THROTTLE_MIN_CRUISE_THROTTLE, V_CTL_AUTO_THROTTLE_MAX_CRUISE_THROTTLE);
250  }
251  return true;
252 }
253 
255 {
256  if (leader_id == AC_ID) {
259  }
260 }
261 
acInfoGetGspeed
static float acInfoGetGspeed(uint8_t ac_id)
Get vehicle ground speed (float).
Definition: traffic_info.h:424
formation_init
int formation_init(void)
Definition: formation.c:62
old_cruise
float old_cruise
Definition: formation.c:30
stateGetHorizontalSpeedDir_f
static float stateGetHorizontalSpeedDir_f(void)
Get dir of horizontal ground speed (float).
Definition: state.h:944
FORM_COURSE_PGAIN
#define FORM_COURSE_PGAIN
Definition: formation.c:47
formation_flight
int formation_flight(void)
Definition: formation.c:124
coef_form_speed
float coef_form_speed
Definition: formation.c:25
slot_::status
enum slot_status status
Definition: formation.h:25
leader_id
uint8_t leader_id
Definition: formation.c:29
status
uint8_t status
Definition: nps_radio_control_spektrum.c:101
GpsState::tow
uint32_t tow
GPS time of week in ms.
Definition: gps.h:109
FORM_SPEED_PGAIN
#define FORM_SPEED_PGAIN
Definition: formation.c:43
form_n
float form_n
Definition: formation.c:19
add_slot
int add_slot(uint8_t _id, float slot_e, float slot_n, float slot_a)
Definition: formation.c:80
stateGetPositionEnu_f
static struct EnuCoor_f * stateGetPositionEnu_f(void)
Get position in local ENU coordinates (float).
Definition: state.h:719
form_prox
float form_prox
Definition: formation.c:23
FORM_POS_PGAIN
#define FORM_POS_PGAIN
Definition: formation.c:39
FORM_MODE
#define FORM_MODE
Definition: formation.c:59
acInfoGetCourse
static float acInfoGetCourse(uint8_t ac_id)
Get vehicle course (float).
Definition: traffic_info.h:416
form_speed_e
float form_speed_e
Definition: formation.c:20
form_mode
uint8_t form_mode
Definition: formation.c:28
slot_::east
float east
Definition: formation.h:26
ACTIVE
@ ACTIVE
Definition: formation.h:22
slot_
Definition: formation.h:24
slot_::alt
float alt
Definition: formation.h:28
EnuCoor_f::y
float y
in meters
Definition: pprz_geodetic_float.h:74
v_ctl_auto_throttle_cruise_throttle
float v_ctl_auto_throttle_cruise_throttle
Definition: energy_ctrl.c:103
form_carrot
float form_carrot
Definition: formation.c:22
EnuCoor_f::z
float z
in meters
Definition: pprz_geodetic_float.h:75
NavVerticalAutoThrottleMode
#define NavVerticalAutoThrottleMode(_pitch)
Set the climb control to auto-throttle with the specified pitch pre-command.
Definition: nav.h:171
form_a
float form_a
Definition: formation.c:19
acInfoGetPositionEnu_f
static struct EnuCoor_f * acInfoGetPositionEnu_f(uint8_t ac_id)
Get position in local ENU coordinates (float).
Definition: traffic_info.h:383
flight_altitude
float flight_altitude
Dynamically adjustable, reset to nav_altitude when it is changing.
Definition: nav.c:75
std.h
acInfoGetItow
static uint32_t acInfoGetItow(uint8_t ac_id)
Get time of week from latest message (ms).
Definition: traffic_info.h:440
desired_x
float desired_x
Definition: nav.c:306
desired_y
float desired_y
Definition: nav.c:306
form_speed_n
float form_speed_n
Definition: formation.c:20
acInfoGetVelocityEnu_f
static struct EnuCoor_f * acInfoGetVelocityEnu_f(uint8_t ac_id)
Get position from ENU coordinates (float).
Definition: traffic_info.h:405
uint8_t
unsigned char uint8_t
Definition: types.h:14
FORM_ALTITUDE_PGAIN
#define FORM_ALTITUDE_PGAIN
Definition: formation.c:51
coef_form_course
float coef_form_course
Definition: formation.c:26
EnuCoor_f
vector in East North Up coordinates Units: meters
Definition: pprz_geodetic_float.h:72
slot_::north
float north
Definition: formation.h:27
FORM_PROX
#define FORM_PROX
Definition: formation.c:55
formation.h
Formation flight library.
nav.h
FORM_MODE_COURSE
#define FORM_MODE_COURSE
Definition: formation.h:15
ti_acs
struct acInfo ti_acs[NB_ACS]
Definition: traffic_info.c:45
stateGetHorizontalSpeedNorm_f
static float stateGetHorizontalSpeedNorm_f(void)
Get norm of horizontal ground speed (float).
Definition: state.h:935
ground_alt
float ground_alt
size == nb_waypoint, waypoint 0 is a dummy waypoint
Definition: common_nav.c:40
old_alt
float old_alt
Definition: formation.c:30
NB_ACS
#define NB_ACS
Definition: rssi.c:38
formation_pre_call
void formation_pre_call(void)
Definition: formation.c:254
form_e
float form_e
Definition: formation.c:19
start_formation
int start_formation(void)
Definition: formation.c:91
coef_form_pos
float coef_form_pos
Definition: formation.c:24
EnuCoor_f::x
float x
in meters
Definition: pprz_geodetic_float.h:73
nav_altitude
float nav_altitude
Definition: nav.c:305
Max
#define Max(x, y)
Definition: main_fbw.c:53
state.h
stop_formation
int stop_formation(void)
Definition: formation.c:106
ac_id
uint8_t ac_id
Definition: sim_ap.c:48
UNSET
@ UNSET
Definition: formation.h:22
FORM_CARROT
#define FORM_CARROT
Definition: formation.c:35
IDLE
@ IDLE
Definition: formation.h:22
gps
struct GpsState gps
global GPS state
Definition: gps.c:69
formation
struct slot_ formation[NB_ACS]
Definition: formation.c:32
ti_acs_id
uint8_t ti_acs_id[NB_ACS_ID]
Definition: traffic_info.c:43
form_speed
float form_speed
Definition: formation.c:20
LOST
@ LOST
Definition: formation.h:22
fly_to_xy
void fly_to_xy(float x, float y)
Computes desired_x, desired_y and desired_course.
Definition: nav.c:355
coef_form_alt
float coef_form_alt
Definition: formation.c:27
guidance_v.h