【模擬】Carla之收集資料快速教程 (附完整程式碼) [7]

Kin_Zhang發表於2022-03-25

收集過程視覺化展示,隨後進入正文:

【模擬】Carla之收集資料快速教程 (附完整程式碼) [7]

參考與前言

看到模擬群對這類任務下(用carla收集資料然後再做訓練等) 需求量大,順手馬上寫一個好了,首先收集資料需要考慮清楚:

  1. 收集什麼資料,需要什麼樣的資料格式

  2. 資料之間的時間戳一定要同步,這就意味著對carla的時間設定有一定的認知

    【模擬】Carla世界的時間 [2]

  3. 收集資料時一般沒啥意外的話 我們傾向於車自己自動跑,有時候可能會想著 不考慮紅綠燈、速度快一點等等等。這意味著要對traffic manager有一定認知

    【模擬】Carla之Traffic Manager [3]

我一直以為... CARLA 寫完的專欄已經很清晰的寫了怎樣使用 但是... 大家好像傾向於動手再說 就導致了 我們群裡不止看到過一次以下問題:

  1. 怎樣保證感測器之間的同步 → 同步模式設定
  2. 為什麼我的CARLA看起來很卡 → 看看GPU能不能跟得上把 bro

接下來 我們將完成這樣一個任務:收集車輛行駛過程中的前端兩個相機圖,頂部雷達點雲,同時儲存自身IMU和GNSS資料(注意GPS和直接從carla拿的location是不一樣的!)GNSS的資料是需要進行一定轉換才能和carla location是一樣的

以下有些部分很基礎,懶得看文字的直接看程式碼也行,程式碼地址:https://gitee.com/kin_zhang/carla-python-api/blob/develop/tutorial/collect_data.py

相關參考連結及教學 一併在前言放出,後續不再進行單獨複製:

  1. 知乎小飛哥 CARLA教程專欄:https://www.zhihu.com/column/c_1324712096148516864

  2. 博主自己的 CSDN教程專欄:https://blog.csdn.net/qq_39537898/category_11562137.html

  3. 最好的!!!還是CARLA 官方文件!!! 球球大家多查查官方文件把!! PS 記得對上自己的CARLA版本哦

    CARLA Simulator

    簡單關注點,以下全部有官方文件對應部分:

    1. CARLA 世界的時間是怎樣執行與規定的:https://carla.readthedocs.io/en/latest/adv_synchrony_timestep/
    2. 內部有哪些感測器可用:https://carla.readthedocs.io/en/latest/ref_sensors/

0. 世界設定

同步時間設定

注意收集資料 一定要開CARLA同步模式,而如果要用trafficmanager,因為開過同步模式,trafficmanager也是需要一起同步的。這塊的知識在前言裡有給出連結

球球大家看看時間設定把:CARLA時間設定

以下直接擷取了,完整程式碼請點選前言部分:

def main(args):
    # We start creating the client
    client = carla.Client(args.host, args.port)
    client.set_timeout(5.0)
    
    # world = client.get_world()
    world = client.load_world('Town01')
    blueprint_library = world.get_blueprint_library()
    try:
        original_settings = world.get_settings()
        settings = world.get_settings()

        # We set CARLA syncronous mode
        settings.fixed_delta_seconds = 0.05
        settings.synchronous_mode = True
        world.apply_settings(settings)
        spectator = world.get_spectator()

        # 手動規定
        # transform_vehicle = carla.Transform(carla.Location(0, 10, 0), carla.Rotation(0, 0, 0))
        # 自動選擇
        transform_vehicle = random.choice(world.get_map().get_spawn_points())
        ego_vehicle = world.spawn_actor(random.choice(blueprint_library.filter("model3")), transform_vehicle)
        actor_list.append(ego_vehicle)
  1. client和server進行連線
  2. get_world就是CARLA現在這個介面上是什麼地圖 世界就是那個;load world呢就是自己可以選不預設的CARLA 內建的幾個城鎮
  3. 開啟同步模式
  4. 放一輛特斯拉的車到上面

