diff --git a/obu-cam-transmistter/NOTES.md b/obu-cam-transmistter/NOTES.md index c672494..c14ae31 100644 --- a/obu-cam-transmistter/NOTES.md +++ b/obu-cam-transmistter/NOTES.md @@ -1,7 +1,7 @@ # OBU transmit firmware - Phase 2 (in progress: HLN-SV DENM beacon) -Started. See `docs/04-transmit-setup.md` in the project root for build/flash -steps and how to validate this against your own sniffer. +Build and flash steps are under "Build and flash" below. (`docs/04-transmit-setup.md`, +referenced here and in the sources, is not in the repo.) ## Toolchain: use a dedicated terminal (ESP-IDF 5.5.4) @@ -29,6 +29,123 @@ referenced an older source path under `micrOBU_workspace/v2x-obu-esp32c5/`, which makes `idf.py fullclean` refuse to run). If that error reappears, delete `build/` manually rather than fighting it. +## Build and flash + +The firmware needs no button, phone or serial connection to start. On every power-up or reset, +`app_main` sets up the radio and starts `tx_task`, which starts driving the simulated route and +sending CAMs on 5900 MHz. A board flashed with this image starts beaconing on its own as soon as it +gets power. + +In a fresh PowerShell window: + +```powershell +$env:IDF_PYTHON_ENV_PATH = $null; $env:IDF_PATH = $null +. C:\Espressif\frameworks\esp-idf-v5.5.4\export.ps1 +cd C:\Users\Ashin\AndroidStudioProjects\MicrOBU\obu-cam-transmistter +``` + +1. **Check what the board is running before you flash it.** Both this project and `obu-firmware` + name their image `obu_firmware.bin`, so the file name tells you nothing. Read the app + descriptor instead (replace `COMx` with the board's port): + + ```powershell + python -m esptool --chip esp32c5 -p COMx read_flash 0x10000 0x100 $env:TEMP\desc.bin + $b = [IO.File]::ReadAllBytes("$env:TEMP\desc.bin") + function S($o,$n){ [Text.Encoding]::ASCII.GetString($b,$o,$n).Trim([char]0) } + "time=" + (S 0x70 16) + " date=" + (S 0x80 16) + " idf=" + (S 0x90 32) + ``` + + `idf=v6.1...` means the board runs the production OBU (`obu-firmware`). Don't flash this beacon + over it. `idf=v5.5.4` means this transmitter, or another bench image. + +2. **Build:** + + ```powershell + idf.py build + ``` + + A rebuild after small changes takes about 1-2 minutes. The output is + `build\obu_firmware.bin`. + +3. **Flash** (the board must be on its UART bridge port or its native USB port): + + ```powershell + idf.py -p COMx flash + ``` + + The flash is good when esptool prints `Hash of data verified.`, then resets the board. + +4. **Check that it's transmitting:** + + ```powershell + idf.py -p COMx monitor + ``` + + (Exit with `Ctrl+]`.) About 1.4 s after reset you should see: + + ``` + W obu-tx: OCB @ 5900 MHz - CAM beacon armed, driving a 103-point street loop + I obu-tx: CAM sent (119 bytes) @ 5900 MHz genDeltaT=1087 pos=53.5531770,10.0220980 50.0 km/h heading 77.0 pt1 + ``` + + After that, a `CAM sent` line appears about 3 times a second, with the position, speed and + heading changing. These lines only mean each frame was + handed to the radio. To confirm the frames actually went out, capture them with a second + ESP32-C5 running the receiver firmware. + +Don't open the console of the production OBU (COM3) while the phone is attached. Opening the port +resets that board and drops the phone's USB link. The beacon boards have no phone attached, so +this doesn't apply to them. + +## Simulated drive + +The beacon pretends to be a car driving a loop through St. Georg / Berliner Tor in Hamburg, on +the real streets. The route comes from six waypoints, which you set in `tools/make_route.py`. + +**Changing the route:** edit `WAYPOINTS` in `tools/make_route.py`, then run + +```powershell +py -3.11 tools/make_route.py +``` + +The script asks the OSRM demo server (router.project-osrm.org) for a legal driving route through the +waypoints in order and back to the first, then writes three files: + +- `main/route_points.h`: the street geometry, thinned to points no more than 1.5 m off the line + (currently 103 points). +- `tools/route_osrm.json`: OSRM's raw answer. `--offline` rebuilds the header from it without the + network. +- `tools/route_map.html`: the route on an OpenStreetMap map. Open it in a browser and check it + before building. + +Then build and flash as above. Route data (c) OpenStreetMap contributors, ODbL; routing by OSRM. + +**Things to know about the routing:** +- OSRM follows one-way streets and turn bans, so the loop can be longer than the waypoints suggest. + The current one is 5.2 km, with two turn-round detours: a loop via Borgfelder Straße and + Anckelmannsplatz between wp2 and wp3, and one round Nagelsweg, Norderstraße and Repsoldstraße + between wp5 and wp6. To avoid a detour, move the waypoint on either side of it. +- Each waypoint is sent with the direction towards the next one. Without it, points on divided + roads (Beim Strohhause, for example) snap to the carriageway going the other way, and the loop + grows to 8.4 km of U-turns. + +**How the car drives** (`main/route.c`): +- **Speed:** it cruises at 50 km/h (`CRUISE_MPS` in `main/main.c`). Each bend gets a speed limit + from its radius, keeping sideways acceleration at 2 m/s², so a 90° junction turn is taken at + about 15 km/h and a gentle curve barely slows the car. It never drops below 10 km/h + (`MIN_CORNER_MPS`). It brakes at 2 m/s² and accelerates at 1.5 m/s², planning braking across as + many points as a bend needs. A lap takes about 7.7 min, averaging 40 km/h. +- **Heading:** the compass bearing of the current straight piece. It changes gradually through + curves but jumps at sharp junction turns. +- **When CAMs are sent:** following ETSI EN 302 637-2, the state is checked every 100 ms. A CAM goes + out when the heading changed by more than 4°, the position by more than 4 m, or the speed by more + than 0.5 m/s since the last one, and at least once a second. That's about 3 CAMs a second at + 50 km/h. +- **What's filled in:** position, speed and heading go into both the CAM and the GeoNetworking + source position vector. `genDeltaT` is milliseconds since boot. +- **Testing:** `route.c` only uses standard headers, so you can compile it on the PC with MSYS2 gcc + and simulate a lap. + ## CAM encoding `main/cam.c` IS compiled here (unlike `obu-firmware`'s copy, which is a @@ -44,10 +161,12 @@ hazard-light GPIO is grounded. No location/alacarte containers. - `main/main.c` - entry point, the `phy_11p_set`/`phy_change_channel(5900,...)` register hack, GPIO polling, TX loop - `main/denm.c` / `.h` - ASN.1 UPER encoding of a minimal DENM +- `main/route.c` / `.h` - simulated drive round the route loop +- `main/route_points.h` - the route, generated by `tools/make_route.py` - `main/geonet.c` / `.h` - GeoNetworking Basic/Common/SHB headers + BTP-B - `main/dot11p.c` / `.h` - 802.11 OCB (QoS Data, broadcast) frame + LLC/SNAP -Known gaps, tracked as TODOs in the source: no real GNSS (lat/long hardcoded -0), no real time source (detectionTime/referenceTime hardcoded 0, decodes as +Known gaps, tracked as TODOs in the source: no real GNSS (the CAM position comes +from the simulated drive above), no real time source (detectionTime/referenceTime hardcoded 0, decodes as 2004-01-01), fixed (non-rotating) pseudonym MAC, SHB instead of GeoBroadcast (no multi-hop forwarding), unsecured (no IEEE 1609.2 signing). diff --git a/obu-cam-transmistter/main/CMakeLists.txt b/obu-cam-transmistter/main/CMakeLists.txt index 805f53d..b107f40 100644 --- a/obu-cam-transmistter/main/CMakeLists.txt +++ b/obu-cam-transmistter/main/CMakeLists.txt @@ -1,8 +1,8 @@ # wifi_patches.c is intentionally NOT in this list anymore - superseded by # tx_custom.c (see that file for why). Left on disk, unused, for history. idf_component_register( - SRCS "main.c" "denm.c" "cam.c" "geonet.c" "dot11p.c" "tx_custom.c" + SRCS "main.c" "denm.c" "cam.c" "geonet.c" "dot11p.c" "tx_custom.c" "route.c" INCLUDE_DIRS "." - REQUIRES esp_event esp_netif nvs_flash driver esp_phy + REQUIRES esp_event esp_timer esp_netif nvs_flash driver esp_phy PRIV_REQUIRES esp_wifi ) diff --git a/obu-cam-transmistter/main/geonet.c b/obu-cam-transmistter/main/geonet.c index 418c92c..8c21add 100644 --- a/obu-cam-transmistter/main/geonet.c +++ b/obu-cam-transmistter/main/geonet.c @@ -4,6 +4,7 @@ int geonet_wrap_shb(const uint8_t *its_payload, int its_len, const uint8_t mac[6], uint8_t station_type, int32_t latitude_tenmicrodeg, int32_t longitude_tenmicrodeg, + uint16_t speed_cm_s, uint16_t heading_ddeg, uint16_t btp_dest_port, uint8_t *out, size_t out_len) { @@ -68,12 +69,12 @@ int geonet_wrap_shb(const uint8_t *its_payload, int its_len, uint32_t lon_u = (uint32_t)longitude_tenmicrodeg; *p++ = (uint8_t)(lon_u >> 24); *p++ = (uint8_t)(lon_u >> 16); *p++ = (uint8_t)(lon_u >> 8); *p++ = (uint8_t)(lon_u); - // PAI(1 bit) + Speed(15 bits), packed into 2 bytes: 0 = PAI false, - // speed 0 - which is actually correct semantics for a STATIONARY - // vehicle beacon, not just a placeholder. - *p++ = 0x00; *p++ = 0x00; - // Heading (16 bits, 0.1 degree units): 0 = due north / unavailable - *p++ = 0x00; *p++ = 0x00; + // PAI(1 bit) + Speed(15 bits, signed, 0.01 m/s), packed into 2 bytes. PAI stays 0: the + // position has no accuracy estimate behind it. + uint16_t spd = speed_cm_s > 0x7FFF ? 0x7FFF : speed_cm_s; + *p++ = (uint8_t)(spd >> 8); *p++ = (uint8_t)(spd & 0xFF); + // Heading (16 bits, 0.1 degree units, clockwise from north) + *p++ = (uint8_t)(heading_ddeg >> 8); *p++ = (uint8_t)(heading_ddeg & 0xFF); // Reserved (4 bytes) - clause 9.8.4: the SHB extended header is the 24-byte Source Position // Vector FOLLOWED BY a 4-byte reserved field (media-dependent data), 28 bytes in total. These // four bytes were missing, which is why a standards-compliant receiver read our CAM payload's diff --git a/obu-cam-transmistter/main/geonet.h b/obu-cam-transmistter/main/geonet.h index 22a5531..cf6f43d 100644 --- a/obu-cam-transmistter/main/geonet.h +++ b/obu-cam-transmistter/main/geonet.h @@ -31,6 +31,10 @@ // working (same extended header shape as CAM). Fine for a single-vehicle // beacon; revisit if you need real multi-hop forwarding later. // +// `speed_cm_s` (0.01 m/s) and `heading_ddeg` (0.1 deg) also go into the Source Long Position +// Vector; pass the same values as the CAM's high-frequency container. Speed is a 15-bit field, so +// values above 32767 are clamped. +// // `btp_dest_port` is the BTP-B destination port for the service being carried // (ETSI TS 103 248): 2001 = CAM, 2002 = DENM, 2003 = MAPEM, 2004 = SPATEM, ... // @@ -38,6 +42,7 @@ int geonet_wrap_shb(const uint8_t *its_payload, int its_len, const uint8_t mac[6], uint8_t station_type, int32_t latitude_tenmicrodeg, int32_t longitude_tenmicrodeg, + uint16_t speed_cm_s, uint16_t heading_ddeg, uint16_t btp_dest_port, uint8_t *out, size_t out_len); diff --git a/obu-cam-transmistter/main/main.c b/obu-cam-transmistter/main/main.c index 8fa708c..1825c05 100644 --- a/obu-cam-transmistter/main/main.c +++ b/obu-cam-transmistter/main/main.c @@ -1,7 +1,11 @@ #include #include +#include +#include +#include #include "freertos/FreeRTOS.h" #include "freertos/task.h" +#include "esp_timer.h" #include "driver/gpio.h" #include "esp_wifi.h" #include "esp_event.h" @@ -14,13 +18,17 @@ #include "geonet.h" #include "dot11p.h" #include "tx_custom.h" +#include "route.h" +#include "route_points.h" static const char *TAG = "obu-tx"; -// CAM beacon: transmit a Cooperative Awareness Message every TX_INTERVAL_MS, -// unconditionally (no hazard-light gating - CAM is a continuous beacon, unlike -// the event-triggered DENM). Matches the working Rust reference -// (esp32-c_its-companion, feat/tx-cam), which beacons CAM on 5900 MHz. +// CAM beacon for a simulated car driving round a block in Hamburg (see route.c). The CAM +// generation rules follow ETSI EN 302 637-2 clause 6.1.3: every CHECK_INTERVAL_MS the car's state +// is compared with the last CAM sent, and a new CAM goes out when the heading changed by more than +// 4 degrees, the position by more than 4 m, the speed by more than 0.5 m/s, or 1 s has passed. +// There is no hazard-light gating - CAM is a continuous beacon, unlike the event-triggered DENM. +// Transmits on 5900 MHz like the working Rust reference (esp32-c_its-companion, feat/tx-cam). // ISOLATION TEST for whether tx_custom.c is the blocker. // 1 = transmit via the STANDARD, well-tested esp_wifi_80211_tx() using a @@ -55,15 +63,19 @@ static const char *TAG = "obu-tx"; #define VEHICLE_LENGTH_DM 40 // VehicleLengthValue, 10cm steps (4.0 m) #define VEHICLE_WIDTH_DM 18 // VehicleWidth, 10cm steps (1.8 m) #define BTP_PORT_CAM 2001 // BTP-B destination port for CAM (ETSI TS 103 248) -#define TX_INTERVAL_MS 1000 // CAM beacon period (1 Hz; ITS allows 1-10 Hz) +#define CHECK_INTERVAL_MS 100 // T_CheckCamGen: how often the generation rules are evaluated +#define CAM_MAX_INTERVAL_MS 1000 // T_GenCamMax: a CAM goes out at least this often +#define CAM_HEADING_DDEG 40 // > 4 degrees heading change triggers a CAM +#define CAM_POSITION_M 4.0 // > 4 m position change triggers a CAM +#define CAM_SPEED_CM_S 50 // > 0.5 m/s speed change triggers a CAM -// Bench location, hardcoded since there's no GNSS module wired in yet and -// the unit is genuinely stationary here: 53°33'16.8"N 10°01'20.6"E, in -// 1/10-microdegree units (decimal_degrees * 10,000,000). Replace with real -// GNSS output once you have a fix source; until then this beats 0/0 -// ("Null Island"), which is an obvious placeholder-tell on any map. -#define BENCH_LATITUDE_TENMICRODEG 535546667 -#define BENCH_LONGITUDE_TENMICRODEG 100223889 +// ---- Simulated drive ---- +// route_points (main/route_points.h) is the street geometry of a driving loop through six waypoints +// in St. Georg, generated by tools/make_route.py from OpenStreetMap via OSRM. To change the route, +// edit WAYPOINTS in that script and rerun it. No GNSS is wired in; replace with real fixes once +// there is one. +#define CRUISE_MPS (50.0 / 3.6) // 50 km/h, the urban limit +#define MIN_CORNER_MPS (10.0 / 3.6) // slowest the car goes, for hairpins and U-turns // Single source of truth for the pseudonym/link-layer address: used both as // the 802.11 source MAC (Addr2) and as GN_ADDR's MID field, since the GN @@ -78,33 +90,28 @@ static const uint8_t pseudonym_mac[6] = {0x02, 0x00, 0x00, 0x00, 0x00, 0x01}; extern void phy_11p_set(int enable, int unused); extern void phy_change_channel(int freq_mhz, int bw_mode, int sec_chan_offset, int unused); -static void send_cam(void) +static void send_cam(const route_state_t *car, uint16_t gen_delta) { - // GenerationDeltaTime is TimestampIts mod 65536 (ms). No RTC/GNSS time here, - // so use a free-running ms counter that advances one beacon-interval per - // send. It wraps at 65536, which is exactly the field's defined behaviour. - static uint16_t gen_delta = 0; - uint8_t frame[300]; cam_fields_t fields = { .station_id = STATION_ID, .station_type = STATION_TYPE, .generation_delta_time = gen_delta, - .latitude_tenmicrodeg = BENCH_LATITUDE_TENMICRODEG, - .longitude_tenmicrodeg = BENCH_LONGITUDE_TENMICRODEG, - .speed_cm_s = 0, // stationary - .heading_ddeg = 3601, // HeadingValue unavailable (no heading source) + .latitude_tenmicrodeg = car->latitude_tenmicrodeg, + .longitude_tenmicrodeg = car->longitude_tenmicrodeg, + .speed_cm_s = car->speed_cm_s, + .heading_ddeg = car->heading_ddeg, .vehicle_length_dm = VEHICLE_LENGTH_DM, .vehicle_width_dm = VEHICLE_WIDTH_DM, }; - gen_delta += TX_INTERVAL_MS; uint8_t cam_payload[96]; int cam_len = cam_encode(&fields, cam_payload, sizeof(cam_payload)); uint8_t gn_payload[160]; int gn_len = geonet_wrap_shb(cam_payload, cam_len, pseudonym_mac, STATION_TYPE, - BENCH_LATITUDE_TENMICRODEG, BENCH_LONGITUDE_TENMICRODEG, + car->latitude_tenmicrodeg, car->longitude_tenmicrodeg, + car->speed_cm_s, car->heading_ddeg, BTP_PORT_CAM, gn_payload, sizeof(gn_payload)); // qos=false for the standard-TX path (esp_wifi_80211_tx accepts only non-QoS @@ -127,7 +134,10 @@ static void send_cam(void) if (err != ESP_OK) { ESP_LOGW(TAG, "esp_wifi_80211_tx (standard) failed: %d", err); } else { - ESP_LOGI(TAG, "CAM sent via STANDARD tx (%d bytes) @ %d MHz genDeltaT=%u", frame_len, TX_FREQ_MHZ, gen_delta); + ESP_LOGI(TAG, "CAM sent (%d bytes) @ %d MHz genDeltaT=%u pos=%.7f,%.7f %.1f km/h heading %.1f pt%d", + frame_len, TX_FREQ_MHZ, gen_delta, + car->latitude_tenmicrodeg / 1e7, car->longitude_tenmicrodeg / 1e7, + car->speed_cm_s * 0.036, car->heading_ddeg / 10.0, car->segment + 1); } #else // tx_custom path: submits to the driver's internal HMAC TX path, @@ -151,12 +161,49 @@ static void send_cam(void) } } +static bool cam_due(const route_state_t *car, const route_state_t *last, int64_t since_last_ms) +{ + if (since_last_ms >= CAM_MAX_INTERVAL_MS) { + return true; + } + int dh = abs((int)car->heading_ddeg - (int)last->heading_ddeg); + if (dh > 1800) { + dh = 3600 - dh; + } + if (dh > CAM_HEADING_DDEG) { + return true; + } + if (abs((int)car->speed_cm_s - (int)last->speed_cm_s) > CAM_SPEED_CM_S) { + return true; + } + // Flat-earth distance is plenty for a 4 m threshold. + double north_m = (car->latitude_tenmicrodeg - last->latitude_tenmicrodeg) * 0.0111194930; + double east_m = (car->longitude_tenmicrodeg - last->longitude_tenmicrodeg) * 0.0111194930 + * cos(car->latitude_tenmicrodeg / 1e7 * M_PI / 180.0); + return north_m * north_m + east_m * east_m > CAM_POSITION_M * CAM_POSITION_M; +} + static void tx_task(void *arg) { + route_state_t car; + route_state_t last_sent; + int64_t last_sent_ms = 0; + bool sent_any = false; + TickType_t wake = xTaskGetTickCount(); + + route_step(0.0, &car); while (1) { - // CAM is a continuous beacon - send every interval, unconditionally. - send_cam(); - vTaskDelay(pdMS_TO_TICKS(TX_INTERVAL_MS)); + int64_t now_ms = esp_timer_get_time() / 1000; + if (!sent_any || cam_due(&car, &last_sent, now_ms - last_sent_ms)) { + // GenerationDeltaTime is TimestampIts mod 65536 (ms). No real clock here, so use + // milliseconds since boot, which advances at the right rate. + send_cam(&car, (uint16_t)now_ms); + last_sent = car; + last_sent_ms = now_ms; + sent_any = true; + } + vTaskDelayUntil(&wake, pdMS_TO_TICKS(CHECK_INTERVAL_MS)); + route_step(CHECK_INTERVAL_MS / 1000.0, &car); } } @@ -255,8 +302,13 @@ void app_main(void) phy_change_channel(TX_FREQ_MHZ, 1, 0, 0); ESP_LOGI(TAG, "phy_change_channel returned"); - ESP_LOGW(TAG, "OCB @ %d MHz - CAM beacon armed, transmitting every %d ms", - TX_FREQ_MHZ, TX_INTERVAL_MS); + if (route_init(route_points, sizeof(route_points) / sizeof(route_points[0]), + CRUISE_MPS, MIN_CORNER_MPS) != 0) { + ESP_LOGE(TAG, "route_init failed - check route_points"); + return; + } + ESP_LOGW(TAG, "OCB @ %d MHz - CAM beacon armed, driving a %d-point street loop", + TX_FREQ_MHZ, (int)(sizeof(route_points) / sizeof(route_points[0]))); xTaskCreate(tx_task, "tx_task", 4096, NULL, 5, NULL); } diff --git a/obu-cam-transmistter/main/route.c b/obu-cam-transmistter/main/route.c new file mode 100644 index 0000000..831bec5 --- /dev/null +++ b/obu-cam-transmistter/main/route.c @@ -0,0 +1,125 @@ +#include "route.h" +#include + +#define DEG_TO_RAD (M_PI / 180.0) +#define METRES_PER_DEG 111194.93 // mean Earth radius 6371 km; a block is small enough for a flat projection +#define ACCEL_MPS2 1.5 // pulling away from a corner +#define DECEL_MPS2 2.0 // braking ahead of a corner +#define LATERAL_MPS2 2.0 // sideways acceleration a normal driver takes a bend at +#define STRAIGHT_DEG 3.0 // kinks gentler than this are digitising noise, not bends +#define BEND_SPAN_M 15.0 // longest segment counted towards a bend's radius (see route_init) + +static const route_point_t *s_pts; +static int s_n; +static double s_len[ROUTE_MAX_POINTS]; // segment i runs from point i to point (i+1) % n +static double s_bearing_deg[ROUTE_MAX_POINTS]; +static double s_corner_mps[ROUTE_MAX_POINTS]; // speed limit at point i, where segment i starts +static double s_cruise_mps; +static int s_seg; +static double s_pos_m; // distance along the current segment + +static double segment_speed(int seg, double pos_m) +{ + double v = s_cruise_mps; + double pull_away = sqrt(s_corner_mps[seg] * s_corner_mps[seg] + 2.0 * ACCEL_MPS2 * pos_m); + int next = (seg + 1) % s_n; + double braking = sqrt(s_corner_mps[next] * s_corner_mps[next] + + 2.0 * DECEL_MPS2 * (s_len[seg] - pos_m)); + if (pull_away < v) v = pull_away; + if (braking < v) v = braking; + return v; +} + +int route_init(const route_point_t *points, int n, double cruise_mps, double min_corner_mps) +{ + if (n < 2 || n > ROUTE_MAX_POINTS) { + return -1; + } + s_pts = points; + s_n = n; + s_cruise_mps = cruise_mps; + + for (int i = 0; i < n; i++) { + const route_point_t *a = &points[i]; + const route_point_t *b = &points[(i + 1) % n]; + double mid_lat = (a->latitude_tenmicrodeg + (double)b->latitude_tenmicrodeg) / 2e7; + double north_m = (b->latitude_tenmicrodeg - a->latitude_tenmicrodeg) / 1e7 * METRES_PER_DEG; + double east_m = (b->longitude_tenmicrodeg - a->longitude_tenmicrodeg) / 1e7 * METRES_PER_DEG + * cos(mid_lat * DEG_TO_RAD); + s_len[i] = sqrt(north_m * north_m + east_m * east_m); + if (s_len[i] < 0.01) { + return -1; + } + double bearing = atan2(east_m, north_m) / DEG_TO_RAD; + s_bearing_deg[i] = bearing < 0 ? bearing + 360.0 : bearing; + } + + // Speed limit at each point from how tight the bend there is. A polyline bend of angle theta + // between segments of length L approximates an arc of radius L / theta, and a car takes a + // radius R at sqrt(a_lat * R). L is capped at BEND_SPAN_M: at a junction the two streets can be + // hundreds of metres long, but the car still turns within the width of the crossing. + for (int i = 0; i < n; i++) { + double turn = fabs(s_bearing_deg[i] - s_bearing_deg[(i + n - 1) % n]); + if (turn > 180.0) { + turn = 360.0 - turn; + } + double v = cruise_mps; + if (turn > STRAIGHT_DEG) { + double span = s_len[(i + n - 1) % n] < s_len[i] ? s_len[(i + n - 1) % n] : s_len[i]; + if (span > BEND_SPAN_M) { + span = BEND_SPAN_M; + } + v = sqrt(LATERAL_MPS2 * span / (turn * DEG_TO_RAD)); + } + if (v > cruise_mps) v = cruise_mps; + if (v < min_corner_mps) v = min_corner_mps; + s_corner_mps[i] = v; + } + + // A point's limit also has to respect the bends after it (the car must be able to brake for + // them within the segments in between) and before it (it can only have sped up so much since). + // segment_speed only looks at the two ends of a segment, so settle this here. Limits only ever + // go down, so repeating the two passes until nothing changes terminates. + for (int changed = 1; changed;) { + changed = 0; + for (int k = 0; k < 2 * n; k++) { + int i = (2 * n - 1 - k) % n; // backwards: braking + int next = (i + 1) % n; + double v = sqrt(s_corner_mps[next] * s_corner_mps[next] + 2.0 * DECEL_MPS2 * s_len[i]); + if (v < s_corner_mps[i] - 1e-9) { s_corner_mps[i] = v; changed = 1; } + } + for (int k = 0; k < 2 * n; k++) { + int i = k % n; // forwards: accelerating + int next = (i + 1) % n; + double v = sqrt(s_corner_mps[i] * s_corner_mps[i] + 2.0 * ACCEL_MPS2 * s_len[i]); + if (v < s_corner_mps[next] - 1e-9) { s_corner_mps[next] = v; changed = 1; } + } + } + + s_seg = 0; + s_pos_m = 0.0; + return 0; +} + +void route_step(double dt_s, route_state_t *out) +{ + // Advance with the speed at the start of the step; at 100 ms steps the error is well under a metre. + double d = segment_speed(s_seg, s_pos_m) * dt_s; + while (s_pos_m + d >= s_len[s_seg]) { + d -= s_len[s_seg] - s_pos_m; + s_seg = (s_seg + 1) % s_n; + s_pos_m = 0.0; + } + s_pos_m += d; + + const route_point_t *a = &s_pts[s_seg]; + const route_point_t *b = &s_pts[(s_seg + 1) % s_n]; + double f = s_pos_m / s_len[s_seg]; + out->latitude_tenmicrodeg = (int32_t)lround(a->latitude_tenmicrodeg + + f * (b->latitude_tenmicrodeg - a->latitude_tenmicrodeg)); + out->longitude_tenmicrodeg = (int32_t)lround(a->longitude_tenmicrodeg + + f * (b->longitude_tenmicrodeg - a->longitude_tenmicrodeg)); + out->speed_cm_s = (uint16_t)lround(segment_speed(s_seg, s_pos_m) * 100.0); + out->heading_ddeg = (uint16_t)(lround(s_bearing_deg[s_seg] * 10.0) % 3600); + out->segment = s_seg; +} diff --git a/obu-cam-transmistter/main/route.h b/obu-cam-transmistter/main/route.h new file mode 100644 index 0000000..5bd61bb --- /dev/null +++ b/obu-cam-transmistter/main/route.h @@ -0,0 +1,40 @@ +#ifndef ROUTE_H +#define ROUTE_H +#include + +// Simulated drive around a closed loop of waypoints, so the beacon looks like a +// car going round the block instead of a parked one. +// +// The car follows straight lines between the points and goes from the last one +// back to the first, forever. For street-following, the points are the street +// geometry from tools/make_route.py (main/route_points.h). Speed is a function +// of where the car is on a segment: it cruises, brakes ahead of each bend down to +// the speed that bend allows, and accelerates away after it. Heading is the +// bearing of the current segment. +// +// Uses only standard headers, so it also compiles on the host for testing. + +typedef struct { + int32_t latitude_tenmicrodeg; // 1/10 microdegree, same units as the CAM + int32_t longitude_tenmicrodeg; +} route_point_t; + +typedef struct { + int32_t latitude_tenmicrodeg; + int32_t longitude_tenmicrodeg; + uint16_t speed_cm_s; // SpeedValue units (0.01 m/s) + uint16_t heading_ddeg; // HeadingValue units (0.1 deg, 0..3599, 0 = north, clockwise) + int segment; // index of the route point the car last passed +} route_state_t; + +#define ROUTE_MAX_POINTS 512 // keep in step with MAX_POINTS in tools/make_route.py + +// `points` must stay valid for as long as the route is used. Returns 0, or -1 +// if n is out of range (2..ROUTE_MAX_POINTS) or a segment has zero length. +// min_corner_mps is the slowest the car ever goes (hairpins, U-turns). +int route_init(const route_point_t *points, int n, double cruise_mps, double min_corner_mps); + +// Moves the car on by dt_s seconds and writes its new position into `out`. +void route_step(double dt_s, route_state_t *out); + +#endif diff --git a/obu-cam-transmistter/main/route_points.h b/obu-cam-transmistter/main/route_points.h new file mode 100644 index 0000000..aa6ccd6 --- /dev/null +++ b/obu-cam-transmistter/main/route_points.h @@ -0,0 +1,116 @@ +// GENERATED by tools/make_route.py - do not edit by hand; change WAYPOINTS there and rerun. +// Route data (c) OpenStreetMap contributors, ODbL. Routing by OSRM. +// +// Driving loop through 6 waypoints: 5179 m (legs 147 m, 1837 m, 381 m, 819 m, 1234 m, 761 m), 103 points after +// simplifying to 1.5 m. Streets: Beim Strohhause, Berlinertordamm, Berliner Tor, Bei der Hauptfeuerwache, Westphalensweg, Berliner Tor, Berlinertordamm, Borgfelder Straße, Anckelmannstraße, Anckelmannsplatz, Bürgerweide, Wallstraße, Lübeckertordamm, Steindamm, Kreuzweg, Adenauerallee, Nagelsweg, Norderstraße, Repsoldstraße, Kurt-Schumacher-Allee, Kreuzweg, Adenauerallee, Kurt-Schumacher-Allee, Beim Strohhause. +#ifndef ROUTE_POINTS_H +#define ROUTE_POINTS_H +#include "route.h" + +static const route_point_t route_points[] = { + { 535531770, 100220980 }, + { 535534470, 100240600 }, + { 535535790, 100244160 }, + { 535536400, 100244520 }, + { 535537130, 100244160 }, + { 535538480, 100242840 }, + { 535538720, 100242140 }, + { 535540390, 100240200 }, + { 535548880, 100233930 }, + { 535549470, 100235130 }, + { 535554140, 100253280 }, + { 535553570, 100254580 }, + { 535546070, 100251700 }, + { 535543130, 100250020 }, + { 535542570, 100249130 }, + { 535542760, 100247800 }, + { 535539980, 100244600 }, + { 535538720, 100242140 }, + { 535538140, 100241960 }, + { 535535720, 100243380 }, + { 535535300, 100244470 }, + { 535535090, 100246580 }, + { 535536830, 100264460 }, + { 535537600, 100270920 }, + { 535538520, 100275220 }, + { 535541110, 100290830 }, + { 535540170, 100291550 }, + { 535539890, 100294430 }, + { 535539580, 100295330 }, + { 535532290, 100299300 }, + { 535527980, 100302450 }, + { 535525130, 100291880 }, + { 535524220, 100289760 }, + { 535522900, 100287820 }, + { 535522890, 100285300 }, + { 535522610, 100282810 }, + { 535520620, 100276050 }, + { 535519820, 100271130 }, + { 535519670, 100269030 }, + { 535520220, 100267120 }, + { 535520930, 100262840 }, + { 535521850, 100260020 }, + { 535522840, 100258210 }, + { 535527790, 100257880 }, + { 535538650, 100261370 }, + { 535551660, 100266470 }, + { 535555790, 100268750 }, + { 535559620, 100271540 }, + { 535561120, 100272050 }, + { 535562430, 100271250 }, + { 535563830, 100269390 }, + { 535569610, 100260190 }, + { 535579530, 100242810 }, + { 535584090, 100237660 }, + { 535585850, 100234670 }, + { 535584970, 100230060 }, + { 535584000, 100227260 }, + { 535580730, 100222030 }, + { 535579100, 100218590 }, + { 535574500, 100208430 }, + { 535570560, 100199010 }, + { 535568130, 100194820 }, + { 535564910, 100187620 }, + { 535563990, 100184630 }, + { 535562540, 100181160 }, + { 535559780, 100176310 }, + { 535542180, 100136840 }, + { 535539720, 100133430 }, + { 535537350, 100132010 }, + { 535534760, 100131390 }, + { 535523840, 100132690 }, + { 535524980, 100155090 }, + { 535524890, 100156360 }, + { 535524440, 100157650 }, + { 535523030, 100158530 }, + { 535517610, 100158580 }, + { 535504440, 100168810 }, + { 535501360, 100156400 }, + { 535499250, 100144880 }, + { 535498470, 100133880 }, + { 535498630, 100126150 }, + { 535499110, 100121980 }, + { 535504260, 100117230 }, + { 535505720, 100115500 }, + { 535507630, 100112310 }, + { 535508400, 100111560 }, + { 535510000, 100110940 }, + { 535511390, 100119560 }, + { 535512440, 100122280 }, + { 535514510, 100132770 }, + { 535515020, 100134120 }, + { 535516630, 100135630 }, + { 535518260, 100136100 }, + { 535523950, 100134870 }, + { 535524980, 100155090 }, + { 535524890, 100156360 }, + { 535524440, 100157650 }, + { 535523470, 100158460 }, + { 535518560, 100158480 }, + { 535519070, 100162430 }, + { 535522260, 100178080 }, + { 535527880, 100197650 }, + { 535530060, 100209020 }, +}; + +#endif diff --git a/obu-cam-transmistter/tools/make_route.py b/obu-cam-transmistter/tools/make_route.py new file mode 100644 index 0000000..f78fd7b --- /dev/null +++ b/obu-cam-transmistter/tools/make_route.py @@ -0,0 +1,170 @@ +"""Turn the beacon's waypoints into a street-following route for main/route_points.h. + +Asks the OSRM demo server (router.project-osrm.org, OpenStreetMap data) for a driving route that +visits WAYPOINTS in order and returns to the first, thins the street geometry out, and writes: + + main/route_points.h the C array the firmware drives (commit this) + tools/route_osrm.json the raw OSRM answer, so the header can be regenerated offline (--offline) + tools/route_map.html the route over an OpenStreetMap map, to check it before flashing + +Each waypoint also gets a bearing (the direction towards the next waypoint), so OSRM snaps it onto +the carriageway going that way. Without it, points on divided roads land on the wrong side and +every leg grows a U-turn detour. + +Usage (Python 3.8+, standard library only): + py tools/make_route.py fetch from OSRM, then write all three files + py -3 tools/make_route.py --offline rebuild from the saved route_osrm.json + +Route data (c) OpenStreetMap contributors, ODbL. Routing by OSRM. +""" +import argparse +import json +import math +import pathlib +import urllib.request + +# (latitude, longitude) in decimal degrees, in driving order. The route closes back to the first. +WAYPOINTS = [ + (53.553309, 10.022043), + (53.553611, 10.024146), + (53.556164, 10.027121), + (53.558310, 10.023362), + (53.554062, 10.013515), + (53.551540, 10.013398), +] +BEARING_TOLERANCE_DEG = 60 # how far the road's direction may differ from the waypoint bearing +SIMPLIFY_M = 1.5 # drop points that move the line by less than this +MAX_POINTS = 512 # must match ROUTE_MAX_POINTS in main/route.h + +HERE = pathlib.Path(__file__).resolve().parent +PROJECT = HERE.parent +OSRM_JSON = HERE / "route_osrm.json" +HEADER = PROJECT / "main" / "route_points.h" +MAP_HTML = HERE / "route_map.html" +METRES_PER_DEG = 111194.93 + + +def to_xy(lat, lon, lat0): + return (lon * METRES_PER_DEG * math.cos(math.radians(lat0)), lat * METRES_PER_DEG) + + +def bearing(a, b): + north = b[0] - a[0] + east = (b[1] - a[1]) * math.cos(math.radians(a[0])) + return math.degrees(math.atan2(east, north)) % 360 + + +def fetch(): + n = len(WAYPOINTS) + pts = WAYPOINTS + [WAYPOINTS[0]] + bearings = [round(bearing(WAYPOINTS[i], WAYPOINTS[(i + 1) % n])) for i in range(n)] + bearings.append(bearings[0]) + url = ("https://router.project-osrm.org/route/v1/driving/" + + ";".join(f"{lon},{lat}" for lat, lon in pts) + + "?overview=full&geometries=geojson&steps=true&bearings=" + + ";".join(f"{b},{BEARING_TOLERANCE_DEG}" for b in bearings)) + req = urllib.request.Request(url, headers={"User-Agent": "MicrOBU-route-tool"}) + with urllib.request.urlopen(req, timeout=30) as resp: + data = json.load(resp) + if data.get("code") != "Ok": + raise SystemExit(f"OSRM error: {data.get('code')} {data.get('message')}") + OSRM_JSON.write_text(json.dumps(data, indent=1), encoding="utf-8") + return data + + +def simplify(xy, tol): + """Douglas-Peucker, iterative. Keeps the first and last point.""" + keep = [False] * len(xy) + keep[0] = keep[-1] = True + stack = [(0, len(xy) - 1)] + while stack: + a, b = stack.pop() + (ax, ay), (bx, by) = xy[a], xy[b] + dx, dy = bx - ax, by - ay + seg2 = dx * dx + dy * dy + worst, worst_d = -1, tol + for i in range(a + 1, b): + px, py = xy[i] + if seg2 == 0: + d = math.hypot(px - ax, py - ay) + else: + t = max(0.0, min(1.0, ((px - ax) * dx + (py - ay) * dy) / seg2)) + d = math.hypot(px - ax - t * dx, py - ay - t * dy) + if d > worst_d: + worst, worst_d = i, d + if worst >= 0: + keep[worst] = True + stack += [(a, worst), (worst, b)] + return [i for i, k in enumerate(keep) if k] + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--offline", action="store_true", help="use the saved route_osrm.json") + args = ap.parse_args() + data = json.loads(OSRM_JSON.read_text(encoding="utf-8")) if args.offline else fetch() + route = data["routes"][0] + + # GeoJSON is [lon, lat]; round to the CAM's 1/10-microdegree grid and drop repeats. + raw = [] + for lon, lat in route["geometry"]["coordinates"]: + p = (round(lat * 1e7), round(lon * 1e7)) + if not raw or p != raw[-1]: + raw.append(p) + if raw[0] == raw[-1]: + raw.pop() + closed = raw + [raw[0]] + lat0 = closed[0][0] / 1e7 + xy = [to_xy(p[0] / 1e7, p[1] / 1e7, lat0) for p in closed] + pts = [closed[i] for i in simplify(xy, SIMPLIFY_M)][:-1] + if len(pts) > MAX_POINTS: + raise SystemExit(f"{len(pts)} points is more than MAX_POINTS={MAX_POINTS}; raise SIMPLIFY_M") + + streets = [] + for leg in route["legs"]: + for step in leg["steps"]: + if step["name"] and (not streets or streets[-1] != step["name"]): + streets.append(step["name"]) + legs = ", ".join(f"{round(l['distance'])} m" for l in route["legs"]) + + lines = [ + "// GENERATED by tools/make_route.py - do not edit by hand; change WAYPOINTS there and rerun.", + "// Route data (c) OpenStreetMap contributors, ODbL. Routing by OSRM.", + "//", + f"// Driving loop through {len(WAYPOINTS)} waypoints: {round(route['distance'])} m " + f"(legs {legs}), {len(pts)} points after", + f"// simplifying to {SIMPLIFY_M} m. Streets: {', '.join(streets)}.", + "#ifndef ROUTE_POINTS_H", + "#define ROUTE_POINTS_H", + '#include "route.h"', + "", + "static const route_point_t route_points[] = {", + ] + lines += [f" {{ {lat}, {lon} }}," for lat, lon in pts] + lines += ["};", "", "#endif", ""] + HEADER.write_text("\n".join(lines), encoding="utf-8", newline="\n") + + MAP_HTML.write_text(f"""Beacon route + + +
+""", encoding="utf-8") + + print(f"{round(route['distance'])} m, legs {legs}") + print(f"{len(route['geometry']['coordinates'])} OSRM points -> {len(pts)} after simplifying") + print(f"wrote {HEADER.relative_to(PROJECT)}, {OSRM_JSON.relative_to(PROJECT)}, " + f"{MAP_HTML.relative_to(PROJECT)}") + + +if __name__ == "__main__": + main() diff --git a/obu-cam-transmistter/tools/route_map.html b/obu-cam-transmistter/tools/route_map.html new file mode 100644 index 0000000..f483dd8 --- /dev/null +++ b/obu-cam-transmistter/tools/route_map.html @@ -0,0 +1,14 @@ +Beacon route + + +
diff --git a/obu-cam-transmistter/tools/route_osrm.json b/obu-cam-transmistter/tools/route_osrm.json new file mode 100644 index 0000000..c7963f9 --- /dev/null +++ b/obu-cam-transmistter/tools/route_osrm.json @@ -0,0 +1,5893 @@ +{ + "code": "Ok", + "routes": [ + { + "legs": [ + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 76 + ], + "location": [ + 10.022098, + 53.553177 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.022098, + 53.553177 + ], + [ + 10.023259, + 53.553346 + ], + [ + 10.023467, + 53.553373 + ], + [ + 10.023585, + 53.553388 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 76, + "bearing_before": 0, + "location": [ + 10.022098, + 53.553177 + ], + "modifier": "left", + "type": "depart" + }, + "name": "Beim Strohhause", + "mode": "driving", + "weight": 9.1, + "duration": 9.1, + "distance": 101.3 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "none" + ] + } + ], + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 75, + 165, + 255 + ], + "location": [ + 10.023585, + 53.553388 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.023585, + 53.553388 + ], + [ + 10.02406, + 53.553447 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 77, + "bearing_before": 75, + "location": [ + 10.023585, + 53.553388 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Berlinertordamm", + "mode": "driving", + "weight": 4.9, + "duration": 4.9, + "distance": 32.1 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "none" + ] + } + ], + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 60, + 75, + 255 + ], + "location": [ + 10.02406, + 53.553447 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.02406, + 53.553447 + ], + [ + 10.024244, + 53.553509 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 59, + "bearing_before": 77, + "location": [ + 10.02406, + 53.553447 + ], + "modifier": "slight left", + "type": "turn" + }, + "name": "Berliner Tor", + "mode": "driving", + "weight": 1.9, + "duration": 1.9, + "distance": 14 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 240 + ], + "location": [ + 10.024244, + 53.553509 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.024244, + 53.553509 + ], + [ + 10.024244, + 53.553509 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 0, + "bearing_before": 60, + "location": [ + 10.024244, + 53.553509 + ], + "modifier": "left", + "type": "arrive" + }, + "name": "Berliner Tor", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 15.9, + "summary": "Beim Strohhause, Berlinertordamm", + "duration": 15.9, + "distance": 147.4 + }, + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 60 + ], + "location": [ + 10.024244, + 53.553509 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + false, + false, + false + ], + "bearings": [ + 45, + 105, + 240, + 315 + ], + "location": [ + 10.024372, + 53.553556 + ] + }, + { + "out": 0, + "in": 1, + "entry": [ + true, + false, + false + ], + "bearings": [ + 0, + 225, + 255 + ], + "location": [ + 10.024442, + 53.55361 + ] + }, + { + "out": 2, + "in": 1, + "entry": [ + true, + false, + true + ], + "bearings": [ + 60, + 150, + 330 + ], + "location": [ + 10.024214, + 53.553872 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.024244, + 53.553509 + ], + [ + 10.024338, + 53.553541 + ], + [ + 10.024372, + 53.553556 + ], + [ + 10.024416, + 53.553579 + ], + [ + 10.024442, + 53.55361 + ], + [ + 10.024452, + 53.55364 + ], + [ + 10.024444, + 53.553668 + ], + [ + 10.024416, + 53.553713 + ], + [ + 10.024284, + 53.553848 + ], + [ + 10.024214, + 53.553872 + ], + [ + 10.02402, + 53.554039 + ], + [ + 10.02392, + 53.554169 + ], + [ + 10.023394, + 53.55486 + ], + [ + 10.02339, + 53.554868 + ], + [ + 10.023389, + 53.554875 + ], + [ + 10.023391, + 53.554882 + ], + [ + 10.023393, + 53.554888 + ], + [ + 10.023402, + 53.554899 + ], + [ + 10.023409, + 53.554905 + ], + [ + 10.023417, + 53.55491 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 60, + "bearing_before": 0, + "location": [ + 10.024244, + 53.553509 + ], + "modifier": "left", + "type": "depart" + }, + "name": "Berliner Tor", + "mode": "driving", + "weight": 17.5, + "duration": 17.5, + "distance": 181.4 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [ + true, + false + ], + "bearings": [ + 45, + 225 + ], + "location": [ + 10.023417, + 53.55491 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.023417, + 53.55491 + ], + [ + 10.023452, + 53.554926 + ], + [ + 10.023513, + 53.554947 + ], + [ + 10.023904, + 53.555049 + ], + [ + 10.024202, + 53.555127 + ], + [ + 10.024293, + 53.555152 + ], + [ + 10.024843, + 53.555297 + ], + [ + 10.024898, + 53.555313 + ], + [ + 10.02501, + 53.555344 + ], + [ + 10.025228, + 53.555401 + ], + [ + 10.025328, + 53.555414 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 52, + "bearing_before": 37, + "location": [ + 10.023417, + 53.55491 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Bei der Hauptfeuerwache", + "mode": "driving", + "weight": 12.7, + "duration": 12.7, + "distance": 138.7 + }, + { + "intersections": [ + { + "out": 1, + "in": 3, + "entry": [ + true, + true, + false, + false + ], + "bearings": [ + 15, + 120, + 195, + 255 + ], + "location": [ + 10.025328, + 53.555414 + ] + }, + { + "out": 1, + "in": 2, + "entry": [ + false, + true, + false + ], + "bearings": [ + 15, + 195, + 300 + ], + "location": [ + 10.025458, + 53.555357 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.025328, + 53.555414 + ], + [ + 10.025355, + 53.55541 + ], + [ + 10.02538, + 53.555403 + ], + [ + 10.0254, + 53.555395 + ], + [ + 10.025424, + 53.555383 + ], + [ + 10.025437, + 53.555373 + ], + [ + 10.025458, + 53.555357 + ], + [ + 10.025287, + 53.554915 + ], + [ + 10.02517, + 53.554607 + ], + [ + 10.025107, + 53.554482 + ], + [ + 10.025047, + 53.554384 + ], + [ + 10.025002, + 53.554313 + ], + [ + 10.024986, + 53.554292 + ], + [ + 10.024973, + 53.55428 + ], + [ + 10.02496, + 53.554272 + ], + [ + 10.024946, + 53.554266 + ], + [ + 10.024928, + 53.55426 + ], + [ + 10.024913, + 53.554257 + ], + [ + 10.024897, + 53.554255 + ], + [ + 10.024875, + 53.554255 + ], + [ + 10.02485, + 53.554258 + ], + [ + 10.02478, + 53.554276 + ], + [ + 10.024724, + 53.554216 + ], + [ + 10.024651, + 53.554152 + ], + [ + 10.024547, + 53.554063 + ], + [ + 10.02446, + 53.553998 + ], + [ + 10.0243, + 53.553905 + ], + [ + 10.024214, + 53.553872 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 125, + "bearing_before": 67, + "location": [ + 10.025328, + 53.555414 + ], + "modifier": "right", + "type": "continue" + }, + "name": "Westphalensweg", + "mode": "driving", + "weight": 36.5, + "duration": 36.5, + "distance": 208.6 + }, + { + "intersections": [ + { + "out": 1, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 60, + 150, + 330 + ], + "location": [ + 10.024214, + 53.553872 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 1, + "in": 3, + "entry": [ + false, + true, + true, + false + ], + "bearings": [ + 75, + 135, + 255, + 345 + ], + "location": [ + 10.024303, + 53.553598 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.024214, + 53.553872 + ], + [ + 10.024196, + 53.553814 + ], + [ + 10.024227, + 53.553761 + ], + [ + 10.024255, + 53.553702 + ], + [ + 10.024303, + 53.553598 + ], + [ + 10.024338, + 53.553572 + ], + [ + 10.024372, + 53.553556 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 147, + "bearing_before": 232, + "location": [ + 10.024214, + 53.553872 + ], + "modifier": "left", + "type": "end of road" + }, + "name": "Berliner Tor", + "mode": "driving", + "weight": 5.7, + "duration": 5.7, + "distance": 38.2 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 1, + "in": 3, + "entry": [ + false, + true, + false, + false + ], + "bearings": [ + 45, + 105, + 240, + 315 + ], + "location": [ + 10.024372, + 53.553556 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + false, + false + ], + "bearings": [ + 75, + 255, + 285 + ], + "location": [ + 10.024658, + 53.553509 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.024372, + 53.553556 + ], + [ + 10.024447, + 53.55353 + ], + [ + 10.024658, + 53.553509 + ], + [ + 10.024745, + 53.553515 + ], + [ + 10.024858, + 53.553523 + ], + [ + 10.025814, + 53.553618 + ], + [ + 10.026218, + 53.553661 + ], + [ + 10.026446, + 53.553683 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 104, + "bearing_before": 135, + "location": [ + 10.024372, + 53.553556 + ], + "modifier": "left", + "type": "turn" + }, + "name": "Berlinertordamm", + "mode": "driving", + "weight": 12.7, + "duration": 12.7, + "distance": 140 + }, + { + "intersections": [ + { + "out": 0, + "in": 1, + "entry": [ + true, + false + ], + "bearings": [ + 75, + 255 + ], + "location": [ + 10.026446, + 53.553683 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.026446, + 53.553683 + ], + [ + 10.026949, + 53.553747 + ], + [ + 10.027092, + 53.55376 + ], + [ + 10.027522, + 53.553852 + ], + [ + 10.028086, + 53.553936 + ], + [ + 10.028587, + 53.55402 + ], + [ + 10.029083, + 53.554111 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 77, + "bearing_before": 80, + "location": [ + 10.026446, + 53.553683 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Borgfelder Stra\u00dfe", + "mode": "driving", + "weight": 18.2, + "duration": 18.2, + "distance": 181.3 + }, + { + "intersections": [ + { + "out": 1, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 75, + 165, + 255 + ], + "location": [ + 10.029083, + 53.554111 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 180, + 255, + 345 + ], + "location": [ + 10.02965, + 53.553748 + ] + }, + { + "out": 1, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 0, + 165, + 255 + ], + "location": [ + 10.029654, + 53.553718 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 150, + 240, + 345 + ], + "location": [ + 10.029975, + 53.553169 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.029083, + 53.554111 + ], + [ + 10.029129, + 53.55403 + ], + [ + 10.029155, + 53.554017 + ], + [ + 10.029244, + 53.554004 + ], + [ + 10.029345, + 53.553995 + ], + [ + 10.029443, + 53.553989 + ], + [ + 10.029475, + 53.553984 + ], + [ + 10.029501, + 53.553974 + ], + [ + 10.029533, + 53.553958 + ], + [ + 10.029546, + 53.553943 + ], + [ + 10.029555, + 53.553929 + ], + [ + 10.029584, + 53.553865 + ], + [ + 10.02965, + 53.553748 + ], + [ + 10.029654, + 53.553718 + ], + [ + 10.029658, + 53.553692 + ], + [ + 10.029898, + 53.553297 + ], + [ + 10.029915, + 53.553261 + ], + [ + 10.02993, + 53.553229 + ], + [ + 10.029975, + 53.553169 + ], + [ + 10.03019, + 53.552873 + ], + [ + 10.030245, + 53.552798 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 158, + "bearing_before": 71, + "location": [ + 10.029083, + 53.554111 + ], + "modifier": "right", + "type": "turn" + }, + "name": "", + "mode": "driving", + "weight": 44.4, + "duration": 44.4, + "distance": 176 + }, + { + "intersections": [ + { + "out": 1, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 60, + 240, + 330 + ], + "location": [ + 10.030245, + 53.552798 + ] + }, + { + "out": 2, + "in": 0, + "entry": [ + false, + false, + true + ], + "bearings": [ + 60, + 195, + 240 + ], + "location": [ + 10.029155, + 53.552501 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.030245, + 53.552798 + ], + [ + 10.029643, + 53.552637 + ], + [ + 10.029188, + 53.552513 + ], + [ + 10.029155, + 53.552501 + ], + [ + 10.029049, + 53.552458 + ], + [ + 10.029015, + 53.552441 + ], + [ + 10.028976, + 53.552422 + ], + [ + 10.028933, + 53.552397 + ], + [ + 10.028877, + 53.55236 + ], + [ + 10.028782, + 53.55229 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 244, + "bearing_before": 156, + "location": [ + 10.030245, + 53.552798 + ], + "modifier": "right", + "type": "end of road" + }, + "name": "Anckelmannstra\u00dfe", + "mode": "driving", + "weight": 12.3, + "duration": 12.3, + "distance": 113.7 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + false, + true + ], + "bearings": [ + 45, + 105, + 255 + ], + "location": [ + 10.028782, + 53.55229 + ] + }, + { + "out": 1, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 90, + 240, + 330 + ], + "location": [ + 10.028166, + 53.552234 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.028782, + 53.55229 + ], + [ + 10.028714, + 53.552292 + ], + [ + 10.028636, + 53.552293 + ], + [ + 10.02853, + 53.552289 + ], + [ + 10.028435, + 53.552282 + ], + [ + 10.028361, + 53.552274 + ], + [ + 10.028281, + 53.552261 + ], + [ + 10.028166, + 53.552234 + ], + [ + 10.028015, + 53.552195 + ], + [ + 10.027605, + 53.552062 + ], + [ + 10.027382, + 53.552018 + ], + [ + 10.027113, + 53.551982 + ], + [ + 10.027013, + 53.551972 + ], + [ + 10.026903, + 53.551967 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 258, + "bearing_before": 222, + "location": [ + 10.028782, + 53.55229 + ], + "modifier": "slight right", + "type": "turn" + }, + "name": "Anckelmannsplatz", + "mode": "driving", + "weight": 11.8, + "duration": 11.8, + "distance": 131.4 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 90, + 270, + 300 + ], + "location": [ + 10.026903, + 53.551967 + ] + }, + { + "out": 0, + "in": 1, + "entry": [ + true, + false, + false + ], + "bearings": [ + 0, + 135, + 150 + ], + "location": [ + 10.025821, + 53.552284 + ] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 295, + "bearing_before": 262, + "location": [ + 10.026903, + 53.551967 + ], + "modifier": "right", + "type": "turn" + }, + "geometry": { + "coordinates": [ + [ + 10.026903, + 53.551967 + ], + [ + 10.026712, + 53.552022 + ], + [ + 10.026488, + 53.552051 + ], + [ + 10.026284, + 53.552093 + ], + [ + 10.02623, + 53.552108 + ], + [ + 10.026176, + 53.552122 + ], + [ + 10.026078, + 53.552155 + ], + [ + 10.026002, + 53.552185 + ], + [ + 10.02592, + 53.552224 + ], + [ + 10.025821, + 53.552284 + ], + [ + 10.025817, + 53.55231 + ], + [ + 10.025802, + 53.552436 + ], + [ + 10.025792, + 53.55271 + ], + [ + 10.025791, + 53.552747 + ], + [ + 10.025788, + 53.552779 + ], + [ + 10.025914, + 53.553218 + ], + [ + 10.025941, + 53.553304 + ], + [ + 10.026029, + 53.553547 + ], + [ + 10.026137, + 53.553865 + ], + [ + 10.026394, + 53.554562 + ], + [ + 10.026411, + 53.554608 + ], + [ + 10.026571, + 53.554995 + ], + [ + 10.026647, + 53.555166 + ], + [ + 10.026745, + 53.555353 + ] + ], + "type": "LineString" + }, + "ref": "B 75", + "name": "B\u00fcrgerweide", + "mode": "driving", + "weight": 44.9, + "duration": 44.9, + "distance": 429.9 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "slight right" + ] + } + ], + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 15, + 30, + 195 + ], + "location": [ + 10.026745, + 53.555353 + ] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 21, + "bearing_before": 14, + "location": [ + 10.026745, + 53.555353 + ], + "modifier": "straight", + "type": "continue" + }, + "geometry": { + "coordinates": [ + [ + 10.026745, + 53.555353 + ], + [ + 10.026824, + 53.555497 + ], + [ + 10.026875, + 53.555579 + ], + [ + 10.027154, + 53.555962 + ], + [ + 10.027201, + 53.556048 + ], + [ + 10.027205, + 53.556112 + ], + [ + 10.027183, + 53.556167 + ] + ], + "type": "LineString" + }, + "ref": "B 75", + "name": "B\u00fcrgerweide", + "mode": "driving", + "weight": 10.8, + "duration": 10.8, + "distance": 96.5 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "slight left" + ] + }, + { + "valid": true, + "indications": [ + "slight left" + ] + }, + { + "valid": true, + "indications": [ + "slight left" + ] + } + ], + "out": 5, + "in": 2, + "entry": [ + false, + false, + false, + false, + false, + true + ], + "bearings": [ + 45, + 75, + 180, + 225, + 285, + 330 + ], + "location": [ + 10.027183, + 53.556167 + ] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 324, + "bearing_before": 351, + "location": [ + 10.027183, + 53.556167 + ], + "modifier": "slight left", + "type": "new name" + }, + "geometry": { + "coordinates": [ + [ + 10.027183, + 53.556167 + ], + [ + 10.027174, + 53.556178 + ] + ], + "type": "LineString" + }, + "ref": "B 75", + "name": "Wallstra\u00dfe", + "mode": "driving", + "weight": 0.1, + "duration": 0.1, + "distance": 1.4 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 154 + ], + "location": [ + 10.027174, + 53.556178 + ] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 0, + "bearing_before": 334, + "location": [ + 10.027174, + 53.556178 + ], + "type": "arrive" + }, + "geometry": { + "coordinates": [ + [ + 10.027174, + 53.556178 + ], + [ + 10.027174, + 53.556178 + ] + ], + "type": "LineString" + }, + "ref": "B 75", + "name": "Wallstra\u00dfe", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 227.6, + "summary": "Westphalensweg, B\u00fcrgerweide", + "duration": 227.6, + "distance": 1837.2 + }, + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 336 + ], + "location": [ + 10.027174, + 53.556178 + ] + }, + { + "out": 2, + "in": 1, + "entry": [ + false, + false, + true + ], + "bearings": [ + 105, + 150, + 315 + ], + "location": [ + 10.026939, + 53.556383 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "slight right" + ] + }, + { + "valid": false, + "indications": [ + "slight right" + ] + } + ], + "out": 1, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 135, + 315, + 345 + ], + "location": [ + 10.026498, + 53.556658 + ] + }, + { + "out": 2, + "in": 1, + "entry": [ + false, + false, + true + ], + "bearings": [ + 15, + 150, + 315 + ], + "location": [ + 10.026019, + 53.556961 + ] + }, + { + "out": 2, + "in": 1, + "entry": [ + false, + false, + true + ], + "bearings": [ + 105, + 135, + 315 + ], + "location": [ + 10.025616, + 53.557179 + ] + } + ], + "driving_side": "right", + "maneuver": { + "bearing_after": 336, + "bearing_before": 0, + "location": [ + 10.027174, + 53.556178 + ], + "type": "depart" + }, + "geometry": { + "coordinates": [ + [ + 10.027174, + 53.556178 + ], + [ + 10.027125, + 53.556243 + ], + [ + 10.02707, + 53.556284 + ], + [ + 10.026939, + 53.556383 + ], + [ + 10.026581, + 53.556604 + ], + [ + 10.026498, + 53.556658 + ], + [ + 10.026406, + 53.556716 + ], + [ + 10.026164, + 53.556869 + ], + [ + 10.026019, + 53.556961 + ], + [ + 10.02588, + 53.557038 + ], + [ + 10.025616, + 53.557179 + ], + [ + 10.025049, + 53.557506 + ], + [ + 10.024633, + 53.55774 + ], + [ + 10.024281, + 53.557953 + ], + [ + 10.024158, + 53.558044 + ], + [ + 10.023963, + 53.558233 + ], + [ + 10.023931, + 53.558265 + ], + [ + 10.023766, + 53.558409 + ] + ], + "type": "LineString" + }, + "ref": "B 75", + "name": "Wallstra\u00dfe", + "mode": "driving", + "weight": 34.3, + "duration": 34.3, + "distance": 337.2 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": false, + "indications": [ + "slight left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 3, + "in": 1, + "entry": [ + true, + false, + false, + true + ], + "bearings": [ + 75, + 150, + 240, + 315 + ], + "location": [ + 10.023766, + 53.558409 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 1, + "entry": [ + false, + false, + true, + true + ], + "bearings": [ + 90, + 135, + 255, + 300 + ], + "location": [ + 10.023467, + 53.558585 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + false + ], + "bearings": [ + 75, + 210, + 255, + 330 + ], + "location": [ + 10.023366, + 53.55857 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.023766, + 53.558409 + ], + [ + 10.023581, + 53.558525 + ], + [ + 10.023508, + 53.558564 + ], + [ + 10.023467, + 53.558585 + ], + [ + 10.023366, + 53.55857 + ], + [ + 10.023237, + 53.558546 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 313, + "bearing_before": 324, + "location": [ + 10.023766, + 53.558409 + ], + "modifier": "left", + "type": "turn" + }, + "name": "L\u00fcbeckertordamm", + "mode": "driving", + "weight": 7.2, + "duration": 7.2, + "distance": 43.7 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 73 + ], + "location": [ + 10.023237, + 53.558546 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.023237, + 53.558546 + ], + [ + 10.023237, + 53.558546 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 0, + "bearing_before": 253, + "location": [ + 10.023237, + 53.558546 + ], + "modifier": "left", + "type": "arrive" + }, + "name": "L\u00fcbeckertordamm", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 41.5, + "summary": "Wallstra\u00dfe, Wallstra\u00dfe", + "duration": 41.5, + "distance": 380.9 + }, + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 252 + ], + "location": [ + 10.023237, + 53.558546 + ] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + true, + true, + false + ], + "bearings": [ + 75, + 120, + 225, + 315 + ], + "location": [ + 10.022846, + 53.558449 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.023237, + 53.558546 + ], + [ + 10.023099, + 53.55852 + ], + [ + 10.023006, + 53.558497 + ], + [ + 10.022846, + 53.558449 + ], + [ + 10.022726, + 53.5584 + ], + [ + 10.02234, + 53.558153 + ], + [ + 10.022203, + 53.558073 + ], + [ + 10.021859, + 53.55791 + ], + [ + 10.02121, + 53.55762 + ], + [ + 10.020843, + 53.55745 + ], + [ + 10.020642, + 53.557368 + ], + [ + 10.020564, + 53.557335 + ], + [ + 10.02036, + 53.557255 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 252, + "bearing_before": 0, + "location": [ + 10.023237, + 53.558546 + ], + "modifier": "left", + "type": "depart" + }, + "name": "L\u00fcbeckertordamm", + "mode": "driving", + "weight": 25.9, + "duration": 25.9, + "distance": 240.4 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [ + false, + true, + true, + true + ], + "bearings": [ + 60, + 135, + 240, + 315 + ], + "location": [ + 10.02036, + 53.557255 + ] + }, + { + "out": 1, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 45, + 225, + 315 + ], + "location": [ + 10.018055, + 53.556223 + ] + }, + { + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + false + ], + "bearings": [ + 60, + 150, + 225, + 330 + ], + "location": [ + 10.016454, + 53.555457 + ] + }, + { + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + true + ], + "bearings": [ + 45, + 165, + 225, + 315 + ], + "location": [ + 10.015911, + 53.555206 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.02036, + 53.557255 + ], + [ + 10.020195, + 53.557185 + ], + [ + 10.019901, + 53.557056 + ], + [ + 10.019774, + 53.556991 + ], + [ + 10.019541, + 53.556846 + ], + [ + 10.019482, + 53.556813 + ], + [ + 10.019386, + 53.556768 + ], + [ + 10.018762, + 53.556491 + ], + [ + 10.018624, + 53.556445 + ], + [ + 10.018463, + 53.556399 + ], + [ + 10.018172, + 53.556279 + ], + [ + 10.018116, + 53.556254 + ], + [ + 10.018055, + 53.556223 + ], + [ + 10.018017, + 53.556204 + ], + [ + 10.017937, + 53.556152 + ], + [ + 10.017863, + 53.5561 + ], + [ + 10.017749, + 53.556033 + ], + [ + 10.017631, + 53.555978 + ], + [ + 10.016821, + 53.555612 + ], + [ + 10.016641, + 53.555539 + ], + [ + 10.016578, + 53.555512 + ], + [ + 10.016454, + 53.555457 + ], + [ + 10.016324, + 53.555399 + ], + [ + 10.015911, + 53.555206 + ], + [ + 10.015577, + 53.555053 + ], + [ + 10.013961, + 53.554325 + ], + [ + 10.013866, + 53.554287 + ], + [ + 10.01378, + 53.554256 + ], + [ + 10.013684, + 53.554218 + ], + [ + 10.013613, + 53.554178 + ], + [ + 10.013545, + 53.554132 + ], + [ + 10.013499, + 53.554101 + ], + [ + 10.013473, + 53.554083 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 233, + "bearing_before": 233, + "location": [ + 10.02036, + 53.557255 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Steindamm", + "mode": "driving", + "weight": 58.1, + "duration": 58.1, + "distance": 578.4 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 41 + ], + "location": [ + 10.013473, + 53.554083 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013473, + 53.554083 + ], + [ + 10.013473, + 53.554083 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 0, + "bearing_before": 221, + "location": [ + 10.013473, + 53.554083 + ], + "type": "arrive" + }, + "name": "Steindamm", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 84, + "summary": "L\u00fcbeckertordamm, Steindamm", + "duration": 84, + "distance": 818.7 + }, + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 219 + ], + "location": [ + 10.013473, + 53.554083 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013473, + 53.554083 + ], + [ + 10.013419, + 53.554044 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 219, + "bearing_before": 0, + "location": [ + 10.013473, + 53.554083 + ], + "type": "depart" + }, + "name": "Steindamm", + "mode": "driving", + "weight": 0.5, + "duration": 0.5, + "distance": 5.6 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + true, + true + ], + "bearings": [ + 45, + 120, + 210, + 255, + 300 + ], + "location": [ + 10.013419, + 53.554044 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013419, + 53.554044 + ], + [ + 10.013343, + 53.553972 + ], + [ + 10.013311, + 53.55393 + ], + [ + 10.013274, + 53.553874 + ], + [ + 10.013243, + 53.553821 + ], + [ + 10.013201, + 53.553735 + ], + [ + 10.013173, + 53.553654 + ], + [ + 10.013153, + 53.553572 + ], + [ + 10.013139, + 53.553476 + ], + [ + 10.013137, + 53.553419 + ], + [ + 10.013145, + 53.553333 + ], + [ + 10.013177, + 53.553108 + ], + [ + 10.013199, + 53.552954 + ], + [ + 10.013229, + 53.552728 + ], + [ + 10.013239, + 53.552655 + ], + [ + 10.013254, + 53.552525 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 210, + "bearing_before": 219, + "location": [ + 10.013419, + 53.554044 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Kreuzweg", + "mode": "driving", + "weight": 17.7, + "duration": 17.7, + "distance": 172.8 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + true + ], + "bearings": [ + 0, + 90, + 180, + 270 + ], + "location": [ + 10.013254, + 53.552525 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": false, + "indications": [ + "right" + ] + } + ], + "out": 1, + "in": 0, + "entry": [ + false, + true, + true, + false + ], + "bearings": [ + 0, + 90, + 180, + 270 + ], + "location": [ + 10.013269, + 53.552384 + ] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 0, + "in": 2, + "entry": [ + true, + false, + false, + true + ], + "bearings": [ + 90, + 165, + 270, + 345 + ], + "location": [ + 10.013487, + 53.552395 + ] + }, + { + "out": 0, + "in": 1, + "entry": [ + true, + false + ], + "bearings": [ + 150, + 345 + ], + "location": [ + 10.015823, + 53.552379 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013254, + 53.552525 + ], + [ + 10.013269, + 53.552384 + ], + [ + 10.013487, + 53.552395 + ], + [ + 10.013654, + 53.552403 + ], + [ + 10.013794, + 53.55241 + ], + [ + 10.013867, + 53.552414 + ], + [ + 10.015428, + 53.552494 + ], + [ + 10.015509, + 53.552498 + ], + [ + 10.015564, + 53.552498 + ], + [ + 10.015602, + 53.552495 + ], + [ + 10.015636, + 53.552489 + ], + [ + 10.01567, + 53.552481 + ], + [ + 10.015708, + 53.552469 + ], + [ + 10.015739, + 53.552457 + ], + [ + 10.015765, + 53.552444 + ], + [ + 10.015791, + 53.552426 + ], + [ + 10.01581, + 53.552406 + ], + [ + 10.015823, + 53.552379 + ], + [ + 10.015846, + 53.552347 + ], + [ + 10.015853, + 53.552303 + ], + [ + 10.01586, + 53.552196 + ], + [ + 10.01586, + 53.552089 + ], + [ + 10.01586, + 53.55205 + ], + [ + 10.01585, + 53.551972 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 175, + "bearing_before": 174, + "location": [ + 10.013254, + 53.552525 + ], + "modifier": "left", + "type": "turn" + }, + "name": "Adenauerallee", + "mode": "driving", + "weight": 30.6, + "duration": 30.6, + "distance": 237.1 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + true + ], + "bearings": [ + 0, + 75, + 180, + 255 + ], + "location": [ + 10.01585, + 53.551972 + ] + }, + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + true, + true, + false + ], + "bearings": [ + 0, + 75, + 165, + 255 + ], + "location": [ + 10.015848, + 53.551856 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 150, + 255, + 345 + ], + "location": [ + 10.015919, + 53.551675 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.01585, + 53.551972 + ], + [ + 10.015848, + 53.551856 + ], + [ + 10.015848, + 53.551797 + ], + [ + 10.015851, + 53.55178 + ], + [ + 10.015858, + 53.551761 + ], + [ + 10.015919, + 53.551675 + ], + [ + 10.01616, + 53.55137 + ], + [ + 10.016184, + 53.551338 + ], + [ + 10.016616, + 53.550789 + ], + [ + 10.016777, + 53.550584 + ], + [ + 10.016804, + 53.550549 + ], + [ + 10.016881, + 53.550444 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 180, + "bearing_before": 182, + "location": [ + 10.01585, + 53.551972 + ], + "modifier": "slight left", + "type": "turn" + }, + "name": "Nagelsweg", + "mode": "driving", + "weight": 21, + "duration": 21, + "distance": 185 + }, + { + "intersections": [ + { + "out": 2, + "in": 3, + "entry": [ + true, + true, + true, + false + ], + "bearings": [ + 60, + 150, + 240, + 330 + ], + "location": [ + 10.016881, + 53.550444 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.016881, + 53.550444 + ], + [ + 10.016384, + 53.55032 + ], + [ + 10.015937, + 53.550209 + ], + [ + 10.01564, + 53.550136 + ], + [ + 10.015452, + 53.550099 + ], + [ + 10.015129, + 53.550036 + ], + [ + 10.014851, + 53.549988 + ], + [ + 10.014488, + 53.549925 + ], + [ + 10.014274, + 53.549908 + ], + [ + 10.013843, + 53.549875 + ], + [ + 10.013388, + 53.549847 + ], + [ + 10.013184, + 53.549844 + ], + [ + 10.013034, + 53.549841 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 246, + "bearing_before": 154, + "location": [ + 10.016881, + 53.550444 + ], + "modifier": "right", + "type": "turn" + }, + "name": "Norderstra\u00dfe", + "mode": "driving", + "weight": 23.9, + "duration": 23.9, + "distance": 265.9 + }, + { + "intersections": [ + { + "out": 2, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 90, + 195, + 270 + ], + "location": [ + 10.013034, + 53.549841 + ] + }, + { + "out": 2, + "in": 0, + "entry": [ + false, + true, + true + ], + "bearings": [ + 150, + 240, + 315 + ], + "location": [ + 10.01155, + 53.550572 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013034, + 53.549841 + ], + [ + 10.012922, + 53.549847 + ], + [ + 10.012741, + 53.549857 + ], + [ + 10.012615, + 53.549863 + ], + [ + 10.012285, + 53.54989 + ], + [ + 10.012198, + 53.549911 + ], + [ + 10.012147, + 53.549952 + ], + [ + 10.012069, + 53.550037 + ], + [ + 10.012026, + 53.550086 + ], + [ + 10.011856, + 53.550277 + ], + [ + 10.011723, + 53.550426 + ], + [ + 10.01155, + 53.550572 + ], + [ + 10.011454, + 53.550632 + ], + [ + 10.011303, + 53.550713 + ], + [ + 10.011231, + 53.550763 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 274, + "bearing_before": 265, + "location": [ + 10.013034, + 53.549841 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Repsoldstra\u00dfe", + "mode": "driving", + "weight": 15.7, + "duration": 15.7, + "distance": 171.6 + }, + { + "intersections": [ + { + "out": 2, + "in": 1, + "entry": [ + false, + false, + true + ], + "bearings": [ + 75, + 135, + 345 + ], + "location": [ + 10.011231, + 53.550763 + ] + }, + { + "out": 0, + "in": 1, + "entry": [ + true, + false, + false + ], + "bearings": [ + 75, + 165, + 255 + ], + "location": [ + 10.011094, + 53.551 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.011231, + 53.550763 + ], + [ + 10.011181, + 53.550809 + ], + [ + 10.011156, + 53.55084 + ], + [ + 10.011141, + 53.550874 + ], + [ + 10.011112, + 53.550941 + ], + [ + 10.011109, + 53.550951 + ], + [ + 10.011094, + 53.551 + ], + [ + 10.011313, + 53.551028 + ], + [ + 10.011463, + 53.551049 + ], + [ + 10.011584, + 53.55107 + ], + [ + 10.011813, + 53.55111 + ], + [ + 10.011956, + 53.551139 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 343, + "bearing_before": 315, + "location": [ + 10.011231, + 53.550763 + ], + "modifier": "right", + "type": "end of road" + }, + "name": "Kurt-Schumacher-Allee", + "mode": "driving", + "weight": 13, + "duration": 13, + "distance": 87.4 + }, + { + "intersections": [ + { + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 60, + 75, + 255 + ], + "location": [ + 10.011956, + 53.551139 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.011956, + 53.551139 + ], + [ + 10.012228, + 53.551244 + ], + [ + 10.012385, + 53.551283 + ], + [ + 10.012561, + 53.551321 + ], + [ + 10.012792, + 53.551363 + ], + [ + 10.013206, + 53.551437 + ], + [ + 10.013277, + 53.551451 + ], + [ + 10.013323, + 53.551464 + ], + [ + 10.013372, + 53.551482 + ], + [ + 10.013412, + 53.551502 + ], + [ + 10.013438, + 53.551522 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 56, + "bearing_before": 74, + "location": [ + 10.011956, + 53.551139 + ], + "modifier": "slight left", + "type": "continue" + }, + "name": "Kurt-Schumacher-Allee", + "mode": "driving", + "weight": 18.2, + "duration": 18.2, + "distance": 108.2 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 218 + ], + "location": [ + 10.013438, + 53.551522 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013438, + 53.551522 + ], + [ + 10.013438, + 53.551522 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 0, + "bearing_before": 38, + "location": [ + 10.013438, + 53.551522 + ], + "type": "arrive" + }, + "name": "Kurt-Schumacher-Allee", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 140.6, + "summary": "Nagelsweg, Kurt-Schumacher-Allee", + "duration": 140.6, + "distance": 1233.7 + }, + { + "steps": [ + { + "intersections": [ + { + "out": 0, + "entry": [ + true + ], + "bearings": [ + 37 + ], + "location": [ + 10.013438, + 53.551522 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013438, + 53.551522 + ], + [ + 10.013465, + 53.551543 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 37, + "bearing_before": 0, + "location": [ + 10.013438, + 53.551522 + ], + "type": "depart" + }, + "name": "Kurt-Schumacher-Allee", + "mode": "driving", + "weight": 1.1, + "duration": 1.1, + "distance": 2.9 + }, + { + "intersections": [ + { + "out": 0, + "in": 2, + "entry": [ + true, + false, + false + ], + "bearings": [ + 30, + 75, + 255 + ], + "location": [ + 10.013465, + 53.551543 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013465, + 53.551543 + ], + [ + 10.013529, + 53.551614 + ], + [ + 10.013563, + 53.551663 + ], + [ + 10.013587, + 53.55172 + ], + [ + 10.013604, + 53.55177 + ], + [ + 10.01361, + 53.551826 + ], + [ + 10.013606, + 53.551876 + ], + [ + 10.013595, + 53.551928 + ], + [ + 10.013525, + 53.552231 + ], + [ + 10.013513, + 53.552283 + ], + [ + 10.013487, + 53.552395 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 26, + "bearing_before": 73, + "location": [ + 10.013465, + 53.551543 + ], + "modifier": "left", + "type": "turn" + }, + "name": "Kreuzweg", + "mode": "driving", + "weight": 13.1, + "duration": 13.1, + "distance": 97.2 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 0, + "in": 1, + "entry": [ + true, + false, + false, + true + ], + "bearings": [ + 90, + 165, + 270, + 345 + ], + "location": [ + 10.013487, + 53.552395 + ] + }, + { + "out": 0, + "in": 1, + "entry": [ + true, + false + ], + "bearings": [ + 150, + 345 + ], + "location": [ + 10.015823, + 53.552379 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.013487, + 53.552395 + ], + [ + 10.013654, + 53.552403 + ], + [ + 10.013794, + 53.55241 + ], + [ + 10.013867, + 53.552414 + ], + [ + 10.015428, + 53.552494 + ], + [ + 10.015509, + 53.552498 + ], + [ + 10.015564, + 53.552498 + ], + [ + 10.015602, + 53.552495 + ], + [ + 10.015636, + 53.552489 + ], + [ + 10.01567, + 53.552481 + ], + [ + 10.015708, + 53.552469 + ], + [ + 10.015739, + 53.552457 + ], + [ + 10.015765, + 53.552444 + ], + [ + 10.015791, + 53.552426 + ], + [ + 10.01581, + 53.552406 + ], + [ + 10.015823, + 53.552379 + ], + [ + 10.015846, + 53.552347 + ], + [ + 10.015853, + 53.552303 + ], + [ + 10.01586, + 53.552196 + ], + [ + 10.01586, + 53.552089 + ], + [ + 10.01586, + 53.55205 + ], + [ + 10.01585, + 53.551972 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 84, + "bearing_before": 351, + "location": [ + 10.013487, + 53.552395 + ], + "modifier": "right", + "type": "turn" + }, + "name": "Adenauerallee", + "mode": "driving", + "weight": 22.4, + "duration": 22.4, + "distance": 206.9 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "right" + ] + } + ], + "out": 2, + "in": 0, + "entry": [ + false, + false, + true, + true + ], + "bearings": [ + 0, + 75, + 180, + 255 + ], + "location": [ + 10.01585, + 53.551972 + ] + }, + { + "lanes": [ + { + "valid": true, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight", + "left" + ] + }, + { + "valid": false, + "indications": [ + "straight" + ] + } + ], + "out": 1, + "in": 0, + "entry": [ + false, + true, + true, + false + ], + "bearings": [ + 0, + 75, + 165, + 255 + ], + "location": [ + 10.015848, + 53.551856 + ] + }, + { + "out": 0, + "in": 2, + "entry": [ + true, + true, + false + ], + "bearings": [ + 60, + 165, + 255 + ], + "location": [ + 10.017617, + 53.552182 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.01585, + 53.551972 + ], + [ + 10.015848, + 53.551856 + ], + [ + 10.016108, + 53.551885 + ], + [ + 10.016243, + 53.551907 + ], + [ + 10.016893, + 53.552031 + ], + [ + 10.017277, + 53.552108 + ], + [ + 10.017617, + 53.552182 + ], + [ + 10.017808, + 53.552226 + ], + [ + 10.01797, + 53.552269 + ], + [ + 10.018247, + 53.552354 + ], + [ + 10.018833, + 53.552524 + ], + [ + 10.018896, + 53.552543 + ], + [ + 10.018943, + 53.552557 + ], + [ + 10.019008, + 53.552577 + ], + [ + 10.019148, + 53.552619 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 180, + "bearing_before": 182, + "location": [ + 10.01585, + 53.551972 + ], + "modifier": "left", + "type": "turn" + }, + "name": "Kurt-Schumacher-Allee", + "mode": "driving", + "weight": 30.8, + "duration": 30.8, + "distance": 248.3 + }, + { + "intersections": [ + { + "lanes": [ + { + "valid": false, + "indications": [ + "left" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "straight" + ] + }, + { + "valid": true, + "indications": [ + "none" + ] + } + ], + "out": 1, + "in": 3, + "entry": [ + true, + true, + false, + false + ], + "bearings": [ + 15, + 60, + 180, + 240 + ], + "location": [ + 10.019148, + 53.552619 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.019148, + 53.552619 + ], + [ + 10.019372, + 53.552684 + ], + [ + 10.019521, + 53.552725 + ], + [ + 10.019765, + 53.552788 + ], + [ + 10.020544, + 53.552946 + ], + [ + 10.020902, + 53.553006 + ], + [ + 10.020994, + 53.553021 + ], + [ + 10.021119, + 53.553039 + ], + [ + 10.022079, + 53.553174 + ], + [ + 10.022098, + 53.553177 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 64, + "bearing_before": 61, + "location": [ + 10.019148, + 53.552619 + ], + "modifier": "straight", + "type": "new name" + }, + "name": "Beim Strohhause", + "mode": "driving", + "weight": 18.6, + "duration": 18.6, + "distance": 205.6 + }, + { + "intersections": [ + { + "in": 0, + "entry": [ + true + ], + "bearings": [ + 255 + ], + "location": [ + 10.022098, + 53.553177 + ] + } + ], + "driving_side": "right", + "geometry": { + "coordinates": [ + [ + 10.022098, + 53.553177 + ], + [ + 10.022098, + 53.553177 + ] + ], + "type": "LineString" + }, + "maneuver": { + "bearing_after": 0, + "bearing_before": 75, + "location": [ + 10.022098, + 53.553177 + ], + "modifier": "left", + "type": "arrive" + }, + "name": "Beim Strohhause", + "mode": "driving", + "weight": 0, + "duration": 0, + "distance": 0 + } + ], + "weight": 86, + "summary": "Kurt-Schumacher-Allee, Beim Strohhause", + "duration": 86, + "distance": 761 + } + ], + "weight_name": "routability", + "geometry": { + "coordinates": [ + [ + 10.022098, + 53.553177 + ], + [ + 10.023259, + 53.553346 + ], + [ + 10.023467, + 53.553373 + ], + [ + 10.023585, + 53.553388 + ], + [ + 10.02406, + 53.553447 + ], + [ + 10.024244, + 53.553509 + ], + [ + 10.024338, + 53.553541 + ], + [ + 10.024372, + 53.553556 + ], + [ + 10.024416, + 53.553579 + ], + [ + 10.024442, + 53.55361 + ], + [ + 10.024452, + 53.55364 + ], + [ + 10.024444, + 53.553668 + ], + [ + 10.024416, + 53.553713 + ], + [ + 10.024284, + 53.553848 + ], + [ + 10.024214, + 53.553872 + ], + [ + 10.02402, + 53.554039 + ], + [ + 10.02392, + 53.554169 + ], + [ + 10.023394, + 53.55486 + ], + [ + 10.02339, + 53.554868 + ], + [ + 10.023389, + 53.554875 + ], + [ + 10.023391, + 53.554882 + ], + [ + 10.023393, + 53.554888 + ], + [ + 10.023402, + 53.554899 + ], + [ + 10.023409, + 53.554905 + ], + [ + 10.023417, + 53.55491 + ], + [ + 10.023452, + 53.554926 + ], + [ + 10.023513, + 53.554947 + ], + [ + 10.023904, + 53.555049 + ], + [ + 10.024202, + 53.555127 + ], + [ + 10.024293, + 53.555152 + ], + [ + 10.024843, + 53.555297 + ], + [ + 10.024898, + 53.555313 + ], + [ + 10.02501, + 53.555344 + ], + [ + 10.025228, + 53.555401 + ], + [ + 10.025328, + 53.555414 + ], + [ + 10.025355, + 53.55541 + ], + [ + 10.02538, + 53.555403 + ], + [ + 10.0254, + 53.555395 + ], + [ + 10.025424, + 53.555383 + ], + [ + 10.025437, + 53.555373 + ], + [ + 10.025458, + 53.555357 + ], + [ + 10.025287, + 53.554915 + ], + [ + 10.02517, + 53.554607 + ], + [ + 10.025107, + 53.554482 + ], + [ + 10.025047, + 53.554384 + ], + [ + 10.025002, + 53.554313 + ], + [ + 10.024986, + 53.554292 + ], + [ + 10.024973, + 53.55428 + ], + [ + 10.02496, + 53.554272 + ], + [ + 10.024946, + 53.554266 + ], + [ + 10.024928, + 53.55426 + ], + [ + 10.024913, + 53.554257 + ], + [ + 10.024897, + 53.554255 + ], + [ + 10.024875, + 53.554255 + ], + [ + 10.02485, + 53.554258 + ], + [ + 10.02478, + 53.554276 + ], + [ + 10.024724, + 53.554216 + ], + [ + 10.024651, + 53.554152 + ], + [ + 10.024547, + 53.554063 + ], + [ + 10.02446, + 53.553998 + ], + [ + 10.0243, + 53.553905 + ], + [ + 10.024214, + 53.553872 + ], + [ + 10.024196, + 53.553814 + ], + [ + 10.024227, + 53.553761 + ], + [ + 10.024255, + 53.553702 + ], + [ + 10.024303, + 53.553598 + ], + [ + 10.024338, + 53.553572 + ], + [ + 10.024372, + 53.553556 + ], + [ + 10.024447, + 53.55353 + ], + [ + 10.024658, + 53.553509 + ], + [ + 10.024745, + 53.553515 + ], + [ + 10.024858, + 53.553523 + ], + [ + 10.025814, + 53.553618 + ], + [ + 10.026218, + 53.553661 + ], + [ + 10.026446, + 53.553683 + ], + [ + 10.026949, + 53.553747 + ], + [ + 10.027092, + 53.55376 + ], + [ + 10.027522, + 53.553852 + ], + [ + 10.028086, + 53.553936 + ], + [ + 10.028587, + 53.55402 + ], + [ + 10.029083, + 53.554111 + ], + [ + 10.029129, + 53.55403 + ], + [ + 10.029155, + 53.554017 + ], + [ + 10.029244, + 53.554004 + ], + [ + 10.029345, + 53.553995 + ], + [ + 10.029443, + 53.553989 + ], + [ + 10.029475, + 53.553984 + ], + [ + 10.029501, + 53.553974 + ], + [ + 10.029533, + 53.553958 + ], + [ + 10.029546, + 53.553943 + ], + [ + 10.029555, + 53.553929 + ], + [ + 10.029584, + 53.553865 + ], + [ + 10.02965, + 53.553748 + ], + [ + 10.029654, + 53.553718 + ], + [ + 10.029658, + 53.553692 + ], + [ + 10.029898, + 53.553297 + ], + [ + 10.029915, + 53.553261 + ], + [ + 10.02993, + 53.553229 + ], + [ + 10.029975, + 53.553169 + ], + [ + 10.03019, + 53.552873 + ], + [ + 10.030245, + 53.552798 + ], + [ + 10.029643, + 53.552637 + ], + [ + 10.029188, + 53.552513 + ], + [ + 10.029155, + 53.552501 + ], + [ + 10.029049, + 53.552458 + ], + [ + 10.029015, + 53.552441 + ], + [ + 10.028976, + 53.552422 + ], + [ + 10.028933, + 53.552397 + ], + [ + 10.028877, + 53.55236 + ], + [ + 10.028782, + 53.55229 + ], + [ + 10.028714, + 53.552292 + ], + [ + 10.028636, + 53.552293 + ], + [ + 10.02853, + 53.552289 + ], + [ + 10.028435, + 53.552282 + ], + [ + 10.028361, + 53.552274 + ], + [ + 10.028281, + 53.552261 + ], + [ + 10.028166, + 53.552234 + ], + [ + 10.028015, + 53.552195 + ], + [ + 10.027605, + 53.552062 + ], + [ + 10.027382, + 53.552018 + ], + [ + 10.027113, + 53.551982 + ], + [ + 10.027013, + 53.551972 + ], + [ + 10.026903, + 53.551967 + ], + [ + 10.026712, + 53.552022 + ], + [ + 10.026488, + 53.552051 + ], + [ + 10.026284, + 53.552093 + ], + [ + 10.02623, + 53.552108 + ], + [ + 10.026176, + 53.552122 + ], + [ + 10.026078, + 53.552155 + ], + [ + 10.026002, + 53.552185 + ], + [ + 10.02592, + 53.552224 + ], + [ + 10.025821, + 53.552284 + ], + [ + 10.025817, + 53.55231 + ], + [ + 10.025802, + 53.552436 + ], + [ + 10.025792, + 53.55271 + ], + [ + 10.025791, + 53.552747 + ], + [ + 10.025788, + 53.552779 + ], + [ + 10.025914, + 53.553218 + ], + [ + 10.025941, + 53.553304 + ], + [ + 10.026029, + 53.553547 + ], + [ + 10.026137, + 53.553865 + ], + [ + 10.026394, + 53.554562 + ], + [ + 10.026411, + 53.554608 + ], + [ + 10.026571, + 53.554995 + ], + [ + 10.026647, + 53.555166 + ], + [ + 10.026745, + 53.555353 + ], + [ + 10.026824, + 53.555497 + ], + [ + 10.026875, + 53.555579 + ], + [ + 10.027154, + 53.555962 + ], + [ + 10.027201, + 53.556048 + ], + [ + 10.027205, + 53.556112 + ], + [ + 10.027183, + 53.556167 + ], + [ + 10.027174, + 53.556178 + ], + [ + 10.027125, + 53.556243 + ], + [ + 10.02707, + 53.556284 + ], + [ + 10.026939, + 53.556383 + ], + [ + 10.026581, + 53.556604 + ], + [ + 10.026498, + 53.556658 + ], + [ + 10.026406, + 53.556716 + ], + [ + 10.026164, + 53.556869 + ], + [ + 10.026019, + 53.556961 + ], + [ + 10.02588, + 53.557038 + ], + [ + 10.025616, + 53.557179 + ], + [ + 10.025049, + 53.557506 + ], + [ + 10.024633, + 53.55774 + ], + [ + 10.024281, + 53.557953 + ], + [ + 10.024158, + 53.558044 + ], + [ + 10.023963, + 53.558233 + ], + [ + 10.023931, + 53.558265 + ], + [ + 10.023766, + 53.558409 + ], + [ + 10.023581, + 53.558525 + ], + [ + 10.023508, + 53.558564 + ], + [ + 10.023467, + 53.558585 + ], + [ + 10.023366, + 53.55857 + ], + [ + 10.023237, + 53.558546 + ], + [ + 10.023099, + 53.55852 + ], + [ + 10.023006, + 53.558497 + ], + [ + 10.022846, + 53.558449 + ], + [ + 10.022726, + 53.5584 + ], + [ + 10.02234, + 53.558153 + ], + [ + 10.022203, + 53.558073 + ], + [ + 10.021859, + 53.55791 + ], + [ + 10.02121, + 53.55762 + ], + [ + 10.020843, + 53.55745 + ], + [ + 10.020642, + 53.557368 + ], + [ + 10.020564, + 53.557335 + ], + [ + 10.02036, + 53.557255 + ], + [ + 10.020195, + 53.557185 + ], + [ + 10.019901, + 53.557056 + ], + [ + 10.019774, + 53.556991 + ], + [ + 10.019541, + 53.556846 + ], + [ + 10.019482, + 53.556813 + ], + [ + 10.019386, + 53.556768 + ], + [ + 10.018762, + 53.556491 + ], + [ + 10.018624, + 53.556445 + ], + [ + 10.018463, + 53.556399 + ], + [ + 10.018172, + 53.556279 + ], + [ + 10.018116, + 53.556254 + ], + [ + 10.018055, + 53.556223 + ], + [ + 10.018017, + 53.556204 + ], + [ + 10.017937, + 53.556152 + ], + [ + 10.017863, + 53.5561 + ], + [ + 10.017749, + 53.556033 + ], + [ + 10.017631, + 53.555978 + ], + [ + 10.016821, + 53.555612 + ], + [ + 10.016641, + 53.555539 + ], + [ + 10.016578, + 53.555512 + ], + [ + 10.016454, + 53.555457 + ], + [ + 10.016324, + 53.555399 + ], + [ + 10.015911, + 53.555206 + ], + [ + 10.015577, + 53.555053 + ], + [ + 10.013961, + 53.554325 + ], + [ + 10.013866, + 53.554287 + ], + [ + 10.01378, + 53.554256 + ], + [ + 10.013684, + 53.554218 + ], + [ + 10.013613, + 53.554178 + ], + [ + 10.013545, + 53.554132 + ], + [ + 10.013499, + 53.554101 + ], + [ + 10.013473, + 53.554083 + ], + [ + 10.013419, + 53.554044 + ], + [ + 10.013343, + 53.553972 + ], + [ + 10.013311, + 53.55393 + ], + [ + 10.013274, + 53.553874 + ], + [ + 10.013243, + 53.553821 + ], + [ + 10.013201, + 53.553735 + ], + [ + 10.013173, + 53.553654 + ], + [ + 10.013153, + 53.553572 + ], + [ + 10.013139, + 53.553476 + ], + [ + 10.013137, + 53.553419 + ], + [ + 10.013145, + 53.553333 + ], + [ + 10.013177, + 53.553108 + ], + [ + 10.013199, + 53.552954 + ], + [ + 10.013229, + 53.552728 + ], + [ + 10.013239, + 53.552655 + ], + [ + 10.013254, + 53.552525 + ], + [ + 10.013269, + 53.552384 + ], + [ + 10.013487, + 53.552395 + ], + [ + 10.013654, + 53.552403 + ], + [ + 10.013794, + 53.55241 + ], + [ + 10.013867, + 53.552414 + ], + [ + 10.015428, + 53.552494 + ], + [ + 10.015509, + 53.552498 + ], + [ + 10.015564, + 53.552498 + ], + [ + 10.015602, + 53.552495 + ], + [ + 10.015636, + 53.552489 + ], + [ + 10.01567, + 53.552481 + ], + [ + 10.015708, + 53.552469 + ], + [ + 10.015739, + 53.552457 + ], + [ + 10.015765, + 53.552444 + ], + [ + 10.015791, + 53.552426 + ], + [ + 10.01581, + 53.552406 + ], + [ + 10.015823, + 53.552379 + ], + [ + 10.015846, + 53.552347 + ], + [ + 10.015853, + 53.552303 + ], + [ + 10.01586, + 53.552196 + ], + [ + 10.01586, + 53.552089 + ], + [ + 10.01586, + 53.55205 + ], + [ + 10.01585, + 53.551972 + ], + [ + 10.015848, + 53.551856 + ], + [ + 10.015848, + 53.551797 + ], + [ + 10.015851, + 53.55178 + ], + [ + 10.015858, + 53.551761 + ], + [ + 10.015919, + 53.551675 + ], + [ + 10.01616, + 53.55137 + ], + [ + 10.016184, + 53.551338 + ], + [ + 10.016616, + 53.550789 + ], + [ + 10.016777, + 53.550584 + ], + [ + 10.016804, + 53.550549 + ], + [ + 10.016881, + 53.550444 + ], + [ + 10.016384, + 53.55032 + ], + [ + 10.015937, + 53.550209 + ], + [ + 10.01564, + 53.550136 + ], + [ + 10.015452, + 53.550099 + ], + [ + 10.015129, + 53.550036 + ], + [ + 10.014851, + 53.549988 + ], + [ + 10.014488, + 53.549925 + ], + [ + 10.014274, + 53.549908 + ], + [ + 10.013843, + 53.549875 + ], + [ + 10.013388, + 53.549847 + ], + [ + 10.013184, + 53.549844 + ], + [ + 10.013034, + 53.549841 + ], + [ + 10.012922, + 53.549847 + ], + [ + 10.012741, + 53.549857 + ], + [ + 10.012615, + 53.549863 + ], + [ + 10.012285, + 53.54989 + ], + [ + 10.012198, + 53.549911 + ], + [ + 10.012147, + 53.549952 + ], + [ + 10.012069, + 53.550037 + ], + [ + 10.012026, + 53.550086 + ], + [ + 10.011856, + 53.550277 + ], + [ + 10.011723, + 53.550426 + ], + [ + 10.01155, + 53.550572 + ], + [ + 10.011454, + 53.550632 + ], + [ + 10.011303, + 53.550713 + ], + [ + 10.011231, + 53.550763 + ], + [ + 10.011181, + 53.550809 + ], + [ + 10.011156, + 53.55084 + ], + [ + 10.011141, + 53.550874 + ], + [ + 10.011112, + 53.550941 + ], + [ + 10.011109, + 53.550951 + ], + [ + 10.011094, + 53.551 + ], + [ + 10.011313, + 53.551028 + ], + [ + 10.011463, + 53.551049 + ], + [ + 10.011584, + 53.55107 + ], + [ + 10.011813, + 53.55111 + ], + [ + 10.011956, + 53.551139 + ], + [ + 10.012228, + 53.551244 + ], + [ + 10.012385, + 53.551283 + ], + [ + 10.012561, + 53.551321 + ], + [ + 10.012792, + 53.551363 + ], + [ + 10.013206, + 53.551437 + ], + [ + 10.013277, + 53.551451 + ], + [ + 10.013323, + 53.551464 + ], + [ + 10.013372, + 53.551482 + ], + [ + 10.013412, + 53.551502 + ], + [ + 10.013438, + 53.551522 + ], + [ + 10.013465, + 53.551543 + ], + [ + 10.013529, + 53.551614 + ], + [ + 10.013563, + 53.551663 + ], + [ + 10.013587, + 53.55172 + ], + [ + 10.013604, + 53.55177 + ], + [ + 10.01361, + 53.551826 + ], + [ + 10.013606, + 53.551876 + ], + [ + 10.013595, + 53.551928 + ], + [ + 10.013525, + 53.552231 + ], + [ + 10.013513, + 53.552283 + ], + [ + 10.013487, + 53.552395 + ], + [ + 10.013654, + 53.552403 + ], + [ + 10.013794, + 53.55241 + ], + [ + 10.013867, + 53.552414 + ], + [ + 10.015428, + 53.552494 + ], + [ + 10.015509, + 53.552498 + ], + [ + 10.015564, + 53.552498 + ], + [ + 10.015602, + 53.552495 + ], + [ + 10.015636, + 53.552489 + ], + [ + 10.01567, + 53.552481 + ], + [ + 10.015708, + 53.552469 + ], + [ + 10.015739, + 53.552457 + ], + [ + 10.015765, + 53.552444 + ], + [ + 10.015791, + 53.552426 + ], + [ + 10.01581, + 53.552406 + ], + [ + 10.015823, + 53.552379 + ], + [ + 10.015846, + 53.552347 + ], + [ + 10.015853, + 53.552303 + ], + [ + 10.01586, + 53.552196 + ], + [ + 10.01586, + 53.552089 + ], + [ + 10.01586, + 53.55205 + ], + [ + 10.01585, + 53.551972 + ], + [ + 10.015848, + 53.551856 + ], + [ + 10.016108, + 53.551885 + ], + [ + 10.016243, + 53.551907 + ], + [ + 10.016893, + 53.552031 + ], + [ + 10.017277, + 53.552108 + ], + [ + 10.017617, + 53.552182 + ], + [ + 10.017808, + 53.552226 + ], + [ + 10.01797, + 53.552269 + ], + [ + 10.018247, + 53.552354 + ], + [ + 10.018833, + 53.552524 + ], + [ + 10.018896, + 53.552543 + ], + [ + 10.018943, + 53.552557 + ], + [ + 10.019008, + 53.552577 + ], + [ + 10.019148, + 53.552619 + ], + [ + 10.019372, + 53.552684 + ], + [ + 10.019521, + 53.552725 + ], + [ + 10.019765, + 53.552788 + ], + [ + 10.020544, + 53.552946 + ], + [ + 10.020902, + 53.553006 + ], + [ + 10.020994, + 53.553021 + ], + [ + 10.021119, + 53.553039 + ], + [ + 10.022079, + 53.553174 + ], + [ + 10.022098, + 53.553177 + ] + ], + "type": "LineString" + }, + "weight": 595.6, + "duration": 595.6, + "distance": 5178.9 + } + ], + "waypoints": [ + { + "hint": "WEcUgP___38BAAAASAAAAAAAAAAUAAAAQKymP9hYnkIAAAAAosKwQQEAAABIAAAAAAAAABQAAAB3JgEA0uyYABkoMQOb7JgAnSgxAwAAzwQAAAAA", + "location": [ + 10.022098, + 53.553177 + ], + "name": "Beim Strohhause", + "distance": 15.13622773 + }, + { + "hint": "kj7Qgf___38TAAAAHgAAAAAAAAAEAAAAqhlgQeCL5UAAAAAAgGwzQBMAAAAeAAAAAAAAAAQAAAB3JgEANPWYAGUpMQPS9JgAyykxAwAAzwMAAAAA", + "location": [ + 10.024244, + 53.553509 + ], + "name": "Berliner Tor", + "distance": 13.07734535 + }, + { + "hint": "6_IjgP___38BAAAACAAAAAAAAAASAAAAkUyuP0W7_UAAAAAAZOqeQQEAAAAIAAAAAAAAABIAAAB3JgEApgCZANIzMQNxAJkAxDMxAwAA_xQAAAAA", + "location": [ + 10.027174, + 53.556178 + ], + "name": "Wallstra\u00dfe", + "distance": 3.841056617 + }, + { + "hint": "ALSQgP___38IAAAAEQAAAAAAAAAlAAAATz8PQVBqGUEAAAAALlKUQQgAAAARAAAAAAAAACUAAAB3JgEARfGYABI9MQPC8ZgAJjwxAwAAzw8AAAAA", + "location": [ + 10.023237, + 53.558546 + ], + "name": "L\u00fcbeckertordamm", + "distance": 27.54034679 + }, + { + "hint": "-uMkj____38CAAAABwAAAMoAAAAAAAAABxUpQKz8s0BC80lDAAAAAAIAAAAHAAAAygAAAAAAAAB3JgEAIcuYAKMrMQNLy5gAjisxAxAAvw0AAAAA", + "location": [ + 10.013473, + 53.554083 + ], + "name": "Steindamm", + "distance": 3.633606067 + }, + { + "hint": "U1iBgP___38EAAAACQAAALIAAAAAAAAA2R80QOJaPECQxNJCAAAAAAQAAAAJAAAAsgAAAAAAAAB3JgEA_sqYAKIhMQPWypgAtCExAxIAXwIAAAAA", + "location": [ + 10.013438, + 53.551522 + ], + "name": "Kurt-Schumacher-Allee", + "distance": 3.321773595 + }, + { + "hint": "WEcUgP___38BAAAASAAAAAAAAAAUAAAAQKymP9hYnkIAAAAAosKwQQEAAABIAAAAAAAAABQAAAB3JgEA0uyYABkoMQOb7JgAnSgxAwAAzwQAAAAA", + "location": [ + 10.022098, + 53.553177 + ], + "name": "Beim Strohhause", + "distance": 15.13622773 + } + ] +} \ No newline at end of file