ProjectNeura / LEADS

Build your race-ready electric car in 10 minutes with powerful electronic stability control and a modern dashboard.
https://leads.projectneura.org
Apache License 2.0
246 stars 53 forks source link

Add Historical Traces to the Map #72

Closed ATATC closed 1 month ago

ATATC commented 3 months ago

To better analyze and improve driving strategies, we want the historical traces to be displayed as a floating layer on the map. A detailed introduction will be later added in a periodic report.

ATATC commented 3 months ago

See https://github.com/ProjectNeura/LEADS/blob/master/docs/reports/2024-03-07.md.

ATATC commented 3 months ago

Here's the .gpx data for the 2023 Waterloo EV Challenge downloaded from Strava. You will need to scrub the data to get the course route with and without the pit. There's some extraneous data as well but I am sure you will be able to pick that out. Here's the Strava link if you want to view the data on their app but it's easy enough to upload to google earth/maps.

ATATC commented 3 months ago

Waterloo_Electric_Vehicle_Challenge_2023.txt

qmascarenhas commented 3 months ago

See https://github.com/ProjectNeura/LEADS/blob/master/docs/reports/2024-03-07.md.

@HaydenHour Please see one of us if you have any questions about this task.

ATATC commented 3 months ago

Accidentally mentioned this issue. It should be #73.

qmascarenhas commented 3 months ago

@HaydenHour Any update on this? Can you give us some more information on where you're stuck?

HaydenHour commented 2 months ago

@ATATC @qmascarenhas Sorry I did not post sooner, I did not have access to my laptop over the weekend. It appears that the code is hitting an issue when trying to read the GPX file (specifically regarding the parse function on line 10). This is my code below:

import gpxpy

def gpx_to_custom_csv(gpx_file_path, output_csv_file_path):

    # Open GPX file
    with open(gpx_file_path, 'r') as gpx_file:

        #Issue appears to be here with the parse
        gpx = gpxpy.parse(gpx_file)

        # write data in CSV format
    with open(output_csv_file_path, 'w') as csv_file:
        for track in gpx.tracks:
            for segment in track.segments:
                for point in segment.points:
                    # Write latitude and longitude separated by semicolon
                    csv_file.write(f"{point.latitude};{point.longitude},")

# file paths:
gpx_file_path = "C:/Users/hayde/OneDrive/VeC/Waterloo_Electric_Vehicle_Challenge_2023.gpx"
output_csv_file_path = "C:/Users/hayde/OneDrive/VeC/VEC2023_CSV.csv"
gpx_to_custom_csv(gpx_file_path, output_csv_file_path)
ATATC commented 2 months ago

Please provide the error message.

ATATC commented 2 months ago

This works for me.

HaydenHour commented 2 months ago

Oh, that's weird. So did it create a new file with the right formatting?

ATATC commented 2 months ago

I haven't tested the file part. I replaced it with print(). But I believe write overwrites the file. There should be an appending function.

ATATC commented 2 months ago

Btw please fork the repository to be ready to merge your contributions.

ATATC commented 1 month ago

I'm gonna finish this feature (including auto corner speed marking) for the website this week.

ATATC commented 1 month ago

@qmascarenhas Now you can directly import the previously recorded data onto the website and move your mouse close to the corners to check the data at that point. image image

qmascarenhas commented 1 month ago

This is excellent @ATATC !

ATATC commented 1 month ago

@HaydenHour Sorry for the wrong instructions previously. I had some misunderstanding about CSV files. I'll provide a new handout later.

ATATC commented 1 month ago

Result

@HaydenHour Take a look if you want.

2023.csv

from gpxpy import parse
from leads.data_persistence import CSVCollection

def gpx_to_custom_csv(gpx_file_path: str, output_csv_file_path: str) -> None:
    with open(gpx_file_path, 'r') as gpx_file:
        gpx = parse(gpx_file)
    csv = CSVCollection(output_csv_file_path, ("t", "voltage", "speed", "front_wheel_speed", "rear_wheel_speed",
                                               "forward_acceleration", "lateral_acceleration", "mileage", "gps_valid",
                                               "gps_ground_speed", "latitude", "longitude"))
    for track in gpx.tracks:
        for segment in track.segments:
            for point in segment.points:
                csv.write_frame(int(point.time.timestamp() * 1000), *((None,) * 9), point.latitude, point.longitude)

gpx_to_custom_csv("Waterloo_Electric_Vehicle_Challenge_2023.gpx", "data/2023.csv")
ATATC commented 1 month ago

Result

An enhanced version with inferred speeds.

2023.csv

from gpxpy import parse
from leads.data_persistence import CSVCollection, DEFAULT_HEADER
from leads.data import dlat2meters, dlon2meters

def gpx_to_custom_csv(gpx_file_path: str, output_csv_file_path: str) -> None:
    with open(gpx_file_path, 'r') as gpx_file:
        gpx = parse(gpx_file)
    csv = CSVCollection(output_csv_file_path, DEFAULT_HEADER)
    # prev time
    t_0 = None
    # prev latitude
    lat_0 = None
    # prev longitude
    lon_0 = None
    for track in gpx.tracks:
        for segment in track.segments:
            for point in segment.points:
                t = point.time.timestamp()
                lat = point.latitude
                lon = point.longitude
                if t_0 is None or lat_0 is None or lon_0 is None:
                    t_0, lat_0, lon_0 = t, lat, lon
                    csv.write_frame(int(t * 1000), *((None,) * 7), True, None, lat, lon)
                    continue
                # dt
                dt = t - t_0
                dlat = lat - lat_0
                dlon = lon - lon_0
                # dy
                dy = dlat2meters(dlat)
                # dx
                dx = dlon2meters(dlon, .5 * (lat_0 + lat))
                # c
                hyp = (dy ** 2 + dx ** 2) ** 0.5
                # v
                v = hyp / dt
                # m/s to km/h
                v *= 3.6

                t_0 = t
                lat_0 = lat
                lon_0 = lon

                csv.write_frame(int(t * 1000), None, v, v, v, *((None,) * 3), True, v, lat, lon)

gpx_to_custom_csv("Waterloo_Electric_Vehicle_Challenge_2023.gpx", "data/2023.csv")