-
Notifications
You must be signed in to change notification settings - Fork 0
/
race_02.py
143 lines (123 loc) · 4.98 KB
/
race_02.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
132
133
134
135
136
137
138
139
140
141
142
143
# Welcome to the Race 2 of the Spherical Car Racing tournament!
#
# Today, we're going to have a slightly more complicated race:
# You need to drive a 100-meter section of a straight road as quickly as possible.
# You can enter the section at any speed, but your speed at the end of the
# section should be 30 m/s or lower.
#
# Note that due to rounding errors you might not be able to have the exit speed
# precisely match 30 m/s.
#
# 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 = 2.386
from common import *
import math
import solver
RACE_DISTANCE = 100 # meters. We're using the SI system here.
MAX_SPEED_AT_FINISH = 30 # m/s.
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
# 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.
# This time, you can control the initial speed.
INITIAL_SPEED = 30 # m/s.
# 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 < 69:
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:
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:
if velocities[0] <= MAX_SPEED_AT_FINISH:
print(f"Finished in {time:.3f} seconds.")
compare_lap_time_with_record_and_reference(time, RECORD, 2.905)
print(f"Distance traveled: {positions[0]:.1f} meters.")
print(f"Speed at the finish: {velocities[0]:.2f} m/s.")
else:
print("DISQUALIFIED!")
print(f"Finished the race in {time:.3f} seconds,")
print(f"but the speed at the finish was too high ({velocities[0]:.2f} m/s.)")
else:
print(f"DNF")
finally:
if len(data_log[0][0]):
try:
import data_log_plotter
graphs_filename = "race_02.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()