@@ -51,30 +51,93 @@ def get_target_point(path, targetL):
51
51
return [x , y , ti ]
52
52
53
53
54
- def line_collision_check (first , second , obstacleList ):
55
- # Line Equation
56
-
57
- x1 = first [0 ]
58
- y1 = first [1 ]
59
- x2 = second [0 ]
60
- y2 = second [1 ]
61
-
62
- try :
63
- a = y2 - y1
64
- b = - (x2 - x1 )
65
- c = y2 * (x2 - x1 ) - x2 * (y2 - y1 )
66
- except ZeroDivisionError :
67
- return False
68
-
69
- for (ox , oy , size ) in obstacleList :
70
- d = abs (a * ox + b * oy + c ) / (math .hypot (a , b ))
71
- if d <= size :
72
- return False
73
-
74
- return True # OK
75
-
76
-
77
- def path_smoothing (path , max_iter , obstacle_list ):
54
+ def is_point_collision (x , y , obstacle_list , robot_radius ):
55
+ """
56
+ Check whether a single point collides with any obstacle.
57
+
58
+ This function calculates the Euclidean distance between the given point (x, y)
59
+ and each obstacle center. If the distance is less than or equal to the sum of
60
+ the obstacle's radius and the robot's radius, a collision is detected.
61
+
62
+ Args:
63
+ x (float): X-coordinate of the point to check.
64
+ y (float): Y-coordinate of the point to check.
65
+ obstacle_list (List[Tuple[float, float, float]]): List of obstacles defined as (ox, oy, radius).
66
+ robot_radius (float): Radius of the robot, used to inflate the obstacles.
67
+
68
+ Returns:
69
+ bool: True if the point is in collision with any obstacle, False otherwise.
70
+ """
71
+ for (ox , oy , obstacle_radius ) in obstacle_list :
72
+ d = math .hypot (ox - x , oy - y )
73
+ if d <= obstacle_radius + robot_radius :
74
+ return True # Collided
75
+ return False
76
+
77
+
78
+ def line_collision_check (first , second , obstacle_list , robot_radius = 0.0 , sample_step = 0.2 ):
79
+ """
80
+ Check if the line segment between `first` and `second` collides with any obstacle.
81
+ Considers the robot_radius by inflating the obstacle size.
82
+
83
+ Args:
84
+ first (List[float]): Start point of the line [x, y]
85
+ second (List[float]): End point of the line [x, y]
86
+ obstacle_list (List[Tuple[float, float, float]]): Obstacles as (x, y, radius)
87
+ robot_radius (float): Radius of robot
88
+ sample_step (float): Distance between sampling points along the segment
89
+
90
+ Returns:
91
+ bool: True if collision-free, False otherwise
92
+ """
93
+ x1 , y1 = first [0 ], first [1 ]
94
+ x2 , y2 = second [0 ], second [1 ]
95
+
96
+ dx = x2 - x1
97
+ dy = y2 - y1
98
+ length = math .hypot (dx , dy )
99
+
100
+ if length == 0 :
101
+ # Degenerate case: point collision check
102
+ return not is_point_collision (x1 , y1 , obstacle_list , robot_radius )
103
+
104
+ steps = int (length / sample_step ) + 1 # Sampling every sample_step along the segment
105
+
106
+ for i in range (steps + 1 ):
107
+ t = i / steps
108
+ x = x1 + t * dx
109
+ y = y1 + t * dy
110
+
111
+ if is_point_collision (x , y , obstacle_list , robot_radius ):
112
+ return False # Collision found
113
+
114
+ return True # Safe
115
+
116
+
117
+ def path_smoothing (path , max_iter , obstacle_list , robot_radius = 0.0 ):
118
+ """
119
+ Smooths a given path by iteratively replacing segments with shortcut connections,
120
+ while ensuring the new segments are collision-free.
121
+
122
+ The algorithm randomly picks two points along the original path and attempts to
123
+ connect them with a straight line. If the line does not collide with any obstacles
124
+ (considering the robot's radius), the intermediate path points between them are
125
+ replaced with the direct connection.
126
+
127
+ Args:
128
+ path (List[List[float]]): The original path as a list of [x, y] coordinates.
129
+ max_iter (int): Number of iterations for smoothing attempts.
130
+ obstacle_list (List[Tuple[float, float, float]]): List of obstacles represented as
131
+ (x, y, radius).
132
+ robot_radius (float, optional): Radius of the robot, used to inflate obstacle size
133
+ during collision checking. Defaults to 0.0.
134
+
135
+ Returns:
136
+ List[List[float]]: The smoothed path as a list of [x, y] coordinates.
137
+
138
+ Example:
139
+ >>> smoothed = path_smoothing(path, 1000, obstacle_list, robot_radius=0.5)
140
+ """
78
141
le = get_path_length (path )
79
142
80
143
for i in range (max_iter ):
@@ -94,7 +157,7 @@ def path_smoothing(path, max_iter, obstacle_list):
94
157
continue
95
158
96
159
# collision check
97
- if not line_collision_check (first , second , obstacle_list ):
160
+ if not line_collision_check (first , second , obstacle_list , robot_radius ):
98
161
continue
99
162
100
163
# Create New path
@@ -119,14 +182,16 @@ def main():
119
182
(3 , 10 , 2 ),
120
183
(7 , 5 , 2 ),
121
184
(9 , 5 , 2 )
122
- ] # [x,y,size ]
185
+ ] # [x,y,radius ]
123
186
rrt = RRT (start = [0 , 0 ], goal = [6 , 10 ],
124
- rand_area = [- 2 , 15 ], obstacle_list = obstacleList )
187
+ rand_area = [- 2 , 15 ], obstacle_list = obstacleList ,
188
+ robot_radius = 0.3 )
125
189
path = rrt .planning (animation = show_animation )
126
190
127
191
# Path smoothing
128
192
maxIter = 1000
129
- smoothedPath = path_smoothing (path , maxIter , obstacleList )
193
+ smoothedPath = path_smoothing (path , maxIter , obstacleList ,
194
+ robot_radius = rrt .robot_radius )
130
195
131
196
# Draw final path
132
197
if show_animation :
0 commit comments