Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
330 changes: 308 additions & 22 deletions src/car_navigation_system/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,33 @@ def __init__(self):
self.client = None
self.world = None
self.vehicle = None
self.camera = None
self.cameras = {} # 存储多个相机
self.controller = None
self.camera_image = None
self.current_view = 'third_person' # 当前视角模式:'first_person', 'third_person', 'birdseye'
self.current_map = 'Town01' # 当前地图
self.available_maps = ['Town01', 'Town02', 'Town03', 'Town04', 'Town05', 'Town06', 'Town07'] # 可用地图列表
self.current_weather = 'clear' # 当前天气
# 简化天气预设,使用肯定存在的天气类型
self.weather_presets = {
'clear': carla.WeatherParameters.ClearNoon,
'rain': carla.WeatherParameters.HardRainNoon,
'cloudy': carla.WeatherParameters.CloudyNoon,
'wet': carla.WeatherParameters.WetNoon
} # 天气预设
self.car_colors = [
(255, 0, 0), # 红色
(0, 0, 255), # 蓝色
(0, 255, 0), # 绿色
(255, 255, 0), # 黄色
(255, 0, 255), # 品红色
(0, 255, 255), # 青色
(128, 0, 128), # 紫色
(255, 165, 0), # 橙色
(128, 128, 128), # 灰色
(255, 255, 255) # 白色
] # 车辆颜色列表
self.current_color_index = 0 # 当前颜色索引

def connect(self):
"""连接到CARLA服务器"""
Expand Down Expand Up @@ -196,7 +220,7 @@ def spawn_vehicle(self):
return False

def setup_camera(self):
"""设置相机"""
"""设置多个相机"""
print("正在设置相机...")

try:
Expand All @@ -208,37 +232,255 @@ def setup_camera(self):
camera_bp.set_attribute('image_size_y', '480')
camera_bp.set_attribute('fov', '90')

