Optimizer

Objective

Generate an optimized velocity profile that minimizes energy,

while keeping velocity and time within given constraints

User input data using parser

distance: (float) Distance to travel (m) Not used

dist_step: (float) Distance between elevation profile measurements (m)

time: (float) Maximum allowable to travel the distance (m/s)

min_velocity: (float) Minimum allowable velocity (m/s)

max_stop_velocity: (float) Maximum velocity for stops/turns (m/s)

Required Elevation File

Text File (COTAelevation_var.txt used in optimizer.py)

  • First row states how many points/sections in a route

  • Each row after the first represents a section of a course. For each row:

    • The index of row

    • change of elevation (starting point of section → end point of section)

    • length of section

    • If there is a turn after this section: Indication of turn

These values are separated by comma.

Example (lines after 16 are omitted, there are 185 lines in total):

181 points 1,0.0,30 2,0.0,30 3,0.0,30 4,0.0,30 5,0.0,30 6,0.0,30 7,0.0,30 8,0.0,30, Turn_1 9,0.0,30 10,0.0,30 11,0.0,30 12,0.0,30 13,0.0,30 14,0.6,30 15,0.9,30, Turn_2

Code Breakdown

The load_course_map() function

  • Parameters:

    • course_name : (str) The name of the course we’re trying to load in

  • Returns:

    • elev_profile: (2D float list)

      • Each row represents a section of a course

      • column 0: the pitch/slope/steepness of the section (rad)

      • column 1: the length of the section (m)

    • stops : (float list)

      • Each element is the index of where each turns are (corresponds to row index in elev_profile)

    • total_dist: (float) All section lengths added up. Total distance. (m)

  • Note:

    • Here we access the elevation text file mentioned above that we will have prior to the competition, and generate 3 return values by extracting data from it.

The generate_initial_profile() function

  • Parameters:

    • time: (float) The maximum allowable time to cover a distance (s),

    • distanc:(float) the distance to be covered (m)

    • e_profile: (2D list)

      • Each row represents a section of a course

      • column 0: the pitch/slope/steepness of the section (rad)

      • column 1: the length/distance of the section (m)

    • min_velocity (float) the minimum allowable velocity (m/s),

    • stop_profile (list) list of indices where the car must stop

    • max_stop_velocity (float) The maximum allowable velocity for stops and turns (m/s)

  • Returns: initial_profile : A map of the same dimensions as the map of elevations with each element representing the average velocity required for the car to move at each point on the map of elevations.

  • Note:

    • Ex. initial_profile[2] = 10 means that according to the initial profile, the car should be moving 10 m/s at point 3 (Index 2) on the map of elevations.

    • This function basically generates the naive/initial solution that will be improved upon through the optimization function later in the program.

    • Only three possible velocity values are stored in initial_profile.

      • Cruise avg_velocity when we can

      • When we can't, we just go max_v or min_velocity

         

MAIN (functions below are inside main):

The objective()function

  • Parameters:

    • v_profile: (list) each element represents the average velocity (m/s) required for the car to move at each section/point in a route.

  • Returns:

    • energy / 1000000 (float):

    • The amount of energy used by the car as a result of driving at the stated velocities in v_profile throughout each point on the map of elevations. The energy usage is calculated by a function located in car_model.py, energy_used().

  • This objective function will be minimized by the optimization function later in the program because we’d want to minimize how much energy the car uses.

The time_constraint() function

  • Parameters:

    • v_profile: (list) each element represents the average velocity (m/s) required for the car to move at each section/point in a route.

  • Returns:

    • time-sum(time_used)

      • Time spent driving as a result of moving at the stated velocities in v_profile throughout each point on the map of elevations subtracted from the maximum allowable time by the competition.

  • Basically returns how much more time we used than is allowed

  • Time used by the v-profile shouldn’t be greater than the maximum time specified by the user.

    • If so, then the return value is negative.

      • Used as a constraint for the optimization function later in the program.

The speed_constraint()function

  • Parameters:

    • v_profile: (list) each element represents the average velocity (m/s) required for the car to move at each section/point in a route.

  • Returns:

    • error: The negative sum of how much the car’s velocity in v_profile is greater than the maximum velocity at each point in the map of elevations

      • If the velocity in v_profile isn’t greater than the maximum velocity at a certain point, the error variable will not be incremented.

      • Used as a constraint for the optimization function later in the program.

  • Note:

    • The maximum velocity is calculated by calling the max_velocity function from car_model.py

    • When calculating the maximum velocity on a certain section, we do not pass the angle of elevation/theta/pitch as parameter to car.max_velocity() function

      • We believe this is error in the code, as we would not be accurately calculate the max_velocity

 

Solution

  • Calculated using scipy.optimize’s minimize function with the objective function as the function that will be minimized, v0 as the initial profile (naive solution), the bounds being the minimum and maximum velocity, Sequential Least SQuares Programming (SLSQP) optimizer as the method of minimizing the objective function, and the constraints being the speed_constraint and time_constraint function.

solution = minimize(objective, v0, method='SLSQP', bounds=bounds, constraints=conditions)