In [1]:
%matplotlib inline
DEFAULT_FIGSIZE = (12, 8)
import itertools
import sys
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
sns.set_style('darkgrid')
sys.path.append('..')
from antlia.record import load_records
from antlia import plot_braking as braking
%load_ext autoreload
%autoreload 2
import matplotlib as mpl
mpl.rcParams['figure.figsize'] = DEFAULT_FIGSIZE
In [2]:
records = load_records(sync=True)
In [3]:
import IPython.display
def animate_braking(rid, tid, xlim, ylim, speedup=1, **kwargs):
record = records[rid]
trial = record.trial[tid]
m, _, _, _ = braking.get_metrics(trial.data)
t0 = m['braking starttime']
t1 = m['braking endtime']
frames = record.lidar.frame(lambda t: (t >= t0 - 1) & (t < t1 + 1))
c = sns.color_palette('Paired', 10)[1::2]
colors = [c[2]
if (t > t0) and (t < t1) else c[1]
for t in frames.time]
return frames.animate(xlim, ylim, speedup, colors, **kwargs)
def display_animation(animation):
plt.close(animation._fig)
IPython.display.display(IPython.display.HTML(ani.to_html5_video()))
for rid, tid in [[0, 6]]:
#for rid, tid in itertools.product(range(3, 4), range(1)):
record = records[rid]
trial = record.trial[tid]
ani = animate_braking(rid, tid,
xlim=(0, 50),
ylim=(0, 2),
speedup=0.5,
plot_kwargs={'marker': 'o'})
ani._fig.get_axes()[0].set_title('rider {} trial {:02d}'.format(rid, tid))
display_animation(ani)
In [4]:
## calculate forward length
# We make some simplifications in the bicycle geometry
# (namely ignoring changes in roll and pitch, and mostly
# assuming yaw to be zero) as they will be small as we
# are near the nominal orientation.
bb_to_front_hub = 0.655 # m
front_wheel_radius = 0.359 # m
head_tube_angle = (90 - 72) * np.pi/180 # rad TODO: measure this
import sympy
import sympy.physics.vector as sv
yaw, steer = sympy.symbols('yaw steer')
N = sv.ReferenceFrame('N')
A = N.orientnew('A', 'axis', [yaw, N.z])
B = A.orientnew('B', 'axis', [head_tube_angle, A.y])
C = B.orientnew('C', 'axis', [steer, B.z])
# vector pointing from front hub center to most forward
# point on front wheel
n = sv.cross(C.y, N.z).normalize()
o = sv.Point('o')
p = o.locatenew('p', bb_to_front_hub*A.x + front_wheel_radius*n)
d = sv.dot(p.pos_from(o), N.x)
def forward_length(steer_angle, yaw_angle = 0):
# distance from bottom bracket to front hub,
# projected onto rear frame body fixed x-axis
return d.subs({yaw: yaw_angle, steer: steer_angle})
print(forward_length(0))
print(forward_length(15*np.pi/180))
print(forward_length(-15*np.pi/180))
print(forward_length(30*np.pi/180))
print(forward_length(-30*np.pi/180))
In [5]:
plt.close('all')
for rid, tid in [[0, 2]]:
record = records[rid]
trial = record.trial[tid]
try:
m, _, _, _ = braking.get_metrics(trial.data)
except TypeError:
continue
print('rider {}, trial {}'.format(rid, tid))
index1 = record.lidar.frame_index(m['braking starttime'][0])
xlim = (0, 50)
ylim = (0.5, 1.5)
fig, ax = plt.subplots()
x, y = record.lidar[index1 - 1].cartesian(xlim=xlim, ylim=ylim)
ax.plot(x.compressed(), y.compressed(), linestyle=' ', marker='.')
x, y = record.lidar[index1].cartesian(xlim=xlim, ylim=ylim)
ax.plot(x.compressed(), y.compressed(), linestyle=' ', marker='.')
ax.set_xlabel('position [m]')
ax.set_ylabel('position [m]')
ax.set_xlim((0, 50))
ax.set_ylim(ylim)
rider_x = x[np.where((x > 10) & (x < 48))]
print('average rider x: {}'.format(rider_x.mean()))
# from bottom bracket to front wheel center
# projected on inertia x-axis
dtc1 = 50 - rider_x.mean() - 0.580
print('trial dtc, fl = .580: {}'.format(dtc1))
steer_angle = np.interp(m['braking starttime'][0],
trial.data.time,
trial.data['steer angle'])
dtc2 = 50 - rider_x.mean() - forward_length(steer_angle)
print('trial dtc, fl func: {}'.format(dtc2))
plt.show()
In [6]:
def calculate_dtc(rid, tid):
record = records[rid]
trial = record.trial[tid]
m, _, _, _ = braking.get_metrics(trial.data)
index = record.lidar.frame_index(m['braking starttime'][0])
index = [-1 + index, index]
xlim = (0, 50)
ylim = (0.5, 1.5)
dtc = []
for i in index:
x, _ = record.lidar[[i]].cartesian(xlim=xlim, ylim=ylim)
x = x.compressed()
rider_x = x[np.where((x > 10) & (x < 48))]
steer_angle = np.interp(record.lidar[i].time[0],
trial.data.time,
trial.data['steer angle'])
dtc.append(50 - rider_x.mean() - forward_length(steer_angle))
dtc = np.array(dtc).astype(np.float64)
t = record.lidar[np.array(index)].time.flatten()
return np.interp(m['braking starttime'][0], t, dtc), m
calculate_dtc(0, 2)
Out[6]:
In [7]:
import pandas as pd
def get_dataframe(records):
"""Define function to get metrics for lidar data.
"""
metrics = []
dtc = []
for rid, tid in itertools.product(range(4), range(15)):
try:
x, m = calculate_dtc(rid, tid)
except TypeError:
print('skipping {}, {}'.format(rid, tid))
continue
dtc.append(x)
m['rider id'] = rid
m['trial id'] = tid
metrics.append(m)
metrics = np.concatenate(metrics)
# exclude non-scalar fields
names = [dtype[0]
for dtype in metrics.dtype.fields.items()
if dtype[1][0].shape == ()]
df = pd.DataFrame(metrics[names])
df['distance-to-collision'] = dtc
f = lambda row: row['distance-to-collision']/row['starting velocity']
df['time-to-collision'] = df.apply(f, axis=1)
return df
df = get_dataframe(records)
df.to_pickle('braking_ttc.p.gz')
# DTC/TTC calculations will be 'nan' if not detected by lidar
# lidar only has a guaranteed detection range of 30 m
df
Out[7]:
In [8]:
plt.close('all')
fig, ax = plt.subplots()
sns.swarmplot(x='rider id', y='starting velocity', data=df, ax=ax)
ax.set_title('rider vs starting velocity (braking event)')
fig, ax = plt.subplots()
sns.swarmplot(x='rider id', y='linregress slope', data=df, ax=ax)
ax.set_title('rider vs acceleration (braking event)')
fig, ax = plt.subplots()
sns.swarmplot(x='rider id', y='distance-to-collision', data=df, ax=ax)
ax.set_title('rider vs DTC')
fig, ax = plt.subplots()
sns.swarmplot(x='rider id', y='time-to-collision', data=df, ax=ax)
ax.set_title('rider vs TTC')
plt.show()
In [9]:
from antlia.plotdf import plotjoint
colors = sns.color_palette()
plt.close('all')
g = plotjoint('starting velocity', 'distance-to-collision',
df[np.isfinite(df['time-to-collision'])],
('rider id', colors))
g.fig.set_size_inches(DEFAULT_FIGSIZE)
g.set_axis_labels('velocity [m/s]', 'distance-to-collision [m]')
g = plotjoint('starting velocity', 'time-to-collision',
df[np.isfinite(df['time-to-collision'])],
('rider id', colors))
g.fig.set_size_inches(DEFAULT_FIGSIZE)
g.set_axis_labels('velocity [m/s]', 'time-to-collision [s]')
plt.show()