codexquadruped-gait-contact-schedules.py
quadruped-gait-contact-schedules.py
"""Illustrative periodic contact schedules; Python 3.14, NumPy, Matplotlib.
Writes a white PNG into the current directory. Stance intervals are constructed,
not measured animal or robot data; force and stability constraints are excluded.
"""
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib.patches import Patch
legs = ['LF', 'RF', 'LH', 'RH']
schedules = [
('Staggered contacts: duty factor 0.75', [0, .5, .75, .25], .75, '#B65D20'),
('Diagonal pairs: duty factor 0.50', [0, .5, .5, 0], .5, '#087F8C'),
]
fig, axes = plt.subplots(1, 2, figsize=(10, 4.8), dpi=120, sharey=True)
fig.patch.set_facecolor('white')
for ax, (title, phases, duty, color) in zip(axes, schedules):
ax.set_facecolor('white')
for row, phase in enumerate(phases):
ax.broken_barh([(0, 1)], (row-.29, .58), facecolors='#EDF0F2')
for shift in (-1, 0, 1):
lo, hi = max(0, phase+shift), min(1, phase+shift+duty)
if hi > lo:
ax.broken_barh([(lo, hi-lo)], (row-.29, .58), facecolors=color)
ax.set_xlim(0, 1)
ax.set_ylim(3.65, -.65)
ax.set_yticks(range(4), legs)
ax.tick_params(labelleft=True)
ax.set_xticks([0, .25, .5, .75, 1])
ax.set_xlabel('Stride phase t/T')
ax.set_title(title, fontsize=11, pad=13)
ax.grid(axis='x', color='#C8CDD2', alpha=.5)
ax.set_axisbelow(True)
for spine in ('top', 'right'):
ax.spines[spine].set_visible(False)
axes[0].set_ylabel('Leg contact')
fig.suptitle('Quadruped gait: timing is part of the motion pattern', fontsize=15, y=.98)
fig.legend(handles=[Patch(facecolor='#546575', label='Colored interval: stance'),
Patch(facecolor='#EDF0F2', label='Pale interval: swing')],
loc='lower center', bbox_to_anchor=(.5, .125), ncols=2, frameon=False)
fig.text(.5, .055, 'LF / RF: left / right front LH / RH: left / right hind', ha='center', fontsize=10)
fig.text(.5, .012, 'Constructed schedules only; contact timing does not establish force feasibility or stability.', ha='center', fontsize=9, color='#48535C')
fig.subplots_adjust(left=.075, right=.98, bottom=.28, top=.80, wspace=.22)
fig.savefig(Path.cwd() / 'quadruped-gait-contact-schedules.png', facecolor='white', dpi=120)
plt.close(fig)