dubins.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. /*
  2. * Copyright (c) 2008-2018, Andrew Walker
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. #ifdef WIN32
  23. #define _USE_MATH_DEFINES
  24. #endif
  25. #include <math.h>
  26. #include "dubins.h"
  27. #define EPSILON (10e-10)
  28. typedef enum
  29. {
  30. L_SEG = 0,
  31. S_SEG = 1,
  32. R_SEG = 2
  33. } SegmentType;
  34. /* The segment types for each of the Path types */
  35. const SegmentType DIRDATA[][3] = {
  36. { L_SEG, S_SEG, L_SEG },
  37. { L_SEG, S_SEG, R_SEG },
  38. { R_SEG, S_SEG, L_SEG },
  39. { R_SEG, S_SEG, R_SEG },
  40. { R_SEG, L_SEG, R_SEG },
  41. { L_SEG, R_SEG, L_SEG }
  42. };
  43. typedef struct
  44. {
  45. double alpha;
  46. double beta;
  47. double d;
  48. double sa;
  49. double sb;
  50. double ca;
  51. double cb;
  52. double c_ab;
  53. double d_sq;
  54. } DubinsIntermediateResults;
  55. int dubins_word(DubinsIntermediateResults* in, DubinsPathType pathType, double out[3]);
  56. int dubins_intermediate_results(DubinsIntermediateResults* in, double q0[3], double q1[3], double rho);
  57. /**
  58. * Floating point modulus suitable for rings
  59. *
  60. * fmod doesn't behave correctly for angular quantities, this function does
  61. */
  62. double fmodr( double x, double y)
  63. {
  64. return x - y*floor(x/y);
  65. }
  66. double mod2pi( double theta )
  67. {
  68. return fmodr( theta, 2 * M_PI );
  69. }
  70. int dubins_shortest_path(DubinsPath* path, double q0[3], double q1[3], double rho)
  71. {
  72. int i, errcode;
  73. DubinsIntermediateResults in;
  74. double params[3];
  75. double cost;
  76. double best_cost = INFINITY;
  77. int best_word = -1;
  78. errcode = dubins_intermediate_results(&in, q0, q1, rho);
  79. if(errcode != EDUBOK) {
  80. return errcode;
  81. }
  82. path->qi[0] = q0[0];
  83. path->qi[1] = q0[1];
  84. path->qi[2] = q0[2];
  85. path->rho = rho;
  86. for( i = 0; i < 6; i++ ) {
  87. DubinsPathType pathType = (DubinsPathType)i;
  88. errcode = dubins_word(&in, pathType, params);
  89. if(errcode == EDUBOK) {
  90. cost = params[0] + params[1] + params[2];
  91. if(cost < best_cost) {
  92. best_word = i;
  93. best_cost = cost;
  94. path->param[0] = params[0];
  95. path->param[1] = params[1];
  96. path->param[2] = params[2];
  97. path->type = pathType;
  98. }
  99. }
  100. }
  101. if(best_word == -1) {
  102. return EDUBNOPATH;
  103. }
  104. return EDUBOK;
  105. }
  106. int dubins_path(DubinsPath* path, double q0[3], double q1[3], double rho, DubinsPathType pathType)
  107. {
  108. int errcode;
  109. DubinsIntermediateResults in;
  110. errcode = dubins_intermediate_results(&in, q0, q1, rho);
  111. if(errcode == EDUBOK) {
  112. double params[3];
  113. errcode = dubins_word(&in, pathType, params);
  114. if(errcode == EDUBOK) {
  115. path->param[0] = params[0];
  116. path->param[1] = params[1];
  117. path->param[2] = params[2];
  118. path->qi[0] = q0[0];
  119. path->qi[1] = q0[1];
  120. path->qi[2] = q0[2];
  121. path->rho = rho;
  122. path->type = pathType;
  123. }
  124. }
  125. return errcode;
  126. }
  127. double dubins_path_length( DubinsPath* path )
  128. {
  129. double length = 0.;
  130. length += path->param[0];
  131. length += path->param[1];
  132. length += path->param[2];
  133. length = length * path->rho;
  134. return length;
  135. }
  136. double dubins_segment_length( DubinsPath* path, int i )
  137. {
  138. if( (i < 0) || (i > 2) )
  139. {
  140. return INFINITY;
  141. }
  142. return path->param[i] * path->rho;
  143. }
  144. double dubins_segment_length_normalized( DubinsPath* path, int i )
  145. {
  146. if( (i < 0) || (i > 2) )
  147. {
  148. return INFINITY;
  149. }
  150. return path->param[i];
  151. }
  152. DubinsPathType dubins_path_type( DubinsPath* path )
  153. {
  154. return path->type;
  155. }
  156. void dubins_segment( double t, double qi[3], double qt[3], SegmentType type)
  157. {
  158. double st = sin(qi[2]);
  159. double ct = cos(qi[2]);
  160. if( type == L_SEG ) {
  161. qt[0] = +sin(qi[2]+t) - st;
  162. qt[1] = -cos(qi[2]+t) + ct;
  163. qt[2] = t;
  164. }
  165. else if( type == R_SEG ) {
  166. qt[0] = -sin(qi[2]-t) + st;
  167. qt[1] = +cos(qi[2]-t) - ct;
  168. qt[2] = -t;
  169. }
  170. else if( type == S_SEG ) {
  171. qt[0] = ct * t;
  172. qt[1] = st * t;
  173. qt[2] = 0.0;
  174. }
  175. qt[0] += qi[0];
  176. qt[1] += qi[1];
  177. qt[2] += qi[2];
  178. }
  179. int dubins_path_sample( DubinsPath* path, double t, double q[3] )
  180. {
  181. /* tprime is the normalised variant of the parameter t */
  182. double tprime = t / path->rho;
  183. double qi[3]; /* The translated initial configuration */
  184. double q1[3]; /* end-of segment 1 */
  185. double q2[3]; /* end-of segment 2 */
  186. const SegmentType* types = DIRDATA[path->type];
  187. double p1, p2;
  188. if( t < 0 || t > dubins_path_length(path) ) {
  189. return EDUBPARAM;
  190. }
  191. /* initial configuration */
  192. qi[0] = 0.0;
  193. qi[1] = 0.0;
  194. qi[2] = path->qi[2];
  195. /* generate the target configuration */
  196. p1 = path->param[0];
  197. p2 = path->param[1];
  198. dubins_segment( p1, qi, q1, types[0] );
  199. dubins_segment( p2, q1, q2, types[1] );
  200. if( tprime < p1 ) {
  201. dubins_segment( tprime, qi, q, types[0] );
  202. }
  203. else if( tprime < (p1+p2) ) {
  204. dubins_segment( tprime-p1, q1, q, types[1] );
  205. }
  206. else {
  207. dubins_segment( tprime-p1-p2, q2, q, types[2] );
  208. }
  209. /* scale the target configuration, translate back to the original starting point */
  210. q[0] = q[0] * path->rho + path->qi[0];
  211. q[1] = q[1] * path->rho + path->qi[1];
  212. q[2] = mod2pi(q[2]);
  213. return EDUBOK;
  214. }
  215. int dubins_path_sample_many(DubinsPath* path, double stepSize,
  216. DubinsPathSamplingCallback cb, void* user_data)
  217. {
  218. int retcode;
  219. double q[3];
  220. double x = 0.0;
  221. double length = dubins_path_length(path);
  222. while( x < length ) {
  223. dubins_path_sample( path, x, q );
  224. retcode = cb(q, x, user_data);
  225. if( retcode != 0 ) {
  226. return retcode;
  227. }
  228. x += stepSize;
  229. }
  230. return 0;
  231. }
  232. int dubins_path_endpoint( DubinsPath* path, double q[3] )
  233. {
  234. return dubins_path_sample( path, dubins_path_length(path) - EPSILON, q );
  235. }
  236. int dubins_extract_subpath( DubinsPath* path, double t, DubinsPath* newpath )
  237. {
  238. /* calculate the true parameter */
  239. double tprime = t / path->rho;
  240. if((t < 0) || (t > dubins_path_length(path)))
  241. {
  242. return EDUBPARAM;
  243. }
  244. /* copy most of the data */
  245. newpath->qi[0] = path->qi[0];
  246. newpath->qi[1] = path->qi[1];
  247. newpath->qi[2] = path->qi[2];
  248. newpath->rho = path->rho;
  249. newpath->type = path->type;
  250. /* fix the parameters */
  251. newpath->param[0] = fmin( path->param[0], tprime );
  252. newpath->param[1] = fmin( path->param[1], tprime - newpath->param[0]);
  253. newpath->param[2] = fmin( path->param[2], tprime - newpath->param[0] - newpath->param[1]);
  254. return 0;
  255. }
  256. int dubins_intermediate_results(DubinsIntermediateResults* in, double q0[3], double q1[3], double rho)
  257. {
  258. double dx, dy, D, d, theta, alpha, beta;
  259. if( rho <= 0.0 ) {
  260. return EDUBBADRHO;
  261. }
  262. dx = q1[0] - q0[0];
  263. dy = q1[1] - q0[1];
  264. D = sqrt( dx * dx + dy * dy );
  265. d = D / rho;
  266. theta = 0;
  267. /* test required to prevent domain errors if dx=0 and dy=0 */
  268. if(d > 0) {
  269. theta = mod2pi(atan2( dy, dx ));
  270. }
  271. alpha = mod2pi(q0[2] - theta);
  272. beta = mod2pi(q1[2] - theta);
  273. in->alpha = alpha;
  274. in->beta = beta;
  275. in->d = d;
  276. in->sa = sin(alpha);
  277. in->sb = sin(beta);
  278. in->ca = cos(alpha);
  279. in->cb = cos(beta);
  280. in->c_ab = cos(alpha - beta);
  281. in->d_sq = d * d;
  282. return EDUBOK;
  283. }
  284. int dubins_LSL(DubinsIntermediateResults* in, double out[3])
  285. {
  286. double tmp0, tmp1, p_sq;
  287. tmp0 = in->d + in->sa - in->sb;
  288. p_sq = 2 + in->d_sq - (2*in->c_ab) + (2 * in->d * (in->sa - in->sb));
  289. if(p_sq >= 0) {
  290. tmp1 = atan2( (in->cb - in->ca), tmp0 );
  291. out[0] = mod2pi(tmp1 - in->alpha);
  292. out[1] = sqrt(p_sq);
  293. out[2] = mod2pi(in->beta - tmp1);
  294. return EDUBOK;
  295. }
  296. return EDUBNOPATH;
  297. }
  298. int dubins_RSR(DubinsIntermediateResults* in, double out[3])
  299. {
  300. double tmp0 = in->d - in->sa + in->sb;
  301. double p_sq = 2 + in->d_sq - (2 * in->c_ab) + (2 * in->d * (in->sb - in->sa));
  302. if( p_sq >= 0 ) {
  303. double tmp1 = atan2( (in->ca - in->cb), tmp0 );
  304. out[0] = mod2pi(in->alpha - tmp1);
  305. out[1] = sqrt(p_sq);
  306. out[2] = mod2pi(tmp1 -in->beta);
  307. return EDUBOK;
  308. }
  309. return EDUBNOPATH;
  310. }
  311. int dubins_LSR(DubinsIntermediateResults* in, double out[3])
  312. {
  313. double p_sq = -2 + (in->d_sq) + (2 * in->c_ab) + (2 * in->d * (in->sa + in->sb));
  314. if( p_sq >= 0 ) {
  315. double p = sqrt(p_sq);
  316. double tmp0 = atan2( (-in->ca - in->cb), (in->d + in->sa + in->sb) ) - atan2(-2.0, p);
  317. out[0] = mod2pi(tmp0 - in->alpha);
  318. out[1] = p;
  319. out[2] = mod2pi(tmp0 - mod2pi(in->beta));
  320. return EDUBOK;
  321. }
  322. return EDUBNOPATH;
  323. }
  324. int dubins_RSL(DubinsIntermediateResults* in, double out[3])
  325. {
  326. double p_sq = -2 + in->d_sq + (2 * in->c_ab) - (2 * in->d * (in->sa + in->sb));
  327. if( p_sq >= 0 ) {
  328. double p = sqrt(p_sq);
  329. double tmp0 = atan2( (in->ca + in->cb), (in->d - in->sa - in->sb) ) - atan2(2.0, p);
  330. out[0] = mod2pi(in->alpha - tmp0);
  331. out[1] = p;
  332. out[2] = mod2pi(in->beta - tmp0);
  333. return EDUBOK;
  334. }
  335. return EDUBNOPATH;
  336. }
  337. int dubins_RLR(DubinsIntermediateResults* in, double out[3])
  338. {
  339. double tmp0 = (6. - in->d_sq + 2*in->c_ab + 2*in->d*(in->sa - in->sb)) / 8.;
  340. double phi = atan2( in->ca - in->cb, in->d - in->sa + in->sb );
  341. if( fabs(tmp0) <= 1) {
  342. double p = mod2pi((2*M_PI) - acos(tmp0) );
  343. double t = mod2pi(in->alpha - phi + mod2pi(p/2.));
  344. out[0] = t;
  345. out[1] = p;
  346. out[2] = mod2pi(in->alpha - in->beta - t + mod2pi(p));
  347. return EDUBOK;
  348. }
  349. return EDUBNOPATH;
  350. }
  351. int dubins_LRL(DubinsIntermediateResults* in, double out[3])
  352. {
  353. double tmp0 = (6. - in->d_sq + 2*in->c_ab + 2*in->d*(in->sb - in->sa)) / 8.;
  354. double phi = atan2( in->ca - in->cb, in->d + in->sa - in->sb );
  355. if( fabs(tmp0) <= 1) {
  356. double p = mod2pi( 2*M_PI - acos( tmp0) );
  357. double t = mod2pi(-in->alpha - phi + p/2.);
  358. out[0] = t;
  359. out[1] = p;
  360. out[2] = mod2pi(mod2pi(in->beta) - in->alpha -t + mod2pi(p));
  361. return EDUBOK;
  362. }
  363. return EDUBNOPATH;
  364. }
  365. int dubins_word(DubinsIntermediateResults* in, DubinsPathType pathType, double out[3])
  366. {
  367. int result;
  368. switch(pathType)
  369. {
  370. case LSL:
  371. result = dubins_LSL(in, out);
  372. break;
  373. case RSL:
  374. result = dubins_RSL(in, out);
  375. break;
  376. case LSR:
  377. result = dubins_LSR(in, out);
  378. break;
  379. case RSR:
  380. result = dubins_RSR(in, out);
  381. break;
  382. case LRL:
  383. result = dubins_LRL(in, out);
  384. break;
  385. case RLR:
  386. result = dubins_RLR(in, out);
  387. break;
  388. default:
  389. result = EDUBNOPATH;
  390. }
  391. return result;
  392. }