Added scripts for recording/replaying, and also add documentation.

This commit is contained in:
bernatx 2019-02-21 12:13:48 +01:00
parent a890649bd8
commit bf693b71bf
12 changed files with 678 additions and 11 deletions

BIN
Docs/img/accident.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 MiB

BIN
Docs/img/actor_blocked1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 284 KiB

BIN
Docs/img/actor_blocked2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

BIN
Docs/img/collision1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

@ -13,8 +13,10 @@
- `get_server_version()`
- `get_world()`
- `start_recorder(string filename)`
- `replay_file(string filename, float start=0, float duration=0)`
- `replay_file(string filename, float start, float duration, int camera_follow_id)`
- `show_recorder_file_info(string filename)`
- `show_recorder_collisions(string filename, char category1, char category2)`
- `show_recorder_actors_blocked(string filename, float min_time, float min_distance)`
## `carla.World`

View File

@ -354,3 +354,262 @@ for each road segment in the map.
Finally, to allow access to the whole road information, the map object can be
converted to OpenDrive format, and saved to disk as such.
#### Recording and Replaying system
CARLA includes now a recording and replaying API, that allows to record a simulation in a file and later replay that simulation. The file is written on server side only, and it includes which **actors are created or destroyed** in the simulation, the **state of the traffic lights** and the **position/orientation** of all vehicles and walkers.
All data is written in a binary file on the server, on folder **CarlaUE4/Saved**. As estimation, a simulation with about 150 actors (50 traffic lights, 100 vehicles) for 1h of recording takes around 200 Mb in size.
To start recording we only need to supply a file name:
```py
client.start_recorder("recording01.rec")
```
To stop the recording, we need to call:
```py
client.stop_recorder()
```
At any point we can replay a simulation, specifying the filename:
```py
client.replay_file("recording01.rec")
```
The replayer will create and destroy all actors that were recorded, and move all actors and setting the traffic lights as they were working at that moment.
When replaying we have some other options that we can use, the full API call is:
```py
client.replay_file("recording01.rec", start, duration, camera)
```
* **start**: time we want to start the simulation.
* If the value is positive, it means the number of seconds from the beginning.
Ex: a value of 10 will start the simulation at second 10.
* If the value is negative, it means the number of seconds from the end.
Ex: a value of -10 will replay only the last 10 seconds of the simulation.
* **duration**: we can say how many seconds we want to play. If the simulation has not reached the end, then all actors will have autopilot enabled automatically. The intention here is to allow for replaying a piece of a simulation and then let all actors start driving in autopilot again.
* **camera**: we can specify the Id of an actor and then the camera will follow that actor while replaying. Continue reading to know which Id has an actor.
We can know details about a recorded simulation, using this API:
```py
client.show_recorder_file_info("recording01.rec")
```
The output result is something like this:
```
Version: 1
Map: Town05
Date: 02/21/19 10:46:20
Frame 1 at 0 seconds
Create 2190: spectator (0) at (-260, -200, 382.001)
Create 2191: traffic.traffic_light (3) at (4255, 10020, 0)
Create 2192: traffic.traffic_light (3) at (4025, 7860, 0)
Create 2193: traffic.traffic_light (3) at (1860, 7975, 0)
Create 2194: traffic.traffic_light (3) at (1915, 10170, 0)
...
Create 2258: traffic.speed_limit.90 (0) at (21651.7, -1347.59, 15)
Create 2259: traffic.speed_limit.90 (0) at (5357, 21457.1, 15)
Create 2260: traffic.speed_limit.90 (0) at (858, 18176.7, 15)
Frame 2 at 0.0254253 seconds
Create 2276: vehicle.mini.cooperst (1) at (4347.63, -8409.51, 120)
number_of_wheels = 4
object_type =
color = 255,241,0
role_name = autopilot
Frame 4 at 0.0758538 seconds
Create 2277: vehicle.diamondback.century (1) at (4017.26, 14489.8, 123.86)
number_of_wheels = 2
object_type =
color = 50,96,242
role_name = autopilot
Frame 6 at 0.122666 seconds
Create 2278: vehicle.seat.leon (1) at (3508.17, 7611.85, 120.002)
number_of_wheels = 4
object_type =
color = 237,237,237
role_name = autopilot
Frame 8 at 0.171718 seconds
Create 2279: vehicle.diamondback.century (1) at (3160, 3020.07, 120.002)
number_of_wheels = 2
object_type =
color = 50,96,242
role_name = autopilot
Frame 10 at 0.219568 seconds
Create 2280: vehicle.bmw.grandtourer (1) at (-5405.99, 3489.52, 125.545)
number_of_wheels = 4
object_type =
color = 0,0,0
role_name = autopilot
Frame 2350 at 60.2805 seconds
Destroy 2276
Frame 2351 at 60.3057 seconds
Destroy 2277
Frame 2352 at 60.3293 seconds
Destroy 2278
Frame 2353 at 60.3531 seconds
Destroy 2279
Frame 2354 at 60.3753 seconds
Destroy 2280
Frames: 2354
Duration: 60.3753 seconds
```
From here we know the **date** and the **map** where the simulation was recorded.
Then for each frame that has an event (create or destroy an actor, collisions) it shows that info. For creating actors we see the **Id** it has and some info about the actor to create. This is the **id** we need to specify in the **camera** option when replaying if we want to follow that actor during the replay.
At the end we can see the **total time** of the recording and also the number of **frames** that were recorded.
In simulations whith a **hero actor** the collisions are automatically saved, so we can query a recorded file to see if any **hero actor** had collisions with some other actor. Currently the actor types we can use in the query are these:
* **h** = Hero
* **v** = Vehicle
* **w** = Walker
* **t** = Traffic light
* **o** = Other
* **a** = Any
The collision query needs to know the type of actors involved in the collision. If we don't care we can specify **a** (any) for both. These are some examples:
* **a** **a**: will show all collisions recorded
* **v** **v**: will show all collisions between vehicles
* **v** **t**: will show all collisions between a vehicle and a traffic light
* **v** **w**: will show all collisions between a vehicle and a walker
* **v** **o**: will show all collisions between a vehicle and other actor, like static meshes
* **h** **w**: will show all collisions between a hero and a walker
Currently only **hero actors** record the collisions, so first actor will be a hero always.
The API for querying the collisions is:
```py
client.show_recorder_collisions("recording01.rec", 'a', 'a')
```
The output is something similar to this:
```
Version: 1
Map: Town05
Date: 02/19/19 15:36:08
Time Types Id 1 Actor 1 Id 2 Actor 2
16 v v 122 vehicle.yamaha.yzf 118 vehicle.dodge_charger.police
27 v o 122 vehicle.yamaha.yzf 0
Frames: 790
Duration: 46 seconds
```
We can see there for each collision the **time** when happened, the **type** of the actors involved, and the **id and description** of each actor.
So, if we want to see what happened on that recording for the first collision where the hero actor was colliding with a vehicle, we could use this API:
```py
client.replay_file("col2.rec", 16, 0, 122)
```
Here a value of 0 for the **duration** is to disable that feature (it is the default value).
We can see something like this then:
![collision](img/collision1.gif)
There is another API to get information about actors that has been blocked by something and are stopped. That could be good to find incidences in the simulation. The API is:
```py
client.show_recorder_actors_blocked("recording01.rec", min_time, min_distance)
```
The parameters are:
* **min_time**: the minimum time that an actor needs to be stopped to be considered ass blocked.
* **min_distance**: the minimum distance to consider an actor to be stopped (in cm).
So, if we want to know which actor is stopped (moving less than 1 meter during 60 seconds), we could use something like:
```py
client.show_recorder_actors_blocked("col3.rec", 60, 100)
```
The result can be something like:
```
Version: 1
Map: Town05
Date: 02/19/19 15:45:01
Time Id Actor Duration
302 143 vehicle.bmw.grandtourer 67
241 162 vehicle.audi.a2 128
303 133 vehicle.nissan.micra 67
75 104 vehicle.dodge_charger.police 295
303 167 vehicle.audi.a2 66
75 214 vehicle.chevrolet.impala 295
36 173 vehicle.nissan.patrol 336
302 80 vehicle.nissan.micra 67
234 76 vehicle.nissan.micra 134
Frames: 6985
Duration: 374 seconds
```
We could check what happened with the next API command:
```py
client.replay_file("col3.rec", 302, 0, 143)
```
![actor blocked](img/actor_blocked1.png)
We see there is some mess there that actually blocks the actor (red vehicle in the image).
or we could check another incidence with:
```py
client.replay_file("col3.rec", 75, 0, 104)
```
![actor blocked](img/actor_blocked2.png)
We can see the incidence is the same but we can see it from another actor involved (police car).
If we check the list we can see that there is one vehicle that is stopped the major part, with Id 173 at time 36 seconds from the beginning it started to be stopped for 336 seconds. We could check how it arrived to that situation replaying a bit before 36 seconds.
```py
client.replay_file("col3.rec", 34, 0, 173)
```
![accident](img/accident.gif)
#### Sample PY scripts to use with the recording / replaying system
There are some scripts you could use:
* **start_recording.py**: this will start recording, and optionally you can spawn several actors and define how much time you want to record.
* -f: filename of write
* -n: vehicles to spawn
* -t: duration of the recording
* **start_replaying.py**: this will start a replay of a file. We can define the starting time, duration and also an actor to follow.
* -f: filename of write
* -s: starting time
* -d: duration
* -c: actor to follow (id)
* **show_recorder_collisions.py**: this will show all the collisions hapenned while recording (currently only involved by hero actors).
* -f: filename of write
* -t: two letters definning the types of the actors involved, for example: -t aa
* **h** = Hero
* **v** = Vehicle
* **w** = Walker
* **t** = Traffic light
* **o** = Other
* **a** = Any
* **show_recorder_actors_blocked.py**: this will show all the actors that are blocked (stopped) in the recorder. We can define the time and distance to be considered as blocked.
* -f: filename of write
* -t: minimum seconds stopped to be considered as blocked
* -d: minimum distance to be considered stopped.

