1. 程式人生 > 其它 >【模擬】Carla介紹與基本使用 [1] (附程式碼 基礎版)

【模擬】Carla介紹與基本使用 [1] (附程式碼 基礎版)

0. 參考與前言

主要介紹無人駕駛的模擬環境CARLA,開源社群維護,以下為相關參考連結:

  1. Carla官方文件 建議後續找的時候 先按好版本號,有些功能/api 是新版本里有的

    Carla官方github

  2. Youtube Python+Window 0.9.5 主要是用Carla環境,使用TensorFlow搭建簡單的自我學習自動駕駛車輛【雖然到最後還是沒看到學成功的車到底長啥樣】

  3. 知乎正在更新中的關於Carla較全面的介紹連結

  4. 安裝見:張聰明的CSDN【壓縮包安裝法】


此係列為張聰明三次使用carla,終於開始寫記錄 認認真真搞一次

第一次:是因為 Youtube Python+Window 0.9.5

,然後當時在windows上沒發運行就不了了之了,具體問題見當初在Github issue連結

第二次:是打算用Carla跑ROS聯通,但是很快就... 沒搞了 有其他活

第三次:也是這次... Autoware的連線,當然就包括ROS了,其實不難查到Carla有一個專門的分支是用autoware核心的,但是呢... 介於我們還要上實車,所以就相當於remap到autoware的topic上了,但是這次因為要設定NPC玩家的軌跡以便驗證每個步驟的流程【識別、OpenPlanner的行駛】所以就剛好認認真真看一次順便做個筆記


更新日誌:

20220527:重置 刪除相關notion外鏈等 新增相關圖片和對應連結

20220525:進行了一次較為大的改動,重組了一下目錄 和 一些內容;去掉了一些原文的大段英文

20210420:第一版說明發布,總結了CARLA的基本使用

1. CARLA 世界組成

這一點在引用3. Carla較全面的介紹 進行了介紹,所以我就寫點 我的note/補充

首先是互動形式:Client-Server,所以當時我提出windows上無法執行成功時有人回覆:是否是2000口沒有開(但後續我確認過開了還是不行)就類似於IP握手連線的感覺?所以應該是可以在主機直接連線到其他跑模擬主機的host_ip的

主要核心

僅進行一些簡單介紹,對整體有個概念,如果沒有到用上的時候,沒有做說明的,可以暫時不用深入瞭解

  • Traffic manager. 類似於一個車輛管理器,更多詳情見 [3] NPC管理/Traffic Manager ,‼️ 建議後續進行了解
  • Sensors. 車輛上的感測器,可以進行設定,CARLA內建有不少的感測器(LiDAR, Camera, Depth, DVS, Radar等等)
  • Recorder. 內建的一個記錄工具,和rosbag異曲同工,更多詳情見 [9] replay用法
  • ROS bridge and Autoware implementation. 和ROS相關的一些bridge,可以直接看github ros-bridge的用法
  • Open assets. 城鎮的一些貼圖之類的,assets,如果不走UE4 原始碼編譯,基本不會用上,0.9.13裡進行了更新,可以修改一些貼圖,更多建議自己探索
  • Scenario runner. 場景生成器,類似於做演算法測試時希望能生成特定場景的功能。更多詳情可以看看CARLA辦的排行榜比賽 [7] Carla leaderboard 排行榜,0.9.11/12 好像引入了openscenario的格式進行設定

2. 標頭檔案設定

一般最好的學習方式是直接先看一下官方的示例,一般用壓縮包安裝法開啟後,整體資料夾的位置如下,可以看到 PythonAPI/examples 資料夾下有很多示例

➜  CARLA tree -L 1
.
├── CarlaUE4
├── CarlaUE4.sh
├── CHANGELOG
├── Co-Simulation
├── Dockerfile
├── Engine
├── HDMaps
├── Import
├── ImportAssets.sh
├── LICENSE
├── Manifest_DebugFiles_Linux.txt
├── Plugins
├── PythonAPI
│   ├── carla
│   ├── examples
│   ├── python_api.md
│   ├── tutorials
│   └── util
├── README
├── Tools
└── VERSION

然後開啟時可以看到基本上所有的開頭都有這樣一段code,其實原因是因為carla有自己的python api庫,可以通過此進行定位匯入

