-
Notifications
You must be signed in to change notification settings - Fork 0
/
race_01.py
131 lines (112 loc) · 4.39 KB
/
race_01.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# Welcome to the Race 1 of the Spherical Car Racing tournament!
#
# Today, we're going to have a simple race:
# You start from a standstill, and your task is to:
# 1) travel at least 1 mile (1609 meters) in total, and
# 2) come to a stop.
#
# Only modify the code between the "LADIES AND GENTLEMEN, START YOUR ENGINES"
# and the "FINISH" lines.
# This is the current record. Can you match or even beat it?
RECORD = 31.896
from common import *
import math
import solver
RACE_DISTANCE = 1609 # meters. We're using the SI system here.
TIME_LIMIT = 50 # seconds.
# For simplicity, the car is AWD with CVT.
# Furthermore, these spherical cars race in vacuum, so there's no aero drag.
MASS = 1000 # kg.
POWER = 150000 # Watts. This is ~200 whp.
TRACTION = 10 # m/s^2.
INITIAL_POSITION = 0
INITIAL_SPEED = 0
# LADIES AND GENTLEMEN, START YOUR ENGINES
#
# Below is a very naive (and not the fastest!) solution.
# Edit it to your liking and see how much faster you can make the driver.
#
# Tip: try to solve this using your physics knowledge.
# Brownie points if your solution provides the fastest result for any RACE_DISTANCE.
# my_driver_algorithm(x, v, t) defines how your driver will drive.
#
# Inputs:
# x: distance from the start position
# v: speed
# t: time since the start of the race
#
# Returns driver input (to the car), encoded as:
# 1 for maximum acceleration (think of it as an accelerator pedal),
# -1 for maximum braking (think of it as a brake pedal),
# anything in between -1 and 1 for partial acceleration/braking.
#
# This spherical car has traction control, meaning if the driver requests more
# power than the tires can handle, the car will only use the amount of power the
# tires can handle.
def my_driver_algorithm(x, v, t):
if x < RACE_DISTANCE:
return 1
else:
return -1
# # # # # # # # # # # # # # # # # # # # #
# # # # # # # # FINISH! # # # # # # # # #
# # # # # # # # # # # # # # # # # # # # #
def convert_racer_algorithm_to_acceleration(driver_input, v):
if driver_input > 1:
raise Exception(f"Too much throttle requested: {driver_input}")
if driver_input < -1:
raise Exception(f"Too much braking requested: {driver_input}")
if driver_input > 0:
# Power = Force * Velocity.
# At low speeds, the car is traction limited and the TC kicks in:
if driver_input * POWER >= TRACTION * MASS * v:
return TRACTION
# Beyond that, it's power-limited:
return driver_input * POWER / (v * MASS)
else:
# Braking.
return driver_input * TRACTION
def calculate_accelerations_p_v_t(positions, velocities, t):
x = positions[0]
v = velocities[0]
return [convert_racer_algorithm_to_acceleration(my_driver_algorithm(x, v, t), v)]
data_log = [
([], "distance, m", "time, sec"),
([], "speed, m/s", "time, sec"),
([], "speed, m/s", "distance, m")
]
def progress_listener_callback_p_v_t(positions, velocities, t):
if velocities[0] < 0 and positions[0] < RACE_DISTANCE:
raise Exception(f"The car went backwards! Position = {positions[0]}, velocity = {velocities[0]}")
data_log[0][0].append((positions[0], t))
data_log[1][0].append((velocities[0], t))
data_log[2][0].append((velocities[0], positions[0]))
if positions[0] >= RACE_DISTANCE and velocities[0] <= 0:
return True # Finished!
return False
def main():
try:
positions, velocities, time = solver.solveRK4(
[INITIAL_POSITION], [INITIAL_SPEED],
calculate_accelerations_p_v_t,
TIME_LIMIT, 0.001,
progress_listener_callback_p_v_t)
if time < TIME_LIMIT:
print(f"Finished in {time:.3f} seconds.")
compare_lap_time_with_record_and_reference(time, RECORD, 36.569)
print(f"Distance traveled: {positions[0]:.1f} meters.")
else:
print(f"DNF")
finally:
if len(data_log[0][0]):
try:
import data_log_plotter
graphs_filename = "race_01.png"
data_log_plotter.plot_graphs(data_log, graphs_filename)
print(f"Graphs for the data log were rendered to '{graphs_filename}'.")
except ModuleNotFoundError:
print("Unable to plot the graphs, please install Pillow. See README for tips.")
else:
print("Warning: no data log collected, not plotting the graphs.")
if __name__ == '__main__':
main()