Skip to content

Commit fbb1368

Browse files
authored
Merge pull request #230 from krishauser/summoning_pr
Summoning team 2nd PR
2 parents 39bcd62 + 033e395 commit fbb1368

13 files changed

Lines changed: 268 additions & 152 deletions

GEMstack/knowledge/defaults/rrt_param.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ map:
1111
# vehicle info
1212
vehicle:
1313
heading_limit: 0.5235987756 # vehicle heading difference limit per rrt step_size (pi/6 in radians)
14-
half_width: 0.8 # vehicle half width in meter
14+
half_width: 0.6 # vehicle half width in meter
1515
# algorithm parameters
1616
rrt:
1717
time_limit: 10 # in sec

GEMstack/knowledge/routes/summoning_roadgraph_highbay.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

GEMstack/knowledge/routes/summoning_roadgraph_sim.json

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

GEMstack/onboard/planning/mission_planning.py

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
from typing import List, Union
22
from klampt.vis import scene
33
from ..component import Component
4-
from ...utils import serialization
54
from ...state import Route, ObjectFrameEnum, AllState, VehicleState, Roadgraph, MissionObjective, MissionEnum, ObjectPose
65
import numpy as np
76
import requests
8-
import json
97
import time
8+
import yaml
109

1110

1211
def check_distance(goal_pose: Union[ObjectPose, list], current_pose : ObjectPose):
@@ -35,14 +34,18 @@ def next_state(self):
3534

3635

3736
class SummoningMissionPlanner(Component):
38-
def __init__(self, use_webapp, webapp_url, goal, state_machine):
37+
def __init__(self, use_webapp, webapp_url, goal=None, state_machine=None):
3938
self.state_machine = StateMachine([eval(s) for s in state_machine])
40-
self.goal_location = goal['location']
41-
self.goal_frame = goal['frame']
39+
40+
# if use_webapp is True, goal should be None
41+
self.goal_location = goal['location'] if not use_webapp else None
42+
self.goal_frame = goal['frame'] if not use_webapp else None
4243
self.new_goal = False
4344
self.goal_pose = None
4445
self.start_pose = None
4546
self.start_time = time.time()
47+
self.end_of_driving_route = None
48+
self.search_count = 0
4649

4750
self.flag_use_webapp = use_webapp
4851
self.url_status = f"{webapp_url}/api/status"
@@ -94,7 +97,7 @@ def update(self, state: AllState):
9497
goal_location = None
9598
goal_frame = None
9699
else:
97-
goal_location = [data['lat'] , data['lon']]
100+
goal_location = [data['lon'] , data['lat']]
98101
goal_frame = 'global'
99102
print("Goal location:", goal_location)
100103
print("Goal frame:", goal_frame)
@@ -110,6 +113,8 @@ def update(self, state: AllState):
110113
goal_location = self.goal_location
111114
goal_frame = self.goal_frame
112115

116+
start_vehicle_pose = state.start_vehicle_pose
117+
113118
if goal_frame == 'global':
114119
self.goal_pose = ObjectPose(t=time.time(), x=goal_location[0], y=goal_location[1],
115120
frame=ObjectFrameEnum.GLOBAL)
@@ -125,7 +130,16 @@ def update(self, state: AllState):
125130
raise ValueError("Invalid frame argument")
126131

127132
if self.goal_pose:
128-
self.goal_pose = self.goal_pose.to_frame(ObjectFrameEnum.START, start_pose_abs=state.start_vehicle_pose)
133+
if start_vehicle_pose.frame == ObjectFrameEnum.ABSOLUTE_CARTESIAN and goal_frame == 'global':
134+
# For global map simulation test
135+
with open("scenes/summoning_map_sim_setting.yaml", "r") as f:
136+
data = yaml.safe_load(f)
137+
start= data['start_pose_global']
138+
start_pose_global = ObjectPose(frame=ObjectFrameEnum.GLOBAL, t=start_vehicle_pose.t, x=start[0], y=start[1], yaw=start[2])
139+
self.goal_pose = self.goal_pose.to_frame(ObjectFrameEnum.START, start_pose_abs=start_pose_global)
140+
else:
141+
self.goal_pose = self.goal_pose.to_frame(ObjectFrameEnum.START, start_pose_abs=start_vehicle_pose)
142+
print("Goal pose:", self.goal_pose)
129143

