pythonAPI总述
LGSVL模拟器可以实时与PythonAPI进行功能通信,你可以用其来操控已加载场景中的物体的位置、车辆的运动、召回传感器配置和数据、控制天气、时间状态以及其它。
API调用的监听接口是在config.yml中定义的。可以在这里查找更多的关于配置文件和命令行参数的信息。
要求
PythonAPI需要在Python 3.5或者更新的版本中运行。
快速开始 quickstart
PythonAPI放在与模拟器不同的代码仓库:https://github.com/lgsvl/PythonAPI
从github仓库下载或者克隆后,按如下步骤运行:
1.运行如下命令来安装Python文件和必要的依赖;
pip3 install --user -e .
2.运行模拟器(从binary.exe或者从Unity编辑器),模拟器默认从8181接口监听主机的连接。
3.点击Open Browser按钮启动模拟器的交互页面。
4.在默认地图和车辆下载完成后,找到Simulation页。
5.创建一个新的模拟,为其命名并确保打开API Only选项,点击Submit。
6.选择新创建的模拟,点击右下方的Play按钮。
7.运行一下案例来查看API的动作:
./quickstart/05-ego-drive-in-circle.py
这会加载BorregasAve.unity场景,实例化一个EGO车辆,然后要求你敲击Enter键来使车辆进行环形驾驶。
当脚本运行的时候,其会将油门和方向盘指令应用到车辆中,使其产生响应的运动。
核心概念
模拟器和API之间的通讯是靠运行在8181接口上的websocket服务器发送json来实现的。API客户端可以运行在同一机器或者处在同一局域网的其它机器。
API主要有以下几个类:
- Simulator-连接至模拟器以及创建其它物体的主要对象
- Agent-车辆和行人对象的父类
- EgoVehicle-具有精确物理模拟以及传感器的EGO 车辆
- NpcVehicle-具有简化的物理特性的NPC车辆,常用作创建许多背景车辆
- Pedestrian-在人行道上行走的行人
Vehicle和Pedestrian是Agent的子类,其都有像转换、位置、速度等共同的属性。
API中的坐标返回的值是Unity坐标系中的值,其基本单位是米,且为左手坐标系,X向左,Z向前,Y向上。
模拟器类提供转换坐标系为经纬度的方法,反之亦可。
Simulation
想要连接至模拟器,你就需要一个Simulator类的实例
import lgsvl
sim = lgsvl.Simulator(address = "localhost", port = 8181)
你可以制定不同的地址作为主机名或者IP地址,默认情况下,只有8181接口用作API连接,一次只能有一台客户端连接到模拟器。
然后,加载场景(“map”),这是通过load的方法实现的:
sim.load(scene = "BorregasAve", seed = 650387)
场景是Web UI中代表地图名的字符串,目前可用的场景为:
- BorregasAVE-小的郊区地图
- AutonomousStuff-小的办公公园
Seed(可选)是一个整数(-2,147,483,648 - 2,147,483,647),它决定着NPC和雨滴效果的随机程度。
可以在Web UI Maps页面看到可用的场景列表。
一旦已经加载了场景,你可以将“行动者”实例化,并运行模拟。参照Agents部分来学习如何创建车辆和行人
加载场景需要一定的时间,可以通过reset方法重置场景来初始化状态,而不用重新加载:
sim.reset()
这会移除已经注册的任何车辆或回调函数。
在设置场景至目标状态后,你可以开始高级时间,当python代码在模拟器中的执行时间是停止的。想要模拟器在实际时间状态运行,调用run方法:
sim.run(time_limit = 5.0)
run有可选参数来制定模拟的运行时间,默认为0代表一直运行。
非实时模拟运行
模拟器可以根据计算机的性能来进行比真实时间更快的高速模拟,可以通过调用run方法的time_scalw参数:
sim.run(time_limit = 6, time_scale = 2)
run的第二个参数指定以多快的速度来运行模拟,如果计算机足够快的话,该模拟将会在3秒完成(6s/2),但是会产生6个虚拟秒时间的数据。如果只指定了time)_scale或者time_limit=0,模拟器会一直以非真实时间运行。
同理,time_scale也可以设置的比1小,这代表运行的速度比真实世界的时间慢。
Agents 行动者
你可以创建车辆和行人,通过使用add_agent方法,这是Simulator的对象。e.g.
ego = sim.add_agent(name = "Lincoln2017MKZ (Apollo 5.0)", \
agent_type = lgsvl.AgentType.EGO, state = None)
这会从Web UI Vehicle页面创建Lincoln2017MKZ (Apollo 5.0)这一车辆,其它可用的Agents类为:
- AgentType.EGO - EGO vehicle
- AgentType.NPC - NPC vehicle
- AgentType.PEDESTRIAN - pedestrian
每个agent类都预设了你可以使用的名字,目前可用的EGO车辆有: - Jaguar2015XE (Apollo 3.0) - Apollo 3.0 vehicle
- Jaguar2015XE (Apollo 5.0) - Apollo 5.0 vehicle
- Jaguar2015XE (Autoware) - Autoware vehicle
- Lexus2016RXHybrid (Autoware) - Autoware vehicle
- Lincoln2017MKZ (Apollo 5.0) - Apollo 5.0 vehicle
可用的NPC车辆有: - Sedan
- SUV
- Jeep
- Hatchback
- SchoolBus
- BoxTruck
可用的行人类有:
- Bob
- EntrepreneurFemale
- Howard
- Johny
- Pamela
- Presley
- Red
- Robin
- Stephen
- Zoe
如果输入了不正确的名字,会提示Python异常。
另外,你还可以在场景中创建处于特定位置和旋转角度的agents对象。你可以利用AgentState类,e.g.
state = lgsvl.AgentState()
state.transform.position = lgsvl.Vector(10, 0, 30)
state.transform.rotation.y = 90
ego = sim.add_agent("Lincoln2017MKZ (Apollo 5.0)", lgsvl.AgentType.EGO, state)
这会创建一个处于x=70,z=30,围绕垂直轴旋转90°的车辆,位置和旋转是处于世界坐标系中的。
当然你也可以随时调正位置、旋转、速度、角速度:
s = ego.state
s.velocity.x = -50
ego.state = s
这会使x方向每秒发生-50米的偏移,而y和z的速度则不变化。
所有的Agents都有以下共同的属性:
-
state
- 设置行动者的状态属性 -
transform
- property to gettransform
member of the state (shortcut forstate.transform
) -
bounding_box
- property to get bounding box in local coordinate space. Note that bounding box is not centered around (0,0,0) - it depends on the actual geometry of the agent. -
on_collision
- method to set a callback function to be called when the agent collides with something (other agent or static obstacle), see callbacks section for more information.
EGO vehicle
EGO 车辆有以下的额外属性:
-
apply_control
- 指定车辆油门、刹车、转向或其它动作
sticky=True
应用这些值到所有模拟器的迭代中
-
get_sensors
- 返回传感器列表 sensors -
connect_bridge
- 连接到ROS或Cyber RT的方法 -
bridge_connected
- 布尔属性,如果连接则为True
你可以通过以下几种方式控制EGO车辆的运动:手动指定状态、应用手动控制、通过bridge连接。
控制油门为20%的示例:
ego = sim.add_agent("Lincoln2017MKZ (Apollo 5.0)", lgsvl.AgentType.EGO)
c = lgsvl.VehicleControl()
c.throttle = 0.2
ego.apply_control(c, True)
NPC 车辆
你可以创建多辆NPC车辆,它们可以沿着车道线或者指定的航点进行行驶。NPC 车辆有以下属性:
change_lane
- 让车辆变道的方法
follow
- 使车辆沿着航点的方法
follow_closest_lane
- 使车辆沿着车道线行驶的方法
on_waypoint_reached
- 回调车辆到达的航点位置的方法on_stop_line
- 回调车辆到达停止位置的方法on_lane_change
- 车辆变道时的回调函数
可以通过以下方式控制NPC车辆的运动:手动指定状态、指示其沿着车道线或者航点行驶。
使车辆沿着航点行驶需要准备DriveWaypoint
对象列表,并调用folow
方法:
npc = sim.add_agent("Sedan", lgsvl.AgentType.NPC)
waypoints = [
lgsvl.DriveWaypoint(lgsvl.Vector(1,0,3), 5, lgsvl.Vector(0, 0, 0), 0, False, 0),
lgsvl.DriveWaypoint(lgsvl.Vector(5,0,3), 10, lgsvl.Vector(0, 0, 0), 0, False, 0),
lgsvl.DriveWaypoint(lgsvl.Vector(1,0,5), 5, lgsvl.Vector(0, 0, 0), 0, False, 0),
]
npc.follow(waypoints, loop=True)
每一个航点都在世界坐标系中有一个坐标信息,一个设定的速度m/s,一个设定的偏转角度,作为欧拉角的矢量,一个车辆保持空闲的设定的等待时间,以及NPC车辆在空闲状态下是否激活的布尔值,以及一个可选的激活距离。NPC车辆会无视交通规则,并且会无视碰撞驶向下一航点。NPC车辆会以在DriveWaypoint
中设置的角度,以内插的方式穿过航点。激活距离,如果使用的话,提供了一种暂停NPC车辆的方式,如果ego车辆接近的话。当NPC车辆与EGO车辆的距离低于设定的激活距离的话,NPC车辆便会开始运动。
follow_closest_lane
会使npc车辆沿着最近的线行驶,当到达十字路口时,会随机决定是直行还是转向。
Pedestrians 行人
你可以创建Pedestrian
行动着,这可以在人行道上创建行人,并使他们行走。
Pedestrian有以下属性:
walk_randomly
- 使行人在人行道随机行走方法
follow
- 使行人沿着航点行走方法
on_waypoint_reached
-
设置回调所抵达航点的回调函数方法
你可以通过以下方法控制行人的运动:手动指定状态、指示他们沿着航点行走或随机行走。
想要使行人沿着航点行走,你需要准备好一个WalkWaypoin
对象列表,并调用follow
方法:
npc = sim.add_agent("Bob", lgsvl.AgentType.PEDESTRIAN)
waypoints = [
lgsvl.WalkWaypoint(lgsvl.Vector(1,0,3), 5, 0),
lgsvl.WalkWaypoint(lgsvl.Vector(5,0,3), 10, 0),
lgsvl.WalkWaypoint(lgsvl.Vector(1,0,5), 5, 0),
]
npc.follow(waypoints, loop=True)
与npc车辆类似,你也可以设置等待时间和激活距离,当车辆到达一定距离行人才开始出现并进行运动。
回调 Callbacks
PythonAPI可以激活回调函数来提醒你在模拟运行中的特定事件。回调函数在Simulator.run
方法中激活,并且当回调函数运行时,仿真世界里的时间会暂停。一旦回调时间重新开始,仿真也开始重新执行。你可以调用Simulator.stop
来结束进一步的执行并立刻跳出回调函数。
Agent Callbacks 行动者回调函数
collision
-当行动者与其它东西发生碰撞时调用
用法示例:
def on_collision(agent1, agent2, contact):
name1 = "STATIC OBSTACLE" if agent1 is None else agent1.name
name2 = "STATIC OBSTACLE" if agent2 is None else agent2.name
print("{} collided with {} at {}".format(name1, name2, contact))
ego.on_collision(on_collision)
回调函数接受三个参数:(agent1,agent2,contact)
-前两个是发生碰撞的行动者,其中一个可以为空,例如与建筑物或交通灯杆发生碰撞时,第三个是碰撞点的世界坐标位置。
EgoVehicle Callbacks
除了Agent
类的回调函数,EgoVehicle还有另一个回调函数。
on_custon
-当传感器插件发送回调函数时调用;可以接收三个参数:(agent, kind, context)
-行动者距离,传感器插件的类型(字符串),JSON文本。
参看Sensor Plugins.
NPC Vehicle Callbacks
除了Agent
类的回调函数,NpcVehicle还有另三个回调函数。
waypoint_reached
-当车辆到达一个航点时调用;接收两个参数:(agent, index)
-行动者距离和航点索引(整数)
stop_line
-当车辆在交通灯或者通知标志的停车线停下时调用;接收一个参数:(agent)
-行动者距离
lane_change
-当车辆开始变道时调用;接收一个参数:(agent)
-行动者距离
Pesrstrian Callbacks
除了Agent
类的回调函数,Pedestrian还有另一个回调函数。
waypoint_reached
-当行人到达航点时调用;接收两个参数:(agent, index)
-行动者距离和航点索引(整数)
Sensor 传感器
EGO vehicles有绑定的传感器。你可以通过调用EgoVehicle.get_Sensors()
来获得它们的列表,它会返回一个如下类的列表:
- CameraSensor-参考Camera传感器
- LidarSensor-参考Lidar传感器
- ImuSensor-参考IMU传感器
- GpsSensor-参考GPS传感器
- RadarSensor-参考Radar传感器
- CanBusSensor-参考CAN bus传感器
每个传感器都有以下共同的属性:
-
name
-传感器的名字,用以区分同一类传感器的不同个,例如选择连接到EGO车辆的多个摄像头中的一个。 -
transform
-包含了与行动者变换相关的位置和角度信息属性
+enable
-布尔值,如果允许捕获和发送数据至ROS或Cyber,将其设为True
Camera Sensor摄像头传感器
摄像头传感器有以下只读属性:
-
frequency
-捕获和发送至ROS或Cyber图像的频率 -
width
-图像宽度 -
height
-图像高度 -
fov
-垂直视角 -
near_plane
-近面距离 -
far_plane
-远面距离 -
format
-图像格式(“RGB”代表24位真彩图,“DEPTH”代表8位灰度深度图像,“SEMANTIC”代表24位真彩分割图像)
摄像头的图像可以调用save
来保存至硬盘:
ego = sim.add_agent("Lincoln2017MKZ (Apollo 5.0)", lgsvl.AgentType.EGO)
for sensor in ego.get_sensors():
if sensor.name = "Main Camera":
sensor.save("main-camera.png", compression=0)
save
方法接收与运行中的模拟器相关的路径,可以选择compression
(0...9)来选择保存png格式的品质,选择quality
(0...100)选择jpeg格式的品质。
IMU Sensor
你可以使用IMU sensor来获得车辆的位置。所有的IMU可以提供的测量数据可以通过使用agent的transform
属性来获得。
GPS Sensor
可以通过调用data
来获得当前的gps位置信息:
data = gps_sensor.data()
print("Latitude:", data.latitude)
返回的数据会包括以下内容:
latitude
longitude
northin
easting
altitude
orientation
- 沿向上的轴旋转的角度
Radar Sensor
目前雷达传感器只能用来获取车辆的位置和偏转角度,雷达测量数据可以通过设置传感器的enable
属性来将其传递给ROS或Cyber。
CAN bus
目前CAN bus只能用来获得车辆的位置和偏转角度信息,测量数据可以通过设置传感器的enable
属性来将其传递给ROS或Cyber。
天气、时间控制
你可以通过读或写weather
属性来控制模拟器的天气属性,你可以设置rain
,fog
, witness
(浮点0...1). e.g.
w = sim.weather
w.rain = 0.5 # set rain to 50%
sim.weather = w
改变一天中的时间可以控制场景是处于白天还是夜晚。通过读取time_of_day
来获得当前时间:
print("Current time of day:", sim.time_of_day)
这会返回一个处于0-24的浮点值,可以通过调用set_time_of_day
来设置一天中的时间:
sim.set_time_of_day(10, fixed=True)
这会将时间设定在10:00am,属性fixed
的布尔值属性会调节模拟器是否自动进行时间流逝还是冻结时间(fixed=True
).
可控制的对象
可控对象是指你可以通过Python API来控制其动作的对象。每一个可控对象有其自己的valid actions
(例如绿色、红色、黄色、激发、等待、循环),可以通过control policy
来进行控制,这为控制动作制定了规则。
例如,交通灯是一个可控对象,你可以通过升级控制策略来改变其行为:
"trigger=50;green=1;yellow=1.5;red=2;loop"
-
trigger=50
-当ego车辆处于50米以内时激活 -
green=1
-改变当前状态为green
并等待1秒 -
yellow=1.5
-改变当前状态为yellow
,并等待1.5秒 -
red=2
-改变当前状态为red
并等待2秒 -
loop
-从控制测策略的开始状态进行循环
可控对象的类型: - signal
- cone
所有的可控对象可以动态的添加或移除,当reset()
被调用时,所有的可控对象被移除,新的可控对象被添加回来(如果地图中存在的话)。 可控对象可以作为插件在运行时载入。插件必须包含IControllable并且可以在Assets/Exteral/Controllables文件夹内被模拟器构建程序构建。
获得一个场景中的可控对象列表:
controllables = sim.get_controllables()
对于一个感兴趣的可控对象,你可以获得以下信息:
signal = controllables[0]
print("Type:", signal.type)
print("Transform:", signal.transform)
print("Current state:", signal.current_state)
print("Valid actions:", signal.valid_actions)
就控制策略而言,每个可控对象都有默认的控制策略(只读),当你第一次加载一个场景或重置场景为出示状态时,可控对象会将其控制策略变更为默认控制策略。
你可以通过以下方式获得默认控制策略和当前控制策略:
print("Default control policy:", signal.default_control_policy)
print("Current control policy:", signal.control_policy)
要改变当前的控制策略,你可以创建一个新的控制策略,并通过调用control
函数来使用:
control_policy = "trigger=50;green=1;yellow=1.5;red=2;loop"
signal.control(control_policy)
要添加可控插件并设置对象状态,参考如下:
state = lgsvl.ObjectState()
state.transform.position = lgsvl.Vector(0,0,0)
state.transform.rotation = lgsvl.Vector(0,0,0)
state.velocity = lgsvl.Vector(0,10,0)
state.angular_velocity = lgsvl.Vector(6.5,0,0)
cone = sim.controllable_add("TrafficCone", state)
要获得可控对象插件状态:
cone.object_state
要设置可控对象插件状态:
state = lgsvl.ObjectState()
state.transform.position = lgsvl.Vector(0, 0, -10)
cone.object_state = state
Helper Functions 帮助函数
模拟器类提供如下帮助函数:
-
version
-版本 -
current_scene
-以字符串返回当前运行场景的名称,如果未载如为None -
current_frame
-返回当前模拟的帧数(整数) -
current_time
-返回当前仿真时间,单位秒(浮点数) -
get_spawn
-返回代表地图中放置车辆的较好位置列表,这些列表可能时空的,取决于unity中地图的情况。以整数形式返回position
,rotation
。 -
get_agents
-返回包含了可以通过add_agent
添加的运动者的列表。
模拟器提供以下两种函数来在GPS坐标系中模拟Unity坐标系: -
map_to_gps
-将地图变换为GPS位置,返回用GPS Sensordata
方法一样的数据 -
map_from_gps
-将GPS信息转换成坐标系 -
raycast
-从指定位置射出一束光线,返回其接触最近的物体
map_from_gps
接受两种不同的输入- latitude/longitude 或 northing/easting
tr1 = sim.map_from_gps(latitude=10, longitude=-30)
tr2 = sim.map_from_gps(northing=123455, easting=552341)
raycast
可以以如下方式使用:
direction = lgsvl.Vector(1, 0, 0)
hit = sim.raycast(origin, direction, layer_mask=1)
if hit:
print("Distance right:", hit.distance)
这会从(10,0,20)在x轴正方向发生光束,如果接触到物体,会返回RaycastHit
对象的distance
,point
,normal
,否则会返回None
.
当你使用raycast时候需要指定layer_mask
,来指定检查“碰撞”的物体,这与unity中检测项目的实际值的层是相对应的。
Changelog
- 2020-01-30 拓展可控对象以支持插件
- 2019-09-05 拓展
DriveWaypoint
以支持角度、空闲时间和激活距离
增加了可控对象,使用Simulatoe.get_controllables
- 2019-08-12 增加
time_scale
参数来是模式器以非真实世界时间进行模拟
添加Simulatoe.load
的seed
参数,来检测NPC - 2019-04-19 最初发布
https://github.com/lgsvl/simulator/blob/master/Docs/docs/python-api.md