我们将创造一辆奔驰自动驾驶汽车,在空荡的城市里穿梭,并且将车载相机与激光雷达接受的数据存储到硬盘中。
在我们开始运行 python script 之前,记得先开启 CarlaUE4

命令行提示符
cd Unreal/CarlaUE4
~/UnrealEngine_4.XX/Engine/Binaries/Linux/UE4Editor "$PWD/CarlaUE4.uproject"

#Carla Library 安装到你的 python3

我们之前虽然已经 make 好了 CarlaPythonAPI , 但是并没有将它的库安装到我们默认的 python3 里,如果你查看 carla 自带的 example , 会发现都要先进行以下操作:

import glob
import os
import sys
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

每次这样操作既不美观,还容易搞错路径,所以我们需要先搞以下几步,从此一劳永逸:

命令行提示符
cd ~/carla/PythonAPI/carla/dist/
unzip carla-0.9.10-py3.6-linux-x86_64.egg -d carla-0.9.10-py3.6-linux-x86_64
cd carla-0.9.10-py3.6-linux-x86_64

接下来打开你的文档编辑器,建立一个 setup.py , 将以下内容复制进去。

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

然后通过 pip 安装到你的 python3 当中,从此可以直接 import carla 了。

命令行提示符
pip3 install -e ~/carla/PythonAPI/carla/dist/carla-0.9.10-py3.6-linux-x86_64

# ClientWorld

Client 我们在第一节提到过,用户通过 Client 载体与 python API 与仿真环境交互,所以我们第一部就是要创建 Client ,并且设置一个 timeout 时间防止连接时间过久。

client = carla.Client('localhost', 2000)
client.set_timeout(2.0)

其中 2000 是端口,2.0 是秒数。接下来我们就要通过这个构建的 Client 来获取仿真世界( World )。我们如果想让仿真世界有任何变化,都要对这个获取的 world 进行操作。

world = client.get_world()

作为一个简单明了的示例,我们可以先试着改变一下世界的天气。

weather = carla.WeatherParameters(cloudiness=10.0,
                                  precipitation=10.0,
                                  fog_density=10.0)
world.set_weather(weather)

# ActorBlueprint

创立了世界之后,就要开始安放我们的主角 —— actor 了。顾名思义, Actor 意味演员,在仿真世界里则代表可以移动的物体,包括汽车,传感器(因为传感器要安在车身上)以及行人。

# 生成spawn Actor

如果我们想生成一个 Actor , 必须要先定义它的蓝图Blueprint,这就好比造房子前要先话设计图一样。

# 拿到这个世界所有物体的蓝图
blueprint_library = world.get_blueprint_library()
# 从浩瀚如海的蓝图中找到奔驰的蓝图
ego_vehicle_bp = blueprint_library.find('vehicle.mercedes-benz.coupe')
# 给我们的车加上特定的颜色
ego_vehicle_bp.set_attribute('color', '0, 0, 0')

构建好蓝图以后,下一步便是选定它的出生点。我们可以给固定的位子,也可以赋予随机的位置,不过这个位置必须是空的位置,比如你不能将奔驰扔在一棵树上。

# 找到所有可以作为初始点的位置并随机选择一个
transform = random.choice(world.get_map().get_spawn_points())
# 在这个位置生成汽车
ego_vehicle = world.spawn_actor(ego_vehicle_bp, transform)

# 操纵Handling Actor

汽车生成以后,我们便可以随意挪动它的初始位置,定义它的动态参数。

# 再给它挪挪窝
location = ego_vehicle.get_location()
location.x += 10.0
ego_vehicle.set_location(location)
# 把它设置成自动驾驶模式
ego_vehicle.set_autopilot(True)
# 我们可以甚至在中途将这辆车 “冻住”,通过抹杀它的物理仿真
# actor.set_simulate_physics(False)

# 注销Destroy Actor

当这个脚本运行完后要记得将这个汽车销毁掉,否则它会一直存在于仿真世界,可能影响其他脚本的运行哦。

