hjjnt2008 发表于 2012-12-30 23:09:59

转 使用补偿修正方法解决Z轴零平面不平问题,特别适用于...

转自:http://bbs.cdle.net/thread-47293-1-1.html


一、背景
      小哥爱好机械,但不是科班出身,所掌握的只是当年工科大学生金工实习所学皮毛,如果后面写了什么外行的话请理解。自己不会做,所以上个月购买了一台商品雕刻机,外观还美观,我这种外行用起来感觉性能还行。慢慢在论坛里学习,慢慢改良自己的机器和技能,先后自行加了三个轴的机械限位及Z轴对刀功能,没办法,老撞车,伤不起。
       小哥常玩的是电子和电脑,雕刻机用来用去也只有雕刻PCB最多。但PCB这东西实际雕刻起来最麻烦的是工件加工平面的不平整,一个原因是雕刻机本身的载物台不平,另一个是PCB很难装夹平整。论坛上常用的解决思路有:1、调校载物台至尽量平整,阿莫那边说是能调校到0.01mm精度。2、在软性载物台上铣一个绝对平面。以上两种方法只能有效解决第一个原因所致的加工平面不平问题,而难以应对第二个原因。因为PCB的装夹常用机械压夹或者不干胶大法,我这样初学者实际用起来很难有效保障精度,特别是比较薄的PCB变形非常严重,使用手上唯一测量工具卡尺不严谨的测量过,我这台机器因本身的载物台不平所带来的误差也就0.1mm左右,但PCB的变形在加工范围内经常高达0.5-1.0mm也不足为奇,相对PCB板下刀深度仅为0.1-0.2mm而言,这样大的误差直接导致手上重金购置的雕刻机无法雕刻出合格的PCB电路板。
      相信很多初学者有跟我一样的困扰,如何解决因加工平面不平问题?小哥不擅长机械,所以只得从软的方面去琢磨,得到了一个使用算法补偿修正的方法,经过试用,方法简单、普适及有效,不敢独享,全盘奉献给各位同好。