自動模式開啟

因為簡單起見,就不在進行專門的規則或者走carla 的behaviour agent了,直接用traffic manager裡面的進行設定為自動駕駛模式,更多設定見官方文件,比如下面列舉了:忽略紅綠燈和限速

# 設定traffic manager
tm = client.get_trafficmanager(args.tm_port)
tm.set_synchronous_mode(True)
# 是否忽略紅綠燈
# tm.ignore_lights_percentage(ego_vehicle, 100)
# 如果限速30km/h -> 30*(1-10%)=27km/h
tm.global_percentage_speed_difference(10.0)
ego_vehicle.set_autopilot(True, tm.get_port())

其中需要著重注意的是 因為前面設了同步 traffic manager也需要設為同步,同時銷燬的時候要設定回來,剛剛寫教程的時候 半天沒找到bug 只看見車不動;前者是幫同學找問題的時候發現如果一個指令碼設了同步 traffic manager不設同步 CARLA 整體npc會卡卡的


不設同步模式在沒那麼好的GPU上就會出現一卡一卡的現象 如下兩幅動圖對比,那麼就會導致感測器收到的資料有丟幀現象,沒錯那篇時間博文裡的插圖,很久之前我畫的(第二幅 很明顯有卡幀和丟幀情況出現):

https://i.iter01.com/images/9de5ab8e29bae74569a8b33a04dabf24a838f8dc0f7df3466369f3e172306d34.gif

https://i.iter01.com/images/e7fbde0fd308e57f5c66fe0aff238bdcb5ad5591ba0e62b5b7a3c05ebcd85330.gif

1. 佈置感測器

此處我們參考carla內部的示例,此處感謝李同學的提示 hhh 一開始打算直接暴力一點,想著都同步了 應該無需走queue了 不過還是frame保險起見比較好:

#-------------------------- 進入感測器部分 --------------------------#
sensor_queue = Queue()
cam_bp = blueprint_library.find('sensor.camera.rgb')
lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
imu_bp = blueprint_library.find('sensor.other.imu')
gnss_bp = blueprint_library.find('sensor.other.gnss')

# 可以設定一些引數 set the attribute of camera
cam_bp.set_attribute("image_size_x", "{}".format(IM_WIDTH))
cam_bp.set_attribute("image_size_y", "{}".format(IM_HEIGHT))
cam_bp.set_attribute("fov", "60")
# cam_bp.set_attribute('sensor_tick', '0.1')

cam01 = world.spawn_actor(cam_bp, carla.Transform(carla.Location(z=args.sensor_h),carla.Rotation(yaw=0)), attach_to=ego_vehicle)
cam01.listen(lambda data: sensor_callback(data, sensor_queue, "rgb_front"))
sensor_list.append(cam01)

cam02 = world.spawn_actor(cam_bp, carla.Transform(carla.Location(z=args.sensor_h),carla.Rotation(yaw=60)), attach_to=ego_vehicle)
cam02.listen(lambda data: sensor_callback(data, sensor_queue, "rgb_left"))
sensor_list.append(cam02)

lidar_bp.set_attribute('channels', '64')
lidar_bp.set_attribute('points_per_second', '200000')
lidar_bp.set_attribute('range', '32')
lidar_bp.set_attribute('rotation_frequency', str(int(1/settings.fixed_delta_seconds))) #

lidar01 = world.spawn_actor(lidar_bp, carla.Transform(carla.Location(z=args.sensor_h)), attach_to=ego_vehicle)
lidar01.listen(lambda data: sensor_callback(data, sensor_queue, "lidar"))
sensor_list.append(lidar01)

imu01 = world.spawn_actor(imu_bp, carla.Transform(carla.Location(z=args.sensor_h)), attach_to=ego_vehicle)
imu01.listen(lambda data: sensor_callback(data, sensor_queue, "imu"))
sensor_list.append(imu01)