# -- coding:UTF-8 --
#!/usr/bin/env python

import glob
import os
import sys
import time

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

import carla

每個檔案請複製這個到頭,或者按照下面所示新增庫到自己的路徑中

0.9.13及後的都可以通過pip install

pip3 install carla

0.9.12及以下的【引用3. 提到的方法把carla內置於python庫當中去】 注意修改自己的CARLA資料夾、版本號和Python 版本號

cd ~/CARLA_0.9.11/PythonAPI/carla/dist/
unzip carla-0.9.11-py2.7-linux-x86_64.egg -d carla-0.9.11-py2.7-linux-x86_64
cd carla-0.9.11-py2.7-linux-x86_64
gedit setup.py

然後複製這段到setup.py裡

from distutils.core import setup
setup(name='carla',
      version='0.9.11', 
      py_modules=['carla'],
      )

最後install一下就行

pip install -e ~/CARLA_0.9.11/PythonAPI/carla/dist/carla-0.9.11-py2.7-linux-x86_64

3. 初步探索

此章節主要參照官方文件的first step裡的內容,學有餘力者可直接閱讀英文原版文件,之中會新增一些自己的使用經驗和碎碎念

1st - World and Client


# 這裡是連線Carla 伺服器
client = carla.Client('localhost', 2000)
client.set_timeout(10.0) # seconds

# 讀取現在開啟的Carla裡的世界資訊
world = client.get_world()

讀取世界資訊的操作呢,主要是為了後面能

  • world.get_map() 拿到世界地圖
  • world.spawn_actor 在世界內生成NPC或自己的車
  • world.get_blueprint_library() 在世界讀blueprint的庫裡都有些啥 加車加感測器
  • world.get_random_location_from_navigation() 就是他名字寫的那樣

那麼這些點後面的 我們應該從哪裡得知呢?→ 跳轉官方文件連結

2nd - Actors and blueprints


關於world能得到的所有的藍圖見此連結,我們先試著生成一輛車

# get blueprint library 
blueprint_library = world.get_blueprint_library()
# 你可以在上面給的連結中找到 你想新增的東西
ego_vehicle_bp = blueprint_library.find('vehicle.audi.a2')
# 給我們的車加上特定的顏色
ego_vehicle_bp.set_attribute('color', '0, 0, 0')

關於第二點,是在find裡找到新增的東西,建議開啟網頁然後CTRL+F,然後搜尋關鍵字,比如

  • 如果你想新增的是感測器那麼一般以sensor開頭,sensor.sensor_type(感測器.感測器型別) sensor.lidar.ray_cast 就是鐳射雷達,sensor.other.collision 就是碰撞檢測的【具體是啥呢 咱也不用管】
  • 如果是車呢,一般就是vehicle開頭,vehicle.audi.a2 就是奧迪A2的車型

Attributes have an carla.ActorAttributeType variable. It states its type from a list of enums. Also, modifiable attributes come with a list of recommended values.
這句話是指 每一個blueprint呢都是有附加的東西的,比如顏色?你可以看看關於attibute的型別有哪些

  • 知道了在BP的庫連結裡能看到,每一個find裡面都有它自身附帶的屬性;可以獲取或設定attribute


看完了怎麼去找到blueprint,那麼怎麼把他加入到world並跟蹤其狀態,包括位置、資訊(如果是感測器的話 就會有感測器的一系列訊息 比如相機會有圖片、鐳射雷達會有點雲)

The world object is responsible of spawning actors and keeping track of these. Spawning only requires a blueprint, and a carla.Transform stating a location and rotation for the actor.

也就是我們已經有了blueprint那麼只需要給出transform就OK啦!

# 設定固定點,和他的朝向應該是怎樣的
transform = carla.Transform(carla.Location(x=-9, y=80, z=2), carla.Rotation(yaw=180))

# 隨機的獲取世界中的一個點,這一行你也可以在spwan_npc.py中看到
spawn_points = world.get_map().get_spawn_points()

# 然後把之前的blueprint填入第一個引數中,transform填入第二個引數中
actor = world.spawn_actor(ego_vehicle_bp, transform)
  • map.get_spawn_points() for vehicles. Returns a list of recommended spawning points.
  • world.get_random_location() for walkers. Returns a random point on a sidewalk. This same method is used to set a goal location for walkers.

