From 668c5094848ec356f63c1a39fd73b7e9d00b0b37 Mon Sep 17 00:00:00 2001 From: nsubiron Date: Sun, 16 Dec 2018 00:02:22 +0100 Subject: [PATCH] Fill Python API tutorial --- Docs/index.md | 2 +- Docs/python_api_overview.md | 330 ++++++++++++++++++++++++++++++------ mkdocs.yml | 2 +- 3 files changed, 277 insertions(+), 57 deletions(-) diff --git a/Docs/index.md b/Docs/index.md index 28367c3f5..53b0b9d96 100644 --- a/Docs/index.md +++ b/Docs/index.md @@ -8,7 +8,7 @@

Quick start

* [Getting started](getting_started.md) - * [Python API overview](python_api_overview.md) + * [Python API tutorial](python_api_overview.md) * [Configuring the simulation](configuring_the_simulation.md) * [Cameras and sensors](cameras_and_sensors.md) diff --git a/Docs/python_api_overview.md b/Docs/python_api_overview.md index 30ae10f15..f48ce6b79 100644 --- a/Docs/python_api_overview.md +++ b/Docs/python_api_overview.md @@ -1,102 +1,186 @@ -

Python API overview

+

Python API tutorial

-![Client window](img/client_window.png) +In this tutorial we introduce the basic concepts of the CARLA Python API, as +well as an overview of its most important functionalities. The reference of all +classes and methods available can be found at +[Python API reference](python_api.md). -First we need to introduce a few core concepts: +!!! note + **This document applies only to the latest development version**.
+ The API has been significantly changed in the latest versions starting at + 0.9.0. We commonly refer to the new API as **0.9.X API** as opposed to + the previous **0.8.X API**. + +First of all, we need to introduce a few core concepts: - **Actor:** Actor is anything that plays a role in the simulation and can be moved around, examples of actors are vehicles, pedestrians, and sensors. - **Blueprint:** Before spawning an actor you need to specify its attributes, and that's what blueprints are for. We provide a blueprint library with - the definitions of all the actors available for you to choose. + the definitions of all the actors available. - **World:** The world represents the currently loaded map and contains the - functions for converting a blueprint into a living actor. + functions for converting a blueprint into a living actor, among other. It + also provides access to the road map and functions to change the weather + conditions. -For the full list of methods available take a look at the -[Python API reference](python_api.md). +#### Connecting and retrieving the world -#### Connecting and retrieving the current world - -To connect to a simulator we need to create a "Client" object providing IP -address and port of a running instance of the simulator. +To connect to a simulator we need to create a "Client" object, and to do so we +need to provide the IP address and port of a running instance of the simulator ```py client = carla.Client('localhost', 2000) ``` -It is very convenient to set the time-out, otherwise networking operations may -block forever. +First thing most scripts do is setting the client time-out. This time-out sets a +time limit to all networking operations, if the time-out is not set networking +operations may block forever. ```py client.set_timeout(10.0) # seconds ``` -Next step is retrieving the active world, we use this world for spawning actors, -changing weather, and getting road info. +Once we have the client configured we can directly retrieve the world ```py world = client.get_world() ``` -#### Blueprint library +Typically we won't need the client object anymore, all the objects created by +the world will connect to the IP and port provided if they need to. This +operations are usually done in the background and are transparent to the user. -Before we can create an actor, we need to take a look at the blueprint library. +#### Blueprints + +A blueprint contains the information necessary to create a new actor. For +instance, if the blueprint defines a car, we can change its color here, if it +defines a lidar, we can decide here how many channels the lidar will have. A +blueprints also has an ID that uniquely identifies it and all the actor +instances created with it. Examples of IDs are "vehicle.nissan.patrol" or +"sensor.camera.depth". + +The list of all available blueprints is kept in the **blueprint library** ```py blueprint_library = world.get_blueprint_library() ``` -You can filter with wildcards. +The library allows us to find specific blueprints by ID, filter them with +wildcards, or just choosing one at random -Some of the attributes of the blueprints can be modified. +```py +# Find specific blueprint. +collision_sensor_bp = blueprint_library.find('sensor.other.collision') +# Chose a vehicle blueprint at random. +vehicle_bp = random.choice(blueprint_library.filter('vehicle.bmw.*')) +``` + +Some of the attributes of the blueprints can be modified while some other are +just read-only. For instance, we cannot modify the number of wheels of a vehicle +but we can change its color + +```py +vehicles = blueprint_library.filter('vehicle.*') +bikes = [x for x in vehicles if int(x.get_attribute('number_of_wheels')) == 2] +for bike in bikes: + bike.set_attribute('color', '255,0,0') +``` + +Modifiable attributes also come with a list of recommended values + +```py +for attr in blueprint: + if attr.is_modifiable: + blueprint.set_attribute(attr.id, random.choice(attr.recommended_values)) +``` + +The blueprint system has been designed to ease contributors adding their custom +actors directly in Unreal Editor, we'll add a tutorial on this soon, keep tuned! #### Spawning actors -Let's just go for a practical example. The following code adds a red Mustang to -the simulation and enables its autopilot so the car can drive freely around the -city on its own +Once we have the blueprint set up, spawning an actor is pretty straightforward ```py -blueprint = blueprint_library.find('vehicle.ford.mustang') -blueprint.set_attribute('color', '255,0,0') - -transform = carla.Transform(carla.Location(x=230, y=195, z=40), carla.Rotation(yaw=180)) - -vehicle = world.spawn_actor(blueprint, transform) +transform = Transform(Location(x=230, y=195, z=40), Rotation(yaw=180)) +actor = world.spawn_actor(blueprint, transform) ``` -Spawn actor function has two flavours, `spawn_actor` and `try_spawn_actor`. +The spawn actor function comes in two flavours, `spawn_actor` and +`try_spawn_actor`. The former will raise an exception if the actor could not be +spawned, the later will return `None` instead. The most typical cause of +failure is collision at spawn point, meaning the actor does not fit at the spot +we chose; probably another vehicle is in that spot or we tried to spawn into a +building. + +To ease the task of finding a spawn location, each map provides a list of +recommended transforms + +```py +spawn_points = world.get_map().get_spawn_points() +``` + +We add more on the map class later in this tutorial. + +Finally, the spawn functions have an optional argument that controls whether the +actor is going to be attached to another actor. This is specially useful for +sensors. In the next example the camera remains rigidly attached to our vehicle +during the rest of the simulation + +```py +camera = world.spawn_actor(camera_bp, relative_transform, attach_to=my_vehicle) +``` + +Note that in this case, the transform provided is treated relative to the parent +actor. #### Handling actors -Actors can also be teleported and moved around the city, for that we have -exposed the `set_location` and `set_transform` methods +Once we have an actor alive in the world, we can move this actor around and +check its dynamic properties ```py -location = vehicle.get_location() -location.x += 10.0 -vehicle.set_location(location) +location = actor.get_location() +location.z += 10.0 +actor.set_location(location) +print(actor.get_acceleration()) +print(actor.get_velocity()) ``` -`get_transform()`, `get_velocity()`, `get_acceleration()`. - -`set_simulate_physics(False)`. - -Once we are tired of an actor we can remove it from the simulation with +We can even freeze and actor by disabling its physics simulation ```py -vehicle.destroy() +actor.set_simulate_physics(False) ``` +And once we are tired of an actor we can remove it from the simulation with + +```py +actor.destroy() +``` + +Note that actors are not cleaned up automatically when we the Python script +finishes, if we want to get rid of them we need to explicitly destroy them. + +!!! important + **Known issue:** To improve performance, most of the methods send requests + to the simulator asynchronously. The simulator queues each of these + requests, but only has a limited amount of time each update to parse them. + If we flood the simulator by calling "set" methods too often, e.g. + set_transform, the requests will accumulate a significant lag. + #### Vehicles -and in the special case of vehicles, they can be controlled too in the usual way +Vehicles are a special type of actors that provide a few methods specific for +wheeled vehicles. Apart from the handling methods common to all actors, vehicles +can also be controlled by providing throttle, break, and steer values ```py vehicle.apply_control(carla.VehicleControl(throttle=1.0, steer=-1.0)) ``` -These are all the parameters of the VehicleControl +These are all the parameters of the VehicleControl object and their default +values ```py carla.VehicleControl( @@ -109,28 +193,164 @@ carla.VehicleControl( gear = 0) ``` -`set_autopilot()`, `bounding_box`. +Our vehicles also come with a handy autopilot + +```py +vehicle.set_autopilot(True) +``` + +As has been a common misconception, we need to clarify that this autopilot +control is purely hard-coded into the simulator and it's not based at all in +machine learning techniques. + +Finally, vehicles also have a bounding box that encapsulates them + +```py +box = vehicle.bounding_box +print(box.location) # Location relative to the vehicle. +print(box.extent) # XYZ half-box extents in meters. +``` #### Sensors -Now let's attach a camera to this vehicle so we can take a look at what's going -on, we are going to save this images to disk +Sensors are a special type of actor that produce a stream of data. Sensors are +such a key component of CARLA that they deserve their own documentation page, so +here we'll limit ourselves to show a small example of how sensors work ```py -blueprint = world.get_blueprint_library().find('sensor.camera.rgb') -transform = carla.Transform(carla.Location(x=0.5, z=1.8)) -camera = world.spawn_actor(blueprint, transform, attach_to=vehicle) - -camera.listen(lambda image: image.save_to_disk('%06d.png' % image.frame_number)) +camera_bp = blueprint_library.find('sensor.camera.rgb') +camera = world.spawn_actor(camera_bp, relative_transform, attach_to=my_vehicle) +camera.listen(lambda image: image.save_to_disk('output/%06d.png' % image.frame_number)) ``` -the callback function passed to the `listen` method will be called every time a -new image is received. This callback is executed asynchronously, this -considerably speeds up the parsing of images. Now it is possible to do things -like saving images to disk keeping up with the speed of the simulator. +In this example we have attached a camera to a vehicle, and told the camera to +save to disk each of the images generated. + +The full list of sensors and their measurement is explained in +[Cameras and sensors](cameras_and_sensors.md). #### Other actors +Apart from vehicles and sensors, there are many other actors in the world. The +full list can be requested to the world + +```py +actor_list = world.get_actors() +``` + +The actor list object returned has functions for finding, filtering, and +iterating actors + +```py +# 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()) +``` + +Among the actors you can find in this list are + + * **Traffic lights** with a `state` property to check the light's current state. + * **Speed limit signs** with the speed codified in their type_id. + * The **Spectator** actor that can be used to move the view of the simulator window. + #### Changing the weather -#### Map +The lighting and weather conditions can be requested and changed with the world +object + +```py +weather = carla.WeatherParameters( + cloudyness=80.0, + precipitation=30.0, + sun_altitude_angle=70.0) + +world.set_weather(weather) + +print(world.get_weather()) +``` + +For convenience, we also provided a list of predefined weather presets that can +be directly applied to the world + +```py +world.set_weather(carla.WeatherParameters.WetCloudySunset) +``` + +The full list of presets can be found in the +[WeatherParameters reference](python_api.md#carlaweatherparameters). + +#### Map and waypoints + +One of the key features of CARLA is that our roads are fully annotated, all our +maps come accompanied by an OpenDrive file that defines the road layout. +Furthermore, we provide a higher level API for querying and navigating this +information. + +These objects were a recent addition to our API and are still in heavy +development, we hope to make them soon much more powerful that are now. + +Let's start by getting the map of the current world + +```py +map = world.get_map() +``` + +For starters, the map has a `name` attribute that matches the name of the +currently loaded city, e.g. Town01. And, as we've seen before, we can also ask +the map to provide a list of recommended locations for spawning vehicles, +`map.get_spawn_points()`. + +However, the real power of this map API comes apparent when we introduce +waypoints. We can tell the map to give us a waypoint on the road closest to our +vehicle + +```py +waypoint = map.get_waypoint(vehicle.get_location()) +``` + +This waypoint's `transform` is located on a drivable lane, and it's oriented +according to the road direction at that point. + +Waypoints also have function to query the "next" waypoints, this method returns +a list of waypoints at a certain distance that can be accessed from this +waypoint following the traffic rules. In other words, if a vehicle is placed in +this waypoint, give me the list of posible locations that this vehicle can drive +to. Let's see a practical example + +```py +# Retrieve the closest waypoint. +waypoint = map.get_waypoint(vehicle.get_location()) + +# Disable physics, in this example we're just teleporting the vehicle. +vehicle.set_simulate_physics(False) + +while True: + # Find next waypoint 2 meters ahead. + waypoint = random.choice(waypoint.next(2.0)) + # Teleport the vehicle. + vehicle.set_transform(waypoint.transform) +``` + +The map object also provides methods for generating in bulk waypoints all over +the map at an approximated distance between them + +```py +map.generate_waypoints(2.0) +``` + +For routing purposes, it is also possible to retrieve a topology graph of the +roads + +```py +waypoint_tuple_list = map.get_topology() +``` + +this method returns a list of pairs (tuples) of waypoints, for each pair, the +first element connects with the second one. Only the minimal set of waypoints to +define the topology are generated by this method, only a waypoint for each lane +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. diff --git a/mkdocs.yml b/mkdocs.yml index aa940ebf9..3386107a7 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -7,7 +7,7 @@ pages: - Home: 'index.md' - Quick start: - 'Getting started': 'getting_started.md' - - 'Python API overview': 'python_api_overview.md' + - 'Python API tutorial': 'python_api_overview.md' - 'Configuring the simulation': 'configuring_the_simulation.md' # - 'Measurements': 'measurements.md' - 'Cameras and sensors': 'cameras_and_sensors.md'