gnss01 = world.spawn_actor(gnss_bp, carla.Transform(carla.Location(z=args.sensor_h)), attach_to=ego_vehicle)
gnss01.listen(lambda data: sensor_callback(data, sensor_queue, "gnss"))
sensor_list.append(gnss01)
#-------------------------- 感測器設定完畢 --------------------------#

以上主要是:

  1. 到庫裡去找到這樣一個感測器
  2. 對感測器進行一些設定,比如相機的FOV,鐳射雷達的通道數
  3. 然後把感測器放到車上!所以有個attch到自己車上哈

主要需要注意的是鐳射雷達的設定:

  1. points_per_second 越多 點越密集,同時和雷達通道數有關哈(可選我記得是:32、64、128)

  2. 一定要注意rotation_frequency 是自己fixed_delta_seconds 的頻率 不然就會出現 只收了半面,比如這幅圖:

    【模擬】Carla之收集資料快速教程 (附完整程式碼) [7]

2. 收集資料

主要參考carla官方示例裡的sensor_synchronization.py,以下為while迴圈內擷取

while True:
    # Tick the server
    world.tick()

    # 將CARLA介面攝像頭跟隨車動
    loc = ego_vehicle.get_transform().location
    spectator.set_transform(carla.Transform(carla.Location(x=loc.x,y=loc.y,z=35),carla.Rotation(yaw=0,pitch=-90,roll=0)))

    w_frame = world.get_snapshot().frame
    print("\nWorld's frame: %d" % w_frame)
    try:
        rgbs = []

        for i in range (0, len(sensor_list)):
            s_frame, s_name, s_data = sensor_queue.get(True, 1.0)
            print("    Frame: %d   Sensor: %s" % (s_frame, s_name))
            sensor_type = s_name.split('_')[0]
            if sensor_type == 'rgb':
                rgbs.append(_parse_image_cb(s_data))
            elif sensor_type == 'lidar':
                lidar = _parse_lidar_cb(s_data)
            elif sensor_type == 'imu':
                imu_yaw = s_data.compass
            elif sensor_type == 'gnss':
                gnss = s_data
        
        # 僅用來視覺化 可註釋
        rgb=np.concatenate(rgbs, axis=1)[...,:3]
        cv2.imshow('vizs', visualize_data(rgb, lidar, imu_yaw, gnss))
        cv2.waitKey(100)
    except Empty:
        print("    Some of the sensor information is missed")

def sensor_callback(sensor_data, sensor_queue, sensor_name):
    # Do stuff with the sensor_data data like save it to disk
    # Then you just need to add to the queue
    sensor_queue.put((sensor_data.frame, sensor_name, sensor_data))

至此完成了收集資料部分,同時執行完整程式碼即可見如下動態所示:

3. 儲存資料

這個就是對應的save一下就行,展示效果如下:

【模擬】Carla之收集資料快速教程 (附完整程式碼) [7]
if rgb is None or args.save_path is not None:
	  # 檢查是否有各自感測器的資料夾
	  mkdir_folder(args.save_path)
	
	  filename = args.save_path +'rgb/'+str(w_frame)+'.png'
	  cv2.imwrite(filename, np.array(rgb[...,::-1]))
	  filename = args.save_path +'lidar/'+str(w_frame)+'.npy'
	  np.save(filename, lidar)

對於點雲如果要有啥其他操作 推薦使用open3d進行,比如:

import numpy as np
import open3d as o3d
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(np.load('217.npy')[:,:3])
o3d.visualization.draw_geometries([pcd])
【模擬】Carla之收集資料快速教程 (附完整程式碼) [7]

總結

以上主要簡單實現了一下CARLA內部簡易版資料收集指令碼,語重心長版:

  1. 要知道自己用CARLA的目的是什麼
  2. 多看官方文件,很多API 官方解釋的很到位
  3. 多看官方示例,很多都是寶藏 hhh

另外完整程式碼在:gitee 外鏈

相關文章