dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
paths.c
Go to the documentation of this file.
1 
21 /*
22  * This program is free software; you can redistribute it and/or modify
23  * it under the terms of the GNU General Public License as published by
24  * the Free Software Foundation; either version 3 of the License, or
25  * (at your option) any later version.
26  *
27  * This program is distributed in the hope that it will be useful, but
28  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
29  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
30  * for more details.
31  *
32  * You should have received a copy of the GNU General Public License along
33  * with this program; if not, see <http://www.gnu.org/licenses/>
34  */
35 
36 #include "pios.h"
37 #include "paths.h"
38 
39 #include "uavobjectmanager.h"
40 #include "pathdesired.h"
41 
42 // private functions
43 static void path_endpoint(const float * start_point, const float * end_point,
44  const float * cur_point, struct path_status * status);
45 static void path_vector(const float * start_point, const float * end_point,
46  const float * cur_point, struct path_status * status);
47 static void path_circle(const float * center_point, float radius,
48  const float * cur_point, struct path_status * status,
49  bool clockwise);
50 static void path_curve(const float * start_point, const float * end_point,
51  float radius, const float * cur_point,
52  struct path_status * status, bool clockwise);
53 
62 void path_progress(const PathDesiredData *pathDesired,
63  const float *cur_point,
64  struct path_status *status)
65 {
66  uint8_t mode = pathDesired->Mode;
67  float start_point[2] = {pathDesired->Start[0],pathDesired->Start[1]};
68  float end_point[2] = {pathDesired->End[0],pathDesired->End[1]};
69 
70  switch(mode) {
71  case PATHDESIRED_MODE_VECTOR:
72  return path_vector(start_point, end_point, cur_point, status);
73  break;
74  case PATHDESIRED_MODE_CIRCLERIGHT:
75  return path_curve(start_point, end_point, pathDesired->ModeParameters, cur_point, status, 1);
76  break;
77  case PATHDESIRED_MODE_CIRCLELEFT:
78  return path_curve(start_point, end_point, pathDesired->ModeParameters, cur_point, status, 0);
79  break;
80  case PATHDESIRED_MODE_CIRCLEPOSITIONLEFT:
81  return path_circle(end_point, pathDesired->ModeParameters, cur_point, status, 0);
82  break;
83  case PATHDESIRED_MODE_CIRCLEPOSITIONRIGHT:
84  return path_circle(end_point, pathDesired->ModeParameters, cur_point, status, 1);
85  break;
86  case PATHDESIRED_MODE_ENDPOINT:
87  case PATHDESIRED_MODE_HOLDPOSITION:
88  default:
89  // use the endpoint as default failsafe if called in unknown modes
90  return path_endpoint(start_point, end_point, cur_point, status);
91  break;
92  }
93 }
94 
102 static void path_endpoint(const float *start_point,
103  const float *end_point,
104  const float *cur_point,
105  struct path_status *status)
106 {
107  float path_north, path_east, diff_north, diff_east;
108  float dist_path, dist_diff;
109 
110  // we do not correct in this mode
111  status->correction_direction[0] = status->correction_direction[1] = 0;
112 
113  // Distance to go
114  path_north = end_point[0] - start_point[0];
115  path_east = end_point[1] - start_point[1];
116 
117  // Current progress location relative to end
118  diff_north = end_point[0] - cur_point[0];
119  diff_east = end_point[1] - cur_point[1];
120 
121  dist_diff = sqrtf( diff_north * diff_north + diff_east * diff_east );
122  dist_path = sqrtf( path_north * path_north + path_east * path_east );
123 
124  if(dist_diff < 1e-6f ) {
125  status->fractional_progress = 1;
126  status->error = 0;
127  status->path_direction[0] = status->path_direction[1] = 0;
128  return;
129  }
130 
131  status->fractional_progress = 1 - dist_diff / (1 + dist_path);
132  status->error = dist_diff;
133 
134  // Compute direction to travel
135  status->path_direction[0] = diff_north / dist_diff;
136  status->path_direction[1] = diff_east / dist_diff;
137 }
138 
146 static void path_vector(const float *start_point,
147  const float *end_point,
148  const float *cur_point,
149  struct path_status *status)
150 {
151  float path_north, path_east, diff_north, diff_east;
152  float dist_path;
153  float dot;
154  float normal[2];
155 
156  // Distance to go
157  path_north = end_point[0] - start_point[0];
158  path_east = end_point[1] - start_point[1];
159 
160  // Current progress location relative to start
161  diff_north = cur_point[0] - start_point[0];
162  diff_east = cur_point[1] - start_point[1];
163 
164  dot = path_north * diff_north + path_east * diff_east;
165  dist_path = sqrtf( path_north * path_north + path_east * path_east );
166 
167  if(dist_path < 1e-6f) {
168  // if the path is too short, we cannot determine vector direction.
169  // Fly towards the endpoint to prevent flying away,
170  // but assume progress=1 either way.
171  path_endpoint( start_point, end_point, cur_point, status );
172  status->fractional_progress = 1;
173  return;
174  }
175 
176  // Compute the normal to the path
177  normal[0] = -path_east / dist_path;
178  normal[1] = path_north / dist_path;
179 
180  status->fractional_progress = dot / (dist_path * dist_path);
181  status->error = normal[0] * diff_north + normal[1] * diff_east;
182 
183  // Compute direction to correct error
184  status->correction_direction[0] = (status->error > 0) ? -normal[0] : normal[0];
185  status->correction_direction[1] = (status->error > 0) ? -normal[1] : normal[1];
186 
187  // Now just want magnitude of error
188  status->error = fabsf(status->error);
189 
190  // Compute direction to travel
191  status->path_direction[0] = path_north / dist_path;
192  status->path_direction[1] = path_east / dist_path;
193 
194 }
195 
203 static void path_circle(const float * center_point,
204  float radius,
205  const float * cur_point,
206  struct path_status * status,
207  bool clockwise)
208 {
209  float diff_north, diff_east;
210  float cradius;
211  float normal[2];
212 
213  if (radius < 0.10f) {
214  radius = 0.10f; // Never try a circle less than 10cm
215  }
216 
217  // Current location relative to center
218  diff_north = cur_point[0] - center_point[0];
219  diff_east = cur_point[1] - center_point[1];
220 
221  cradius = sqrtf( diff_north * diff_north + diff_east * diff_east );
222 
223  if (cradius < 1e-6f) {
224  // cradius is zero, just fly somewhere and make sure correction is still a normal
225  status->fractional_progress = 1;
226  status->error = radius;
227  status->correction_direction[0] = 0;
228  status->correction_direction[1] = 1;
229  status->path_direction[0] = 1;
230  status->path_direction[1] = 0;
231  return;
232  }
233 
234  if (clockwise) {
235  // Compute the normal to the radius clockwise
236  normal[0] = -diff_east / cradius;
237  normal[1] = diff_north / cradius;
238  } else {
239  // Compute the normal to the radius counter clockwise
240  normal[0] = diff_east / cradius;
241  normal[1] = -diff_north / cradius;
242  }
243 
244  status->fractional_progress = 0;
245 
246  // error is current radius minus wanted radius - positive if too close
247  status->error = radius - cradius;
248 
249  // Compute direction to correct error
250  status->correction_direction[0] = (status->error>0?1:-1) * diff_north / cradius;
251  status->correction_direction[1] = (status->error>0?1:-1) * diff_east / cradius;
252 
253  // Compute direction to travel
254  status->path_direction[0] = normal[0];
255  status->path_direction[1] = normal[1];
256 
257  status->error = fabsf(status->error);
258 }
259 
268 static void path_curve(const float * start_point,
269  const float * end_point,
270  float radius,
271  const float * cur_point,
272  struct path_status *status,
273  bool clockwise)
274 {
275  // OK for up to 10km
276  float min_radius = sqrtf(powf(start_point[0] - end_point[0], 2) +
277  powf(start_point[1] - end_point[1], 2)) / 2.0f + 0.01f;
278 
279  if (fabsf(radius) < min_radius) {
280  // This was possibly floating point confusion.
281  // Add 5cm and .5% and call it good.
282  if (radius >= 0) {
283  radius += 0.05f;
284  } else {
285  radius -= 0.05f;
286  }
287 
288  radius *= 1.005f;
289 
290  if (fabsf(radius) < min_radius) {
291  // Whoops! Radius was not close. Convert to (nearly)
292  // straight line.
293  radius = min_radius * 1000;
294  }
295  }
296 
297  float diff_north, diff_east;
298  float path_north, path_east;
299  float cradius;
300  float normal[2];
301 
302  // Compute the center of the circle connecting the two points as the intersection of two circles
303  // around the two points from
304  // http://www.mathworks.com/matlabcentral/newsreader/view_thread/255121
305  float m_n, m_e, p_n, p_e, d, center[2];
306 
307  // Center between start and end
308  m_n = (start_point[0] + end_point[0]) / 2;
309  m_e = (start_point[1] + end_point[1]) / 2;
310 
311  // Normal vector the line between start and end.
312  if (clockwise) {
313  p_n = -(end_point[1] - start_point[1]);
314  p_e = (end_point[0] - start_point[0]);
315  } else {
316  p_n = (end_point[1] - start_point[1]);
317  p_e = -(end_point[0] - start_point[0]);
318  }
319 
320  // Work out how far to go along the perpendicular bisector
321  d = sqrtf(radius * radius / (p_n * p_n + p_e * p_e) - 0.25f);
322 
323  float radius_sign = (radius > 0) ? 1 : -1;
324  float m_radius = fabsf(radius);
325 
326  if (fabsf(p_n) < 1e-3f && fabsf(p_e) < 1e-3f) {
327  center[0] = m_n;
328  center[1] = m_e;
329  } else {
330  center[0] = m_n + p_n * d * radius_sign;
331  center[1] = m_e + p_e * d * radius_sign;
332  }
333 
334  // Current location relative to center
335  diff_north = cur_point[0] - center[0];
336  diff_east = cur_point[1] - center[1];
337 
338  // Compute current radius from the center
339  cradius = sqrtf( diff_north * diff_north + diff_east * diff_east );
340 
341  // Compute error in terms of meters from the curve (the distance projected
342  // normal onto the path i.e. cross-track distance)
343  status->error = m_radius - cradius;
344 
345  if (cradius < 1e-6f) {
346  // cradius is zero, just fly somewhere and make sure correction is still a normal
347  status->fractional_progress = 1;
348  status->error = m_radius;
349  status->correction_direction[0] = 0;
350  status->correction_direction[1] = 1;
351  status->path_direction[0] = 1;
352  status->path_direction[1] = 0;
353  return;
354  }
355 
356  if (clockwise) {
357  // Compute the normal to the radius clockwise
358  normal[0] = -diff_east / cradius;
359  normal[1] = diff_north / cradius;
360  } else {
361  // Compute the normal to the radius counter clockwise
362  normal[0] = diff_east / cradius;
363  normal[1] = -diff_north / cradius;
364  }
365 
366  // Compute direction to correct error
367  status->correction_direction[0] = (status->error>0?1:-1) * diff_north / cradius;
368  status->correction_direction[1] = (status->error>0?1:-1) * diff_east / cradius;
369 
370  // Compute direction to travel
371  status->path_direction[0] = normal[0];
372  status->path_direction[1] = normal[1];
373 
374  path_north = end_point[0] - start_point[0];
375  path_east = end_point[1] - start_point[1];
376  diff_north = cur_point[0] - start_point[0];
377  diff_east = cur_point[1] - start_point[1];
378  float dist_path = sqrtf( path_north * path_north + path_east * path_east );
379  float dot = path_north * diff_north + path_east * diff_east;
380 
381  status->fractional_progress = dot / (dist_path * dist_path);
382 
383  status->error = fabsf(status->error);
384 }
385 
static void path_endpoint(const float *start_point, const float *end_point, const float *cur_point, struct path_status *status)
Compute progress towards endpoint. Deviation equals distance.
Definition: paths.c:102
static PathDesiredData pathDesired
Main PiOS header to include all the compiled in PiOS options.
static void path_circle(const float *center_point, float radius, const float *cur_point, struct path_status *status, bool clockwise)
Circle location continuously.
Definition: paths.c:203
static void path_vector(const float *start_point, const float *end_point, const float *cur_point, struct path_status *status)
Compute progress along path and deviation from it.
Definition: paths.c:146
float fractional_progress
Definition: paths.h:37
float error
Definition: paths.h:38
static void path_curve(const float *start_point, const float *end_point, float radius, const float *cur_point, struct path_status *status, bool clockwise)
Compute progress along circular path and deviation from it.
Definition: paths.c:268
int16_t status
Definition: main.c:61
Path calculation library with common API.
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
enum channel_mode mode
Definition: pios_servo.c:58
uint8_t d
Definition: msp_messages.h:98
tuple f
Definition: px_mkfw.py:81
float correction_direction[2]
Definition: paths.h:39