Skip to content

Commit eaf4661

Browse files
committed
WIP: Integrate server, frontend, and state machine
1 parent bf2c21e commit eaf4661

5 files changed

Lines changed: 129 additions & 87 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ downloads/
2222
eggs/
2323
.eggs/
2424
lib/
25+
!frontend/*
2526
lib64/
2627
parts/
2728
sdist/

GEMstack/onboard/execution/execution.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,6 @@ def run(self):
655655
"A component may have hung. Traceback:\n{}",
656656
traceback.format_exc(),
657657
)
658-
print("validated: ", validated)
659658
if validated:
660659
self.begin()
661660
while True:
@@ -819,8 +818,6 @@ def run_until_switch(self):
819818
dt_min = min([c.dt for c in components if c.dt != 0.0])
820819
looper = TimedLooper(dt_min, name="main executor")
821820
while looper and not self.done():
822-
response = requests.get("http://localhost:8000/api/inspect")
823-
print("data: ", response.json())
824821
self.state.t = self.vehicle_interface.time()
825822
self.logging_manager.set_vehicle_time(self.state.t)
826823
self.last_loop_time = time.time()

GEMstack/onboard/planning/inspection_planning.py

Lines changed: 115 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22
import matplotlib.pyplot as plt
33
from typing import List, Tuple, Union
44
from ..component import Component
5-
from ...state import AllState, VehicleState, EntityRelation, EntityRelationEnum, Path, Trajectory, Route, ObjectFrameEnum, AgentState
5+
from ...state import (
6+
AllState,
7+
VehicleState,
8+
EntityRelation,
9+
EntityRelationEnum,
10+
Path,
11+
Trajectory,
12+
Route,
13+
ObjectFrameEnum,
14+
AgentState,
15+
)
616
from ...utils import serialization
717
from ...mathutils.transforms import vector_madd
818
from ...mathutils.quadratic_equation import quad_root
@@ -15,11 +25,15 @@
1525
import matplotlib.patches as patches
1626
import math
1727
from scipy.optimize import minimize
18-
from .longitudinal_planning import longitudinal_plan, detect_collision, longitudinal_brake
28+
from .longitudinal_planning import (
29+
longitudinal_plan,
30+
detect_collision,
31+
longitudinal_brake,
32+
)
1933

2034

2135
def is_inside_geofence(x, y, xmin, xmax, ymin, ymax):
22-
return xmin+0.2 < x < xmax-0.2 and ymin+0.2 < y < ymax-0.2
36+
return xmin + 0.2 < x < xmax - 0.2 and ymin + 0.2 < y < ymax - 0.2
2337

2438

2539
def max_visible_arc(circle_center, radius, geofence):
@@ -70,13 +84,22 @@ def plot_circle_with_geofence_and_arc(circle_center, radius, geofence, rem_pts):
7084

7185
# Plot geofence
7286
(xmin, ymin), (xmax, ymax) = geofence
73-
rect = plt.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin, linewidth=2, edgecolor='red', facecolor='none')
87+
rect = plt.Rectangle(
88+
(xmin, ymin),
89+
xmax - xmin,
90+
ymax - ymin,
91+
linewidth=2,
92+
edgecolor="red",
93+
facecolor="none",
94+
)
7495
ax.add_patch(rect)
7596

7697
rem_pts = np.array(rem_pts)
77-
ax.plot(rem_pts[:, 0], rem_pts[:, 1], color='blue', linewidth=3, label='Max Valid Arc')
98+
ax.plot(
99+
rem_pts[:, 0], rem_pts[:, 1], color="blue", linewidth=3, label="Max Valid Arc"
100+
)
78101

79-
ax.set_aspect('equal')
102+
ax.set_aspect("equal")
80103
ax.grid(True)
81104
plt.legend()
82105
plt.show()
@@ -90,27 +113,29 @@ def plot_circle_with_geofence_and_arc(circle_center, radius, geofence, rem_pts):
90113
# rem_points = max_visible_arc(circle_center, radius, geofence)
91114
# plot_circle_with_geofence_and_arc(circle_center, radius, geofence, rem_points)
92115

116+
93117
def check_point_exists(server_url="http://localhost:8000"):
94118
try:
95-
response = requests.get(f"{server_url}/point")
119+
response = requests.get(f"{server_url}/api/inspect")
96120
response.raise_for_status()
97-
points = response.json().get("points", [])
98-
121+
points = response.json().get("coords", [])
122+
99123
for point in points:
100-
return True, [point["x"], point["y"]]
124+
return True, [point["lat"], point["lng"]]
101125
return False, []
102126

103127
except requests.exceptions.RequestException as e:
104128
print("Error contacting server:", e)
105129
return False, []
106130

131+
107132
class InspectionPlanner(Component):
108133
"""Follows the given route. Brakes if you have to yield or
109134
you are at the end of the route, otherwise accelerates to
110135
the desired speed.
111136
"""
112137

113-
def __init__(self, mode : str = 'real', params: dict = {'state_machine' :[]}):
138+
def __init__(self, mode: str = "real", params: dict = {"state_machine": []}):
114139
self.route_progress = None
115140
self.t_last = None
116141
self.acceleration = 2
@@ -121,35 +146,35 @@ def __init__(self, mode : str = 'real', params: dict = {'state_machine' :[]}):
121146
self.max_deceleration = 8.0
122147

123148
self.mode = mode
124-
self.planner = 'dt'
125-
self.state_list = params['state_machine']
126-
self.goal = [10,0]
127-
self.inspect_goal = [15,0]
149+
self.planner = "dt"
150+
self.state_list = params["state_machine"]
151+
self.goal = [10, 0]
152+
self.inspect_goal = [15, 0]
128153
self.index = 0
129154
self.mission = self.state_list[self.index]
130155
self.x = 0
131156
print(self.mission)
132157

133158
def state_inputs(self):
134-
return ['all']
159+
return ["all"]
135160

136161
def state_outputs(self) -> List[str]:
137-
return ['trajectory']
162+
return ["trajectory"]
138163

139164
def rate(self):
140165
return 10
141166

142-
def update(self, state : AllState):
167+
def update(self, state: AllState):
143168
start_time = time.time()
144169

145-
vehicle = state.vehicle # type: VehicleState
146-
route = state.route # type: Route
170+
vehicle = state.vehicle # type: VehicleState
171+
route = state.route # type: Route
147172
t = state.t
148173

149174
if self.t_last is None:
150175
self.t_last = t
151176
dt = t - self.t_last
152-
177+
153178
# Position in vehicle frame (Start (0,0) to (15,0))
154179
curr_x = vehicle.pose.x
155180
curr_y = vehicle.pose.y
@@ -160,11 +185,15 @@ def update(self, state : AllState):
160185

161186
if self.route_progress is None:
162187
self.route_progress = 0.0
163-
closest_dist,closest_parameter = state.route.closest_point_local((curr_x,curr_y),[self.route_progress-5.0,self.route_progress+5.0])
188+
closest_dist, closest_parameter = state.route.closest_point_local(
189+
(curr_x, curr_y), [self.route_progress - 5.0, self.route_progress + 5.0]
190+
)
164191
self.route_progress = closest_parameter
165192

166193
lookahead_distance = max(10, curr_v**2 / (2 * self.deceleration))
167-
route_with_lookahead = route.trim(closest_parameter,closest_parameter + lookahead_distance)
194+
route_with_lookahead = route.trim(
195+
closest_parameter, closest_parameter + lookahead_distance
196+
)
168197
print("Lookahead distance:", lookahead_distance)
169198
print(self.mission)
170199

@@ -175,73 +204,111 @@ def update(self, state : AllState):
175204
points_found, pts = check_point_exists()
176205
if points_found:
177206
self.goal = pts
178-
print(self.state_list[self.index+1])
179-
self.mission = self.state_list[self.index+1]
207+
print(self.state_list[self.index + 1])
208+
self.mission = self.state_list[self.index + 1]
180209
self.index += 1
181210
print("CHANGING STATES", self.mission)
182211

183-
184212
elif self.mission == "NAV":
185213
print(self.goal)
186-
print(abs_x,abs_y)
214+
print(abs_x, abs_y)
187215

188216
if abs(abs_x - self.goal[0]) <= 0.1 and abs(abs_y - self.goal[1]) <= 0.1:
189217
self.mission = self.state_list[self.index + 1]
190218
self.index += 1
191219
print("CHANGING STATES", self.mission)
192-
193220

194221
should_yield = False
195222
yield_deceleration = 0.0
196223

197224
print("Current Speed: ", curr_v)
198225

199226
for r in state.relations:
200-
if r.type == EntityRelationEnum.YIELDING and r.obj1 == '':
201-
#get the object we are yielding to
227+
if r.type == EntityRelationEnum.YIELDING and r.obj1 == "":
228+
# get the object we are yielding to
202229
obj = state.agents[r.obj2]
203230

204-
detected, deceleration = detect_collision(abs_x, abs_y, curr_v, obj, self.min_deceleration, self.max_deceleration, self.acceleration, self.desired_speed)
231+
detected, deceleration = detect_collision(
232+
abs_x,
233+
abs_y,
234+
curr_v,
235+
obj,
236+
self.min_deceleration,
237+
self.max_deceleration,
238+
self.acceleration,
239+
self.desired_speed,
240+
)
205241
if isinstance(deceleration, list):
206242
print("@@@@@ INPUT", deceleration)
207243
time_collision = deceleration[1]
208244
distance_collision = deceleration[0]
209-
b = 3*time_collision - 2*curr_v
210-
c = curr_v**2 - 3*distance_collision
211-
desired_speed = (-b + (b**2 - 4*c)**0.5)/2
245+
b = 3 * time_collision - 2 * curr_v
246+
c = curr_v**2 - 3 * distance_collision
247+
desired_speed = (-b + (b**2 - 4 * c) ** 0.5) / 2
212248
deceleration = 1.5
213249
print("@@@@@ YIELDING", desired_speed)
214-
route_yield = route.trim(closest_parameter,closest_parameter + distance_collision)
215-
traj = longitudinal_plan(route_yield, self.acceleration, deceleration, desired_speed, curr_v, self.planner)
250+
route_yield = route.trim(
251+
closest_parameter, closest_parameter + distance_collision
252+
)
253+
traj = longitudinal_plan(
254+
route_yield,
255+
self.acceleration,
256+
deceleration,
257+
desired_speed,
258+
curr_v,
259+
self.planner,
260+
)
216261
return traj
217262
else:
218263
if detected and deceleration > 0:
219264
yield_deceleration = deceleration
220265
should_yield = True
221-
266+
222267
print("should yield: ", should_yield)
223268

224-
should_accelerate = (not should_yield and curr_v < self.desired_speed)
269+
should_accelerate = not should_yield and curr_v < self.desired_speed
225270

226-
#choose whether to accelerate, brake, or keep at current velocity
271+
# choose whether to accelerate, brake, or keep at current velocity
227272
if should_accelerate:
228-
traj = longitudinal_plan(route_to_end, self.acceleration, self.deceleration, self.desired_speed, curr_v, self.planner)
273+
traj = longitudinal_plan(
274+
route_to_end,
275+
self.acceleration,
276+
self.deceleration,
277+
self.desired_speed,
278+
curr_v,
279+
self.planner,
280+
)
229281
elif should_yield:
230282
traj = longitudinal_brake(route_to_end, yield_deceleration, curr_v)
231283
else:
232-
traj = longitudinal_plan(route_to_end, 0.0, self.deceleration, self.desired_speed, curr_v, self.planner)
284+
traj = longitudinal_plan(
285+
route_to_end,
286+
0.0,
287+
self.deceleration,
288+
self.desired_speed,
289+
curr_v,
290+
self.planner,
291+
)
292+
293+
return traj
233294

234-
return traj
235-
236295
elif self.mission == "INSPECT":
237296

238-
if abs(abs_x - self.inspect_goal[0]) <= 0.1 and abs(abs_y - self.inspect_goal[1]) <= 0.1:
297+
if (
298+
abs(abs_x - self.inspect_goal[0]) <= 0.1
299+
and abs(abs_y - self.inspect_goal[1]) <= 0.1
300+
):
239301
self.mission = self.state_list[self.index + 1]
240302
self.index += 1
241303
print("CHANGING STATES", self.mission)
242304

305+
traj = longitudinal_plan(
306+
route_to_end,
307+
self.acceleration,
308+
self.deceleration,
309+
self.desired_speed,
310+
curr_v,
311+
self.planner,
312+
)
243313

244-
traj = longitudinal_plan(route_to_end, self.acceleration, self.deceleration, self.desired_speed, curr_v, self.planner)
245-
246-
return traj
247-
314+
return traj

server/main.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,10 @@ class Coordinates(BaseModel):
6262
lng: float
6363

6464

65+
class InspectResponse(BaseModel):
66+
coords: List[Coordinates]
67+
68+
6569
### HELPERS ###
6670
# def create_jwt(username: str) -> str:
6771
# payload = {"sub": username, "jti": str(uuid.uuid4())}
@@ -114,16 +118,22 @@ def cancel(req: CancelRequest):
114118
return CancelResponse(launch_id=req.launch_id, status="cancelled")
115119

116120

117-
bounding_box = None
121+
bounding_box = []
118122

119123

120124
@app.post("/api/inspect", status_code=201)
121125
def get_bounding_box(coords: list[Coordinates]):
122126
global bounding_box
127+
# Check to see if it's a quadrilateral
128+
if len(coords) != 4:
129+
return JSONResponse(
130+
content="Require 4 values for bounding box coordinates", status_code=400
131+
)
132+
123133
bounding_box = coords
124134
return "Successfully retrieved bounding box coords!"
125135

126136

127-
@app.get("/api/inspect", response_model=list[Coordinates] | None, status_code=200)
137+
@app.get("/api/inspect", response_model=InspectResponse, status_code=200)
128138
def send_bounding_box():
129-
return bounding_box
139+
return InspectResponse(coords=bounding_box)

server/message_constants.py

Lines changed: 0 additions & 33 deletions
This file was deleted.

0 commit comments

Comments
 (0)