View File

@ -287,7 +287,7 @@ class KeyboardControl(object):
world.player.set_autopilot(self._autopilot_enabled)
world.hud.notification("Replaying file 'manual_recording.rec'")
# replayer
client.replay_file("manual_recording.rec", world.recording_start, 0)
client.replay_file("manual_recording.rec", world.recording_start, 0, 0)
world.camera_manager.set_sensor(currentIndex)
elif event.key == K_MINUS and (pygame.key.get_mods() & KMOD_CTRL):
if pygame.key.get_mods() & KMOD_SHIFT:

View File

@ -0,0 +1,80 @@
#!/usr/bin/env python
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB).
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
import glob
import os
import sys
try:
sys.path.append(glob.glob('**/*%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
import argparse
import random
import time
def main():
argparser = argparse.ArgumentParser(
description=__doc__)
argparser.add_argument(
'--host',
metavar='H',
default='127.0.0.1',
help='IP of the host server (default: 127.0.0.1)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-f', '--recorder_filename',
metavar='F',
default="test1.rec",
help='recorder filename (test1.rec)')
argparser.add_argument(
'-t', '--time',
metavar='T',
default="30",
type=float,
help='minimum time to consider it is blocked')
argparser.add_argument(
'-d', '--distance',
metavar='D',
default="100",
type=float,
help='minimum distance to consider it is not moving (in cm)')
args = argparser.parse_args()
try:
client = carla.Client(args.host, args.port)
client.set_timeout(60.0)
world = client.get_world()
print client.show_recorder_actors_blocked(args.recorder_filename, args.time, args.distance)
finally:
pass
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
print('\ndone.')

View File

@ -0,0 +1,78 @@
#!/usr/bin/env python
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB).
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
import glob
import os
import sys
try:
sys.path.append(glob.glob('**/*%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
import argparse
import random
import time
def main():
argparser = argparse.ArgumentParser(
description=__doc__)
argparser.add_argument(
'--host',
metavar='H',
default='127.0.0.1',
help='IP of the host server (default: 127.0.0.1)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-f', '--recorder_filename',
metavar='F',
default="test1.rec",
help='recorder filename (test1.rec)')
argparser.add_argument(
'-t', '--types',
metavar='T',
default="aa",
help='pair of types (a=any, h=hero, v=vehicle, w=walkers, t=trafficLight, o=others')
args = argparser.parse_args()
try:
client = carla.Client(args.host, args.port)
client.set_timeout(60.0)
world = client.get_world()
# types pattern samples:
# -t aa == any to any == show every collision (the default)
# -t vv == vehicle to vehicle == show every collision between vehicles only
# -t vt == vehicle to traffic light == show every collision between a vehicle and a traffic light
# -t hh == hero to hero == show collision between a hero and another hero
print client.show_recorder_collisions(args.recorder_filename, args.types[0], args.types[1])
finally:
pass
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
print('\ndone.')

View File

@ -27,23 +27,37 @@ import time
def main():
argparser = argparse.ArgumentParser(
description=__doc__)
argparser.add_argument(
'--host',
metavar='H',
default='127.0.0.1',
help='IP of the host server (default: 127.0.0.1)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-f', '--recorder_filename',
metavar='F',
default="test1.rec",
help='recorder filename (test1.rec)')
args = argparser.parse_args()
actor_list = []
try:
client = carla.Client('localhost', 2000)
client.set_timeout(2.0)
client = carla.Client(args.host, args.port)
client.set_timeout(60.0)
world = client.get_world()
#print "Recording on file:", client.start_recorder("test1.rec")
#print client.show_recorder_file_info("test1.rec")
print client.replay_file("test1.rec", 2)
#time.sleep(5)
print client.show_recorder_file_info(args.recorder_filename)
finally:
#print "Stop recording"
#client.stop_recorder()
pass
if __name__ == '__main__':

View File

@ -0,0 +1,146 @@
#!/usr/bin/env python
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB).
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
import glob
import os
import sys
try:
sys.path.append(glob.glob('**/*%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
import argparse
import random
import time
def main():
argparser = argparse.ArgumentParser(
description=__doc__)
argparser.add_argument(
'--host',
metavar='H',
default='127.0.0.1',
help='IP of the host server (default: 127.0.0.1)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-n', '--number-of-vehicles',
metavar='N',
default=10,
type=int,
help='number of vehicles (default: 10)')
argparser.add_argument(
'-d', '--delay',
metavar='D',
default=2.0,
type=float,
help='delay in seconds between spawns (default: 2.0)')
argparser.add_argument(
'--safe',
action='store_true',
help='avoid spawning vehicles prone to accidents')
argparser.add_argument(
'-f', '--recorder_filename',
metavar='F',
default="test1.rec",
help='recorder filename (test1.rec)')
argparser.add_argument(
'-t', '--recorder_time',
metavar='T',
default=0,
type=int,
help='recorder duration (auto-stop)')
args = argparser.parse_args()
actor_list = []
try:
client = carla.Client(args.host, args.port)
client.set_timeout(2.0)
world = client.get_world()
blueprints = world.get_blueprint_library().filter('vehicle.*')
if args.safe:
blueprints = [x for x in blueprints if int(x.get_attribute('number_of_wheels')) == 4]
blueprints = [x for x in blueprints if not x.id.endswith('isetta')]
def try_spawn_random_vehicle_at(transform):
blueprint = random.choice(blueprints)
if blueprint.has_attribute('color'):
color = random.choice(blueprint.get_attribute('color').recommended_values)
blueprint.set_attribute('color', color)
blueprint.set_attribute('role_name', 'autopilot')
vehicle = world.try_spawn_actor(blueprint, transform)
if vehicle is not None:
actor_list.append(vehicle)
vehicle.set_autopilot()
print('spawned %r at %s' % (vehicle.type_id, transform.location))
return True
return False
# @todo Needs to be converted to list to be shuffled.
spawn_points = list(world.get_map().get_spawn_points())
random.shuffle(spawn_points)
print('found %d spawn points.' % len(spawn_points))
count = args.number_of_vehicles
print "Recording on file:", client.start_recorder(args.recorder_filename)
for spawn_point in spawn_points:
if try_spawn_random_vehicle_at(spawn_point):
count -= 1
if count <= 0:
break
while count > 0:
time.sleep(args.delay)
if try_spawn_random_vehicle_at(random.choice(spawn_points)):
count -= 1
#print client.show_recorder_file_info("test1.rec")
print('spawned %d vehicles, press Ctrl+C to exit.' % args.number_of_vehicles)
#time.sleep(10);
if (args.recorder_time > 0):
time.sleep(args.recorder_time)
else:
while True:
time.sleep(0.1)
finally:
print('\ndestroying %d actors' % len(actor_list))
for actor in actor_list:
actor.destroy()
print "Stop recording"
client.stop_recorder()
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
print('\ndone.')

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
# Copyright (c) 2017 Computer Vision Center (CVC) at the Universitat Autonoma de
# Barcelona (UAB).
#
# This work is licensed under the terms of the MIT license.
# For a copy, see <https://opensource.org/licenses/MIT>.
import glob
import os
import sys
try:
sys.path.append(glob.glob('**/*%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
import argparse
import random
import time
def main():
argparser = argparse.ArgumentParser(
description=__doc__)
argparser.add_argument(
'--host',
metavar='H',
default='127.0.0.1',
help='IP of the host server (default: 127.0.0.1)')
argparser.add_argument(
'-p', '--port',
metavar='P',
default=2000,
type=int,
help='TCP port to listen to (default: 2000)')
argparser.add_argument(
'-s', '--start',
metavar='S',
default=0.0,
type=float,
help='starting time (default: 0.0)')
argparser.add_argument(
'-d', '--duration',
metavar='D',
default=0.0,
type=float,
help='duration (default: 0.0)')
argparser.add_argument(
'-f', '--recorder_filename',
metavar='F',
default="test1.rec",
help='recorder filename (test1.rec)')
argparser.add_argument(
'-c', '--camera',
metavar='C',
default=0,
type=int,
help='camera follows an actor (ex: 82)')
args = argparser.parse_args()
actor_list = []
try:
client = carla.Client(args.host, args.port)
client.set_timeout(60.0)
world = client.get_world()
print client.replay_file(args.recorder_filename, args.start, args.duration, args.camera)
finally:
pass
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
pass
finally:
print('\ndone.')