首页/文章/ 详情

仿真测试入门参考(21):CARLA的道路环境

6月前浏览3525

 经常有朋友问如何学习仿真测试,于是想着把自己的一些经验和理解分享出来,希望能有所帮助。不过视野和技术有限,所说不一定对,供大家批评和参考。这是第21篇,CARLA的道路环境。

前面介绍了车辆模型和传感器,本篇介绍CARLA中道路环境的加载方式和如何获取相应信息

道路环境不仅包含道路结构,还包括附着在道路上的交通标志、标线、信号灯和建筑树木等静态元素。道路环境是生成仿真世界的基础,也是复杂多样的测试场景的重要组成部分。

01

道路环境的加载


CARLA中道路环境的加载方法如下图所示。

仿真世界的正常运行需要两个方面的信息:①几何渲染信息,一方面生成可视化的道路、天气、交通参与者等各种物体方便观察,另一方也是进一步生成各种传感器信息的基础,这部分由UnrealEngine map asset文件提供(.uaset/.uexp/.umap等文件);
②路网逻辑描述信息,用于交通参与者按照设定路线行驶、实现相应驾驶行为等等,这部分由OpenDRIVE格式文件提供(.xodr文件)。这些文件都保存在carla_root/CarlaUE4/Content/Carla文件夹中。
CARLA提供了两种道路环境(仿真世界)的加载方式,用以满足不同用户的需求,下面通过一个代码实例来说明。
    1.import carla  2.import os  3.import time  4.  5.# 设置道路环境加载方式  6.LOAD_MODE = "map" #map or xodr  7.  8.def main():  9.    # 创建client,并获取world  10.    client = carla.Client("localhost", 2000)  11.  12.    # 加载地图  13.    if LOAD_MODE == "map":  14.        # 加载Town10HD_Opt  15.        maps = client.get_available_maps()  16.        print(f"maps = {maps}")  17.        world = client.load_world("Town10HD_Opt")  18.        time.sleep(3)  19.        world.unload_map_layer(carla.MapLayer.All)  20.        time.sleep(1)  21.        world.load_map_layer(carla.MapLayer.Ground)  22.        time.sleep(1)  23.        world.load_map_layer(carla.MapLayer.Buildings)  24.    elif LOAD_MODE == "xodr":  25.        # 加载OpenDRIVE  26.        xodr_path_base = "/home/sun/adsim_sun/carla_api_example/OpenDrive"  27.        xodr_name = "Town10HD_Opt"  28.        xodr_path = os.path.join(xodr_path_base, f"{xodr_name}.xodr")  29.        with open(xodr_path, encoding='utf-8') as od_file:  30.            data = od_file.read()  31.            print(f"load opendrive map {xodr_path}")  32.  33.        vertex_distance = 2.0  # in meters  34.        max_road_length = 500.0 # in meters  35.        wall_height = 1.0      # in meters  36.        extra_width = 0.6      # in meters  37.        world = client.generate_opendrive_world(  38.            data, carla.OpendriveGenerationParameters(  39.                vertex_distance=vertex_distance,  40.                max_road_length=max_road_length,  41.                wall_height=wall_height,  42.                additional_width=extra_width,  43.                smooth_junctions=True,  44.                enable_mesh_visibility=True))  45.  46.if __name__ == "__main__":  47.    main() 
    (1)使用load_world方法加载map asset文件和OpenDRIVE文件,生成完整世界。
    采用预先定义的几何渲染文件和道路逻辑文件,可提供良好的可视化和传感器模拟效果,根据map asset文件中信息的详实程度,可显示路面、建筑、树木等各种元素。
    CARLA自带了Town01~Town12等多张现成的地图供用户使用,用户也可以根据需求自行开发地图:首先在地图生成软件中编辑并导出.fbx和.xodr文件,然后使用CARLA提供的工具进行格式转换,生成map asset文件(类似3.3.1中AdditionalMaps_0.9.14.tar.gz),最后导入CARLA中使用。地图生成软件CARLA官方推荐使用RoadRunner,用户也可以使用Autodesk Maya、Blender等其他能生成.fbx和.xodr文件的软件,或者由其他格式文件转换而来。开发地图并导入可参考CARLA文档[ https://carla.readthedocs.io/en/latest/tuto_M_custom_map_overview/]。
    如代码第15~17行所示,通过client的load_world方法可加载相应名称的地图文件,现有的地图文件名称可以通过client.get_available_maps() 方法查看。加载名称后缀为“_Opt”地图后,可使用unload_map_layer或load_map_layer对道路、建筑等不同元素分层隐藏或者显示。
    (2)通过generate_opendrive_world方法仅加载OpenDRIVE地图生成简易世界,即OpenDRIVE standalone模式。
    该方法仅需要OpenDRIVE文件,不需要map asset文件,由CARLA根据OpenDRIVE中的相关信息生成简易的渲染信息,主要包括路网结构,而不包括建筑、树木、车道线等,满足了只关注道路结构或者难以生成几何渲染信息的用户的使用需求。
    如代码第26~44行所示,通过generate_opendrive_world方法可加载对应路径下的OpenDRIVE文件,加载时可进行相应的参数设置,一般保持默认即可。
    两种模式可通过代码第6行定义的全局变量LOAD_MODE切换,两种模式加载的仿真世界可视化效果如下图所示:

    02

    道路环境信息的获取


    比较重要的道路环境信息有车道、车道线和红绿灯等,一般我们需要获取这些信息时都与某个位置相关,如需要获取ego车当前位置一定范围内的车道、车道线和红绿灯信息。CARLA中也提供了路径点(waypoint)的概念,上述所有信息都可以通过路径点获取。
    路径点可以理解成沿车道中心线分布的离散点,CARLA中这些离散点的最小距离是2cm,车辆在道路上行驶的过程就是通过一个又一个路径点的过程。车辆在某个位置时,其所在的车道和周围的车道线、红绿灯等信息都可以通过当前路径点的相关方法获取。
    下面通过一个实例来说明如何通过路径点获取想要的信息。
      1.import carla  2.import random  3.  4.def main():  5.    # 创建client,并获取world  6.    client = carla.Client("localhost", 2000)  7.    world = client.get_world()  8.  9.    # 获取map信息  10.    map = world.get_map()  11.  12.    # 设置ego的车型  13.    ego_bp = world.get_blueprint_library().find('vehicle.tesla.model3')  14.    ego_bp.set_attribute('role_name','ego')  15.  16.    # 随机选择预定义的生成点为ego生成位置  17.    spawn_points = world.get_map().get_spawn_points()  18.    spawn_point = random.choice(spawn_points)  19.      20.    # 生成ego车并设置自动驾驶  21.    ego_vehicle = world.try_spawn_actor(ego_bp, spawn_point)  22.    ego_vehicle.set_autopilot(True)  23.      24.    snap = world.wait_for_tick()  25.    init_frame = snap.frame  26.    run_frame = 0  27.    print(f"spawn ego vehicle at: {spawn_point}")  28.  29.    # 采用默认的异步变步长模式  30.    while run_frame < 10000:  31.        snap = world.wait_for_tick()  32.        run_frame = snap.frame - init_frame  33.        print(f"----- run_frame = {run_frame} -----")  34.  35.        # 设置spectator跟随ego车  36.        spectator = world.get_spectator()  37.        ego_tf = ego_vehicle.get_transform()  38.        spectator_tf = carla.Transform(ego_tf.location, ego_tf.rotation)  39.        spectator_tf.location += ego_tf.get_forward_vector() * (-10)  40.        spectator_tf.location += ego_tf.get_up_vector() * 3  41.        spectator.set_transform(spectator_tf)  42.          43.        # 获取车辆位置  44.        transform = ego_vehicle.get_transform()  45.        waypoint = map.get_waypoint(transform.location)  46.        print(f"-- current waypoint = {waypoint}")  47.  48.        #获取当前位置的车道信息  49.        road_id = waypoint.road_id  50.        section_id = waypoint.section_id  51.        lane_id = waypoint.lane_id  52.        lane_type = waypoint.lane_type  53.        s = waypoint.s  54.        print(f" -road_id = {road_id}, section_id = {section_id}, lane_id = {lane_id}, lane_type = {lane_type}, s = {s}")  55.  56.        right_marking = waypoint.right_lane_marking  57.        print(f" -right marking color = {right_marking.color}, type = {right_marking.type}, width = {right_marking.width}")  58.59.        #获取当前位置附近的红绿灯  60.        landmarks = waypoint.get_landmarks(50)  61.        for landmark in landmarks:  62.            tf = landmark.transform  63.            distance = landmark.distance  64.            name = landmark.name  65.            type = landmark.type  66.            print(f" -landmark tf = {tf}, distance = {distance}, name = {name}, type = {type}")  67.    68.        #获取附近路径点  69.        next_wp = waypoint.next(10) #获取前进方向10米处的路径点列表,分叉处可能有多个点  70.        previous_wp = waypoint.previous(5) #获取后退方向5米的路径点列表,合流处可能有多个点  71.        left_wp = waypoint.get_left_lane() #获取左侧车道的路径点  72.        right_wp = waypoint.get_right_lane() #获取右侧车道的路径点  73.        print(f" -next_wp = {next_wp[0]}")  74.        print(f" -previous_wp = {previous_wp[0]}")  75.        print(f" -left_wp = {left_wp}")  76.        print(f" -right_wp = {right_wp}")  77.  78.    # 销毁车辆  79.    is_destroyed = ego_vehicle.destroy()  80.    if is_destroyed:  81.        print(f"ego_vehicle has been destroyed sucessfully")  82.  83.if __name__ == "__main__":  84.    main()

      若想通过路径点获取当前位置的各种信息,首先要获取当前位置对应的路径点,方法是:①通过world的get_map方法获取当前仿真世界的地图信息,如代码第10行所示,该方法一次会获取所有地图信息,因此耗时较大、获取一次即可反复使用;②获取当前位置,进而通过map的get_waypoint方法获取对应的路径点,如代码第44~45行;③获取当前路径点对应的各种信息。

      代码第48~54行获取了当前车道信息,如道路、路段、车道id,车道类型和车道线等;代码第59~66行获取了当前位置一定范围内的红绿灯信息,包括红绿灯的位置、名称和类型等;代码第68~76行获取了前方、后方一定距离和左右相邻车道上的路径点信息,这方便对周围一定范围内的道路信息进行遍历获取。
      来源:孙工自动驾驶
      建筑自动驾驶Maya渲染
      著作权归作者所有,欢迎分享,未经许可,不得转载
      首次发布时间:2023-10-24
      最近编辑:6月前
      孙工自动驾驶
      硕士 专注自动驾驶仿真测试
      获赞 15粉丝 14文章 74课程 0
      点赞
      收藏
      未登录
      还没有评论

      课程
      培训
      服务
      行家

      VIP会员 学习 福利任务 兑换礼品
      下载APP
      联系我们
      帮助与反馈