# 如果注销单个 Actor
ego_vehicle.destroy()
# 如果你有多个 Actor 存在 list 里,想一起销毁。
client.apply_batch([carla.command.DestroyActor(x) for x in actor_list])

# Sensor 搭建

有了车子之后,我们就可以往上放各种各样的 sensor 啦!在这里先简单介绍下 Carla 有哪些 Sensors , 有了车子之后,我们就可以往上放各种各样的 sensor 啦!在这里先简单介绍下 Carla 有哪些 Sensors , 在 https://carla.readthedocs.io/en/latest/python_api/ 里有对每一种数据格式类别的详细介绍。

Sensor Sensor 输出数据形式 功能 类别
RGB Camera carla.Image 普通的 RGB 相机 Cameras
深度相机 carla.Image 深度相机,以灰度图形式储存 Cameras
分割相机 carla.Image 直接输出景物分割图,不同颜色代表不同的种类 Cameras
Collision carla.CollisionEvent 汽车发生碰撞时启动,会将事故的信息记录下来 Detector
Lane invasion carla.LaneInvasionEvent 汽车变道时启动,将 Lane ID 与汽车 ID 记录下来 Detector
Obstacle carla.ObstacleDetectionEvent 将可能挡在前方行驶道路上的物体记下 Detector
GNSS carla.GNSSMeasurement 记录车子的地理位置 Other
IMU carla.IMUMeasurement 记录汽车的轴加速度与角加速度 Other
LIDAR carla.LidarMeasurement 激光雷达 Other
Radar carla.RadarMeasurement 声波雷达 Other
Semantic LIDAR carla.SemanticLidarMeasurement 除了 3D 点云外,还提供额外的 Semantic 信息 Other

在这个教程里,我们会建立 Camera 与激光雷达。

# Camera 构建

与汽车类似,我们先创建蓝图,再定义位置,然后再选择我们想要的汽车安装上去。不过,这里的位置都是相对汽车中心点的位置(以米计量)。

camera_bp = blueprint_library.find('sensor.camera.rgb')
camera_transform = carla.Transform(carla.Location(x=1.5, z=2.4))
camera = world.spawn_actor(camera_bp, camera_transform, attach_to=ego_vehicle)

我们还要对相机定义它的 callback function , 定义每次仿真世界里传感器数据传回来后,我们要对它进行什么样的处理。在这个教程里我们只需要简单地将文件存在硬盘里。

camera.listen(lambda image: image.save_to_disk(os.path.join(output_path, '%06d.png' % image.frame)))

# Lidar 构建

Lidar 可以设置的参数比较多,对 Lidar 模型不熟也没有关系,我在后面会另开文章详细介绍激光雷达模型,现在就知道我们设置了一些常用参数就好。

lidar_bp = blueprint_library.find('sensor.lidar.ray_cast')
lidar_bp.set_attribute('channels', str(32))
lidar_bp.set_attribute('points_per_second', str(90000))
lidar_bp.set_attribute('rotation_frequency', str(40))
lidar_bp.set_attribute('range', str(20))

接着把 lidar 放置在奔驰上,定义它的 callback function .

lidar_location = carla.Location(0, 0, 2)
lidar_rotation = carla.Rotation(0, 0, 0)
lidar_transform = carla.Transform(lidar_location, lidar_rotation)
lidar = world.spawn_actor(lidar_bp, lidar_transform, attach_to=ego_vehicle)
lidar.listen(lambda point_cloud: \
            point_cloud.save_to_disk(os.path.join(output_path, '%06d.ply' % point_cloud.frame)))

# 观察者spectator放置

当我们去观察仿真界面时,我们会发现,自己的视野并不会随我们造的小车子移动,所以经常会跟丢它。解决这个问题的办法就是把 spectator 对准汽车,这样小汽车就永远在我们的视野里了!

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

放置观察者后效果如下,我们将以俯视的角度观察它的运行:

# 查看储存的照片与 3D 点云

储存的 RGB 相机图如下:

查看点云图需要另外安装 meshlab , 然后进入 meshlab 后选择 import mesh

命令行提示符
sudo apt-get update -y
sudo apt-get install -y meshlab
meshlab