官方文件的這個章節有詳細的講解怎麼新增感測器到車上,行人的軌跡等。基於我的需求 我就寫到這裡了,噢 還有個部分就是創建出來的NPC你在退出的時候要銷燬,不然... 就會有很多很多很多NPC只能關閉Carla本身去銷燬,而且後續也容易出BUG

然後這裡就是執行完後直接CTRL+C停止指令碼的同時,執行銷燬

按照下面的程式碼及位置生成車輛

停止執行並,銷燬車輛

  • 完整程式碼見:

    # -- coding:UTF-8 --
    #!/usr/bin/env python
    # Author:Kin Zhang
    # email: [email protected]
    
    import glob
    import os
    import sys
    import time
    
    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
    
    import carla
    
    from carla import VehicleLightState as vls
    
    import argparse
    import logging
    from numpy import random
    
    def main():
        synchronous_master = False
        try:
            client = carla.Client('localhost', 2000)
            client.set_timeout(2.0)
            world = client.get_world()
    
            # 拿到這個世界所有物體的藍圖
            blueprint_library = world.get_blueprint_library()
            # 從浩瀚如海的藍圖中找到賓士的藍圖
            ego_vehicle_bp = blueprint_library.find('vehicle.audi.a2')
            # 給我們的車加上特定的顏色
            ego_vehicle_bp.set_attribute('color', '0, 0, 0')
    
            # 找到所有可以作為初始點的位置並隨機選擇一個
            # transform = random.choice(world.get_map().get_spawn_points())
            
            # 設定固定點
            transform = carla.Transform(carla.Location(x=-9, y=80, z=2), carla.Rotation(yaw=90))
            # 在這個位置生成汽車
            ego_vehicle = world.spawn_actor(ego_vehicle_bp, transform)
    
            while True:
                if synchronous_master:
                    world.tick()
                else:
                    world.wait_for_tick()
        finally:
            # 如果設定了同步記得 設定回去非同步否則下次無法開啟同步
            if synchronous_master:
                settings = world.get_settings()
                settings.synchronous_mode = False
                settings.fixed_delta_seconds = None
                world.apply_settings(settings)
            print('\ndestroying vehicles')
            ego_vehicle.destroy()
            time.sleep(0.5)
    
    if __name__ == '__main__':
    
        try:
            main()
        except KeyboardInterrupt:
            pass
        finally:
            print('\ndone.')
    

關於生成我們已經清楚了【可以留個作業:怎麼生成走路的行人,也就是製作重複行人過馬路的場景 .gif圖如下,會再下次再貼程式碼講】那麼在使用過程中我們可能需要設定行人過馬路或者突然橫穿馬路的情景,在這裡,我們繼續實現前者以便驗證一些感知、規劃演算法等

首先關於這一點還有一些知識,但也就是官網上的,主要呢就是說 整個actor的狀態你都是可以知道的;當你生成了很多actors後,可以使用

# 讀取現在開啟的Carla裡的世界資訊
world = client.get_world()
# 前提是你定義的client.get_world()是賦給了叫world的變數哈

# 這樣就拿到了這個世界裡所有actor的資訊
actor_list = world.get_actors()

我們可以看到圖片中是執行的結果,如果你只想關注vehicle可以actor_list.filter('vehicle.*') 而圖片中我是抽取了限速標誌 看看所有限速標誌的位置即其id號

那麼我是怎麼知道他的是type_id而不是type呢?【別問 問就是我... 以為是type然後報錯了 然後就去官網,有一說一官網的文件寫的那叫一個好,前提是你入門了這個..】

Python API reference

開啟文件後我們可以看到如圖所示的然後就知道了一個actor所包含的東西,往下翻還可以看到為什麼我能拿到他的位置因為Methods裡面有:Getters都有些啥

同時還可以設定一些引數,注意輸入的資料格式即可,比如你可以先生成車輛,再把車輛set_location

說了Actors的操作後,我們還需要強調一點前面提到過的,destory銷燬這些,不然你僅僅退出,這個actor還是會在這個地圖裡的,如果下一個位置你還是在這裡生成車輛

