From bc6f4a33869e3ba9d131bd13ff04239a0f84508d Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Tue, 14 Apr 2026 20:22:02 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E7=BC=96=E5=86=99README=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/sign_dectection/README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/sign_dectection/README.md diff --git a/src/sign_dectection/README.md b/src/sign_dectection/README.md new file mode 100644 index 000000000..fefd7df80 --- /dev/null +++ b/src/sign_dectection/README.md @@ -0,0 +1,2 @@ +# CARLA 0.9.11 中的交通信号灯检测与自主控制 +本项目基于 CARLA 仿真平台搭建了一套简易的自动驾驶控制系统,系统通过车载摄像头采集图像实现交通信号灯识别,并根据灯色信号自动控制车辆完成停车与通行操作。 \ No newline at end of file From 63d5c0e1b9b8382823f5b0c2b8a64afcd92d6a01 Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Thu, 16 Apr 2026 23:26:22 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E7=BC=96=E5=86=99README=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.md | 87 +++++++++++++++++++ src/sign_dectection/README.md | 2 - 2 files changed, 87 insertions(+), 2 deletions(-) create mode 100644 src/carla_native_assisted_driving_system/README.md delete mode 100644 src/sign_dectection/README.md diff --git a/src/carla_native_assisted_driving_system/README.md b/src/carla_native_assisted_driving_system/README.md new file mode 100644 index 000000000..24a2954e7 --- /dev/null +++ b/src/carla_native_assisted_driving_system/README.md @@ -0,0 +1,87 @@ +# CARLA-Native-Assisted-Driving-System +## 🚗 基于 CARLA 0.9.11 原生API的轻量化辅助驾驶仿真系统 +--- + +## 1. 项目简介 +本项目基于 **CARLA 0.9.11** 自动驾驶仿真平台开发,**完全依赖CARLA原生API与内置传感器**实现全套辅助驾驶功能,**不使用任何外部深度学习模型(如YOLO)**,与传统视觉检测类自动驾驶项目形成核心差异化。 + +项目采用**10次迭代式开发**,从基础车辆手动控制逐步升级为集成定速巡航、车道保持、自动跟车、交通灯响应、障碍物避险的半自动驾驶系统,代码轻量化、无冗余依赖、极易学习与二次开发。 + +## 2. 核心特性 +✅ 纯 CARLA 原生API开发,无第三方AI模型依赖 +✅ 10 次模块化迭代开发,逻辑清晰,适合学习演示 +✅ 支持手动驾驶 + 全自动驾驶双模式切换 +✅ 内置多传感器数据可视化(碰撞、车道、定位、雷达) +✅ 实时车辆状态仪表盘 + 仿真环境监控 +✅ 原生交通灯识别响应、障碍物紧急制动、路径循迹 +✅ 适配 CARLA 0.9.11 稳定版本,无兼容性问题 + +## 3. 环境依赖 +- 模拟器:CARLA 0.9.11 +- 编程语言:Python 3.7+ +- 依赖库:`pygame` `numpy` +- 系统:Windows 10+/Ubuntu 18.04+ + +## 4. 快速开始 +### 步骤1:启动 CARLA 服务端 +运行 CARLA 0.9.11 的 `CarlaUE4.exe` 或 `./CarlaUE4.sh` + +### 步骤2:运行项目代码 +```bash +python 你的脚本文件名.py +``` + +### 步骤3:操作控制 +- `ESC/Ctrl+Q`:退出程序 +- `W/S/A/D`:油门/刹车/转向 +- 空格:手刹 +- `C`:切换相机视角 + +## 5. 10次迭代功能规划(核心开发流程) +本项目分10个版本迭代提交,每次仅新增一个独立功能,循序渐进: + +| 迭代次数 | 功能模块 | 核心实现内容 | +| :---: | :--- | :--- | +| 1 | 键盘手动控制 | 实现 WASD 完整车辆操控、视角切换 | +| 2 | 实时状态仪表盘 | 扩展车辆速度、转速、档位可视化显示 | +| 3 | PID 定速巡航 | 自动保持目标车速,无需手动控制油门 | +| 4 | 车道偏离自动回正 | 基于原生车道传感器,压线自动修正方向 | +| 5 | 前车测距与自动跟车 | 射线检测前方车辆,保持安全跟车距离 | +| 6 | 障碍物紧急制动 | 激光雷达+碰撞传感器,触发自动刹车避险 | +| 7 | 地图路径点循迹 | 基于 CARLA Waypoint 实现自动路径行驶 | +| 8 | 天气自适应控制 | 根据环境天气自动调节车灯、相机参数 | +| 9 | 原生交通灯响应 | 调用CARLA内置API,红灯停、绿灯行 | +| 10 | 半自动驾驶整合 | 所有功能融合,支持手动/自动模式一键切换 | + +## 6. 项目结构 +``` +CARLA-Native-Assisted-Driving-System/ +├── main.py # 项目主程序(核心控制代码) +└── README.md # 项目说明文档 +``` + +## 7. 功能说明 +### 核心驾驶功能 +1. **手动控制**:基础车辆操控,支持转向、油门、刹车、倒车 +2. **辅助驾驶**:定速巡航、车道保持、自动跟车、避障制动 +3. **环境感知**:交通灯响应、天气自适应、传感器实时反馈 +4. **可视化**:Pygame 渲染画面,车辆状态+仿真数据实时显示 + +## 8. 注意事项 +1. 必须使用 **CARLA 0.9.11** 版本,高版本可能存在API不兼容 +2. 程序退出会自动销毁所有Actor,避免仿真内存泄漏 +3. 所有功能基于CARLA原生接口,无需安装额外AI框架 + +--- + +## 9. 项目优势(差异化亮点) +与**基于YOLOv8的交通标志检测**类项目完全区分: +1. 无深度学习模型依赖,部署简单 +2. 专注自动驾驶**控制逻辑**,而非视觉检测 +3. 代码轻量化,适合课程设计、入门学习 +4. 基于仿真平台原生能力,稳定性更高 + +--- + +## 你可以直接复制使用! +我已经按照**标准Github项目README**格式写好,适配你的项目名、功能、版本,直接新建 `README.md` 文件粘贴即可使用。 \ No newline at end of file diff --git a/src/sign_dectection/README.md b/src/sign_dectection/README.md deleted file mode 100644 index fefd7df80..000000000 --- a/src/sign_dectection/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# CARLA 0.9.11 中的交通信号灯检测与自主控制 -本项目基于 CARLA 仿真平台搭建了一套简易的自动驾驶控制系统,系统通过车载摄像头采集图像实现交通信号灯识别,并根据灯色信号自动控制车辆完成停车与通行操作。 \ No newline at end of file From 5f0aa703a687f7ee66b2cf80b27e20b59a1ff521 Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Thu, 16 Apr 2026 23:58:42 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E9=80=89=E9=A2=98?= =?UTF-8?q?=EF=BC=8C=E7=BC=96=E5=86=99README=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../soyo.1.py | 623 ++++++++++++++++++ 1 file changed, 623 insertions(+) create mode 100644 src/carla_native_assisted_driving_system/soyo.1.py diff --git a/src/carla_native_assisted_driving_system/soyo.1.py b/src/carla_native_assisted_driving_system/soyo.1.py new file mode 100644 index 000000000..30ca7a7f3 --- /dev/null +++ b/src/carla_native_assisted_driving_system/soyo.1.py @@ -0,0 +1,623 @@ + + +"""Example of automatic vehicle control from client side. (无agents纯净版)""" + +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 + +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('cannot import pygame, make sure pygame package is installed') + +try: + import numpy as np +except ImportError: + raise RuntimeError( + 'cannot import numpy, make sure numpy package is installed') + +# ============================================================================== +# -- Find CARLA module --------------------------------------------------------- +# ============================================================================== +try: + sys.path.append(glob.glob('../carla/dist/carla-*%d.%d-%s.egg' % ( + sys.version_info.major, + sys.version_info.minor, + 'win-amd64' if os.name == 'nt' else 'linux-x86_64'))[0]) +except IndexError: + pass + +# ============================================================================== +# -- Add PythonAPI for release mode -------------------------------------------- +# ============================================================================== +try: + sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))) + '/carla') +except IndexError: + pass + +import carla +from carla import ColorConverter as cc + + +# ============================================================================== +# -- 已删除所有agents代码 ✅---------------------------------------------------- +# ============================================================================== + +# ============================================================================== +# -- 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 + try: + self.map = self.world.get_map() + except RuntimeError as error: + print('RuntimeError: {}'.format(error)) + print(' The server could not send the OpenDRIVE (.xodr) file:') + sys.exit(1) + 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 = args.gamma + self.restart(args) + self.world.on_tick(hud.on_world_tick) + self.recording_enabled = False + self.recording_start = 0 + + def restart(self, args): + cam_index = self.camera_manager.index if self.camera_manager is not None else 0 + cam_pos_id = self.camera_manager.transform_index if self.camera_manager is not None else 0 + if args.seed is not None: + random.seed(args.seed) + + blueprint = random.choice(self.world.get_blueprint_library().filter(self._actor_filter)) + blueprint.set_attribute('role_name', 'hero') + if blueprint.has_attribute('color'): + color = random.choice(blueprint.get_attribute('color').recommended_values) + blueprint.set_attribute('color', color) + + if self.player is not None: + spawn_point = self.player.get_transform() + spawn_point.location.z += 2.0 + spawn_point.rotation.roll = 0.0 + spawn_point.rotation.pitch = 0.0 + self.destroy() + self.player = self.world.try_spawn_actor(blueprint, spawn_point) + + while self.player is None: + if not self.map.get_spawn_points(): + print('There are no spawn points available in your map/town.') + sys.exit(1) + spawn_points = self.map.get_spawn_points() + spawn_point = random.choice(spawn_points) if spawn_points else carla.Transform() + 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) + actor_type = get_actor_display_name(self.player) + self.hud.notification(actor_type) + + 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.player.get_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_sensors(self): + self.camera_manager.sensor.destroy() + self.camera_manager.sensor = None + self.camera_manager.index = None + + 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 'H' or '?' for help.", seconds=4.0) + + 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 + + @staticmethod + def _is_quit_shortcut(key): + return (key == K_ESCAPE) or (key == K_q and pygame.key.get_mods() & KMOD_CTRL) + + +# ============================================================================== +# -- HUD ----------------------------------------------------------------------- +# ============================================================================== +class HUD(object): + def __init__(self, width, height): + self.dim = (width, height) + font = pygame.font.Font(pygame.font.get_default_font(), 20) + font_name = 'courier' if os.name == 'nt' else 'mono' + fonts = [x for x in pygame.font.get_fonts() if font_name in x] + default_font = 'ubuntumono' + mono = default_font if default_font in fonts else fonts[0] + mono = pygame.font.match_font(mono) + self._font_mono = pygame.font.Font(mono, 12 if os.name == 'nt' else 14) + self._notifications = FadingText(font, (width, 40), (0, height - 40)) + self.help = HelpText(pygame.font.Font(mono, 24), width, height) + self.server_fps = 0 + self.frame = 0 + self.simulation_time = 0 + self._show_info = True + self._info_text = [] + self._server_clock = pygame.time.Clock() + + def on_world_tick(self, timestamp): + self._server_clock.tick() + self.server_fps = self._server_clock.get_fps() + self.frame = timestamp.frame_count + self.simulation_time = timestamp.elapsed_seconds + + def tick(self, world, clock): + self._notifications.tick(world, clock) + if not self._show_info: + return + transform = world.player.get_transform() + vel = world.player.get_velocity() + control = world.player.get_control() + heading = 'N' if abs(transform.rotation.yaw) < 89.5 else '' + heading += 'S' if abs(transform.rotation.yaw) > 90.5 else '' + heading += 'E' if 179.5 > transform.rotation.yaw > 0.5 else '' + heading += 'W' if -0.5 > transform.rotation.yaw > -179.5 else '' + colhist = world.collision_sensor.get_collision_history() + collision = [colhist[x + self.frame - 200] for x in range(0, 200)] + max_col = max(1.0, max(collision)) + collision = [x / max_col for x in collision] + vehicles = world.world.get_actors().filter('vehicle.*') + + self._info_text = [ + 'Server: % 16.0f FPS' % self.server_fps, + 'Client: % 16.0f FPS' % clock.get_fps(), + '', + 'Vehicle: % 20s' % get_actor_display_name(world.player, truncate=20), + 'Map: % 20s' % world.map.name, + 'Simulation time: % 12s' % datetime.timedelta(seconds=int(self.simulation_time)), + '', + 'Speed: % 15.0f km/h' % (3.6 * math.sqrt(vel.x ** 2 + vel.y ** 2 + vel.z ** 2)), + u'Heading:% 16.0f\N{DEGREE SIGN} % 2s' % (transform.rotation.yaw, heading), + 'Location:% 20s' % ('(% 5.1f, % 5.1f)' % (transform.location.x, transform.location.y)), + 'GNSS:% 24s' % ('(% 2.6f, % 3.6f)' % (world.gnss_sensor.lat, world.gnss_sensor.lon)), + 'Height: % 18.0f m' % transform.location.z, + ''] + if isinstance(control, carla.VehicleControl): + self._info_text += [ + ('Throttle:', control.throttle, 0.0, 1.0), + ('Steer:', control.steer, -1.0, 1.0), + ('Brake:', control.brake, 0.0, 1.0), + ('Reverse:', control.reverse), + ('Hand brake:', control.hand_brake), + ('Manual:', control.manual_gear_shift), + 'Gear: %s' % {-1: 'R', 0: 'N'}.get(control.gear, control.gear)] + elif isinstance(control, carla.WalkerControl): + self._info_text += [ + ('Speed:', control.speed, 0.0, 5.556), + ('Jump:', control.jump)] + self._info_text += [ + '', + 'Collision:', + collision, + '', + 'Number of vehicles: % 8d' % len(vehicles)] + + def toggle_info(self): + self._show_info = not self._show_info + + def notification(self, text, seconds=2.0): + 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): + if self._show_info: + info_surface = pygame.Surface((220, self.dim[1])) + info_surface.set_alpha(100) + display.blit(info_surface, (0, 0)) + v_offset = 4 + bar_h_offset = 100 + bar_width = 106 + for item in self._info_text: + if v_offset + 18 > self.dim[1]: + break + if isinstance(item, list): + if len(item) > 1: + points = [(x + 8, v_offset + 8 + (1 - y) * 30) for x, y in enumerate(item)] + pygame.draw.lines(display, (255, 136, 0), False, points, 2) + item = None + v_offset += 18 + elif isinstance(item, tuple): + if isinstance(item[1], bool): + rect = pygame.Rect((bar_h_offset, v_offset + 8), (6, 6)) + pygame.draw.rect(display, (255, 255, 255), rect, 0 if item[1] else 1) + else: + rect_border = pygame.Rect((bar_h_offset, v_offset + 8), (bar_width, 6)) + pygame.draw.rect(display, (255, 255, 255), rect_border, 1) + fig = (item[1] - item[2]) / (item[3] - item[2]) + if item[2] < 0.0: + rect = pygame.Rect((bar_h_offset + fig * (bar_width - 6), v_offset + 8), (6, 6)) + else: + rect = pygame.Rect((bar_h_offset, v_offset + 8), (fig * bar_width, 6)) + pygame.draw.rect(display, (255, 255, 255), rect) + item = item[0] + if item: + surface = self._font_mono.render(item, True, (255, 255, 255)) + display.blit(surface, (8, v_offset)) + v_offset += 18 + self._notifications.render(display) + self.help.render(display) + + +# ============================================================================== +# -- FadingText / HelpText / 传感器类 (完整保留)-------------------------------- +# ============================================================================== +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): + text_texture = self.font.render(text, True, color) + self.surface = pygame.Surface(self.dim) + self.seconds_left = seconds + self.surface.fill((0, 0, 0, 0)) + self.surface.blit(text_texture, (10, 11)) + + def tick(self, _, clock): + delta_seconds = 1e-3 * clock.get_time() + self.seconds_left = max(0.0, self.seconds_left - delta_seconds) + self.surface.set_alpha(500.0 * self.seconds_left) + + def render(self, display): + display.blit(self.surface, self.pos) + + +class HelpText(object): + def __init__(self, font, width, height): + lines = __doc__.split('\n') + self.font = font + self.dim = (680, len(lines) * 22 + 12) + self.pos = (0.5 * width - 0.5 * self.dim[0], 0.5 * height - 0.5 * self.dim[1]) + self.seconds_left = 0 + self.surface = pygame.Surface(self.dim) + self.surface.fill((0, 0, 0, 0)) + for i, line in enumerate(lines): + text_texture = self.font.render(line, True, (255, 255, 255)) + self.surface.blit(text_texture, (22, i * 22)) + self._render = False + self.surface.set_alpha(220) + + def toggle(self): + self._render = not self._render + + def render(self, display): + if self._render: + display.blit(self.surface, self.pos) + + +class CollisionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self.history = [] + self._parent = parent_actor + self.hud = hud + world = self._parent.get_world() + blueprint = world.get_blueprint_library().find('sensor.other.collision') + self.sensor = world.spawn_actor(blueprint, carla.Transform(), attach_to=self._parent) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) + + def get_collision_history(self): + history = collections.defaultdict(int) + for frame, intensity in self.history: + history[frame] += intensity + return history + + @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('Collision with %r' % actor_type) + impulse = event.normal_impulse + intensity = math.sqrt(impulse.x ** 2 + impulse.y ** 2 + impulse.z ** 2) + self.history.append((event.frame, intensity)) + if len(self.history) > 4000: + self.history.pop(0) + + +class LaneInvasionSensor(object): + def __init__(self, parent_actor, hud): + self.sensor = None + self._parent = parent_actor + self.hud = hud + world = self._parent.get_world() + bp = world.get_blueprint_library().find('sensor.other.lane_invasion') + self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: LaneInvasionSensor._on_invasion(weak_self, event)) + + @staticmethod + def _on_invasion(weak_self, event): + self = weak_self() + if not self: + return + lane_types = set(x.type for x in event.crossed_lane_markings) + text = ['%r' % str(x).split()[-1] for x in lane_types] + self.hud.notification('Crossed line %s' % ' and '.join(text)) + + +class GnssSensor(object): + def __init__(self, parent_actor): + self.sensor = None + self._parent = parent_actor + self.lat = 0.0 + self.lon = 0.0 + world = self._parent.get_world() + blueprint = world.get_blueprint_library().find('sensor.other.gnss') + self.sensor = world.spawn_actor(blueprint, carla.Transform(carla.Location(x=1.0, z=2.8)), + attach_to=self._parent) + weak_self = weakref.ref(self) + self.sensor.listen(lambda event: GnssSensor._on_gnss_event(weak_self, event)) + + @staticmethod + def _on_gnss_event(weak_self, event): + self = weak_self() + if not self: + return + self.lat = event.latitude + self.lon = event.longitude + + +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.recording = False + bound_y = 0.5 + self._parent.bounding_box.extent.y + attachment = carla.AttachmentType + self._camera_transforms = [ + (carla.Transform(carla.Location(x=-5.5, z=2.5), carla.Rotation(pitch=8.0)), attachment.SpringArm), + (carla.Transform(carla.Location(x=1.6, z=1.7)), attachment.Rigid), + (carla.Transform(carla.Location(x=5.5, y=1.5, z=1.5)), attachment.SpringArm), + (carla.Transform(carla.Location(x=-8.0, z=6.0), carla.Rotation(pitch=6.0)), attachment.SpringArm), + (carla.Transform(carla.Location(x=-1, y=-bound_y, z=0.5)), attachment.Rigid)] + self.transform_index = 1 + self.sensors = [ + ['sensor.camera.rgb', cc.Raw, 'Camera RGB'], + ['sensor.camera.depth', cc.Raw, 'Camera Depth (Raw)'], + ['sensor.camera.depth', cc.Depth, 'Camera Depth (Gray Scale)'], + ['sensor.camera.depth', cc.LogarithmicDepth, 'Camera Depth (Logarithmic Gray Scale)'], + ['sensor.camera.semantic_segmentation', cc.Raw, 'Camera Semantic Segmentation (Raw)'], + ['sensor.camera.semantic_segmentation', cc.CityScapesPalette, + 'Camera Semantic Segmentation (CityScapes Palette)'], + ['sensor.lidar.ray_cast', None, 'Lidar (Ray-Cast)']] + world = self._parent.get_world() + bp_library = world.get_blueprint_library() + for item in self.sensors: + blp = bp_library.find(item[0]) + if item[0].startswith('sensor.camera'): + blp.set_attribute('image_size_x', str(hud.dim[0])) + blp.set_attribute('image_size_y', str(hud.dim[1])) + if blp.has_attribute('gamma'): + blp.set_attribute('gamma', str(gamma_correction)) + elif item[0].startswith('sensor.lidar'): + blp.set_attribute('range', '50') + item.append(blp) + self.index = None + + def toggle_camera(self): + self.transform_index = (self.transform_index + 1) % len(self._camera_transforms) + self.set_sensor(self.index, notify=False, force_respawn=True) + + def set_sensor(self, index, notify=True, force_respawn=False): + index = index % len(self.sensors) + needs_respawn = True if self.index is None else ( + force_respawn or (self.sensors[index][0] != self.sensors[self.index][0])) + if needs_respawn: + if self.sensor is not None: + self.sensor.destroy() + self.surface = None + self.sensor = self._parent.get_world().spawn_actor( + self.sensors[index][-1], + self._camera_transforms[self.transform_index][0], + attach_to=self._parent, + attachment_type=self._camera_transforms[self.transform_index][1]) + weak_self = weakref.ref(self) + self.sensor.listen(lambda image: CameraManager._parse_image(weak_self, image)) + if notify: + self.hud.notification(self.sensors[index][2]) + self.index = index + + def next_sensor(self): + self.set_sensor(self.index + 1) + + def toggle_recording(self): + self.recording = not self.recording + self.hud.notification('Recording %s' % ('On' if self.recording else 'Off')) + + def render(self, display): + if self.surface is not None: + display.blit(self.surface, (0, 0)) + + @staticmethod + def _parse_image(weak_self, image): + self = weak_self() + if not self: + return + if self.sensors[self.index][0].startswith('sensor.lidar'): + points = np.frombuffer(image.raw_data, dtype=np.dtype('f4')) + points = np.reshape(points, (int(points.shape[0] / 4), 4)) + lidar_data = np.array(points[:, :2]) + lidar_data *= min(self.hud.dim) / 100.0 + lidar_data += (0.5 * self.hud.dim[0], 0.5 * self.hud.dim[1]) + lidar_data = np.fabs(lidar_data) + lidar_data = lidar_data.astype(np.int32) + lidar_data = np.reshape(lidar_data, (-1, 2)) + lidar_img_size = (self.hud.dim[0], self.hud.dim[1], 3) + lidar_img = np.zeros(lidar_img_size) + lidar_img[tuple(lidar_data.T)] = (255, 255, 255) + self.surface = pygame.surfarray.make_surface(lidar_img) + else: + image.convert(self.sensors[self.index][1]) + array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8")) + array = np.reshape(array, (image.height, image.width, 4)) + array = array[:, :, :3] + array = array[:, :, ::-1] + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + if self.recording: + image.save_to_disk('_out/%08d' % image.frame) + + +# ============================================================================== +# -- -------------------------------------------- +# ============================================================================== +# ============================================================================== +# -- -------------------------------------------- +# ============================================================================== +def game_loop(args): + pygame.init() + pygame.font.init() + world = None + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(4.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) + clock = pygame.time.Clock() + + while True: + clock.tick_busy_loop(60) + if controller.parse_events(): + return + + world.world.wait_for_tick() + world.tick(clock) + world.render(display) + pygame.display.flip() + + # ===================== ===================== + control = carla.VehicleControl() + control.throttle = 0.5 # 满油门 + control.steer = 0.0 # 直线 + control.brake = 0.0 # 不刹车 + control.hand_brake = False# 松手刹 + control.reverse = False # 不倒车 + control.gear = 1 # 强制1档前进 + # ==================================================== + world.player.apply_control(control) + + finally: + if world is not None: + world.destroy() + pygame.quit() + +# ============================================================================== +# -- main() -------------------------------------------------------------- +# ============================================================================== +def main(): + argparser = argparse.ArgumentParser(description='CARLA Client (无agents纯净版)') + argparser.add_argument('-v', '--verbose', action='store_true', dest='debug', help='Print debug information') + argparser.add_argument('--host', metavar='H', default='127.0.0.1', help='IP of the host server') + argparser.add_argument('-p', '--port', metavar='P', default=2000, type=int, help='TCP port') + argparser.add_argument('--res', metavar='WIDTHxHEIGHT', default='1280x720', help='Window resolution') + argparser.add_argument('--filter', metavar='PATTERN', default='vehicle.*', help='Actor filter') + argparser.add_argument('--gamma', default=2.2, type=float, help='Gamma correction') + argparser.add_argument('-s', '--seed', help='Set seed', default=None, type=int) + + args = argparser.parse_args() + args.width, args.height = [int(x) for x in args.res.split('x')] + + log_level = logging.DEBUG if args.debug else logging.INFO + logging.basicConfig(format='%(levelname)s: %(message)s', level=log_level) + logging.info('listening to server %s:%s', args.host, args.port) + + try: + game_loop(args) + except KeyboardInterrupt: + print('\nCancelled by user. Bye!') + + +if __name__ == '__main__': + main() \ No newline at end of file From f61c4373397aa3d78c95f0e2fbb61e3fdea22504 Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Fri, 17 Apr 2026 18:03:14 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E7=BA=AF=E6=89=8B=E5=8A=A8=E9=A9=BE=E9=A9=B6=20W=20?= =?UTF-8?q?=E6=B2=B9=E9=97=A8=20/=20S=20=E5=88=B9=E8=BD=A6=20A/D=20?= =?UTF-8?q?=E5=B9=B3=E6=BB=91=E8=BD=AC=E5=90=91=20=E7=A9=BA=E6=A0=BC=20?= =?UTF-8?q?=E6=89=8B=E5=88=B9=20C=20=E5=88=87=E6=8D=A2=E7=9B=B8=E6=9C=BA?= =?UTF-8?q?=E8=A7=86=E8=A7=92=20ESC=20=E9=80=80=E5=87=BA=20=E5=BD=BB?= =?UTF-8?q?=E5=BA=95=E7=A7=BB=E9=99=A4=E8=87=AA=E5=8A=A8=E7=9B=B4=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E7=BA=AF=E6=89=8B=E5=8A=A8=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../soyo.1.py | 90 ++++++++++--------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/src/carla_native_assisted_driving_system/soyo.1.py b/src/carla_native_assisted_driving_system/soyo.1.py index 30ca7a7f3..672eb5668 100644 --- a/src/carla_native_assisted_driving_system/soyo.1.py +++ b/src/carla_native_assisted_driving_system/soyo.1.py @@ -1,8 +1,9 @@ - +from __future__ import print_function """Example of automatic vehicle control from client side. (无agents纯净版)""" -from __future__ import print_function + +"""CARLA-Native-Assisted-Driving-System - Version 1.0""" import argparse import collections @@ -16,19 +17,9 @@ import sys import weakref -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('cannot import pygame, make sure pygame package is installed') - -try: - import numpy as np -except ImportError: - raise RuntimeError( - 'cannot import numpy, make sure numpy package is installed') +import pygame +from pygame.locals import * +import numpy as np # ============================================================================== # -- Find CARLA module --------------------------------------------------------- @@ -52,7 +43,6 @@ import carla from carla import ColorConverter as cc - # ============================================================================== # -- 已删除所有agents代码 ✅---------------------------------------------------- # ============================================================================== @@ -170,28 +160,57 @@ def destroy(self): # ============================================================================== -# -- KeyboardControl ----------------------------------------------------------- +# -- KeyboardControl (完美版手动控制) ----------------------------------------------------------- +# ============================================================================== +# ============================================================================== +# -- KeyboardControl (最终稳定版) ----------------------------------------------------------- # ============================================================================== class KeyboardControl(object): def __init__(self, world): - world.hud.notification("Press 'H' or '?' for help.", seconds=4.0) + self.world = world + self.steer = 0.0 + world.hud.notification("W前进 S刹车 A/D转向 空格手刹 C切换视角 ESC退出", 10) 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): + # 按键按下 + if event.type == pygame.KEYDOWN: + # C 切换视角 + if event.key == K_c: + self.world.camera_manager.toggle_camera() + # ESC 退出 + if event.key == K_ESCAPE: return True - @staticmethod - def _is_quit_shortcut(key): - return (key == K_ESCAPE) or (key == K_q and pygame.key.get_mods() & KMOD_CTRL) + # 实时按键检测 + keys = pygame.key.get_pressed() + + # 车辆控制 + control = carla.VehicleControl() + control.manual_gear_shift = False + + # 油门 + control.throttle = 0.6 if keys[K_w] else 0.0 + # 刹车 + control.brake = 1.0 if keys[K_s] else 0.0 + # 转向 + if keys[K_a]: + self.steer = max(self.steer - 0.05, -1.0) + elif keys[K_d]: + self.steer = min(self.steer + 0.05, 1.0) + else: + self.steer = 0.0 + control.steer = self.steer + # 手刹 + control.hand_brake = keys[K_SPACE] + # 应用控制 + self.world.player.apply_control(control) + return False -# ============================================================================== -# -- HUD ----------------------------------------------------------------------- -# ============================================================================== class HUD(object): def __init__(self, width, height): self.dim = (width, height) @@ -345,7 +364,7 @@ def render(self, display): class HelpText(object): def __init__(self, font, width, height): - lines = __doc__.split('\n') + lines = ["CARLA-Native-Assisted-Driving-System", "WASD Drive, C Switch Camera, ESC Quit"] self.font = font self.dim = (680, len(lines) * 22 + 12) self.pos = (0.5 * width - 0.5 * self.dim[0], 0.5 * height - 0.5 * self.dim[1]) @@ -546,9 +565,7 @@ def _parse_image(weak_self, image): # ============================================================================== # -- -------------------------------------------- # ============================================================================== -# ============================================================================== -# -- -------------------------------------------- -# ============================================================================== + def game_loop(args): pygame.init() pygame.font.init() @@ -569,6 +586,7 @@ def game_loop(args): while True: clock.tick_busy_loop(60) + # 仅处理键盘控制 if controller.parse_events(): return @@ -577,22 +595,10 @@ def game_loop(args): world.render(display) pygame.display.flip() - # ===================== ===================== - control = carla.VehicleControl() - control.throttle = 0.5 # 满油门 - control.steer = 0.0 # 直线 - control.brake = 0.0 # 不刹车 - control.hand_brake = False# 松手刹 - control.reverse = False # 不倒车 - control.gear = 1 # 强制1档前进 - # ==================================================== - world.player.apply_control(control) - finally: if world is not None: world.destroy() pygame.quit() - # ============================================================================== # -- main() -------------------------------------------------------------- # ============================================================================== From 001fd420883e717d6c70e577595340efcd90efec Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Fri, 17 Apr 2026 18:08:43 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E9=94=AE?= =?UTF-8?q?=E7=9B=98=E7=BA=AF=E6=89=8B=E5=8A=A8=E9=A9=BE=E9=A9=B6=20W=20?= =?UTF-8?q?=E6=B2=B9=E9=97=A8=20/=20S=20=E5=88=B9=E8=BD=A6=20A/D=20?= =?UTF-8?q?=E5=B9=B3=E6=BB=91=E8=BD=AC=E5=90=91=20=E7=A9=BA=E6=A0=BC=20?= =?UTF-8?q?=E6=89=8B=E5=88=B9=20C=20=E5=88=87=E6=8D=A2=E7=9B=B8=E6=9C=BA?= =?UTF-8?q?=E8=A7=86=E8=A7=92=20ESC=20=E9=80=80=E5=87=BA=20=E5=BD=BB?= =?UTF-8?q?=E5=BA=95=E7=A7=BB=E9=99=A4=E8=87=AA=E5=8A=A8=E7=9B=B4=E8=A1=8C?= =?UTF-8?q?=EF=BC=8C=E7=BA=AF=E6=89=8B=E5=8A=A8=E6=8E=A7=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_native_assisted_driving_system/soyo.1.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/carla_native_assisted_driving_system/soyo.1.py b/src/carla_native_assisted_driving_system/soyo.1.py index 672eb5668..e6f5a5107 100644 --- a/src/carla_native_assisted_driving_system/soyo.1.py +++ b/src/carla_native_assisted_driving_system/soyo.1.py @@ -1,10 +1,7 @@ from __future__ import print_function """Example of automatic vehicle control from client side. (无agents纯净版)""" - - """CARLA-Native-Assisted-Driving-System - Version 1.0""" - import argparse import collections import datetime @@ -43,9 +40,6 @@ import carla from carla import ColorConverter as cc -# ============================================================================== -# -- 已删除所有agents代码 ✅---------------------------------------------------- -# ============================================================================== # ============================================================================== # -- Global functions ---------------------------------------------------------- @@ -210,7 +204,6 @@ def parse_events(self): # 应用控制 self.world.player.apply_control(control) return False - class HUD(object): def __init__(self, width, height): self.dim = (width, height) From f9780e4b68eae9c58ea3fb42d3da5f70b380400b Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Fri, 17 Apr 2026 22:15:45 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=BD=A6=E8=BE=86?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=AE=9A=E9=80=9F=E5=B7=A1=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../soyo.1.py | 107 ++++++++---------- 1 file changed, 49 insertions(+), 58 deletions(-) diff --git a/src/carla_native_assisted_driving_system/soyo.1.py b/src/carla_native_assisted_driving_system/soyo.1.py index e6f5a5107..a810b9e49 100644 --- a/src/carla_native_assisted_driving_system/soyo.1.py +++ b/src/carla_native_assisted_driving_system/soyo.1.py @@ -44,6 +44,25 @@ # ============================================================================== # -- Global functions ---------------------------------------------------------- # ============================================================================== +# ============================================================================== +# -- PID Controller (智能控制算法) ------------------------------------------------ +# ============================================================================== +class PIDController: + def __init__(self, Kp=1.0, Ki=0.0, Kd=0.0): + self.Kp = Kp + self.Ki = Ki + self.Kd = Kd + self.error = 0.0 + self.last_error = 0.0 + self.integral = 0.0 + + def step(self, target, current, dt=0.05): + self.error = target - current + self.integral += self.error * dt + derivative = (self.error - self.last_error) / dt + output = self.Kp * self.error + self.Ki * self.integral + self.Kd * derivative + self.last_error = self.error + return max(0.0, min(1.0, output)) def find_weather_presets(): rgx = re.compile('.+?(?:(?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|$)') @@ -152,58 +171,6 @@ def destroy(self): if actor is not None: actor.destroy() - -# ============================================================================== -# -- KeyboardControl (完美版手动控制) ----------------------------------------------------------- -# ============================================================================== -# ============================================================================== -# -- KeyboardControl (最终稳定版) ----------------------------------------------------------- -# ============================================================================== -class KeyboardControl(object): - def __init__(self, world): - self.world = world - self.steer = 0.0 - world.hud.notification("W前进 S刹车 A/D转向 空格手刹 C切换视角 ESC退出", 10) - - def parse_events(self): - # 退出事件 - for event in pygame.event.get(): - if event.type == pygame.QUIT: - return True - # 按键按下 - if event.type == pygame.KEYDOWN: - # C 切换视角 - if event.key == K_c: - self.world.camera_manager.toggle_camera() - # ESC 退出 - if event.key == K_ESCAPE: - return True - - # 实时按键检测 - keys = pygame.key.get_pressed() - - # 车辆控制 - control = carla.VehicleControl() - control.manual_gear_shift = False - - # 油门 - control.throttle = 0.6 if keys[K_w] else 0.0 - # 刹车 - control.brake = 1.0 if keys[K_s] else 0.0 - # 转向 - if keys[K_a]: - self.steer = max(self.steer - 0.05, -1.0) - elif keys[K_d]: - self.steer = min(self.steer + 0.05, 1.0) - else: - self.steer = 0.0 - control.steer = self.steer - # 手刹 - control.hand_brake = keys[K_SPACE] - - # 应用控制 - self.world.player.apply_control(control) - return False class HUD(object): def __init__(self, width, height): self.dim = (width, height) @@ -357,7 +324,7 @@ def render(self, display): class HelpText(object): def __init__(self, font, width, height): - lines = ["CARLA-Native-Assisted-Driving-System", "WASD Drive, C Switch Camera, ESC Quit"] + lines = ["CARLA-Native-Assisted-Driving-System", "PID自动定速巡航 | ESC退出"] self.font = font self.dim = (680, len(lines) * 22 + 12) self.pos = (0.5 * width - 0.5 * self.dim[0], 0.5 * height - 0.5 * self.dim[1]) @@ -559,14 +526,21 @@ def _parse_image(weak_self, image): # -- -------------------------------------------- # ============================================================================== +# ============================================================================== +# -- game_loop (PID定速巡航 自动控制版) ------------------------------------------ +# ============================================================================== def game_loop(args): pygame.init() pygame.font.init() world = None + # 初始化PID控制器(目标速度:30 km/h) + pid = PIDController(Kp=0.8, Ki=0.1, Kd=0.05) + target_speed = 30.0 # 目标巡航速度 + try: client = carla.Client(args.host, args.port) - client.set_timeout(4.0) + client.set_timeout(10.0) display = pygame.display.set_mode( (args.width, args.height), @@ -574,20 +548,37 @@ def game_loop(args): hud = HUD(args.width, args.height) world = World(client.get_world(), hud, args) - controller = KeyboardControl(world) clock = pygame.time.Clock() while True: clock.tick_busy_loop(60) - # 仅处理键盘控制 - if controller.parse_events(): - return + + # 仅处理退出事件,无任何手动控制 + for event in pygame.event.get(): + if event.type == pygame.QUIT or (event.type == pygame.KEYUP and event.key == K_ESCAPE): + return world.world.wait_for_tick() world.tick(clock) world.render(display) pygame.display.flip() + # ===================== PID算法自动控制 ===================== + # 获取当前车速(km/h) + vel = world.player.get_velocity() + current_speed = 3.6 * math.sqrt(vel.x ** 2 + vel.y ** 2 + vel.z ** 2) + + # PID计算油门 + control = carla.VehicleControl() + control.throttle = pid.step(target_speed, current_speed) + control.brake = 0.0 + control.steer = 0.0 + control.hand_brake = False + control.manual_gear_shift = False + + # 算法输出控制指令 + world.player.apply_control(control) + finally: if world is not None: world.destroy() From dba9fe50bb30530a242f939b34a3330ee631c0dc Mon Sep 17 00:00:00 2001 From: soyo0001 <3487131467@qq.com> Date: Fri, 17 Apr 2026 22:22:35 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E8=BD=A6=E8=BE=86?= =?UTF-8?q?=E8=87=AA=E5=8A=A8=E5=AE=9A=E9=80=9F=E5=B7=A1=E8=88=AA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_native_assisted_driving_system/soyo.1.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/carla_native_assisted_driving_system/soyo.1.py b/src/carla_native_assisted_driving_system/soyo.1.py index a810b9e49..e1b417add 100644 --- a/src/carla_native_assisted_driving_system/soyo.1.py +++ b/src/carla_native_assisted_driving_system/soyo.1.py @@ -357,6 +357,7 @@ def __init__(self, parent_actor, hud): weak_self = weakref.ref(self) self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event)) + def get_collision_history(self): history = collections.defaultdict(int) for frame, intensity in self.history: