22 import matplotlib.pylab
as plt
23 from nav2_msgs.action
import ComputePathToPose, SmoothPath
27 from numpy.typing
import NDArray
29 from tabulate
import tabulate
32 def getPaths(results: list[ComputePathToPose.Result | SmoothPath.Result]) -> list[Path]:
34 for i
in range(len(results)):
37 paths.append(results[i].path)
40 for result
in results[i]:
41 paths.append(result.path)
45 def getTimes(results: list[ComputePathToPose.Result | SmoothPath.Result]) -> list[float]:
47 for i
in range(len(results)):
51 results[i].planning_time.nanosec / 1e09 + results[i].planning_time.sec
55 for result
in results[i]:
57 result.smoothing_duration.nanosec / 1e09
58 + result.smoothing_duration.sec
63 def getMapCoordsFromPaths(paths: list[Path], resolution: float) -> list[list[float]]:
68 for pose
in path.poses:
69 x.append(pose.pose.position.x / resolution)
70 y.append(pose.pose.position.y / resolution)
76 def getPathLength(path: Path) -> float:
78 x_prev = path.poses[0].pose.position.x
79 y_prev = path.poses[0].pose.position.y
80 for i
in range(1, len(path.poses)):
81 x_curr = path.poses[i].pose.position.x
82 y_curr = path.poses[i].pose.position.y
83 path_length = path_length + math.sqrt(
84 (x_curr - x_prev) ** 2 + (y_curr - y_prev) ** 2
93 pt_prev: NDArray[np.float64], pt: NDArray[np.float64],
94 pt_next: NDArray[np.float64]) -> float:
98 return float(np.linalg.norm(delta))
101 def getPathSmoothnesses(paths: list[Path]) -> list[float]:
103 pm0 = np.array([0.0, 0.0])
104 pm1 = np.array([0.0, 0.0])
105 pm2 = np.array([0.0, 0.0])
108 for i
in range(2, len(path.poses)):
109 pm0[0] = path.poses[i].pose.position.x
110 pm0[1] = path.poses[i].pose.position.y
111 pm1[0] = path.poses[i - 1].pose.position.x
112 pm1[1] = path.poses[i - 1].pose.position.y
113 pm2[0] = path.poses[i - 2].pose.position.x
114 pm2[1] = path.poses[i - 2].pose.position.y
115 smoothness += getSmoothness(pm2, pm1, pm0)
116 smoothnesses.append(smoothness)
121 def arcCenter(pt_prev: NDArray[np.float64], pt: NDArray[np.float64],
122 pt_next: NDArray[np.float64]) -> NDArray[np.float64]:
128 d1_norm = d1 / np.linalg.norm(d1)
129 d2_norm = d2 / np.linalg.norm(d2)
130 cos_angle = np.dot(d1_norm, d2_norm)
132 if cos_angle < cusp_thresh:
137 det = d1[0] * d2[1] - d1[1] * d2[0]
139 return np.array([float(
'inf'), float(
'inf')])
145 mid1 = (pt_prev + pt) / 2
146 mid2 = (pt + pt_next) / 2
149 det1 = (mid1[0] + n1[0]) * mid1[1] - (mid1[1] + n1[1]) * mid1[0]
150 det2 = (mid2[0] + n2[0]) * mid2[1] - (mid2[1] + n2[1]) * mid2[0]
152 [(det1 * n2[0] - det2 * n1[0]) / det, (det1 * n2[1] - det2 * n1[1]) / det]
157 def getPathCurvatures(paths: list[Path]) -> list[float]:
159 pm0 = np.array([0.0, 0.0])
160 pm1 = np.array([0.0, 0.0])
161 pm2 = np.array([0.0, 0.0])
164 for i
in range(2, len(path.poses)):
165 pm0[0] = path.poses[i].pose.position.x
166 pm0[1] = path.poses[i].pose.position.y
167 pm1[0] = path.poses[i - 1].pose.position.x
168 pm1[1] = path.poses[i - 1].pose.position.y
169 pm2[0] = path.poses[i - 2].pose.position.x
170 pm2[1] = path.poses[i - 2].pose.position.y
171 center = arcCenter(pm2, pm1, pm0)
172 if center[0] != float(
'inf'):
173 turning_rad = np.linalg.norm(pm1 - center)
174 radiuses.append(turning_rad)
175 curvatures.append(np.average(radiuses))
179 def plotResults(costmap: Costmap, paths: list[Path]) ->
None:
180 coords = getMapCoordsFromPaths(paths, costmap.metadata.resolution)
181 data = np.asarray(costmap.data)
182 data.resize(costmap.metadata.size_y, costmap.metadata.size_x)
183 data = np.where(data <= 253, 0, data)
186 ax = sns.heatmap(data, cmap=
'Greys', cbar=
False)
187 for i
in range(0, len(coords), 2):
188 ax.plot(coords[i], coords[i + 1], linewidth=0.7)
190 ax.set_aspect(
'equal',
'box')
195 paths: list[Path], costmap: Costmap,
196 num_of_planners: int) -> list[list[float]]:
197 coords = getMapCoordsFromPaths(paths, costmap.metadata.resolution)
198 data = np.asarray(costmap.data)
199 data.resize(costmap.metadata.size_y, costmap.metadata.size_x)
201 average_path_costs: list[list[float]] = []
202 for i
in range(num_of_planners):
203 average_path_costs.append([])
206 for i
in range(0, len(coords), 2):
208 for j
in range(len(coords[i])):
209 costs.append(data[math.floor(coords[i + 1][j])][math.floor(coords[i][j])])
210 average_path_costs[k % num_of_planners].append(sum(costs) / len(costs))
213 return average_path_costs
217 paths: list[Path], costmap: Costmap,
218 num_of_planners: int) -> list[list[float]]:
219 coords = getMapCoordsFromPaths(paths, costmap.metadata.resolution)
220 data = np.asarray(costmap.data)
221 data.resize(costmap.metadata.size_y, costmap.metadata.size_x)
223 max_path_costs: list[list[float]] = []
224 for i
in range(num_of_planners):
225 max_path_costs.append([])
228 for i
in range(0, len(coords), 2):
230 for j
in range(len(coords[i])):
231 cost = data[math.floor(coords[i + 1][j])][math.floor(coords[i][j])]
234 max_path_costs[k % num_of_planners].append(max_cost)
237 return max_path_costs
242 benchmark_dir = os.getcwd()
244 with open(os.path.join(benchmark_dir,
'results.pickle'),
'rb')
as f:
245 results = pickle.load(f)
247 with open(os.path.join(benchmark_dir,
'methods.pickle'),
'rb')
as f:
248 smoothers = pickle.load(f)
249 planner = smoothers[0]
251 methods_num = len(smoothers) + 1
253 with open(os.path.join(benchmark_dir,
'costmap.pickle'),
'rb')
as f:
254 costmap = pickle.load(f)
257 paths = getPaths(results)
258 path_lengths_list = []
261 path_lengths_list.append(getPathLength(path))
262 path_lengths = np.asarray(path_lengths_list)
263 total_paths = len(paths)
266 path_lengths.resize((int(total_paths / methods_num), methods_num))
268 path_lengths = path_lengths.transpose()
271 times = np.asarray(getTimes(results))
272 times.resize((int(total_paths / methods_num), methods_num))
273 times = np.transpose(times)
276 average_path_costs = np.asarray(averagePathCost(paths, costmap, methods_num))
277 max_path_costs = np.asarray(maxPathCost(paths, costmap, methods_num))
280 smoothnesses = np.asarray(getPathSmoothnesses(paths))
281 smoothnesses.resize((int(total_paths / methods_num), methods_num))
282 smoothnesses = np.transpose(smoothnesses)
285 curvatures = np.asarray(getPathCurvatures(paths))
286 curvatures.resize((int(total_paths / methods_num), methods_num))
287 curvatures = np.transpose(curvatures)
297 'Path smoothness (x100)',
298 'Average turning rad (m)',
302 planner_table.append(
305 np.average(times[0]),
306 np.average(path_lengths[0]),
307 np.average(average_path_costs[0]),
308 np.average(max_path_costs[0]),
309 np.average(smoothnesses[0]) * 100,
310 np.average(curvatures[0]),
314 for i
in range(1, methods_num):
315 planner_table.append(
318 np.average(times[i]),
319 np.average(path_lengths[i]),
320 np.average(average_path_costs[i]),
321 np.average(max_path_costs[i]),
322 np.average(smoothnesses[i]) * 100,
323 np.average(curvatures[i]),
328 print(tabulate(planner_table))
329 plotResults(costmap, paths)
334 if __name__ ==
'__main__':