Carma-platform v4.2.0
CARMA Platform is built on robot operating system (ROS) and utilizes open source software (OSS) that enables Cooperative Driving Automation (CDA) features to allow Automated Driving Systems to interact and cooperate with infrastructure and other vehicles through communication.
create_two_lane_map.py
Go to the documentation of this file.
1"""
2This script creates a vector map with two parallel lanes using the Lanelet2 library and saves it as an OSM file.
3The script can be run from the command line with the following arguments:
4- filename: The output filename for the vector map.
5- total_length: The length of the lanes (default is 50.0).
6- lane_width: The width of the lanes (default is 3.7).
7- points_per_meter: The number of points per meter (default is 5).
8
9Dependencies:
10- lanelet2: The Lanelet2 library for handling lanelet maps.
11- argparse: For parsing command line arguments.
12Usage:
13 python3 create_two_lane_map.py --filename output.osm --total_length <total_length> --lane_width <lane_width> --points_per_meter <points_per_meter>
14"""
15
16from pyproj import Proj, Transformer
17import xml.etree.ElementTree as ET
18from xml.dom import minidom
19import argparse
20
21
22# Adjusted geoReference (removed vertical geoid grid)
23geo_reference = "+proj=tmerc +lat_0=0 +lon_0=0 +k=1 +x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
24
25# Coordinate transformer (meters → lat/lon)
26proj = Proj(geo_reference)
27transformer = Transformer.from_proj(proj, "epsg:4326", always_xy=True)
28
29# Globals
30node_id = 1000000
31way_id = 1000
32relation_id = 100
33nodes, ways, relations = [], [], []
34
35def add_node(x, y, z=0.0):
36 global node_id
37 lon, lat = transformer.transform(x, y)
38 node = ET.Element("node", id=str(node_id), version="1", lat=f"{lat:.9f}", lon=f"{lon:.9f}", visible="true")
39 ET.SubElement(node, "tag", k="ele", v=f"{z:.2f}")
40 ET.SubElement(node, "tag", k="lat", v=f"{lat:.9f}")
41 ET.SubElement(node, "tag", k="lon", v=f"{lon:.9f}")
42 nodes.append((node_id, node))
43 node_id += 1
44 return node_id - 1
45
46def create_way(node_ids, tags):
47 global way_id
48 way = ET.Element("way", id=str(way_id), version="1", visible="true")
49 for nid in node_ids:
50 ET.SubElement(way, "nd", ref=str(nid))
51 for k, v in tags.items():
52 ET.SubElement(way, "tag", k=k, v=v)
53 ways.append((way_id, way))
54 way_id += 1
55 return way_id - 1
56
57def create_lanelet(left_id, right_id, tags):
58 global relation_id
59 rel = ET.Element("relation", id=str(relation_id), version="1", visible="true")
60 ET.SubElement(rel, "member", type="way", ref=str(left_id), role="left")
61 ET.SubElement(rel, "member", type="way", ref=str(right_id), role="right")
62 for k, v in tags.items():
63 ET.SubElement(rel, "tag", k=k, v=v)
64 ET.SubElement(rel, "tag", k="cad_id", v=str(relation_id))
65 relations.append((relation_id, rel))
66 relation_id += 1
67
68def create_vector_map(filename, total_length, lane_width, points_per_meter):
69 """
70 Create a vector map with two parallel lanes.
71 Inputs:
72 - filename: The output filename for the vector map.
73 - total_length: The length of the lanes.
74 - lane_width: The width of the lanes.
75 - points_per_meter: The number of points per meter.
76 """
77 # Road geometry
78 lanelet_length = 25.0
79 total_points = int(total_length * points_per_meter) + 1
80 points_per_lanelet = int(lanelet_length * points_per_meter) + 1
81 # Generate lane boundaries
82 x_offset = -total_length / 2
83 y_offset = -lane_width
84 left1, right1, left2, right2 = [], [], [], []
85 for i in range(total_points):
86 x = i / points_per_meter + x_offset
87 right1.append(add_node(x, 0 + y_offset))
88 left1.append(add_node(x, lane_width + y_offset))
89 right2.append(add_node(x, lane_width + y_offset))
90 left2.append(add_node(x, 2 * lane_width + y_offset))
91
92 stride = points_per_lanelet - 1
93 way_dict = {"type": "line_thin", "subtype": "solid"}
94 lanelet_dict = {"type": "lanelet",
95 "subtype": "road",
96 "road_type": "road",
97 "turn_direction": "straight",
98 "from_cad_id" : [],
99 "direction" : "ONE_WAY",
100 "level" : "0",
101 "location" : "private",
102 "near_spaces" : [],
103 "participant:vehicle" : "yes",
104 "to_cad_id" : [],
105 }
106 for i in range(0, total_points - stride, stride):
107 # Outer left boundary of lane 2
108 l2_nodes = left2[i:i + points_per_lanelet]
109 l2_id = create_way(l2_nodes, way_dict) # solid
110
111 # Shared dashed centerline between lanes
112 center_nodes = right2[i:i + points_per_lanelet]
113 center_id = create_way(center_nodes, {"type": "line_thin", "subtype": "dashed"})
114
115 # Outer right boundary of lane 1
116 r1_nodes = right1[i:i + points_per_lanelet]
117 r1_id = create_way(r1_nodes, way_dict) # solid
118
119 # Lanelet for lane 2 (left: outer left, right: dashed center)
120 create_lanelet(l2_id, center_id, lanelet_dict)
121
122 # Lanelet for lane 1 (left: dashed center, right: outer right)
123 create_lanelet(center_id, r1_id, lanelet_dict)
124
125 # Build OSM XML tree
126 osm = ET.Element("osm", version="0.6")
127 ET.SubElement(osm, "geoReference", v=geo_reference)
128 for _, node in nodes:
129 osm.append(node)
130 for _, way in ways:
131 osm.append(way)
132 for _, rel in relations:
133 osm.append(rel)
134
135 # Write to file
136 with open(filename, "w", encoding="utf-8") as f:
137 xml_str = minidom.parseString(ET.tostring(osm)).toprettyxml(indent=" ")
138 f.write(xml_str)
139
140 print(f"Map saved to {filename}")
141
142if __name__ == "__main__":
143 parser = argparse.ArgumentParser(description="Create a vector map with two parallel lanes.")
144 parser.add_argument("--filename", type=str, default="two_lane_straight.osm", help="Output filename for the vector map.")
145 parser.add_argument("--total_length", type=float, default=50.0, help="Length of the lanes.")
146 parser.add_argument("--lane_width", type=float, default=3.7, help="Width of the lanes.")
147 parser.add_argument("--points_per_meter", type=int, default=5, help="Number of points per meter.")
148 args = parser.parse_args()
149 create_vector_map(args.filename, args.total_length, args.lane_width, args.points_per_meter)
150 print("Vector map with two parallel lanes created successfully.")
def create_way(node_ids, tags)
def create_lanelet(left_id, right_id, tags)
def create_vector_map(filename, total_length, lane_width, points_per_meter)
def add_node(x, y, z=0.0)