dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fixedwingpathfollower.c
Go to the documentation of this file.
1 
19 /*
20  * This program is free software; you can redistribute it and/or modify
21  * it under the terms of the GNU General Public License as published by
22  * the Free Software Foundation; either version 3 of the License, or
23  * (at your option) any later version.
24  *
25  * This program is distributed in the hope that it will be useful, but
26  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
27  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
28  * for more details.
29  *
30  * You should have received a copy of the GNU General Public License along
31  * with this program; if not, see <http://www.gnu.org/licenses/>
32  *
33  * Additional note on redistribution: The copyright and license notices above
34  * must be maintained in each individual source file that is a derivative work
35  * of this source file; otherwise redistribution is prohibited.
36  */
37 
52 #include "openpilot.h"
53 #include "physical_constants.h"
54 #include "paths.h"
55 #include "misc_math.h"
56 
57 #include "modulesettings.h"
58 #include "attitudeactual.h"
59 #include "pathdesired.h" // object that will be updated by the module
60 #include "positionactual.h"
61 #include "flightstatus.h"
62 #include "pathstatus.h"
63 #include "airspeedactual.h"
64 #include "gpsvelocity.h"
65 #include "gpsposition.h"
66 #include "fixedwingairspeeds.h"
67 #include "fixedwingpathfollowersettings.h"
68 #include "fixedwingpathfollowerstatus.h"
69 #include "homelocation.h"
70 #include "nedposition.h"
71 #include "stabilizationdesired.h"
72 #include "stabilizationsettings.h"
73 #include "systemsettings.h"
74 #include "velocitydesired.h"
75 #include "velocityactual.h"
76 #include "coordinate_conversions.h"
77 #include "pios_thread.h"
78 
79 // Private constants
80 #define MAX_QUEUE_SIZE 4
81 #define STACK_SIZE_BYTES 1548
82 #define TASK_PRIORITY PIOS_THREAD_PRIO_NORMAL
83 // Private types
84 
85 // Private variables
86 static bool module_enabled = false;
87 static struct pios_thread *pathfollowerTaskHandle;
88 static PathDesiredData pathDesired;
89 static PathStatusData pathStatus;
90 static FixedWingPathFollowerSettingsData fixedwingpathfollowerSettings;
91 static FixedWingAirspeedsData fixedWingAirspeeds;
92 
93 // Private functions
94 static void pathfollowerTask(void *parameters);
95 static void SettingsUpdatedCb(const UAVObjEvent *ev,
96  void *ctx, void *obj, int len);
97 static void updatePathVelocity();
98 static uint8_t updateFixedDesiredAttitude();
99 static void airspeedActualUpdatedCb(const UAVObjEvent *ev,
100  void *ctx, void *obj, int len);
101 
107 {
108  if (module_enabled) {
109  // Start main task
111  TaskMonitorAdd(TASKINFO_RUNNING_PATHFOLLOWER, pathfollowerTaskHandle);
112  }
113 
114  return 0;
115 }
116 
122 {
123 #ifdef MODULE_FixedWingPathFollower_BUILTIN
124  module_enabled = true;
125 #else
126  uint8_t module_state[MODULESETTINGS_ADMINSTATE_NUMELEM];
127  ModuleSettingsAdminStateGet(module_state);
128  if (module_state[MODULESETTINGS_ADMINSTATE_FIXEDWINGPATHFOLLOWER] == MODULESETTINGS_ADMINSTATE_ENABLED) {
129  module_enabled = true;
130  } else {
131  return 0;
132  }
133 #endif
134 
136  module_enabled = false;
137  return -1;
138  }
139 
140 
142  module_enabled = false;
143  return -1;
144  }
145 
146  if (FixedWingPathFollowerSettingsInitialize() == -1 \
147  || FixedWingAirspeedsInitialize() == -1 \
148  || FixedWingPathFollowerStatusInitialize() == -1 \
149  || PathDesiredInitialize() == -1 \
150  || PathStatusInitialize() == -1 \
151  || VelocityDesiredInitialize() == -1 \
152  || AirspeedActualInitialize() == -1 ){
153 
154  module_enabled = false;
155  return -1;
156  }
157 
158  return 0;
159 }
161 
162 static float northVelIntegral = 0;
163 static float eastVelIntegral = 0;
164 static float downVelIntegral = 0;
165 
166 static float bearingIntegral = 0;
167 static float speedIntegral = 0;
168 static float accelIntegral = 0;
169 static float powerIntegral = 0;
170 static float airspeedErrorInt=0;
171 
172 // correct speed by measured airspeed
175 
179 static void pathfollowerTask(void *parameters)
180 {
181  SystemSettingsData systemSettings;
182  FlightStatusData flightStatus;
183 
184  uint32_t lastUpdateTime;
185 
186  AirspeedActualConnectCallback(airspeedActualUpdatedCb);
187  FixedWingPathFollowerSettingsConnectCallback(SettingsUpdatedCb);
188  FixedWingAirspeedsConnectCallback(SettingsUpdatedCb);
189  PathDesiredConnectCallback(SettingsUpdatedCb);
190 
191  // Force update of all the settings
192  SettingsUpdatedCb(NULL, NULL, NULL, 0);
193 
194  FixedWingPathFollowerSettingsGet(&fixedwingpathfollowerSettings);
195  path_desired_updated = false;
196  PathDesiredGet(&pathDesired);
197  PathDesiredConnectCallbackCtx(UAVObjCbSetFlag, &path_desired_updated);
198 
199  // Main task loop
200  lastUpdateTime = PIOS_Thread_Systime();
201  while (1) {
202 
203  // Conditions when this runs:
204  // 1. Must have FixedWing type airframe
205  // 2. Flight mode is PositionHold and PathDesired.Mode is Endpoint OR
206  // FlightMode is PathPlanner and PathDesired.Mode is Endpoint or Path
207 
208  SystemSettingsGet(&systemSettings);
209  if ( (systemSettings.AirframeType != SYSTEMSETTINGS_AIRFRAMETYPE_FIXEDWING) &&
210  (systemSettings.AirframeType != SYSTEMSETTINGS_AIRFRAMETYPE_FIXEDWINGELEVON) &&
211  (systemSettings.AirframeType != SYSTEMSETTINGS_AIRFRAMETYPE_FIXEDWINGVTAIL) )
212  {
213  AlarmsSet(SYSTEMALARMS_ALARM_PATHFOLLOWER,SYSTEMALARMS_ALARM_CRITICAL);
214  PIOS_Thread_Sleep(1000);
215  continue;
216  }
217 
218  // Continue collecting data if not enough time
219  PIOS_Thread_Sleep_Until(&lastUpdateTime, fixedwingpathfollowerSettings.UpdatePeriod);
220 
221  static uint8_t last_flight_mode;
222  FlightStatusGet(&flightStatus);
223  PathStatusGet(&pathStatus);
224 
225  PositionActualData positionActual;
226 
227  static enum {FW_FOLLOWER_IDLE, FW_FOLLOWER_RUNNING, FW_FOLLOWER_ERR} state = FW_FOLLOWER_IDLE;
228 
229  // Check whether an update to the path desired occured and we should
230  // process it. This makes sure that the follower alarm state is
231  // updated.
232  bool process_path_desired_update =
233  (last_flight_mode == FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER) &&
234  path_desired_updated;
235  path_desired_updated = false;
236 
237  // Process most of these when the flight mode changes
238  // except when in path following mode in which case
239  // each iteration must make sure this has the latest
240  // PathDesired
241  if (flightStatus.FlightMode != last_flight_mode ||
242  process_path_desired_update) {
243 
244  last_flight_mode = flightStatus.FlightMode;
245 
246  switch(flightStatus.FlightMode) {
247  case FLIGHTSTATUS_FLIGHTMODE_RETURNTOHOME:
248  state = FW_FOLLOWER_RUNNING;
249 
250  PositionActualGet(&positionActual);
251 
252  pathDesired.Mode = PATHDESIRED_MODE_CIRCLEPOSITIONRIGHT;
253  pathDesired.Start[0] = positionActual.North;
254  pathDesired.Start[1] = positionActual.East;
255  pathDesired.Start[2] = positionActual.Down;
256  pathDesired.End[0] = 0;
257  pathDesired.End[1] = 0;
258  pathDesired.End[2] = -30.0f;
259  pathDesired.ModeParameters = fixedwingpathfollowerSettings.OrbitRadius;
260  pathDesired.StartingVelocity = fixedWingAirspeeds.CruiseSpeed;
261  pathDesired.EndingVelocity = fixedWingAirspeeds.CruiseSpeed;
262  PathDesiredSet(&pathDesired);
263 
264  break;
265  case FLIGHTSTATUS_FLIGHTMODE_POSITIONHOLD:
266  state = FW_FOLLOWER_RUNNING;
267 
268  PositionActualGet(&positionActual);
269 
270  pathDesired.Mode = PATHDESIRED_MODE_CIRCLEPOSITIONRIGHT;
271  pathDesired.Start[0] = positionActual.North;
272  pathDesired.Start[1] = positionActual.East;
273  pathDesired.Start[2] = positionActual.Down;
274  pathDesired.End[0] = positionActual.North;
275  pathDesired.End[1] = positionActual.East;
276  pathDesired.End[2] = positionActual.Down;
277  pathDesired.ModeParameters = fixedwingpathfollowerSettings.OrbitRadius;
278  pathDesired.StartingVelocity = fixedWingAirspeeds.CruiseSpeed;
279  pathDesired.EndingVelocity = fixedWingAirspeeds.CruiseSpeed;
280  PathDesiredSet(&pathDesired);
281 
282  break;
283  case FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER:
284  case FLIGHTSTATUS_FLIGHTMODE_TABLETCONTROL:
285  state = FW_FOLLOWER_RUNNING;
286 
287  PathDesiredGet(&pathDesired);
288  switch(pathDesired.Mode) {
289  case PATHDESIRED_MODE_ENDPOINT:
290  case PATHDESIRED_MODE_VECTOR:
291  case PATHDESIRED_MODE_CIRCLERIGHT:
292  case PATHDESIRED_MODE_CIRCLELEFT:
293  break;
294  default:
295  state = FW_FOLLOWER_ERR;
296  pathStatus.Status = PATHSTATUS_STATUS_CRITICAL;
297  PathStatusSet(&pathStatus);
298  AlarmsSet(SYSTEMALARMS_ALARM_PATHFOLLOWER,SYSTEMALARMS_ALARM_CRITICAL);
299  break;
300  }
301  break;
302  default:
303  state = FW_FOLLOWER_IDLE;
304  break;
305  }
306  }
307 
308  switch(state) {
309  case FW_FOLLOWER_RUNNING:
310  {
312  uint8_t result = updateFixedDesiredAttitude();
313  if (result) {
314  AlarmsClear(SYSTEMALARMS_ALARM_PATHFOLLOWER);
315  } else {
316  AlarmsSet(SYSTEMALARMS_ALARM_PATHFOLLOWER,SYSTEMALARMS_ALARM_WARNING);
317  }
318  PathStatusSet(&pathStatus);
319  break;
320  }
321  case FW_FOLLOWER_IDLE:
322  // Be cleaner and get rid of global variables
323  northVelIntegral = 0;
324  eastVelIntegral = 0;
325  downVelIntegral = 0;
326  bearingIntegral = 0;
327  speedIntegral = 0;
328  accelIntegral = 0;
329  powerIntegral = 0;
330  airspeedErrorInt = 0;
331  AlarmsClear(SYSTEMALARMS_ALARM_PATHFOLLOWER);
332  break;
333  case FW_FOLLOWER_ERR:
334  default:
335  // Leave alarms set above
336  break;
337  }
338  }
339 }
340 
347 static void updatePathVelocity()
348 {
349  PositionActualData positionActual;
350  PositionActualGet(&positionActual);
351  VelocityActualData velocityActual;
352  VelocityActualGet(&velocityActual);
353 
354  float cur[3] = {
355  positionActual.North +
356  velocityActual.North * fixedwingpathfollowerSettings.PositionFeedforward,
357  positionActual.East +
358  velocityActual.East * fixedwingpathfollowerSettings.PositionFeedforward,
359  positionActual.Down
360  };
361  struct path_status progress;
362 
363  path_progress(&pathDesired, cur, &progress);
364 
365  float groundspeed = 0;
366  float altitudeSetpoint = 0;
367  switch (pathDesired.Mode) {
368  case PATHDESIRED_MODE_CIRCLERIGHT:
369  case PATHDESIRED_MODE_CIRCLELEFT:
370  groundspeed = pathDesired.EndingVelocity;
371  altitudeSetpoint = pathDesired.End[2];
372  break;
373  case PATHDESIRED_MODE_ENDPOINT:
374  case PATHDESIRED_MODE_VECTOR:
375  default:
376  groundspeed = pathDesired.StartingVelocity + (pathDesired.EndingVelocity - pathDesired.StartingVelocity) *
377  bound_min_max(progress.fractional_progress,0,1);
378  altitudeSetpoint = pathDesired.Start[2] + (pathDesired.End[2] - pathDesired.Start[2]) *
379  bound_min_max(progress.fractional_progress,0,1);
380  break;
381  }
382  // this ensures a significant forward component at least close to the real trajectory
383  if (groundspeed<fixedWingAirspeeds.BestClimbRateSpeed/10.0f)
384  groundspeed=fixedWingAirspeeds.BestClimbRateSpeed/10.0f;
385 
386  // calculate velocity - can be zero if waypoints are too close
387  VelocityDesiredData velocityDesired;
388  velocityDesired.North = progress.path_direction[0] * groundspeed;
389  velocityDesired.East = progress.path_direction[1] * groundspeed;
390 
391  float error_speed = progress.error * fixedwingpathfollowerSettings.HorizontalPosP;
392 
393  // calculate correction - can also be zero if correction vector is 0 or no error present
394  velocityDesired.North += progress.correction_direction[0] * error_speed;
395  velocityDesired.East += progress.correction_direction[1] * error_speed;
396 
397  float downError = altitudeSetpoint - positionActual.Down;
398  velocityDesired.Down = downError * fixedwingpathfollowerSettings.VerticalPosP;
399 
400  // update pathstatus
401  pathStatus.error = progress.error;
402  pathStatus.fractional_progress = progress.fractional_progress;
403 
404  pathStatus.fractional_progress = progress.fractional_progress;
405  if (pathStatus.fractional_progress < 1)
406  pathStatus.Status = PATHSTATUS_STATUS_INPROGRESS;
407  else
408  pathStatus.Status = PATHSTATUS_STATUS_COMPLETED;
409 
410  pathStatus.Waypoint = pathDesired.Waypoint;
411 
412  VelocityDesiredSet(&velocityDesired);
413 }
414 
423 {
424 
425  uint8_t result = 1;
426 
427  float dT = fixedwingpathfollowerSettings.UpdatePeriod / 1000.0f; //Convert from [ms] to [s]
428 
429  VelocityDesiredData velocityDesired;
430  VelocityActualData velocityActual;
431  StabilizationDesiredData stabDesired;
432  AttitudeActualData attitudeActual;
433  FixedWingPathFollowerStatusData fixedwingpathfollowerStatus;
434  AirspeedActualData airspeedActual;
435 
436  float groundspeedActual;
437  float groundspeedDesired;
438  float indicatedAirspeedActual;
439  float indicatedAirspeedDesired;
440  float airspeedError;
441 
442  float pitchCommand;
443 
444  float descentspeedDesired;
445  float descentspeedError;
446  float powerError;
447  float powerCommand;
448 
449  float bearingError;
450  float bearingCommand;
451 
452  FixedWingPathFollowerStatusGet(&fixedwingpathfollowerStatus);
453 
454  VelocityActualGet(&velocityActual);
455  StabilizationDesiredGet(&stabDesired);
456  VelocityDesiredGet(&velocityDesired);
457  AttitudeActualGet(&attitudeActual);
458  AirspeedActualGet(&airspeedActual);
459 
460 
465  // Current ground speed
466  groundspeedActual = sqrtf( velocityActual.East*velocityActual.East + velocityActual.North*velocityActual.North );
467  // note that airspeedActualBias is ( calibratedAirspeed - groundSpeed ) at the time of measurement,
468  // but thanks to accelerometers, groundspeed reacts faster to changes in direction
469  // than airspeed and gps sensors alone
470  indicatedAirspeedActual = groundspeedActual + indicatedAirspeedActualBias;
471 
472  // Desired ground speed
473  groundspeedDesired = sqrtf(velocityDesired.North*velocityDesired.North + velocityDesired.East*velocityDesired.East);
474  indicatedAirspeedDesired = bound_min_max( groundspeedDesired + indicatedAirspeedActualBias,
475  fixedWingAirspeeds.BestClimbRateSpeed,
476  fixedWingAirspeeds.CruiseSpeed);
477 
478  // Airspeed error (positive means not enough airspeed)
479  airspeedError = indicatedAirspeedDesired - indicatedAirspeedActual;
480 
481  // Vertical speed error
482  descentspeedDesired = bound_min_max (
483  velocityDesired.Down,
484  -fixedWingAirspeeds.VerticalVelMax,
485  fixedWingAirspeeds.VerticalVelMax);
486  descentspeedError = descentspeedDesired - velocityActual.Down;
487 
488  // Error condition: wind speed is higher than maximum allowed speed. We are forced backwards!
489  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_WIND] = 0;
490  if (groundspeedDesired - indicatedAirspeedActualBias <= 0 ) {
491  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_WIND] = 1;
492  result = 0;
493  }
494  // Error condition: plane too slow or too fast
495  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_HIGHSPEED] = 0;
496  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_LOWSPEED] = 0;
497  if ( indicatedAirspeedActual > fixedWingAirspeeds.AirSpeedMax) {
498  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_OVERSPEED] = 1;
499  result = 0;
500  }
501  if ( indicatedAirspeedActual > fixedWingAirspeeds.CruiseSpeed * 1.2f) {
502  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_HIGHSPEED] = 1;
503  result = 0;
504  }
505  if (indicatedAirspeedActual < fixedWingAirspeeds.BestClimbRateSpeed * 0.8f && 1) { //The next three && 1 are placeholders for UAVOs representing LANDING and TAKEOFF
506  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_LOWSPEED] = 1;
507  result = 0;
508  }
509  if (indicatedAirspeedActual < fixedWingAirspeeds.StallSpeedClean && 1 && 1) { //Where the && 1 represents the UAVO that will control whether the airplane is prepped for landing or not
510  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_STALLSPEED] = 1;
511  result = 0;
512  }
513  if (indicatedAirspeedActual < fixedWingAirspeeds.StallSpeedDirty && 1) {
514  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_STALLSPEED] = 1;
515  result = 0;
516  }
517 
518  if (indicatedAirspeedActual<1e-6f) {
519  // prevent division by zero, abort without controlling anything. This guidance mode is not suited for takeoff or touchdown, or handling stationary planes
520  // also we cannot handle planes flying backwards, lets just wait until the nose drops
521  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_LOWSPEED] = 1;
522  return 0;
523  }
524 
530  // compute proportional throttle response
531  powerError = -descentspeedError +
533  (airspeedError / fixedWingAirspeeds.BestClimbRateSpeed)* fixedwingpathfollowerSettings.AirspeedToVerticalCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_AIRSPEEDTOVERTICALCROSSFEED_KP] ,
534  -fixedwingpathfollowerSettings.AirspeedToVerticalCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_AIRSPEEDTOVERTICALCROSSFEED_MAX],
535  fixedwingpathfollowerSettings.AirspeedToVerticalCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_AIRSPEEDTOVERTICALCROSSFEED_MAX]
536  );
537 
538  // compute saturated integral error throttle response. Make integral leaky for better performance. Approximately 30s time constant.
539  if (fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_KI] >0) {
540  powerIntegral = bound_min_max(powerIntegral + -descentspeedError * dT,
541  -fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_ILIMIT]/fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_KI],
542  fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_ILIMIT]/fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_KI]
543  )*(1.0f-1.0f/(1.0f+30.0f/dT));
544  } else
545  powerIntegral = 0;
546 
547  // Compute final throttle response
548  powerCommand = bound_min_max(
549  (powerError * fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_KP] +
550  powerIntegral* fixedwingpathfollowerSettings.PowerPI[FIXEDWINGPATHFOLLOWERSETTINGS_POWERPI_KI]) + fixedwingpathfollowerSettings.ThrottleLimit[FIXEDWINGPATHFOLLOWERSETTINGS_THROTTLELIMIT_NEUTRAL],
551  fixedwingpathfollowerSettings.ThrottleLimit[FIXEDWINGPATHFOLLOWERSETTINGS_THROTTLELIMIT_MIN],
552  fixedwingpathfollowerSettings.ThrottleLimit[FIXEDWINGPATHFOLLOWERSETTINGS_THROTTLELIMIT_MAX]);
553 
554  //Output internal state to telemetry
555  fixedwingpathfollowerStatus.Error[FIXEDWINGPATHFOLLOWERSTATUS_ERROR_POWER] = powerError;
556  fixedwingpathfollowerStatus.ErrorInt[FIXEDWINGPATHFOLLOWERSTATUS_ERRORINT_POWER] = powerIntegral;
557  fixedwingpathfollowerStatus.Command[FIXEDWINGPATHFOLLOWERSTATUS_COMMAND_POWER] = powerCommand;
558 
559  // set throttle
560  stabDesired.Thrust = powerCommand;
561 
562  // Error condition: plane cannot hold altitude at current speed.
563  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_LOWPOWER] = 0;
564  if (
565  powerCommand == fixedwingpathfollowerSettings.ThrottleLimit[FIXEDWINGPATHFOLLOWERSETTINGS_THROTTLELIMIT_MAX] // throttle at maximum
566  && velocityActual.Down > 0 // we ARE going down
567  && descentspeedDesired < 0 // we WANT to go up
568  && airspeedError > 0 // we are too slow already
569  )
570  {
571  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_LOWPOWER] = 1;
572  result = 0;
573  }
574  // Error condition: plane keeps climbing despite minimum throttle (opposite of above)
575  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_HIGHPOWER] = 0;
576  if (
577  powerCommand == fixedwingpathfollowerSettings.ThrottleLimit[FIXEDWINGPATHFOLLOWERSETTINGS_THROTTLELIMIT_MIN] // throttle at minimum
578  && velocityActual.Down < 0 // we ARE going up
579  && descentspeedDesired > 0 // we WANT to go down
580  && airspeedError < 0 // we are too fast already
581  )
582  {
583  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_HIGHPOWER] = 1;
584  result = 0;
585  }
586 
587 
592  if (fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_KI] > 0){
593  //Integrate with saturation
594  airspeedErrorInt=bound_min_max(airspeedErrorInt + airspeedError * dT,
595  -fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_ILIMIT]/fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_KI],
596  fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_ILIMIT]/fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_KI]);
597  } else
598  airspeedErrorInt = 0;
599 
600  //Compute the cross feed from vertical speed to pitch, with saturation
601  float verticalSpeedToPitchCommandComponent=bound_min_max (-descentspeedError * fixedwingpathfollowerSettings.VerticalToPitchCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_VERTICALTOPITCHCROSSFEED_KP],
602  -fixedwingpathfollowerSettings.VerticalToPitchCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_VERTICALTOPITCHCROSSFEED_MAX],
603  fixedwingpathfollowerSettings.VerticalToPitchCrossFeed[FIXEDWINGPATHFOLLOWERSETTINGS_VERTICALTOPITCHCROSSFEED_MAX]
604  );
605 
606  //Compute the pitch command as err*Kp + errInt*Ki + X_feed.
607  pitchCommand= -(airspeedError*fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_KP]
608  + airspeedErrorInt*fixedwingpathfollowerSettings.SpeedPI[FIXEDWINGPATHFOLLOWERSETTINGS_SPEEDPI_KI]
609  ) + verticalSpeedToPitchCommandComponent;
610 
611  fixedwingpathfollowerStatus.Error[FIXEDWINGPATHFOLLOWERSTATUS_ERROR_SPEED] = airspeedError;
612  fixedwingpathfollowerStatus.ErrorInt[FIXEDWINGPATHFOLLOWERSTATUS_ERRORINT_SPEED] = airspeedErrorInt;
613  fixedwingpathfollowerStatus.Command[FIXEDWINGPATHFOLLOWERSTATUS_COMMAND_SPEED] = pitchCommand;
614 
615  stabDesired.Pitch = bound_min_max(fixedwingpathfollowerSettings.PitchLimit[FIXEDWINGPATHFOLLOWERSETTINGS_PITCHLIMIT_NEUTRAL] +
616  pitchCommand,
617  fixedwingpathfollowerSettings.PitchLimit[FIXEDWINGPATHFOLLOWERSETTINGS_PITCHLIMIT_MIN],
618  fixedwingpathfollowerSettings.PitchLimit[FIXEDWINGPATHFOLLOWERSETTINGS_PITCHLIMIT_MAX]);
619 
620  // Error condition: high speed dive
621  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_PITCHCONTROL] = 0;
622  if (
623  pitchCommand == fixedwingpathfollowerSettings.PitchLimit[FIXEDWINGPATHFOLLOWERSETTINGS_PITCHLIMIT_MAX] // pitch demand is full up
624  && velocityActual.Down > 0 // we ARE going down
625  && descentspeedDesired < 0 // we WANT to go up
626  && airspeedError < 0 // we are too fast already
627  ) {
628  fixedwingpathfollowerStatus.Errors[FIXEDWINGPATHFOLLOWERSTATUS_ERRORS_PITCHCONTROL] = 1;
629  result = 0;
630  }
631 
635  if (groundspeedDesired> 1e-6f) {
636  bearingError = RAD2DEG * (atan2f(velocityDesired.East,velocityDesired.North) - atan2f(velocityActual.East,velocityActual.North));
637  } else {
638  // if we are not supposed to move, keep going wherever we are now. Don't make things worse by changing direction.
639  bearingError = 0;
640  }
641 
642  if (bearingError<-180.0f) bearingError+=360.0f;
643  if (bearingError>180.0f) bearingError-=360.0f;
644 
645  bearingIntegral = bound_min_max(bearingIntegral + bearingError * dT * fixedwingpathfollowerSettings.BearingPI[FIXEDWINGPATHFOLLOWERSETTINGS_BEARINGPI_KI],
646  -fixedwingpathfollowerSettings.BearingPI[FIXEDWINGPATHFOLLOWERSETTINGS_BEARINGPI_ILIMIT],
647  fixedwingpathfollowerSettings.BearingPI[FIXEDWINGPATHFOLLOWERSETTINGS_BEARINGPI_ILIMIT]);
648  bearingCommand = (bearingError * fixedwingpathfollowerSettings.BearingPI[FIXEDWINGPATHFOLLOWERSETTINGS_BEARINGPI_KP] +
650 
651  fixedwingpathfollowerStatus.Error[FIXEDWINGPATHFOLLOWERSTATUS_ERROR_BEARING] = bearingError;
652  fixedwingpathfollowerStatus.ErrorInt[FIXEDWINGPATHFOLLOWERSTATUS_ERRORINT_BEARING] = bearingIntegral;
653  fixedwingpathfollowerStatus.Command[FIXEDWINGPATHFOLLOWERSTATUS_COMMAND_BEARING] = bearingCommand;
654 
655  stabDesired.Roll = bound_min_max( fixedwingpathfollowerSettings.RollLimit[FIXEDWINGPATHFOLLOWERSETTINGS_ROLLLIMIT_NEUTRAL] +
656  bearingCommand,
657  fixedwingpathfollowerSettings.RollLimit[FIXEDWINGPATHFOLLOWERSETTINGS_ROLLLIMIT_MIN],
658  fixedwingpathfollowerSettings.RollLimit[FIXEDWINGPATHFOLLOWERSETTINGS_ROLLLIMIT_MAX] );
659 
660  // TODO: find a check to determine loss of directional control. Likely needs some check of derivative
661 
662 
666  // TODO implement raw control mode for yaw and base on Accels.Y
667  stabDesired.Yaw = 0;
668 
669  stabDesired.ReprojectionMode = STABILIZATIONDESIRED_REPROJECTIONMODE_NONE;
670 
671  stabDesired.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_ROLL] = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
672  stabDesired.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_PITCH] = STABILIZATIONDESIRED_STABILIZATIONMODE_ATTITUDE;
673  stabDesired.StabilizationMode[STABILIZATIONDESIRED_STABILIZATIONMODE_YAW] = STABILIZATIONDESIRED_STABILIZATIONMODE_MANUAL;
674  stabDesired.ThrustMode = STABILIZATIONDESIRED_THRUSTMODE_DIRECT;
675 
676  if (isnan(stabDesired.Roll) || isnan(stabDesired.Pitch) || isnan(stabDesired.Yaw) || isnan(stabDesired.Thrust)) {
677  northVelIntegral = 0;
678  eastVelIntegral = 0;
679  downVelIntegral = 0;
680  bearingIntegral = 0;
681  speedIntegral = 0;
682  accelIntegral = 0;
683  powerIntegral = 0;
684  airspeedErrorInt = 0;
685 
686  result = 0;
687  } else {
688  StabilizationDesiredSet(&stabDesired);
689  }
690 
691  FixedWingPathFollowerStatusSet(&fixedwingpathfollowerStatus);
692 
693  return result;
694 }
695 
696 static void SettingsUpdatedCb(const UAVObjEvent *ev,
697  void *ctx, void *obj, int len)
698 {
699  (void) ctx; (void) obj; (void) len;
700 
701  if (ev == NULL || ev->obj == FixedWingPathFollowerSettingsHandle())
702  FixedWingPathFollowerSettingsGet(&fixedwingpathfollowerSettings);
703  if (ev == NULL || ev->obj == FixedWingAirspeedsHandle())
704  FixedWingAirspeedsGet(&fixedWingAirspeeds);
705 }
706 
707 static void airspeedActualUpdatedCb(const UAVObjEvent *ev,
708  void *ctx, void *obj,
709  int len)
710 {
711  (void) ctx;
712 
713  AirspeedActualData airspeedActual;
714 
715  AirspeedActualGet(&airspeedActual);
716 
717  VelocityActualData velocityActual;
718 
719  VelocityActualGet(&velocityActual);
720 
721  float groundspeed = sqrtf(velocityActual.East*velocityActual.East + velocityActual.North*velocityActual.North );
722 
723  indicatedAirspeedActualBias = airspeedActual.CalibratedAirspeed - groundspeed;
724  // note - we do fly by Indicated Airspeed (== calibrated airspeed)
725  // however since airspeed is updated less often than groundspeed, we use sudden changes to groundspeed to offset the airspeed by the same measurement.
726 }
727 
#define TASK_PRIORITY
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
static float eastVelIntegral
static float accelIntegral
static PathDesiredData pathDesired
static void airspeedActualUpdatedCb(const UAVObjEvent *ev, void *ctx, void *obj, int len)
static void pathfollowerTask(void *parameters)
static float northVelIntegral
int32_t FixedWingPathFollowerInitialize()
void UAVObjCbSetFlag(const UAVObjEvent *objEv, void *ctx, void *obj, int len)
float fractional_progress
Definition: paths.h:37
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
static PathStatusData pathStatus
int32_t FixedWingPathFollowerStart()
static uint8_t updateFixedDesiredAttitude()
UAVObjHandle obj
float error
Definition: paths.h:38
static float airspeedErrorInt
static bool path_desired_updated
static bool module_enabled
Path calculation library with common API.
bool PIOS_SENSORS_IsRegistered(enum pios_sensor_type type)
Checks if a sensor type is registered with the PIOS_SENSORS interface.
Definition: pios_sensors.c:88
#define MODULE_INITCALL(ifn, sfn)
Definition: pios_initcall.h:67
static float downVelIntegral
float path_direction[2]
Definition: paths.h:40
void path_progress(const PathDesiredData *pathDesired, const float *cur_point, struct path_status *status)
Compute progress along path and deviation from it.
Definition: paths.c:62
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
uint16_t groundspeed
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
float bound_min_max(float val, float min, float max)
Bound input value between min and max.
Definition: misc_math.c:38
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
static float speedIntegral
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
Header for Coordinate conversions library in coordinate_conversions.c.
static float indicatedAirspeedActualBias
tuple f
Definition: px_mkfw.py:81
#define STACK_SIZE_BYTES
static float bearingIntegral
Includes PiOS and core architecture components.
static FixedWingAirspeedsData fixedWingAirspeeds
int32_t AlarmsClear(SystemAlarmsAlarmElem alarm)
Definition: alarms.c:171
float correction_direction[2]
Definition: paths.h:39
static float powerIntegral
static FixedWingPathFollowerSettingsData fixedwingpathfollowerSettings
static void updatePathVelocity()
static struct pios_thread * pathfollowerTaskHandle
static void SettingsUpdatedCb(const UAVObjEvent *ev, void *ctx, void *obj, int len)
enum arena_state state