所以一定要記得destroyed_sucessfully = actor.destroy() # Returns True if successful 這個destory命令 在執行後,特別是針對於在Carla中用學習來不斷創造場景的

當然你還可以設定你的視野,所以你可以繫結你的視野,或者是... 繫結相機的位置 到司機的位置

spectator = world.get_spectator()
transform = vehicle.get_transform()
spectator.set_transform(carla.Transform(transform.location + carla.Location(z=50),
carla.Rotation(pitch=-90)))

讀取交通燈的狀態

#Get the traffic light affecting a vehicle
if vehicle_actor.is_at_traffic_light():
    traffic_light = vehicle_actor.get_traffic_light()

甚至是改變交通燈的狀態【上帝模式】

#Change a red traffic light to green
if traffic_light.get_state() == carla.TrafficLightState.Red:
    traffic_light.set_state(carla.TrafficLightState.Green)
    traffic_light.set_set_green_time(4.0)

3rd - Maps and navigation

啊 後悔,太晚才看這個點... 寫到這裡還是再次建議大家看官方文件比較好,如果對英文閱讀沒有什麼障礙的話,文件的語言都很簡單放心 不像論文那樣,字都認識連起來不知道啥意思【沒錯說我自己呢】

在上面的例子中,我們可以在client後建立世界的時候,載入自己想要的地圖

    try:
        client = carla.Client('localhost', 2000)
        client.set_timeout(2.0)
        world = client.load_world('Town01') #load Town 01 Map
				world = reload_world() #reload the same map as world have
Town Summary
Town01 A basic town layout with all "T junctions".
Town02 Similar to Town01, but smaller.
Town03 The most complex town, with a 5-lane junction, a roundabout, unevenness, a tunnel, and much more. Essentially a medley.
Town04 An infinite loop with a highway and a small town.
Town05 Squared-grid town with cross junctions and a bridge. It has multiple lanes per direction. Useful to perform lane changes.
Town06 Long highways with many highway entrances and exits. It also has a Michigan left.
Town07 A rural environment with narrow roads, barely non traffic lights and barns.
Town10HD A city environment with with different environments such as an avenue or a promenade, and more realistic textures.

更多關於城鎮路線俯檢視圖片可以跳轉此處檢視

對於地圖的格式,其實如果要在其他地方用的話,是可以直接提取地圖裡的waypoint點的,準確點是根據OpenDRIVE 1.4的標準來看,也就是說其實在Carla世界裡是不需要建圖、定位,直接導航即可,The traffic signs defined in the OpenDRIVE file are translated into CARLA as landmark objects that can be queried from the API. In order to facilitate their manipulation, there have been several additions to it.

  • carla.Landmark objects represent the OpenDRIVE signals. The attributes and methods describe the landmark, and where it is effective.
  • carla.Waypoint can get landmarks located a certain distance ahead of it. The type of landmark can be specified.
  • The carla.Map retrieves sets of landmarks. It can return all the landmarks in the map, or those having an ID, type or group in common.
  • The carla.World acts as intermediary between landmarks, and the carla.TrafficSign and carla.TrafficLight that embody them in the simulation.

下面我們可以試著讀取一下地圖裡有的waypoint,world.get_map().generate_waypoints(distance) 如果是老版本可能是world.map().generate_waypoints(distance) 或者是沒有這個功能

waypoint點顯示圖 Town01下的

def main():
    
    try:
        SpawnActor = carla.command.SpawnActor
        client = carla.Client('localhost', 2000)
        client.set_timeout(2.0)
        world = client.load_world('Town01')

        distance = 10 #waypoint的間距
        waypoints = world.get_map().generate_waypoints(distance)
        for w in waypoints:
            world.debug.draw_string(w.transform.location, 'O', draw_shadow=False,
                                            color=carla.Color(r=255, g=0, b=0), life_time=120.0,
                                            persistent_lines=True)
        while True:
            world.wait_for_tick()
        
    finally:
        print('\ndestroying vehicles')
        time.sleep(0.5)

if __name__ == '__main__':

    try:
        main()
    except KeyboardInterrupt:
        pass
    finally:
        print('\ndone.')