二、原理
   PCB工件平面的变形各式各样,不遵守严格的规律。但从微分的角度上看,在指定加工精度(比如0.1-0.2mm)情况下,我们可以认为在一个足够小(比如5mm*5mm)的加工范围,PCB的工件平面的变形仅是一个简单的平面倾斜。换而言之,在这个足够小的加工范围内,PCB工件平面各点处处共面,只不过这个平面相对加工的绝对平面有一定的倾斜。这个结论针对不是绝对柔性的工件而言是显然的。
   从上面结论出发,我们只需要在需要加工的范围内取样足够数量的加工平面样本点Si (xi,yi,zi),针对一个加工点A(x,y,z),找到距离该点最近的3个样本点Si ,使用这3个样本点构制一个平面(三点确定一个平面),得到该平面的方程,因为认为加工点A就落在这个平面上,所以将加工点A的xy轴坐标代入所得到的平面方程,就能得到一个新的z轴坐标值z`,接下来修正加工点A的实际加工坐标点为(x,y,z`),也就是说,让雕刻机在x,y位置上实际下刀深度为z`,最后雕刻出来的效果即会有一个深度为原来的需求值z的刀路。
三、实现
      雕刻PCB,我采用的是用protel99se输出dxf文件,使用ArtCAM导入矢量后产生刀路(前后要删去几行关于相对坐标设置等代码,论坛中有介绍),再通过Mach3控制雕刻机完成加工。要实现上述补偿修正方法,我的步骤是:
   1、装夹好PCB板,连接好对刀线路,对刀线路两个端子一端在刀头,一端在PCB铜箔。在加工零点处进行z轴对刀;
   2、我在林大夫的Mach3对刀界面上增加了z轴校零功能(界面及代码文件见附件1),在该Mach3界面上相应输入框内设置z轴校零范围,该范围要稍大于实际加工范围,比如设置x最大为100mm,y最大为120mm,步长为5mm(见图1. Mach3校零界面示意所示);
                                 
                               图1. Mach3校零界面示意.jpg
   3、此时保持对刀线路工作正常,点击z校零按钮后,雕刻机会在x从0至100mm,y从0至120mm的范围内,每隔5mm步长抬刀、落刀进行z平面零点的取样。注意:只能指定x和y的最大值,x和y的最小值默认为0,不能修改。这只是个人使用习惯问题,并不会影响雕刻的实现;
   4、耐心等到所有取样完成后,刀头会退回到加工零点,Mach3界面上会提示所有样本数据已经保存到CNCZ0fix.z0f文件中。CNCZ0fix.z0f在Mach3安装目录下,比如C:\Mach3,实在找不到就搜索一下。
   5、启动程序Z0Fix.exe(程序见附件2,附图见图2),该程序的功能是根据之前的取样数据,读取并修改加工源文件G代码坐标数据,补偿其中的z轴下刀深度,并为了保证精度,还会对水平加工距离较长(暂时设置为大于二分之一个取样点步长的距离)的G1代码进行加工点插值,修正后的刀路会存在新文件中(不会对源文件进行任何写操作)。
                              
                                     图2. Z0Fix界面.jpg
          Z0Fix.exe的使用步骤是:(1)手工输入或打开步骤4生成的CNCZ0fix.z0f文件,并点击导入,确认界面上提示的x最大值、y最大值、步长及样本点数无误;(2)打开加工源文件,我使用的是ArtCAM导入dxf矢量后产生刀路*.nc文件;(3)手工输入或打开新文件*.nc;(4)点击“修正”按钮,修正结果会出现在界面上。
    6、在Mach3中加载步骤5中生成的新刀路文件,确认刀头的x,y坐标回位到加工零点,建议此次再做一次z轴对刀,确认需要加工的范围在做z轴零点校准步骤中所指定的范围内,本例中为:x从0至100mm,y从0至120mm。接下来按正常操作进行加工即可,会看到z轴实际走刀深度在各处有深有浅,这是针对每处工件平面的具体情况补偿后的结果,加工出来的实际效果应当是符合原期望的。
四、说明
    1、除了Z0Fix.exe外,其余思路、方法、代码针对任何刀路产生程序都是通用的,而Z0Fix.exe只针对使用ArtCAM导入Protel99se的dxf矢量后产生nc刀路(前后要删去几行代码)环境下使用过(因为软件编制的初衷仅仅是满足我个人使用需求,如果要考虑其他各种情况,那就太麻烦了),其他软件产生的刀路不一定能兼容。事实上我认为,如果能保证两个简单条件:(1)源文件每行G代码的各个字符之间连着写,不要有空格;(2)坐标定义不一定要xyz齐全,但一定要保证次序,即x一定要在y和z之前,y一定要在z之前。比如如下的各个例子都不会有问题。
   N70G0X0.000Y0.000S8000M3
   G0X5.588Y0.679Z3.000
   N90G1Z-0.200F120.0
   G1X5.233Y1.034F300.0
   2、z校零范围只能指定x和y的最大值,x和y的最小值默认为0,不能修改。实际加工范围必须在z校零范围之内。
   3、Mach3的界面和代码要更改成附件1提供的文件,否则没有校零功能,具体方法请参考林大夫的帖子:http://bbs.5imx.com/bbs/viewthread.php?tid=355431&extra=&highlight=%B6%D4%B5%B6&page=1
   4、回馈论坛,完全公开,附件3和4是 Z0Fix.exe的CBuilder6源代码及相应功能的Matlab代码(事实上最早只是写成了Matlab代码给自己用的,为方便大家才重新用C++做了.exe文件),供有兴趣同好们的参考。如果 Z0Fix.exe在使用中不便,大家也可自行修改代码。
   5、只要保持PCB装夹固定不变,保持加工原点(x=0,y=0)不变,原理上z轴校零产生的CNCZ0fix.z0f数据文件可以反复使用,比如雕刻PCB的线路和钻孔刀路,都可以用同一个CNCZ0fix.z0f数据文件补偿。如果要换刀,须在加工原点(x=0,y=0)再做一次z轴对刀。如果相关环境改变,或者间隔时间较长或者操作频繁,使工件表面相对状态变化了,都需要再次做z轴校零,形成新的CNCZ0fix.z0f。
   6、附图3中是一个雕刻实例,在同一块1mm厚,平整度很差PCB板上,保持相关环境不变,使用0.2mm深度雕刻同一线路;左下为不补偿的雕刻结果,可以看到很多地方因为加工平面形变完全不着刀或只有很浅的划痕,导致雕刻无法继续下去; 右上为补偿修正过的刀路雕刻结果,同一块板子上各处下刀深度均匀,补偿是有效的。
                                 
                                       图3. PCB效果图.jpg
   7、本文为个人经验,如有不妥或需要改进的地方请各位不吝指出,目标是给坛友造福,大家共同学习进步。本文原创首发至CDLE.net及5imx.com,这两个论坛对我帮助很大。至于x莫那里就不发了,他喜欢当自己是上帝,但我恰是无神论者。









未经试验,纯分享,有条件的大虾,试了回来说一声!

nnimo 发表于 2012-12-31 12:36:23

这个一定要顶的 ! 怎么没人支持啊 ! 很好的Z轴校正思路 !

hjjnt2008 发表于 2012-12-31 22:54:23

现在才认真看完了贴子,转过来是纯技术交流的,对于里面有得罪阿莫大哥多多包涵。

yuyanlzh 发表于 2013-2-6 22:25:43

这个真的是技术帖啊

f13960 发表于 2013-2-7 13:01:45

{:victory:}{:handshake:}

sunoracle 发表于 2013-2-8 07:47:25

有用。。。 mark

jlian168 发表于 2013-2-8 08:12:38

mark,take a look.

zgzhenglei 发表于 2013-4-29 16:47:23

MARK,一会试下

zgzhenglei 发表于 2013-4-29 21:42:23

请问ARTCAM保存成哪种NC文件

xiaojuren 发表于 2013-5-6 12:56:31

好人,大力的顶起

fwluck 发表于 2013-5-7 11:34:39

有试成的吗?我没试成。

颜靖峰 发表于 2013-5-23 13:55:18

wonderful!!!!!!

颜靖峰 发表于 2013-5-24 00:57:45

原作者后来有个更新,看看
(2012.7.12日:经过雕刻试验,不断优化Mach3的对刀及校零代码,现再传上最新版本,含对刀、Z校零两个代码文件,下 载请见本段文字后,可以代替原帖中附件1内相应代码文件。新版本代码的精度及效率均高过旧版本)
直接把优化后的Mach3的对刀及校零代码原文贴上来,这样就不怕丢了,大家拷贝后直接贴到相应按钮的VB代码中。


一. 对刀代码:

Message "对刀开始,请准备..."
CurrentFeed=GetOEMDRO(818)'获得当前进给率
CurrentZ=GetOEMDRO(802)   '获得当前Z坐标值
MsgBox("请务必确认对刀线路连接良好!!")
Code "G4 P1"    '执行G4代码,程序停顿1秒,等候准备工作
Code "F100"   '为探测设置进给速率为100 mm/min
GageH=GetUserDRO(1001)    '获取用户设置的测量块高度
ZNew=CurrentZ-30   'Z轴目标为当前高度向下移动30mm
Code "G31 Z"&ZNew    '执行G31,向下进行30mm探测
While IsMoving()   '等待触碰,执行这个函数后,当所有轴停止则返回0
Wend               ' end while
Znew=GetOEMDRO(802)   '获得当前Z坐标值
Call SetDro(2,GageH)   '将量块高度指定给Z轴坐标,实现量块底面为Z轴0坐标
FinalMove=GageH+3    '对刀后Z轴上移至量块顶面上方3mm
Code "G0 Z"&FinalMove'执行Z轴移动到最终位置
Code "F"&CurrentFeed    '回存保留的进给率
Message "Z0=" & Znew & ", 对刀结束,工件顶面已置为Z轴零点。"







二、Z校零代码

Dim Lz(100) As Double    '每行的Z值先记录在数组中
Dim Yk As Integer   
Dim Xk As Integer
TotX=GetOEMDRO(1221)      '用户从DRO输入需要测试区域X方向最大坐标mm
TotY=GetOEMDRO(1222)      '用户从DRO输入需要测试区域Y方向最大坐标mm
Testep=GetOEMDRO(1223)    '用户从DRO输入每个测试样本点步进mm
Open "CNCZ0fix.z0f" For Output As #1    '新建测试数据记录文件
Print #1,TotX & "," & TotY & "," & Testep    ' 写TotX,TotY,Testep到文件
Message "检查开始,请准备..."
MsgBox("请务必确认对刀线路连接良好!!")
Code "G4 P1"    '执行G4代码,程序停顿1秒,等候准备工作
CurrentFeed=GetOEMDRO(818)'获得当前进给率
Code "F100"   '为探测设置进给速率为100 mm/min
GageH=GetUserDRO(1001)    '获取用户设置的测量块高度
X0=GetOEMDRO(800)   '获得起始点X坐标值
Y0=GetOEMDRO(801)   '获得起始点Y坐标值
Message "TotalX=" & TotX & ",TotalY=" & TotY & ",Testep=" & Testep
Yk=0               '当前行号
For Y=Y0 To TotY Step Testep
   Code "G0 Y" & Y   '走刀到当前Y
   Yk=CInt(Y/Testep)         '当前行号(从0开始)
   If(YK Mod 2)=0    Then
      Xbg=X0      '奇数行X轴起始位置
      Xed=TotX    '奇数行X轴终止位置
      Xsp=Testep'奇数行X轴步进
   Else
      Xbg=TotX      '偶数行X轴起始位置
      Xed=X0    '偶数行X轴终止位置
      Xsp=-Testep'偶数行X轴步进
   End If
   ForX=Xbg To Xed Step Xsp
      Code "G0 X" & X   '走刀到当前X
      CurrentZ=GetOEMDRO(802)   '获得当前Z坐标值
      ZNew=CurrentZ-10   'Z轴目标为当前高度向下移动10mm
      Code "G31 Z" & ZNew    '执行G31,向下进行探测
      While IsMoving()   '等待触碰,执行这个函数后,当所有轴停止则返回0
      Wend                  'end while
      Znew=GetOEMDRO(802)    '记录刀尖触碰时Z的位置
      FinalMove=Znew+2    '对刀后Z轴上移至量块顶面上方2mm
      Code "G0 Z" & FinalMove'执行Z轴移动到最终位置
      Z0=Znew-GageH         '减去量块高度,得到Z0平面误差
      Xk=CInt(X/Testep)       '当前列号(从0开始)
      Lz(Xk)=Z0               'Z0值暂存数组中
      Message "TotalX=" & TotX & ",TotalY=" & TotY & "; X=" & X & ",Y=" & Y & ",Z0=" & Z0   '信息栏输出完成的测试点信息
   Next
   ForX=X0 To TotX Step Testep   '完成一行后,统一写测试信息
      Xk=CInt(X/Testep)       '当前列号(从0开始)
      Print #1,X & "," & Y & "," & Lz(Xk)    '写X,Y,Z0到文件
    Next
Next
Close #1
Code "F" & CurrentFeed    '回存保留的进给率
Code "G0 X" & X0 & "Y" & Y0'返回起始点
Message "检测完毕,数据保存至CNCZ0fix.z0f"

hjjnt2008 发表于 2013-5-24 08:42:26

颜靖峰 发表于 2013-5-24 00:57 static/image/common/back.gif
原作者后来有个更新,看看
(2012.7.12日:经过雕刻试验,不断优化Mach3的对刀及校零代码,现再传上最新版本 ...

谢谢LS帮忙更新{:smile:}

nojiya88 发表于 2013-5-27 22:38:54

我试过,对原点设在工件中心的,不适用。。原点设在工件左下角的有用。

n109 发表于 2013-6-25 14:35:17

不错好东西,刻pcb用得上。

LouisChiang 发表于 2013-7-2 08:59:00

MARK!{:biggrin:}

lsea 发表于 2013-12-26 22:47:38

刚才试验了一下你的软件,为啥z轴对 刀的话明明提升是5mm 却显示的提升7mm结果撞刀,悲剧了。

小手冰凉 发表于 2014-1-29 17:44:44

hjjnt2008 发表于 2013-5-24 08:42
谢谢LS帮忙更新

请问楼主 我用您的代码发现 Z轴向上寻找0点,把代码的+改成-之后 正常了,请问 影响校准效果吗?

apeng2012 发表于 2014-3-11 17:00:41

我用CopperCAM出刀路。底层出隔离刀路,x坐标都为负值。更改了下楼主的程序,发上来供大家参考。

Dim Lz(100) As Double    '每行的Z值先记录在数组中
Dim Yk As Integer   
Dim Xk As Integer
TotX=-105 'GetOEMDRO(1221)      '用户从DRO输入需要测试区域X方向最大坐标mm
TotY=45 'GetOEMDRO(1222)      '用户从DRO输入需要测试区域Y方向最大坐标mm
Testep=5 'GetOEMDRO(1223)    '用户从DRO输入每个测试样本点步进mm
Open "CNCZ0fix.z0f" For Output As #1    '新建测试数据记录文件
Print #1,TotX & "," & TotY & "," & Testep    ' 写TotX,TotY,Testep到文件
Message "检查开始,请准备..."
MsgBox("请务必确认对刀线路连接良好!!")
Code "G4 P1"    '执行G4代码,程序停顿1秒,等候准备工作
CurrentFeed=GetOEMDRO(818)'获得当前进给率
Code "F100"   '为探测设置进给速率为100 mm/min
GageH=0 'GetUserDRO(1001)    '获取用户设置的测量块高度
Code "G0 Z10"
Code "G0 X0 Y0"
X0=0 'GetOEMDRO(800)   '获得起始点X坐标值
Y0=0 'GetOEMDRO(801)   '获得起始点Y坐标值
Message "TotalX=" & TotX & ",TotalY=" & TotY & ",Testep=" & Testep
Yk=0               '当前行号
Dim xTestep As Integer
Dim yTestep As Integer
If (TotX > X0) Then
xTestep = Testep
Else
xTestep = -Testep
End If
If (TotY > Y0) Then
yTestep = Testep
Else
yTestep = -Testep
End If
For Y=Y0 To TotY Step yTestep
   Code "G0 Y" & Y   '走刀到当前Y
   Yk=CInt(Y/yTestep)         '当前行号(从0开始)
   If(YK Mod 2)=0    Then
      Xbg=X0      '奇数行X轴起始位置
      Xed=TotX    '奇数行X轴终止位置
      Xsp=xTestep'奇数行X轴步进
   Else
      Xbg=TotX      '偶数行X轴起始位置
      Xed=X0    '偶数行X轴终止位置
      Xsp=-xTestep'偶数行X轴步进
   End If
   ForX=Xbg To Xed Step Xsp
      Code "G0 X" & X   '走刀到当前X
      CurrentZ=GetOEMDRO(802)   '获得当前Z坐标值
      ZNew=CurrentZ-10   'Z轴目标为当前高度向下移动10mm
      Code "G31 Z" & ZNew    '执行G31,向下进行探测
      While IsMoving()   '等待触碰,执行这个函数后,当所有轴停止则返回0
      Wend                  'end while
      Znew=GetOEMDRO(802)    '记录刀尖触碰时Z的位置
      FinalMove=Znew+2    '对刀后Z轴上移至量块顶面上方2mm
      Code "G0 Z" & FinalMove'执行Z轴移动到最终位置
      Z0=Znew-GageH         '减去量块高度,得到Z0平面误差
      Xk=CInt(X/xTestep)       '当前列号(从0开始)
      Lz(Xk)=Z0               'Z0值暂存数组中
      Message "TotalX=" & TotX & ",TotalY=" & TotY & "; X=" & X & ",Y=" & Y & ",Z0=" & Z0   '信息栏输出完成的测试点信息
   Next
   ForX=X0 To TotX Step xTestep   '完成一行后,统一写测试信息
      Xk=CInt(X/xTestep)       '当前列号(从0开始)
      Print #1,X & "," & Y & "," & Lz(Xk)    '写X,Y,Z0到文件
    Next
Next
Close #1
Code "F" & CurrentFeed    '回存保留的进给率
Code "G0 X" & X0 & "Y" & Y0'返回起始点
Message "检测完毕,数据保存至CNCZ0fix.z0f"

对应matlab程序
clear all;
clc;
ztest=load('d:\CNCZ0fix.z0f');%导入CNC Z轴零点测试数据
fnc=fopen('d:\test.CNC','rt');%原nc文件
fncnew=fopen('d:\newline.nc','wt');%带生成的新的nc文件

totx=ztest(1,1);%零点测试区域x轴最大值
toty=ztest(1,2);%零点测试区域y轴最大值
testep=ztest(1,3);   %零点测试步长mm
x_testep = testep;
y_testep = testep;
if (totx < 0)
    x_testep = -x_testep;
end
if (toty < 0)
    y_testep = -y_testep;
end
xPointNum = round(totx./x_testep)+1;
yPointNum = round(toty./y_testep)+1;
zerr=zeros(xPointNum, yPointNum);
m=2;
for j=1:1:yPointNum
for i=1:1:xPointNum
      zerr(i,j)=ztest(m,3);      %生成Z轴零点误差矩阵
      m=m+1;
end
end


ptsrd=zeros(1,7);   %nc文件行号,点x值,点y值,点z值,本句中用于更新(插入)修正后的z值的首位、尾位、G语句值
m=0;
lncnt=0;%文件行号
Gval=1;%当前是否G语句值
xx0=0;    %之前点x,y值
yy0=0;
xx=0;   %当前点x,y,z值
yy=0;
zz=3;
wh_z=;%x,y,z定义值所在当前语句中的字符首尾位置


fln=fgets(fnc);
while(fln~=-1)
lncnt=lncnt+1;
wh_z=;
flg=0;
for i=1:1:size(fln,2)
      if((fln(i)=='G') | (fln(i)=='g'))    %当前语句中包含G语句的定义
         for j=i+1:1:size(fln,2)
            if(~(fln(j)>='0' & fln(j)<='9'))   %找到G语句定义的尾位
                break;
            end
         end
         Gval=str2num(fln(i+1:j-1));   %获取G语句值定义
      end
      
      if((fln(i)=='X') | (fln(i)=='x'))    %当前语句中包含x值的定义
         for j=i+1:1:size(fln,2)
            if(~((fln(j)>='0' & fln(j)<='9') | (fln(j)=='.') | (fln(j)=='-') | (fln(j)=='+')))   %找到x值定义的尾位
                break;
            end
         end
         flg=1;%flg==1,本语句有坐标值定义
         xx=str2num(fln(i+1:j-1));   %获取x值定义
         wh_z=;             %本句中用于更新(插入)修正后的z值的首尾位(新语句的首位位置置'Z',旧语句尾位起为其他后续语句)
      end
      if((fln(i)=='Y') | (fln(i)=='y'))    %当前语句中包含y值的定义
         for j=i+1:1:size(fln,2)
            if(~((fln(j)>='0' & fln(j)<='9') | (fln(j)=='.') | (fln(j)=='-') | (fln(j)=='+')))%找到y值定义的尾位
                break;
            end
         end
         flg=1;   %flg==1,本语句有坐标值定义
         yy=str2num(fln(i+1:j-1));%获取y值定义
         wh_z=;             %本句中用于更新(插入)修正后的z值的首尾位(新语句的首位位置置'Z',旧语句尾位起为其他后续语句)
      end
      if((fln(i)=='Z') | (fln(i)=='z'))   %当前语句中包含y值的定义
         for j=i+1:1:size(fln,2)
            if(~((fln(j)>='0' & fln(j)<='9') | (fln(j)=='.') | (fln(j)=='-') | (fln(j)=='+')))%找到z值定义的尾位
                break;
            end
         end
         flg=1;    %flg==1,本语句有坐标值定义
         zz=str2num(fln(i+1:j-1));   %获取z值定义
         wh_z=;    %本句中用于更新(插入)修正后的z值的首尾位(新语句的首位位置置'Z',旧语句尾位起为其他后续语句)
      end
end
if(flg==1)
   if(m>0)
      xx0=ptsrd(m,2);
      yy0=ptsrd(m,3);
   else
      xx0=0;
      yy0=0;
   end
   
   dis=sqrt((xx-xx0).^2+(yy-yy0).^2);
   if( (dis>testep/2) & (Gval==1) )%当前走刀为G1,且当前点较之前点水平位移大于testep/2,则进行插值
         zz0=ptsrd(m,4);
         n=ceil(dis/(testep/2));%将本条刀路内共分为n个子刀路,需插值n-1个
         for k=1:1:n-1
            m=m+1;
            ptsrd(m,1:4)=;    %插值的行号设为0
            ptsrd(m,7)=Gval;    %存放G值
         end
   end
   m=m+1;
   ptsrd(m,1:4)=;   %写入本语句行号,x,y,z值
   ptsrd(m,5:6)=;   %本句中用于更新(插入)修正后的z值的首尾位(新语句的首位位置置'Z',旧语句尾位起为其他后续语句)
   ptsrd(m,7)=Gval;    %存放G值
         
end
fln=fgets(fnc);
end



%以下通过Z轴零点误差矩阵修正各点z值
for i=1:1:size(ptsrd,1)
   x0=ptsrd(i,2)/x_testep;
   y0=ptsrd(i,3)/y_testep;
   x1=floor(x0);
   x2=ceil(x0);
   y1=floor(y0);
   y2=ceil(y0);
   if(x2==x1 & y2==y1)      %当前雕刻点与样本点重合
      z0=zerr(x1+1,y1+1);
      ptsrd(i,4)=ptsrd(i,4)+z0;   %z0取重合的样本点的零点位置,修正当前点z轴的下刀量
   else                     %当前雕刻点与样本点不重合
      if(x2==x1)
         if(x1>0)
         x1=x1-1;
         else
         x2=x2+1;
         end
      end
   
      if(y2==y1)
         if(y1>0)
         y1=y1-1;
         else
         y2=y2+1;
         end
      end

      nbpts=; %四周的样本点
      dis=sqrt((x0-nbpts(:,1)).^2+(y0-nbpts(:,2)).^2);   %计算与四周样本点的水平距离
      =sort(dis);   %距离从小到大排序
      plpts=nbpts(I(1:3),:);%选出距离最小的三个样本点
      a1=x0-plpts(1,1);      %将当前点的x,y值代入由三个样本点构建平面方程,得到z0
      a2=plpts(2,1)-plpts(1,1);
      a3=plpts(3,1)-plpts(1,1);
      b1=y0-plpts(1,2);
      b2=plpts(2,2)-plpts(1,2);
      b3=plpts(3,2)-plpts(1,2);
      c2=plpts(2,3)-plpts(1,3);
      c3=plpts(3,3)-plpts(1,3);
      c1=(a1*b3*c2+a2*b1*c3-a1*b2*c3-a3*b1*c2)./(a2*b3-a3*b2);
      z0=c1+plpts(1,3);
      ptsrd(i,4)=ptsrd(i,4)+z0;   %通过估计的零点位置z0,修正当前点z轴的下刀量

   end
end

fseek(fnc,0,'bof');

m=1;
lncnt=0;
wh_z=;
fln=fgets(fnc);
while((fln~=-1) & (m<=size(ptsrd,1)))
   lncnt=lncnt+1;
   if(lncnt==ptsrd(m,1))%只修改有坐标值定义的语句
   wh_z=ptsrd(m,5:6);    %本句中用于更新(插入)修正后的z值的首尾位(新语句的首位位置置'Z',旧语句尾位起为其他后续语句)
   flnnew=sprintf('%sZ%0.3f%s',fln(1:wh_z(1)-1),ptsrd(m,4),fln(wh_z(2):size(fln,2)));%生成新语句
   fprintf(fncnew,'%s',flnnew);
   while((m<size(ptsrd,1)) & (ptsrd(m+1,1)==0))%本语句后面有插值,创建新语句输出
         m=m+1;
         flnnew=sprintf('G%dX%0.3fY%0.3fZ%0.3f\n',ptsrd(m,7),ptsrd(m,2),ptsrd(m,3),ptsrd(m,4));%生成新语句
         fprintf(fncnew,'%s',flnnew);
   end
   m=m+1;
   else
   fprintf(fncnew,'%s',fln);   %没有坐标值定义的语句直接输出
   end

   fln=fgets(fnc);
end
fclose(fnc);
fclose(fncnew);
plot3(ptsrd(:,2),ptsrd(:,3),ptsrd(:,4));

574474631 发表于 2014-3-11 20:27:15

好。。先赞个,慢慢看

bygreencn 发表于 2014-3-11 22:02:55

技术帖..

walwyn75 发表于 2014-3-12 18:49:36

谢谢分享,慢慢看{:biggrin:}

walwyn75 发表于 2014-3-14 07:47:04

很棒的技术帖,谢谢分享{:biggrin:}

a33403916 发表于 2016-4-17 14:45:05

好东西, 村长的好像是手动取点的,操作很困难
这个是自动的
页: [1]
查看完整版本: 转 使用补偿修正方法解决Z轴零平面不平问题,特别适用于...