# 相机位置(车辆后方)
camera_transform = carla.Transform(
# 第一人称相机
first_person_transform = carla.Transform(
carla.Location(x=2.0, z=1.2), # 驾驶座位置
carla.Rotation(pitch=0.0) # 平视
)
first_person_camera = self.world.spawn_actor(
camera_bp, first_person_transform, attach_to=self.vehicle
)
first_person_camera.listen(lambda image: self.camera_callback(image, 'first_person'))
self.cameras['first_person'] = first_person_camera

# 第三人称相机
third_person_transform = carla.Transform(
carla.Location(x=-8.0, z=6.0), # 在车辆后方上方
carla.Rotation(pitch=-20.0) # 向下看
)

# 生成相机
self.camera = self.world.spawn_actor(
camera_bp, camera_transform, attach_to=self.vehicle
third_person_camera = self.world.spawn_actor(
camera_bp, third_person_transform, attach_to=self.vehicle
)
third_person_camera.listen(lambda image: self.camera_callback(image, 'third_person'))
self.cameras['third_person'] = third_person_camera

# 设置回调函数
self.camera.listen(lambda image: self.camera_callback(image))
# 鸟瞰图相机
birdseye_transform = carla.Transform(
carla.Location(x=0.0, z=30.0), # 车辆正上方30米
carla.Rotation(pitch=-90.0) # 垂直向下
)
birdseye_camera = self.world.spawn_actor(
camera_bp, birdseye_transform, attach_to=self.vehicle
)
birdseye_camera.listen(lambda image: self.camera_callback(image, 'birdseye'))
self.cameras['birdseye'] = birdseye_camera

print("相机设置成功")
print("相机设置成功 - 已创建三个视角相机")
return True

except Exception as e:
print(f"设置相机时出错: {e}")
return False

def camera_callback(self, image):
def camera_callback(self, image, view_mode=None):
"""相机数据回调"""
try:
# 转换图像数据
array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
array = np.reshape(array, (image.height, image.width, 4))
self.camera_image = array[:, :, :3] # RGB通道
# 只有当前视角的相机数据才会被使用
if view_mode == self.current_view:
# 转换图像数据
array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8"))
array = np.reshape(array, (image.height, image.width, 4))
self.camera_image = array[:, :, :3] # RGB通道
except:
pass

def update_camera_view(self):
"""更新相机视角"""
print(f"已切换到{self.get_view_name()}视角")

def switch_map(self):
"""切换到下一个地图"""
try:
# 停止所有相机
for view_mode, camera in self.cameras.items():
if camera:
try:
camera.stop()
camera.destroy()
except:
pass
self.cameras.clear()

# 销毁车辆
if self.vehicle:
try:
self.vehicle.destroy()
except:
pass
self.vehicle = None

# 等待清理完成
time.sleep(1.0)

# 切换到下一个地图
current_index = self.available_maps.index(self.current_map)
next_index = (current_index + 1) % len(self.available_maps)
new_map = self.available_maps[next_index]

print(f"正在加载地图: {new_map}...")

# 完全重新连接CARLA客户端
self.client = carla.Client('localhost', 2000)
self.client.set_timeout(10.0)

# 加载新地图
self.world = self.client.load_world(new_map)
self.current_map = new_map

# 等待地图完全加载
time.sleep(3.0)

# 重新生成车辆
if not self.spawn_vehicle():
raise Exception("车辆生成失败")

# 重新设置相机
if not self.setup_camera():
raise Exception("相机设置失败")

# 重新设置控制器
self.setup_controller()

# 重新生成NPC车辆
self.spawn_npc_vehicles(2)

# 应用当前天气
self.set_weather(self.current_weather)

print(f"地图切换成功: {self.current_map}")

except Exception as e:
print(f"切换地图时出错: {e}")
# 尝试重新加载Town01作为备份
try:
print("正在恢复到Town01...")
self.current_map = 'Town01'
time.sleep(1.0)
self.client = carla.Client('localhost', 2000)
self.client.set_timeout(10.0)
self.world = self.client.load_world(self.current_map)
time.sleep(3.0)
self.spawn_vehicle()
self.setup_camera()
self.setup_controller()
self.set_weather(self.current_weather)
print("已恢复到Town01")
except Exception as e2:
print(f"恢复失败: {e2}")

def set_weather(self, weather_type):
"""设置天气"""
try:
if weather_type in self.weather_presets:
weather = self.weather_presets[weather_type]
self.world.set_weather(weather)
self.current_weather = weather_type
print(f"天气设置成功: {weather_type}")
return True
else:
print(f"无效的天气类型: {weather_type}")
return False
except Exception as e:
print(f"设置天气时出错: {e}")
return False

def switch_weather(self):
"""切换到下一个天气"""
try:
weather_types = list(self.weather_presets.keys())
current_index = weather_types.index(self.current_weather)
next_index = (current_index + 1) % len(weather_types)
next_weather = weather_types[next_index]
self.set_weather(next_weather)
except Exception as e:
print(f"切换天气时出错: {e}")

def switch_color(self):
"""切换车辆颜色"""
try:
if self.vehicle:
# 获取当前车辆位置和方向
transform = self.vehicle.get_transform()

# 切换到下一个颜色
self.current_color_index = (self.current_color_index + 1) % len(self.car_colors)
color = self.car_colors[self.current_color_index]

# 获取颜色名称
color_names = ['Red', 'Blue', 'Green', 'Yellow', 'Magenta', 'Cyan', 'Purple', 'Orange', 'Gray', 'White']
color_name = color_names[self.current_color_index]

# 停止相机
for view_mode, camera in self.cameras.items():
if camera:
try:
camera.stop()
camera.destroy()
except:
pass
self.cameras.clear()

# 销毁当前车辆
self.vehicle.destroy()
self.vehicle = None

# 创建新车辆蓝图
blueprint_library = self.world.get_blueprint_library()
vehicle_bp = blueprint_library.find('vehicle.tesla.model3')
if not vehicle_bp:
vehicle_bp = blueprint_library.filter('vehicle.*')[0]

# 设置新颜色
vehicle_bp.set_attribute('color', f'{color[0]},{color[1]},{color[2]}')

# 首先尝试在相同位置生成新车辆
self.vehicle = self.world.try_spawn_actor(vehicle_bp, transform)

# 如果失败,尝试使用出生点
if not self.vehicle:
spawn_points = self.world.get_map().get_spawn_points()
for spawn_point in spawn_points[:5]: # 尝试前5个出生点
self.vehicle = self.world.try_spawn_actor(vehicle_bp, spawn_point)
if self.vehicle:
print("车辆已移动到新位置")
break

if self.vehicle:
# 禁用自动驾驶
self.vehicle.set_autopilot(False)

# 重新设置相机
self.setup_camera()

# 重新设置控制器
self.setup_controller()

print(f"车辆颜色已切换: {color_name}")
else:
print("无法生成新车辆,颜色切换失败")
# 重置颜色索引
self.current_color_index = (self.current_color_index - 1) % len(self.car_colors)
# 尝试恢复车辆
self.spawn_vehicle()
else:
print("车辆不存在,无法切换颜色")
except Exception as e:
print(f"切换车辆颜色时出错: {e}")
# 重置颜色索引
self.current_color_index = (self.current_color_index - 1) % len(self.car_colors)
# 尝试恢复车辆
if not self.vehicle:
self.spawn_vehicle()

def get_view_name(self):
"""获取视角名称"""
view_names = {
'first_person': 'First Person',
'third_person': 'Third Person',
'birdseye': 'Birds Eye'
}
return view_names.get(self.current_view, 'Unknown')

def setup_controller(self):
"""设置控制器"""
self.controller = SimpleController(self.world, self.vehicle)
Expand Down Expand Up @@ -287,6 +529,10 @@ def run(self):
print(" r - 重置车辆")
print(" s - 紧急停止")
print(" x - 切换倒车/前进模式(速度为0时生效)")
print(" v - 切换视角(第一人称/第三人称/鸟瞰图)")
print(" m - 切换地图(Town01/Town02/Town03等)")
print(" w - 切换天气(晴天/雨天/多云/湿滑)")
print(" c - 切换车辆颜色")
print("\n开始自动驾驶...\n")

frame_count = 0
Expand Down Expand Up @@ -336,6 +582,28 @@ def run(self):
cv2.putText(display_img, "REVERSE MODE",
(20, 200), cv2.FONT_HERSHEY_SIMPLEX,
0.8, (0, 0, 255), 2) # 红色显示

# 显示当前视角模式
cv2.putText(display_img, f"View: {self.get_view_name()}",
(20, 240), cv2.FONT_HERSHEY_SIMPLEX,
0.8, (0, 255, 0), 2) # 绿色显示

# 显示当前地图
cv2.putText(display_img, f"Map: {self.current_map}",
(20, 280), cv2.FONT_HERSHEY_SIMPLEX,
0.8, (255, 255, 0), 2) # 黄色显示

# 显示当前天气
cv2.putText(display_img, f"Weather: {self.current_weather}",
(20, 320), cv2.FONT_HERSHEY_SIMPLEX,
0.8, (255, 0, 255), 2) # 品红色显示

# 显示当前车辆颜色
color_names = ['Red', 'Blue', 'Green', 'Yellow', 'Magenta', 'Cyan', 'Purple', 'Orange', 'Gray', 'White']
current_color_name = color_names[self.current_color_index]
cv2.putText(display_img, f"Color: {current_color_name}",
(20, 360), cv2.FONT_HERSHEY_SIMPLEX,
0.8, (0, 128, 255), 2) # 橙色显示

cv2.imshow('Autonomous Driving - Simple Version', display_img)

Expand All @@ -358,6 +626,22 @@ def run(self):
self.controller.toggle_reverse()
else:
print("请先减速到接近停止(速度<1km/h)再切换倒车模式")
elif key == ord('v'):
# 切换视角模式
view_modes = ['third_person', 'first_person', 'birdseye']
current_index = view_modes.index(self.current_view)
next_index = (current_index + 1) % len(view_modes)
self.current_view = view_modes[next_index]
self.update_camera_view()
elif key == ord('m'):
# 切换地图
self.switch_map()
elif key == ord('w'):
# 切换天气
self.switch_weather()
elif key == ord('c'):
# 切换车辆颜色
self.switch_color()

frame_count += 1

Expand Down Expand Up @@ -427,12 +711,14 @@ def cleanup(self):
"""清理资源"""
print("\n正在清理资源...")

if self.camera:
try:
self.camera.stop()
self.camera.destroy()
except:
pass
# 清理所有相机
for view_mode, camera in self.cameras.items():
if camera:
try:
camera.stop()
camera.destroy()
except:
pass

if self.vehicle:
try:
Expand Down