"""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)