Add AC/BC RTCP programs and 3D machine manager

This commit is contained in:
2026-09-20 12:31:12 +08:00
parent 1c1e5f9672
commit 8aab531b02
363 changed files with 53213 additions and 58 deletions

View File

@@ -0,0 +1,103 @@
"""Original diagrams for the beginner's work-coordinate handbook."""
import shutil
from pathlib import Path
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
from matplotlib import font_manager
from matplotlib.patches import Rectangle, Polygon
import numpy as np
ROOT=Path(__file__).resolve().parents[1]
OUT=ROOT/'docs/teaching/rtcp-beginners/assets';OUT.mkdir(parents=True,exist_ok=True)
font_manager.fontManager.addfont('/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc')
plt.rcParams.update({'font.family':'Noto Sans CJK JP','font.size':14,'axes.unicode_minus':False})
BLUE,TEAL,RED,GRAY,INK='#2563b8','#00877b','#d45549','#8a969f','#23303a'
for name in ['machine-ac','machine-bc','hierarchy','identity-no-follow','tcp-follow','rotated-direction','bc-frame','pivot-offset','arc-chord','tool-length','orientation']:
shutil.copyfile(ROOT/f'docs/teaching/rtcp-five-axis/assets/{name}.png',OUT/f'{name}.png')
def save(fig,name):
fig.savefig(OUT/f'{name}.png',dpi=190,facecolor='white',bbox_inches='tight',pad_inches=.18);plt.close(fig)
def arrow(ax,start,end,color,label='',dx=0,dy=0):
ax.annotate('',end,start,arrowprops={'arrowstyle':'-|>','lw':2,'color':color})
if label:ax.text(end[0]+dx,end[1]+dy,label,color=color,fontsize=14)
fig,ax=plt.subplots(figsize=(8,4.2));ax.set(xlim=(-8,55),ylim=(-8,38),aspect='equal');ax.axis('off')
for x in range(0,51,10):ax.plot([x,x],[0,30],c='#dce6ec',lw=1);ax.text(x,-4,str(x),ha='center',fontsize=12,color=GRAY)
for y in range(0,31,10):ax.plot([0,50],[y,y],c='#dce6ec',lw=1);ax.text(-4,y,str(y),va='center',fontsize=12,color=GRAY)
arrow(ax,(0,0),(54,0),BLUE,'X',-1,-5);arrow(ax,(0,0),(0,36),BLUE,'Y',-5,-1)
ax.scatter([30],[20],s=90,color=RED);ax.plot([30,30,0],[0,20,20],ls='--',color=RED,lw=1.5)
ax.text(32,22,'P = (30, 20) mm',color=RED);ax.text(2,32,'先选原点,再沿指定方向量距离',fontsize=14,color=INK)
save(fig,'coordinate-grid')
fig,ax=plt.subplots(figsize=(8,4.4));ax.set(xlim=(-10,95),ylim=(-10,60),aspect='equal');ax.axis('off')
arrow(ax,(0,0),(90,0),BLUE,'X_M',-8,-7);arrow(ax,(0,0),(0,56),BLUE,'Y_M',-8,-2)
arrow(ax,(40,20),(79,20),TEAL,'X_W',0,-2);arrow(ax,(40,20),(40,54),TEAL,'Y_W',2,0)
ax.scatter([50],[35],s=95,color=RED);ax.text(54,38,'同一个点 P',color=RED)
ax.plot([50,50,40],[20,35,35],ls='--',color=TEAL);ax.text(43,24,'10',color=TEAL);ax.text(32,27,'15',color=TEAL)
ax.annotate('O_W 在 M 中为 (40,20)',(40,20),xytext=(23,6),fontsize=12,arrowprops={'arrowstyle':'->','color':GRAY})
ax.text(3,46,'P_M=(50,35)\nP_W=(10,15)',fontsize=15,color=INK)
save(fig,'same-point')
fig,axes=plt.subplots(1,2,figsize=(10,5))
for ax,c in zip(axes,[0,90]):
ax.set(xlim=(-55,85),ylim=(-28,95),aspect='equal');ax.axis('off')
arrow(ax,(0,0),(78,0),BLUE,'X_M',-5,-12);arrow(ax,(0,0),(0,85),BLUE,'Y_M',-18,-1)
rad=np.deg2rad(c);r=np.array([[np.cos(rad),-np.sin(rad)],[np.sin(rad),np.cos(rad)]])
o=r@np.array([40,20]);point=r@np.array([50,20]);x=r@np.array([25,0]);y=r@np.array([0,25])
poly=np.array([o+r@np.array(v) for v in [[-5,-5],[30,-5],[30,20],[-5,20]]]);ax.add_patch(Polygon(poly,fc='#e1f2ee',ec=TEAL,alpha=.65))
arrow(ax,o,o+x,TEAL,'X_W',2,0);arrow(ax,o,o+y,TEAL,'Y_W',2,0)
ax.scatter(*o,color=TEAL,s=70);ax.scatter(*point,color=RED,s=100,marker='*')
ax.text(-48,89,f'C = {c}°',color=INK,fontsize=17)
ax.text(-48,-23,f'O_M=({o[0]:.0f},{o[1]:.0f})\nP_M=({point[0]:.0f},{point[1]:.0f})',color=INK,fontsize=13)
label_position=(12,57) if c else (-45,67)
ax.annotate('P:X10,Y0',point,xytext=label_position,arrowprops={'arrowstyle':'->','color':RED},color=RED,fontsize=12)
fig.subplots_adjust(wspace=.15)
save(fig,'moving-origin')
fig,ax=plt.subplots(figsize=(8,4.5));ax.axis('off');ax.set(xlim=(-10,120),ylim=(-15,80),aspect='equal')
front=np.array([[10,15],[85,15],[85,38],[10,38]]);side=np.array([[85,15],[108,37],[108,60],[85,38]]);top=np.array([[10,38],[85,38],[108,60],[33,60]])
for poly,color in [(front,'#d4e3e8'),(side,'#b9cdd3'),(top,'#e5f2ef')]:ax.add_patch(Polygon(poly,fc=color,ec=GRAY))
origin=(10,38);arrow(ax,origin,(66,38),TEAL,'+X',0,-7);arrow(ax,origin,(33,60),TEAL,'+Y',-4,7);arrow(ax,origin,(10,72),TEAL,'+Z',2,0)
ax.scatter(*origin,color=RED,s=70);ax.annotate('示例:顶面左前角为零点',origin,xytext=(5,2),arrowprops={'arrowstyle':'->','color':RED},color=RED,fontsize=14)
ax.scatter([65],[48],color=BLUE,s=130,facecolors='none');ax.annotate('也可选孔中心\n必须与CAD/CAM约定一致',(65,48),xytext=(75,74),arrowprops={'arrowstyle':'->','color':BLUE},color=BLUE,fontsize=12)
save(fig,'datum-choice')
fig,ax=plt.subplots(figsize=(8,4.5));ax.axis('off');ax.set(xlim=(-20,110),ylim=(-20,85),aspect='equal')
o=np.array([15,8]);a=np.deg2rad(20);u=np.array([np.cos(a),np.sin(a)]);v=np.array([-np.sin(a),np.cos(a)])
pts=[o,o+u*75,o+v*45]
ax.plot([pts[1][0],o[0],pts[2][0]],[pts[1][1],o[1],pts[2][1]],color=TEAL,lw=2)
for p,label,dx,dy in zip(pts,['O:所选原点','P_x:确定 +X','P_y:确定 XY 面'],[-12,2,-10],[-12,0,6]):ax.scatter(*p,s=80,color=RED);ax.text(p[0]+dx,p[1]+dy,label,fontsize=13,color=INK)
arrow(ax,o,o+u*93,TEAL,'+X',0,0);arrow(ax,o,o+v*62,TEAL,'+Y',-5,3)
arrow(ax,(-8,-9),(100,-9),BLUE,'机床 X',-25,-8)
ax.text(48,64,'工件不能只靠“一个点”\n确定全部方向',color=INK,fontsize=15,ha='center')
save(fig,'orientation-measure')
fig,axes=plt.subplots(2,1,figsize=(8,3.6))
for ax,title,target in zip(axes,['当前位置 X=10,G90 X20','当前位置 X=10,G91 X20'],[20,30]):
ax.set(xlim=(-3,39),ylim=(-1,6));ax.axis('off');arrow(ax,(0,1),(37,1),BLUE)
for x in [0,10,20,30]:ax.plot([x,x],[.8,1.2],color=GRAY);ax.text(x,-.2,str(x),ha='center',fontsize=13)
ax.text(0,4,title,fontsize=15,color=INK);ax.scatter([10],[1],color=GRAY,s=70);ax.scatter([target],[1],color=RED,s=90)
arrow(ax,(10,2),(target,2),RED);ax.text((10+target)/2,2.8,f'实际移动 {target-10}',ha='center',color=RED,fontsize=12)
fig.subplots_adjust(hspace=.35);save(fig,'absolute-incremental')
fig,ax=plt.subplots(figsize=(8,4));ax.axis('off');ax.set(xlim=(0,10),ylim=(0,5))
rows=[('① 程序工件点 W','(10, 0, 5)',TEAL),('② 加 G54 零位偏置','+(40, 20, 10)',GRAY),('③ 运动学输入 K','(50, 20, 15)',BLUE),('④ C=90°,RTCP变换','(-20, 50, 15)',RED)]
for i,(label,value,color) in enumerate(rows):
y=4.15-i*1.06;ax.add_patch(Rectangle((.3,y-.34),9.3,.74,fc='#eef4f6',ec='none'))
ax.text(.55,y,label,color=color,fontsize=15,va='center');ax.text(6.1,y,value,color=color,fontsize=16,va='center')
if i<3:ax.text(5,y-.58,'↓',ha='center',va='center',color=GRAY)
save(fig,'offset-pipeline')
c=np.linspace(0,90,181);r=np.deg2rad(c);qx=50*np.cos(r)-20*np.sin(r);qy=50*np.sin(r)+20*np.cos(r)
fig,ax=plt.subplots(figsize=(8,4));ax.plot(c,qx,color=BLUE,lw=2.4,label='关节 X');ax.plot(c,qy,color=TEAL,lw=2.4,label='关节 Y');ax.plot(c,np.full_like(c,15),color=RED,lw=2.4,label='关节 Z')
ax.set(xlabel='C 角度(°)',ylabel='关节位置(mm)',xlim=(0,90));ax.grid(alpha=.2);ax.legend(loc='lower left',ncol=3,fontsize=12);ax.set_title('程序 X10 Y0 Z5 保持;关节由RTCP连续计算',fontsize=15,color=INK)
fig.tight_layout();save(fig,'continuous-joints')
fig,ax=plt.subplots(figsize=(6.7,4.1));ax.set(aspect='equal',xlim=(-3,14),ylim=(-3,14));ax.axis('off')
arrow(ax,(0,0),(13,0),BLUE,'X',0,-1);arrow(ax,(0,0),(0,13),BLUE,'Y',-1,0)
t=np.linspace(0,np.pi/2,100);ax.plot(10*np.cos(t),10*np.sin(t),color=TEAL,lw=3)
arrow(ax,(8.5,5.27),(7.8,6.25),TEAL);ax.scatter([10,0,0],[0,10,0],color=[RED,TEAL,GRAY],s=80)
ax.text(6.8,-1.8,'起点 (10,0)',color=RED,fontsize=13);ax.text(.8,10.5,'终点 (0,10)',color=TEAL,fontsize=13)
ax.text(2.8,3.5,'圆心 (0,0)\nI=-10,J=0',color=INK,fontsize=14)
ax.plot([10,0],[0,0],ls=':',color=GRAY,lw=2);save(fig,'arc-words')
print('Created 9 new diagrams and reused 11 verified original assets:',OUT)