carla/Docs/core_map.md

14 KiB

3rd. Maps and navigation

After discussing about the world and its actors, it is time to put everything into place and understand the map and how do the actors navigate it.


The map

A map includes both the 3D model of a town and its road definition. Every map is based on an OpenDRIVE file describing the road layout fully annotated. The way the OpenDRIVE standard 1.4 defines roads, lanes, junctions, etc. is extremely important. It determines the possibilities of the API and the reasoning behind decisions made.

The Python API makes for a high level querying system to navigate these roads. It is constantly evolving to provide a wider set of tools.

Changing the map

To change the map, the world has to change too. Everything will be rebooted and created from scratch, besides the Unreal Editor itself. There are two ways to do so.

  • reload_world() creates a new instance of the world with the same map.
  • load_world() changes the current map and creates a new world.
world = client.load_world('Town01')

The client can get a list of available maps. Each map has a name attribute that matches the name of the currently loaded city, e.g. Town01.

print(client.get_available_maps())

Landmarks

The traffic signs defined in the OpenDRIVE file are translated into CARLA as landmark objects that can be queried from the API. In order to facilitate their manipulation, there have been several additions to it.

  • carla.Landmark objects represent the OpenDRIVE signals. The attributes and methods describe the landmark, and where it is effective.
  • A carla.Waypoint can get landmarks located a certain distance ahead of it. The type of landmark can be specified.
  • The carla.Map retrieves sets of landmarks. It can return all the landmarks in the map, or those having an ID, type or group in common.
  • The carla.World acts as intermediary between landmarks, and the carla.TrafficSign and carla.TrafficLight that embody them in the simulation.
my_waypoint.get_landmarks(200.0,True)

Lanes

The lane types defined by OpenDRIVE standard 1.4 are translated to the API in carla.LaneType as a series of enum values.

The lane markings surrounding a lane can be accessed through carla.LaneMarking. These are defined with a series of variables.

Waypoints use these to aknowledge traffic permissions.

# Get the lane type where the waypoint is. 
lane_type = waypoint.lane_type

# Get the type of lane marking on the left. 
left_lanemarking_type = waypoint.left_lane_marking.type()

# Get available lane changes for this waypoint.
lane_change = waypoint.lane_change

Junctions

A carla.Junction represents an OpenDRIVE junction. This class provides for a bounding box to state whereas lanes or vehicles are inside of it.

The most remarkable method of this class returns a pair of waypoints per lane inside the junction. Each pair is located at the starting and ending point of the junction boundaries.

waypoints_junc = my_junction.get_waypoints()

Waypoints

A carla.Waypoint is a 3D-directed point. These are prepared to mediate between the world and the openDRIVE definition of the road. Everything related with waypoints happens on the client-side, so there no communication with the server is needed.

Each waypoint contains a carla.Transform. This states its location on the map and the orientation of the lane containing it. The variables road_id,section_id,lane_id and s translate this transform to the OpenDRIVE road. These combined, create the id of the waypoint.

!!! Note Due to granularity, waypoints closer than 2cm within the same road share the same id.

A waypoint also contains some information regarding the lane containing it. Specifically its left and right lane markings, and a boolean to determine if it is inside a junction.

# Examples of a waypoint accessing to lane information
inside_junction = waypoint.is_junction()
width = waypoint.lane_width
right_lm_color = waypoint.right_lane_marking.color

Environment Objects

Every object on a CARLA map has a set of associated variables which can be found here. Included in these variables is a unique ID that can be used to toggle that object's visibility on the map. You can use the Python API to fetch the IDs of each environment object based on their semantic tag:

	# Get the buildings in the world
    world = client.get_world()
	env_objs = world.get_environment_objects(carla.CityObjectLabel.Buildings)

	# Access individual building IDs and save in a set
	building_01 = env_objs[0]
	building_02 = env_objs[1]
	objects_to_toggle = {building_01.id, building_02.id}

	# Toggle buildings off
	world.enable_environment_objects(objects_to_toggle, False)
	# Toggle buildings on
	world.enable_environment_objects(objects_to_toggle, True)

See an example of distinct objects being toggled:

toggle_objects_gif


Navigation in CARLA

Navigation in CARLA is managed via the waypoint API. This consists of a summary of methods in carla.Waypoint and carla.Map.

All the queries happen on the client-side. The client only communicates with the server when retrieving the map object that will be used for the queries. There is no need to retrieve the map (world.get_map()) more than once.

Navigating through waypoints

