Telemetry Export for Video Overlays
How to turn your Zero's diagnostic logs into a CSV or GPX you can drag into Telemetry Overlay, RaceRender, Dashware, Insta360 Studio, Garmin VIRB Edit, and friends.
TL;DR
No GPS in your video editor? Use CSV (no GPS) — sync to your video by aligning t_seconds = 0 to a known frame. Have GPS from your phone or Garmin? Use GPX merge — we attach Zero metrics as <extensions> to your trackpoints.
Densification (resampling to 1Hz) is optional and off by default. Read the "When to densify" section before turning it on.
Which format should I use?
Quick decision tree based on what you have and what you want.
CSV — fast, no GPS needed
Pure telemetry: timestamp + speed + SOC + voltage + temperatures + everything else, one row per sample.
- You don't have a separate GPS recording
- You only need data gauges (speed, kW, temps), not a map
- Your editor is Telemetry Overlay, RaceRender, or Dashware
- You're syncing manually to a video (drag to position in timeline)
- Identify a known moment in your video (engine start, throttle wide-open, etc.)
- Find the same moment in the CSV (e.g.
speed_kmhjumps from 0 to non-zero) - Note the
t_secondsat that moment - In your video editor, align the data clip so that the moment lands on the same video frame
GPX — your GPS + Zero metrics
Your GPS track from a phone app or Garmin, enriched per-trackpoint with Zero telemetry as XML extensions.
- You recorded GPS with a phone app (Strava, OsmAnd, Wahoo, GaiaGPS, etc.)
- You have a Garmin Edge / Forerunner / VIRB recording the ride
- You want a map overlay in the video (not just gauges)
- Your editor is Insta360 Studio, Garmin VIRB Edit, or Telemetry Overlay
Zero motorcycles don't broadcast GPS coordinates in their diagnostic logs. A GPX without lat/lon is invalid. Some tools fake coordinates from speed integration — we don't, because it lies about where you were.
Compatibility with video tools
Which exports work with which editors. = works, ~ = partial / manual mapping needed, — = not supported.
| Tool | CSV | GPX | Needs GPS | Notes |
|---|---|---|---|---|
| Telemetry Overlay | no | Most flexible. Reads CSV without GPS, GPX with extensions, gauges + graphs + maps. | ||
| RaceRender | no | Drag CSV in, map columns to gauges. GPS optional. | ||
| Dashware | ~ | no | CSV-first; you map columns manually to gauges. GPS not required. | |
| GoPro Quik (native) | — | — | yes | Reads only GPMF embedded by GoPro hardware. Use Telemetry Overlay alongside it. |
| DJI native overlay | — | — | yes | Locked to DJI SRT/DAT. Use Telemetry Overlay for Zero data on DJI footage. |
| Insta360 Studio | — | yes | GPX with GPS for path overlay. Use the GPX merge mode. | |
| Garmin VIRB Edit | — | yes | GPX or FIT. Reads Garmin TrackPointExtension (atemp emitted by us). | |
| Race Chrono | yes | Lap timer + overlay. Needs GPS to be useful. | ||
| Harry's Lap Timer | yes | Lap analysis app. CSV import for non-GPS data + paired GPX. | ||
| TrackAddict | yes | Lap timer; CSV import works but GPS-centric. |
For best results across most editors we recommend Telemetry Overlay — it accepts both CSV and GPX, supports the Zero zero: namespace via custom field mappings, and ships per-frame interpolation.
Gen2 vs Gen3: why Gen3 may need two files
How telemetry coverage differs by generation, and what we do about it.
Gen2 (S, SR, DS, FX, FXS, FXE)
One log file is enough. The MBB log on Gen2 carries motor data and battery data together (because the BMS publishes onto the bike's CAN bus and MBB logs both).
Sample rate: roughly 0.5–2 Hz during riding. The CSV will have most columns populated.
Gen3 — two flavours
Zero's "Gen3" label covers two different hardware lineups, both running Cypher III firmware:
- FXE — Cypher III firmware on older XMX hardware. Its MBB log is rich (speed, RPM, voltage, SOC, temps, odo) — works like a Gen2 export.
- SR/F · SR/S · DSR/X (FST platform) — Cypher III firmware on new hardware. Motor telemetry moved into the BMS. The MBB log carries bike state, power limits, and odometer; the BMS log carries voltage, current, SOC, cell data, temperatures.
If you upload both MBB and BMS for an FST bike, we automatically merge them by timestamp (within 30 seconds). The Export dialog shows "Gen3 MBB+BMS merged" and the CSV filename includes _merged.
On SR/F · SR/S · DSR/X the MBB binary doesn't contain motor data — those bytes are zero on the bus. Speed/RPM/throttle won't appear in the CSV no matter what you upload. FXE bikes are unaffected.
Gen3 logs use a ring buffer that retains roughly 5–7 days of data. If you're trying to export a ride from two weeks ago and the data isn't there, the buffer overwrote it. See Why Your Gen3 Log Shows No Rides for the full story.
What you'll get per generation, in practice
| Field | Gen2 | FXE (Gen3 / XMX) | SR/F · SR/S · DSR/X |
|---|---|---|---|
| speed_kmh | ✓ | ✓ | no (hw) |
| motor_rpm | ✓ | ✓ | no (hw) |
| throttle_pct | no | no | no |
| pack_voltage_v | ✓ | ✓ | ✓ BMS |
| pack_current_a | ✓ | ✓ | ✓ BMS |
| power_kw | ✓ | ✓ | ✓ BMS |
| soc_pct | ✓ | ✓ | ✓ BMS |
| battery_temp_c | ✓ | ✓ | ✓ BMS |
| motor_temp_c | ✓ | ✓ | ~ |
| controller_temp_c | ✓ | ✓ | ~ |
| odometer_km | ✓ | ✓ | ~ |
| cell_voltage_min/max/delta | partial | ✓ | ✓ BMS |
| bike_state | — | ✓ | ✓ |
| discharge_limit_kw / charge_limit_kw | — | ✓ | ✓ |
FXE is Gen3 in firmware terms (Cypher III stack) but rides on the older XMX hardware platform — so its MBB log keeps the rich Gen2-style motor telemetry. The newer FST bikes (SR/F, SR/S, DSR/X) consolidated motor instrumentation into the BMS, which is why their MBB logs don't carry speed/RPM. Always upload both MBB and BMS for SR/F-class bikes to get the full picture.
"no (hw)" means the bytes are physically absent from the binary on that hardware. "sparse" means present on a fraction of samples — densification helps fill gaps inside an active ride. "throttle_pct" is in the schema but not extracted by the upstream binary parser yet.
Densification: when (and why not) to use it
Native sample rates vs resampling to a regular grid.
Native (default): we hand you exactly what your bike recorded. Timestamps are irregular (whatever the firmware decided to log), but every value is real.
Resampled to 1 Hz: we lay down a regular one-sample-per-second grid and fill it with linear interpolation between your real samples for numeric values (speed, voltage, temps) and forward-fill for state values (RUN/STOP/CHRG, charging on/off).
We never interpolate across gaps larger than 60 seconds — if your bike sat in HIB (deep sleep) for 10 minutes, the CSV will show that gap as a gap, not as fabricated data.
Turn densification ON when
- You want smooth needle/gauge animations in the overlay
- Your editor expects regular-rate input (some legacy tools)
- You're building a chart that doesn't tolerate timestamp gaps
- You're using RaceRender's generic data import (prefers regular cadence)
Leave densification OFF when
- You want forensic accuracy (incident analysis, warranty disputes)
- Your tool natively interpolates (Telemetry Overlay does)
- You're feeding the CSV to other software for analysis (pandas, R)
- You'd rather see real gaps than synthetic smoothness
Step-by-step: CSV in Telemetry Overlay
A worked example with the most common workflow.
- 1Open your report
Pick the log file on your reports page. If it's a Gen3 ride, make sure both the MBB and BMS files for that day are uploaded — they'll auto-merge.
- 2(Optional) Click into the specific ride session
If you only want a fragment, click the ride session card. The Export dialog will pre-fill that ride's start/end as a custom range — saves you typing.
- 3Open Export → Telemetry (CSV / GPX)
Top right of the report page. Stay on the CSV tab. Leave "Resample to 1 Hz" off unless your editor needs it. Click Download CSV.
- 4Drop the CSV into Telemetry Overlay
Drag the file onto the Telemetry Overlay window. It auto-detects ISO timestamps. Pick the columns you want as gauges (speed_kmh, soc_pct, pack_voltage_v are good defaults).
- 5Sync to your video
Find a moment that's identifiable in both the data and the footage (engine start; first hard pull; arriving home → speed drops to 0). Set the data offset so they line up. Render.
CSV column reference
All columns in the exported CSV. Empty cell = the field wasn't recorded for that timestamp.
| Column | Unit | Source | What it tells you |
|---|---|---|---|
| timestamp_iso | ISO 8601 | both | Absolute time of the sample (with timezone) |
| t_seconds | s | derived | Seconds from the first row — your sync handle |
| speed_kmh | km/h | MBB | Vehicle speed |
| throttle_pct | % | MBB | Throttle position |
| motor_rpm | RPM | MBB | Motor revolutions per minute |
| torque_nm | Nm | derived | Calculated as power × 9549 / RPM |
| pack_voltage_v | V | BMS / Gen2 MBB | Total pack voltage |
| pack_current_a | A | BMS / Gen2 MBB | Negative when discharging, positive when charging |
| power_kw | kW | derived | V × A / 1000 |
| soc_pct | % | BMS / Gen2 MBB | State of charge |
| motor_temp_c | °C | MBB | Motor temperature |
| battery_temp_c | °C | BMS / Gen2 MBB | Battery pack temperature |
| controller_temp_c | °C | MBB | Motor controller temperature |
| ambient_temp_c | °C | both | Ambient temperature (where available) |
| odometer_km | km | MBB | Lifetime odometer reading |
| discharge_limit_kw | kW | Gen3 MBB | BMS-imposed power ceiling (low SOC, hot pack, etc.) |
| charge_limit_kw | kW | Gen3 MBB | Maximum allowed charge rate at this moment |
| cell_voltage_min_v | V | BMS | Lowest individual cell voltage |
| cell_voltage_max_v | V | BMS | Highest individual cell voltage |
| cell_voltage_delta_v | V | BMS | Spread between min and max — health indicator |
| cell_voltage_ocv_min_v | V | Gen3 BMS | Open-circuit voltage of the lowest cell |
| bike_state | — | Gen3 | RUN / STOP / CHRG / HIB / WAIT / WAKE / STRT / PWSU |
| is_charging | 0/1 | both | Charging session active |
| is_under_load | 0/1 | Gen3 BMS | BMS sees significant current draw |
GPX extension reference
The enriched GPX is a valid GPX 1.1 file (your editor will load it). Extra Zero metrics live in two namespaces inside <extensions> blocks:
Garmin standard. We emit gpxtpx:atemp (ambient temperature) when present. Read by Garmin VIRB Edit, Connect, and most GPS analytics tools.
Custom Zero namespace for everything specific to electric motorcycles:
<zero:speed_kmh> <zero:throttle_pct> <zero:motor_rpm> <zero:torque_nm> <zero:voltage_v> <zero:current_a> <zero:power_kw> <zero:soc_pct> <zero:motor_temp_c> <zero:battery_temp_c> <zero:controller_temp_c> <zero:odometer_km> <zero:state>
Editors that don't understand the namespace will silently ignore it (per XML rules) — no harm done.
FAQ
You probably exported a Gen3 BMS log on its own — BMS only carries battery data. Upload the matching MBB log too; we'll auto-merge them.
Your GPS track and the Zero log don't overlap in time. Check both clocks — phone GPS is usually correct; if your bike clock drifted, use the "Time offset (seconds)" field in the GPX merge dialog.
Native rate is 0.5–2 Hz on Gen2 and event-driven on Gen3 (sparse during HIB, dense during RUN). A 30-minute ride is typically 1500–3000 rows. Turn on densification if you want a regular 1Hz grid.
Not yet. FIT is on the roadmap. For now, export GPX (with your GPS) and upload that to Strava — Zero metrics travel as extensions.
It goes to our backend for processing (we need server-side resources to query telemetry and align by timestamp), but we don't store it. The merged result is streamed back and not persisted.
For each GPS trackpoint we look for the nearest Zero telemetry sample. If the closest one is more than this many seconds away, we leave that trackpoint without telemetry rather than attaching wrong data. 5 seconds is usually right.
It would be wrong. Heading isn't logged, so any reconstruction is a straight line — which lies about your route. We'd rather you bring real GPS.
Honesty. Showing real samples means the viewer sees what the bike actually recorded, including gaps. Interpolation invents data that wasn't there. Most overlay tools do their own interpolation at render time anyway.
Ready to overlay your Zero ride?
Open one of your reports and click Export → Telemetry. If you don't have any logs uploaded yet, start there.