from scipy.optimize import brentq
z_m = B / 2 # ball centre height
r_si, r_so, r_cb = 12.0, 14.0, 15.0 # slot walls and cap counterbore
z_s = z_m + np.sqrt(r_g**2 - (r_so - r_m)**2) # split plane of the outer race
z_l = z_m + np.sqrt(r_g**2 - (r_cb - r_m)**2) # lower end of the cap lip
z_e = z_m - np.sqrt(r_g**2 - (r_so - r_m)**2) # groove exit, lower side
def arc(r0, z0, R, a0, a1, n=240):
# Points on an arc of radius R about (r0, z0), angles measured from the r axis
a = np.linspace(a0, a1, n)
return np.column_stack([r0 + R * np.cos(a), z0 + R * np.sin(a)])
def ang(r0, z0, r, z):
return np.arctan2(z - z0, r - r0)
g = lambda r, z: ang(r_m, z_m, r, z) # angle on the race groove
outer = np.vstack([[[D / 2, 0], [D / 2, z_s], [r_cb, z_s], [r_cb, z_l]],
arc(r_m, z_m, r_g, g(r_cb, z_l), g(r_so, z_e)),
[[r_so, 0]]])
cap = np.vstack([[[D / 2, B], [D / 2, z_s], [r_cb, z_s], [r_cb, z_l]],
arc(r_m, z_m, r_g, g(r_cb, z_l), g(r_so, z_s)),
[[r_so, B]]])
inner = np.vstack([[[d / 2, 0], [r_si, 0], [r_si, z_e]],
arc(r_m, z_m, r_g, g(r_si, z_e), g(r_si, z_s) - 2 * np.pi),
[[r_si, B], [d / 2, B]]])
# Cage: a circle 0.50 mm clear of the groove, flared to a 1.00 mm skirt by R8 arcs.
R_c, R_f, r_n = r_g - 0.50, 8.0, r_m + 0.5
centre = lambda th: (r_m + (R_c + R_f) * np.cos(th), z_m + (R_c + R_f) * np.sin(th))
th_t = brentq(lambda th: np.hypot(*np.subtract(centre(th), (r_n, 0.0))) - R_f, -1.2, -0.2)
a_f, b_f = centre(th_t)
P_t = (r_m + R_c * np.cos(th_t), z_m + R_c * np.sin(th_t))
flare = arc(a_f, b_f, R_f, ang(a_f, b_f, r_n, 0.0), ang(a_f, b_f, *P_t))
mirror = lambda p: np.column_stack([2 * r_m - p[:, 0], p[:, 1]])
cage = np.vstack([flare, arc(r_m, z_m, R_c, th_t, np.pi - th_t), mirror(flare[::-1])])
fig, ax = plt.subplots(figsize=(6.6, 6.4))
for poly, colour, name in [(outer, '#2E6E8E', 'Outer ring'), (cap, '#9EC6D8', 'Cap'),
(inner, '#7A9E3F', 'Inner ring'), (cage, '#E0A33E', 'Cage')]:
ax.fill(poly[:, 0], poly[:, 1], color=colour, ec='k', lw=0.8, label=name, zorder=2)
ax.add_patch(plt.Circle((r_m, z_m), d_w / 2, fc='none', ec='k', ls='--', lw=1.2, zorder=4))
ax.plot(r_m, z_m, 'k+', ms=8, zorder=4)
ax.plot([r_so, 17.8], [z_s, z_s], color='0.3', ls=':', lw=0.9, zorder=5)
ax.annotate('split plane, $z = 5.57$', (17.8, z_s), xytext=(0, 4),
textcoords='offset points', ha='right', fontsize=8.5)
ax.annotate('ball', (r_m, z_m + d_w / 2), xytext=(0, 7), textcoords='offset points',
ha='center', fontsize=8.5, zorder=5)
ax.annotate('race groove', xy=(r_m + r_g, z_m), xytext=(17.75, z_m), ha='right',
va='center', fontsize=8.5,
arrowprops=dict(arrowstyle='-', lw=0.8, color='0.3',
shrinkA=0, shrinkB=2))
ax.set_aspect('equal')
ax.set_xlim(9.3, 17.8)
ax.set_ylim(-0.7, 7.7)
ax.set_xlabel('Radius from the axis (mm)')
ax.set_ylabel('Height (mm)')
ax.legend(fontsize=9, loc='upper center', bbox_to_anchor=(0.5, -0.11), ncol=4,
frameon=False)
plt.tight_layout()
plt.show()