reeds_shepp.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720
  1. import math
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. import draw
  5. # parameters initiation
  6. STEP_SIZE = 0.2
  7. MAX_LENGTH = 1000.0
  8. PI = math.pi
  9. # class for PATH element
  10. class PATH:
  11. def __init__(self, lengths, ctypes, L, x, y, yaw, directions):
  12. self.lengths = lengths # lengths of each part of path (+: forward, -: backward) [float]
  13. self.ctypes = ctypes # type of each part of the path [string]
  14. self.L = L # total path length [float]
  15. self.x = x # final s positions [m]
  16. self.y = y # final y positions [m]
  17. self.yaw = yaw # final yaw angles [rad]
  18. self.directions = directions # forward: 1, backward:-1
  19. def calc_optimal_path(sx, sy, syaw, gx, gy, gyaw, maxc, step_size=STEP_SIZE):
  20. paths = calc_all_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size=step_size)
  21. minL = paths[0].L
  22. mini = 0
  23. for i in range(len(paths)):
  24. if paths[i].L <= minL:
  25. minL, mini = paths[i].L, i
  26. return paths[mini]
  27. def calc_all_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size=STEP_SIZE):
  28. q0 = [sx, sy, syaw]
  29. q1 = [gx, gy, gyaw]
  30. paths = generate_path(q0, q1, maxc)
  31. for path in paths:
  32. x, y, yaw, directions = \
  33. generate_local_course(path.L, path.lengths,
  34. path.ctypes, maxc, step_size * maxc)
  35. # convert global coordinate
  36. path.x = [math.cos(-q0[2]) * ix + math.sin(-q0[2]) * iy + q0[0] for (ix, iy) in zip(x, y)]
  37. path.y = [-math.sin(-q0[2]) * ix + math.cos(-q0[2]) * iy + q0[1] for (ix, iy) in zip(x, y)]
  38. path.yaw = [pi_2_pi(iyaw + q0[2]) for iyaw in yaw]
  39. path.directions = directions
  40. path.lengths = [l / maxc for l in path.lengths]
  41. path.L = path.L / maxc
  42. return paths
  43. def set_path(paths, lengths, ctypes):
  44. path = PATH([], [], 0.0, [], [], [], [])
  45. path.ctypes = ctypes
  46. path.lengths = lengths
  47. # check same path exist
  48. for path_e in paths:
  49. if path_e.ctypes == path.ctypes:
  50. if sum([x - y for x, y in zip(path_e.lengths, path.lengths)]) <= 0.01:
  51. return paths # not insert path
  52. path.L = sum([abs(i) for i in lengths])
  53. if path.L >= MAX_LENGTH:
  54. return paths
  55. assert path.L >= 0.01
  56. paths.append(path)
  57. return paths
  58. def LSL(x, y, phi):
  59. u, t = R(x - math.sin(phi), y - 1.0 + math.cos(phi))
  60. if t >= 0.0:
  61. v = M(phi - t)
  62. if v >= 0.0:
  63. return True, t, u, v
  64. return False, 0.0, 0.0, 0.0
  65. def LSR(x, y, phi):
  66. u1, t1 = R(x + math.sin(phi), y - 1.0 - math.cos(phi))
  67. u1 = u1 ** 2
  68. if u1 >= 4.0:
  69. u = math.sqrt(u1 - 4.0)
  70. theta = math.atan2(2.0, u)
  71. t = M(t1 + theta)
  72. v = M(t - phi)
  73. if t >= 0.0 and v >= 0.0:
  74. return True, t, u, v
  75. return False, 0.0, 0.0, 0.0
  76. def LRL(x, y, phi):
  77. u1, t1 = R(x - math.sin(phi), y - 1.0 + math.cos(phi))
  78. if u1 <= 4.0:
  79. u = -2.0 * math.asin(0.25 * u1)
  80. t = M(t1 + 0.5 * u + PI)
  81. v = M(phi - t + u)
  82. if t >= 0.0 and u <= 0.0:
  83. return True, t, u, v
  84. return False, 0.0, 0.0, 0.0
  85. def SCS(x, y, phi, paths):
  86. flag, t, u, v = SLS(x, y, phi)
  87. if flag:
  88. paths = set_path(paths, [t, u, v], ["S", "L", "S"])
  89. flag, t, u, v = SLS(x, -y, -phi)
  90. if flag:
  91. paths = set_path(paths, [t, u, v], ["S", "R", "S"])
  92. return paths
  93. def SLS(x, y, phi):
  94. phi = M(phi)
  95. if y > 0.0 and 0.0 < phi < PI * 0.99:
  96. xd = -y / math.tan(phi) + x
  97. t = xd - math.tan(phi / 2.0)
  98. u = phi
  99. v = math.sqrt((x - xd) ** 2 + y ** 2) - math.tan(phi / 2.0)
  100. return True, t, u, v
  101. elif y < 0.0 and 0.0 < phi < PI * 0.99:
  102. xd = -y / math.tan(phi) + x
  103. t = xd - math.tan(phi / 2.0)
  104. u = phi
  105. v = -math.sqrt((x - xd) ** 2 + y ** 2) - math.tan(phi / 2.0)
  106. return True, t, u, v
  107. return False, 0.0, 0.0, 0.0
  108. def CSC(x, y, phi, paths):
  109. flag, t, u, v = LSL(x, y, phi)
  110. if flag:
  111. paths = set_path(paths, [t, u, v], ["L", "S", "L"])
  112. flag, t, u, v = LSL(-x, y, -phi)
  113. if flag:
  114. paths = set_path(paths, [-t, -u, -v], ["L", "S", "L"])
  115. flag, t, u, v = LSL(x, -y, -phi)
  116. if flag:
  117. paths = set_path(paths, [t, u, v], ["R", "S", "R"])
  118. flag, t, u, v = LSL(-x, -y, phi)
  119. if flag:
  120. paths = set_path(paths, [-t, -u, -v], ["R", "S", "R"])
  121. flag, t, u, v = LSR(x, y, phi)
  122. if flag:
  123. paths = set_path(paths, [t, u, v], ["L", "S", "R"])
  124. flag, t, u, v = LSR(-x, y, -phi)
  125. if flag:
  126. paths = set_path(paths, [-t, -u, -v], ["L", "S", "R"])
  127. flag, t, u, v = LSR(x, -y, -phi)
  128. if flag:
  129. paths = set_path(paths, [t, u, v], ["R", "S", "L"])
  130. flag, t, u, v = LSR(-x, -y, phi)
  131. if flag:
  132. paths = set_path(paths, [-t, -u, -v], ["R", "S", "L"])
  133. return paths
  134. def CCC(x, y, phi, paths):
  135. flag, t, u, v = LRL(x, y, phi)
  136. if flag:
  137. paths = set_path(paths, [t, u, v], ["L", "R", "L"])
  138. flag, t, u, v = LRL(-x, y, -phi)
  139. if flag:
  140. paths = set_path(paths, [-t, -u, -v], ["L", "R", "L"])
  141. flag, t, u, v = LRL(x, -y, -phi)
  142. if flag:
  143. paths = set_path(paths, [t, u, v], ["R", "L", "R"])
  144. flag, t, u, v = LRL(-x, -y, phi)
  145. if flag:
  146. paths = set_path(paths, [-t, -u, -v], ["R", "L", "R"])
  147. # backwards
  148. xb = x * math.cos(phi) + y * math.sin(phi)
  149. yb = x * math.sin(phi) - y * math.cos(phi)
  150. flag, t, u, v = LRL(xb, yb, phi)
  151. if flag:
  152. paths = set_path(paths, [v, u, t], ["L", "R", "L"])
  153. flag, t, u, v = LRL(-xb, yb, -phi)
  154. if flag:
  155. paths = set_path(paths, [-v, -u, -t], ["L", "R", "L"])
  156. flag, t, u, v = LRL(xb, -yb, -phi)
  157. if flag:
  158. paths = set_path(paths, [v, u, t], ["R", "L", "R"])
  159. flag, t, u, v = LRL(-xb, -yb, phi)
  160. if flag:
  161. paths = set_path(paths, [-v, -u, -t], ["R", "L", "R"])
  162. return paths
  163. def calc_tauOmega(u, v, xi, eta, phi):
  164. delta = M(u - v)
  165. A = math.sin(u) - math.sin(delta)
  166. B = math.cos(u) - math.cos(delta) - 1.0
  167. t1 = math.atan2(eta * A - xi * B, xi * A + eta * B)
  168. t2 = 2.0 * (math.cos(delta) - math.cos(v) - math.cos(u)) + 3.0
  169. if t2 < 0:
  170. tau = M(t1 + PI)
  171. else:
  172. tau = M(t1)
  173. omega = M(tau - u + v - phi)
  174. return tau, omega
  175. def LRLRn(x, y, phi):
  176. xi = x + math.sin(phi)
  177. eta = y - 1.0 - math.cos(phi)
  178. rho = 0.25 * (2.0 + math.sqrt(xi * xi + eta * eta))
  179. if rho <= 1.0:
  180. u = math.acos(rho)
  181. t, v = calc_tauOmega(u, -u, xi, eta, phi)
  182. if t >= 0.0 and v <= 0.0:
  183. return True, t, u, v
  184. return False, 0.0, 0.0, 0.0
  185. def LRLRp(x, y, phi):
  186. xi = x + math.sin(phi)
  187. eta = y - 1.0 - math.cos(phi)
  188. rho = (20.0 - xi * xi - eta * eta) / 16.0
  189. if 0.0 <= rho <= 1.0:
  190. u = -math.acos(rho)
  191. if u >= -0.5 * PI:
  192. t, v = calc_tauOmega(u, u, xi, eta, phi)
  193. if t >= 0.0 and v >= 0.0:
  194. return True, t, u, v
  195. return False, 0.0, 0.0, 0.0
  196. def CCCC(x, y, phi, paths):
  197. flag, t, u, v = LRLRn(x, y, phi)
  198. if flag:
  199. paths = set_path(paths, [t, u, -u, v], ["L", "R", "L", "R"])
  200. flag, t, u, v = LRLRn(-x, y, -phi)
  201. if flag:
  202. paths = set_path(paths, [-t, -u, u, -v], ["L", "R", "L", "R"])
  203. flag, t, u, v = LRLRn(x, -y, -phi)
  204. if flag:
  205. paths = set_path(paths, [t, u, -u, v], ["R", "L", "R", "L"])
  206. flag, t, u, v = LRLRn(-x, -y, phi)
  207. if flag:
  208. paths = set_path(paths, [-t, -u, u, -v], ["R", "L", "R", "L"])
  209. flag, t, u, v = LRLRp(x, y, phi)
  210. if flag:
  211. paths = set_path(paths, [t, u, u, v], ["L", "R", "L", "R"])
  212. flag, t, u, v = LRLRp(-x, y, -phi)
  213. if flag:
  214. paths = set_path(paths, [-t, -u, -u, -v], ["L", "R", "L", "R"])
  215. flag, t, u, v = LRLRp(x, -y, -phi)
  216. if flag:
  217. paths = set_path(paths, [t, u, u, v], ["R", "L", "R", "L"])
  218. flag, t, u, v = LRLRp(-x, -y, phi)
  219. if flag:
  220. paths = set_path(paths, [-t, -u, -u, -v], ["R", "L", "R", "L"])
  221. return paths
  222. def LRSR(x, y, phi):
  223. xi = x + math.sin(phi)
  224. eta = y - 1.0 - math.cos(phi)
  225. rho, theta = R(-eta, xi)
  226. if rho >= 2.0:
  227. t = theta
  228. u = 2.0 - rho
  229. v = M(t + 0.5 * PI - phi)
  230. if t >= 0.0 and u <= 0.0 and v <= 0.0:
  231. return True, t, u, v
  232. return False, 0.0, 0.0, 0.0
  233. def LRSL(x, y, phi):
  234. xi = x - math.sin(phi)
  235. eta = y - 1.0 + math.cos(phi)
  236. rho, theta = R(xi, eta)
  237. if rho >= 2.0:
  238. r = math.sqrt(rho * rho - 4.0)
  239. u = 2.0 - r
  240. t = M(theta + math.atan2(r, -2.0))
  241. v = M(phi - 0.5 * PI - t)
  242. if t >= 0.0 and u <= 0.0 and v <= 0.0:
  243. return True, t, u, v
  244. return False, 0.0, 0.0, 0.0
  245. def CCSC(x, y, phi, paths):
  246. flag, t, u, v = LRSL(x, y, phi)
  247. if flag:
  248. paths = set_path(paths, [t, -0.5 * PI, u, v], ["L", "R", "S", "L"])
  249. flag, t, u, v = LRSL(-x, y, -phi)
  250. if flag:
  251. paths = set_path(paths, [-t, 0.5 * PI, -u, -v], ["L", "R", "S", "L"])
  252. flag, t, u, v = LRSL(x, -y, -phi)
  253. if flag:
  254. paths = set_path(paths, [t, -0.5 * PI, u, v], ["R", "L", "S", "R"])
  255. flag, t, u, v = LRSL(-x, -y, phi)
  256. if flag:
  257. paths = set_path(paths, [-t, 0.5 * PI, -u, -v], ["R", "L", "S", "R"])
  258. flag, t, u, v = LRSR(x, y, phi)
  259. if flag:
  260. paths = set_path(paths, [t, -0.5 * PI, u, v], ["L", "R", "S", "R"])
  261. flag, t, u, v = LRSR(-x, y, -phi)
  262. if flag:
  263. paths = set_path(paths, [-t, 0.5 * PI, -u, -v], ["L", "R", "S", "R"])
  264. flag, t, u, v = LRSR(x, -y, -phi)
  265. if flag:
  266. paths = set_path(paths, [t, -0.5 * PI, u, v], ["R", "L", "S", "L"])
  267. flag, t, u, v = LRSR(-x, -y, phi)
  268. if flag:
  269. paths = set_path(paths, [-t, 0.5 * PI, -u, -v], ["R", "L", "S", "L"])
  270. # backwards
  271. xb = x * math.cos(phi) + y * math.sin(phi)
  272. yb = x * math.sin(phi) - y * math.cos(phi)
  273. flag, t, u, v = LRSL(xb, yb, phi)
  274. if flag:
  275. paths = set_path(paths, [v, u, -0.5 * PI, t], ["L", "S", "R", "L"])
  276. flag, t, u, v = LRSL(-xb, yb, -phi)
  277. if flag:
  278. paths = set_path(paths, [-v, -u, 0.5 * PI, -t], ["L", "S", "R", "L"])
  279. flag, t, u, v = LRSL(xb, -yb, -phi)
  280. if flag:
  281. paths = set_path(paths, [v, u, -0.5 * PI, t], ["R", "S", "L", "R"])
  282. flag, t, u, v = LRSL(-xb, -yb, phi)
  283. if flag:
  284. paths = set_path(paths, [-v, -u, 0.5 * PI, -t], ["R", "S", "L", "R"])
  285. flag, t, u, v = LRSR(xb, yb, phi)
  286. if flag:
  287. paths = set_path(paths, [v, u, -0.5 * PI, t], ["R", "S", "R", "L"])
  288. flag, t, u, v = LRSR(-xb, yb, -phi)
  289. if flag:
  290. paths = set_path(paths, [-v, -u, 0.5 * PI, -t], ["R", "S", "R", "L"])
  291. flag, t, u, v = LRSR(xb, -yb, -phi)
  292. if flag:
  293. paths = set_path(paths, [v, u, -0.5 * PI, t], ["L", "S", "L", "R"])
  294. flag, t, u, v = LRSR(-xb, -yb, phi)
  295. if flag:
  296. paths = set_path(paths, [-v, -u, 0.5 * PI, -t], ["L", "S", "L", "R"])
  297. return paths
  298. def LRSLR(x, y, phi):
  299. # formula 8.11 *** TYPO IN PAPER ***
  300. xi = x + math.sin(phi)
  301. eta = y - 1.0 - math.cos(phi)
  302. rho, theta = R(xi, eta)
  303. if rho >= 2.0:
  304. u = 4.0 - math.sqrt(rho * rho - 4.0)
  305. if u <= 0.0:
  306. t = M(math.atan2((4.0 - u) * xi - 2.0 * eta, -2.0 * xi + (u - 4.0) * eta))
  307. v = M(t - phi)
  308. if t >= 0.0 and v >= 0.0:
  309. return True, t, u, v
  310. return False, 0.0, 0.0, 0.0
  311. def CCSCC(x, y, phi, paths):
  312. flag, t, u, v = LRSLR(x, y, phi)
  313. if flag:
  314. paths = set_path(paths, [t, -0.5 * PI, u, -0.5 * PI, v], ["L", "R", "S", "L", "R"])
  315. flag, t, u, v = LRSLR(-x, y, -phi)
  316. if flag:
  317. paths = set_path(paths, [-t, 0.5 * PI, -u, 0.5 * PI, -v], ["L", "R", "S", "L", "R"])
  318. flag, t, u, v = LRSLR(x, -y, -phi)
  319. if flag:
  320. paths = set_path(paths, [t, -0.5 * PI, u, -0.5 * PI, v], ["R", "L", "S", "R", "L"])
  321. flag, t, u, v = LRSLR(-x, -y, phi)
  322. if flag:
  323. paths = set_path(paths, [-t, 0.5 * PI, -u, 0.5 * PI, -v], ["R", "L", "S", "R", "L"])
  324. return paths
  325. def generate_local_course(L, lengths, mode, maxc, step_size):
  326. point_num = int(L / step_size) + len(lengths) + 3
  327. px = [0.0 for _ in range(point_num)]
  328. py = [0.0 for _ in range(point_num)]
  329. pyaw = [0.0 for _ in range(point_num)]
  330. directions = [0 for _ in range(point_num)]
  331. ind = 1
  332. if lengths[0] > 0.0:
  333. directions[0] = 1
  334. else:
  335. directions[0] = -1
  336. if lengths[0] > 0.0:
  337. d = step_size
  338. else:
  339. d = -step_size
  340. pd = d
  341. ll = 0.0
  342. for m, l, i in zip(mode, lengths, range(len(mode))):
  343. if l > 0.0:
  344. d = step_size
  345. else:
  346. d = -step_size
  347. ox, oy, oyaw = px[ind], py[ind], pyaw[ind]
  348. ind -= 1
  349. if i >= 1 and (lengths[i - 1] * lengths[i]) > 0:
  350. pd = -d - ll
  351. else:
  352. pd = d - ll
  353. while abs(pd) <= abs(l):
  354. ind += 1
  355. px, py, pyaw, directions = \
  356. interpolate(ind, pd, m, maxc, ox, oy, oyaw, px, py, pyaw, directions)
  357. pd += d
  358. ll = l - pd - d # calc remain length
  359. ind += 1
  360. px, py, pyaw, directions = \
  361. interpolate(ind, l, m, maxc, ox, oy, oyaw, px, py, pyaw, directions)
  362. # remove unused data
  363. while px[-1] == 0.0:
  364. px.pop()
  365. py.pop()
  366. pyaw.pop()
  367. directions.pop()
  368. return px, py, pyaw, directions
  369. def interpolate(ind, l, m, maxc, ox, oy, oyaw, px, py, pyaw, directions):
  370. if m == "S":
  371. px[ind] = ox + l / maxc * math.cos(oyaw)
  372. py[ind] = oy + l / maxc * math.sin(oyaw)
  373. pyaw[ind] = oyaw
  374. else:
  375. ldx = math.sin(l) / maxc
  376. if m == "L":
  377. ldy = (1.0 - math.cos(l)) / maxc
  378. elif m == "R":
  379. ldy = (1.0 - math.cos(l)) / (-maxc)
  380. gdx = math.cos(-oyaw) * ldx + math.sin(-oyaw) * ldy
  381. gdy = -math.sin(-oyaw) * ldx + math.cos(-oyaw) * ldy
  382. px[ind] = ox + gdx
  383. py[ind] = oy + gdy
  384. if m == "L":
  385. pyaw[ind] = oyaw + l
  386. elif m == "R":
  387. pyaw[ind] = oyaw - l
  388. if l > 0.0:
  389. directions[ind] = 1
  390. else:
  391. directions[ind] = -1
  392. return px, py, pyaw, directions
  393. def generate_path(q0, q1, maxc):
  394. dx = q1[0] - q0[0]
  395. dy = q1[1] - q0[1]
  396. dth = q1[2] - q0[2]
  397. c = math.cos(q0[2])
  398. s = math.sin(q0[2])
  399. x = (c * dx + s * dy) * maxc
  400. y = (-s * dx + c * dy) * maxc
  401. paths = []
  402. paths = SCS(x, y, dth, paths)
  403. paths = CSC(x, y, dth, paths)
  404. paths = CCC(x, y, dth, paths)
  405. paths = CCCC(x, y, dth, paths)
  406. paths = CCSC(x, y, dth, paths)
  407. paths = CCSCC(x, y, dth, paths)
  408. return paths
  409. # utils
  410. def pi_2_pi(theta):
  411. while theta > PI:
  412. theta -= 2.0 * PI
  413. while theta < -PI:
  414. theta += 2.0 * PI
  415. return theta
  416. def R(x, y):
  417. """
  418. Return the polar coordinates (r, theta) of the point (s, y)
  419. """
  420. r = math.hypot(x, y)
  421. theta = math.atan2(y, x)
  422. return r, theta
  423. def M(theta):
  424. """
  425. Regulate theta to -pi <= theta < pi
  426. """
  427. phi = theta % (2.0 * PI)
  428. if phi < -PI:
  429. phi += 2.0 * PI
  430. if phi > PI:
  431. phi -= 2.0 * PI
  432. return phi
  433. def get_label(path):
  434. label = ""
  435. for m, l in zip(path.ctypes, path.lengths):
  436. label = label + m
  437. if l > 0.0:
  438. label = label + "+"
  439. else:
  440. label = label + "-"
  441. return label
  442. def calc_curvature(x, y, yaw, directions):
  443. c, ds = [], []
  444. for i in range(1, len(x) - 1):
  445. dxn = x[i] - x[i - 1]
  446. dxp = x[i + 1] - x[i]
  447. dyn = y[i] - y[i - 1]
  448. dyp = y[i + 1] - y[i]
  449. dn = math.hypot(dxn, dyn)
  450. dp = math.hypot(dxp, dyp)
  451. dx = 1.0 / (dn + dp) * (dp / dn * dxn + dn / dp * dxp)
  452. ddx = 2.0 / (dn + dp) * (dxp / dp - dxn / dn)
  453. dy = 1.0 / (dn + dp) * (dp / dn * dyn + dn / dp * dyp)
  454. ddy = 2.0 / (dn + dp) * (dyp / dp - dyn / dn)
  455. curvature = (ddy * dx - ddx * dy) / (dx ** 2 + dy ** 2)
  456. d = (dn + dp) / 2.0
  457. if np.isnan(curvature):
  458. curvature = 0.0
  459. if directions[i] <= 0.0:
  460. curvature = -curvature
  461. if len(c) == 0:
  462. ds.append(d)
  463. c.append(curvature)
  464. ds.append(d)
  465. c.append(curvature)
  466. ds.append(ds[-1])
  467. c.append(c[-1])
  468. return c, ds
  469. def check_path(sx, sy, syaw, gx, gy, gyaw, maxc):
  470. paths = calc_all_paths(sx, sy, syaw, gx, gy, gyaw, maxc)
  471. assert len(paths) >= 1
  472. for path in paths:
  473. assert abs(path.x[0] - sx) <= 0.01
  474. assert abs(path.y[0] - sy) <= 0.01
  475. assert abs(path.yaw[0] - syaw) <= 0.01
  476. assert abs(path.x[-1] - gx) <= 0.01
  477. assert abs(path.y[-1] - gy) <= 0.01
  478. assert abs(path.yaw[-1] - gyaw) <= 0.01
  479. # course distance check
  480. d = [math.hypot(dx, dy)
  481. for dx, dy in zip(np.diff(path.x[0:len(path.x) - 1]),
  482. np.diff(path.y[0:len(path.y) - 1]))]
  483. for i in range(len(d)):
  484. assert abs(d[i] - STEP_SIZE) <= 0.001
  485. def main():
  486. # choose states pairs: (s, y, yaw)
  487. # simulation-1
  488. # states = [(0, 0, 0), (10, 10, -90), (20, 5, 60), (30, 10, 120),
  489. # (35, -5, 30), (25, -10, -120), (15, -15, 100), (0, -10, -90)]
  490. # simulation-2
  491. states = [(-3, 3, 120), (10, -7, 30), (10, 13, 30), (20, 5, -25),
  492. (35, 10, 180), (32, -10, 180), (5, -12, 90)]
  493. max_c = 0.1 # max curvature
  494. path_x, path_y, yaw = [], [], []
  495. for i in range(len(states) - 1):
  496. s_x = states[i][0]
  497. s_y = states[i][1]
  498. s_yaw = np.deg2rad(states[i][2])
  499. g_x = states[i + 1][0]
  500. g_y = states[i + 1][1]
  501. g_yaw = np.deg2rad(states[i + 1][2])
  502. path_i = calc_optimal_path(s_x, s_y, s_yaw,
  503. g_x, g_y, g_yaw, max_c)
  504. path_x += path_i.x
  505. path_y += path_i.y
  506. yaw += path_i.yaw
  507. # animation
  508. plt.ion()
  509. plt.figure(1)
  510. for i in range(len(path_x)):
  511. plt.clf()
  512. plt.plot(path_x, path_y, linewidth=1, color='gray')
  513. for x, y, theta in states:
  514. draw.Arrow(x, y, np.deg2rad(theta), 2, 'blueviolet')
  515. draw.Car(path_x[i], path_y[i], yaw[i], 1.5, 3)
  516. plt.axis("equal")
  517. plt.title("Simulation of Reeds-Shepp Curves")
  518. plt.axis([-10, 42, -20, 20])
  519. plt.draw()
  520. plt.pause(0.001)
  521. plt.pause(1)
  522. if __name__ == '__main__':
  523. main()