创立了世界之后,就要开始安放我们的主角 actor
了。Actor
翻译为演员,在仿真世界里则代表可以移动的物体,包括交通标志、交通信号灯、视角、汽车,传感器(因为传感器要安在车身上)以及行人。
要创建 Actor
,首先需要提供要创建的 Actor
的类型,不同的类型会有不同的属性,比如一台车,它可以是不同的型号,可以是不同的颜色, 外观不同,可以通过油门和方向盘来控制,而如果是一个传感器,它可能都没有这些任何一个属性,因此创建一个 Actor
需要知道这些信息,也就是类似于需要使用一个模板,这个东西在 Carla
中叫做蓝图,即 Blueprints
,Carla
中已经内置了一个蓝图库,里边包含了许多不同的 Actors
。
这些布局允许用户将新的 Actor
顺利加入仿真。 它们是带有动画和一系列属性的已制作模型。 其中一些是可修改的,而另一些则不能。 这些属性包括车辆颜色、激光雷达传感器中的通道数量、步行者的速度等等。
carla.BlueprintLibrary
类包含一个 carla.ActorBlueprint
元素列表。 world
对象可以提供对它的访问。
# 拿到这个世界所有物体的蓝图
blueprint_library = world.get_blueprint_library()
blueprint
有一个 ID
来识别它们以及由此产生的 Actor
。 可以读取该库以查找特定 ID
、随机选择 blueprint
或使用通配符模式过滤结果。
# 从浩瀚如海的蓝图中找到奔驰的蓝图
ego_vehicle_bp = blueprint_library.find('vehicle.mercedes-benz.coupe')
# 给我们的车加上特定的颜色
ego_vehicle_bp.set_attribute('color', '0, 0, 0')
# 找到一个碰撞蓝图
collision_sensor_bp = blueprint_library.find('sensor.other.collision')
# Choose a vehicle blueprint at random.
# 使用 `filter` 方法然后给定模糊匹配的方法获取到多个蓝图
vehicle_bp = random.choice(blueprint_library.filter('vehicle.*.*'))
在
find
里找到添加的东西,建议打开网页然后CTRL+F
,然后搜索关键字,比如:
- 如果想添加的是传感器,那么一般以
sensor
开头,sensor.sensor_type
(传感器.传感器类型)sensor.lidar.ray_cast
就是激光雷达,sensor.other.collision
就是碰撞检测的- 如果是车呢,一般就是
vehicle
开头,vehicle.audi.a2
就是奥迪A2的车型
除此之外,每个 carla.ActorBlueprint
都有一系列 carla.ActorAttribute
可以 get
和 set
。
is_bike = [vehicle.get_attribute('number_of_wheels') == 2]
if(is_bike):
vehicle.set_attribute('color', '255,0,0')
有些属性不能修改。在 蓝图库 中查看一下。
属性有一个 carla.ActorAttributeType
变量。 它从枚举列表中声明其类型。 此外,可修改属性带有推荐值列表。
for attr in blueprint:
if attr.is_modifiable:
blueprint.set_attribute(attr.id, random.choice(attr.recommended_values))
一个 Actor
可以被生成(Spawning
),使用(Handling
),以及销毁(Destruction
)。
生成
:有了蓝图之后,意味着我们有了模板,然后就需要使用这个模板生成一个或者多个演员(Actor
),这一过程叫做 Spawning
,因为 Actor
是在世界中存在的一个物体,因此在生成的时候,需要告诉环境它的出生点在哪里。使用
:当 Actor
生成以后,就可以通过客户端来控制它的一些行为,比如可以让车子跑起来,并控制它的油门和转向。销毁
:当我们不在需要一个 Actor
的时候可以选择销毁它,这样可以释放仿真环境的资源,让环境运行更顺畅。构建好蓝图以后,下一步便是选定它的出生点。不过上边提到,在生成 Actor
的时候,需要告诉世界它的出生点在哪里,出生点在 Carla
中抽象为 carla.Transform
。
world
对象负责生成 actors
并跟踪它们,生成 actors
只需要一个 blueprint
和一个 carla.Transform
,说明 actor
的位置和旋转角。
world
有两种不同的方法来产生 Actors
:
spawn_actor()
如果生成失败会引发异常。try_spawn_actor()
如果生成失败将返回 None
。比如,我们可以用下边这段代码,指定将 Actor
生成到某一个地点。
transform = Transform(Location(x=230, y=195, z=40), Rotation(yaw=180))
actor = world.spawn_actor(blueprint, transform)
CARLA uses the Unreal Engine coordinates system. Remember that carla.Rotation constructor is defined as (pitch, yaw, roll), that differs from Unreal Engine Editor (roll, pitch, yaw).
或者赋予随机的位置,不过这个位置必须是空的位置,因为物体在世界中是有体积的,所以有可能你指定的地点上已经有其他物体了,比如,该位置已经有台车子,或者该位置是一个建筑物,这种情况下,Actor
被生成的时候就会出现碰撞,为了避免这个问题,Carla
提供了一个接口可以获取到所有空的出生点,只要在这些空的出生点上生成 Actor
就不会出现碰撞的问题了。
如果在指定位置发生碰撞,actor
将不会生成。 无论这发生在静态对象还是其他 Actor
身上。 可以尝试避免这些不希望的产碰撞产生。
map.get_spawn_points()
对于车辆,返回推荐的生成点列表spawn_points = world.get_map().get_spawn_points()
transform = np.random.choice(spawn_points)
ego_vehicle = world.spawn_actor(ego_vehicle_bp, transform )
world.get_random_location()
对于步行者。 返回人行道上的随机点。 同样的方法用于为步行者设置目标位置。spawn_point = carla.Transform()
spawn_point.location = world.get_random_location_from_navigation()
一个 actor
在生成时可以附加到另一个 actor
上。 Actor
跟随他们所依附的 Actor
。 这对传感器特别有用。 附件可以是刚性的(适合检索精确数据),也可以根据其父项轻松移动。 它由助手类 carla.AttachmentType
定义。
将摄像头固定在车辆上,因此它们的相对位置保持固定。
camera = world.spawn_actor(camera_bp, relative_transform,
attach_to=my_vehicle, carla.AttachmentType.Rigid)
注意:When spawning attached actors, the transform provided must be relative to the parent actor.
生成后,world
对象会将 Actor
添加到列表中。 这可以很容易地搜索或迭代。
actor_list = world.get_actors()
# Find an actor by id.
actor = actor_list.find(id)
# Print the location of all the speed limit signs in the world.
for speed_sign in actor_list.filter('traffic.speed_limit.*'):
print(speed_sign.get_location())
当 Actor
被生成以后,生成方法会返回被生成的 Actor
对象,我们可以使用该对象控制 Actor
的行为。比如,我们可以随意挪动它的初始位置,定义它的动态参数等等,根据不同的 Actor
类型,可以控制的参数也不一样。
carla.Actor
主要由 get()
和 set()
方法组成,用于管理地图周围的 Actor
。
print(actor.get_acceleration())
print(actor.get_velocity())
location = actor.get_location()
location.z += 10.0
actor.set_location(location)
可以禁用演员的物理特性以将其冻结在适当的位置。
# 我们可以甚至在中途将这辆车“冻住”,通过抹杀它的物理仿真
actor.set_simulate_physics(False)
除此之外,Actor
也有他们的 blueprint
蓝图提供的标签。 这些对语义分割传感器最有用。
大多数方法都以异步方式向仿真器发送请求。每次更新时,仿真器解析它们的时间有限。用 set()
方法充斥仿真器会积累大量的延迟。
当 Python
脚本完成时,Actor
不会被自动销毁。 必须明确地摧毁自己。
destroyed = actor.destroy() # Returns True if successful
最后如果我们不需要生成的 actor
之后,我们可以用代码把原来生成的车辆关闭,语句如下:
finally:
for actor in actor_list:
actor.destroy()
销毁一个 actor
将阻塞仿真器,直到进程完成。
command
有一些最常见的 CARLA
方法的适配,也可以批量应用。例如,命令 SetAutopilot
等同于vehicle.set_autopilot()
,启用车辆的自动驾驶。也可以使用批量的 Client
方法。
# 如果你有多个 Actor 存在 list 里,可以一起销毁。
client.apply_batch([carla.command.DestroyActor(x) for x in actor_list])
当执行多个脚本文件的时候,服务器是不会自动清理掉上一个脚本生成的 actor
的,所以需要手动清除。