对于CARLA模拟器来说,这是一段漫长的旅程。该团队于2016年底开始了这一冒险活动,旨在将最先进的自动驾驶模拟器带入开源社区。我们的目标很明确:通过可访问的模拟使自动驾驶民主化,并创建一个平台,使学者和行业成员可以共享知识和结果公开。2017年11月,我们首次公开发行了CARLA。当时,该平台是一个谦虚的模拟器,围绕基于摄像机的策略学习和数据获取任务的用例构建。一个很好的起点,但还不够。因此,我们决定完全重新设计平台,以生产出更先进,更灵活的自动驾驶模拟器,并牢记以下目标:
- 用户必须能够以简单的方式创建新的内容(即地图,关卡)
- 用户必须能够创建复杂的交通场景(又名交通状况)
- 用户必须能够利用自动驾驶中使用的任何现有传感器
- 用户必须能够自动培训和评估他们的驾驶人员(驾驶人员)
- 该平台必须是可扩展的,即计算在不同节点之间分布
我们在过去的10个月中致力于重新设计平台以实现这些目标。0.9.0版本是此工作的初步展示,其中引入了新的CARLA API,多客户端体系结构以及可以随意控制所有仿真车辆的功能。
在此0.9.1版本中,我们添加了关键功能,以启用使用外部工具制作的新内容(地图)的摄取,以及使用基于航点和地图查询的新API轻松导航这些地图。为此,我们采用了OpenDrive作为CARLA道路网络格式的核心。我们的地图表示基于OpenDrive构建,从而提供了易于使用的通用导航API。我们还介绍了Town03,这是一个复杂的城市场景,具有多车道的道路,隧道,环形交叉路口和许多其他有趣的功能,以外部工具半自动生成的地图为例。
现在,让我们深入了解此版本的新功能,请注意,这仍然是开发版本!
驾驶模拟消息
服务器在0.8.X分支中生成的所有驾驶消息都已作为CARLA 0.9.1的传感器合并回去。这使客户能够检测到碰撞并确定车道变化。新的可以检测到与场景的静态布局和动态对象(如车辆)的碰撞sensor.other.collision
。
class CollisionSensor(object):
"""
Encapsulate sensor.other.collision messages
"""
def __init__(self, parent_actor):
self._parent = parent_actor
self._history = collections.defaultdict(int)
bp = world.get_blueprint_library().find('sensor.other.collision')
self._sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
# We need to pass the lambda a weak reference to self to avoid circular
# reference.
weak_self = weakref.ref(self)
self.sensor.listen(lambda event: CollisionSensor._on_collision(weak_self, event))
@staticmethod
def _on_collision(weak_self, event):
self = weak_self()
if not self:
return
actor_type = ' '.join(event.other_actor.type_id.replace('_', '.').title().split('.')[1:])
self._hud.notification('Collision with %r' % actor_type)
impulse = event.normal_impulse
intensity = math.sqrt(impulse.x**2 + impulse.y**2 + impulse.z**2)
self._history.append((event.frame_number, intensity))
...
在这个例子中,我们将接收的消息的每个所述时间parent_actor
(车辆)崩溃针对场景的其它演员,说明其类型和大小的影响。该传感器还报告与地图的静态元素(例如交通标志,墙壁,交通信号灯,人行道等)的碰撞。
sensor.other.lane_detector
现在可以使用新的传感器来检测车道变化。新的CARLA地图更加复杂,包含多车道的道路。在这种情况下,重要的是要检测车辆何时改变车道,确定车辆已越过哪种类型的车道标记以及目标车道的方向是什么。请参见下面的代码示例:
class LaneInvasionSensor(object):
def __init__(self, parent_actor, hud):
self.sensor = None
self._parent = parent_actor
self._hud = hud
world = self._parent.get_world()
bp = world.get_blueprint_library().find('sensor.other.lane_detector')
self.sensor = world.spawn_actor(bp, carla.Transform(), attach_to=self._parent)
# We need to pass the lambda a weak reference to self to avoid circular
# reference.
weak_self = weakref.ref(self)
self.sensor.listen(lambda event: LaneInvasionSensor._on_invasion(weak_self, event))
@staticmethod
def _on_invasion(weak_self, event):
self = weak_self()
if not self:
return
text = ['%r' % str(x).split()[-1] for x in set(event.crossed_lane_markings)]
self._hud.notification('Crossed line %s' % ' and '.join(text))
地图和航点表示
现在可以通过Map类访问公路网的高级表示。借助地图对象,我们可以获取建议的车辆生成点(可以安全地实例化新对象的地方):
map.get_spawn_points()
通过新的航点查询API,这也使从客户端驱动变得非常容易。在下面的代码中,我们获得与角色的当前位置关联的航路点。
w = map.get_waypoint(location)
用户还可以生成指定距离内的航路点:
map.generate_waypoints(distance)
总体而言,用户可以利用这些新功能来创建自己的导航算法:
client = carla.Client(args.host, args.port)
client.set_timeout(2.0)
hud = HUD(args.width, args.height)
world = World(client.get_world(), hud)
world.vehicle.set_simulate_physics(False)
m = world.world.get_map()
w = m.get_waypoint(world.vehicle.get_location())
clock = pygame.time.Clock()
count = 0
while True:
clock.tick_busy_loop(60)
world.tick(clock)
world.render(display)
pygame.display.flip()
if count % 10 == 0:
nexts = list(w.next(1.0))
print('Next(1.0) --> %d waypoints' % len(nexts))
if not nexts:
raise RuntimeError("No more waypoints!")
w = random.choice(nexts)
text = "road id = %d, lane id = %d, transform = %s"
print(text % (w.road_id, w.lane_id, w.transform))
if count % 40 == 0:
draw_waypoints(world.world, w)
count = 0
t = w.transform
world.vehicle.set_transform(t)
count += 1
图1.使用新的Waypoint类即时生成的航点
用于半自动地图生成的管道
此版本最令人兴奋的功能之一就是与使用外部工具创建的新地图的兼容性。我们希望用户在CARLA中轻松创建自己的地图。为此,我们采用了OpenDrive作为我们的地图定义标准。使用众所周知的标准可减少创建与CARLA模拟器兼容的新内容所需的工作。
我们一直与VectorZero紧密合作,以确保RoadRunner和CARLA之间的完全兼容性。凭借强大的程序生成引擎,RoadRunner是一种只需单击几下即可生成复杂驾驶地图的工具。最好的是,它还会生成与3D地图关联的OpenDrive文件,因此RoadRunner生成的地图可以直接在CARLA中使用,并具有当前城镇可用的所有功能。
VectorZero已承诺向要求它的学者免费授予将RoadRunner用于学术和研究目的的许可。因此,请访问他们的网站以获得许可证并开始构建自己的地图!
图2. RoadRunner场景示例
缺少的东西
- 全同步模式
- 模拟行人
- 功能齐全的ROS桥
这些功能将很快添加。我们将在以后的版本中继续改进此API。如果您发现任何问题或可以添加的建议,请随时在我们的GitHub或 Discord chat上与社区共享。有关可用方法的完整列表,请参阅《Python API参考》。
非常感谢我们所有的支持者和赞助者使这个项目成为现实。祝1年快乐CARLA!
完整变更清单
- 使用VectorZero的RoadRunner生成的New Town03
- Python API增强功能
- 支持Python 3
- 支持检索和更改照明和天气状况
- 激光雷达传感器支持
- 图像转换器方法支持:Depth,LogarithmicDepth和CityScapesPalette
- IO方法支持传感器数据,“ save_to_disk”可用于PNG,JPEG,TIFF和PLY
- 添加了碰撞事件传感器“ sensor.other.collision”,该碰撞事件在每次碰撞时触发一个回调,该碰撞会附加到该actor
- 添加了车道检测器传感器“ sensor.other.lane_detector”,用于检测车道入侵事件
- 添加了
carla.Map
和carla.Waypoint
类用于查询有关道路布局的信息- 添加了将地图转换和保存为OpenDrive格式的方法
- 已添加
map.get_spawn_points()
以检索建议的车辆生成点 - 添加
map.get_waypoint(location)
查询最近的航路点 - 已添加
map.generate_waypoints(distance)
以在整个地图上以近似距离生成航点 - 添加
map.get_topology()
用于获取包含定义路线图边缘的航点元组的列表 - 已添加
waypoint.next(distance)
以检索从给定航路点可以到达的特定距离处的航路点列表
- 为车辆添加了边界框属性,
vehicle.bounding_box
-
parent
为角色添加了属性,如果角色附加到另一个角色,则没有属性 - 添加了启用/禁用演员物理模拟的功能,
actor.set_simulate_physics(enabled=True)
- 增加了对请求当前世界上所有活着的演员名单的支持,
world.get_actors()
-
world.get_actors()
返回ActorList
具有filter
功能和参与者的延迟初始化的对象 - 已添加
semantic_tags
到包含其所有组件标签列表的actor(这些标签与语义分割传感器检索到的标签匹配) - 暴露于车辆的最后控制权,
vehicle.get_vehicle_control()
- 添加了一个“滴答”消息,其中包含场景中所有演员的信息
- 在后台执行并缓存
- 添加
world.wait_for_tick()
用于阻止当前线程,直到收到“滴答”消息 -
world.on_tick(callback)
每次接收“滴答”消息时添加的异步执行回调函数。这些方法返回/传递一个carla.Timestamp
包含以下内容的对象:帧计数,上次滴答的增量时间,全局模拟时间和OS时间戳 - 检索参与者信息的方法,例如
actor.get_transform()
,不需要与模拟器连接,这使得这些调用相当便宜
- 允许从Python绘制调试形状:点,线,箭头,框和字符串(
world.debug.draw_*
) - 已将ID(当前剧集的ID)和地图名称添加到
carla.World
- 暴露的交通信号灯和交通标志作为参与者。红绿灯具有专门的actor类,可将红绿灯状态(红色,绿色,黄色)作为属性公开
- 添加了访问和修改
carla.Image
(像素)和carla.LidarMeasurement
(位置)中单个项目的方法 - 新增
carla.Vector3D
的(X,Y,Z)的对象是不是carla.Location
- 删除
client.ping()
并添加client.get_server_version()
,实现相同的目的 - 将
contains_X()
方法重命名为has_X()
- 将超时更改为使用秒(浮动)
- 允许迭代Actor蓝图的属性
- 修复了通配符过滤问题,现在称为“车辆”。”或“ bmw *”模式也可以使用!
- 修复
actor.set_transform()
了附属演员的损坏
- 更多Python示例脚本并改进了当前示例
- 现在,所有脚本都使用每个地图的建议生成点列表
- 将“ example.py”重命名为“ tutorial.py”,并使用API中的最新更改进行了更新
- 在示例中添加了超时
- “ manual_control.py”性能得到了改进,同时具有更多的度量
- “ manual_control.py”现在具有更改相机类型和位置的选项
- “ manual_control.py”现在具有迭代天气预设的选项
- “ manual_control.py”现在具有更精美的HUD,其中包含大量信息,并通过F1键绑定将其删除
- 添加了“ dynamic_weather.py”以实时更改天气(视频中使用的天气)
- 添加了“ spawn_npc.py”以将大量NPC车辆快速添加到模拟器中
- 添加了“ spawn_npc.py –safe”以仅添加非问题车辆
- “ vehicle_gallery.py”也有一些小问题
- 资产和内容改进
- 改善了对自行车和摩托车的控制,虽然还不完善,但事故较少
- 调整了树叶的最大距离剔除
- 调整了行人动画和缩放问题(尽管新API尚不提供)
- 调整后的车辆物理和质心
- 在Windows上打包项目时修复文件名过长
- 修复了“ SplineMeshRepeater”有时会丢失其对撞机网格的问题
- 基于OpenDrive格式的道路信息新系统
- 添加了新的地图类,用于查询有关道路布局和拓扑的信息
- 添加了在道路上查找最接近点的方法
- 添加了根据道路布局生成和迭代航点的方法
- 添加了OpenDrive解析器,可将OpenDrive文件转换为我们的地图数据结构
- 其他杂项改进和修复
- 修复了单通道激光雷达崩溃(通过@cwecht)
- 固定的命令行参数
-carla-settings
无法加载绝对路径(通过@harlowja) - 在启动模拟器时,在命令行中添加了更改质量级别的选项,
-quality-level=Low
- 添加了ROS桥测距消息(通过@ShepelIlya)
- 新的Docker教程
- 禁用纹理流,以避免在场景捕获中未加载纹理的问题
- 将场景捕获相机的灰度系数调整为2.4
- 修复了生成车辆时模拟中的泄漏对象的问题。现在当销毁一个Actor时,如果有必要,Pawn的控制器也会被销毁
- 修复了平台时间戳上的溢出。现在使用
double
- 升级@rpclib以修复客户端退出速度过快时发生的崩溃(rpclib / PR#167)
- 将“ PythonClient”移至不推荐使用的文件夹中,以避免造成混淆
- 重构传感器相关代码
- 用于传感器的新插件系统,可简化传感器的添加,在#830上的微型教程
- 传感器和串行器的编译时调度程序
- 流媒体库的改进
- 添加了多流以同时流式传输到多个客户端(由“ tick”消息使用)
- 消息尽可能重用分配的内存
- 允许退订流
- 固定客户端接收交错的传感器消息,但是如果连接速度太慢,则某些消息可以被丢弃
- 固定流客户端无法在Windows中连接
- 修复了流客户端在销毁传感器后不断尝试重新连接的问题
- 重构的客户端C ++ API
- 尽可能释放Python GIL,以避免阻塞
- 修复了在连接客户端时关闭模拟器时的死锁
- 修复了如果客户端在某个时间点已连接,则会在模拟器关闭时崩溃的问题
- 现在,异步发送Set方法,这大大提高了客户端的性能
- 车辆控制已缓存,如果未更改,则不会发送
- 析构函数中的异常抑制
- 其他发展改进
- 改进的Linux Makefile,细粒度目标可减少开发中的编译时间
- “ setup.py”再次链接到“ libcarla_client.a”的解决方法(仅Linux)
- 添加了对“ .gtest”文件的支持,该文件的每一行在运行
make check
目标时作为参数传递给GTest可执行文件 - Python鸡蛋也被存档在Jenkins上,无需下载完整软件包即可轻松获取它们
- 添加了用于格式化UE4 C ++代码的uncrustify配置文件