130144
# Initiate state
131145
if mission is None:
@@ -137,34 +151,52 @@ def update(self, state: AllState):
137151
if self.new_goal:
138152
mission.goal_pose = self.goal_pose
139153
mission.type = self.state_machine.next_state()
154+
self.new_goal = False
140155
print("============== Next state:", mission.type)
141156

142157
# Reach the end of the route, begin to search for parking
143-
elif mission.type == MissionEnum.SUMMONING_DRIVE:
158+
# elif mission.type == MissionEnum.SUMMONING_DRIVE:
159+
elif mission.type == MissionEnum.SUMMON_DRIVING:
144160
mission.goal_pose = self.goal_pose
145161
if route:
146162
_, closest_index = route.closest_point([vehicle.pose.x, vehicle.pose.y], edges=False)
147-
if closest_index == len(route.points) - 1 or check_distance(mission.goal_pose, vehicle.pose) < 1:
148-
mission.type = self.state_machine.next_state()
149-
print("============== Next state:", mission.type)
163+
if closest_index == len(route.points) - 1 or check_distance(mission.goal_pose, vehicle.pose) < 5:
164+
if vehicle.v < 0.1:
165+
mission.type = self.state_machine.next_state()
166+
print("============== Next state:", mission.type)
167+
self.end_of_driving_route = route.points[-1]
168+
else:
169+
self.search_count += 1
150170

151171
# Finish parking, back to idle and wait for the next goal location
152172
elif mission.type == MissionEnum.PARALLEL_PARKING:
153173
if route:
154-
_, closest_index = route.closest_point([vehicle.pose.x, vehicle.pose.y], edges=False)
155-
if closest_index == len(route.points) - 1 or check_distance(route.points[-1], vehicle.pose) < 0.1:
156-
mission.type = self.state_machine.next_state()
157-
self.goal_pose = None
158-
mission.goal_pose = self.goal_pose
159-
print("============== Next state:", mission.type)
174+
if route.points[-1] != self.end_of_driving_route:
175+
_, closest_index = route.closest_point([vehicle.pose.x, vehicle.pose.y], edges=False)
176+
if vehicle.v < 0.01 and (closest_index >= len(route.points) - 1 or check_distance(route.points[-1], vehicle.pose) < 0.5):
177+
# Set everything to idle
178+
mission.type = self.state_machine.next_state()
179+
print("============== Next state:", mission.type)
180+
else:
181+
self.search_count += 1
160182

161183
else:
162184
raise ValueError("Invalid mission type")
163185

186+
# Can not find a path, stop mission.
187+
if mission.type != MissionEnum.IDLE:
188+
print("Route searching times:", self.search_count)
189+
if self.search_count > 10:
190+
mission.type = MissionEnum.IDLE
191+
self.goal_pose = None
192+
self.goal_location = None
193+
self.goal_frame = None
194+
self.search_count = 0
195+
164196

165197
if self.flag_use_webapp:
166198
data = {
167-
"status": mission.planner_type.name
199+
"status": mission.type.name
168200
}
169201
print("POST:", data)
170202
response = requests.post(url=self.url_status, json=data)

