From 78a15cd66a31d1b6e0c5d53947078668d05b476d Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Tue, 14 Apr 2026 11:22:50 +0800 Subject: [PATCH 01/28] Update CONTRIBUTORS.md --- .../ultralytics/nn/extra_modules/cutlass/CONTRIBUTORS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/yolo12_object_detection/scripts/ultralytics/nn/extra_modules/cutlass/CONTRIBUTORS.md b/src/yolo12_object_detection/scripts/ultralytics/nn/extra_modules/cutlass/CONTRIBUTORS.md index a4e0a2a435..b12d6088e1 100644 --- a/src/yolo12_object_detection/scripts/ultralytics/nn/extra_modules/cutlass/CONTRIBUTORS.md +++ b/src/yolo12_object_detection/scripts/ultralytics/nn/extra_modules/cutlass/CONTRIBUTORS.md @@ -45,7 +45,7 @@ Albert Xu Jack Yang Xiuxia Zhang Nick Zhao - +jokic ## ACKNOWLEDGEMENTS Girish Bharambe From 862859948e527fe6afcb9f50cbbfa12aa817e1c3 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Fri, 17 Apr 2026 16:32:51 +0800 Subject: [PATCH 02/28] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=B8=BB=E5=87=BD=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完成选题创建主函数 --- src/carla_ driving_car_lane/main.py | 87 +++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 src/carla_ driving_car_lane/main.py diff --git a/src/carla_ driving_car_lane/main.py b/src/carla_ driving_car_lane/main.py new file mode 100644 index 0000000000..19414cbd18 --- /dev/null +++ b/src/carla_ driving_car_lane/main.py @@ -0,0 +1,87 @@ +from common.transformations.camera import transform_img, eon_intrinsics +from common.transformations.model import medmodel_intrinsics +import numpy as np +from tqdm import tqdm +import matplotlib +import matplotlib.pyplot as plt + +import cv2 +from tensorflow.keras.models import load_model +from common.tools.lib.parser import parser +import cv2 +import sys +camerafile = sys.argv[1] +supercombo = load_model('models/supercombo.keras') + +MAX_DISTANCE = 140. +LANE_OFFSET = 1.8 +MAX_REL_V = 10. + +LEAD_X_SCALE = 10 +LEAD_Y_SCALE = 10 + +cap = cv2.VideoCapture(camerafile) + +imgs = [] + +for i in tqdm(range(1000)): + ret, frame = cap.read() + img_yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) + imgs.append(img_yuv.reshape((874*3//2, 1164))) + + +def frames_to_tensor(frames): + H = (frames.shape[1]*2)//3 + W = frames.shape[2] + in_img1 = np.zeros((frames.shape[0], 6, H//2, W//2), dtype=np.uint8) + + in_img1[:, 0] = frames[:, 0:H:2, 0::2] + in_img1[:, 1] = frames[:, 1:H:2, 0::2] + in_img1[:, 2] = frames[:, 0:H:2, 1::2] + in_img1[:, 3] = frames[:, 1:H:2, 1::2] + in_img1[:, 4] = frames[:, H:H+H//4].reshape((-1, H//2,W//2)) + in_img1[:, 5] = frames[:, H+H//4:H+H//2].reshape((-1, H//2,W//2)) + return in_img1 + +imgs_med_model = np.zeros((len(imgs), 384, 512), dtype=np.uint8) +for i, img in tqdm(enumerate(imgs)): + imgs_med_model[i] = transform_img(img, from_intr=eon_intrinsics, to_intr=medmodel_intrinsics, yuv=True, + output_size=(512,256)) +frame_tensors = frames_to_tensor(np.array(imgs_med_model)).astype(np.float32)/128.0 - 1.0 + + +state = np.zeros((1,512)) +desire = np.zeros((1,8)) + +cap = cv2.VideoCapture(camerafile) + +for i in tqdm(range(len(frame_tensors) - 1)): + inputs = [np.vstack(frame_tensors[i:i+2])[None], desire, state] + outs = supercombo.predict(inputs) + parsed = parser(outs) + # Important to refeed the state + state = outs[-1] + pose = outs[-2] + ret, frame = cap.read() + frame = cv2.resize(frame, (640, 420)) + # Show raw camera image + cv2.imshow("modeld", frame) + # Clean plot for next frame + plt.clf() + plt.title("lanes and path") + # lll = left lane line + plt.plot(parsed["lll"][0], range(0,192), "b-", linewidth=1) + # rll = right lane line + plt.plot(parsed["rll"][0], range(0, 192), "r-", linewidth=1) + # path = path cool isn't it ? + plt.plot(parsed["path"][0], range(0, 192), "g-", linewidth=1) + #print(np.array(pose[0,:3]).shape) + #plt.scatter(pose[0,:3], range(3), c="y") + + # Needed to invert axis because standart left lane is positive and right lane is negative, so we flip the x axis + plt.gca().invert_xaxis() + plt.pause(0.001) + if cv2.waitKey(10) & 0xFF == ord('q'): + break + +plt.show() From 818aabe366f864ca9ad971a32b13b52bb8e2cd35 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Fri, 17 Apr 2026 16:38:02 +0800 Subject: [PATCH 03/28] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=E5=B9=B6=E5=88=9B=E5=BB=BA=E4=B8=AD=E6=96=87=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 完成选题并创建中文文档 --- src/carla_ driving_car_lane/READMD.md | 43 +++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/carla_ driving_car_lane/READMD.md diff --git a/src/carla_ driving_car_lane/READMD.md b/src/carla_ driving_car_lane/READMD.md new file mode 100644 index 0000000000..5345a2f6db --- /dev/null +++ b/src/carla_ driving_car_lane/READMD.md @@ -0,0 +1,43 @@ + +====================================== + +## 自动驾驶车道与路径检测 + +====================================== + + +本项目基于 Windows11 与 Python 3.7 环境开发, +主要实现自动驾驶场景下的车道线识别与行驶路径实时检 +测,可对车载摄像头采集的视频流(如 .hevc 格式行车视频)进行解析,通过视觉算法识别道路车道线、规划安 +全行驶轨迹,为自动驾驶决策提供车道感知与路径引导支持。 +项目面向自动驾驶辅助系统(ADAS)的基础视觉感知模块,依赖系统底层库与 Python 机器学习 / 视觉处理工具链,可快速部署运行, + +完成对行车视频的离线车道与路径分析,适用于自动驾驶算法验证、智能驾驶教学实验等场景。 + + +# 操作系统 + Windows11 + +# Python + python Version 3.7 + + pip Version 21.3.1 + + Setuptools Version & Install + + pip3 install setuptools==45.2.0 + + (高版本卸载命令pip3 uninstall setuptools) + +# 安装依赖 + 安装库文件 + + sudo apt install libssl-dev libcurl4-openssl-dev curl + + sudo apt install libarchive-dev + +# 安装 + pip3 install -r requirements.txt + +# 运行程序 + python3 main.py ../sample.hevc From 730501a9d66298208353eda96f2aa5aa4acad850 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Mon, 20 Apr 2026 10:53:11 +0800 Subject: [PATCH 04/28] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=90=8D=E7=9A=84=E7=A9=BA=E7=99=BD=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/1.py | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/carla_driving_car_lane/1.py diff --git a/src/carla_driving_car_lane/1.py b/src/carla_driving_car_lane/1.py new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/src/carla_driving_car_lane/1.py @@ -0,0 +1 @@ + From fea2fe8adedec23f18cf80753c3f2cee4b561d4a Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Mon, 20 Apr 2026 10:54:21 +0800 Subject: [PATCH 05/28] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=E5=B9=B6=E5=88=9B=E5=BB=BA=E4=B8=BB=E7=A8=8B=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/1.py | 1 - src/carla_driving_car_lane/main.py | 88 ++++++++++++++++++++++++++++++ 2 files changed, 88 insertions(+), 1 deletion(-) delete mode 100644 src/carla_driving_car_lane/1.py create mode 100644 src/carla_driving_car_lane/main.py diff --git a/src/carla_driving_car_lane/1.py b/src/carla_driving_car_lane/1.py deleted file mode 100644 index 8b13789179..0000000000 --- a/src/carla_driving_car_lane/1.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/carla_driving_car_lane/main.py b/src/carla_driving_car_lane/main.py new file mode 100644 index 0000000000..3d1a3c34d7 --- /dev/null +++ b/src/carla_driving_car_lane/main.py @@ -0,0 +1,88 @@ + +from common.transformations.camera import transform_img, eon_intrinsics +from common.transformations.model import medmodel_intrinsics +import numpy as np +from tqdm import tqdm +import matplotlib +import matplotlib.pyplot as plt + +import cv2 +from tensorflow.keras.models import load_model +from common.tools.lib.parser import parser +import cv2 +import sys +camerafile = sys.argv[1] +supercombo = load_model('models/supercombo.keras') + +MAX_DISTANCE = 140. +LANE_OFFSET = 1.8 +MAX_REL_V = 10. + +LEAD_X_SCALE = 10 +LEAD_Y_SCALE = 10 + +cap = cv2.VideoCapture(camerafile) + +imgs = [] + +for i in tqdm(range(1000)): + ret, frame = cap.read() + img_yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) + imgs.append(img_yuv.reshape((874*3//2, 1164))) + + +def frames_to_tensor(frames): + H = (frames.shape[1]*2)//3 + W = frames.shape[2] + in_img1 = np.zeros((frames.shape[0], 6, H//2, W//2), dtype=np.uint8) + + in_img1[:, 0] = frames[:, 0:H:2, 0::2] + in_img1[:, 1] = frames[:, 1:H:2, 0::2] + in_img1[:, 2] = frames[:, 0:H:2, 1::2] + in_img1[:, 3] = frames[:, 1:H:2, 1::2] + in_img1[:, 4] = frames[:, H:H+H//4].reshape((-1, H//2,W//2)) + in_img1[:, 5] = frames[:, H+H//4:H+H//2].reshape((-1, H//2,W//2)) + return in_img1 + +imgs_med_model = np.zeros((len(imgs), 384, 512), dtype=np.uint8) +for i, img in tqdm(enumerate(imgs)): + imgs_med_model[i] = transform_img(img, from_intr=eon_intrinsics, to_intr=medmodel_intrinsics, yuv=True, + output_size=(512,256)) +frame_tensors = frames_to_tensor(np.array(imgs_med_model)).astype(np.float32)/128.0 - 1.0 + + +state = np.zeros((1,512)) +desire = np.zeros((1,8)) + +cap = cv2.VideoCapture(camerafile) + +for i in tqdm(range(len(frame_tensors) - 1)): + inputs = [np.vstack(frame_tensors[i:i+2])[None], desire, state] + outs = supercombo.predict(inputs) + parsed = parser(outs) + # Important to refeed the state + state = outs[-1] + pose = outs[-2] + ret, frame = cap.read() + frame = cv2.resize(frame, (640, 420)) + # Show raw camera image + cv2.imshow("modeld", frame) + # Clean plot for next frame + plt.clf() + plt.title("lanes and path") + # lll = left lane line + plt.plot(parsed["lll"][0], range(0,192), "b-", linewidth=1) + # rll = right lane line + plt.plot(parsed["rll"][0], range(0, 192), "r-", linewidth=1) + # path = path cool isn't it ? + plt.plot(parsed["path"][0], range(0, 192), "g-", linewidth=1) + #print(np.array(pose[0,:3]).shape) + #plt.scatter(pose[0,:3], range(3), c="y") + + # Needed to invert axis because standart left lane is positive and right lane is negative, so we flip the x axis + plt.gca().invert_xaxis() + plt.pause(0.001) + if cv2.waitKey(10) & 0xFF == ord('q'): + break + +plt.show() From 2124605797f62ef45a5ed239e8a9d2446fc45c1a Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Mon, 20 Apr 2026 10:54:48 +0800 Subject: [PATCH 06/28] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=B8=AD=E6=96=87?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/README.md | 43 ++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/carla_driving_car_lane/README.md diff --git a/src/carla_driving_car_lane/README.md b/src/carla_driving_car_lane/README.md new file mode 100644 index 0000000000..5345a2f6db --- /dev/null +++ b/src/carla_driving_car_lane/README.md @@ -0,0 +1,43 @@ + +====================================== + +## 自动驾驶车道与路径检测 + +====================================== + + +本项目基于 Windows11 与 Python 3.7 环境开发, +主要实现自动驾驶场景下的车道线识别与行驶路径实时检 +测,可对车载摄像头采集的视频流(如 .hevc 格式行车视频)进行解析,通过视觉算法识别道路车道线、规划安 +全行驶轨迹,为自动驾驶决策提供车道感知与路径引导支持。 +项目面向自动驾驶辅助系统(ADAS)的基础视觉感知模块,依赖系统底层库与 Python 机器学习 / 视觉处理工具链,可快速部署运行, + +完成对行车视频的离线车道与路径分析,适用于自动驾驶算法验证、智能驾驶教学实验等场景。 + + +# 操作系统 + Windows11 + +# Python + python Version 3.7 + + pip Version 21.3.1 + + Setuptools Version & Install + + pip3 install setuptools==45.2.0 + + (高版本卸载命令pip3 uninstall setuptools) + +# 安装依赖 + 安装库文件 + + sudo apt install libssl-dev libcurl4-openssl-dev curl + + sudo apt install libarchive-dev + +# 安装 + pip3 install -r requirements.txt + +# 运行程序 + python3 main.py ../sample.hevc From 85ea0de7330f1838023173cc86f565337c875334 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Mon, 20 Apr 2026 22:39:02 +0800 Subject: [PATCH 07/28] Delete src/carla_ driving_car_lane directory --- src/carla_ driving_car_lane/READMD.md | 43 ------------- src/carla_ driving_car_lane/main.py | 87 --------------------------- 2 files changed, 130 deletions(-) delete mode 100644 src/carla_ driving_car_lane/READMD.md delete mode 100644 src/carla_ driving_car_lane/main.py diff --git a/src/carla_ driving_car_lane/READMD.md b/src/carla_ driving_car_lane/READMD.md deleted file mode 100644 index 5345a2f6db..0000000000 --- a/src/carla_ driving_car_lane/READMD.md +++ /dev/null @@ -1,43 +0,0 @@ - -====================================== - -## 自动驾驶车道与路径检测 - -====================================== - - -本项目基于 Windows11 与 Python 3.7 环境开发, -主要实现自动驾驶场景下的车道线识别与行驶路径实时检 -测,可对车载摄像头采集的视频流(如 .hevc 格式行车视频)进行解析,通过视觉算法识别道路车道线、规划安 -全行驶轨迹,为自动驾驶决策提供车道感知与路径引导支持。 -项目面向自动驾驶辅助系统(ADAS)的基础视觉感知模块,依赖系统底层库与 Python 机器学习 / 视觉处理工具链,可快速部署运行, - -完成对行车视频的离线车道与路径分析,适用于自动驾驶算法验证、智能驾驶教学实验等场景。 - - -# 操作系统 - Windows11 - -# Python - python Version 3.7 - - pip Version 21.3.1 - - Setuptools Version & Install - - pip3 install setuptools==45.2.0 - - (高版本卸载命令pip3 uninstall setuptools) - -# 安装依赖 - 安装库文件 - - sudo apt install libssl-dev libcurl4-openssl-dev curl - - sudo apt install libarchive-dev - -# 安装 - pip3 install -r requirements.txt - -# 运行程序 - python3 main.py ../sample.hevc diff --git a/src/carla_ driving_car_lane/main.py b/src/carla_ driving_car_lane/main.py deleted file mode 100644 index 19414cbd18..0000000000 --- a/src/carla_ driving_car_lane/main.py +++ /dev/null @@ -1,87 +0,0 @@ -from common.transformations.camera import transform_img, eon_intrinsics -from common.transformations.model import medmodel_intrinsics -import numpy as np -from tqdm import tqdm -import matplotlib -import matplotlib.pyplot as plt - -import cv2 -from tensorflow.keras.models import load_model -from common.tools.lib.parser import parser -import cv2 -import sys -camerafile = sys.argv[1] -supercombo = load_model('models/supercombo.keras') - -MAX_DISTANCE = 140. -LANE_OFFSET = 1.8 -MAX_REL_V = 10. - -LEAD_X_SCALE = 10 -LEAD_Y_SCALE = 10 - -cap = cv2.VideoCapture(camerafile) - -imgs = [] - -for i in tqdm(range(1000)): - ret, frame = cap.read() - img_yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) - imgs.append(img_yuv.reshape((874*3//2, 1164))) - - -def frames_to_tensor(frames): - H = (frames.shape[1]*2)//3 - W = frames.shape[2] - in_img1 = np.zeros((frames.shape[0], 6, H//2, W//2), dtype=np.uint8) - - in_img1[:, 0] = frames[:, 0:H:2, 0::2] - in_img1[:, 1] = frames[:, 1:H:2, 0::2] - in_img1[:, 2] = frames[:, 0:H:2, 1::2] - in_img1[:, 3] = frames[:, 1:H:2, 1::2] - in_img1[:, 4] = frames[:, H:H+H//4].reshape((-1, H//2,W//2)) - in_img1[:, 5] = frames[:, H+H//4:H+H//2].reshape((-1, H//2,W//2)) - return in_img1 - -imgs_med_model = np.zeros((len(imgs), 384, 512), dtype=np.uint8) -for i, img in tqdm(enumerate(imgs)): - imgs_med_model[i] = transform_img(img, from_intr=eon_intrinsics, to_intr=medmodel_intrinsics, yuv=True, - output_size=(512,256)) -frame_tensors = frames_to_tensor(np.array(imgs_med_model)).astype(np.float32)/128.0 - 1.0 - - -state = np.zeros((1,512)) -desire = np.zeros((1,8)) - -cap = cv2.VideoCapture(camerafile) - -for i in tqdm(range(len(frame_tensors) - 1)): - inputs = [np.vstack(frame_tensors[i:i+2])[None], desire, state] - outs = supercombo.predict(inputs) - parsed = parser(outs) - # Important to refeed the state - state = outs[-1] - pose = outs[-2] - ret, frame = cap.read() - frame = cv2.resize(frame, (640, 420)) - # Show raw camera image - cv2.imshow("modeld", frame) - # Clean plot for next frame - plt.clf() - plt.title("lanes and path") - # lll = left lane line - plt.plot(parsed["lll"][0], range(0,192), "b-", linewidth=1) - # rll = right lane line - plt.plot(parsed["rll"][0], range(0, 192), "r-", linewidth=1) - # path = path cool isn't it ? - plt.plot(parsed["path"][0], range(0, 192), "g-", linewidth=1) - #print(np.array(pose[0,:3]).shape) - #plt.scatter(pose[0,:3], range(3), c="y") - - # Needed to invert axis because standart left lane is positive and right lane is negative, so we flip the x axis - plt.gca().invert_xaxis() - plt.pause(0.001) - if cv2.waitKey(10) & 0xFF == ord('q'): - break - -plt.show() From c1d908c2f3afeb84b70fa93d5347491158e43c4e Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 22 Apr 2026 19:19:31 +0800 Subject: [PATCH 08/28] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=B8=BB=E7=A8=8B?= =?UTF-8?q?=E5=BA=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/main.py | 425 +++++++++++++++++++++++------ 1 file changed, 339 insertions(+), 86 deletions(-) diff --git a/src/carla_driving_car_lane/main.py b/src/carla_driving_car_lane/main.py index 3d1a3c34d7..73752cec9d 100644 --- a/src/carla_driving_car_lane/main.py +++ b/src/carla_driving_car_lane/main.py @@ -1,88 +1,341 @@ +#!/usr/bin/env python -from common.transformations.camera import transform_img, eon_intrinsics -from common.transformations.model import medmodel_intrinsics -import numpy as np -from tqdm import tqdm -import matplotlib -import matplotlib.pyplot as plt - -import cv2 -from tensorflow.keras.models import load_model -from common.tools.lib.parser import parser -import cv2 +# Copyright (c) 2018 Intel Labs. +# authors: German Ros (german.ros@gmail.com) +# +# This work is licensed under the terms of the MIT license. +# For a copy, see + +"""Example of automatic vehicle control from client side.""" + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re import sys -camerafile = sys.argv[1] -supercombo = load_model('models/supercombo.keras') - -MAX_DISTANCE = 140. -LANE_OFFSET = 1.8 -MAX_REL_V = 10. - -LEAD_X_SCALE = 10 -LEAD_Y_SCALE = 10 - -cap = cv2.VideoCapture(camerafile) - -imgs = [] - -for i in tqdm(range(1000)): - ret, frame = cap.read() - img_yuv = cv2.cvtColor(frame, cv2.COLOR_BGR2YUV_I420) - imgs.append(img_yuv.reshape((874*3//2, 1164))) - - -def frames_to_tensor(frames): - H = (frames.shape[1]*2)//3 - W = frames.shape[2] - in_img1 = np.zeros((frames.shape[0], 6, H//2, W//2), dtype=np.uint8) - - in_img1[:, 0] = frames[:, 0:H:2, 0::2] - in_img1[:, 1] = frames[:, 1:H:2, 0::2] - in_img1[:, 2] = frames[:, 0:H:2, 1::2] - in_img1[:, 3] = frames[:, 1:H:2, 1::2] - in_img1[:, 4] = frames[:, H:H+H//4].reshape((-1, H//2,W//2)) - in_img1[:, 5] = frames[:, H+H//4:H+H//2].reshape((-1, H//2,W//2)) - return in_img1 - -imgs_med_model = np.zeros((len(imgs), 384, 512), dtype=np.uint8) -for i, img in tqdm(enumerate(imgs)): - imgs_med_model[i] = transform_img(img, from_intr=eon_intrinsics, to_intr=medmodel_intrinsics, yuv=True, - output_size=(512,256)) -frame_tensors = frames_to_tensor(np.array(imgs_med_model)).astype(np.float32)/128.0 - 1.0 - - -state = np.zeros((1,512)) -desire = np.zeros((1,8)) - -cap = cv2.VideoCapture(camerafile) - -for i in tqdm(range(len(frame_tensors) - 1)): - inputs = [np.vstack(frame_tensors[i:i+2])[None], desire, state] - outs = supercombo.predict(inputs) - parsed = parser(outs) - # Important to refeed the state - state = outs[-1] - pose = outs[-2] - ret, frame = cap.read() - frame = cv2.resize(frame, (640, 420)) - # Show raw camera image - cv2.imshow("modeld", frame) - # Clean plot for next frame - plt.clf() - plt.title("lanes and path") - # lll = left lane line - plt.plot(parsed["lll"][0], range(0,192), "b-", linewidth=1) - # rll = right lane line - plt.plot(parsed["rll"][0], range(0, 192), "r-", linewidth=1) - # path = path cool isn't it ? - plt.plot(parsed["path"][0], range(0, 192), "g-", linewidth=1) - #print(np.array(pose[0,:3]).shape) - #plt.scatter(pose[0,:3], range(3), c="y") - - # Needed to invert axis because standart left lane is positive and right lane is negative, so we flip the x axis - plt.gca().invert_xaxis() - plt.pause(0.001) - if cv2.waitKey(10) & 0xFF == ord('q'): - break - -plt.show() +import weakref + +# ========================================== +# 适配你的路径 D:\carla0.9.15 +# ========================================== +CARLA_ROOT = r"D:\carla0.9.15" +PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") +sys.path.append(PYTHON_API) +sys.path.append(os.path.join(PYTHON_API, "carla")) + +try: + eggs = glob.glob(os.path.join(PYTHON_API, "carla", "dist", "*.egg")) + for e in eggs: + sys.path.append(e) +except: + pass + +# ================= 依赖导入 ================= +try: + import pygame + from pygame.locals import KMOD_CTRL + from pygame.locals import K_ESCAPE + from pygame.locals import K_q +except ImportError: + raise RuntimeError('请安装:pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装:pip install numpy') + +import carla +from carla import ColorConverter as cc + +# 已删除不存在的 RoamingAgent +from agents.navigation.behavior_agent import BehaviorAgent +from agents.navigation.basic_agent import BasicAgent + +# ============================================================================== +# -- Global functions +# ============================================================================== +def find_weather_presets(): + rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] + return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +# ============================================================================== +# -- World +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._weather_presets = find_weather_presets() + self._weather_index = 0 + self._actor_filter = args.filter + self._gamma = 2.2 + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 + + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud, self._gamma) + self.camera_manager.transform_index = cam_pos_id + self.camera_manager.set_sensor(cam_index, notify=False) + + def next_weather(self, reverse=False): + self._weather_index += -1 if reverse else 1 + self._weather_index %= len(self._weather_presets) + preset = self._weather_presets[self._weather_index] + self.hud.notification('Weather: %s' % preset[1]) + self.world.set_weather(preset[0]) + + def tick(self, clock): + self.hud.tick(self, clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None: + actor.destroy() + +# ============================================================================== +# -- KeyboardControl +# ============================================================================== +class KeyboardControl(object): + def __init__(self, world): + world.hud.notification("Press ESC or Ctrl+Q to quit", seconds=2) + + def parse_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if self._is_quit_shortcut(event.key): + return True + return False + + @staticmethod + def _is_quit_shortcut(key): + return key == K_ESCAPE or (key == K_q and pygame.key.get_mod() & KMOD_CTRL) + +# ============================================================================== +# -- HUD +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / timestamp.delta_seconds + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, world, clock): + self._notifications.tick(world, clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def error(self, text): + self._notifications.set_text('Error: %s' % text, (255, 0, 0)) + + def render(self, display): + self._notifications.render(display) + +# ============================================================================== +# -- FadingText +# ============================================================================== +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2.0): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, _, clock): + self.seconds_left = max(0.0, self.seconds_left - clock.get_time() / 1000.0) + + def render(self, display): + display.blit(self.surface, self.pos) + +# ============================================================================== +# -- CollisionSensor +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.collision') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda e: self.hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) + +# ============================================================================== +# -- LaneInvasionSensor +# ============================================================================== +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + +# ============================================================================== +# -- GnssSensor +# ============================================================================== +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self.lat = self.lon = 0.0 + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.gnss') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(carla.Location(z=2.0)), attach_to=parent_actor) + +# ============================================================================== +# -- CameraManager +# ============================================================================== +class CameraManager(object): + def __init__(self, parent_actor, hud, gamma): + self.sensor = None + self.surface = None + self._parent = parent_actor + self.hud = hud + self.transform_index = 0 + self._camera_transforms = [ + (carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)), carla.AttachmentType.SpringArm) + ] + self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB']] + world = parent_actor.get_world() + for item in self.sensors: + b = world.get_blueprint_library().find(item[0]) + b.set_attribute('image_size_x', str(hud.dim[0])) + b.set_attribute('image_size_y', str(hud.dim[1])) + item.append(b) + self.index = None + + def set_sensor(self, index, notify=True): + if self.sensor: + self.sensor.destroy() + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[0][-1], + self._camera_transforms[0][0], + attach_to=self._parent + ) + self.sensor.listen(lambda img: self._parse_image(img)) + self.index = 0 + + def _parse_image(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4)[:, :, :3] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) + + def render(self, display): + if self.surface: + display.blit(self.surface, (0, 0)) + +# ============================================================================== +# -- Game Loop +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + controller = KeyboardControl(world) + + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + agent.set_destination(random.choice(spawn_points).location) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + control = agent.run_step() + world.player.apply_control(control) + + finally: + if world: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA Automatic Control Client') + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('-b', '--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + game_loop(args) + +if __name__ == '__main__': + main() From 0d64d6784a0a497634996359e43df6693fce883e Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 22 Apr 2026 19:22:29 +0800 Subject: [PATCH 09/28] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E4=B8=AD=E6=96=87?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/README.md | 64 ++++++++++++++-------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/src/carla_driving_car_lane/README.md b/src/carla_driving_car_lane/README.md index 5345a2f6db..abeadf0f5a 100644 --- a/src/carla_driving_car_lane/README.md +++ b/src/carla_driving_car_lane/README.md @@ -1,43 +1,45 @@ -====================================== - -## 自动驾驶车道与路径检测 - -====================================== +--- +## CARLA 0.9.15 交通灯检测与自动驾驶控制系统 -本项目基于 Windows11 与 Python 3.7 环境开发, -主要实现自动驾驶场景下的车道线识别与行驶路径实时检 -测,可对车载摄像头采集的视频流(如 .hevc 格式行车视频)进行解析,通过视觉算法识别道路车道线、规划安 -全行驶轨迹,为自动驾驶决策提供车道感知与路径引导支持。 -项目面向自动驾驶辅助系统(ADAS)的基础视觉感知模块,依赖系统底层库与 Python 机器学习 / 视觉处理工具链,可快速部署运行, -完成对行车视频的离线车道与路径分析,适用于自动驾驶算法验证、智能驾驶教学实验等场景。 +本项目基于 CARLA 仿真器(0.9.15 版本)实现了一套简易自动驾驶控制系统。系统通过摄像头数据检测交通信号灯,并控制车辆在红灯时停车、绿灯时通行。 +## 功能特性 +- **交通灯检测**:使用 RGB 摄像头与目标包围框实现交通灯识别 +- **启停逻辑**:车辆在红灯时自动停车,绿灯时自动恢复行驶 +- **自动驾驶控制**:根据交通灯状态自动调整油门与刹车 -# 操作系统 - Windows11 +## 使用技术 +- **仿真平台**:CARLA 仿真器 0.9.15 +- **编程语言**:Python 3.9 +- **依赖库**: + - pygame:用于渲染仿真界面 + - cv2(OpenCV):用于图像处理(可扩展功能) + - numpy、time、math、random:用于数值计算与时序控制 -# Python - python Version 3.7 - - pip Version 21.3.1 - - Setuptools Version & Install - - pip3 install setuptools==45.2.0 - - (高版本卸载命令pip3 uninstall setuptools) +## 工作原理 +1. **传感器配置** + 车辆搭载前置 RGB 摄像头及其他 CARLA 内置传感器。 -# 安装依赖 - 安装库文件 +2. **交通灯检测** + 脚本通过 CARLA 内置环境信息(目标包围框)检测交通灯, + 并判断信号灯状态(红灯/绿灯)。 - sudo apt install libssl-dev libcurl4-openssl-dev curl +3. **控制逻辑** + - 若前方检测到红灯,车辆自动刹车并停车 + - 若检测到绿灯或无有效红灯,车辆继续行驶 - sudo apt install libarchive-dev +## 运行方法 +1. 安装 Python 依赖库: + ```bash + pip install pygame opencv-python numpy + ``` +2. 使用方式: + 启动 `CarlaUE4.exe`(Windows 系统) -# 安装 - pip3 install -r requirements.txt +## 预期效果 +车辆在前方检测到红灯时平稳停车,绿灯亮起后恢复行驶,所有行为均由控制逻辑自动完成。 -# 运行程序 - python3 main.py ../sample.hevc +--- From 19eca7a487567a79c3d2733a20b8859dad45f991 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 22 Apr 2026 19:24:17 +0800 Subject: [PATCH 10/28] =?UTF-8?q?=E5=AE=89=E8=A3=85=E4=BE=9D=E8=B5=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/Requirements.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 src/carla_driving_car_lane/Requirements.txt diff --git a/src/carla_driving_car_lane/Requirements.txt b/src/carla_driving_car_lane/Requirements.txt new file mode 100644 index 0000000000..8437a15171 --- /dev/null +++ b/src/carla_driving_car_lane/Requirements.txt @@ -0,0 +1,9 @@ + +carla==0.9.15 +pygame==2.1.0 +numpy==1.23.5 +opencv-python==4.8.0.76 +matplotlib==3.7.1 +torch==2.0.0 # Only if you're using PyTorch for detection +torchvision==0.15.1 +Pillow==9.4.0 From 6bf2b7dcf580294f2020fe14a6f4f45f14585164 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 22 Apr 2026 22:12:25 +0800 Subject: [PATCH 11/28] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=90=AF=E5=8A=A8caela?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../start_carla_sim.bat | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/carla_driving_car_lane/start_carla_sim.bat diff --git a/src/carla_driving_car_lane/start_carla_sim.bat b/src/carla_driving_car_lane/start_carla_sim.bat new file mode 100644 index 0000000000..7383dbc8ae --- /dev/null +++ b/src/carla_driving_car_lane/start_carla_sim.bat @@ -0,0 +1,27 @@ +@echo off +chcp 65001 >nul 2>&1 +color 0A +mode con: cols=80 lines=25 +title CARLA AUTOPILOT + +echo ============================================== +echo CARLA 0.9.15 AUTOPILOT LAUNCHER +echo ============================================== +echo. + +echo Starting CARLA Simulator... +start "" "D:\carla0.9.15\CarlaUE4.exe" -quality-level=Low + +echo. +echo Waiting for CARLA server (15s)... +timeout /t 15 /nobreak >nul + +echo. +echo Starting autopilot script... +echo. + +"D:\carla_automatic1\.venv\Scripts\python.exe" "D:\carla_automatic1\automatic_control.py" + +echo. +echo Done. +pause From 8df8257889422f7b8d3086ce25a9bc019dea051a Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 23 Apr 2026 13:13:03 +0800 Subject: [PATCH 12/28] chuan --- .../automatic_control.py | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/carla_driving_car_lane/automatic_control.py diff --git a/src/carla_driving_car_lane/automatic_control.py b/src/carla_driving_car_lane/automatic_control.py new file mode 100644 index 0000000000..078bf9e2aa --- /dev/null +++ b/src/carla_driving_car_lane/automatic_control.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref + +# --------------- Python 3.9 专用修复 --------------- +# 清理冲突路径 +for path in list(sys.path): + if "carla/dist" in path and path.endswith(".egg"): + sys.path.remove(path) + +# 正确添加 CARLA PythonAPI 路径 +CARLA_ROOT = r"D:\carla0.9.15" +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI")) +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI", "carla")) + +# ---------------- 依赖 ---------------- +try: + import pygame + from pygame.locals import KMOD_CTRL + from pygame.locals import K_ESCAPE + from pygame.locals import K_q +except ImportError: + raise RuntimeError('请安装: pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装: pip install numpy') + +import carla +from carla import ColorConverter as cc + +# 导入自动驾驶代理 +from agents.navigation.behavior_agent import BehaviorAgent + + +# ============================================================================== +# -- 工具函数 +# ============================================================================== +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + + +# ============================================================================== +# -- World 场景管理 +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._actor_filter = args.filter + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + # 清理旧车辆 + if self.player is not None: + self.destroy() + + # 生成车辆 + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + # 传感器(全部修复完成) + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud) + self.camera_manager.set_sensor(0) + + def tick(self, clock): + self.hud.tick(clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + + +# ============================================================================== +# -- 键盘控制 +# ============================================================================== +class KeyboardControl(object): + @staticmethod + def parse_events(): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if event.key == K_ESCAPE or (event.key == K_q and pygame.key.get_mod() & KMOD_CTRL): + return True + return False + + +# ============================================================================== +# -- HUD 显示 +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.server_fps = 0 + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) + + def tick(self, clock): + self._notifications.tick(clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def render(self, display): + self._notifications.render(display) + + +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, clock): + self.seconds_left = max(0, self.seconds_left - clock.get_time() / 1000) + + def render(self, display): + display.blit(self.surface, self.pos) + + +# ============================================================================== +# -- 传感器(全部修复完成) +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.collision'), + carla.Transform(), attach_to=parent) + self.sensor.listen(lambda e: hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) + + +class LaneInvasionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), + carla.Transform(), attach_to=parent) + + +class GnssSensor(object): + def __init__(self, parent): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.gnss'), + carla.Transform(carla.Location(z=2.0)), attach_to=parent) + + +# ============================================================================== +# -- 相机 +# ============================================================================== +class CameraManager(object): + def __init__(self, parent, hud): + self.sensor = None + self.surface = None + self._parent = parent + self.hud = hud + self.index = 0 + + def set_sensor(self, index): + if self.sensor: self.sensor.destroy() + bp = self._parent.get_world().get_blueprint_library().find('sensor.camera.rgb') + bp.set_attribute('image_size_x', str(self.hud.dim[0])) + bp.set_attribute('image_size_y', str(self.hud.dim[1])) + + transform = carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)) + self.sensor = self._parent.get_world().spawn_actor( + bp, transform, attach_to=self._parent, attachment_type=carla.AttachmentType.SpringArm) + self.sensor.listen(lambda img: self._parse(img)) + + def _parse(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4)[:, :, :3] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) + + def render(self, display): + if self.surface: display.blit(self.surface, (0, 0)) + + +# ============================================================================== +# -- 主循环 +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height)) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + + # 自动导航 + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + target = random.choice(spawn_points).location + agent.set_destination(target) + hud.notification("自动导航已启动", 3) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if KeyboardControl.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + # 自动驾驶控制 + control = agent.run_step() + world.player.apply_control(control) + + # 到达目标后自动换新目标 + if agent.done(): + new_target = random.choice(spawn_points).location + agent.set_destination(new_target) + hud.notification("已到达!前往下一个目标", 2) + + finally: + if world: + world.destroy() + pygame.quit() + + +# ============================================================================== +# -- 主函数 +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser() + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + game_loop(args) + + +if __name__ == '__main__': + main() From ce90c9dfe7688c91af5d8f98560df98e30e27b7e Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 23 Apr 2026 13:16:01 +0800 Subject: [PATCH 13/28] c --- .../automatic_control/automatic_control.py | 291 ++++++++++++++++++ 1 file changed, 291 insertions(+) create mode 100644 src/carla_driving_car_lane/automatic_control/automatic_control.py diff --git a/src/carla_driving_car_lane/automatic_control/automatic_control.py b/src/carla_driving_car_lane/automatic_control/automatic_control.py new file mode 100644 index 0000000000..078bf9e2aa --- /dev/null +++ b/src/carla_driving_car_lane/automatic_control/automatic_control.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref + +# --------------- Python 3.9 专用修复 --------------- +# 清理冲突路径 +for path in list(sys.path): + if "carla/dist" in path and path.endswith(".egg"): + sys.path.remove(path) + +# 正确添加 CARLA PythonAPI 路径 +CARLA_ROOT = r"D:\carla0.9.15" +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI")) +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI", "carla")) + +# ---------------- 依赖 ---------------- +try: + import pygame + from pygame.locals import KMOD_CTRL + from pygame.locals import K_ESCAPE + from pygame.locals import K_q +except ImportError: + raise RuntimeError('请安装: pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装: pip install numpy') + +import carla +from carla import ColorConverter as cc + +# 导入自动驾驶代理 +from agents.navigation.behavior_agent import BehaviorAgent + + +# ============================================================================== +# -- 工具函数 +# ============================================================================== +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + + +# ============================================================================== +# -- World 场景管理 +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._actor_filter = args.filter + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + # 清理旧车辆 + if self.player is not None: + self.destroy() + + # 生成车辆 + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + # 传感器(全部修复完成) + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud) + self.camera_manager.set_sensor(0) + + def tick(self, clock): + self.hud.tick(clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + + +# ============================================================================== +# -- 键盘控制 +# ============================================================================== +class KeyboardControl(object): + @staticmethod + def parse_events(): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if event.key == K_ESCAPE or (event.key == K_q and pygame.key.get_mod() & KMOD_CTRL): + return True + return False + + +# ============================================================================== +# -- HUD 显示 +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.server_fps = 0 + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) + + def tick(self, clock): + self._notifications.tick(clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def render(self, display): + self._notifications.render(display) + + +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, clock): + self.seconds_left = max(0, self.seconds_left - clock.get_time() / 1000) + + def render(self, display): + display.blit(self.surface, self.pos) + + +# ============================================================================== +# -- 传感器(全部修复完成) +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.collision'), + carla.Transform(), attach_to=parent) + self.sensor.listen(lambda e: hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) + + +class LaneInvasionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), + carla.Transform(), attach_to=parent) + + +class GnssSensor(object): + def __init__(self, parent): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.gnss'), + carla.Transform(carla.Location(z=2.0)), attach_to=parent) + + +# ============================================================================== +# -- 相机 +# ============================================================================== +class CameraManager(object): + def __init__(self, parent, hud): + self.sensor = None + self.surface = None + self._parent = parent + self.hud = hud + self.index = 0 + + def set_sensor(self, index): + if self.sensor: self.sensor.destroy() + bp = self._parent.get_world().get_blueprint_library().find('sensor.camera.rgb') + bp.set_attribute('image_size_x', str(self.hud.dim[0])) + bp.set_attribute('image_size_y', str(self.hud.dim[1])) + + transform = carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)) + self.sensor = self._parent.get_world().spawn_actor( + bp, transform, attach_to=self._parent, attachment_type=carla.AttachmentType.SpringArm) + self.sensor.listen(lambda img: self._parse(img)) + + def _parse(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4)[:, :, :3] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) + + def render(self, display): + if self.surface: display.blit(self.surface, (0, 0)) + + +# ============================================================================== +# -- 主循环 +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height)) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + + # 自动导航 + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + target = random.choice(spawn_points).location + agent.set_destination(target) + hud.notification("自动导航已启动", 3) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if KeyboardControl.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + # 自动驾驶控制 + control = agent.run_step() + world.player.apply_control(control) + + # 到达目标后自动换新目标 + if agent.done(): + new_target = random.choice(spawn_points).location + agent.set_destination(new_target) + hud.notification("已到达!前往下一个目标", 2) + + finally: + if world: + world.destroy() + pygame.quit() + + +# ============================================================================== +# -- 主函数 +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser() + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + game_loop(args) + + +if __name__ == '__main__': + main() From 869c85f744b62c5d1767990d5796478aa7b4c8da Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 23 Apr 2026 19:54:09 +0800 Subject: [PATCH 14/28] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E9=A9=BE=E9=A9=B6?= =?UTF-8?q?=E6=98=BE=E9=80=9F=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../automatic_control/automatic2.0 | 322 ++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 src/carla_driving_car_lane/automatic_control/automatic2.0 diff --git a/src/carla_driving_car_lane/automatic_control/automatic2.0 b/src/carla_driving_car_lane/automatic_control/automatic2.0 new file mode 100644 index 0000000000..a1b277b65b --- /dev/null +++ b/src/carla_driving_car_lane/automatic_control/automatic2.0 @@ -0,0 +1,322 @@ +#!/usr/bin/env python + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref +import threading + +# --------------- Python 3.9 专用修复 --------------- +# 清理冲突路径 +for path in list(sys.path): + if "carla/dist" in path and path.endswith(".egg"): + sys.path.remove(path) + +# 正确添加 CARLA PythonAPI 路径 +CARLA_ROOT = r"D:\carla0.9.15" +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI")) +sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI", "carla")) + +# ---------------- 依赖 ---------------- +try: + import pygame + from pygame.locals import * +except ImportError: + raise RuntimeError('请安装: pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装: pip install numpy') + +import carla +from carla import ColorConverter as cc + +# 导入自动驾驶代理 +from agents.navigation.behavior_agent import BehaviorAgent + + +# ============================================================================== +# -- 工具函数 +# ============================================================================== +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +def play_warning_sound(): + """车道偏离语音提醒(异步播放不卡顿)""" + def play(): + try: + pygame.mixer.init() + warning = pygame.mixer.Sound("warning.wav") + warning.play() + except: + pass + threading.Thread(target=play, daemon=True).start() + + +# ============================================================================== +# -- World 场景管理 +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._actor_filter = args.filter + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + # 清理旧车辆 + if self.player is not None: + self.destroy() + + # 生成车辆 + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + # 传感器 + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud) + self.camera_manager.set_sensor(0) + + def tick(self, clock): + self.hud.tick(clock) + # 更新车速 + v = self.player.get_velocity() + speed = 3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2) + self.hud.speed = int(speed) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + + +# ============================================================================== +# -- 键盘控制(新增 P 键切换自动驾驶) +# ============================================================================== +class KeyboardControl(object): + def __init__(self): + self.auto_pilot = True + + def parse_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if event.key == K_ESCAPE or (event.key == K_q and pygame.key.get_mod() & KMOD_CTRL): + return True + if event.key == K_p: + self.auto_pilot = not self.auto_pilot + return False + + +# ============================================================================== +# -- HUD 显示(新增车速 + 模式显示) +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + self.font = pygame.font.Font(pygame.font.get_default_font(), 16) + self.font_big = pygame.font.Font(pygame.font.get_default_font(), 32) + self._notifications = FadingText(self.font, (width, 40), (0, height - 40)) + self.server_fps = 0 + self.speed = 0 + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) + + def tick(self, clock): + self._notifications.tick(clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def render(self, display): + # 车速 + speed_text = self.font_big.render(f"{self.speed} km/h", True, (0,255,255)) + display.blit(speed_text, (20,20)) + self._notifications.render(display) + + +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, clock): + self.seconds_left = max(0, self.seconds_left - clock.get_time() / 1000) + + def render(self, display): + display.blit(self.surface, self.pos) + + +# ============================================================================== +# -- 传感器 +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.collision'), + carla.Transform(), attach_to=parent) + self.sensor.listen(lambda e: hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) + + +class LaneInvasionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), + carla.Transform(), attach_to=parent) + self.sensor.listen(lambda e: self._on_lane(e, hud)) + + def _on_lane(self, event, hud): + hud.notification("车道偏离!") + play_warning_sound() + + +class GnssSensor(object): + def __init__(self, parent): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.gnss'), + carla.Transform(carla.Location(z=2.0)), attach_to=parent) + + +# ============================================================================== +# -- 相机 +# ============================================================================== +class CameraManager(object): + def __init__(self, parent, hud): + self.sensor = None + self.surface = None + self._parent = parent + self.hud = hud + self.index = 0 + + def set_sensor(self, index): + if self.sensor: self.sensor.destroy() + bp = self._parent.get_world().get_blueprint_library().find('sensor.camera.rgb') + bp.set_attribute('image_size_x', str(self.hud.dim[0])) + bp.set_attribute('image_size_y', str(self.hud.dim[1])) + + transform = carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)) + self.sensor = self._parent.get_world().spawn_actor( + bp, transform, attach_to=self._parent, attachment_type=carla.AttachmentType.SpringArm) + self.sensor.listen(lambda img: self._parse(img)) + + def _parse(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4)[:, :, :3] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) + + def render(self, display): + if self.surface: display.blit(self.surface, (0, 0)) + + +# ============================================================================== +# -- 主循环 +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + controller = KeyboardControl() + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height)) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + + # 自动导航 + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + target = random.choice(spawn_points).location + agent.set_destination(target) + hud.notification("自动导航已启动", 3) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + # 自动驾驶开关 + if controller.auto_pilot: + control = agent.run_step() + world.player.apply_control(control) + hud.notification("模式:自动驾驶", 1) + # 到达目标换新 + if agent.done(): + new_target = random.choice(spawn_points).location + agent.set_destination(new_target) + else: + hud.notification("模式:手动驾驶", 1) + + finally: + if world: + world.destroy() + pygame.quit() + + +# ============================================================================== +# -- 主函数 +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser() + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + game_loop(args) + + +if __name__ == '__main__': + main() From 92201d4f187c9ca4feb53ba14f7c2a0e57beff6f Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Fri, 24 Apr 2026 22:07:36 +0800 Subject: [PATCH 15/28] Delete src/carla_driving_car_lane/automatic_control/automatic_control.py --- .../automatic_control/automatic_control.py | 291 ------------------ 1 file changed, 291 deletions(-) delete mode 100644 src/carla_driving_car_lane/automatic_control/automatic_control.py diff --git a/src/carla_driving_car_lane/automatic_control/automatic_control.py b/src/carla_driving_car_lane/automatic_control/automatic_control.py deleted file mode 100644 index 078bf9e2aa..0000000000 --- a/src/carla_driving_car_lane/automatic_control/automatic_control.py +++ /dev/null @@ -1,291 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import argparse -import collections -import datetime -import glob -import logging -import math -import os -import random -import re -import sys -import weakref - -# --------------- Python 3.9 专用修复 --------------- -# 清理冲突路径 -for path in list(sys.path): - if "carla/dist" in path and path.endswith(".egg"): - sys.path.remove(path) - -# 正确添加 CARLA PythonAPI 路径 -CARLA_ROOT = r"D:\carla0.9.15" -sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI")) -sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI", "carla")) - -# ---------------- 依赖 ---------------- -try: - import pygame - from pygame.locals import KMOD_CTRL - from pygame.locals import K_ESCAPE - from pygame.locals import K_q -except ImportError: - raise RuntimeError('请安装: pip install pygame') - -try: - import numpy as np -except ImportError: - raise RuntimeError('请安装: pip install numpy') - -import carla -from carla import ColorConverter as cc - -# 导入自动驾驶代理 -from agents.navigation.behavior_agent import BehaviorAgent - - -# ============================================================================== -# -- 工具函数 -# ============================================================================== -def get_actor_display_name(actor, truncate=250): - name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) - return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name - - -# ============================================================================== -# -- World 场景管理 -# ============================================================================== -class World(object): - def __init__(self, carla_world, hud, args): - self.world = carla_world - self.map = self.world.get_map() - self.hud = hud - self.player = None - self.collision_sensor = None - self.lane_invasion_sensor = None - self.gnss_sensor = None - self.camera_manager = None - self._actor_filter = args.filter - self.restart(args) - self.world.on_tick(hud.on_world_tick) - - def restart(self, args): - # 清理旧车辆 - if self.player is not None: - self.destroy() - - # 生成车辆 - blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) - blueprint.set_attribute('role_name', 'hero') - - while self.player is None: - spawn_point = random.choice(self.map.get_spawn_points()) - self.player = self.world.try_spawn_actor(blueprint, spawn_point) - - # 传感器(全部修复完成) - self.collision_sensor = CollisionSensor(self.player, self.hud) - self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) - self.gnss_sensor = GnssSensor(self.player) - self.camera_manager = CameraManager(self.player, self.hud) - self.camera_manager.set_sensor(0) - - def tick(self, clock): - self.hud.tick(clock) - - def render(self, display): - self.camera_manager.render(display) - self.hud.render(display) - - def destroy(self): - actors = [ - self.camera_manager.sensor, - self.collision_sensor.sensor, - self.lane_invasion_sensor.sensor, - self.gnss_sensor.sensor, - self.player] - for actor in actors: - if actor is not None and actor.is_alive: - actor.destroy() - - -# ============================================================================== -# -- 键盘控制 -# ============================================================================== -class KeyboardControl(object): - @staticmethod - def parse_events(): - for event in pygame.event.get(): - if event.type == pygame.QUIT: - return True - if event.type == pygame.KEYUP: - if event.key == K_ESCAPE or (event.key == K_q and pygame.key.get_mod() & KMOD_CTRL): - return True - return False - - -# ============================================================================== -# -- HUD 显示 -# ============================================================================== -class HUD(object): - def __init__(self, width, height): - self.dim = (width, height) - font = pygame.font.Font(pygame.font.get_default_font(), 16) - self._notifications = FadingText(font, (width, 40), (0, height - 40)) - self.server_fps = 0 - - def on_world_tick(self, timestamp): - self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) - - def tick(self, clock): - self._notifications.tick(clock) - - def notification(self, text, seconds=2): - self._notifications.set_text(text, seconds=seconds) - - def render(self, display): - self._notifications.render(display) - - -class FadingText(object): - def __init__(self, font, dim, pos): - self.font = font - self.dim = dim - self.pos = pos - self.seconds_left = 0 - self.surface = pygame.Surface(self.dim) - - def set_text(self, text, color=(255, 255, 255), seconds=2): - self.seconds_left = seconds - self.surface = self.font.render(text, True, color) - - def tick(self, clock): - self.seconds_left = max(0, self.seconds_left - clock.get_time() / 1000) - - def render(self, display): - display.blit(self.surface, self.pos) - - -# ============================================================================== -# -- 传感器(全部修复完成) -# ============================================================================== -class CollisionSensor(object): - def __init__(self, parent, hud): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.collision'), - carla.Transform(), attach_to=parent) - self.sensor.listen(lambda e: hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) - - -class LaneInvasionSensor(object): - def __init__(self, parent, hud): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), - carla.Transform(), attach_to=parent) - - -class GnssSensor(object): - def __init__(self, parent): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.gnss'), - carla.Transform(carla.Location(z=2.0)), attach_to=parent) - - -# ============================================================================== -# -- 相机 -# ============================================================================== -class CameraManager(object): - def __init__(self, parent, hud): - self.sensor = None - self.surface = None - self._parent = parent - self.hud = hud - self.index = 0 - - def set_sensor(self, index): - if self.sensor: self.sensor.destroy() - bp = self._parent.get_world().get_blueprint_library().find('sensor.camera.rgb') - bp.set_attribute('image_size_x', str(self.hud.dim[0])) - bp.set_attribute('image_size_y', str(self.hud.dim[1])) - - transform = carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)) - self.sensor = self._parent.get_world().spawn_actor( - bp, transform, attach_to=self._parent, attachment_type=carla.AttachmentType.SpringArm) - self.sensor.listen(lambda img: self._parse(img)) - - def _parse(self, image): - array = np.frombuffer(image.raw_data, dtype=np.uint8) - array = array.reshape(image.height, image.width, 4)[:, :, :3] - self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) - - def render(self, display): - if self.surface: display.blit(self.surface, (0, 0)) - - -# ============================================================================== -# -- 主循环 -# ============================================================================== -def game_loop(args): - pygame.init() - pygame.font.init() - world = None - - try: - client = carla.Client(args.host, args.port) - client.set_timeout(10.0) - display = pygame.display.set_mode((args.width, args.height)) - hud = HUD(args.width, args.height) - world = World(client.get_world(), hud, args) - - # 自动导航 - agent = BehaviorAgent(world.player, behavior=args.behavior) - spawn_points = world.map.get_spawn_points() - target = random.choice(spawn_points).location - agent.set_destination(target) - hud.notification("自动导航已启动", 3) - - clock = pygame.time.Clock() - - while True: - clock.tick_busy_loop(60) - if KeyboardControl.parse_events(): - return - - world.tick(clock) - world.render(display) - pygame.display.flip() - - # 自动驾驶控制 - control = agent.run_step() - world.player.apply_control(control) - - # 到达目标后自动换新目标 - if agent.done(): - new_target = random.choice(spawn_points).location - agent.set_destination(new_target) - hud.notification("已到达!前往下一个目标", 2) - - finally: - if world: - world.destroy() - pygame.quit() - - -# ============================================================================== -# -- 主函数 -# ============================================================================== -def main(): - argparser = argparse.ArgumentParser() - argparser.add_argument('--host', default='127.0.0.1') - argparser.add_argument('--port', default=2000, type=int) - argparser.add_argument('--res', default='1280x720') - argparser.add_argument('--filter', default='vehicle.*') - argparser.add_argument('--behavior', default='normal') - args = argparser.parse_args() - args.width, args.height = map(int, args.res.split('x')) - game_loop(args) - - -if __name__ == '__main__': - main() From a1fefb740e25fbb4b88c5f4808c0e83fc933abc1 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Mon, 27 Apr 2026 18:05:57 +0800 Subject: [PATCH 16/28] Rename automatic2.0 to automatic2.py --- .../automatic_control/{automatic2.0 => automatic2.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/carla_driving_car_lane/automatic_control/{automatic2.0 => automatic2.py} (100%) diff --git a/src/carla_driving_car_lane/automatic_control/automatic2.0 b/src/carla_driving_car_lane/automatic_control/automatic2.py similarity index 100% rename from src/carla_driving_car_lane/automatic_control/automatic2.0 rename to src/carla_driving_car_lane/automatic_control/automatic2.py From 25aaef372719dc6e9408cdadb6d865c275e0b328 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Tue, 28 Apr 2026 00:04:28 +0800 Subject: [PATCH 17/28] Delete src/carla_driving_car_lane/automatic_control directory --- .../automatic_control/automatic2.py | 322 ------------------ 1 file changed, 322 deletions(-) delete mode 100644 src/carla_driving_car_lane/automatic_control/automatic2.py diff --git a/src/carla_driving_car_lane/automatic_control/automatic2.py b/src/carla_driving_car_lane/automatic_control/automatic2.py deleted file mode 100644 index a1b277b65b..0000000000 --- a/src/carla_driving_car_lane/automatic_control/automatic2.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function - -import argparse -import collections -import datetime -import glob -import logging -import math -import os -import random -import re -import sys -import weakref -import threading - -# --------------- Python 3.9 专用修复 --------------- -# 清理冲突路径 -for path in list(sys.path): - if "carla/dist" in path and path.endswith(".egg"): - sys.path.remove(path) - -# 正确添加 CARLA PythonAPI 路径 -CARLA_ROOT = r"D:\carla0.9.15" -sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI")) -sys.path.append(os.path.join(CARLA_ROOT, "PythonAPI", "carla")) - -# ---------------- 依赖 ---------------- -try: - import pygame - from pygame.locals import * -except ImportError: - raise RuntimeError('请安装: pip install pygame') - -try: - import numpy as np -except ImportError: - raise RuntimeError('请安装: pip install numpy') - -import carla -from carla import ColorConverter as cc - -# 导入自动驾驶代理 -from agents.navigation.behavior_agent import BehaviorAgent - - -# ============================================================================== -# -- 工具函数 -# ============================================================================== -def get_actor_display_name(actor, truncate=250): - name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) - return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name - -def play_warning_sound(): - """车道偏离语音提醒(异步播放不卡顿)""" - def play(): - try: - pygame.mixer.init() - warning = pygame.mixer.Sound("warning.wav") - warning.play() - except: - pass - threading.Thread(target=play, daemon=True).start() - - -# ============================================================================== -# -- World 场景管理 -# ============================================================================== -class World(object): - def __init__(self, carla_world, hud, args): - self.world = carla_world - self.map = self.world.get_map() - self.hud = hud - self.player = None - self.collision_sensor = None - self.lane_invasion_sensor = None - self.gnss_sensor = None - self.camera_manager = None - self._actor_filter = args.filter - self.restart(args) - self.world.on_tick(hud.on_world_tick) - - def restart(self, args): - # 清理旧车辆 - if self.player is not None: - self.destroy() - - # 生成车辆 - blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) - blueprint.set_attribute('role_name', 'hero') - - while self.player is None: - spawn_point = random.choice(self.map.get_spawn_points()) - self.player = self.world.try_spawn_actor(blueprint, spawn_point) - - # 传感器 - self.collision_sensor = CollisionSensor(self.player, self.hud) - self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) - self.gnss_sensor = GnssSensor(self.player) - self.camera_manager = CameraManager(self.player, self.hud) - self.camera_manager.set_sensor(0) - - def tick(self, clock): - self.hud.tick(clock) - # 更新车速 - v = self.player.get_velocity() - speed = 3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2) - self.hud.speed = int(speed) - - def render(self, display): - self.camera_manager.render(display) - self.hud.render(display) - - def destroy(self): - actors = [ - self.camera_manager.sensor, - self.collision_sensor.sensor, - self.lane_invasion_sensor.sensor, - self.gnss_sensor.sensor, - self.player] - for actor in actors: - if actor is not None and actor.is_alive: - actor.destroy() - - -# ============================================================================== -# -- 键盘控制(新增 P 键切换自动驾驶) -# ============================================================================== -class KeyboardControl(object): - def __init__(self): - self.auto_pilot = True - - def parse_events(self): - for event in pygame.event.get(): - if event.type == pygame.QUIT: - return True - if event.type == pygame.KEYUP: - if event.key == K_ESCAPE or (event.key == K_q and pygame.key.get_mod() & KMOD_CTRL): - return True - if event.key == K_p: - self.auto_pilot = not self.auto_pilot - return False - - -# ============================================================================== -# -- HUD 显示(新增车速 + 模式显示) -# ============================================================================== -class HUD(object): - def __init__(self, width, height): - self.dim = (width, height) - self.font = pygame.font.Font(pygame.font.get_default_font(), 16) - self.font_big = pygame.font.Font(pygame.font.get_default_font(), 32) - self._notifications = FadingText(self.font, (width, 40), (0, height - 40)) - self.server_fps = 0 - self.speed = 0 - - def on_world_tick(self, timestamp): - self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) - - def tick(self, clock): - self._notifications.tick(clock) - - def notification(self, text, seconds=2): - self._notifications.set_text(text, seconds=seconds) - - def render(self, display): - # 车速 - speed_text = self.font_big.render(f"{self.speed} km/h", True, (0,255,255)) - display.blit(speed_text, (20,20)) - self._notifications.render(display) - - -class FadingText(object): - def __init__(self, font, dim, pos): - self.font = font - self.dim = dim - self.pos = pos - self.seconds_left = 0 - self.surface = pygame.Surface(self.dim) - - def set_text(self, text, color=(255, 255, 255), seconds=2): - self.seconds_left = seconds - self.surface = self.font.render(text, True, color) - - def tick(self, clock): - self.seconds_left = max(0, self.seconds_left - clock.get_time() / 1000) - - def render(self, display): - display.blit(self.surface, self.pos) - - -# ============================================================================== -# -- 传感器 -# ============================================================================== -class CollisionSensor(object): - def __init__(self, parent, hud): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.collision'), - carla.Transform(), attach_to=parent) - self.sensor.listen(lambda e: hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) - - -class LaneInvasionSensor(object): - def __init__(self, parent, hud): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), - carla.Transform(), attach_to=parent) - self.sensor.listen(lambda e: self._on_lane(e, hud)) - - def _on_lane(self, event, hud): - hud.notification("车道偏离!") - play_warning_sound() - - -class GnssSensor(object): - def __init__(self, parent): - self.sensor = parent.get_world().spawn_actor( - parent.get_world().get_blueprint_library().find('sensor.other.gnss'), - carla.Transform(carla.Location(z=2.0)), attach_to=parent) - - -# ============================================================================== -# -- 相机 -# ============================================================================== -class CameraManager(object): - def __init__(self, parent, hud): - self.sensor = None - self.surface = None - self._parent = parent - self.hud = hud - self.index = 0 - - def set_sensor(self, index): - if self.sensor: self.sensor.destroy() - bp = self._parent.get_world().get_blueprint_library().find('sensor.camera.rgb') - bp.set_attribute('image_size_x', str(self.hud.dim[0])) - bp.set_attribute('image_size_y', str(self.hud.dim[1])) - - transform = carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)) - self.sensor = self._parent.get_world().spawn_actor( - bp, transform, attach_to=self._parent, attachment_type=carla.AttachmentType.SpringArm) - self.sensor.listen(lambda img: self._parse(img)) - - def _parse(self, image): - array = np.frombuffer(image.raw_data, dtype=np.uint8) - array = array.reshape(image.height, image.width, 4)[:, :, :3] - self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) - - def render(self, display): - if self.surface: display.blit(self.surface, (0, 0)) - - -# ============================================================================== -# -- 主循环 -# ============================================================================== -def game_loop(args): - pygame.init() - pygame.font.init() - world = None - controller = KeyboardControl() - - try: - client = carla.Client(args.host, args.port) - client.set_timeout(10.0) - display = pygame.display.set_mode((args.width, args.height)) - hud = HUD(args.width, args.height) - world = World(client.get_world(), hud, args) - - # 自动导航 - agent = BehaviorAgent(world.player, behavior=args.behavior) - spawn_points = world.map.get_spawn_points() - target = random.choice(spawn_points).location - agent.set_destination(target) - hud.notification("自动导航已启动", 3) - - clock = pygame.time.Clock() - - while True: - clock.tick_busy_loop(60) - if controller.parse_events(): - return - - world.tick(clock) - world.render(display) - pygame.display.flip() - - # 自动驾驶开关 - if controller.auto_pilot: - control = agent.run_step() - world.player.apply_control(control) - hud.notification("模式:自动驾驶", 1) - # 到达目标换新 - if agent.done(): - new_target = random.choice(spawn_points).location - agent.set_destination(new_target) - else: - hud.notification("模式:手动驾驶", 1) - - finally: - if world: - world.destroy() - pygame.quit() - - -# ============================================================================== -# -- 主函数 -# ============================================================================== -def main(): - argparser = argparse.ArgumentParser() - argparser.add_argument('--host', default='127.0.0.1') - argparser.add_argument('--port', default=2000, type=int) - argparser.add_argument('--res', default='1280x720') - argparser.add_argument('--filter', default='vehicle.*') - argparser.add_argument('--behavior', default='normal') - args = argparser.parse_args() - args.width, args.height = map(int, args.res.split('x')) - game_loop(args) - - -if __name__ == '__main__': - main() From fad52c333d7e3590dee66bd70ba61b2043a59621 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Tue, 28 Apr 2026 00:24:00 +0800 Subject: [PATCH 18/28] =?UTF-8?q?=E6=94=B9=E5=8F=98=E5=A4=A9=E6=B0=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Add_weather_switching.py | 342 ++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 src/carla_driving_car_lane/Add_weather_switching.py diff --git a/src/carla_driving_car_lane/Add_weather_switching.py b/src/carla_driving_car_lane/Add_weather_switching.py new file mode 100644 index 0000000000..28cb478900 --- /dev/null +++ b/src/carla_driving_car_lane/Add_weather_switching.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python + +# Copyright (c) 2018 Intel Labs. +# authors: German Ros (german.ros@gmail.com) +# +# This work is licensed under the terms of the MIT license. +# For a copy, see + +"""Example of automatic vehicle control from client side.""" + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref + +# ========================================== +# 适配你的路径 D:\carla0.9.15 +# ========================================== +CARLA_ROOT = r"D:\carla0.9.15" +PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") +sys.path.append(PYTHON_API) +sys.path.append(os.path.join(PYTHON_API, "carla")) + +try: + eggs = glob.glob(os.path.join(PYTHON_API, "carla", "dist", "*.egg")) + for e in eggs: + sys.path.append(e) +except: + pass + +# ================= 依赖导入 ================= +try: + import pygame + from pygame.locals import * +except ImportError: + raise RuntimeError('请安装:pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装:pip install numpy') + +import carla +from carla import ColorConverter as cc + +from agents.navigation.behavior_agent import BehaviorAgent + +# ============================================================================== +# -- Global functions +# ============================================================================== +def find_weather_presets(): + rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] + return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +# ============================================================================== +# -- World +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._weather_presets = find_weather_presets() + self._weather_index = 0 + self._actor_filter = args.filter + self._gamma = 2.2 + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 + + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud, self._gamma) + self.camera_manager.transform_index = cam_pos_id + self.camera_manager.set_sensor(cam_index, notify=False) + + def next_weather(self, reverse=False): + self._weather_index += -1 if reverse else 1 + self._weather_index %= len(self._weather_presets) + preset = self._weather_presets[self._weather_index] + self.hud.notification('Weather: %s' % preset[1]) + self.world.set_weather(preset[0]) + + def tick(self, clock): + self.hud.tick(clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None: + actor.destroy() + +# ============================================================================== +# -- KeyboardControl +# ============================================================================== +class KeyboardControl(object): + def __init__(self, world): + world.hud.notification("Press ESC or Ctrl+Q to quit", seconds=2) + world.hud.notification("PageUp / PageDown: Change Weather", seconds=2) + + def parse_events(self, world): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if self._is_quit_shortcut(event.key): + return True + if event.key == K_PAGEUP: + world.next_weather(reverse=True) + if event.key == K_PAGEDOWN: + world.next_weather() + return False + + @staticmethod + def _is_quit_shortcut(key): + return key == K_ESCAPE or (key == K_q and pygame.key.get_mod() & KMOD_CTRL) + +# ============================================================================== +# -- HUD +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / timestamp.delta_seconds + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, clock): + self._notifications.tick(clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def error(self, text): + self._notifications.set_text('Error: %s' % text, (255, 0, 0)) + + def render(self, display): + self._notifications.render(display) + +# ============================================================================== +# -- FadingText +# ============================================================================== +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2.0): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, clock): + self.seconds_left = max(0.0, self.seconds_left - clock.get_time() / 1000.0) + + def render(self, display): + display.blit(self.surface, self.pos) + +# ============================================================================== +# -- CollisionSensor +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.collision') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda e: self.hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) + +# ============================================================================== +# -- LaneInvasionSensor +# ============================================================================== +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + +# ============================================================================== +# -- GnssSensor +# ============================================================================== +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self.lat = self.lon = 0.0 + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.gnss') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(carla.Location(z=2.0)), attach_to=parent_actor) + +# ============================================================================== +# -- CameraManager +# ============================================================================== +class CameraManager(object): + def __init__(self, parent_actor, hud, gamma): + self.sensor = None + self.surface = None + self._parent = parent_actor + self.hud = hud + self.transform_index = 0 + self._camera_transforms = [ + (carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)), carla.AttachmentType.SpringArm) + ] + self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB']] + world = parent_actor.get_world() + for item in self.sensors: + b = world.get_blueprint_library().find(item[0]) + b.set_attribute('image_size_x', str(hud.dim[0])) + b.set_attribute('image_size_y', str(hud.dim[1])) + item.append(b) + self.index = None + + def set_sensor(self, index, notify=True): + if self.sensor: + self.sensor.destroy() + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[0][-1], + self._camera_transforms[0][0], + attach_to=self._parent + ) + self.sensor.listen(lambda img: self._parse_image(img)) + self.index = 0 + + def _parse_image(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4)[:, :, :3] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)[:, :, ::-1]) + + def render(self, display): + if self.surface: + display.blit(self.surface, (0, 0)) + +# ============================================================================== +# -- Game Loop +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + controller = KeyboardControl(world) + + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + agent.set_destination(random.choice(spawn_points).location) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(world): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + control = agent.run_step() + world.player.apply_control(control) + + finally: + if world: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA Automatic Control Client') + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('-b', '--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + game_loop(args) + +if __name__ == '__main__': + main() From ec71263e02b9ec2bcedb301cfd52107fe013c1be Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Tue, 28 Apr 2026 23:28:26 +0800 Subject: [PATCH 19/28] =?UTF-8?q?=E5=9D=90=E6=A0=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../World_Coordinate.py | 417 ++++++++++++++++++ 1 file changed, 417 insertions(+) create mode 100644 src/carla_driving_car_lane/World_Coordinate.py diff --git a/src/carla_driving_car_lane/World_Coordinate.py b/src/carla_driving_car_lane/World_Coordinate.py new file mode 100644 index 0000000000..7c7195eba2 --- /dev/null +++ b/src/carla_driving_car_lane/World_Coordinate.py @@ -0,0 +1,417 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Intel Labs. +# authors: German Ros (german.ros@gmail.com) +# This work is licensed under the terms of the MIT license. +# For a copy, see + +""" +CARLA Automatic Control Client +适配:Python 3.9 + CARLA 0.9.15 +功能:自动导航行驶 + 传感器 + HUD 显示 +""" + +from __future__ import print_function + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import time +import weakref + +# ========================================== +# 你的 CARLA 路径(保持不变) +# ========================================== +CARLA_ROOT = r"D:\carla0.9.15" +PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") +sys.path.append(PYTHON_API) +sys.path.append(os.path.join(PYTHON_API, "carla")) + +try: + eggs = glob.glob(os.path.join(PYTHON_API, "carla", "dist", "*.egg")) + for e in eggs: + sys.path.append(e) +except: + pass + +# ================= 依赖 ================= +try: + import pygame + from pygame.locals import K_ESCAPE, K_q, KMOD_CTRL, K_PAGEUP, K_PAGEDOWN +except ImportError: + raise RuntimeError('请安装:pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装:pip install numpy') + +import carla +from carla import ColorConverter as cc + +from agents.navigation.behavior_agent import BehaviorAgent + +# ============================================================================== +# -- Global functions +# ============================================================================== +def find_weather_presets(): + rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] + return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +# ============================================================================== +# -- World +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._weather_presets = find_weather_presets() + self._weather_index = 0 + self._actor_filter = args.filter + self._gamma = 2.2 + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 + + blueprint_library = self.world.get_blueprint_library() + blueprint = random.choice(blueprint_library.filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud, self._gamma) + self.camera_manager.transform_index = cam_pos_id + self.camera_manager.set_sensor(cam_index, notify=False) + + def next_weather(self, reverse=False): + self._weather_index += -1 if reverse else 1 + self._weather_index %= len(self._weather_presets) + preset = self._weather_presets[self._weather_index] + self.hud.notification('天气: %s' % preset[1]) + self.world.set_weather(preset[0]) + + def tick(self, clock): + self.hud.tick(clock, self) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + +# ============================================================================== +# -- KeyboardControl +# ============================================================================== +class KeyboardControl(object): + def __init__(self, world): + world.hud.notification("按 ESC 或 Ctrl+Q 退出", 2) + world.hud.notification("PageUp/PageDown: 切换天气", 2) + + def parse_events(self, world): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if self._is_quit_shortcut(event.key): + return True + if event.key == K_PAGEUP: + world.next_weather(reverse=True) + if event.key == K_PAGEDOWN: + world.next_weather() + return False + + @staticmethod + def _is_quit_shortcut(key): + return key == K_ESCAPE or (key == K_q and pygame.key.get_mods() & KMOD_CTRL) + +# ============================================================================== +# -- HUD (显示车速、GPS、信息) +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.font = font + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, clock, world): + self._notifications.tick(clock) + if not world.player: + return + v = world.player.get_velocity() + speed = round(3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2), 1) + lat = round(world.gnss_sensor.lat, 6) + lon = round(world.gnss_sensor.lon, 6) + self.speed = speed + self.lat = lat + self.lon = lon + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def error(self, text): + self._notifications.set_text('错误: %s' % text, (255, 0, 0)) + + def render(self, display): + if self._show_info: + info_text = [ + "FPS: %.1f" % self.server_fps, + "车速: %.1f km/h" % getattr(self, 'speed', 0), + "纬度: %.6f" % getattr(self, 'lat', 0), + "经度: %.6f" % getattr(self, 'lon', 0) + ] + y = 10 + for s in info_text: + surf = self.font.render(s, True, (255,255,255)) + display.blit(surf, (10, y)) + y += 20 + self._notifications.render(display) + +# ============================================================================== +# -- FadingText +# ============================================================================== +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2.0): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, clock): + self.seconds_left = max(0.0, self.seconds_left - clock.get_time() / 1000.0) + + def render(self, display): + alpha = int(255 * (self.seconds_left / 2.0)) if self.seconds_left > 0 else 0 + self.surface.set_alpha(alpha) + display.blit(self.surface, self.pos) + +# ============================================================================== +# -- CollisionSensor +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + world = parent_actor.get_world() + bp = world.get_blueprint_library().find('sensor.other.collision') + self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) + + @staticmethod + def _on_collision(weak_self, event): + self = weak_self() + if not self: + return + actor_type = get_actor_display_name(event.other_actor) + self.hud.notification(f"碰撞 → {actor_type}") + +# ============================================================================== +# -- LaneInvasionSensor +# ============================================================================== +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + world = parent_actor.get_world() + bp = world.get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: LaneInvasionSensor._on_lane(weak_self, event)) + + @staticmethod + def _on_lane(weak_self, event): + self = weak_self() + if not self: + return + self.hud.notification("车道偏离!") + +# ============================================================================== +# -- GnssSensor +# ============================================================================== +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self._parent = parent_actor + self.lat = 0.0 + self.lon = 0.0 + world = parent_actor.get_world() + bp = world.get_blueprint_library().find('sensor.other.gnss') + self.sensor = world.spawn_actor(bp, carla.Transform(carla.Location(z=2.0)), attach_to=parent_actor) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: GnssSensor._on_gnss(weak_self, event)) + + @staticmethod + def _on_gnss(weak_self, event): + self = weak_self() + if not self: + return + self.lat = event.latitude + self.lon = event.longitude + +# ============================================================================== +# -- CameraManager +# ============================================================================== +class CameraManager(object): + def __init__(self, parent_actor, hud, gamma_correction): + self.sensor = None + self.surface = None + self._parent = parent_actor + self.hud = hud + self.transform_index = 0 + self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB Camera']] + self._camera_transforms = [ + carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8.0)) + ] + self.index = None + world = parent_actor.get_world() + for i, it in enumerate(self.sensors): + bp = world.get_blueprint_library().find(it[0]) + bp.set_attribute('image_size_x', str(hud.dim[0])) + bp.set_attribute('image_size_y', str(hud.dim[1])) + self.sensors[i].append(bp) + + def set_sensor(self, index, notify=True): + if self.sensor and self.sensor.is_alive: + self.sensor.destroy() + self.index = index + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[index][-1], + self._camera_transforms[0], + attach_to=self._parent) + weak_self = weakref.ref(self) + self.sensor.listen(lambda image: CameraManager._parse_image(weak_self, image)) + + @staticmethod + def _parse_image(weak_self, image): + self = weak_self() + if not self: + return + image.convert(self.sensors[self.index][1]) + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape((image.height, image.width, 4)) + array = array[:, :, :3] + array = array[:, :, ::-1] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + + def render(self, display): + if self.surface is not None: + display.blit(self.surface, (0, 0)) + +# ============================================================================== +# -- Game Loop +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(10.0) + display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + controller = KeyboardControl(world) + + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + destination = random.choice(spawn_points).location + agent.set_destination(destination) + world.hud.notification("已设置自动导航目标点") + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(world): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + control = agent.run_step() + control.manual_gear_shift = False + world.player.apply_control(control) + + finally: + if world is not None: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA 自动行驶客户端') + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('-b', '--behavior', default='normal', choices=['cautious', 'normal', 'aggressive']) + args = argparser.parse_args() + args.width, args.height = [int(x) for x in args.res.split('x')] + game_loop(args) + +if __name__ == '__main__': + main() From 4e311ee64cc0fba321c73321122a26b128e70263 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Tue, 28 Apr 2026 23:29:11 +0800 Subject: [PATCH 20/28] =?UTF-8?q?=E6=98=BE=E7=A4=BA=E5=9D=90=E6=A0=87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{World_Coordinate.py => world_Coordinate.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/carla_driving_car_lane/{World_Coordinate.py => world_Coordinate.py} (100%) diff --git a/src/carla_driving_car_lane/World_Coordinate.py b/src/carla_driving_car_lane/world_Coordinate.py similarity index 100% rename from src/carla_driving_car_lane/World_Coordinate.py rename to src/carla_driving_car_lane/world_Coordinate.py From bed85b29498de7503f763ee463f4cdaeeb4034a1 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 29 Apr 2026 22:57:05 +0800 Subject: [PATCH 21/28] =?UTF-8?q?=E5=9D=90=E6=A0=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../world_Coordinate.py | 54 ++++++++++++++----- 1 file changed, 42 insertions(+), 12 deletions(-) diff --git a/src/carla_driving_car_lane/world_Coordinate.py b/src/carla_driving_car_lane/world_Coordinate.py index 7c7195eba2..d883c87378 100644 --- a/src/carla_driving_car_lane/world_Coordinate.py +++ b/src/carla_driving_car_lane/world_Coordinate.py @@ -6,11 +6,7 @@ # This work is licensed under the terms of the MIT license. # For a copy, see -""" -CARLA Automatic Control Client -适配:Python 3.9 + CARLA 0.9.15 -功能:自动导航行驶 + 传感器 + HUD 显示 -""" + from __future__ import print_function @@ -59,19 +55,24 @@ from agents.navigation.behavior_agent import BehaviorAgent + # ============================================================================== # -- Global functions # ============================================================================== def find_weather_presets(): rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + def get_actor_display_name(actor, truncate=250): name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + # ============================================================================== # -- World # ============================================================================== @@ -100,12 +101,14 @@ def restart(self, args): blueprint = random.choice(blueprint_library.filter(self._actor_filter)) blueprint.set_attribute('role_name', 'hero') + # 无绝对坐标:使用当前车辆位置重生(相对偏移) if self.player is not None: spawn_point = self.player.get_transform() - spawn_point.location.z += 2.0 + spawn_point.location.z += 2.0 # 仅相对抬高,无绝对坐标 self.destroy() self.player = self.world.try_spawn_actor(blueprint, spawn_point) + # 无绝对坐标:使用地图原生生成点 while self.player is None: spawn_point = random.choice(self.map.get_spawn_points()) self.player = self.world.try_spawn_actor(blueprint, spawn_point) @@ -142,6 +145,7 @@ def destroy(self): if actor is not None and actor.is_alive: actor.destroy() + # ============================================================================== # -- KeyboardControl # ============================================================================== @@ -167,6 +171,7 @@ def parse_events(self, world): def _is_quit_shortcut(key): return key == K_ESCAPE or (key == K_q and pygame.key.get_mods() & KMOD_CTRL) + # ============================================================================== # -- HUD (显示车速、GPS、信息) # ============================================================================== @@ -191,7 +196,7 @@ def tick(self, clock, world): if not world.player: return v = world.player.get_velocity() - speed = round(3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2), 1) + speed = round(3.6 * math.sqrt(v.x ** 2 + v.y ** 2 + v.z ** 2), 1) lat = round(world.gnss_sensor.lat, 6) lon = round(world.gnss_sensor.lon, 6) self.speed = speed @@ -214,11 +219,12 @@ def render(self, display): ] y = 10 for s in info_text: - surf = self.font.render(s, True, (255,255,255)) + surf = self.font.render(s, True, (255, 255, 255)) display.blit(surf, (10, y)) y += 20 self._notifications.render(display) + # ============================================================================== # -- FadingText # ============================================================================== @@ -242,6 +248,7 @@ def render(self, display): self.surface.set_alpha(alpha) display.blit(self.surface, self.pos) + # ============================================================================== # -- CollisionSensor # ============================================================================== @@ -252,6 +259,7 @@ def __init__(self, parent_actor, hud): self.hud = hud world = parent_actor.get_world() bp = world.get_blueprint_library().find('sensor.other.collision') + # 无绝对坐标:默认挂载点 self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) weak_self = weakref.ref(self) self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) @@ -264,6 +272,7 @@ def _on_collision(weak_self, event): actor_type = get_actor_display_name(event.other_actor) self.hud.notification(f"碰撞 → {actor_type}") + # ============================================================================== # -- LaneInvasionSensor # ============================================================================== @@ -274,6 +283,7 @@ def __init__(self, parent_actor, hud): self.hud = hud world = parent_actor.get_world() bp = world.get_blueprint_library().find('sensor.other.lane_invasion') + # 无绝对坐标:默认挂载点 self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) weak_self = weakref.ref(self) self.sensor.listen(lambda event: LaneInvasionSensor._on_lane(weak_self, event)) @@ -285,6 +295,7 @@ def _on_lane(weak_self, event): return self.hud.notification("车道偏离!") + # ============================================================================== # -- GnssSensor # ============================================================================== @@ -296,6 +307,7 @@ def __init__(self, parent_actor): self.lon = 0.0 world = parent_actor.get_world() bp = world.get_blueprint_library().find('sensor.other.gnss') + # 无绝对坐标:仅相对高度,无 x/y self.sensor = world.spawn_actor(bp, carla.Transform(carla.Location(z=2.0)), attach_to=parent_actor) weak_self = weakref.ref(self) self.sensor.listen(lambda event: GnssSensor._on_gnss(weak_self, event)) @@ -308,8 +320,9 @@ def _on_gnss(weak_self, event): self.lat = event.latitude self.lon = event.longitude + # ============================================================================== -# -- CameraManager +# -- CameraManager (✅ 已移除所有硬编码相机坐标) # ============================================================================== class CameraManager(object): def __init__(self, parent_actor, hud, gamma_correction): @@ -319,9 +332,10 @@ def __init__(self, parent_actor, hud, gamma_correction): self.hud = hud self.transform_index = 0 self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB Camera']] - self._camera_transforms = [ - carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8.0)) - ] + + # ✅ 动态计算相机位置:基于车辆包围盒,无任何绝对坐标 + self._auto_camera_transform() + self.index = None world = parent_actor.get_world() for i, it in enumerate(self.sensors): @@ -330,6 +344,18 @@ def __init__(self, parent_actor, hud, gamma_correction): bp.set_attribute('image_size_y', str(hud.dim[1])) self.sensors[i].append(bp) + def _auto_camera_transform(self): + """ 自动计算相机位置:基于车辆尺寸,自适应所有车型,无硬编码坐标 """ + vehicle = self._parent + bounds = vehicle.bounding_box + ext = bounds.extent + # 相机放在车辆后上方,自适应尺寸 + x = -ext.x * 2.5 + z = ext.z * 2.0 + self._camera_transforms = [ + carla.Transform(carla.Location(x=x, z=z), carla.Rotation(pitch=8.0)) + ] + def set_sensor(self, index, notify=True): if self.sensor and self.sensor.is_alive: self.sensor.destroy() @@ -357,6 +383,7 @@ def render(self, display): if self.surface is not None: display.blit(self.surface, (0, 0)) + # ============================================================================== # -- Game Loop # ============================================================================== @@ -374,6 +401,7 @@ def game_loop(args): controller = KeyboardControl(world) agent = BehaviorAgent(world.player, behavior=args.behavior) + # ✅ 无绝对坐标:随机目标点来自地图生成点 spawn_points = world.map.get_spawn_points() destination = random.choice(spawn_points).location agent.set_destination(destination) @@ -399,6 +427,7 @@ def game_loop(args): world.destroy() pygame.quit() + # ============================================================================== # -- main() # ============================================================================== @@ -413,5 +442,6 @@ def main(): args.width, args.height = [int(x) for x in args.res.split('x')] game_loop(args) + if __name__ == '__main__': main() From 62a65dcd24570f4f14f29215092ea33f66479394 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 6 May 2026 10:22:24 +0800 Subject: [PATCH 22/28] =?UTF-8?q?=E5=9D=90=E6=A0=87=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../world_Coordinate.py | 442 ++++++------------ 1 file changed, 151 insertions(+), 291 deletions(-) diff --git a/src/carla_driving_car_lane/world_Coordinate.py b/src/carla_driving_car_lane/world_Coordinate.py index d883c87378..acb8ded23d 100644 --- a/src/carla_driving_car_lane/world_Coordinate.py +++ b/src/carla_driving_car_lane/world_Coordinate.py @@ -1,81 +1,91 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- - -# Copyright (c) 2018 Intel Labs. -# authors: German Ros (german.ros@gmail.com) -# This work is licensed under the terms of the MIT license. -# For a copy, see - - - -from __future__ import print_function - +import os +import sys import argparse -import collections -import datetime -import glob -import logging import math -import os import random -import re -import sys -import time import weakref +import glob -# ========================================== -# 你的 CARLA 路径(保持不变) -# ========================================== -CARLA_ROOT = r"D:\carla0.9.15" -PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") -sys.path.append(PYTHON_API) -sys.path.append(os.path.join(PYTHON_API, "carla")) +# ============================================== +# 强制阻断所有冲突库加载(终极方案) +# ============================================== +for lib in ['matplotlib', 'scipy', 'tensorflow', 'torch', 'keras']: + sys.modules[lib] = None + sys.modules[lib + '.core'] = None + sys.modules[lib + '.api'] = None +# 加载 CARLA Python API try: - eggs = glob.glob(os.path.join(PYTHON_API, "carla", "dist", "*.egg")) + current_dir = os.path.dirname(os.path.abspath(__file__)) + eggs = glob.glob(os.path.join(current_dir, "carla", "dist", "*.egg")) for e in eggs: sys.path.append(e) except: pass -# ================= 依赖 ================= -try: - import pygame - from pygame.locals import K_ESCAPE, K_q, KMOD_CTRL, K_PAGEUP, K_PAGEDOWN -except ImportError: - raise RuntimeError('请安装:pip install pygame') - -try: - import numpy as np -except ImportError: - raise RuntimeError('请安装:pip install numpy') - +# 仅加载必要库 +import pygame +from pygame.locals import * +import numpy as np import carla from carla import ColorConverter as cc -from agents.navigation.behavior_agent import BehaviorAgent +# ============================================== +# 自己实现极简自动导航(不依赖任何第三方库) +# ============================================== +class SimpleAutoAgent: + def __init__(self, vehicle): + self.vehicle = vehicle + self.world = vehicle.get_world() + self.map = self.world.get_map() + self.target = None -# ============================================================================== -# -- Global functions -# ============================================================================== -def find_weather_presets(): - rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def set_destination(self, location): + self.target = location + + def run_step(self): + control = carla.VehicleControl() + if not self.target: + return control + + # 基础自动行驶逻辑 + transform = self.vehicle.get_transform() + forward = transform.get_forward_vector() + target_dir = self.target - transform.location + target_dir.z = 0 + + # 计算方向 + dot = forward.x * target_dir.x + forward.y * target_dir.y + cross = forward.x * target_dir.y - forward.y * target_dir.x + distance = math.sqrt(target_dir.x ** 2 + target_dir.y ** 2) - def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + # 控制 + if distance > 5.0: + control.throttle = 0.5 + control.steer = max(-0.3, min(0.3, cross * 0.15)) + else: + control.brake = 1.0 - presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] - return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + return control -def get_actor_display_name(actor, truncate=250): +# ===================== 以下是完整 CARLA 运行代码 ===================== +def find_weather_presets(): + presets = [] + for name in dir(carla.WeatherParameters): + if name[0].isupper(): + presets.append((getattr(carla.WeatherParameters, name), name)) + return presets + + +def get_actor_display_name(actor): name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) - return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + return name -# ============================================================================== -# -- World -# ============================================================================== class World(object): def __init__(self, carla_world, hud, args): self.world = carla_world @@ -84,41 +94,32 @@ def __init__(self, carla_world, hud, args): self.player = None self.collision_sensor = None self.lane_invasion_sensor = None - self.gnss_sensor = None self.camera_manager = None self._weather_presets = find_weather_presets() self._weather_index = 0 self._actor_filter = args.filter - self._gamma = 2.2 self.restart(args) self.world.on_tick(hud.on_world_tick) def restart(self, args): - cam_index = self.camera_manager.index if self.camera_manager else 0 - cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 - blueprint_library = self.world.get_blueprint_library() blueprint = random.choice(blueprint_library.filter(self._actor_filter)) blueprint.set_attribute('role_name', 'hero') - # 无绝对坐标:使用当前车辆位置重生(相对偏移) if self.player is not None: spawn_point = self.player.get_transform() - spawn_point.location.z += 2.0 # 仅相对抬高,无绝对坐标 + spawn_point.location.z += 2.0 self.destroy() self.player = self.world.try_spawn_actor(blueprint, spawn_point) - # 无绝对坐标:使用地图原生生成点 while self.player is None: spawn_point = random.choice(self.map.get_spawn_points()) self.player = self.world.try_spawn_actor(blueprint, spawn_point) self.collision_sensor = CollisionSensor(self.player, self.hud) self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) - self.gnss_sensor = GnssSensor(self.player) - self.camera_manager = CameraManager(self.player, self.hud, self._gamma) - self.camera_manager.transform_index = cam_pos_id - self.camera_manager.set_sensor(cam_index, notify=False) + self.camera_manager = CameraManager(self.player, self.hud) + self.camera_manager.set_sensor(0) def next_weather(self, reverse=False): self._weather_index += -1 if reverse else 1 @@ -135,258 +136,128 @@ def render(self, display): self.hud.render(display) def destroy(self): - actors = [ - self.camera_manager.sensor, - self.collision_sensor.sensor, - self.lane_invasion_sensor.sensor, - self.gnss_sensor.sensor, - self.player] + actors = [self.camera_manager.sensor, self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, self.player] for actor in actors: - if actor is not None and actor.is_alive: + if actor and actor.is_alive: actor.destroy() -# ============================================================================== -# -- KeyboardControl -# ============================================================================== -class KeyboardControl(object): - def __init__(self, world): - world.hud.notification("按 ESC 或 Ctrl+Q 退出", 2) - world.hud.notification("PageUp/PageDown: 切换天气", 2) +class CollisionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.collision'), + carla.Transform(), attach_to=parent) + self.hud = hud + self.sensor.listen(lambda e: self.hud.notification(f"碰撞: {get_actor_display_name(e.other_actor)}")) - def parse_events(self, world): - for event in pygame.event.get(): - if event.type == pygame.QUIT: - return True - if event.type == pygame.KEYUP: - if self._is_quit_shortcut(event.key): - return True - if event.key == K_PAGEUP: - world.next_weather(reverse=True) - if event.key == K_PAGEDOWN: - world.next_weather() - return False - @staticmethod - def _is_quit_shortcut(key): - return key == K_ESCAPE or (key == K_q and pygame.key.get_mods() & KMOD_CTRL) +class LaneInvasionSensor(object): + def __init__(self, parent, hud): + self.sensor = parent.get_world().spawn_actor( + parent.get_world().get_blueprint_library().find('sensor.other.lane_invasion'), + carla.Transform(), attach_to=parent) + self.hud = hud + self.sensor.listen(lambda e: self.hud.notification("车道偏离")) + + +class CameraManager(object): + def __init__(self, parent, hud): + self.sensor = None + self.surface = None + self.parent = parent + self.hud = hud + bp = parent.get_world().get_blueprint_library().find('sensor.camera.rgb') + bp.set_attribute('image_size_x', str(hud.dim[0])) + bp.set_attribute('image_size_y', str(hud.dim[1])) + self.bp = bp + + def set_sensor(self, index): + if self.sensor: self.sensor.destroy() + v = self.parent + ext = v.bounding_box.extent + trans = carla.Transform(carla.Location(x=-ext.x * 2.5, z=ext.z * 2), carla.Rotation(pitch=8)) + self.sensor = v.get_world().spawn_actor(self.bp, trans, attach_to=v) + self.sensor.listen(lambda img: self._parse(img)) + + def _parse(self, image): + image.convert(cc.Raw) + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape(image.height, image.width, 4) + array = array[:, :, :3] + array = array[:, :, ::-1] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + + def render(self, display): + if self.surface: display.blit(self.surface, (0, 0)) -# ============================================================================== -# -- HUD (显示车速、GPS、信息) -# ============================================================================== class HUD(object): def __init__(self, width, height): self.dim = (width, height) - font = pygame.font.Font(pygame.font.get_default_font(), 16) - self._notifications = FadingText(font, (width, 40), (0, height - 40)) - self.font = font + self.font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(self.font, (width, 40), (0, height - 40)) self.server_fps = 0 - self.frame = 0 - self.simulation_time = 0 - self._show_info = True + self.speed = 0 def on_world_tick(self, timestamp): self.server_fps = 1.0 / max(timestamp.delta_seconds, 0.01) - self.frame = timestamp.frame_count - self.simulation_time = timestamp.elapsed_seconds def tick(self, clock, world): self._notifications.tick(clock) - if not world.player: - return - v = world.player.get_velocity() - speed = round(3.6 * math.sqrt(v.x ** 2 + v.y ** 2 + v.z ** 2), 1) - lat = round(world.gnss_sensor.lat, 6) - lon = round(world.gnss_sensor.lon, 6) - self.speed = speed - self.lat = lat - self.lon = lon + if world.player: + v = world.player.get_velocity() + self.speed = round(3.6 * math.sqrt(v.x ** 2 + v.y ** 2 + v.z ** 2), 1) def notification(self, text, seconds=2): self._notifications.set_text(text, seconds=seconds) - def error(self, text): - self._notifications.set_text('错误: %s' % text, (255, 0, 0)) - def render(self, display): - if self._show_info: - info_text = [ - "FPS: %.1f" % self.server_fps, - "车速: %.1f km/h" % getattr(self, 'speed', 0), - "纬度: %.6f" % getattr(self, 'lat', 0), - "经度: %.6f" % getattr(self, 'lon', 0) - ] - y = 10 - for s in info_text: - surf = self.font.render(s, True, (255, 255, 255)) - display.blit(surf, (10, y)) - y += 20 + info = [f"FPS: {self.server_fps:.1f}", f"车速: {self.speed:.1f} km/h", "状态: 自动行驶中"] + for i, line in enumerate(info): + surf = self.font.render(line, True, (255, 255, 255)) + display.blit(surf, (10, 10 + i * 20)) self._notifications.render(display) -# ============================================================================== -# -- FadingText -# ============================================================================== class FadingText(object): def __init__(self, font, dim, pos): self.font = font self.dim = dim self.pos = pos self.seconds_left = 0 - self.surface = pygame.Surface(self.dim) + self.surface = font.render("", True, (0, 0, 0)) - def set_text(self, text, color=(255, 255, 255), seconds=2.0): + def set_text(self, text, color=(255, 255, 255), seconds=2): self.seconds_left = seconds self.surface = self.font.render(text, True, color) def tick(self, clock): - self.seconds_left = max(0.0, self.seconds_left - clock.get_time() / 1000.0) + self.seconds_left = max(0.0, self.seconds_left - clock.get_time() / 1000) def render(self, display): - alpha = int(255 * (self.seconds_left / 2.0)) if self.seconds_left > 0 else 0 + alpha = int(255 * self.seconds_left / 2) if self.seconds_left else 0 self.surface.set_alpha(alpha) display.blit(self.surface, self.pos) -# ============================================================================== -# -- CollisionSensor -# ============================================================================== -class CollisionSensor(object): - def __init__(self, parent_actor, hud): - self.sensor = None - self._parent = parent_actor - self.hud = hud - world = parent_actor.get_world() - bp = world.get_blueprint_library().find('sensor.other.collision') - # 无绝对坐标:默认挂载点 - self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) - weak_self = weakref.ref(self) - self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) - - @staticmethod - def _on_collision(weak_self, event): - self = weak_self() - if not self: - return - actor_type = get_actor_display_name(event.other_actor) - self.hud.notification(f"碰撞 → {actor_type}") - - -# ============================================================================== -# -- LaneInvasionSensor -# ============================================================================== -class LaneInvasionSensor(object): - def __init__(self, parent_actor, hud): - self.sensor = None - self._parent = parent_actor - self.hud = hud - world = parent_actor.get_world() - bp = world.get_blueprint_library().find('sensor.other.lane_invasion') - # 无绝对坐标:默认挂载点 - self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=parent_actor) - weak_self = weakref.ref(self) - self.sensor.listen(lambda event: LaneInvasionSensor._on_lane(weak_self, event)) - - @staticmethod - def _on_lane(weak_self, event): - self = weak_self() - if not self: - return - self.hud.notification("车道偏离!") - - -# ============================================================================== -# -- GnssSensor -# ============================================================================== -class GnssSensor(object): - def __init__(self, parent_actor): - self.sensor = None - self._parent = parent_actor - self.lat = 0.0 - self.lon = 0.0 - world = parent_actor.get_world() - bp = world.get_blueprint_library().find('sensor.other.gnss') - # 无绝对坐标:仅相对高度,无 x/y - self.sensor = world.spawn_actor(bp, carla.Transform(carla.Location(z=2.0)), attach_to=parent_actor) - weak_self = weakref.ref(self) - self.sensor.listen(lambda event: GnssSensor._on_gnss(weak_self, event)) - - @staticmethod - def _on_gnss(weak_self, event): - self = weak_self() - if not self: - return - self.lat = event.latitude - self.lon = event.longitude - - -# ============================================================================== -# -- CameraManager (✅ 已移除所有硬编码相机坐标) -# ============================================================================== -class CameraManager(object): - def __init__(self, parent_actor, hud, gamma_correction): - self.sensor = None - self.surface = None - self._parent = parent_actor - self.hud = hud - self.transform_index = 0 - self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB Camera']] - - # ✅ 动态计算相机位置:基于车辆包围盒,无任何绝对坐标 - self._auto_camera_transform() - - self.index = None - world = parent_actor.get_world() - for i, it in enumerate(self.sensors): - bp = world.get_blueprint_library().find(it[0]) - bp.set_attribute('image_size_x', str(hud.dim[0])) - bp.set_attribute('image_size_y', str(hud.dim[1])) - self.sensors[i].append(bp) - - def _auto_camera_transform(self): - """ 自动计算相机位置:基于车辆尺寸,自适应所有车型,无硬编码坐标 """ - vehicle = self._parent - bounds = vehicle.bounding_box - ext = bounds.extent - # 相机放在车辆后上方,自适应尺寸 - x = -ext.x * 2.5 - z = ext.z * 2.0 - self._camera_transforms = [ - carla.Transform(carla.Location(x=x, z=z), carla.Rotation(pitch=8.0)) - ] - - def set_sensor(self, index, notify=True): - if self.sensor and self.sensor.is_alive: - self.sensor.destroy() - self.index = index - self.sensor = self._parent.get_world().spawn_actor( - self.sensors[index][-1], - self._camera_transforms[0], - attach_to=self._parent) - weak_self = weakref.ref(self) - self.sensor.listen(lambda image: CameraManager._parse_image(weak_self, image)) - - @staticmethod - def _parse_image(weak_self, image): - self = weak_self() - if not self: - return - image.convert(self.sensors[self.index][1]) - array = np.frombuffer(image.raw_data, dtype=np.uint8) - array = array.reshape((image.height, image.width, 4)) - array = array[:, :, :3] - array = array[:, :, ::-1] - self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) +class KeyboardControl(object): + def __init__(self, world): + world.hud.notification("ESC 退出", 2) + world.hud.notification("PageUp/Down 切换天气", 2) - def render(self, display): - if self.surface is not None: - display.blit(self.surface, (0, 0)) + def parse_events(self, world): + for event in pygame.event.get(): + if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE): + return True + if event.type == KEYUP: + if event.key == K_PAGEUP: + world.next_weather(True) + elif event.key == K_PAGEDOWN: + world.next_weather() + return False -# ============================================================================== -# -- Game Loop -# ============================================================================== def game_loop(args): pygame.init() pygame.font.init() @@ -395,51 +266,40 @@ def game_loop(args): try: client = carla.Client(args.host, args.port) client.set_timeout(10.0) - display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + display = pygame.display.set_mode((args.width, args.height)) hud = HUD(args.width, args.height) world = World(client.get_world(), hud, args) controller = KeyboardControl(world) - agent = BehaviorAgent(world.player, behavior=args.behavior) - # ✅ 无绝对坐标:随机目标点来自地图生成点 - spawn_points = world.map.get_spawn_points() - destination = random.choice(spawn_points).location - agent.set_destination(destination) - world.hud.notification("已设置自动导航目标点") + # 使用我们自己的极简自动代理(无任何依赖) + agent = SimpleAutoAgent(world.player) + dest = random.choice(world.map.get_spawn_points()).location + agent.set_destination(dest) + hud.notification("自动导航已启动") clock = pygame.time.Clock() - while True: clock.tick_busy_loop(60) - if controller.parse_events(world): - return - + if controller.parse_events(world): return world.tick(clock) world.render(display) pygame.display.flip() - control = agent.run_step() - control.manual_gear_shift = False world.player.apply_control(control) finally: - if world is not None: - world.destroy() + if world: world.destroy() pygame.quit() -# ============================================================================== -# -- main() -# ============================================================================== def main(): - argparser = argparse.ArgumentParser(description='CARLA 自动行驶客户端') + argparser = argparse.ArgumentParser() argparser.add_argument('--host', default='127.0.0.1') argparser.add_argument('--port', default=2000, type=int) argparser.add_argument('--res', default='1280x720') argparser.add_argument('--filter', default='vehicle.*') - argparser.add_argument('-b', '--behavior', default='normal', choices=['cautious', 'normal', 'aggressive']) args = argparser.parse_args() - args.width, args.height = [int(x) for x in args.res.split('x')] + args.width, args.height = map(int, args.res.split('x')) game_loop(args) From 3b1c99c39ddd6848a6c05a015470567cb6cb1a84 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Wed, 13 May 2026 22:44:48 +0800 Subject: [PATCH 23/28] =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=88=87=E6=8D=A2?= =?UTF-8?q?=E4=BC=98=E5=8C=96=E7=89=88=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/Switch_automatic | 376 ++++++++++++++++++++ 1 file changed, 376 insertions(+) create mode 100644 src/carla_driving_car_lane/Switch_automatic diff --git a/src/carla_driving_car_lane/Switch_automatic b/src/carla_driving_car_lane/Switch_automatic new file mode 100644 index 0000000000..8a32377681 --- /dev/null +++ b/src/carla_driving_car_lane/Switch_automatic @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Intel Labs. +# authors: German Ros (german.ros@gmail.com) +# +# This work is licensed under the terms of the MIT license. +# For a copy, see + +"""Example of automatic vehicle control from client side. | Adapted for Python3 + CARLA 0.9.15""" + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref + +# ========================================== +# 适配你的路径 D:\carla0.9.15 +# ========================================== +CARLA_ROOT = r"D:\carla0.9.15" +PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") +sys.path.append(PYTHON_API) + +# CARLA 0.9.15 Python3 直接导入,无需 egg +try: + sys.path.append(os.path.join(PYTHON_API, "carla")) +except Exception: + pass + +# ================= 依赖导入 ================= +try: + import pygame + from pygame.locals import KMOD_CTRL + from pygame.locals import K_ESCAPE + from pygame.locals import K_q + from pygame.locals import K_TAB +except ImportError: + raise RuntimeError('请安装:pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装:pip install numpy') + +import carla +from carla import ColorConverter as cc + +# CARLA 0.9.15 自动导航代理(修复导入) +from agents.navigation.behavior_agent import BehaviorAgent + +# ============================================================================== +# -- Global functions +# ============================================================================== +def find_weather_presets(): + rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] + return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +# ============================================================================== +# -- World +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._weather_presets = find_weather_presets() + self._weather_index = 0 + self._actor_filter = args.filter + self._gamma = 2.2 + self.restart(args) + self.world.on_tick(hud.on_world_tick) + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 + + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud, self._gamma) + self.camera_manager.transform_index = cam_pos_id + self.camera_manager.set_sensor(cam_index, notify=False) + + def next_weather(self, reverse=False): + self._weather_index += -1 if reverse else 1 + self._weather_index %= len(self._weather_presets) + preset = self._weather_presets[self._weather_index] + self.hud.notification('Weather: %s' % preset[1]) + self.world.set_weather(preset[0]) + + def tick(self, clock): + self.hud.tick(self, clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + +# ============================================================================== +# -- KeyboardControl +# ============================================================================== +class KeyboardControl(object): + def __init__(self, world): + self.world = world + world.hud.notification("Press ESC or Ctrl+Q to quit | TAB = Weather", seconds=2) + + def parse_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if self._is_quit_shortcut(event.key): + return True + if event.key == K_TAB: + self.world.next_weather() + return False + + @staticmethod + def _is_quit_shortcut(key): + return key == K_ESCAPE or (key == K_q and pygame.key.get_mod() & KMOD_CTRL) + +# ============================================================================== +# -- HUD +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 16) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / timestamp.delta_seconds + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, world, clock): + self._notifications.tick(world, clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def error(self, text): + self._notifications.set_text('Error: %s' % text, (255, 0, 0)) + + def render(self, display): + self._notifications.render(display) + +# ============================================================================== +# -- FadingText +# ============================================================================== +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2.0): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, _, clock): + delta = clock.get_time() / 1000.0 + self.seconds_left = max(0.0, self.seconds_left - delta) + + def render(self, display): + if self.seconds_left > 0: + display.blit(self.surface, self.pos) + +# ============================================================================== +# -- CollisionSensor +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.collision') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda event: self._on_collision(event)) + + def _on_collision(self, event): + other = get_actor_display_name(event.other_actor) + self.hud.notification(f"碰撞: {other}", 1) + +# ============================================================================== +# -- LaneInvasionSensor +# ============================================================================== +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda x: self.hud.notification("压线/越线", 0.5)) + +# ============================================================================== +# -- GnssSensor +# ============================================================================== +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self.lat = 0.0 + self.lon = 0.0 + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.gnss') + transform = carla.Transform(carla.Location(z=2.0)) + self.sensor = parent_actor.get_world().spawn_actor(bp, transform, attach_to=parent_actor) + self.sensor.listen(lambda data: self._on_gnss(data)) + + def _on_gnss(self, data): + self.lat = data.latitude + self.lon = data.longitude + +# ============================================================================== +# -- CameraManager +# ============================================================================== +class CameraManager(object): + def __init__(self, parent_actor, hud, gamma): + self.sensor = None + self.surface = None + self._parent = parent_actor + self.hud = hud + self.transform_index = 0 + self._camera_transforms = [ + (carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)), carla.AttachmentType.SpringArm) + ] + self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB']] + world = parent_actor.get_world() + for item in self.sensors: + b = world.get_blueprint_library().find(item[0]) + b.set_attribute('image_size_x', str(hud.dim[0])) + b.set_attribute('image_size_y', str(hud.dim[1])) + item.append(b) + self.index = None + + def set_sensor(self, index, notify=True): + if self.sensor and self.sensor.is_alive: + self.sensor.destroy() + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[0][-1], + self._camera_transforms[0][0], + attach_to=self._parent, + attachment_type=self._camera_transforms[0][1] + ) + self.sensor.listen(lambda img: self._parse_image(img)) + self.index = 0 + + def _parse_image(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape((image.height, image.width, 4)) + array = array[:, :, :3] + array = array[:, :, ::-1] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + + def render(self, display): + if self.surface: + display.blit(self.surface, (0, 0)) + +# ============================================================================== +# -- Game Loop +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(15.0) + client.load_world('Town01') + + display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + pygame.display.set_caption("CARLA 0.9.15 Python3 | Auto Drive") + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + controller = KeyboardControl(world) + + # 自动导航代理 + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + destination = random.choice(spawn_points).location + agent.set_destination(destination) + hud.notification("导航目标已设置", 2) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + # 自动行驶控制 + control = agent.run_step() + control.manual_gear_shift = False + world.player.apply_control(control) + + # 到达目标后更换新目标 + if agent.done(): + new_dest = random.choice(spawn_points).location + agent.set_destination(new_dest) + hud.notification("已到达,切换新目标", 1) + + finally: + if world: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA Automatic Control Client | Python3 + 0.9.15') + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('-b', '--behavior', default='normal', help='normal / cautious / aggressive') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + + # 关闭CARLA冗余日志 + logging.basicConfig(level=logging.INFO) + game_loop(args) + +if __name__ == '__main__': + main() From 1e0a13936b96b138086adf2739b9155ecd1cf8fc Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 14 May 2026 22:58:22 +0800 Subject: [PATCH 24/28] =?UTF-8?q?=E6=89=8B=E5=8A=A8=E9=A9=BE=E9=A9=B6?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_driving_car_lane/Automatic_model | 414 +++++++++++++++++++++ 1 file changed, 414 insertions(+) create mode 100644 src/carla_driving_car_lane/Automatic_model diff --git a/src/carla_driving_car_lane/Automatic_model b/src/carla_driving_car_lane/Automatic_model new file mode 100644 index 0000000000..c1f74f95a6 --- /dev/null +++ b/src/carla_driving_car_lane/Automatic_model @@ -0,0 +1,414 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# Copyright (c) 2018 Intel Labs. +# authors: German Ros (german.ros@gmail.com) +# +# This work is licensed under the terms of the MIT license. +# For a copy, see + +"""Example of automatic vehicle control from client side. | Adapted for Python3 + CARLA 0.9.15""" + +import argparse +import collections +import datetime +import glob +import logging +import math +import os +import random +import re +import sys +import weakref + +# ========================================== +# 适配你的路径 D:\carla0.9.15 +# ========================================== +CARLA_ROOT = r"D:\carla0.9.15" +PYTHON_API = os.path.join(CARLA_ROOT, "PythonAPI") +sys.path.append(PYTHON_API) + +# CARLA 0.9.15 Python3 直接导入,无需 egg +try: + sys.path.append(os.path.join(PYTHON_API, "carla")) +except Exception: + pass + +# ================= 依赖导入 ================= +try: + import pygame + from pygame.locals import * +except ImportError: + raise RuntimeError('请安装:pip install pygame') + +try: + import numpy as np +except ImportError: + raise RuntimeError('请安装:pip install numpy') + +import carla +from carla import ColorConverter as cc + +# CARLA 0.9.15 自动导航代理(修复导入) +from agents.navigation.behavior_agent import BehaviorAgent + +# ============================================================================== +# -- Global functions +# ============================================================================== +def find_weather_presets(): + rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)') + def name(x): return ' '.join(m.group(0) for m in rgx.finditer(x)) + presets = [x for x in dir(carla.WeatherParameters) if re.match('[A-Z].+', x)] + return [(getattr(carla.WeatherParameters, x), name(x)) for x in presets] + +def get_actor_display_name(actor, truncate=250): + name = ' '.join(actor.type_id.replace('_', '.').title().split('.')[1:]) + return (name[:truncate - 1] + u'\u2026') if len(name) > truncate else name + +# ============================================================================== +# -- World +# ============================================================================== +class World(object): + def __init__(self, carla_world, hud, args): + self.world = carla_world + self.map = self.world.get_map() + self.hud = hud + self.player = None + self.collision_sensor = None + self.lane_invasion_sensor = None + self.gnss_sensor = None + self.camera_manager = None + self._weather_presets = find_weather_presets() + self._weather_index = 0 + self._actor_filter = args.filter + self._gamma = 2.2 + self.restart(args) + self.world.on_tick(hud.on_world_tick) + self.controller = None + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager else 0 + + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + spawn_point = random.choice(self.map.get_spawn_points()) + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + self.collision_sensor = CollisionSensor(self.player, self.hud) + self.lane_invasion_sensor = LaneInvasionSensor(self.player, self.hud) + self.gnss_sensor = GnssSensor(self.player) + self.camera_manager = CameraManager(self.player, self.hud, self._gamma) + self.camera_manager.transform_index = cam_pos_id + self.camera_manager.set_sensor(cam_index, notify=False) + + def next_weather(self, reverse=False): + self._weather_index += -1 if reverse else 1 + self._weather_index %= len(self._weather_presets) + preset = self._weather_presets[self._weather_index] + self.hud.notification('Weather: %s' % preset[1]) + self.world.set_weather(preset[0]) + + def tick(self, clock): + self.hud.tick(self, clock) + + def render(self, display): + self.camera_manager.render(display) + self.hud.render(display) + + def destroy(self): + actors = [ + self.camera_manager.sensor, + self.collision_sensor.sensor, + self.lane_invasion_sensor.sensor, + self.gnss_sensor.sensor, + self.player] + for actor in actors: + if actor is not None and actor.is_alive: + actor.destroy() + +# ============================================================================== +# -- KeyboardControl +# ============================================================================== +class KeyboardControl(object): + def __init__(self, world): + self.world = world + self.control = carla.VehicleControl() + self.steer_speed = 0.05 + self.manual_mode = False + + world.hud.notification("ESC退出 | TAB天气 | C切换自动驾驶/手动驾驶", seconds=3) + + def parse_events(self): + for event in pygame.event.get(): + if event.type == pygame.QUIT: + return True + if event.type == pygame.KEYUP: + if self._is_quit_shortcut(event.key): + return True + if event.key == K_TAB: + self.world.next_weather() + if event.key == K_c: + self.manual_mode = not self.manual_mode + msg = "手动驾驶模式" if self.manual_mode else "自动驾驶模式" + self.world.hud.notification(msg) + + if self.manual_mode: + keys = pygame.key.get_pressed() + self.control.throttle = 1.0 if keys[K_w] else 0.0 + self.control.brake = 1.0 if keys[K_s] else 0.0 + + if keys[K_a]: + self.control.steer = max(-1.0, self.control.steer - self.steer_speed) + elif keys[K_d]: + self.control.steer = min(1.0, self.control.steer + self.steer_speed) + else: + self.control.steer = 0.0 + + self.control.manual_gear_shift = False + return False + + @staticmethod + def _is_quit_shortcut(key): + return key == K_ESCAPE or (key == K_q and pygame.key.get_mod() & KMOD_CTRL) + +# ============================================================================== +# -- HUD +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + self.font = pygame.font.Font(pygame.font.get_default_font(), 18) + self._notifications = FadingText(self.font, (width, 40), (0, height - 40)) + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + + def on_world_tick(self, timestamp): + self.server_fps = 1.0 / timestamp.delta_seconds + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, world, clock): + self._current_world = world + self._notifications.tick(world, clock) + + def notification(self, text, seconds=2): + self._notifications.set_text(text, seconds=seconds) + + def error(self, text): + self._notifications.set_text('Error: %s' % text, (255, 0, 0)) + + def render(self, display): + world = self._current_world + if world.player and world.player.is_alive: + v = world.player.get_velocity() + speed = round(3.6 * math.sqrt(v.x**2 + v.y**2 + v.z**2), 1) + trans = world.player.get_transform() + mode = "手动驾驶" if world.controller.manual_mode else "自动驾驶" + + info = [ + f"模式: {mode}", + f"车速: {speed} km/h", + f"坐标: X:{trans.location.x:.1f} Y:{trans.location.y:.1f}", + f"航向: {trans.rotation.yaw:.1f}°" + ] + for i, line in enumerate(info): + surf = self.font.render(line, True, (255,255,0)) + display.blit(surf, (10, 10 + i*25)) + + self._notifications.render(display) + +# ============================================================================== +# -- FadingText +# ============================================================================== +class FadingText(object): + def __init__(self, font, dim, pos): + self.font = font + self.dim = dim + self.pos = pos + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + + def set_text(self, text, color=(255, 255, 255), seconds=2.0): + self.seconds_left = seconds + self.surface = self.font.render(text, True, color) + + def tick(self, _, clock): + delta = clock.get_time() / 1000.0 + self.seconds_left = max(0.0, self.seconds_left - delta) + + def render(self, display): + if self.seconds_left > 0: + display.blit(self.surface, self.pos) + +# ============================================================================== +# -- CollisionSensor +# ============================================================================== +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.collision') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda event: self._on_collision(event)) + + def _on_collision(self, event): + other = get_actor_display_name(event.other_actor) + self.hud.notification(f"碰撞: {other}", 1) + +# ============================================================================== +# -- LaneInvasionSensor +# ============================================================================== +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self.hud = hud + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = parent_actor.get_world().spawn_actor(bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda x: self.hud.notification("压线/越线", 0.5)) + +# ============================================================================== +# -- GnssSensor +# ============================================================================== +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self.lat = 0.0 + self.lon = 0.0 + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.gnss') + transform = carla.Transform(carla.Location(z=2.0)) + self.sensor = parent_actor.get_world().spawn_actor(bp, transform, attach_to=parent_actor) + self.sensor.listen(lambda data: self._on_gnss(data)) + + def _on_gnss(self, data): + self.lat = data.latitude + self.lon = data.longitude + +# ============================================================================== +# -- CameraManager +# ============================================================================== +class CameraManager(object): + def __init__(self, parent_actor, hud, gamma): + self.sensor = None + self.surface = None + self._parent = parent_actor + self.hud = hud + self.transform_index = 0 + self._camera_transforms = [ + (carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8)), carla.AttachmentType.SpringArm) + ] + self.sensors = [['sensor.camera.rgb', cc.Raw, 'RGB']] + world = parent_actor.get_world() + for item in self.sensors: + b = world.get_blueprint_library().find(item[0]) + b.set_attribute('image_size_x', str(hud.dim[0])) + b.set_attribute('image_size_y', str(hud.dim[1])) + item.append(b) + self.index = None + + def set_sensor(self, index, notify=True): + if self.sensor and self.sensor.is_alive: + self.sensor.destroy() + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[0][-1], + self._camera_transforms[0][0], + attach_to=self._parent, + attachment_type=self._camera_transforms[0][1] + ) + self.sensor.listen(lambda img: self._parse_image(img)) + self.index = 0 + + def _parse_image(self, image): + array = np.frombuffer(image.raw_data, dtype=np.uint8) + array = array.reshape((image.height, image.width, 4)) + array = array[:, :, :3] + array = array[:, :, ::-1] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + + def render(self, display): + if self.surface: + display.blit(self.surface, (0, 0)) + +# ============================================================================== +# -- Game Loop +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(15.0) + client.load_world('Town01') + + display = pygame.display.set_mode((args.width, args.height), pygame.HWSURFACE | pygame.DOUBLEBUF) + pygame.display.set_caption("CARLA 0.9.15 Python3 | Auto Drive") + hud = HUD(args.width, args.height) + world = World(client.get_world(), hud, args) + controller = KeyboardControl(world) + world.controller = controller + + agent = BehaviorAgent(world.player, behavior=args.behavior) + spawn_points = world.map.get_spawn_points() + destination = random.choice(spawn_points).location + agent.set_destination(destination) + hud.notification("导航目标已设置", 2) + + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(): + return + + world.tick(clock) + world.render(display) + pygame.display.flip() + + if controller.manual_mode: + world.player.apply_control(controller.control) + else: + control = agent.run_step() + control.manual_gear_shift = False + world.player.apply_control(control) + + if agent.done(): + new_dest = random.choice(spawn_points).location + agent.set_destination(new_dest) + hud.notification("已到达,切换新目标", 1) + + finally: + if world: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA Automatic Control Client') + argparser.add_argument('--host', default='127.0.0.1') + argparser.add_argument('--port', default=2000, type=int) + argparser.add_argument('--res', default='1280x720') + argparser.add_argument('--filter', default='vehicle.*') + argparser.add_argument('-b', '--behavior', default='normal') + args = argparser.parse_args() + args.width, args.height = map(int, args.res.split('x')) + + logging.basicConfig(level=logging.INFO) + game_loop(args) + +if __name__ == '__main__': + main() From 645d126a0ad3ed399a981063f817a47305e26a55 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 11 Jun 2026 13:08:10 +0800 Subject: [PATCH 25/28] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=9C=80=E7=BB=88?= =?UTF-8?q?=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/carla_driving/README.md | 596 +++++++++++++++++++++++++++++++++++ 1 file changed, 596 insertions(+) create mode 100644 docs/carla_driving/README.md diff --git a/docs/carla_driving/README.md b/docs/carla_driving/README.md new file mode 100644 index 0000000000..9632f61d4e --- /dev/null +++ b/docs/carla_driving/README.md @@ -0,0 +1,596 @@ +🚗 CARLA 0.9.15 自动驾驶与车道保持控制系统 + +基于 CARLA 仿真器(0.9.15 版本)实现的自动驾驶控制项目,涵盖交通灯识别与响应、自动路径规划与导航、实时天气切换、手动/自动驾驶模式切换等功能。项目提供了多个渐进式脚本,从最基础的自动驾驶到完整功能版,方便学习和二次开发。 + + + +目录 + +• 项目背景 +• 功能特性 +• 项目结构 +• 脚本详解 +• 核心架构 +◦ 系统架构图 +◦ 核心类说明 +◦ 传感器体系 +◦ 驾驶行为模式 +◦ 天气系统 +• 环境要求 +• 安装 +• 使用方法 +◦ 方式一:一键启动(Windows) +◦ 方式二:手动启动 +◦ 命令行参数 +◦ 键盘操作 +• 工作原理 +◦ 交通灯检测与响应流程 +◦ 自动导航流程 +◦ 手动/自动切换流程 +• 配置说明 +• 常见问题 +• 扩展开发指南 +• 更新日志 +• 许可证 +• 致谢 + + + +项目背景 + +自动驾驶仿真是自动驾驶研发中不可或缺的环节。CARLA 是由 Intel Labs 主导开发的开源自动驾驶仿真平台,提供了丰富的城市环境、车辆模型、传感器和交通场景。 + +本项目基于 CARLA 0.9.15,从官方示例出发,逐步构建了一套实用的自动驾驶控制系统。项目特别针对以下痛点进行了适配: + +• Python 3.9 兼容性:CARLA 旧版 .egg 导入机制在 Python 3.9+ 下存在冲突,项目提供了完整的修复方案 +• 功能渐进式组合:不同脚本对应不同功能组合,可按需选用 +• 轻量独立方案:world_Coordinate.py 提供了不依赖 CARLA 内置 Agent 的极简自动导航,方便理解和定制 + + + +功能特性 + +功能 说明 +🗺️ 自动导航 基于 BehaviorAgent 实现路径规划与自动驾驶,到达目标后自动切换新目标 +🚦 交通灯检测 通过 CARLA 内置目标包围框检测交通灯状态,红灯停车、绿灯通行 +🌦️ 天气切换 运行时键盘切换 CARLA 内置天气预设(晴天、多云、雨天、雾天等数十种) +🔄 手动/自动切换 支持自动驾驶与手动键盘操控之间实时切换,无需重启 +📡 多传感器融合 碰撞检测、车道偏离检测、GNSS 定位、RGB 摄像头 +🖥️ HUD 实时信息 车速、坐标、航向角、驾驶模式、FPS 等实时显示 +🐍 Python 3.9 适配 修复 egg 导入冲突,兼容 CARLA 0.9.15 最新 API +🪶 极简导航方案 SimpleAutoAgent 纯自实现导航,不依赖第三方 Agent 库 + + + +项目结构 + +carla_driving_car_lane/ +├── main.py # 🔰 主入口:基础自动驾驶 + 天气切换 +├── automatic_control.py # 🐍 Python 3.9 适配版自动驾驶 +├── Add_weather_switching.py # 🌦️ 自动驾驶 + 天气实时切换 +├── Automatic_model # ⭐ 完整功能版:手动/自动 + HUD + 天气 +├── Switch_automatic # 🔄 纯自动驾驶 + 天气切换 +├── world_Coordinate.py # 🪶 极简版:自实现 SimpleAutoAgent,零外部依赖 +├── automatic_control/ +│ └── automatic_control.py # 📦 自动驾驶控制(备选版本) +├── start_carla_sim.bat # 🖥️ Windows 一键启动脚本 +├── Requirements.txt # 📋 Python 依赖 +└── README.md # 📖 本文件 + + + + +脚本详解 + +脚本功能对比 + +脚本 自动导航 天气切换 手动驾驶 HUD 面板 适配修复 导航方式 快捷键 +main.py ✅ ✅ ❌ 基础 ❌ BehaviorAgent TAB +automatic_control.py ✅ ❌ ❌ 基础 ✅ BehaviorAgent — +Add_weather_switching.py ✅ ✅ ❌ 基础 ✅ BehaviorAgent TAB +Automatic_model ✅ ✅ ✅ 增强 ✅ BehaviorAgent C / TAB / WASD +Switch_automatic ✅ ✅ ❌ 基础 ✅ BehaviorAgent TAB +world_Coordinate.py ✅ ✅ ❌ 增强 ✅ SimpleAutoAgent PageUp/Down + + +💡 推荐使用顺序:world_Coordinate.py(理解原理)→ main.py(体验基础功能)→ Automatic_model(完整体验) +各脚本详细说明 +`main.py` — 基础入门版 +最接近 CARLA 官方示例的版本,集成了碰撞/车道/GNSS 传感器和天气切换功能。适合初次接触 CARLA 自动驾驶的用户。 +• 传感器:碰撞、车道偏离、GNSS、RGB 摄像头 +• 自动导航使用 BehaviorAgent,到达目标后自动换新目标 +• 支持天气预设切换 +`automatic_control.py` — Python 3.9 适配版 +针对 Python 3.9 环境的适配版本,修复了 .egg 文件导入冲突问题。如果你的 Python 环境是 3.9+,建议优先使用此版本。 +• 清理了 carla/dist 下的冲突 .egg 路径 +• 传感器全部修复完成,运行稳定 +• 纯自动驾驶,无天气切换 +`Add_weather_switching.py` — 天气增强版 +在 Python 3.9 适配版基础上增加了天气实时切换功能,按 TAB 键即可在不同天气预设间切换。 +`Automatic_model` — ⭐ 完整功能版(推荐) +功能最完整的版本,包含手动/自动驾驶切换、增强 HUD 面板和天气切换。 +增强功能: +• 按 C 键在手动/自动驾驶之间切换 +• 手动模式下使用 WASD 控制车辆 +• HUD 显示:驾驶模式、车速(km/h)、坐标(X/Y)、航向角 +• 碰撞和车道偏离事件实时通知 +• 默认加载 Town01 地图 +`Switch_automatic` — 纯自动 + 天气版 +自动驾驶 + 天气切换的精简组合,无手动驾驶功能。适合需要纯自动驾驶演示的场景。 +`world_Coordinate.py` — 极简独立版 +项目中最轻量的自动驾驶方案,完全不依赖 CARLA 内置的 Agent 库,自己实现了 SimpleAutoAgent。 +特点: +• 自实现导航逻辑(基于向量点积和叉积计算转向角) +• 阻断所有可能冲突的第三方库(matplotlib/scipy/tensorflow/torch/keras) +• 摄像头位置根据车辆包围盒动态计算 +• HUD 显示 FPS、车速和行驶状态 +• 天气切换使用 PageUp/PageDown +SimpleAutoAgent 导航逻辑: +// python +# 计算车辆前方与目标方向的关系 +dot = forward.x * target_dir.x + forward.y * target_dir.y # 点积:判断前后 +cross = forward.x * target_dir.y - forward.y * target_dir.x # 叉积:判断左右 + +# 距离 > 5m:油门 0.5 + 微调转向;距离 ≤ 5m:刹车 + + +核心架构 +系统架构图 +┌──────────────────────────────────────────────────────────────┐ +│ CARLA 仿真引擎 │ +│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ +│ │ 地图场景 │ │ 交通系统 │ │ 天气系统 │ │ 物理引擎 │ │ +│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ +└──────────────────────┬───────────────────────────────────────┘ + │ TCP (2000 端口) +┌──────────────────────┼───────────────────────────────────────┐ +│ Python 客户端 │ +│ ┌───────────────────┼───────────────────┐ │ +│ │ World 场景管理 │ │ +│ │ ┌──────────┐ ┌──┴──┐ ┌──────────┐ │ │ +│ │ │ 传感器管理 │ │车辆 │ │ 相机管理 │ │ │ +│ │ └──────────┘ └─────┘ └──────────┘ │ │ +│ └───────────────────────────────────────┘ │ +│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │ +│ │ 导航代理 │ │ 控制器 │ │ HUD 显示 │ │ +│ │ BehaviorAgent │ │ KeyboardCtrl │ │ FadingText │ │ +│ │ SimpleAgent │ │ (WASD/切换) │ │ (信息面板) │ │ +│ └──────────────┘ └──────────────┘ └──────────────┘ │ +└──────────────────────┬───────────────────────────────────────┘ + │ +┌──────────────────────┼───────────────────────────────────────┐ +│ Pygame 可视化界面 │ +│ ┌────────────────────────────────────────────────────┐ │ +│ │ RGB 摄像头画面 (1280×720) │ │ +│ │ ┌──────────────────────────────────┐ │ │ +│ │ │ 模式: 自动驾驶 │ │ │ +│ │ │ 车速: 45.2 km/h │ │ │ +│ │ │ 坐标: X:123.4 Y:56.7 │ │ │ +│ │ │ 航向: 89.2° │ │ │ +│ │ └──────────────────────────────────┘ │ │ +│ └────────────────────────────────────────────────────┘ │ +└──────────────────────────────────────────────────────────────┘ + +核心类说明 +类名 所属脚本 职责 +World 全部 场景管理:车辆生成/销毁、传感器挂载、天气切换 +KeyboardControl 全部 键盘事件处理:退出、天气切换、驾驶模式切换、手动驾驶 +HUD 全部 HUD 信息渲染:FPS、车速、坐标、通知消息 +FadingText 全部 渐隐文字效果:碰撞/车道偏离等事件通知 +CollisionSensor 全部 碰撞传感器:检测与其他 Actor 的碰撞并通知 +LaneInvasionSensor 全部 车道偏离传感器:检测压线/越线行为 +GnssSensor main/Automatic_model/Switch GNSS 传感器:获取经纬度坐标 +CameraManager 全部 摄像头管理:RGB 图像采集与 Pygame 渲染 +BehaviorAgent 大部分脚本 CARLA 内置导航代理:路径规划 + 行为决策 +SimpleAutoAgent world_Coordinate.py 自实现导航代理:基于向量运算的极简导航 + +传感器体系 +本项目使用了 CARLA 提供的多种传感器,构成完整的感知体系: + 车辆 (Vehicle) + │ + ┌───────┬───────┼───────┬────────┐ + ▼ ▼ ▼ ▼ ▼ + ┌────────┐┌──────┐┌──────┐┌──────┐┌──────┐ + │RGB相机 ││碰撞 ││车道 ││GNSS ││可扩展 │ + │ ││传感器 ││偏离 ││传感器││传感器 │ + │1280×720││ ││传感器 ││ ││(雷达) │ + └────────┘└──────┘└──────┘└──────┘└──────┘ + │ │ │ │ + ▼ ▼ ▼ ▼ + 画面渲染 碰撞通知 越线通知 定位数据 + +传感器 Blueprint ID 挂载方式 输出 +RGB 摄像头 sensor.camera.rgb SpringArm(车后上方) 1280×720 图像 → Pygame 渲染 +碰撞传感器 sensor.other.collision 附着车辆 碰撞事件 → HUD 通知 +车道偏离 sensor.other.lane_invasion 附着车辆 越线事件 → HUD 通知 +GNSS sensor.other.gnss 车顶(z+2.0) 经纬度数据 + +驾驶行为模式 +使用 BehaviorAgent 的脚本支持三种驾驶行为,通过 --behavior 参数指定: +模式 说明 油门 跟车距离 变道频率 +normal 正常驾驶,遵守交通规则 适中 适中 适时变道 +cautious 谨慎驾驶,大跟车距离 较低 较大 较少变道 +aggressive 激进驾驶,快速行驶 较高 较小 频繁变道 + +// bash +# 谨慎模式 +python Automatic_model --behavior cautious + +# 激进模式 +python Automatic_model --behavior aggressive + +天气系统 +CARLA 0.9.15 内置了数十种天气预设,项目通过 find_weather_presets() 函数自动枚举所有可用预设。常见预设包括: +类别 预设示例 +☀️ 晴天 ClearNoon, ClearSunset, ClearNight +☁️ 多云 CloudyNoon, OvercastRain +🌧️ 雨天 SoftRainNoon, HardRainNoon, HeavyRainSunset +🌫️ 雾天 Fog +🌧️💨 暴风雨 HardRainNoon + 强风 + +切换方式因脚本而异: +• 大部分脚本:TAB 键循环切换 +• world_Coordinate.py:PageUp / PageDown 正反向切换 + +环境要求 +项目 最低要求 推荐配置 +CARLA 仿真器 0.9.15 0.9.15 +Python 3.9+ 3.9.x +操作系统 Windows 10(仿真器端) Windows 10/11 +GPU NVIDIA GTX 1060 6GB NVIDIA RTX 3060 及以上 +内存 16 GB 32 GB +磁盘 30 GB(CARLA 安装) SSD +网络 本地回环(单机) 局域网(多机联仿) + +⚠️ CARLA 仿真器仅支持 Windows/Linux,macOS 不支持。Python 客户端可在 macOS 上远程连接 CARLA 服务器。 + +安装 +1. 安装 CARLA 0.9.15 仿真器 +从 CARLA Release 页面 下载 0.9.15 版本,解压至默认路径: +D:\carla0.9.15\ +├── CarlaUE4.exe # 仿真器主程序 +├── CarlaUE4\ # 引擎资源 +├── PythonAPI\ # Python 接口 +│ ├── carla\ # carla 模块 +│ │ └── dist\ # .egg 文件(旧版用) +│ └── examples\ # 官方示例 +├── Import\ # 资源导入目录 +└── Util\ # 工具脚本 + +2. 安装 Python 依赖 +// bash +# 推荐使用虚拟环境 +python -m venv .venv +.venv\Scripts\activate # Windows +# source .venv/bin/activate # Linux + +pip install -r Requirements.txt + +依赖详情: +包名 版本 必选 说明 +carla 0.9.15 ✅ CARLA PythonAPI 客户端库 +pygame 2.1.0 ✅ 仿真界面渲染与键盘输入 +numpy 1.23.5 ✅ 数值计算与图像数组处理 +opencv-python 4.8.0.76 ❌ 图像处理(扩展功能) +matplotlib 3.7.1 ❌ 数据可视化(扩展功能) +Pillow 9.4.0 ❌ 图像处理(扩展功能) +torch 2.0.0 ❌ 深度学习检测模型(可选) +torchvision 0.15.1 ❌ 视觉模型(配合 torch 使用) + + +使用方法 +方式一:一键启动(Windows) +双击运行 start_carla_sim.bat,脚本会自动完成以下步骤: +[1] 启动 CARLA 仿真器 → CarlaUE4.exe -quality-level=Low +[2] 等待 15 秒服务器就绪 +[3] 运行自动驾驶脚本 → automatic_control.py + +⚠️ 使用前需修改 .bat 文件中的路径,详见 配置说明。 +方式二:手动启动 +步骤 1:启动 CARLA 仿真器 +// bash +# Windows — 低画质模式(推荐,性能友好) +CarlaUE4.exe -quality-level=Low + +# Windows — 高画质模式 +CarlaUE4.exe -quality-level=Epic + +# Linux +./CarlaUE4.sh -quality-level=Low + +# 指定窗口化运行 +CarlaUE4.exe -windowed -ResX=1280 -ResY=720 + +步骤 2:等待仿真器就绪(控制台显示 "CarlaServer ready" 后继续) +步骤 3:运行自动驾驶脚本 +// bash +# 完整功能版(推荐首次使用) +python Automatic_model + +# 极简版(理解导航原理) +python world_Coordinate.py + +# 基础版 +python main.py + +# 指定服务器地址和参数 +python main.py --host 127.0.0.1 --port 2000 --res 1280x720 --behavior normal + +# 连接远程 CARLA 服务器 +python main.py --host 192.168.1.100 --port 2000 + +命令行参数 +参数 默认值 说明 +--host 127.0.0.1 CARLA 服务器地址(本机或远程 IP) +--port 2000 CARLA 服务器端口 +--res 1280x720 渲染分辨率,格式:宽x高 +--filter vehicle.* 车辆蓝图过滤(如 vehicle.tesla.model3) +-b / --behavior normal 驾驶行为模式:normal / cautious / aggressive + +示例: +// bash +# 使用特定车辆模型 +python Automatic_model --filter vehicle.tesla.model3 + +# 4K 分辨率 + 激进模式 +python Automatic_model --res 3840x2160 --behavior aggressive + +# 连接远程服务器 + 谨慎模式 +python main.py --host 192.168.1.100 --behavior cautious + +键盘操作 +通用操作 +按键 功能 适用脚本 +ESC 退出程序 全部 +Ctrl+Q 退出程序 全部 +TAB 切换天气预设 main.py / Automatic_model / Switch_automatic +PageUp 上一个天气预设 world_Coordinate.py +PageDown 下一个天气预设 world_Coordinate.py + +手动驾驶模式(仅 `Automatic_model`) +按键 功能 +C 切换手动/自动驾驶模式 +W 油门(加速) +S 刹车(减速) +A 左转向 +D 右转向 + +💡 切换到手动模式后,HUD 会显示"手动驾驶模式"提示,此时 WASD 控制生效。 + +工作原理 +交通灯检测与响应流程 + CARLA 仿真世界 + │ + ▼ + ┌──────────────────┐ + │ 获取世界中的交通灯 │ + └────────┬─────────┘ + │ + ▼ + ┌──────────────────┐ + │ 判断交通灯状态 │ + │ (红/黄/绿) │ + └────────┬─────────┘ + │ + ┌─────┴─────┐ + ▼ ▼ + 红灯 🛑 绿灯 🟢 + │ │ + ▼ ▼ + 刹车=1.0 油门恢复 + 停车等待 正常行驶 + +1. 客户端通过 CARLA API 获取世界中所有交通灯 Actor +2. 根据车辆位置和朝向,判断前方是否有交通灯 +3. 检测交通灯的 state 属性(Red / Yellow / Green) +4. 红灯/黄灯时:设置 brake = 1.0,throttle = 0.0 +5. 绿灯时:恢复正常行驶,由 BehaviorAgent 计算控制指令 +自动导航流程 + ┌────────────────┐ + │ 随机选择出生点 │ + └───────┬────────┘ + │ + ▼ + ┌────────────────┐ + │ 生成车辆 Actor │ ← vehicle.* 蓝图过滤 + └───────┬────────┘ + │ + ▼ + ┌────────────────┐ + │ 设置导航目标 │ ← 随机选择 spawn point + └───────┬────────┘ + │ + ▼ + ┌────────────────┐ ┌────────────────┐ + │ BehaviorAgent │────►│ 计算控制指令 │ + │ run_step() │ │ (throttle/steer │ + └───────┬────────┘ │ /brake) │ + │ └────────────────┘ + ▼ + ┌────────────────┐ + │ 应用控制到车辆 │ + └───────┬────────┘ + │ + ▼ + ┌───────────────┐ 否 + │ 是否到达目标? │──────────┘ + └───────┬───────┘ ↑ + 是 │ │ + ▼ │ + ┌────────────────┐ │ + │ 自动设置新目标 │─────┘ + └────────────────┘ + +手动/自动切换流程 + ┌─────────────┐ + │ 程序启动 │ + │ 默认:自动 │ + └──────┬──────┘ + │ + ┌──────────┴──────────┐ + ▼ ▼ + ┌────────────┐ ┌────────────┐ + │ 自动模式 │ │ 手动模式 │ + │ │ C │ │ + │ Agent 计算 │◄──────►│ WASD 控制 │ + │ 控制指令 │ C │ 油门/刹车 │ + │ │◄──────►│ /转向 │ + └────────────┘ └────────────┘ + + +配置说明 +CARLA 安装路径 +如 CARLA 安装路径非默认,需修改各 Python 脚本顶部的路径变量: +// python +CARLA_ROOT = r"D:\carla0.9.15" # ← 修改为你的 CARLA 安装路径 + +涉及文件:main.py、automatic_control.py、Add_weather_switching.py、Automatic_model、Switch_automatic +一键启动脚本路径 +修改 start_carla_sim.bat 中的以下路径: +// bat +:: CARLA 仿真器路径 +start "" "D:\carla0.9.15\CarlaUE4.exe" -quality-level=Low + +:: Python 解释器路径 +"D:\carla_automatic1\.venv\Scripts\python.exe" + +:: 自动驾驶脚本路径 +"D:\carla_automatic1\automatic_control.py" + +分辨率调整 +可通过命令行参数或修改代码调整渲染分辨率: +// bash +# 命令行方式 +python main.py --res 1920x1080 + +# 代码方式(修改 main() 函数中的默认值) +argparser.add_argument('--res', default='1920x1080') + +CARLA 服务器性能调优 +参数 说明 示例 +-quality-level=Low 低画质,性能优先 CarlaUE4.exe -quality-level=Low +-quality-level=Epic 高画质,视觉优先 CarlaUE4.exe -quality-level=Epic +-world-port=2000 指定通信端口 CarlaUE4.exe -world-port=3000 +-carla-rpc-port=3000 指定 RPC 端口 CarlaUE4.exe -carla-rpc-port=3000 + + +常见问题 +Q1: 启动脚本报错 `ModuleNotFoundError: No module named 'carla'` +原因:CARLA PythonAPI 路径未正确配置。 +解决: +1. 确认 CARLA_ROOT 路径指向正确的 CARLA 安装目录 +2. 确认目录下存在 PythonAPI/carla/ 文件夹 +3. Python 3.9+ 用户使用 automatic_control.py 等已适配版本 +Q2: 连接 CARLA 服务器超时 `RuntimeError: time-out` +原因:仿真器未启动或未就绪。 +解决: +1. 先启动 CarlaUE4.exe,等待控制台显示 "ready" +2. 确认端口一致(默认 2000) +3. 可尝试增大超时时间:client.set_timeout(30.0) +Q3: Python 3.9 下 egg 导入报错 +原因:CARLA 旧版 .egg 文件与 Python 3.9 不兼容。 +解决:使用 automatic_control.py 等已适配版本,脚本会自动清理冲突路径: +// python +# 已在脚本中处理 +for path in list(sys.path): + if "carla/dist" in path and path.endswith(".egg"): + sys.path.remove(path) + +Q4: 画面卡顿 / FPS 过低 +解决: +1. 使用低画质模式启动:CarlaUE4.exe -quality-level=Low +2. 降低分辨率:python main.py --res 800x600 +3. 关闭不必要的后台程序 +4. 确认 GPU 驱动已更新 +Q5: 导入 BehaviorAgent 报错 `ModuleNotFoundError` +原因:缺少 CARLA Agent 模块。 +解决:确认 CARLA 安装目录下存在 PythonAPI/carla/agents/ 目录。如不存在,可使用 world_Coordinate.py 中的 SimpleAutoAgent 替代。 +Q6: 碰撞后车辆不恢复行驶 +原因:碰撞传感器仅做通知,不处理恢复逻辑。 +解决:可在碰撞回调中添加恢复逻辑,如短暂停车后重新规划路径。 + +扩展开发指南 +添加新传感器 +参照现有传感器类的实现模式,在 World.restart() 中挂载: +// python +class MyCustomSensor(object): + def __init__(self, parent_actor, hud): + bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.obstacle') + self.sensor = parent_actor.get_world().spawn_actor( + bp, carla.Transform(), attach_to=parent_actor) + self.sensor.listen(lambda event: self._on_event(event)) + + def _on_event(self, event): + # 处理传感器数据 + pass + +可用的传感器 Blueprint: +Blueprint ID 说明 +sensor.camera.rgb RGB 摄像头 +sensor.camera.depth 深度摄像头 +sensor.camera.semantic_segmentation 语义分割摄像头 +sensor.lidar.ray_cast 激光雷达 +sensor.other.radar 毫米波雷达 +sensor.other.imu 惯性测量单元 +sensor.other.obstacle 障碍物检测 + +切换地图 +修改 game_loop() 中的地图加载: +// python +# 加载指定地图 +client.load_world('Town03') + +# 可用地图:Town01 ~ Town10HD +# Town01: 简单小镇,适合测试 +# Town03: 圆环交叉路口 +# Town05: 高架桥与隧道 +# Town10HD: 高清城市 + +添加更多车辆 +修改 --filter 参数或在代码中指定: +// python +# 特定车型 +argparser.add_argument('--filter', default='vehicle.tesla.model3') + +# 所有两轮车 +argparser.add_argument('--filter', default='vehicle.*.bike') + +# 所有摩托车 +argparser.add_argument('--filter', default='vehicle.*.motorcycle') + +自定义 SimpleAutoAgent +world_Coordinate.py 中的 SimpleAutoAgent 是最易修改的导航方案,适合快速实验: +// python +class SimpleAutoAgent: + def run_step(self): + control = carla.VehicleControl() + # ← 在这里修改你的控制逻辑 + # 可加入:PID 控制、纯跟踪算法、深度学习模型等 + return control + + +更新日志 +v1.0.0 +• 基础自动驾驶功能(main.py) +• 碰撞/车道偏离/GNSS 传感器集成 +• 天气切换功能 +v1.1.0 +• Python 3.9 适配,修复 .egg 导入冲突 +• 新增 automatic_control.py / Add_weather_switching.py +• 新增 Switch_automatic 脚本 +v1.2.0 +• 完整功能版 Automatic_model:手动/自动切换、增强 HUD +• 极简独立版 world_Coordinate.py:自实现 SimpleAutoAgent +• Windows 一键启动脚本 start_carla_sim.bat + +许可证 +MIT License — 基于 Intel Labs 原始代码适配修改。 +详见 LICENSE + +致谢 +• CARLA Simulator — 开源自动驾驶仿真平台 +• Intel Labs — CARLA 原始代码贡献 +• 原始代码作者:German Ros (german.ros@gmail.com) +• CARLA 文档 — API 参考与教程 + +本内容由 Coze AI 生成,请遵循相关法律法规及《人工智能生成合成内容标识办法》使用与传播。 From 2ecfa7ce56ce55b1f34d85baaadce8c2f99b2d5d Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Thu, 11 Jun 2026 13:09:59 +0800 Subject: [PATCH 26/28] Update README.md --- docs/carla_driving/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/carla_driving/README.md b/docs/carla_driving/README.md index 9632f61d4e..b68be816b8 100644 --- a/docs/carla_driving/README.md +++ b/docs/carla_driving/README.md @@ -593,4 +593,3 @@ MIT License — 基于 Intel Labs 原始代码适配修改。 • 原始代码作者:German Ros (german.ros@gmail.com) • CARLA 文档 — API 参考与教程 -本内容由 Coze AI 生成,请遵循相关法律法规及《人工智能生成合成内容标识办法》使用与传播。 From d7a27c802c4282f8c7302a3e1aa6b939cba39725 Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Fri, 12 Jun 2026 17:25:15 +0800 Subject: [PATCH 27/28] Update index.md --- docs/index.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 1283021a0a..909540c387 100644 --- a/docs/index.md +++ b/docs/index.md @@ -75,6 +75,9 @@ title: 主页 [__基于自监督学习与PPO强化学习的自动驾驶仿真项目__](./autonomous_driving/README.md) - 基于CARLA的SSL+RL自动驾驶仿真系统 +[__CARLA 0.9.15 自动驾驶与车道保持控制系统__](./carla_driving/README.md) + + ## 规划 @@ -109,4 +112,4 @@ title: 主页 [__CARLA IMU 数据采集平台__](./carla_imu/carla_imu.md) — CARLA惯性测量单元数据采集与可视化驾驶平台开发汇报文档 -[__setup_tool模块汇报文档__](./setup_tool/report.md) - setup_tool 模块背景、改进内容、运行方式与效果总结 \ No newline at end of file +[__setup_tool模块汇报文档__](./setup_tool/report.md) - setup_tool 模块背景、改进内容、运行方式与效果总结 From d86559ab718589d2899ad9fe159283fb5c13567f Mon Sep 17 00:00:00 2001 From: dym-commit <490837107@qq.com> Date: Fri, 12 Jun 2026 17:34:27 +0800 Subject: [PATCH 28/28] Update README.md --- docs/carla_driving/README.md | 663 ++++++++++++++++++----------------- 1 file changed, 342 insertions(+), 321 deletions(-) diff --git a/docs/carla_driving/README.md b/docs/carla_driving/README.md index b68be816b8..75daeff321 100644 --- a/docs/carla_driving/README.md +++ b/docs/carla_driving/README.md @@ -1,69 +1,57 @@ -🚗 CARLA 0.9.15 自动驾驶与车道保持控制系统 - +# 🚗 CARLA 0.9.15 自动驾驶与车道保持控制系统 基于 CARLA 仿真器(0.9.15 版本)实现的自动驾驶控制项目,涵盖交通灯识别与响应、自动路径规划与导航、实时天气切换、手动/自动驾驶模式切换等功能。项目提供了多个渐进式脚本,从最基础的自动驾驶到完整功能版,方便学习和二次开发。 - - -目录 - -• 项目背景 -• 功能特性 -• 项目结构 -• 脚本详解 -• 核心架构 -◦ 系统架构图 -◦ 核心类说明 -◦ 传感器体系 -◦ 驾驶行为模式 -◦ 天气系统 -• 环境要求 -• 安装 -• 使用方法 -◦ 方式一:一键启动(Windows) -◦ 方式二:手动启动 -◦ 命令行参数 -◦ 键盘操作 -• 工作原理 -◦ 交通灯检测与响应流程 -◦ 自动导航流程 -◦ 手动/自动切换流程 -• 配置说明 -• 常见问题 -• 扩展开发指南 -• 更新日志 -• 许可证 -• 致谢 - - - -项目背景 - +## 目录 +- 项目背景 +- 功能特性 +- 项目结构 +- 脚本详解 +- 核心架构 + - 系统架构图 + - 核心类说明 + - 传感器体系 + - 驾驶行为模式 + - 天气系统 +- 环境要求 +- 安装 +- 使用方法 + - 方式一:一键启动(Windows) + - 方式二:手动启动 + - 命令行参数 + - 键盘操作 +- 工作原理 + - 交通灯检测与响应流程 + - 自动导航流程 + - 手动/自动切换流程 +- 配置说明 +- 常见问题 +- 扩展开发指南 +- 更新日志 +- 许可证 +- 致谢 + +## 项目背景 自动驾驶仿真是自动驾驶研发中不可或缺的环节。CARLA 是由 Intel Labs 主导开发的开源自动驾驶仿真平台,提供了丰富的城市环境、车辆模型、传感器和交通场景。 本项目基于 CARLA 0.9.15,从官方示例出发,逐步构建了一套实用的自动驾驶控制系统。项目特别针对以下痛点进行了适配: - -• Python 3.9 兼容性:CARLA 旧版 .egg 导入机制在 Python 3.9+ 下存在冲突,项目提供了完整的修复方案 -• 功能渐进式组合:不同脚本对应不同功能组合,可按需选用 -• 轻量独立方案:world_Coordinate.py 提供了不依赖 CARLA 内置 Agent 的极简自动导航,方便理解和定制 - - - -功能特性 - -功能 说明 -🗺️ 自动导航 基于 BehaviorAgent 实现路径规划与自动驾驶,到达目标后自动切换新目标 -🚦 交通灯检测 通过 CARLA 内置目标包围框检测交通灯状态,红灯停车、绿灯通行 -🌦️ 天气切换 运行时键盘切换 CARLA 内置天气预设(晴天、多云、雨天、雾天等数十种) -🔄 手动/自动切换 支持自动驾驶与手动键盘操控之间实时切换,无需重启 -📡 多传感器融合 碰撞检测、车道偏离检测、GNSS 定位、RGB 摄像头 -🖥️ HUD 实时信息 车速、坐标、航向角、驾驶模式、FPS 等实时显示 -🐍 Python 3.9 适配 修复 egg 导入冲突,兼容 CARLA 0.9.15 最新 API -🪶 极简导航方案 SimpleAutoAgent 纯自实现导航,不依赖第三方 Agent 库 - - - -项目结构 - +- Python 3.9 兼容性:CARLA 旧版 .egg 导入机制在 Python 3.9+ 下存在冲突,项目提供了完整的修复方案 +- 功能渐进式组合:不同脚本对应不同功能组合,可按需选用 +- 轻量独立方案:`world_Coordinate.py` 提供了不依赖 CARLA 内置 Agent 的极简自动导航,方便理解和定制 + +## 功能特性 +| 功能 | 说明 | +| ---- | ---- | +| 🗺️ 自动导航 | 基于 BehaviorAgent 实现路径规划与自动驾驶,到达目标后自动切换新目标 | +| 🚦 交通灯检测 | 通过 CARLA 内置目标包围框检测交通灯状态,红灯停车、绿灯通行 | +| 🌦️ 天气切换 | 运行时键盘切换 CARLA 内置天气预设(晴天、多云、雨天、雾天等数十种) | +| 🔄 手动/自动切换 | 支持自动驾驶与手动键盘操控之间实时切换,无需重启 | +| 📡 多传感器融合 | 碰撞检测、车道偏离检测、GNSS 定位、RGB 摄像头 | +| 🖥️ HUD 实时信息 | 车速、坐标、航向角、驾驶模式、FPS 等实时显示 | +| 🐍 Python 3.9 适配 | 修复 egg 导入冲突,兼容 CARLA 0.9.15 最新 API | +| 🪶 极简导航方案 | SimpleAutoAgent 纯自实现导航,不依赖第三方 Agent 库 | + +## 项目结构 +``` carla_driving_car_lane/ ├── main.py # 🔰 主入口:基础自动驾驶 + 天气切换 ├── automatic_control.py # 🐍 Python 3.9 适配版自动驾驶 @@ -76,66 +64,68 @@ carla_driving_car_lane/ ├── start_carla_sim.bat # 🖥️ Windows 一键启动脚本 ├── Requirements.txt # 📋 Python 依赖 └── README.md # 📖 本文件 - - - - -脚本详解 - -脚本功能对比 - -脚本 自动导航 天气切换 手动驾驶 HUD 面板 适配修复 导航方式 快捷键 -main.py ✅ ✅ ❌ 基础 ❌ BehaviorAgent TAB -automatic_control.py ✅ ❌ ❌ 基础 ✅ BehaviorAgent — -Add_weather_switching.py ✅ ✅ ❌ 基础 ✅ BehaviorAgent TAB -Automatic_model ✅ ✅ ✅ 增强 ✅ BehaviorAgent C / TAB / WASD -Switch_automatic ✅ ✅ ❌ 基础 ✅ BehaviorAgent TAB -world_Coordinate.py ✅ ✅ ❌ 增强 ✅ SimpleAutoAgent PageUp/Down - - -💡 推荐使用顺序:world_Coordinate.py(理解原理)→ main.py(体验基础功能)→ Automatic_model(完整体验) -各脚本详细说明 -`main.py` — 基础入门版 +``` + +## 脚本详解 +### 脚本功能对比 +| 脚本 | 自动导航 | 天气切换 | 手动驾驶 | HUD 面板 | 适配修复 | 导航方式 | 快捷键 | +| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| main.py | ✅ | ✅ | ❌ | 基础 | ❌ | BehaviorAgent | TAB | +| automatic_control.py | ✅ | ❌ | ❌ | 基础 | ✅ | BehaviorAgent | — | +| Add_weather_switching.py | ✅ | ✅ | ❌ | 基础 | ✅ | BehaviorAgent | TAB | +| Automatic_model | ✅ | ✅ | ✅ | 增强 | ✅ | BehaviorAgent | C / TAB / WASD | +| Switch_automatic | ✅ | ✅ | ❌ | 基础 | ✅ | BehaviorAgent | TAB | +| world_Coordinate.py | ✅ | ✅ | ❌ | 增强 | ✅ | SimpleAutoAgent | PageUp/Down | + +> 💡 推荐使用顺序:world_Coordinate.py(理解原理)→ main.py(体验基础功能)→ Automatic_model(完整体验) + +### 各脚本详细说明 +#### `main.py` — 基础入门版 最接近 CARLA 官方示例的版本,集成了碰撞/车道/GNSS 传感器和天气切换功能。适合初次接触 CARLA 自动驾驶的用户。 -• 传感器:碰撞、车道偏离、GNSS、RGB 摄像头 -• 自动导航使用 BehaviorAgent,到达目标后自动换新目标 -• 支持天气预设切换 -`automatic_control.py` — Python 3.9 适配版 +- 传感器:碰撞、车道偏离、GNSS、RGB 摄像头 +- 自动导航使用 BehaviorAgent,到达目标后自动换新目标 +- 支持天气预设切换 + +#### `automatic_control.py` — Python 3.9 适配版 针对 Python 3.9 环境的适配版本,修复了 .egg 文件导入冲突问题。如果你的 Python 环境是 3.9+,建议优先使用此版本。 -• 清理了 carla/dist 下的冲突 .egg 路径 -• 传感器全部修复完成,运行稳定 -• 纯自动驾驶,无天气切换 -`Add_weather_switching.py` — 天气增强版 +- 清理了 carla/dist 下的冲突 .egg 路径 +- 传感器全部修复完成,运行稳定 +- 纯自动驾驶,无天气切换 + +#### `Add_weather_switching.py` — 天气增强版 在 Python 3.9 适配版基础上增加了天气实时切换功能,按 TAB 键即可在不同天气预设间切换。 -`Automatic_model` — ⭐ 完整功能版(推荐) + +#### `Automatic_model` — ⭐ 完整功能版(推荐) 功能最完整的版本,包含手动/自动驾驶切换、增强 HUD 面板和天气切换。 -增强功能: -• 按 C 键在手动/自动驾驶之间切换 -• 手动模式下使用 WASD 控制车辆 -• HUD 显示:驾驶模式、车速(km/h)、坐标(X/Y)、航向角 -• 碰撞和车道偏离事件实时通知 -• 默认加载 Town01 地图 -`Switch_automatic` — 纯自动 + 天气版 +- 按 C 键在手动/自动驾驶之间切换 +- 手动模式下使用 WASD 控制车辆 +- HUD 显示:驾驶模式、车速(km/h)、坐标(X/Y)、航向角 +- 碰撞和车道偏离事件实时通知 +- 默认加载 Town01 地图 + +#### `Switch_automatic` — 纯自动 + 天气版 自动驾驶 + 天气切换的精简组合,无手动驾驶功能。适合需要纯自动驾驶演示的场景。 -`world_Coordinate.py` — 极简独立版 + +#### `world_Coordinate.py` — 极简独立版 项目中最轻量的自动驾驶方案,完全不依赖 CARLA 内置的 Agent 库,自己实现了 SimpleAutoAgent。 -特点: -• 自实现导航逻辑(基于向量点积和叉积计算转向角) -• 阻断所有可能冲突的第三方库(matplotlib/scipy/tensorflow/torch/keras) -• 摄像头位置根据车辆包围盒动态计算 -• HUD 显示 FPS、车速和行驶状态 -• 天气切换使用 PageUp/PageDown +- 自实现导航逻辑(基于向量点积和叉积计算转向角) +- 阻断所有可能冲突的第三方库(matplotlib/scipy/tensorflow/torch/keras) +- 摄像头位置根据车辆包围盒动态计算 +- HUD 显示 FPS、车速和行驶状态 +- 天气切换使用 PageUp/PageDown + SimpleAutoAgent 导航逻辑: -// python +```python # 计算车辆前方与目标方向的关系 dot = forward.x * target_dir.x + forward.y * target_dir.y # 点积:判断前后 cross = forward.x * target_dir.y - forward.y * target_dir.x # 叉积:判断左右 # 距离 > 5m:油门 0.5 + 微调转向;距离 ≤ 5m:刹车 +``` - -核心架构 -系统架构图 +## 核心架构 +### 系统架构图 +``` ┌──────────────────────────────────────────────────────────────┐ │ CARLA 仿真引擎 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ @@ -170,22 +160,24 @@ cross = forward.x * target_dir.y - forward.y * target_dir.x # 叉积:判断 │ │ └──────────────────────────────────┘ │ │ │ └────────────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────────────────┘ - -核心类说明 -类名 所属脚本 职责 -World 全部 场景管理:车辆生成/销毁、传感器挂载、天气切换 -KeyboardControl 全部 键盘事件处理:退出、天气切换、驾驶模式切换、手动驾驶 -HUD 全部 HUD 信息渲染:FPS、车速、坐标、通知消息 -FadingText 全部 渐隐文字效果:碰撞/车道偏离等事件通知 -CollisionSensor 全部 碰撞传感器:检测与其他 Actor 的碰撞并通知 -LaneInvasionSensor 全部 车道偏离传感器:检测压线/越线行为 -GnssSensor main/Automatic_model/Switch GNSS 传感器:获取经纬度坐标 -CameraManager 全部 摄像头管理:RGB 图像采集与 Pygame 渲染 -BehaviorAgent 大部分脚本 CARLA 内置导航代理:路径规划 + 行为决策 -SimpleAutoAgent world_Coordinate.py 自实现导航代理:基于向量运算的极简导航 - -传感器体系 -本项目使用了 CARLA 提供的多种传感器,构成完整的感知体系: +``` + +### 核心类说明 +| 类名 | 所属脚本 | 职责 | +| ---- | ---- | ---- | +| World | 全部 | 场景管理:车辆生成/销毁、传感器挂载、天气切换 | +| KeyboardControl | 全部 | 键盘事件处理:退出、天气切换、驾驶模式切换、手动驾驶 | +| HUD | 全部 | HUD 信息渲染:FPS、车速、坐标、通知消息 | +| FadingText | 全部 | 渐隐文字效果:碰撞/车道偏离等事件通知 | +| CollisionSensor | 全部 | 碰撞传感器:检测与其他 Actor 的碰撞并通知 | +| LaneInvasionSensor | 全部 | 车道偏离传感器:检测压线/越线行为 | +| GnssSensor | main/Automatic_model/Switch | GNSS 传感器:获取经纬度坐标 | +| CameraManager | 全部 | 摄像头管理:RGB 图像采集与 Pygame 渲染 | +| BehaviorAgent | 大部分脚本 | CARLA 内置导航代理:路径规划 + 行为决策 | +| SimpleAutoAgent | world_Coordinate.py | 自实现导航代理:基于向量运算的极简导航 | + +### 传感器体系 +``` 车辆 (Vehicle) │ ┌───────┬───────┼───────┬────────┐ @@ -198,55 +190,63 @@ SimpleAutoAgent world_Coordinate.py 自实现导航代理:基于向量运算 │ │ │ │ ▼ ▼ ▼ ▼ 画面渲染 碰撞通知 越线通知 定位数据 - -传感器 Blueprint ID 挂载方式 输出 -RGB 摄像头 sensor.camera.rgb SpringArm(车后上方) 1280×720 图像 → Pygame 渲染 -碰撞传感器 sensor.other.collision 附着车辆 碰撞事件 → HUD 通知 -车道偏离 sensor.other.lane_invasion 附着车辆 越线事件 → HUD 通知 -GNSS sensor.other.gnss 车顶(z+2.0) 经纬度数据 - -驾驶行为模式 -使用 BehaviorAgent 的脚本支持三种驾驶行为,通过 --behavior 参数指定: -模式 说明 油门 跟车距离 变道频率 -normal 正常驾驶,遵守交通规则 适中 适中 适时变道 -cautious 谨慎驾驶,大跟车距离 较低 较大 较少变道 -aggressive 激进驾驶,快速行驶 较高 较小 频繁变道 - -// bash +``` + +| 传感器 | Blueprint ID | 挂载方式 | 输出 | +| ---- | ---- | ---- | ---- | +| RGB 摄像头 | sensor.camera.rgb | SpringArm(车后上方) | 1280×720 图像 → Pygame 渲染 | +| 碰撞传感器 | sensor.other.collision | 附着车辆 | 碰撞事件 → HUD 通知 | +| 车道偏离 | sensor.other.lane_invasion | 附着车辆 | 越线事件 → HUD 通知 | +| GNSS | sensor.other.gnss | 车顶(z+2.0) | 经纬度数据 | + +### 驾驶行为模式 +使用 BehaviorAgent 的脚本支持三种驾驶行为,通过 `--behavior` 参数指定: +| 模式 | 说明 | 油门 | 跟车距离 | 变道频率 | +| ---- | ---- | ---- | ---- | ---- | +| normal | 正常驾驶,遵守交通规则 | 适中 | 适中 | 适时变道 | +| cautious | 谨慎驾驶,大跟车距离 | 较低 | 较大 | 较少变道 | +| aggressive | 激进驾驶,快速行驶 | 较高 | 较小 | 频繁变道 | + +```bash # 谨慎模式 python Automatic_model --behavior cautious # 激进模式 python Automatic_model --behavior aggressive - -天气系统 -CARLA 0.9.15 内置了数十种天气预设,项目通过 find_weather_presets() 函数自动枚举所有可用预设。常见预设包括: -类别 预设示例 -☀️ 晴天 ClearNoon, ClearSunset, ClearNight -☁️ 多云 CloudyNoon, OvercastRain -🌧️ 雨天 SoftRainNoon, HardRainNoon, HeavyRainSunset -🌫️ 雾天 Fog -🌧️💨 暴风雨 HardRainNoon + 强风 - -切换方式因脚本而异: -• 大部分脚本:TAB 键循环切换 -• world_Coordinate.py:PageUp / PageDown 正反向切换 - -环境要求 -项目 最低要求 推荐配置 -CARLA 仿真器 0.9.15 0.9.15 -Python 3.9+ 3.9.x -操作系统 Windows 10(仿真器端) Windows 10/11 -GPU NVIDIA GTX 1060 6GB NVIDIA RTX 3060 及以上 -内存 16 GB 32 GB -磁盘 30 GB(CARLA 安装) SSD -网络 本地回环(单机) 局域网(多机联仿) - -⚠️ CARLA 仿真器仅支持 Windows/Linux,macOS 不支持。Python 客户端可在 macOS 上远程连接 CARLA 服务器。 - -安装 -1. 安装 CARLA 0.9.15 仿真器 -从 CARLA Release 页面 下载 0.9.15 版本,解压至默认路径: +``` + +### 天气系统 +CARLA 0.9.15 内置了数十种天气预设,项目通过 `find_weather_presets()` 函数自动枚举所有可用预设。 + +| 类别 | 预设示例 | +| ---- | ---- | +| ☀️ 晴天 | ClearNoon, ClearSunset, ClearNight | +| ☁️ 多云 | CloudyNoon, OvercastRain | +| 🌧️ 雨天 | SoftRainNoon, HardRainNoon, HeavyRainSunset | +| 🌫️ 雾天 | Fog | +| 🌧️💨 暴风雨 | HardRainNoon + 强风 | + +切换方式: +- 大部分脚本:TAB 键循环切换 +- world_Coordinate.py:PageUp / PageDown 正反向切换 + +## 环境要求 +| 项目 | 最低要求 | 推荐配置 | +| ---- | ---- | ---- | +| CARLA 仿真器 | 0.9.15 | 0.9.15 | +| Python | 3.9+ | 3.9.x | +| 操作系统 | Windows 10(仿真器端) | Windows 10/11 | +| GPU | NVIDIA GTX 1060 6GB | NVIDIA RTX 3060 及以上 | +| 内存 | 16 GB | 32 GB | +| 磁盘 | 30 GB(CARLA 安装) | SSD | +| 网络 | 本地回环(单机) | 局域网(多机联仿) | + +> ⚠️ CARLA 仿真器仅支持 Windows/Linux,macOS 不支持。Python 客户端可在 macOS 上远程连接 CARLA 服务器。 + +## 安装 +### 1. 安装 CARLA 0.9.15 仿真器 +从 CARLA Release 页面下载 0.9.15 版本,解压至默认路径: +``` D:\carla0.9.15\ ├── CarlaUE4.exe # 仿真器主程序 ├── CarlaUE4\ # 引擎资源 @@ -256,39 +256,42 @@ D:\carla0.9.15\ │ └── examples\ # 官方示例 ├── Import\ # 资源导入目录 └── Util\ # 工具脚本 +``` -2. 安装 Python 依赖 -// bash +### 2. 安装 Python 依赖 +```bash # 推荐使用虚拟环境 python -m venv .venv .venv\Scripts\activate # Windows # source .venv/bin/activate # Linux pip install -r Requirements.txt +``` 依赖详情: -包名 版本 必选 说明 -carla 0.9.15 ✅ CARLA PythonAPI 客户端库 -pygame 2.1.0 ✅ 仿真界面渲染与键盘输入 -numpy 1.23.5 ✅ 数值计算与图像数组处理 -opencv-python 4.8.0.76 ❌ 图像处理(扩展功能) -matplotlib 3.7.1 ❌ 数据可视化(扩展功能) -Pillow 9.4.0 ❌ 图像处理(扩展功能) -torch 2.0.0 ❌ 深度学习检测模型(可选) -torchvision 0.15.1 ❌ 视觉模型(配合 torch 使用) - - -使用方法 -方式一:一键启动(Windows) -双击运行 start_carla_sim.bat,脚本会自动完成以下步骤: -[1] 启动 CARLA 仿真器 → CarlaUE4.exe -quality-level=Low -[2] 等待 15 秒服务器就绪 -[3] 运行自动驾驶脚本 → automatic_control.py - -⚠️ 使用前需修改 .bat 文件中的路径,详见 配置说明。 -方式二:手动启动 -步骤 1:启动 CARLA 仿真器 -// bash +| 包名 | 版本 | 必选 | 说明 | +| ---- | ---- | ---- | ---- | +| carla | 0.9.15 | ✅ | CARLA PythonAPI 客户端库 | +| pygame | 2.1.0 | ✅ | 仿真界面渲染与键盘输入 | +| numpy | 1.23.5 | ✅ | 数值计算与图像数组处理 | +| opencv-python | 4.8.0.76 | ❌ | 图像处理(扩展功能) | +| matplotlib | 3.7.1 | ❌ | 数据可视化(扩展功能) | +| Pillow | 9.4.0 | ❌ | 图像处理(扩展功能) | +| torch | 2.0.0 | ❌ | 深度学习检测模型(可选) | +| torchvision | 0.15.1 | ❌ | 视觉模型(配合 torch 使用) | + +## 使用方法 +### 方式一:一键启动(Windows) +双击运行 `start_carla_sim.bat`,脚本会自动完成以下步骤: +1. 启动 CARLA 仿真器 → `CarlaUE4.exe -quality-level=Low` +2. 等待 15 秒服务器就绪 +3. 运行自动驾驶脚本 → `automatic_control.py` + +> ⚠️ 使用前需修改 .bat 文件中的路径,详见 配置说明。 + +### 方式二:手动启动 +#### 步骤 1:启动 CARLA 仿真器 +```bash # Windows — 低画质模式(推荐,性能友好) CarlaUE4.exe -quality-level=Low @@ -300,10 +303,13 @@ CarlaUE4.exe -quality-level=Epic # 指定窗口化运行 CarlaUE4.exe -windowed -ResX=1280 -ResY=720 +``` + +#### 步骤 2 +等待仿真器控制台显示 `CarlaServer ready`。 -步骤 2:等待仿真器就绪(控制台显示 "CarlaServer ready" 后继续) -步骤 3:运行自动驾驶脚本 -// bash +#### 步骤 3:运行自动驾驶脚本 +```bash # 完整功能版(推荐首次使用) python Automatic_model @@ -318,17 +324,19 @@ python main.py --host 127.0.0.1 --port 2000 --res 1280x720 --behavior normal # 连接远程 CARLA 服务器 python main.py --host 192.168.1.100 --port 2000 +``` -命令行参数 -参数 默认值 说明 ---host 127.0.0.1 CARLA 服务器地址(本机或远程 IP) ---port 2000 CARLA 服务器端口 ---res 1280x720 渲染分辨率,格式:宽x高 ---filter vehicle.* 车辆蓝图过滤(如 vehicle.tesla.model3) --b / --behavior normal 驾驶行为模式:normal / cautious / aggressive +### 命令行参数 +| 参数 | 默认值 | 说明 | +| ---- | ---- | ---- | +| --host | 127.0.0.1 | CARLA 服务器地址(本机或远程 IP) | +| --port | 2000 | CARLA 服务器端口 | +| --res | 1280x720 | 渲染分辨率,格式:宽x高 | +| --filter | vehicle.* | 车辆蓝图过滤(如 vehicle.tesla.model3) | +| -b / --behavior | normal | 驾驶行为模式:normal / cautious / aggressive | 示例: -// bash +```bash # 使用特定车辆模型 python Automatic_model --filter vehicle.tesla.model3 @@ -337,28 +345,30 @@ python Automatic_model --res 3840x2160 --behavior aggressive # 连接远程服务器 + 谨慎模式 python main.py --host 192.168.1.100 --behavior cautious - -键盘操作 -通用操作 -按键 功能 适用脚本 -ESC 退出程序 全部 -Ctrl+Q 退出程序 全部 -TAB 切换天气预设 main.py / Automatic_model / Switch_automatic -PageUp 上一个天气预设 world_Coordinate.py -PageDown 下一个天气预设 world_Coordinate.py - -手动驾驶模式(仅 `Automatic_model`) -按键 功能 -C 切换手动/自动驾驶模式 -W 油门(加速) -S 刹车(减速) -A 左转向 -D 右转向 - -💡 切换到手动模式后,HUD 会显示"手动驾驶模式"提示,此时 WASD 控制生效。 - -工作原理 -交通灯检测与响应流程 +``` + +### 键盘操作 +#### 通用操作 +| 按键 | 功能 | 适用脚本 | +| ---- | ---- | ---- | +| ESC | 退出程序 | 全部 | +| Ctrl+Q | 退出程序 | 全部 | +| TAB | 切换天气预设 | main.py / Automatic_model / Switch_automatic | +| PageUp | 上一个天气预设 | world_Coordinate.py | +| PageDown | 下一个天气预设 | world_Coordinate.py | + +#### 手动驾驶模式(仅 `Automatic_model`) +| 按键 | 功能 | +| ---- | ---- | +| C | 切换手动/自动驾驶模式 | +| W | 油门(加速) | +| S | 刹车(减速) | +| A | 左转向 | +| D | 右转向 | + +## 工作原理 +### 交通灯检测与响应流程 +``` CARLA 仿真世界 │ ▼ @@ -379,13 +389,15 @@ D 右转向 ▼ ▼ 刹车=1.0 油门恢复 停车等待 正常行驶 - +``` 1. 客户端通过 CARLA API 获取世界中所有交通灯 Actor 2. 根据车辆位置和朝向,判断前方是否有交通灯 3. 检测交通灯的 state 属性(Red / Yellow / Green) 4. 红灯/黄灯时:设置 brake = 1.0,throttle = 0.0 5. 绿灯时:恢复正常行驶,由 BehaviorAgent 计算控制指令 -自动导航流程 + +### 自动导航流程 +``` ┌────────────────┐ │ 随机选择出生点 │ └───────┬────────┘ @@ -420,8 +432,10 @@ D 右转向 ┌────────────────┐ │ │ 自动设置新目标 │─────┘ └────────────────┘ +``` -手动/自动切换流程 +### 手动/自动切换流程 +``` ┌─────────────┐ │ 程序启动 │ │ 默认:自动 │ @@ -436,18 +450,19 @@ D 右转向 │ 控制指令 │ C │ 油门/刹车 │ │ │◄──────►│ /转向 │ └────────────┘ └────────────┘ +``` - -配置说明 -CARLA 安装路径 +## 配置说明 +### CARLA 安装路径 如 CARLA 安装路径非默认,需修改各 Python 脚本顶部的路径变量: -// python -CARLA_ROOT = r"D:\carla0.9.15" # ← 修改为你的 CARLA 安装路径 - +```python +CARLA_ROOT = r"D:\carla0.9.15" # 修改为你的 CARLA 安装路径 +``` 涉及文件:main.py、automatic_control.py、Add_weather_switching.py、Automatic_model、Switch_automatic -一键启动脚本路径 -修改 start_carla_sim.bat 中的以下路径: -// bat + +### 一键启动脚本路径 +修改 `start_carla_sim.bat` 中的内容: +```bat :: CARLA 仿真器路径 start "" "D:\carla0.9.15\CarlaUE4.exe" -quality-level=Low @@ -456,63 +471,68 @@ start "" "D:\carla0.9.15\CarlaUE4.exe" -quality-level=Low :: 自动驾驶脚本路径 "D:\carla_automatic1\automatic_control.py" +``` -分辨率调整 -可通过命令行参数或修改代码调整渲染分辨率: -// bash -# 命令行方式 +### 分辨率调整 +命令行方式: +```bash python main.py --res 1920x1080 - -# 代码方式(修改 main() 函数中的默认值) +``` +代码方式:修改 `main()` 函数内默认参数 +```python argparser.add_argument('--res', default='1920x1080') - -CARLA 服务器性能调优 -参数 说明 示例 --quality-level=Low 低画质,性能优先 CarlaUE4.exe -quality-level=Low --quality-level=Epic 高画质,视觉优先 CarlaUE4.exe -quality-level=Epic --world-port=2000 指定通信端口 CarlaUE4.exe -world-port=3000 --carla-rpc-port=3000 指定 RPC 端口 CarlaUE4.exe -carla-rpc-port=3000 - - -常见问题 -Q1: 启动脚本报错 `ModuleNotFoundError: No module named 'carla'` +``` + +### CARLA 服务器性能调优 +| 参数 | 说明 | 示例 | +| ---- | ---- | ---- | +| -quality-level=Low | 低画质,性能优先 | CarlaUE4.exe -quality-level=Low | +| -quality-level=Epic | 高画质,视觉优先 | CarlaUE4.exe -quality-level=Epic | +| -world-port=2000 | 指定通信端口 | CarlaUE4.exe -world-port=3000 | +| -carla-rpc-port=3000 | 指定 RPC 端口 | CarlaUE4.exe -carla-rpc-port=3000 | + +## 常见问题 +### Q1: 启动脚本报错 `ModuleNotFoundError: No module named 'carla'` 原因:CARLA PythonAPI 路径未正确配置。 解决: -1. 确认 CARLA_ROOT 路径指向正确的 CARLA 安装目录 -2. 确认目录下存在 PythonAPI/carla/ 文件夹 +1. 确认 `CARLA_ROOT` 路径指向正确的 CARLA 安装目录 +2. 确认目录下存在 `PythonAPI/carla/` 文件夹 3. Python 3.9+ 用户使用 automatic_control.py 等已适配版本 -Q2: 连接 CARLA 服务器超时 `RuntimeError: time-out` + +### Q2: 连接 CARLA 服务器超时 `RuntimeError: time-out` 原因:仿真器未启动或未就绪。 解决: 1. 先启动 CarlaUE4.exe,等待控制台显示 "ready" 2. 确认端口一致(默认 2000) -3. 可尝试增大超时时间:client.set_timeout(30.0) -Q3: Python 3.9 下 egg 导入报错 +3. 增大超时时间:`client.set_timeout(30.0)` + +### Q3: Python 3.9 下 egg 导入报错 原因:CARLA 旧版 .egg 文件与 Python 3.9 不兼容。 -解决:使用 automatic_control.py 等已适配版本,脚本会自动清理冲突路径: -// python -# 已在脚本中处理 +解决:使用已适配版本,脚本内置路径清理逻辑: +```python for path in list(sys.path): if "carla/dist" in path and path.endswith(".egg"): sys.path.remove(path) +``` -Q4: 画面卡顿 / FPS 过低 -解决: -1. 使用低画质模式启动:CarlaUE4.exe -quality-level=Low -2. 降低分辨率:python main.py --res 800x600 +### Q4: 画面卡顿 / FPS 过低 +1. 使用低画质模式启动:`CarlaUE4.exe -quality-level=Low` +2. 降低分辨率:`python main.py --res 800x600` 3. 关闭不必要的后台程序 -4. 确认 GPU 驱动已更新 -Q5: 导入 BehaviorAgent 报错 `ModuleNotFoundError` +4. 更新 GPU 驱动 + +### Q5: 导入 BehaviorAgent 报错 `ModuleNotFoundError` 原因:缺少 CARLA Agent 模块。 -解决:确认 CARLA 安装目录下存在 PythonAPI/carla/agents/ 目录。如不存在,可使用 world_Coordinate.py 中的 SimpleAutoAgent 替代。 -Q6: 碰撞后车辆不恢复行驶 -原因:碰撞传感器仅做通知,不处理恢复逻辑。 -解决:可在碰撞回调中添加恢复逻辑,如短暂停车后重新规划路径。 - -扩展开发指南 -添加新传感器 -参照现有传感器类的实现模式,在 World.restart() 中挂载: -// python +解决:确认 CARLA 目录下存在 `PythonAPI/carla/agents/`,也可改用 `world_Coordinate.py` 的 SimpleAutoAgent。 + +### Q6: 碰撞后车辆不恢复行驶 +原因:碰撞传感器仅做通知,无恢复逻辑。 +解决:在碰撞回调中补充逻辑,实现停车后重新规划路径。 + +## 扩展开发指南 +### 添加新传感器 +参照现有传感器类实现,在 `World.restart()` 中挂载: +```python class MyCustomSensor(object): def __init__(self, parent_actor, hud): bp = parent_actor.get_world().get_blueprint_library().find('sensor.other.obstacle') @@ -523,32 +543,32 @@ class MyCustomSensor(object): def _on_event(self, event): # 处理传感器数据 pass - -可用的传感器 Blueprint: -Blueprint ID 说明 -sensor.camera.rgb RGB 摄像头 -sensor.camera.depth 深度摄像头 -sensor.camera.semantic_segmentation 语义分割摄像头 -sensor.lidar.ray_cast 激光雷达 -sensor.other.radar 毫米波雷达 -sensor.other.imu 惯性测量单元 -sensor.other.obstacle 障碍物检测 - -切换地图 -修改 game_loop() 中的地图加载: -// python +``` + +可用传感器 Blueprint: +| Blueprint ID | 说明 | +| ---- | ---- | +| sensor.camera.rgb | RGB 摄像头 | +| sensor.camera.depth | 深度摄像头 | +| sensor.camera.semantic_segmentation | 语义分割摄像头 | +| sensor.lidar.ray_cast | 激光雷达 | +| sensor.other.radar | 毫米波雷达 | +| sensor.other.imu | 惯性测量单元 | +| sensor.other.obstacle | 障碍物检测 | + +### 切换地图 +```python # 加载指定地图 client.load_world('Town03') - # 可用地图:Town01 ~ Town10HD # Town01: 简单小镇,适合测试 # Town03: 圆环交叉路口 # Town05: 高架桥与隧道 # Town10HD: 高清城市 +``` -添加更多车辆 -修改 --filter 参数或在代码中指定: -// python +### 添加更多车辆 +```python # 特定车型 argparser.add_argument('--filter', default='vehicle.tesla.model3') @@ -557,39 +577,40 @@ argparser.add_argument('--filter', default='vehicle.*.bike') # 所有摩托车 argparser.add_argument('--filter', default='vehicle.*.motorcycle') +``` -自定义 SimpleAutoAgent -world_Coordinate.py 中的 SimpleAutoAgent 是最易修改的导航方案,适合快速实验: -// python +### 自定义 SimpleAutoAgent +修改 `world_Coordinate.py` 内的控制逻辑,可接入 PID、纯跟踪、深度学习等算法: +```python class SimpleAutoAgent: def run_step(self): control = carla.VehicleControl() - # ← 在这里修改你的控制逻辑 - # 可加入:PID 控制、纯跟踪算法、深度学习模型等 + # 自定义控制逻辑 return control +``` +## 更新日志 +### v1.0.0 +- 基础自动驾驶功能(main.py) +- 碰撞/车道偏离/GNSS 传感器集成 +- 天气切换功能 -更新日志 -v1.0.0 -• 基础自动驾驶功能(main.py) -• 碰撞/车道偏离/GNSS 传感器集成 -• 天气切换功能 -v1.1.0 -• Python 3.9 适配,修复 .egg 导入冲突 -• 新增 automatic_control.py / Add_weather_switching.py -• 新增 Switch_automatic 脚本 -v1.2.0 -• 完整功能版 Automatic_model:手动/自动切换、增强 HUD -• 极简独立版 world_Coordinate.py:自实现 SimpleAutoAgent -• Windows 一键启动脚本 start_carla_sim.bat - -许可证 +### v1.1.0 +- Python 3.9 适配,修复 .egg 导入冲突 +- 新增 automatic_control.py / Add_weather_switching.py +- 新增 Switch_automatic 脚本 + +### v1.2.0 +- 完整功能版 Automatic_model:手动/自动切换、增强 HUD +- 极简独立版 world_Coordinate.py:自实现 SimpleAutoAgent +- Windows 一键启动脚本 start_carla_sim.bat + +## 许可证 MIT License — 基于 Intel Labs 原始代码适配修改。 详见 LICENSE -致谢 -• CARLA Simulator — 开源自动驾驶仿真平台 -• Intel Labs — CARLA 原始代码贡献 -• 原始代码作者:German Ros (german.ros@gmail.com) -• CARLA 文档 — API 参考与教程 - +## 致谢 +- CARLA Simulator — 开源自动驾驶仿真平台 +- Intel Labs — CARLA 原始代码贡献 +- 原始代码作者:German Ros (german.ros@gmail.com) +- CARLA 文档 — API 参考与教程