From 9ce538bf1fae57890327b2ac55ae3b090ff20ce2 Mon Sep 17 00:00:00 2001 From: XieTJ <2922472198@qq.com> Date: Sun, 19 Apr 2026 13:40:48 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=9C=BA=E6=99=AF?= =?UTF-8?q?=E5=88=87=E6=8D=A2=E5=8A=9F=E8=83=BD=EF=BC=88=E6=94=AF=E6=8C=81?= =?UTF-8?q?=E4=B8=8D=E5=90=8CCARLA=E5=9C=B0=E5=9B=BE=E9=97=B4=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E5=88=87=E6=8D=A2=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/car_navigation_system/main.py | 181 ++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 22 deletions(-) diff --git a/src/car_navigation_system/main.py b/src/car_navigation_system/main.py index 761eb2f457..9921357d7d 100644 --- a/src/car_navigation_system/main.py +++ b/src/car_navigation_system/main.py @@ -101,9 +101,12 @@ 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'] # 可用地图列表 def connect(self): """连接到CARLA服务器""" @@ -196,7 +199,7 @@ def spawn_vehicle(self): return False def setup_camera(self): - """设置相机""" + """设置多个相机""" print("正在设置相机...") try: @@ -208,37 +211,147 @@ 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) + + 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() + print("已恢复到Town01") + except Exception as e2: + print(f"恢复失败: {e2}") + + 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) @@ -287,6 +400,8 @@ def run(self): print(" r - 重置车辆") print(" s - 紧急停止") print(" x - 切换倒车/前进模式(速度为0时生效)") + print(" v - 切换视角(第一人称/第三人称/鸟瞰图)") + print(" m - 切换地图(Town01/Town02/Town03等)") print("\n开始自动驾驶...\n") frame_count = 0 @@ -336,6 +451,16 @@ 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.imshow('Autonomous Driving - Simple Version', display_img) @@ -358,6 +483,16 @@ 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() frame_count += 1 @@ -427,12 +562,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: From d874693e5ab2471aa7ebbcf2e388e73946cb5a4e Mon Sep 17 00:00:00 2001 From: XieTJ <2922472198@qq.com> Date: Wed, 29 Apr 2026 17:37:35 +0800 Subject: [PATCH 2/2] Add files via upload --- src/car_navigation_system/main.py | 191 ++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/src/car_navigation_system/main.py b/src/car_navigation_system/main.py index 9921357d7d..5ac34a7868 100644 --- a/src/car_navigation_system/main.py +++ b/src/car_navigation_system/main.py @@ -107,6 +107,28 @@ def __init__(self): 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 # 当前颜色索引 + self.screenshot_dir = 'screenshots' # 截图保存目录 def connect(self): """连接到CARLA服务器""" @@ -323,6 +345,9 @@ def switch_map(self): # 重新生成NPC车辆 self.spawn_npc_vehicles(2) + # 应用当前天气 + self.set_weather(self.current_weather) + print(f"地图切换成功: {self.current_map}") except Exception as e: @@ -339,10 +364,149 @@ def switch_map(self): 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 take_screenshot(self, image): + """保存当前画面截图""" + try: + import os + import time + + # 创建截图目录 + os.makedirs(self.screenshot_dir, exist_ok=True) + + # 获取当前时间戳 + timestamp = time.strftime("%Y%m%d_%H%M%S") + + # 获取当前地图名称 + map_name = self.current_map + + # 获取当前天气 + weather_name = self.current_weather + + # 获取当前颜色名称 + color_names = ['Red', 'Blue', 'Green', 'Yellow', 'Magenta', 'Cyan', 'Purple', 'Orange', 'Gray', 'White'] + color_name = color_names[self.current_color_index] + + # 生成文件名 + filename = f"screenshot_{timestamp}_{map_name}_{weather_name}_{color_name}.png" + filepath = os.path.join(self.screenshot_dir, filename) + + # 保存截图 + cv2.imwrite(filepath, image) + + print(f"截图已保存: {filepath}") + + except Exception as e: + print(f"保存截图时出错: {e}") + def get_view_name(self): """获取视角名称""" view_names = { @@ -402,6 +566,9 @@ def run(self): print(" x - 切换倒车/前进模式(速度为0时生效)") print(" v - 切换视角(第一人称/第三人称/鸟瞰图)") print(" m - 切换地图(Town01/Town02/Town03等)") + print(" w - 切换天气(晴天/雨天/多云/湿滑)") + print(" c - 切换车辆颜色") + print(" p - 保存当前画面截图") print("\n开始自动驾驶...\n") frame_count = 0 @@ -461,6 +628,18 @@ def run(self): 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) @@ -493,6 +672,18 @@ def run(self): elif key == ord('m'): # 切换地图 self.switch_map() + elif key == ord('w'): + # 切换天气 + self.switch_weather() + elif key == ord('c'): + # 切换车辆颜色 + self.switch_color() + elif key == ord('p'): + # 保存截图 + if self.camera_image is not None: + self.take_screenshot(self.camera_image) + else: + print("当前没有图像可保存") frame_count += 1