GEMstack/onboard/planning/reeds_shepp_parking.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ def all_parking_spots_in_parking_lot(self,
204204
List of (x, y, yaw) poses for each parking spot.
205205
"""
206206
if len(static_horizontal_curb) != 2:
207+
return None
207208
raise ValueError("Exactly two curb endpoints are required.")
208209

209210
# Extract center points of the curb rectangles
@@ -225,6 +226,7 @@ def all_parking_spots_in_parking_lot(self,
225226
spacing = spot_length
226227

227228
if total_length < spot_length:
229+
return None
228230
raise ValueError("Insufficient curb length to place even one spot.")
229231

230232
# Number of full spots that can fit along the curb
@@ -398,6 +400,7 @@ def shift_points_perpendicular_ccw(self, p1, p2, shift_amount):
398400
# 2) Compute its magnitude |v|
399401
length = math.hypot(v_x, v_y)
400402
if length == 0:
403+
return None, None, None
401404
raise ValueError("p1 and p2 must be distinct points to define a direction.")
402405

403406
# 3) Normalize v to get unit direction v̂ = (v_x, v_y) / |v|
@@ -453,6 +456,7 @@ def project_point_on_axis(self, p1, p2, p3):
453456
dot_vv = v_x * v_x + v_y * v_y # v · v
454457

455458
if dot_vv == 0:
459+
return (None, None)
456460
raise ValueError("p1 and p2 must be distinct to define an axis.")
457461

458462
# Parameter t gives the position along the line: p_proj = p1 + t * v
@@ -486,6 +490,7 @@ def move_point_along_vector(self, p0, direction, step, positive_direction=True):
486490
# Compute the length of the direction vector
487491
length = math.hypot(dx, dy)
488492
if length == 0:
493+
print(None, None)
489494
raise ValueError("Direction vector must be non-zero to define a movement direction.")
490495

491496
# Normalize the direction vector to unit length
@@ -627,20 +632,28 @@ def find_available_parking_spots_and_search_vector(self, detected_cones=[], vehi
627632
self.parking_lot_axis_shift_margin
628633
)
629634

635+
if self.curb_0_xy_shifted is None:
636+
return
637+
630638
# Horizontal axis search direction
631639
_ , _, self.horizontal_search_axis_direction = self.shift_points_perpendicular_ccw(
632640
self.static_horizontal_curb_xy_coordinates[0],
633641
self.curb_0_xy_shifted,
634642
self.parking_lot_axis_shift_margin
635643
)
644+
645+
if self.horizontal_search_axis_direction is None:
646+
return
636647

637648
# Project vehicle pose onto the search axis
638649
self.vehicle_pose_proj = self.project_point_on_axis(
639650
self.curb_0_xy_shifted,
640651
self.curb_1_xy_shifted,
641652
self.vehicle_pose[0:2]
642653
)
643-
654+
655+
if self.vehicle_pose_proj is None:
656+
return
644657
# Compute bounds for the search axis
645658
self.upper_bound_xy = self.move_point_along_vector(
646659
self.curb_1_xy_shifted,
@@ -680,7 +693,9 @@ def find_collision_free_trajectory_to_park(self, detected_cones=[], vehicle_pose
680693
self.vehicle_pose[0:2]
681694
)
682695

683-
696+
if self.vehicle_pose_proj is None:
697+
return
698+
684699
while True:
685700
# Move projected pose along the search axis
686701
self.vehicle_pose_proj = self.move_point_along_vector(
@@ -751,7 +766,8 @@ def find_collision_free_trajectory_to_park(self, detected_cones=[], vehicle_pose
751766
# Use self.horizontal_search_axis_direction_var
752767
break # Give up in this direction
753768

754-
# If both directions fail
769+
# If both directions fail
770+
return
755771
raise ValueError("No collision-free trajectory available in either direction for parking.")
756772

757773

@@ -767,7 +783,9 @@ def find_collision_free_trajectory_to_unpark(self, detected_cones=[], vehicle_po
767783
self.curb_0_xy_shifted,
768784
self.curb_1_xy_shifted,
769785
self.vehicle_pose[0:2]
770-
)
786+
)
787+
if self.vehicle_pose_proj is None:
788+
return
771789

772790
# Move projected pose along the search axis
773791
self.vehicle_pose_proj = self.move_point_along_vector(
@@ -824,5 +842,6 @@ def find_collision_free_trajectory_to_unpark(self, detected_cones=[], vehicle_po
824842
if dist_to_upper_bound < self.search_bound_threshold or dist_to_lower_bound < self.search_bound_threshold:
825843
break # Give up in this direction
826844

827-
# If both directions fail
845+
# If both directions fail
846+
return
828847
raise ValueError("No collision-free trajectory available for unparking.")

0 commit comments

Comments
 (0)