【模擬】Carla介紹與基本使用 [1] (附程式碼 基礎版)
0. 參考與前言
主要介紹無人駕駛的模擬環境CARLA,開源社區維護,以下為相關參考鏈接:
-
Carla官方文檔 建議後續找的時候 先按好版本號,有些功能/api 是新版本里有的
-
Youtube Python+Window 0.9.5 主要是用Carla環境,使用TensorFlow搭建簡單的自我學習自動駕駛車輛【雖然到最後還是沒看到學成功的車到底長啥樣】
-
知乎正在更新中的關於Carla較全面的介紹鏈接
-
安裝見:張聰明的CSDN【壓縮包安裝法】
此系列為張聰明三次使用carla,終於開始寫記錄 認認真真搞一次
第一次:是因為 Youtube Python+Window 0.9.5 ,然後當時在windows上沒發運行就不了了之了,具體問題見當初在Github issue鏈接
第二次:是打算用Carla跑ROS聯通,但是很快就… 沒搞了 有其他活
第三次:也是這次… Autoware的連接,當然就包括ROS了,其實不難查到Carla有一個專門的分支是用autoware內核的,但是呢… 介於我們還要上實車,所以就相當於remap到autoware的topic上了,但是這次因為要設置NPC玩家的軌跡以便驗證每個步驟的流程【識別、OpenPlanner的行駛】所以就剛好認認真真看一次順便做個筆記
這個系列同步在cnblog和csdn上進行更新,相關專欄和分類鏈接如下,有用的話 點個小贊,正向回饋~ 👍
- CSDN: //blog.csdn.net/qq_39537898/category_11562137.html
- cnblog: //www.cnblogs.com/kin-zhang/category/2096236.html
更新日誌:
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() # 從浩瀚如海的藍圖中找到Benz的藍圖 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然後報錯了 然後就去官網,有一說一官網的文檔寫的那叫一個好,前提是你入門了這個..】
打開文檔後我們可以看到如圖所示的然後就知道了一個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.LandmarkOrientation states the orientation of the landmark with regards of the road’s geometry definition.
- carla.LandmarkType contains some common landmark types, to ease translation to OpenDRIVE types.
- A 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)
插入的位置與前置條件:
- 需要一開始把自己的車型定下來,或者看好actor_id然後再到另一個py腳本找這個對應的id
- 一定要記得get_map()這樣才有前面提到的一些操作
- waypoint其下也有判斷,點擊此處官方文檔進行了解
- is_junction其實在官方的3st這個節下寫錯了應該是沒有()不然會報錯bool no callback

4th. Sensors and data
這一節主要是告訴大家怎麼將現有的車上安裝 感測器,和感測器的數據格式,其實在manual_control.py和tutorial.py裡面都有… 看著看著也就會模仿了,比如RGB相機的,怎麼看有什麼呢?前面提到了blueprint大集合官方文檔://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. 補充
參考://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. 總結
- Carla原來比我想的強大太多了,主要是關於地圖的定義也很明確,感測器類型,等等等等簡直了… 太適合做學習類的了
- 感覺下來學習Carla最重要的就是看官方文檔而不是百度,首先明確自己想要幹什麼,比如設置速度,設置位置,你就要知道actor.get_location()或者是actor.set_location()這些都可以在blueprint那裡面看到每一個blueprint下都有什麼屬性
- 以上,也算是給自己做一個筆記了,後續可能會繼續學習怎麼建立學習的環境(看到github上其實有很多挺棒的,但是版本都比較老了)
贈人點贊 手有餘香 😆;正向回饋 才能更好開放記錄 hhh