Import CSV
Import CSV
import math
import heapq
import os
import numpy as np
from controller import Supervisor
import matplotlib.pyplot as plt
class Node:
def __init__(self, x, y):
self.x = x
self.y = y
self.parent = None
self.g = 0
self.h = 0
self.f = 0
def __hash__(self):
return hash((self.x, self.y))
class AStarPlanner:
def __init__(self, csv_file):
self.road_points = set()
self.load_map(csv_file)
print(f"Map loaded with {len(self.road_points)} road points")
min_dist = float('inf')
nearest = None
if nearest:
print(f"Found nearest road point {nearest} at distance {min_dist:.2f}")
return nearest
else:
print("Error: Could not find nearest road point")
return None
open_set = []
open_set_hash = set()
closed_set = set()
heapq.heappush(open_set, start)
open_set_hash.add((start.x, start.y))
current = heapq.heappop(open_set)
open_set_hash.remove((current.x, current.y))
# Goal reached
if current.x == goal.x and current.y == goal.y:
path = []
while current:
path.append((current.x, current.y))
current = current.parent
print(f"Path found with {len(path)} points after {iterations}
iterations")
return path[::-1] # Return reversed path
closed_set.add((current.x, current.y))
class LPAStarPlanner:
def __init__(self, road_points):
# Store the valid road points from global planner
self.road_points = set(road_points) # Convert to set for faster lookup
# g-values: cost from start to vertex
self.g = {}
# rhs-values: one-step lookahead values based on g-values of predecessors
self.rhs = {}
# Priority queue for vertices to be processed
self.U = []
# Start and goal vertices
self.start = None
self.goal = None
# Safety radius around obstacles (m)
self.safety_radius = 3.0
# Maximum allowable bias from road points
self.max_bias = 0.5
self.start = start_point
self.goal = goal_point
min_dist = float('inf')
nearest = None
return nearest
if collision:
continue
predecessors.append(road_point)
return predecessors
iterations = 0
max_iterations = 10000 # Prevent infinite loops
iterations += 1
path = [self.start]
current = self.start
if next_vertex is None:
print("Path extraction failed - no valid successor found")
break
path.append(next_vertex)
current = next_vertex
self.compute_shortest_path(obstacles)
return self.extract_path()
class StanleyController:
def __init__(self, k=0.2): # Increased gain parameter for more responsive
steering
self.k = k # Stanley gain parameter
self.prev_steering = 0.0 # For steering smoothing
self.prev_error = 0.0 # For derivative term
self.error_sum = 0.0 # For integral term
self.damping = 0.0 # Reduced damping to make steering more responsive
self.max_integral = 1.0 # Prevent integral windup
# Heading error
heading_error = path_heading - car_heading
# Normalize to [-pi, pi]
heading_error = (heading_error + math.pi) % (2 * math.pi) - math.pi
def get_yaw_from_supervisor_rotation(rotation_matrix):
"""
Calculate yaw angle from supervisor rotation matrix for X-Y plane movement
Args:
rotation_matrix: 3x3 rotation matrix in row-major order (list of 9
elements)
Returns:
yaw: rotation angle around Z-axis in radians
"""
# For rotation about z-axis, yaw = atan2(R[1,0], R[0,0])
# In flattened form, R[1,0] is rotation_matrix[3] and R[0,0] is
rotation_matrix[0]
yaw = math.atan2(rotation_matrix[3], rotation_matrix[0])
return yaw
Args:
path: List of (x,y) tuples representing the original path
spacing: Desired spacing between waypoints in meters
Returns:
new_path: List of (x,y) tuples with approximately uniform spacing
"""
if not path or len(path) < 2:
return path
accumulated_distance = remaining_segment
else:
accumulated_distance += segment_length
last_point = current_point
return new_path
class CarController(Supervisor):
def __init__(self):
super().__init__()
self.timestep = int(self.getBasicTimeStep())
# Initialize variables
self.local_planner = None
self.initialization_success = False
self.car = None
self.path = []
self.current_waypoint = 0
self.other_vehicles = []
# Initialize motors
if not self.initialize_motors():
print("Error: Failed to initialize motors")
return
except Exception as e:
print(f"Error in controller initialization: {str(e)}")
def list_all_devices(self):
try:
n = self.getNumberOfDevices()
print(f"Vehicle has {n} devices:")
for i in range(min(n, 15)): # Print first 15 devices
device = self.getDeviceByIndex(i)
print(f" {i}: {device.getName()} (type: {device.getNodeType()})")
return True
except Exception as e:
print(f"Error listing devices: {str(e)}")
return False
def initialize_motors(self):
try:
# BMW X5 has separate motors for left and right steering
self.left_steer = self.getDevice('left_steer')
self.right_steer = self.getDevice('right_steer')
def initialize_path_planner(self):
# Try to load the CSV file with the road grid
try:
# Use raw string to avoid Unicode issues
csv_path = r"road_grid_poits_inflatesobstacles_2m.csv"
print(f"Looking for CSV at: {csv_path}")
self.planner = AStarPlanner(csv_path)
print("Successfully initialized path planner")
return True
except Exception as e:
print(f"Error in planner initialization: {str(e)}")
return False
def get_position_and_orientation(self):
"""Get position and orientation from supervisor API"""
try:
# Get position
pos = self.car.getPosition()
if pos is None:
print("Warning: Failed to get position from supervisor")
return (0, 0), 0.0