Waypoints have a set of methods to connect with others and create a road flow. All of these methods follow traffic rules to determine only places where the vehicle can go.

  • next(d) creates a list of waypoints at an approximate distance d in the direction of the lane. The list contains one waypoint for each deviation possible.
  • previous(d) creates a list of waypoints waypoint at an approximate distance d on the opposite direction of the lane. The list contains one waypoint for each deviation possible.
  • next_until_lane_end(d) and previous_until_lane_start(d) returns a list of waypoints a distance d apart. The list goes from the current waypoint to the end and start of its lane, respectively.
  • get_right_lane() and get_left_lane() return the equivalent waypoint in an adjacent lane, if any. A lane change maneuver can be made by finding the next waypoint to the one on its right/left lane, and moving to it.
# Disable physics, in this example the vehicle is teleported.
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)

Generating a map navigation

The instance of the map is provided by the world. It will be useful to create routes and make vehicles roam around the city and reach goal destinations.

The following method asks the server for the XODR map file, and parses it to a carla.Map object. It only needs to be calle once. Maps can be quite heavy, and successive calls are unnecessary and expensive.

map = world.get_map()
  • Get recommended spawn points for vehicles pointed by developers. There is no ensurance that these spots will be free.
spawn_points = world.get_map().get_spawn_points()
  • Get the closest waypoint to a specific location or to a certain road_id, lane_id and s in OpenDRIVE.
# Nearest waypoint on the center of a Driving or Sidewalk lane.
waypoint01 = map.get_waypoint(vehicle.get_location(),project_to_road=True, lane_type=(carla.LaneType.Driving | carla.LaneType.Sidewalk))

#Nearest waypoint but specifying OpenDRIVE parameters. 
waypoint02 = map.get_waypoint_xodr(road_id,lane_id,s)
  • Generate a collection of waypoints to visualize the city lanes. Creates waypoints all over the map, for every road and lane. All of them will be an approximate distance apart.
waypoint_list = map.generate_waypoints(2.0)
  • Generate road topology. Returns a list of pairs (tuples) of waypoints. For each pair, the first element connects with the second one and both define the starting and ending point of each lane in the map.
waypoint_tuple_list = map.get_topology()
  • Convert simulation point to geographical coordinates. Transforms a certain location to a carla.GeoLocation with latitude and longitude values.
my_geolocation = map.transform_to_geolocation(vehicle.transform)
  • Save road information. Converts the road information to OpenDRIVE format, and saves it to disk.
info_map = map.to_opendrive()

CARLA maps

There are eight towns in the CARLA ecosystem and each of those towns have two kinds of map, non-layered and layered. Layers refer to the grouped objects within a map and consist of the following:

  • NONE
  • Buildings
  • Decals
  • Foliage
  • Ground
  • ParkedVehicles
  • Particles
  • Props
  • StreetLights
  • Walls
  • All

Non-layered maps

Non-layered maps are shown in the table below (click the town name to see an overhead image of the layout). All of the layers are present at all times and cannot be toggled on or off in these maps. Up until CARLA 0.9.11, these were the only kinds of map available.

!!! Note Users can customize a map or even create a new map to be used in CARLA.

Town Summary
Town01 A basic town layout consisting of "T junctions".
Town02 Similar to Town01, but smaller.
Town03 The most complex town, with a 5-lane junction, a roundabout, unevenness, a tunnel, and more.
Town04 An infinite loop with a highway and a small town.
Town05 Squared-grid town with cross junctions and a bridge. It has multiple lanes per direction. Useful to perform lane changes.
Town06 Long highways with many highway entrances and exits. It also has a Michigan left.
Town07 A rural environment with narrow roads, barns and hardly any traffic lights.
Town10 A city environment with different environments such as an avenue or promenade, and more realistic textures.

Layered maps

The layout of layered maps is the same as non-layered maps but it is possible to toggle off and on the layers of the map. There is a minimum layout that cannot be toggled off and consists of roads, sidewalks, traffic lights and traffic signs. Layered maps can be identified by the suffix _Opt, for example, Town01_Opt. With these maps it is possible to load and unload layers via the Python API:

	# Load layered map for Town 01 with minimum layout plus buildings and parked vehicles
	world = client.load_world('Town01_Opt', carla.MapLayer.Buildings | carla.MapLayer.ParkedVehicles)

	# Toggle all buildings off
	world.unload_map_layer(carla.MapLayer.Buildings)

	# Toggle all buildings on	
	world.load_map_layer(carla.MapLayer.Buildings)

See an example of all layers being loaded and unloaded in sequence:

map-layers



That is a wrap as regarding maps and navigation in CARLA. The next step takes a closer look into sensors types, and the data they retrieve.

Keep reading to learn more or visit the forum to post any doubts or suggestions that have come to mind during this reading.