in long_term/locomotion_utils.py [0:0]
def build_phase_track(positions_world):
"""
Detect foot steps and extract a control signal that describes the current state of the walking cycle.
This is based on the assumption that the speed of a foot is almost zero during a contact.
"""
l_speed = np.linalg.norm(np.diff(positions_world[:, lf], axis=0), axis=1)
r_speed = np.linalg.norm(np.diff(positions_world[:, rf], axis=0), axis=1)
displacements = np.cumsum(np.linalg.norm(np.diff(positions_world[:, 0], axis=0), axis=1))
left_contact = l_speed[0] < r_speed[0]
epsilon = 0.1 # Hysteresis (i.e. minimum height difference before a foot switch is triggered)
cooldown = 3 # Minimum # of frames between steps
accumulator = np.pi if left_contact else 0
phase_points = [ (0, accumulator) ]
disp_points = [ (0, displacements[0]) ]
i = cooldown
while i < len(l_speed):
if left_contact and l_speed[i] > r_speed[i] + epsilon:
left_contact = False
accumulator += np.pi
phase_points.append((i, accumulator))
disp_points.append((i, displacements[i] - displacements[disp_points[-1][0]]))
i += cooldown
elif not left_contact and r_speed[i] > l_speed[i] + epsilon:
left_contact = True
accumulator += np.pi
phase_points.append((i, accumulator))
disp_points.append((i, displacements[i] - displacements[disp_points[-1][0]]))
i += cooldown
else:
i += 1
phase = np.zeros(l_speed.shape[0])
end_idx = 0
for i in range(len(phase_points) - 1):
start_idx = phase_points[i][0]
end_idx = phase_points[i+1][0]
phase[start_idx:end_idx] = np.linspace(phase_points[i][1], phase_points[i+1][1], end_idx-start_idx, endpoint=False)
phase[end_idx:] = phase_points[-1][1]
last_point = (phase[-1] - phase[-2]) + phase[-1]
phase = np.concatenate((phase, [last_point]))
return phase