python-motion-planning 0.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. python_motion_planning/__init__.py +4 -0
  2. python_motion_planning/curve_generation/__init__.py +9 -0
  3. python_motion_planning/curve_generation/bezier_curve.py +131 -0
  4. python_motion_planning/curve_generation/bspline_curve.py +271 -0
  5. python_motion_planning/curve_generation/cubic_spline.py +128 -0
  6. python_motion_planning/curve_generation/curve.py +64 -0
  7. python_motion_planning/curve_generation/dubins_curve.py +348 -0
  8. python_motion_planning/curve_generation/fem_pos_smooth.py +114 -0
  9. python_motion_planning/curve_generation/polynomial_curve.py +226 -0
  10. python_motion_planning/curve_generation/reeds_shepp.py +736 -0
  11. python_motion_planning/global_planner/__init__.py +3 -0
  12. python_motion_planning/global_planner/evolutionary_search/__init__.py +4 -0
  13. python_motion_planning/global_planner/evolutionary_search/aco.py +186 -0
  14. python_motion_planning/global_planner/evolutionary_search/evolutionary_search.py +87 -0
  15. python_motion_planning/global_planner/evolutionary_search/pso.py +356 -0
  16. python_motion_planning/global_planner/graph_search/__init__.py +28 -0
  17. python_motion_planning/global_planner/graph_search/a_star.py +124 -0
  18. python_motion_planning/global_planner/graph_search/d_star.py +291 -0
  19. python_motion_planning/global_planner/graph_search/d_star_lite.py +188 -0
  20. python_motion_planning/global_planner/graph_search/dijkstra.py +77 -0
  21. python_motion_planning/global_planner/graph_search/gbfs.py +78 -0
  22. python_motion_planning/global_planner/graph_search/graph_search.py +87 -0
  23. python_motion_planning/global_planner/graph_search/jps.py +165 -0
  24. python_motion_planning/global_planner/graph_search/lazy_theta_star.py +114 -0
  25. python_motion_planning/global_planner/graph_search/lpa_star.py +230 -0
  26. python_motion_planning/global_planner/graph_search/s_theta_star.py +133 -0
  27. python_motion_planning/global_planner/graph_search/theta_star.py +171 -0
  28. python_motion_planning/global_planner/graph_search/voronoi.py +200 -0
  29. python_motion_planning/global_planner/sample_search/__init__.py +6 -0
  30. python_motion_planning/global_planner/sample_search/informed_rrt.py +152 -0
  31. python_motion_planning/global_planner/sample_search/rrt.py +151 -0
  32. python_motion_planning/global_planner/sample_search/rrt_connect.py +147 -0
  33. python_motion_planning/global_planner/sample_search/rrt_star.py +77 -0
  34. python_motion_planning/global_planner/sample_search/sample_search.py +135 -0
  35. python_motion_planning/local_planner/__init__.py +19 -0
  36. python_motion_planning/local_planner/apf.py +144 -0
  37. python_motion_planning/local_planner/ddpg.py +630 -0
  38. python_motion_planning/local_planner/dqn.py +687 -0
  39. python_motion_planning/local_planner/dwa.py +212 -0
  40. python_motion_planning/local_planner/local_planner.py +262 -0
  41. python_motion_planning/local_planner/lqr.py +146 -0
  42. python_motion_planning/local_planner/mpc.py +214 -0
  43. python_motion_planning/local_planner/pid.py +158 -0
  44. python_motion_planning/local_planner/rpp.py +147 -0
  45. python_motion_planning/utils/__init__.py +19 -0
  46. python_motion_planning/utils/agent/__init__.py +0 -0
  47. python_motion_planning/utils/agent/agent.py +135 -0
  48. python_motion_planning/utils/environment/__init__.py +0 -0
  49. python_motion_planning/utils/environment/env.py +134 -0
  50. python_motion_planning/utils/environment/node.py +85 -0
  51. python_motion_planning/utils/environment/point2d.py +96 -0
  52. python_motion_planning/utils/environment/pose2d.py +91 -0
  53. python_motion_planning/utils/helper/__init__.py +3 -0
  54. python_motion_planning/utils/helper/math_helper.py +65 -0
  55. python_motion_planning/utils/planner/__init__.py +0 -0
  56. python_motion_planning/utils/planner/control_factory.py +31 -0
  57. python_motion_planning/utils/planner/curve_factory.py +29 -0
  58. python_motion_planning/utils/planner/planner.py +40 -0
  59. python_motion_planning/utils/planner/search_factory.py +51 -0
  60. python_motion_planning/utils/plot/__init__.py +0 -0
  61. python_motion_planning/utils/plot/plot.py +274 -0
  62. python_motion_planning-0.1.dist-info/LICENSE +674 -0
  63. python_motion_planning-0.1.dist-info/METADATA +873 -0
  64. python_motion_planning-0.1.dist-info/RECORD +66 -0
  65. python_motion_planning-0.1.dist-info/WHEEL +5 -0
  66. python_motion_planning-0.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,134 @@
