Skip to content

Commit 0bc9edd

Browse files
fixed file ending
1 parent b3b68cc commit 0bc9edd

1 file changed

Lines changed: 345 additions & 0 deletions

File tree

Lines changed: 345 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,345 @@
1+
from typing import List
2+
from ..component import Component
3+
from ...state import AllState, VehicleIntent
4+
import time
5+
import math
6+
7+
class ParkingLogic(Component):
8+
"""
9+
Component that handles parking logic for GEM vehicles.
10+
This includes finding a parking spot and executing parking maneuvers.
11+
"""
12+
# Intent codes
13+
INTENT_NORMAL_DRIVING = 0
14+
INTENT_SEARCHING = 1
15+
INTENT_PARKING = 2
16+
INTENT_PARKED = 3
17+
INTENT_EXITING = 4
18+
19+
# Parking state machine states
20+
STATE_IDLE = 0
21+
STATE_SEARCHING = 1
22+
STATE_APPROACH = 2
23+
STATE_ALIGNING = 3
24+
STATE_BACKING = 4
25+
STATE_ADJUSTING = 5
26+
STATE_PARKED = 6
27+
STATE_EXITING = 7
28+
29+
def rate(self) -> float:
30+
"""Returns the rate in Hz at which this component should be updated."""
31+
return 10.0 # Higher rate for more responsive parking
32+
33+
def state_inputs(self) -> List[str]:
34+
"""Returns the list of AllState inputs this component requires."""
35+
return ['all', 'perception', 'localization']
36+
37+
def state_outputs(self) -> List[str]:
38+
"""Returns the list of AllState outputs this component generates."""
39+
return ['intent', 'trajectory']
40+
41+
def healthy(self):
42+
"""Returns True if the element is in a stable state."""
43+
return self.error_count < 5 # Consider unhealthy after multiple errors
44+
45+
def initialize(self):
46+
"""Initialize the component. This is called once before the first update."""
47+
self.parking_state = self.STATE_IDLE
48+
self.spot_found = False
49+
self.error_count = 0
50+
self.start_time = time.time()
51+
self.last_state_change = time.time()
52+
53+
# Parking spot characteristics
54+
self.min_spot_length = 5.0 # meters
55+
self.min_spot_width = 2.5 # meters
56+
57+
# Vehicle characteristics (example values)
58+
self.vehicle_length = 3.5 # meters
59+
self.vehicle_width = 1.5 # meters
60+
61+
# Parking maneuver parameters
62+
self.approach_distance = 1.0 # meters ahead of spot
63+
self.backing_speed = 0.5 # m/s
64+
self.forward_speed = 1.0 # m/s
65+
66+
# For detecting a spot
67+
self.last_obstacles = []
68+
self.potential_spots = []
69+
70+
# Parking spot once found
71+
self.target_spot = None
72+
73+
# Debug information
74+
self.debug("initialized", True)
75+
self.debug_event("ParkingLogic initialized")
76+
77+
def cleanup(self):
78+
"""Cleans up resources used by the component."""
79+
self.debug_event("ParkingLogic cleanup")
80+
pass
81+
82+
def update(self, state: AllState):
83+
"""Update the component based on current state."""
84+
try:
85+
if self.parking_state == self.STATE_IDLE:
86+
# Enter searching state
87+
self.parking_state = self.STATE_SEARCHING
88+
self.debug_event("Starting to search for parking spot")
89+
state.intent.intent = self.INTENT_SEARCHING
90+
91+
elif self.parking_state == self.STATE_SEARCHING:
92+
# Logic to search for a parking spot using perception data
93+
if self._find_parking_spot(state):
94+
self.parking_state = self.STATE_APPROACH
95+
self.debug_event(f"Parking spot found at {self.target_spot}")
96+
state.intent.intent = self.INTENT_PARKING
97+
else:
98+
# Continue searching
99+
self._maintain_search_pattern(state)
100+
101+
elif self.parking_state == self.STATE_APPROACH:
102+
# Approach the parking spot
103+
if self._approach_parking_spot(state):
104+
self.parking_state = self.STATE_ALIGNING
105+
self.debug_event("Aligned with parking spot")
106+
107+
elif self.parking_state == self.STATE_ALIGNING:
108+
# Align the vehicle parallel to the parking spot
109+
if self._align_with_spot(state):
110+
self.parking_state = self.STATE_BACKING
111+
self.debug_event("Starting to back into spot")
112+
113+
elif self.parking_state == self.STATE_BACKING:
114+
# Back into the parking spot
115+
if self._back_into_spot(state):
116+
self.parking_state = self.STATE_ADJUSTING
117+
self.debug_event("Backed into spot, making final adjustments")
118+
119+
elif self.parking_state == self.STATE_ADJUSTING:
120+
# Make final adjustments to center in the spot
121+
if self._adjust_position(state):
122+
self.parking_state = self.STATE_PARKED
123+
self.debug_event("Successfully parked")
124+
state.intent.intent = self.INTENT_PARKED
125+
126+
elif self.parking_state == self.STATE_PARKED:
127+
# Stay parked until requested to exit
128+
if self._should_exit_parking(state):
129+
self.parking_state = self.STATE_EXITING
130+
self.debug_event("Starting to exit parking spot")
131+
state.intent.intent = self.INTENT_EXITING
132+
133+
elif self.parking_state == self.STATE_EXITING:
134+
# Exit the parking spot
135+
if self._exit_parking_spot(state):
136+
self.parking_state = self.STATE_IDLE
137+
self.debug_event("Exited parking spot, resuming normal operation")
138+
state.intent.intent = self.INTENT_NORMAL_DRIVING
139+
140+
# Log current state for debugging
141+
self.debug("parking_state", self.parking_state)
142+
self.debug("intent", state.intent.intent)
143+
144+
except Exception as e:
145+
self.error_count += 1
146+
self.debug("error", str(e))
147+
self.debug_event(f"Error in parking logic: {str(e)}")
148+
149+
def _find_parking_spot(self, state: AllState) -> bool:
150+
"""
151+
Use perception data to find a suitable parking spot.
152+
Returns True if a spot is found, False otherwise.
153+
"""
154+
# Example implementation using perception data
155+
# In a real implementation, you would use perception data to identify open spaces
156+
157+
if not hasattr(state, 'perception') or not hasattr(state.perception, 'obstacles'):
158+
return False
159+
160+
current_obstacles = state.perception.obstacles
161+
162+
# Simple spot detection logic: look for gaps between obstacles
163+
# that are large enough for the vehicle
164+
potential_spots = []
165+
166+
# For parallel parking, look for gaps along the side of the road
167+
if hasattr(state, 'localization') and hasattr(state.localization, 'lane_position'):
168+
# Get current lane information
169+
current_lane = state.localization.lane_position
170+
171+
# Example code to detect gaps - this would be much more sophisticated in reality
172+
# using advanced perception and mapping
173+
gaps = self._detect_gaps(current_obstacles, current_lane)
174+
175+
for gap in gaps:
176+
if gap['length'] >= self.min_spot_length and gap['width'] >= self.min_spot_width:
177+
potential_spots.append(gap)
178+
179+
# If we found at least one spot, select the best one
180+
if potential_spots:
181+
# For this demo, just select the first valid spot
182+
self.target_spot = potential_spots[0]
183+
return True
184+
185+
return False
186+
187+
def _detect_gaps(self, obstacles, lane_info):
188+
"""
189+
Analyze obstacle data to find gaps that could be parking spots.
190+
This is a simplified implementation.
191+
"""
192+
# In a real implementation, this would use sophisticated algorithms
193+
# to detect gaps between vehicles or in designated parking areas
194+
195+
# Placeholder example
196+
gaps = []
197+
198+
# Simulate finding a gap after a certain time for demo purposes
199+
if time.time() - self.start_time > 10.0: # After 10 seconds, "find" a spot
200+
# Generate a simulated spot relative to current position
201+
example_gap = {
202+
'length': self.min_spot_length + 0.5, # A bit larger than minimum
203+
'width': self.min_spot_width + 0.2,
204+
'position': {
205+
'x': lane_info.x + 5.0, # 5 meters ahead
206+
'y': lane_info.y + 2.0, # 2 meters to the right
207+
'heading': lane_info.heading
208+
},
209+
'type': 'parallel' # Could also be 'perpendicular'
210+
}
211+
gaps.append(example_gap)
212+
213+
return gaps
214+
215+
def _maintain_search_pattern(self, state: AllState):
216+
"""Maintain a driving pattern while searching for parking spots."""
217+
# In a real implementation, this would follow a search route
218+
# For the demo, just continue with normal driving
219+
state.intent.intent = self.INTENT_SEARCHING
220+
221+
def _approach_parking_spot(self, state: AllState) -> bool:
222+
"""
223+
Move the vehicle to the approach position for the target parking spot.
224+
Returns True when in position.
225+
"""
226+
if not self.target_spot:
227+
return False
228+
229+
# Calculate approach position (would use proper path planning in real implementation)
230+
target_x = self.target_spot['position']['x'] - self.approach_distance
231+
target_y = self.target_spot['position']['y']
232+
233+
# Check if we've reached the approach position
234+
current_x = state.localization.x
235+
current_y = state.localization.y
236+
237+
distance_to_approach = math.sqrt((target_x - current_x)**2 + (target_y - current_y)**2)
238+
239+
# Update trajectory to approach position
240+
if hasattr(state, 'trajectory'):
241+
# Set trajectory to approach position
242+
# (This is a simplified placeholder - real implementation would
243+
# generate proper trajectory points)
244+
state.trajectory.target_speed = self.forward_speed
245+
246+
# Return True if we're close enough to approach position
247+
return distance_to_approach < 0.3 # meters
248+
249+
def _align_with_spot(self, state: AllState) -> bool:
250+
"""
251+
Align the vehicle parallel to the parking spot.
252+
Returns True when aligned.
253+
"""
254+
if not self.target_spot:
255+
return False
256+
257+
target_heading = self.target_spot['position']['heading']
258+
current_heading = state.localization.heading
259+
260+
# Calculate heading difference (accounting for circular values)
261+
heading_diff = abs((target_heading - current_heading + 180) % 360 - 180)
262+
263+
# Update trajectory for alignment
264+
if hasattr(state, 'trajectory'):
265+
# Would set a trajectory that aligns with target heading
266+
state.trajectory.target_speed = 0.5 # Slow for precise alignment
267+
268+
# Return True if aligned within threshold
269+
return heading_diff < 5.0 # degrees
270+
271+
def _back_into_spot(self, state: AllState) -> bool:
272+
"""
273+
Execute backing maneuver into the parking spot.
274+
Returns True when in the spot.
275+
"""
276+
if not self.target_spot:
277+
return False
278+
279+
# Calculate spot center
280+
spot_center_x = self.target_spot['position']['x']
281+
spot_center_y = self.target_spot['position']['y']
282+
283+
# Current position
284+
current_x = state.localization.x
285+
current_y = state.localization.y
286+
287+
# Distance to spot center
288+
distance_to_center = math.sqrt((spot_center_x - current_x)**2 + (spot_center_y - current_y)**2)
289+
290+
# Update trajectory for backing
291+
if hasattr(state, 'trajectory'):
292+
# Would set reverse trajectory into spot
293+
state.trajectory.target_speed = -self.backing_speed # Negative for reverse
294+
295+
# Check if we've reached an appropriate position in the spot
296+
# In real implementation, would use more sophisticated positioning
297+
return distance_to_center < 0.5 # meters
298+
299+
def _adjust_position(self, state: AllState) -> bool:
300+
"""
301+
Make final adjustments to center in the parking spot.
302+
Returns True when properly centered.
303+
"""
304+
# Simple implementation - in reality would use precise positioning
305+
# For demo, just assume adjustment is complete after a delay
306+
adjustment_time = 3.0 # seconds
307+
308+
if time.time() - self.last_state_change > adjustment_time:
309+
return True
310+
311+
# Would set small adjustment trajectories
312+
if hasattr(state, 'trajectory'):
313+
state.trajectory.target_speed = 0.2 # Very slow for fine adjustments
314+
315+
return False
316+
317+
def _should_exit_parking(self, state: AllState) -> bool:
318+
"""
319+
Determine if the vehicle should exit the parking spot.
320+
In a real implementation, this could be triggered by user input
321+
or a scheduled departure time.
322+
"""
323+
# For demo purposes, exit after 10 seconds of being parked
324+
parked_duration = time.time() - self.last_state_change
325+
return parked_duration > 10.0
326+
327+
def _exit_parking_spot(self, state: AllState) -> bool:
328+
"""
329+
Execute maneuver to exit the parking spot.
330+
Returns True when back on the road.
331+
"""
332+
# Simple implementation - in reality would plan a path out
333+
# For demo, just assume exit is complete after a delay
334+
exit_time = 5.0 # seconds
335+
336+
if time.time() - self.last_state_change > exit_time:
337+
# Reset parking state
338+
self.target_spot = None
339+
return True
340+
341+
# Would set exit trajectory
342+
if hasattr(state, 'trajectory'):
343+
state.trajectory.target_speed = self.forward_speed
344+
345+
return False

0 commit comments

Comments
 (0)