這樣一來如果在Carla裡面去實現什麼,根本不需要再用大采樣的方式了,取樣只需在兩個waypoint與可達點範圍內即。至此我們已經知道怎樣獲取waypoint了,可以試一試manual_control.py內,獲取我們車的位置所處的waypoint甚至是lane_id,判斷是否在junction裡等一系列

執行演示gif 判斷是否到了交叉路口處

執行判斷的示意圖

for ego_vehilce in my_vehicles:
                waypoint01 = my_maps.get_waypoint(ego_vehilce.get_location(),project_to_road=True, lane_type=(carla.LaneType.Driving))
                client.get_world().debug.draw_string(waypoint01.transform.location, 'O', draw_shadow=False,
                                            color=carla.Color(r=255, g=0, b=0), life_time=120.0,
                                            persistent_lines=True)
                # Examples of a waypoint accessing to lane information
                inside_junction = waypoint01.is_junction
                width = waypoint01.lane_width
                # right_lm_color = waypoint01.right_lane_marking.color
                print('waypoint:',waypoint01)
                print('is inside junction:',inside_junction,'lane width',width)

插入的位置與前置條件:

  1. 需要一開始把自己的車型定下來,或者看好actor_id然後再到另一個py指令碼找這個對應的id
  2. 一定要記得get_map()這樣才有前面提到的一些操作
  3. waypoint其下也有判斷,點選此處官方文件進行了解
  4. is_junction其實在官方的3st這個節下寫錯了應該是沒有()不然會報錯bool no callback

4th. Sensors and data

這一節主要是告訴大家怎麼將現有的車上安裝 感測器,和感測器的資料格式,其實在manual_control.py和tutorial.py裡面都有... 看著看著也就會模仿了,比如RGB相機的,怎麼看有什麼呢?前面提到了blueprint大集合官方文件:https://carla.readthedocs.io/en/latest/bp_library/ 然後CTRL+F 輸入sensor就可以看到所有的感測器型別即其輸出的資訊

# 找到感測器的藍圖
# Find the blueprint of the sensor.
blueprint = world.get_blueprint_library().find('sensor.camera.rgb')
# Modify the attributes of the blueprint to set image resolution and field of view.
blueprint.set_attribute('image_size_x', '1920')
blueprint.set_attribute('image_size_y', '1080')
blueprint.set_attribute('fov', '110')
# Set the time in seconds between sensor captures
blueprint.set_attribute('sensor_tick', '1.0')

# 設定感測器位置,attach to的vehicle
transform = carla.Transform(carla.Location(x=0.8, z=1.7))
sensor = world.spawn_actor(blueprint, transform, attach_to=my_vehicle)

# 接收感測器的資料
# do_something() will be called each time a new image is generated by the camera.
sensor.listen(lambda data: do_something(data))

...

# This collision sensor would print everytime a collision is detected. 
def callback(event):
    for actor_id in event:
        vehicle = world_ref().get_actor(actor_id)
        print('Vehicle too close: %s' % vehicle.type_id)

sensor02.listen(callback)

4. 補充

參考:https://carla.readthedocs.io/en/latest/start_quickstart/#import-additional-assets

附加地圖的匯入

官方的package下載模式,是沒有把Town06, Town07, and Town10的地圖放入的,但是可以由xdor開啟,就是不帶模型的 只有OpenDrive格式的

比如 Town7:

github

首先去github的release上下載對應版本對應系統的additional

Ubuntu/Linux

把下載的壓縮包(不用解壓!)直接移到Carla的根目錄下有個叫 Import 的資料夾

move the package to the Import folder and run the following script to extract the contents:

cd path/to/carla/root

./ImportAssets.sh

然後就好了

Windows

直接解壓到根目錄下即可

5. 總結

  1. Carla原來比我想的強大太多了,主要是關於地圖的定義也很明確,感測器型別,等等等等簡直了... 太適合做學習類的了
  2. 感覺下來學習Carla最重要的就是看官方文件而不是百度,首先明確自己想要幹什麼,比如設定速度,設定位置,你就要知道actor.get_location()或者是actor.set_location()這些都可以在blueprint那裡面看到每一個blueprint下都有什麼屬性
  3. 以上,也算是給自己做一個筆記了,後續可能會繼續學習怎麼建立學習的環境(看到github上其實有很多挺棒的,但是版本都比較老了)