Skip to content

Commit ac00eaa

Browse files
committed
Change heuristic function to reeds shepp
1 parent df86ee6 commit ac00eaa

2 files changed

Lines changed: 80 additions & 7 deletions

File tree

testing/reeds_shepp_path.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import numpy as np
2+
import math
3+
4+
def path_length(start, goal, turning_radius):
5+
"""
6+
Calculate the length of the Reeds-Shepp path between two configurations.
7+
8+
Args:
9+
start: (x, y, theta) tuple for start configuration
10+
goal: (x, y, theta) tuple for goal configuration
11+
turning_radius: minimum turning radius of the vehicle
12+
13+
Returns:
14+
float: length of the shortest path
15+
"""
16+
x1, y1, theta1 = start
17+
x2, y2, theta2 = goal
18+
19+
# Convert to relative coordinates
20+
dx = x2 - x1
21+
dy = y2 - y1
22+
dtheta = theta2 - theta1
23+
24+
# Calculate Euclidean distance
25+
euclidean_dist = math.sqrt(dx*dx + dy*dy)
26+
27+
# Calculate orientation difference
28+
orientation_diff = abs(dtheta)
29+
30+
# Simple approximation: path length is at least the Euclidean distance
31+
# plus a penalty for orientation changes
32+
path_length = euclidean_dist + turning_radius * orientation_diff
33+
34+
return path_length

testing/test_hybrid_astar.py

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from GEMstack.state.physical_object import PhysicalObject, ObjectPose, ObjectFrameEnum
1111
from GEMstack.mathutils.dynamics import IntegratorControlSpace
1212
import GEMstack.mathutils.collisions as collisions
13+
from reeds_shepp_path import path_length
1314

1415
import matplotlib.pyplot as plt
1516
import numpy as np
@@ -90,19 +91,57 @@ def __init__(self, obstacles):
9091
self.actions = [(1,-2), (1, -1), (1, -0.5), (1,0), (1,0.5), (1, 1),
9192
(1,2), (0,0), (-1, -0.25), (-1,0), (-1, 0.25)]
9293

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+
9398
def is_goal_reached(self, current, goal):
9499
# @TODO Currently, the threshold is just a random number, get rid of magic constants
95100

96101
if current[3] > 0.5: return False # car must be stopped, this equality will only work in simulation
97102
return np.linalg.norm(np.array(current[:2]) - np.array(goal[:2])) < .5
98103

99104
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
102109
(x1, y1, theta1, v1, dtheta1) = n1
103110
(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
106145

107146
def distance_between(self, n1, n2):
108147
"""this method always returns 1, as two 'neighbors' are always adajcent"""
@@ -153,15 +192,15 @@ def solve():
153192
# generate obstacle
154193
# obstacles = gen_obstacle(1)
155194
pose = ObjectPose(frame=ObjectFrameEnum(3),
156-
t=0, x = 8, y=5)
195+
t=0, x = 2, y=5)
157196
pose2 = ObjectPose(frame=ObjectFrameEnum(3),
158-
t=0, x = 8, y=0)
197+
t=0, x = 8, y=5)
159198
dimensions = (1.5,2.5,1)
160199
obstacles = [PhysicalObject(pose, dimensions, None), PhysicalObject(pose2, dimensions, None)]
161200
# obstacles = [PhysicalObject(pose, dimensions, None)]
162201
# obstacles = []
163202
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
165204

166205
# let's solve it
167206
foundPath = list(ParkingSolverSecondOrderDubins(obstacles).astar(start, goal))

0 commit comments

Comments
 (0)