dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pathplanner.c
Go to the documentation of this file.
1 
13 /*
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  * for more details.
23  *
24  * You should have received a copy of the GNU General Public License along
25  * with this program; if not, see <http://www.gnu.org/licenses/>
26  */
27 
28 #include "openpilot.h"
29 #include "physical_constants.h"
30 #include "paths.h"
31 
32 #include "flightstatus.h"
33 #include "pathdesired.h"
34 #include "pathplannersettings.h"
35 #include "pathstatus.h"
36 #include "positionactual.h"
37 #include "waypoint.h"
38 #include "waypointactive.h"
39 #include "modulesettings.h"
40 #include "pios_thread.h"
41 #include "pios_queue.h"
42 
43 // Private constants
44 #define STACK_SIZE_BYTES 1024
45 #define TASK_PRIORITY PIOS_THREAD_PRIO_LOW
46 #define MAX_QUEUE_SIZE 2
47 #define UPDATE_RATE_MS 20
48 
49 // Private types
50 
51 // Private variables
52 static struct pios_thread *taskHandle;
53 static struct pios_queue *queue;
54 static PathPlannerSettingsData pathPlannerSettings;
55 static WaypointActiveData waypointActive;
56 static WaypointData waypoint;
57 static bool path_completed;
58 
59 // Private functions
60 static void advanceWaypoint();
61 static void activateWaypoint(int idx);
62 
63 static void pathPlannerTask(void *parameters);
64 static void process_pp_settings();
65 
66 static void waypointsUpdated(const UAVObjEvent *ev,
67  void *ctx, void *obj, int len);
68 static void pathStatusUpdated(const UAVObjEvent *ev,
69  void *ctx, void *obj, int len);
70 static void createPathBox();
71 static void createPathLogo();
72 
73 static bool module_enabled;
74 
75 static volatile bool pathplanner_config_dirty;
76 
78 static int32_t active_waypoint = -1;
80 static int32_t previous_waypoint = -1;
85 {
86  if(module_enabled) {
87  taskHandle = NULL;
88 
89  // Start VM thread
91  TaskMonitorAdd(TASKINFO_RUNNING_PATHPLANNER, taskHandle);
92  return 0;
93  }
94 
95  return -1;
96 }
97 
102 {
103  taskHandle = NULL;
104 
105 #ifdef MODULE_PathPlanner_BUILTIN
106  module_enabled = true;
107 #else
108  uint8_t module_state[MODULESETTINGS_ADMINSTATE_NUMELEM];
109  ModuleSettingsAdminStateGet(module_state);
110  if (module_state[MODULESETTINGS_ADMINSTATE_PATHPLANNER] == MODULESETTINGS_ADMINSTATE_ENABLED) {
111  module_enabled = true;
112  } else {
113  module_enabled = false;
114  }
115 #endif
116 
117  if (PathPlannerSettingsInitialize() == -1) {
118  module_enabled = false;
119  return -1;
120  }
121 
122  if(module_enabled) {
123  if (WaypointInitialize() == -1 || WaypointActiveInitialize() == -1) {
124  module_enabled = false;
125  return -1;
126  }
127 
128  // Create object queue
129  queue = PIOS_Queue_Create(MAX_QUEUE_SIZE, sizeof(UAVObjEvent));
130  FlightStatusConnectQueue(queue);
131 
132  return 0;
133  }
134 
135  return -1;
136 }
137 
139 
140 
143 static void pathPlannerTask(void *parameters)
144 {
145  // If the PathStatus isn't available no follower is running and we should abort
146  while (PathStatusHandle() == NULL || !TaskMonitorQueryRunning(TASKINFO_RUNNING_PATHFOLLOWER)) {
147  AlarmsSet(SYSTEMALARMS_ALARM_PATHPLANNER, SYSTEMALARMS_ALARM_CRITICAL);
148  PIOS_Thread_Sleep(1000);
149  }
150 
151  AlarmsClear(SYSTEMALARMS_ALARM_PATHPLANNER);
152 
153  PathPlannerSettingsConnectCallbackCtx(UAVObjCbSetFlag,
156 
157  WaypointConnectCallback(waypointsUpdated);
158  WaypointActiveConnectCallback(waypointsUpdated);
159 
160  FlightStatusData flightStatus;
161 
162  // Main thread loop
163  bool pathplanner_active = false;
164 
165  // TODO: This is janky.
166  PathStatusConnectCallback(pathStatusUpdated);
167  pathStatusUpdated(NULL, NULL, NULL, 0);
168  path_completed = false;
169 
170  while (1)
171  {
174 
175  pathplanner_config_dirty = false;
176  }
177 
178  // Make sure when flight mode toggles, to immediately update the path
179  UAVObjEvent ev;
180  PIOS_Queue_Receive(queue, &ev, UPDATE_RATE_MS);
181 
182  // When not running the path planner short circuit and wait
183  FlightStatusGet(&flightStatus);
184  if (flightStatus.FlightMode != FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER) {
185  pathplanner_active = false;
186  continue;
187  }
188 
189  if(pathplanner_active == false) {
190  // Reset the state. Active waypoint should be set to an invalid
191  // value to force waypoint 0 to become activated when starting
192  // Note: this needs to be done before the callback is triggered!
193  active_waypoint = -1;
194  previous_waypoint = -1;
195 
196  // This triggers callback to update variable
197  WaypointActiveGet(&waypointActive);
198  waypointActive.Index = 0;
199  WaypointActiveSet(&waypointActive);
200 
201  pathplanner_active = true;
202  continue;
203  }
204 
205  /* This method determines if we have achieved the goal of the active */
206  /* waypoint */
207  if (path_completed)
208  advanceWaypoint();
209 
210  /* If advance waypoint takes a long time to calculate then it should */
211  /* be called from here when the active_waypoints does not equal the */
212  /* WaypointActive.Index */
213  /* if (active_waypoint != WaypointActive.Index) */
214  /* advanceWaypoint(WaypointActive.Index) */
215  }
216 }
217 
222 static void waypointsUpdated(const UAVObjEvent *ev,
223  void *ctx, void *obj, int len)
224 {
225  (void) ev; (void) ctx; (void) obj; (void) len;
226 
227  FlightStatusData flightStatus;
228  FlightStatusGet(&flightStatus);
229  if (flightStatus.FlightMode != FLIGHTSTATUS_FLIGHTMODE_PATHPLANNER)
230  return;
231 
232  WaypointActiveGet(&waypointActive);
233  if(active_waypoint != waypointActive.Index) {
235 
237  }
238 }
239 
243 static void pathStatusUpdated(const UAVObjEvent *ev,
244  void *ctx, void *obj, int len)
245 {
246  (void) ev; (void) ctx; (void) obj; (void) len;
247 
248  PathStatusData pathStatus;
249 
250  PathStatusGet(&pathStatus);
251 
252  if ((pathStatus.Status == PATHSTATUS_STATUS_COMPLETED) &&
253  (pathStatus.Waypoint == active_waypoint)) {
254  path_completed = true;
255  }
256 }
257 
262 static void holdCurrentPosition()
263 {
264  // TODO: Define a separate error condition method which can select RTH versus PH
265  PositionActualData position;
266  PositionActualGet(&position);
267 
268  PathDesiredData pathDesired;
269  pathDesired.Start[PATHDESIRED_START_NORTH] = position.North;
270  pathDesired.Start[PATHDESIRED_START_EAST] = position.East;
271  pathDesired.Start[PATHDESIRED_START_DOWN] = position.Down;
272  pathDesired.End[PATHDESIRED_END_NORTH] = position.North;
273  pathDesired.End[PATHDESIRED_END_EAST] = position.East;
274  pathDesired.End[PATHDESIRED_END_DOWN] = position.Down;
275  pathDesired.Mode = PATHDESIRED_MODE_HOLDPOSITION;
276  pathDesired.StartingVelocity = 5; // This will be the max velocity it uses to try and hold
277  pathDesired.EndingVelocity = 5;
278  pathDesired.ModeParameters = 0;
279  pathDesired.Waypoint = -1;
280  PathDesiredSet(&pathDesired);
281 }
282 
287 static void holdPosition(uint32_t idx)
288 {
289  // Get the selected waypoint
290  WaypointData waypoint;
291  WaypointInstGet(idx, &waypoint);
292 
293  PositionActualData position;
294  PositionActualGet(&position);
295 
296  PathDesiredData pathDesired;
297  pathDesired.Start[PATHDESIRED_START_NORTH] = position.North;
298  pathDesired.Start[PATHDESIRED_START_EAST] = position.East;
299  pathDesired.Start[PATHDESIRED_START_DOWN] = position.Down;
300  pathDesired.End[PATHDESIRED_END_NORTH] = waypoint.Position[WAYPOINT_POSITION_NORTH];
301  pathDesired.End[PATHDESIRED_END_EAST] = waypoint.Position[WAYPOINT_POSITION_EAST];
302  pathDesired.End[PATHDESIRED_END_DOWN] = waypoint.Position[WAYPOINT_POSITION_DOWN];
303  pathDesired.Mode = PATHDESIRED_MODE_HOLDPOSITION;
304  pathDesired.StartingVelocity = 5; // This will be the max velocity it uses to try and hold
305  pathDesired.EndingVelocity = 5;
306  pathDesired.ModeParameters = 0;
307  pathDesired.Waypoint = -1;
308  PathDesiredSet(&pathDesired);
309 }
310 
311 static bool waypointValid(int32_t idx) {
312  if (idx < 0) return false;
313 
314  if (idx >= UAVObjGetNumInstances(WaypointHandle())) {
315  return false;
316  }
317 
318  // Get the activated waypoint
319  WaypointData waypoint;
320  WaypointInstGet(idx, &waypoint);
321 
322  // Perhaps should fully validate here..
323  if (waypoint.Mode == WAYPOINT_MODE_INVALID) {
324  return false;
325  }
326 
327  return true;
328 }
329 
333 static void advanceWaypoint()
334 {
335  WaypointActiveGet(&waypointActive);
336 
337  // Default implementation simply jumps to the next possible waypoint. Insert any
338  // conditional logic desired here.
339  // Note: In the case of conditional logic it is the responsibilty of the implementer
340  // to ensure all possible paths are valid.
341 
342  int32_t next_waypoint = waypointActive.Index + 1;
343 
344  if (!waypointValid(next_waypoint)) {
345  holdPosition(waypointActive.Index); // This means current waypoint
346  } else {
348 
349  waypointActive.Index = next_waypoint;
350 
351  WaypointActiveSet(&waypointActive);
352  }
353 
354  path_completed = false;
355 }
356 
365 static void activateWaypoint(int idx)
366 {
367  if (!waypointValid(idx)) {
368  // Attempting to access invalid waypoint. Fall back to position hold at current location
369  AlarmsSet(SYSTEMALARMS_ALARM_PATHPLANNER, SYSTEMALARMS_ALARM_ERROR);
371  return;
372  }
373 
374  // Get the activated waypoint
375  WaypointInstGet(idx, &waypoint);
376 
377  PathDesiredData pathDesired;
378 
379  pathDesired.Waypoint = idx;
380 
381  pathDesired.End[PATHDESIRED_END_NORTH] = waypoint.Position[WAYPOINT_POSITION_NORTH];
382  pathDesired.End[PATHDESIRED_END_EAST] = waypoint.Position[WAYPOINT_POSITION_EAST];
383  pathDesired.End[PATHDESIRED_END_DOWN] = waypoint.Position[WAYPOINT_POSITION_DOWN];
384  pathDesired.ModeParameters = waypoint.ModeParameters;
385 
386  // Use this to ensure the cases match up (catastrophic if not) and to cover any cases
387  // that don't make sense to come from the path planner
388  switch(waypoint.Mode) {
389  case WAYPOINT_MODE_VECTOR:
390  pathDesired.Mode = PATHDESIRED_MODE_VECTOR;
391  break;
392  case WAYPOINT_MODE_ENDPOINT:
393  pathDesired.Mode = PATHDESIRED_MODE_ENDPOINT;
394  break;
395  case WAYPOINT_MODE_CIRCLELEFT:
396  pathDesired.Mode = PATHDESIRED_MODE_CIRCLELEFT;
397  break;
398  case WAYPOINT_MODE_CIRCLERIGHT:
399  pathDesired.Mode = PATHDESIRED_MODE_CIRCLERIGHT;
400  break;
401  case WAYPOINT_MODE_LAND:
402  pathDesired.Mode = PATHDESIRED_MODE_LAND;
403  break;
404  default:
406  AlarmsSet(SYSTEMALARMS_ALARM_PATHPLANNER, SYSTEMALARMS_ALARM_ERROR);
407  return;
408  }
409 
410  pathDesired.EndingVelocity = waypoint.Velocity;
411 
412  if(previous_waypoint < 0) {
413  // For first waypoint, get current position as start point
414  PositionActualData positionActual;
415  PositionActualGet(&positionActual);
416 
417  pathDesired.Start[PATHDESIRED_START_NORTH] = positionActual.North;
418  pathDesired.Start[PATHDESIRED_START_EAST] = positionActual.East;
419  pathDesired.Start[PATHDESIRED_START_DOWN] = positionActual.Down - 1;
420  pathDesired.StartingVelocity = waypoint.Velocity;
421  } else {
422  // Get previous waypoint as start point
423  WaypointData waypointPrev;
424  WaypointInstGet(previous_waypoint, &waypointPrev);
425 
426  pathDesired.Start[PATHDESIRED_END_NORTH] = waypointPrev.Position[WAYPOINT_POSITION_NORTH];
427  pathDesired.Start[PATHDESIRED_END_EAST] = waypointPrev.Position[WAYPOINT_POSITION_EAST];
428  pathDesired.Start[PATHDESIRED_END_DOWN] = waypointPrev.Position[WAYPOINT_POSITION_DOWN];
429  pathDesired.StartingVelocity = waypointPrev.Velocity;
430  }
431 
432  PathDesiredSet(&pathDesired);
433 
434  // Invalidate any pending path status updates
435  path_completed = false;
436 
437  AlarmsClear(SYSTEMALARMS_ALARM_PATHPLANNER);
438 }
439 
440 static void process_pp_settings() {
441  uint8_t preprogrammedPath = pathPlannerSettings.PreprogrammedPath;
442 
443  PathPlannerSettingsGet(&pathPlannerSettings);
444 
445  if (pathPlannerSettings.PreprogrammedPath != preprogrammedPath) {
446  switch(pathPlannerSettings.PreprogrammedPath) {
447  case PATHPLANNERSETTINGS_PREPROGRAMMEDPATH_NONE:
448  break;
449  case PATHPLANNERSETTINGS_PREPROGRAMMEDPATH_10M_BOX:
450  createPathBox();
451  break;
452  case PATHPLANNERSETTINGS_PREPROGRAMMEDPATH_LOGO:
453  createPathLogo();
454  break;
455 
456  }
457  }
458 }
459 
460 static void createPathBox()
461 {
462  WaypointCreateInstance();
463  WaypointCreateInstance();
464  WaypointCreateInstance();
465  WaypointCreateInstance();
466  WaypointCreateInstance();
467 
468  // Draw O
469  WaypointData waypoint;
470  waypoint.Velocity = 2.5;
471  waypoint.Mode = WAYPOINT_MODE_VECTOR;
472 
473  waypoint.Position[0] = 0;
474  waypoint.Position[1] = 0;
475  waypoint.Position[2] = -10;
476  WaypointInstSet(0, &waypoint);
477 
478  waypoint.Position[0] = 5;
479  waypoint.Position[1] = 5;
480  waypoint.Position[2] = -10;
481  WaypointInstSet(1, &waypoint);
482 
483  waypoint.Position[0] = -5;
484  waypoint.Position[1] = 5;
485  waypoint.Mode = WAYPOINT_MODE_VECTOR;
486  waypoint.ModeParameters = 35;
487  WaypointInstSet(2, &waypoint);
488 
489  waypoint.Position[0] = -5;
490  waypoint.Position[1] = -5;
491  WaypointInstSet(3, &waypoint);
492 
493  waypoint.Position[0] = 5;
494  waypoint.Position[1] = -5;
495  WaypointInstSet(4, &waypoint);
496 
497  waypoint.Position[0] = 5;
498  waypoint.Position[1] = 5;
499  WaypointInstSet(5, &waypoint);
500 
501  waypoint.Position[0] = 0;
502  waypoint.Position[1] = 0;
503  waypoint.Mode = WAYPOINT_MODE_VECTOR;
504  WaypointInstSet(6, &waypoint);
505 }
506 
507 static void createPathLogo()
508 {
509  // Draw O
510  WaypointData waypoint;
511  waypoint.Velocity = 5; // Since for now this isn't directional just set a mag
512  waypoint.Mode = WAYPOINT_MODE_VECTOR;
513  waypoint.ModeParameters = 0;
514  waypoint.Position[2] = -20;
515 
516  waypoint.Position[0] = 6.49;
517  waypoint.Position[1] = -9.52;
518  WaypointInstSet(0, &waypoint);
519 
520  waypoint.Position[0] = 6.32;
521  waypoint.Position[1] = -94.82;
522  WaypointCreateInstance();
523  WaypointInstSet(1, &waypoint);
524 
525  waypoint.Position[0] = 6.32;
526  waypoint.Position[1] = -77.13;
527  WaypointCreateInstance();
528  WaypointInstSet(2, &waypoint);
529 
530  waypoint.Position[0] = -17.04;
531  waypoint.Position[1] = -77.071;
532  WaypointCreateInstance();
533  WaypointInstSet(3, &waypoint);
534 
535  waypoint.Position[0] = -26.42;
536  waypoint.Position[1] = -69.30;
537  waypoint.Mode = WAYPOINT_MODE_CIRCLELEFT;
538  waypoint.ModeParameters = 10;
539  WaypointCreateInstance();
540  WaypointInstSet(4, &waypoint);
541 
542  waypoint.Position[0] = -27.06;
543  waypoint.Position[1] = -59.58;
544  waypoint.Mode = WAYPOINT_MODE_VECTOR;
545  waypoint.ModeParameters = 0;
546  WaypointCreateInstance();
547  WaypointInstSet(5, &waypoint);
548 
549  waypoint.Position[0] = -22.37;
550  waypoint.Position[1] = -51.81;
551  waypoint.Mode = WAYPOINT_MODE_CIRCLELEFT;
552  waypoint.ModeParameters = 8;
553  WaypointCreateInstance();
554  WaypointInstSet(6, &waypoint);
555 
556  waypoint.Position[0] = -4.25;
557  waypoint.Position[1] = -38.64;
558  waypoint.Mode = WAYPOINT_MODE_VECTOR;
559  waypoint.ModeParameters = 0;
560  WaypointCreateInstance();
561  WaypointInstSet(7, &waypoint);
562 
563  waypoint.Position[0] = 6.33;
564  waypoint.Position[1] = -45.74;
565  waypoint.Mode = WAYPOINT_MODE_CIRCLELEFT;
566  waypoint.ModeParameters = 10;
567  WaypointCreateInstance();
568  WaypointInstSet(8, &waypoint);
569 
570  waypoint.Position[0] = -5.11;
571  waypoint.Position[1] = -52.46;
572  waypoint.Mode = WAYPOINT_MODE_CIRCLELEFT;
573  waypoint.ModeParameters = 10;
574  WaypointCreateInstance();
575  WaypointInstSet(9, &waypoint);
576 
577  waypoint.Position[0] = -26.84;
578  waypoint.Position[1] = -41.45;
579  waypoint.Mode = WAYPOINT_MODE_VECTOR;
580  waypoint.ModeParameters = 0;
581  WaypointCreateInstance();
582  WaypointInstSet(10, &waypoint);
583 
584  waypoint.Position[0] = -18.11;
585  waypoint.Position[1] = -34.11;
586  waypoint.Mode = WAYPOINT_MODE_CIRCLERIGHT;
587  waypoint.ModeParameters = 10;
588  WaypointCreateInstance();
589  WaypointInstSet(11, &waypoint);
590 
591  waypoint.Position[0] = -10.65;
592  waypoint.Position[1] = -3.45;
593  waypoint.Mode = WAYPOINT_MODE_VECTOR;
594  waypoint.ModeParameters = 0;
595  WaypointCreateInstance();
596  WaypointInstSet(12, &waypoint);
597 }
598 
static WaypointData waypoint
Definition: pathplanner.c:56
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
static PathDesiredData pathDesired
bool TaskMonitorQueryRunning(TaskInfoRunningElem task)
Definition: taskmonitor.c:105
static void process_pp_settings()
Definition: pathplanner.c:440
static void pathPlannerTask(void *parameters)
Definition: pathplanner.c:143
#define UPDATE_RATE_MS
Definition: pathplanner.c:47
#define MAX_QUEUE_SIZE
Definition: pathplanner.c:46
static void pathStatusUpdated(const UAVObjEvent *ev, void *ctx, void *obj, int len)
Definition: pathplanner.c:243
static struct pios_queue * queue
Definition: pathplanner.c:53
void UAVObjCbSetFlag(const UAVObjEvent *objEv, void *ctx, void *obj, int len)
int32_t AlarmsSet(SystemAlarmsAlarmElem alarm, SystemAlarmsAlarmOptions severity)
Definition: alarms.c:97
static bool path_completed
Definition: pathplanner.c:57
static PathStatusData pathStatus
bool PIOS_Queue_Receive(struct pios_queue *queuep, void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:213
static void createPathBox()
Definition: pathplanner.c:460
#define TASK_PRIORITY
Definition: pathplanner.c:45
int32_t PathPlannerStart()
Definition: pathplanner.c:84
Path calculation library with common API.
static PathPlannerSettingsData pathPlannerSettings
Definition: pathplanner.c:54
static struct pios_thread * taskHandle
Definition: pathplanner.c:52
#define MODULE_INITCALL(ifn, sfn)
Definition: pios_initcall.h:67
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
int32_t TaskMonitorAdd(TaskInfoRunningElem task, struct pios_thread *threadp)
Definition: taskmonitor.c:67
static void activateWaypoint(int idx)
Definition: pathplanner.c:365
static void advanceWaypoint()
Definition: pathplanner.c:333
int32_t PathPlannerInitialize()
Definition: pathplanner.c:101
static int32_t active_waypoint
Store which waypoint has actually been pushed into PathDesired.
Definition: pathplanner.c:78
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
static void waypointsUpdated(const UAVObjEvent *ev, void *ctx, void *obj, int len)
Definition: pathplanner.c:222
static WaypointActiveData waypointActive
Definition: pathplanner.c:55
#define STACK_SIZE_BYTES
Definition: pathplanner.c:44
Includes PiOS and core architecture components.
int32_t AlarmsClear(SystemAlarmsAlarmElem alarm)
Definition: alarms.c:171
uint16_t UAVObjGetNumInstances(UAVObjHandle obj)
static volatile bool pathplanner_config_dirty
Definition: pathplanner.c:75
static bool module_enabled
Definition: pathplanner.c:73
static void holdCurrentPosition()
Definition: pathplanner.c:262
static void holdPosition(uint32_t idx)
Definition: pathplanner.c:287
static bool waypointValid(int32_t idx)
Definition: pathplanner.c:311
static int32_t previous_waypoint
Store the previous waypoint which is used to determine the path trajectory.
Definition: pathplanner.c:80
static void createPathLogo()
Definition: pathplanner.c:507