1
+ """
2
+ @file: env.py
3
+ @breif: 2-dimension environment
4
+ @author: Winter
5
+ @update: 2023.1.13
6
+ """
7
+ from math import sqrt
8
+ from abc import ABC, abstractmethod
9
+ from scipy.spatial import cKDTree
10
+ import numpy as np
11
+
12
+ from .node import Node
13
+
14
+ class Env(ABC):
15
+ """
16
+ Class for building 2-d workspace of robots.
17
+
18
+ Parameters:
19
+ x_range (int): x-axis range of enviroment
20
+ y_range (int): y-axis range of environmet
21
+ eps (float): tolerance for float comparison
22
+
23
+ Examples:
24
+ >>> from python_motion_planning.utils import Env
25
+ >>> env = Env(30, 40)
26
+ """
27
+ def __init__(self, x_range: int, y_range: int, eps: float = 1e-6) -> None:
28
+ # size of environment
29
+ self.x_range = x_range
30
+ self.y_range = y_range
31
+ self.eps = eps
32
+
33
+ @property
34
+ def grid_map(self) -> set:
35
+ return {(i, j) for i in range(self.x_range) for j in range(self.y_range)}
36
+
37
+ @abstractmethod
38
+ def init(self) -> None:
39
+ pass
40
+
41
+ class Grid(Env):
42
+ """
43
+ Class for discrete 2-d grid map.
44
+ """
45
+ def __init__(self, x_range: int, y_range: int) -> None:
46
+ super().__init__(x_range, y_range)
47
+ # allowed motions
48
+ self.motions = [Node((-1, 0), None, 1, None), Node((-1, 1), None, sqrt(2), None),
49
+ Node((0, 1), None, 1, None), Node((1, 1), None, sqrt(2), None),
50
+ Node((1, 0), None, 1, None), Node((1, -1), None, sqrt(2), None),
51
+ Node((0, -1), None, 1, None), Node((-1, -1), None, sqrt(2), None)]
52
+ # obstacles
53
+ self.obstacles = None
54
+ self.obstacles_tree = None
55
+ self.init()
56
+
57
+ def init(self) -> None:
58
+ """
59
+ Initialize grid map.
60
+ """
61
+ x, y = self.x_range, self.y_range
62
+ obstacles = set()
63
+
64
+ # boundary of environment
65
+ for i in range(x):
66
+ obstacles.add((i, 0))
67
+ obstacles.add((i, y - 1))
68
+ for i in range(y):
69
+ obstacles.add((0, i))
70
+ obstacles.add((x - 1, i))
71
+
72
+ # user-defined obstacles
73
+ for i in range(10, 21):
74
+ obstacles.add((i, 15))
75
+ for i in range(15):
76
+ obstacles.add((20, i))
77
+ for i in range(15, 30):
78
+ obstacles.add((30, i))
79
+ for i in range(16):
80
+ obstacles.add((40, i))
81
+
82
+ self.obstacles = obstacles
83
+ self.obstacles_tree = cKDTree(np.array(list(obstacles)))
84
+
85
+ def update(self, obstacles):
86
+ self.obstacles = obstacles
87
+ self.obstacles_tree = cKDTree(np.array(list(obstacles)))
88
+
89
+
90
+ class Map(Env):
91
+ """
92
+ Class for continuous 2-d map.
93
+ """
94
+ def __init__(self, x_range: int, y_range: int) -> None:
95
+ super().__init__(x_range, y_range)
96
+ self.boundary = None
97
+ self.obs_circ = None
98
+ self.obs_rect = None
99
+ self.init()
100
+
101
+ def init(self):
102
+ """
103
+ Initialize map.
104
+ """
105
+ x, y = self.x_range, self.y_range
106
+
107
+ # boundary of environment
108
+ self.boundary = [
109
+ [0, 0, 1, y],
110
+ [0, y, x, 1],
111
+ [1, 0, x, 1],
112
+ [x, 1, 1, y]
113
+ ]
114
+
115
+ # user-defined obstacles
116
+ self.obs_rect = [
117
+ [14, 12, 8, 2],
118
+ [18, 22, 8, 3],
119
+ [26, 7, 2, 12],
120
+ [32, 14, 10, 2]
121
+ ]
122
+
123
+ self.obs_circ = [
124
+ [7, 12, 3],
125
+ [46, 20, 2],
126
+ [15, 5, 2],
127
+ [37, 7, 3],
128
+ [37, 23, 3]
129
+ ]
130
+
131
+ def update(self, boundary, obs_circ, obs_rect):
132
+ self.boundary = boundary if boundary else self.boundary
133
+ self.obs_circ = obs_circ if obs_circ else self.obs_circ
134
+ self.obs_rect = obs_rect if obs_rect else self.obs_rect
@@ -0,0 +1,85 @@
1
+ """
2
+ @file: node.py
3
+ @breif: 2-dimension node data stucture
4
+ @author: Yang Haodong, Wu Maojia
5
+ @update: 2024.3.15
6
+ """
7
+
8
+ class Node(object):
9
+ """
10
+ Class for searching nodes.
11
+
12
+ Parameters:
13
+ current (tuple): current coordinate
14
+ parent (tuple): coordinate of parent node
15
+ g (float): path cost
16
+ h (float): heuristic cost
17
+
18
+ Examples:
19
+ >>> from env import Node
20
+ >>> node1 = Node((1, 0), (2, 3), 1, 2)
21
+ >>> node2 = Node((1, 0), (2, 5), 2, 8)
22
+ >>> node3 = Node((2, 0), (1, 6), 3, 1)
23
+ ...
24
+ >>> node1 + node2
25
+ >>> Node((2, 0), (2, 3), 3, 2)
26
+ ...
27
+ >>> node1 == node2
28
+ >>> True
29
+ ...
30
+ >>> node1 != node3
31
+ >>> True
32
+ """
33
+ def __init__(self, current: tuple, parent: tuple = None, g: float = 0, h: float = 0) -> None:
34
+ self.current = current
35
+ self.parent = parent
36
+ self.g = g
37
+ self.h = h
38
+
39
+ def __add__(self, node):
40
+ assert isinstance(node, Node)
41
+ return Node((self.x + node.x, self.y + node.y), self.parent, self.g + node.g, self.h)
42
+
43
+ def __eq__(self, node) -> bool:
44
+ if not isinstance(node, Node):
45
+ return False
46
+ return self.current == node.current
47
+
48
+ def __ne__(self, node) -> bool:
49
+ return not self.__eq__(node)
50
+
51
+ def __lt__(self, node) -> bool:
52
+ assert isinstance(node, Node)
53
+ return self.g + self.h < node.g + node.h or \
54
+ (self.g + self.h == node.g + node.h and self.h < node.h)
55
+
56
+ def __hash__(self) -> int:
57
+ return hash(self.current)
58
+
59
+ def __str__(self) -> str:
60
+ return "Node({}, {}, {}, {})".format(self.current, self.parent, self.g, self.h)
61
+
62
+ def __repr__(self) -> str:
63
+ return self.__str__()
64
+
65
+ @property
66
+ def x(self) -> float:
67
+ return self.current[0]
68
+
69
+ @property
70
+ def y(self) -> float:
71
+ return self.current[1]
72
+
73
+ @property
74
+ def px(self) -> float:
75
+ if self.parent:
76
+ return self.parent[0]
77
+ else:
78
+ return None
79
+
80
+ @property
81
+ def py(self) -> float:
82
+ if self.parent:
83
+ return self.parent[1]
84
+ else:
85
+ return None
@@ -0,0 +1,96 @@
1
+ """
2
+ @file: point2d.py
3
+ @breif: 2-dimension point data stucture
4
+ @author: Wu Maojia
5
+ @update: 2024.3.15
6
+ """
7
+ import math
8
+
9
+
10
+ class Point2D(object):
11
+ """
12
+ Class for searching and manipulating 2-dimensional points.
13
+
14
+ Parameters:
15
+ x: x-coordinate of the 2d point
16
+ y: y-coordinate of the 2d point
17
+ eps: tolerance for float comparison
18
+
19
+ Examples:
20
+ >>> from python_motion_planning import Point2D
21
+ >>> p1 = Point2D(1, 2)
22
+ >>> p2 = Point2D(3, 4)
23
+ ...
24
+ >>> p1
25
+ >>> Point2D(1, 2)
26
+ ...
27
+ >>> p1 + p2
28
+ >>> Point2D(4, 6)
29
+ ...
30
+ >>> p1 - p2
31
+ >>> Point2D(-2, -2)
32
+ ...
33
+ >>> p1 == p2
34
+ >>> False
35
+ ...
36
+ >>> p1!= p2
37
+ >>> True
38
+ ...
39
+ >>> p1.dist(p2)
40
+ >>> 2.8284271247461903
41
+ ...
42
+ >>> p1.angle(p2)
43
+ >>> 0.7853981633974483
44
+ """
45
+
46
+ def __init__(self, x: float, y: float, eps: float = 1e-6) -> None:
47
+ self.x = x
48
+ self.y = y
49
+ self.eps = eps
50
+
51
+ if abs(self.x - round(self.x)) < self.eps:
52
+ self.x = round(self.x)
53
+
54
+ if abs(self.y - round(self.y)) < self.eps:
55
+ self.y = round(self.y)
56
+
57
+ def __add__(self, point):
58
+ assert isinstance(point, Point2D)
59
+ return Point2D(self.x + point.x, self.y + point.y)
60
+
61
+ def __sub__(self, point):
62
+ assert isinstance(point, Point2D)
63
+ return Point2D(self.x - point.x, self.y - point.y)
64
+
65
+ def __eq__(self, point) -> bool:
66
+ if not isinstance(point, Point2D):
67
+ return False
68
+ return abs(self.x - point.x) < self.eps and abs(self.y - point.y) < self.eps
69
+
70
+ def __ne__(self, point) -> bool:
71
+ return not self.__eq__(point)
72
+
73
+ def __hash__(self) -> int:
74
+ return hash((self.x, self.y))
75
+
76
+ def __str__(self) -> str:
77
+ return "Point2D({}, {})".format(self.x, self.y)
78
+
79
+ def __repr__(self) -> str:
80
+ return self.__str__()
81
+
82
+ @staticmethod
83
+ def from_tuple(point: tuple):
84
+ return Point2D(point[0], point[1])
85
+
86
+ @property
87
+ def to_tuple(self) -> tuple:
88
+ return int(self.x), int(self.y)
89
+
90
+ def dist(self, point) -> float:
91
+ assert isinstance(point, Point2D)
92
+ return math.hypot(self.x - point.x, self.y - point.y)
93
+
94
+ def angle(self, point) -> float:
95
+ assert isinstance(point, Point2D)
96
+ return math.atan2(point.y - self.y, point.x - self.x)
@@ -0,0 +1,91 @@
1
+ """
2
+ @file: pose2d.py
3
+ @breif: 2-dimension pose data stucture
4
+ @author: Wu Maojia
5
+ @update: 2024.3.15
6
+ """
7
+ import math
8
+
9
+
10
+ class Pose2D(object):
11
+ """
12
+ Class for searching and manipulating 2-dimensional poses.
13
+
14
+ Parameters:
15
+ x: x-coordinate of the 2d pose
16
+ y: y-coordinate of the 2d pose
17
+ theta: orientation of the 2d pose in radians
18
+ eps: tolerance for float comparison
19
+
20
+ Examples:
21
+ >>> from python_motion_planning import Pose2D
22
+ >>> p1 = Pose2D(1, 2)
23
+ >>> p2 = Pose2D(3, 4, 1)
24
+ ...
25
+ >>> p1
26
+ >>> Pose2D(1, 2, 0)
27
+ ...
28
+ >>> p2
29
+ >>> Pose2D(3, 4, 1)
30
+ ...
31
+ >>> p1 + p2
32
+ >>> Pose2D(4, 6, 1)
33
+ ...
34
+ >>> p1 - p2
35
+ >>> Pose2D(-2, -2, -1)
36
+ ...
37
+ >>> p1 == p2
38
+ >>> False
39
+ ...
40
+ >>> p1!= p2
41
+ >>> True
42
+ """
43
+
44
+ def __init__(self, x: float, y: float, theta: float = 0, eps: float = 1e-6) -> None:
45
+ self.x = x
46
+ self.y = y
47
+ self.theta = theta
48
+ self.eps = eps
49
+
50
+ if abs(self.x - round(self.x)) < self.eps:
51
+ self.x = round(self.x)
52
+
53
+ if abs(self.y - round(self.y)) < self.eps:
54
+ self.y = round(self.y)
55
+
56
+ if abs(self.theta - round(self.theta)) < self.eps:
57
+ self.theta = round(self.theta)
58
+
59
+ def __add__(self, pose):
60
+ assert isinstance(pose, Pose2D)
61
+ return Pose2D(self.x + pose.x, self.y + pose.y, self.theta + pose.theta)
62
+
63
+ def __sub__(self, pose):
64
+ assert isinstance(pose, Pose2D)
65
+ return Pose2D(self.x - pose.x, self.y - pose.y, self.theta - pose.theta)
66
+
67
+ def __eq__(self, pose) -> bool:
68
+ if not isinstance(pose, Pose2D):
69
+ return False
70
+ return (abs(self.x - pose.x) < self.eps and abs(self.y - pose.y) < self.eps
71
+ and abs(self.theta - pose.theta) < self.eps)
72
+
73
+ def __ne__(self, pose) -> bool:
74
+ return not self.__eq__(pose)
75
+
76
+ def __hash__(self) -> int:
77
+ return hash((self.x, self.y, self.theta))
78
+
79
+ def __str__(self) -> str:
80
+ return "Pose2D({}, {}, {})".format(self.x, self.y, self.theta)
81
+
82
+ def __repr__(self) -> str:
83
+ return self.__str__()
84
+
85
+ @staticmethod
86
+ def from_tuple(pose: tuple):
87
+ return Pose2D(pose[0], pose[1], pose[2])
88
+
89
+ @property
90
+ def to_tuple(self) -> tuple:
91
+ return self.x, self.y, self.theta
@@ -0,0 +1,3 @@
1
+ from .math_helper import MathHelper
2
+
3
+ __all__ = ["MathHelper"]
@@ -0,0 +1,65 @@
1
+ """
2
+ @file: math_helper.py
3
+ @breif: Contains common/commonly used math function
4
+ @author: Yang Haodong, Wu Maojia
5
+ @update: 2024.5.20
6
+ """
7
+ import math
8
+
9
+ class MathHelper:
10
+ @staticmethod
11
+ def circleSegmentIntersection(p1: tuple, p2: tuple, r: float) -> list:
12
+ x1, x2 = p1[0], p2[0]
13
+ y1, y2 = p1[1], p2[1]
14
+
15
+ dx, dy = x2 - x1, y2 - y1
16
+ dr2 = dx * dx + dy * dy
17
+ D = x1 * y2 - x2 * y1
18
+
19
+ # the first element is the point within segment
20
+ d1 = x1 * x1 + y1 * y1
21
+ d2 = x2 * x2 + y2 * y2
22
+ dd = d2 - d1
23
+
24
+ delta_2 = r * r * dr2 - D * D
25
+ if delta_2 < 0: # no intersection
26
+ return []
27
+
28
+ delta = math.sqrt(delta_2)
29
+ if (delta == 0):
30
+ return [(D * dy / dr2, -D * dx / dr2)]
31
+ else: # delta > 0
32
+ return [
33
+ ((D * dy + math.copysign(1.0, dd) * dx * delta) / dr2,
34
+ (-D * dx + math.copysign(1.0, dd) * dy * delta) / dr2),
35
+ ((D * dy - math.copysign(1.0, dd) * dx * delta) / dr2,
36
+ (-D * dx - math.copysign(1.0, dd) * dy * delta) / dr2)
37
+ ]
38
+
39
+ @staticmethod
40
+ def closestPointOnLine(a: tuple, b: tuple, p: tuple = (0.0, 0.0)) -> tuple:
41
+ """
42
+ Find the closest intersection point (foot of a perpendicular) between point p and the line ab.
43
+
44
+ Parameters:
45
+ a (tuple): point a of the line
46
+ b (tuple): point b of the line
47
+ p (tuple): point p to find the closest intersection point
48
+
49
+ References:
50
+ [1] method 2 of https://www.youtube.com/watch?v=TPDgB6136ZE
51
+ """
52
+ ap = (p[0] - a[0], p[1] - a[1])
53
+ ab = (b[0] - a[0], b[1] - a[1])
54
+ af_coef = (ap[0] * ab[0] + ap[1] * ab[1]) / (ab[0] ** 2 + ab[1] ** 2)
55
+ af = (af_coef * ab[0], af_coef * ab[1])
56
+ f = (a[0] + af[0], a[1] + af[1])
57
+ return f
58
+
59
+ @staticmethod
60
+ def clamp(val: float, min_val: float, max_val: float) -> float:
61
+ if val < min_val:
62
+ val = min_val
63
+ if val > max_val :
64
+ val = max_val
65
+ return val
File without changes
@@ -0,0 +1,31 @@
1
+ """
2
+ @file: control_factory.py
3
+ @breif: Facotry class for local planner.
4
+ @author: Winter
5
+ @update: 2023.10.24
6
+ """
7
+ from python_motion_planning.local_planner import *
8
+
9
+ class ControlFactory(object):
10
+ def __init__(self) -> None:
11
+ pass
12
+
13
+ def __call__(self, planner_name, **config):
14
+ if planner_name == "dwa":
15
+ return DWA(**config)
16
+ elif planner_name == "pid":
17
+ return PID(**config)
18
+ elif planner_name == "apf":
19
+ return APF(**config)
20
+ elif planner_name == "rpp":
21
+ return RPP(**config)
22
+ elif planner_name == "lqr":
23
+ return LQR(**config)
24
+ elif planner_name == "mpc":
25
+ return MPC(**config)
26
+ elif planner_name == "ddpg":
27
+ return DDPG(actor_load_path="models/actor_best_example.pth",
28
+ critic_load_path="models/critic_best_example.pth",
29
+ **config)
30
+ else:
31
+ raise ValueError("The `planner_name` must be set correctly.")
@@ -0,0 +1,29 @@
1
+ """
2
+ @file: curve_factory.py
3
+ @breif: Facotry class for curve generation.
4
+ @author: Winter
5
+ @update: 2023.7.25
6
+ """
7
+ from python_motion_planning.curve_generation import *
8
+
9
+ class CurveFactory(object):
10
+ def __init__(self) -> None:
11
+ pass
12
+
13
+ def __call__(self, curve_name, **config):
14
+ if curve_name == "dubins":
15
+ return Dubins(**config)
16
+ elif curve_name == "bezier":
17
+ return Bezier(**config)
18
+ elif curve_name == "polynomial":
19
+ return Polynomial(**config)
20
+ elif curve_name == "reeds_shepp":
21
+ return ReedsShepp(**config)
22
+ elif curve_name == "cubic_spline":
23
+ return CubicSpline(**config)
24
+ elif curve_name == "bspline":
25
+ return BSpline(**config)
26
+ elif curve_name == "fem_pos_smoother":
27
+ return FemPosSmoother(**config)
28
+ else:
29
+ raise ValueError("The `curve_name` must be set correctly.")
@@ -0,0 +1,40 @@
1
+ """
2
+ @file: planner.py
3
+ @breif: Abstract class for planner
4
+ @author: Winter
5
+ @update: 2023.1.17
6
+ """
7
+ import math
8
+ from abc import abstractmethod, ABC
9
+ from ..environment.env import Env, Node
10
+ from ..plot.plot import Plot
11
+
12
+ class Planner(ABC):
13
+ def __init__(self, start: tuple, goal: tuple, env: Env) -> None:
14
+ # plannig start and goal
15
+ self.start = Node(start, start, 0, 0)
16
+ self.goal = Node(goal, goal, 0, 0)
17
+ # environment
18
+ self.env = env
19
+ # graph handler
20
+ self.plot = Plot(start, goal, env)
21
+
22
+ def dist(self, node1: Node, node2: Node) -> float:
23
+ return math.hypot(node2.x - node1.x, node2.y - node1.y)
24
+
25
+ def angle(self, node1: Node, node2: Node) -> float:
26
+ return math.atan2(node2.y - node1.y, node2.x - node1.x)
27
+
28
+ @abstractmethod
29
+ def plan(self):
30
+ '''
31
+ Interface for planning.
32
+ '''
33
+ pass
34
+
35
+ @abstractmethod
36
+ def run(self):
37
+ '''
38
+ Interface for running both plannig and animation.
39
+ '''
40
+ pass
@@ -0,0 +1,51 @@
1
+ """
2
+ @file: search_factory.py
3
+ @breif: Factory class for global planner.
4
+ @author: Winter
5
+ @update: 2023.3.2
6
+ """
7
+ from python_motion_planning.global_planner import *
8
+
9
+ class SearchFactory(object):
10
+ def __init__(self) -> None:
11
+ pass
12
+
13
+ def __call__(self, planner_name, **config):
14
+ if planner_name == "a_star":
15
+ return AStar(**config)
16
+ elif planner_name == "dijkstra":
17
+ return Dijkstra(**config)
18
+ elif planner_name == "gbfs":
19
+ return GBFS(**config)
20
+ elif planner_name == "jps":
21
+ return JPS(**config)
22
+ elif planner_name == "d_star":
23
+ return DStar(**config)
24
+ elif planner_name == "lpa_star":
25
+ return LPAStar(**config)
26
+ elif planner_name == "d_star_lite":
27
+ return DStarLite(**config)
28
+ elif planner_name == "voronoi":
29
+ return VoronoiPlanner(**config)
30
+ elif planner_name == "theta_star":
31
+ return ThetaStar(**config)
32
+ elif planner_name == "lazy_theta_star":
33
+ return LazyThetaStar(**config)
34
+ elif planner_name == "s_theta_star":
35
+ return SThetaStar(**config)
36
+ elif planner_name == "anya":
37
+ return Anya(**config)
38
+ elif planner_name == "rrt":
39
+ return RRT(**config)
40
+ elif planner_name == "rrt_connect":
41
+ return RRTConnect(**config)
42
+ elif planner_name == "rrt_star":
43
+ return RRTStar(**config)
44
+ elif planner_name == "informed_rrt":
45
+ return InformedRRT(**config)
46
+ elif planner_name == "aco":
47
+ return ACO(**config)
48
+ elif planner_name == "pso":
49
+ return PSO(**config)
50
+ else:
51
+ raise ValueError("The `planner_name` must be set correctly.")
File without changes