|
10 | 10 | from GEMstack.state.physical_object import PhysicalObject, ObjectPose, ObjectFrameEnum |
11 | 11 | from GEMstack.mathutils.dynamics import IntegratorControlSpace |
12 | 12 | import GEMstack.mathutils.collisions as collisions |
| 13 | +from reeds_shepp_path import path_length |
13 | 14 |
|
14 | 15 | import matplotlib.pyplot as plt |
15 | 16 | import numpy as np |
@@ -90,19 +91,57 @@ def __init__(self, obstacles): |
90 | 91 | self.actions = [(1,-2), (1, -1), (1, -0.5), (1,0), (1,0.5), (1, 1), |
91 | 92 | (1,2), (0,0), (-1, -0.25), (-1,0), (-1, 0.25)] |
92 | 93 |
|
| 94 | + # Add Reeds-Shepp parameters |
| 95 | + self.turning_radius = 1.0 # Adjust based on your vehicle |
| 96 | + self.velocity_penalty_weight = 0.1 # Adjust to balance path length vs velocity changes |
| 97 | + |
93 | 98 | def is_goal_reached(self, current, goal): |
94 | 99 | # @TODO Currently, the threshold is just a random number, get rid of magic constants |
95 | 100 |
|
96 | 101 | if current[3] > 0.5: return False # car must be stopped, this equality will only work in simulation |
97 | 102 | return np.linalg.norm(np.array(current[:2]) - np.array(goal[:2])) < .5 |
98 | 103 |
|
99 | 104 | def heuristic_cost_estimate(self, n1, n2): |
100 | | - # @TODO Consider creating a more sophisticated heuristic |
101 | | - """computes the 'direct' distance between two (x,y) tuples""" |
| 105 | + """ |
| 106 | + Computes the Reeds-Shepp path length between two configurations as the heuristic cost |
| 107 | + """ |
| 108 | + # Extract position and orientation from states |
102 | 109 | (x1, y1, theta1, v1, dtheta1) = n1 |
103 | 110 | (x2, y2, theta2, v2, dtheta2) = n2 |
104 | | - return math.hypot(x2 - x1, y2 - y1, 2*(v2-v1)) |
105 | | - #return math.hypot(x2 - x1, y2 - y1, theta2 - theta1, v2-v1, dtheta2-dtheta1) |
| 111 | + |
| 112 | + # Create start and goal configurations for Reeds-Shepp |
| 113 | + start = (x1, y1, theta1) |
| 114 | + goal = (x2, y2, theta2) |
| 115 | + |
| 116 | + # Calculate Reeds-Shepp path length |
| 117 | + path_length_cost = path_length(start, goal, self.turning_radius) |
| 118 | + |
| 119 | + # Add a small penalty for velocity difference to encourage smooth transitions |
| 120 | + velocity_penalty = abs(v2 - v1) * self.velocity_penalty_weight |
| 121 | + |
| 122 | + return path_length_cost + velocity_penalty |
| 123 | + |
| 124 | + def terminal_cost_estimate(self, current, goal): |
| 125 | + """ |
| 126 | + Computes the terminal cost estimate between current state and goal state. |
| 127 | + This is used to determine how close we are to the goal configuration. |
| 128 | + """ |
| 129 | + # Extract position and orientation from states |
| 130 | + (x1, y1, theta1, v1, dtheta1) = current |
| 131 | + (x2, y2, theta2, v2, dtheta2) = goal |
| 132 | + |
| 133 | + # Create start and goal configurations for Reeds-Shepp |
| 134 | + start = (x1, y1, theta1) |
| 135 | + goal_config = (x2, y2, theta2) |
| 136 | + |
| 137 | + # Calculate Reeds-Shepp path length |
| 138 | + path_length_cost = path_length(start, goal_config, self.turning_radius) |
| 139 | + |
| 140 | + # Add penalties for velocity and angular velocity differences |
| 141 | + velocity_penalty = abs(v2 - v1) * self.velocity_penalty_weight |
| 142 | + angular_velocity_penalty = abs(dtheta2 - dtheta1) * 0.1 |
| 143 | + |
| 144 | + return path_length_cost + velocity_penalty + angular_velocity_penalty |
106 | 145 |
|
107 | 146 | def distance_between(self, n1, n2): |
108 | 147 | """this method always returns 1, as two 'neighbors' are always adajcent""" |
@@ -153,15 +192,15 @@ def solve(): |
153 | 192 | # generate obstacle |
154 | 193 | # obstacles = gen_obstacle(1) |
155 | 194 | pose = ObjectPose(frame=ObjectFrameEnum(3), |
156 | | - t=0, x = 8, y=5) |
| 195 | + t=0, x = 2, y=5) |
157 | 196 | pose2 = ObjectPose(frame=ObjectFrameEnum(3), |
158 | | - t=0, x = 8, y=0) |
| 197 | + t=0, x = 8, y=5) |
159 | 198 | dimensions = (1.5,2.5,1) |
160 | 199 | obstacles = [PhysicalObject(pose, dimensions, None), PhysicalObject(pose2, dimensions, None)] |
161 | 200 | # obstacles = [PhysicalObject(pose, dimensions, None)] |
162 | 201 | # obstacles = [] |
163 | 202 | start = (0, 0, 0, 0, 0) # we choose to start at the upper left corner |
164 | | - goal = (8, 3, 0, 0, 0) # we want to reach the lower right corner |
| 203 | + goal = (5, 5, 0, 0, 0) # we want to reach the lower right corner |
165 | 204 |
|
166 | 205 | # let's solve it |
167 | 206 | foundPath = list(ParkingSolverSecondOrderDubins(obstacles).astar(start, goal)) |
|
0 commit comments