刀具切割直线段过渡方法在文章旋转偏心裁切刀切向跟踪及半径补偿 已经有过说明。刻字机由于刀具半径的影响,切割直角时会不直会比较圆滑,而且在闭合曲线的下刀点会容易不闭合。使用尖角补偿可以克服这些问题。

如上图所示,切割俩条相邻线段AB和BC时,刀心需要走的轨迹是从A' --> B' --> B'' -->C'。由于刻字机使用的刻刀刀尖半径都比较小,而且刀具也是固定没有转动轴控制转动,所以从B'过渡到B''时使用圆弧进行过渡。这里B2和B1都是圆弧上的过渡点。示意图中从B'B''采用小线段B'B2、B2B1、B1B''进行圆弧拟合过渡。
AB的矢量角α,则A'点坐标为(Xa+r*cosα,Ya+r*sinα)。BC的矢量角为β,则B''的坐标为(Xb+r*cosβ,Yb+r*sinβ)。C'的坐标为(Xc+r*cosβ,Yc+r*sinβ)。AB的转角为β-α。
- import numpy
- import cv2
- import math
-
- const_ratio = 10
- WIDTH = 100
- HEIGHT = 60
- KNIFE_CIR = 40 #plt中40个单位=1mm
- ANGLE_STEP = 30 #圆弧过渡时插补间隔30度
-
- def show_img(window,img):
- cv2.namedWindow(window,0)
- cv2.resizeWindow(window,int(img.shape[1]),int(img.shape[0]))
- cv2.imshow(window,img)
-
- def proc_line(line):
- i = 0
- signZ = 1
- if len(line) == 0:
- return None
- while line[i]<'0' or line[i]>'9':
- if line[i] == 'U':
- signZ = 0
- if line[i] == '-':
- break
- i = i+1
- if i == len(line):
- return None
-
- line = line[i:]
- if len(line) == 0:
- return None
- strs = line.split(',')
- if len(strs) != 2:
- return None
- axis_y = int(strs[0])
- axis_x = int(strs[1])
-
- if (axis_x is None) or (axis_y is None):
- return None
- return {'x':axis_x,'y':axis_y,'z':signZ}
-
- def plot_plt(cv_img,data,print_width,print_height):
- height_total = print_height
- width_total = print_width
- line = ""
- comma = 0
- points = []
- for i in range(len(data)):
- try:
- ch = chr(data[i])
- except:
- ch = data[i]
- if ch == ';':
- point = proc_line(line)
- if point is not None:
- points.append(point)
- line = ""
- comma = 0
- else:
- line = line+ch
- if ch==',' or ch==' ':
- comma = comma+1
- if comma == 2:
- point = proc_line(line)
- if point is not None:
- points.append(point)
- line = ""
- comma = 0
- max_x = points[0]['x']
- max_y = points[0]['y']
- min_x = points[0]['x']
- min_y = points[0]['y']
-
- for point in points:
- if point['x']>max_x:
- max_x = point['x']
- if point['y']>max_y:
- max_y = point['y']
- if point['x']
- min_x = point['x']
- if point['y']
- min_y = point['y']
- print(max_x,max_y,min_x,min_y)
-
- pre_point = points[0]
- black = (0,255,0)
-
- offset_x = 10*const_ratio
- offset_y = 10*const_ratio
-
- for point in points:
- x = int((point['x'])*const_ratio/40+offset_x)
- y = int((point['y'])*const_ratio/40+offset_y)
- if point['z'] == 1:
- cv2.line(cv_img,(pre_point['x'],pre_point['y']),(width_total*const_ratio-x,height_total*const_ratio-y),black,lineType=cv2.LINE_AA)
- pre_point = {'x':width_total*const_ratio-x,'y':height_total*const_ratio-y}
-
- def plot_file(img,filepath):
- with open(filepath) as f:
- data = f.read()
- plot_plt(img,data,WIDTH,HEIGHT)
-
- def plot_plt_comp(cv_img,data,print_width,print_height):
- height_total = print_height
- width_total = print_width
- line = ""
- comma = 0
- points = []
- for i in range(len(data)):
- try:
- ch = chr(data[i])
- except:
- ch = data[i]
- if ch == ';':
- point = proc_line(line)
- if point is not None:
- points.append(point)
- line = ""
- comma = 0
- else:
- line = line+ch
- if ch==',' or ch==' ':
- comma = comma+1
- if comma == 2:
- point = proc_line(line)
- if point is not None:
- points.append(point)
- line = ""
- comma = 0
- max_x = points[0]['x']
- max_y = points[0]['y']
- min_x = points[0]['x']
- min_y = points[0]['y']
-
- for point in points:
- if point['x']>max_x:
- max_x = point['x']
- if point['y']>max_y:
- max_y = point['y']
- if point['x']
- min_x = point['x']
- if point['y']
- min_y = point['y']
- print(max_x,max_y,min_x,min_y)
-
- #这里开始执行尖角补偿插补计算
- angleArr = []
- pointNum = len(points)
- pre_point = {'x':0,'y':0,'z':0}
- pre_angle = 0
- downPoint = None
- downAngle = 0
- off_x = 0
- off_y = 0
- pointsInterpArr = []
- for i in range(pointNum):
- point = points[i]
- angle = math.atan2(point['y']-pre_point['y'],point['x']-pre_point['x'])
- length = math.sqrt((point['y']-pre_point['y'])*(point['y']-pre_point['y'])+(point['x']-pre_point['x'])*(point['x']-pre_point['x']))
- angleArr.append(angle)
- angle_delta = (angle-pre_angle)*180/math.pi
- if angle_delta >= 180:
- angle_delta = angle_delta-360
- elif angle_delta <= -180:
- angle_delta = angle_delta+360
- if angle_delta>0:
- angle_step = ANGLE_STEP
- else:
- angle_step = -ANGLE_STEP
- print(angle_delta,length)
- if length == 0:
- continue
- elif point['z'] == 0: #抬刀时不处理
- pointsInterpArr.append(point)
- elif pre_point['z'] == 0:#由抬刀变为下刀保存下刀点坐标和角度,并进行起点和终点偏移
- downPoint = pre_point
- downAngle = angle
- x1=pre_point['x']+KNIFE_CIR*math.cos(angle)
- y1=pre_point['y']+KNIFE_CIR*math.sin(angle)
- pointsInterpArr.append({'x':int(x1),'y':int(y1),'z':0})
- x2 = point['x']+KNIFE_CIR*math.cos(angle)
- y2 = point['y']+KNIFE_CIR*math.sin(angle)
- pointsInterpArr.append({'x':int(x2),'y':int(y2),'z':1})
- off_x = KNIFE_CIR*math.cos(angle)
- off_y = KNIFE_CIR*math.sin(angle)
- elif abs(angle_delta)>30:#下刀切割时线段转角大于30度时进行圆弧过渡
- count = math.floor(angle_delta/angle_step)
- remain = angle_delta-count*angle_step
- for j in range(0,count):
- x = pre_point['x']+KNIFE_CIR*math.cos(pre_angle+angle_step*(j+1)*math.pi/180)
- y = pre_point['y']+KNIFE_CIR*math.sin(pre_angle+angle_step*(j+1)*math.pi/180)
- pointsInterpArr.append({'x':int(x),'y':int(y),'z':1})
- if abs(remain) > 0.1:
- x = pre_point['x']+KNIFE_CIR*math.cos(angle)
- y = pre_point['y']+KNIFE_CIR*math.sin(angle)
- pointsInterpArr.append({'x':int(x),'y':int(y),'z':1})
-
- delta_x = KNIFE_CIR*math.cos(angle)
- delta_y = KNIFE_CIR*math.sin(angle)
- pointsInterpArr.append({'x':int(point['x']+delta_x),'y':int(point['y']+delta_y),'z':point['z']})
-
- off_x = KNIFE_CIR*math.cos(angle)
- off_y = KNIFE_CIR*math.sin(angle)
- else:#转角小于30度直接过渡
- delta_x = KNIFE_CIR*math.cos(angle)
- delta_y = KNIFE_CIR*math.sin(angle)
- pointsInterpArr.append({'x':int(point['x']+delta_x),'y':int(point['y']+delta_y),'z':point['z']})
-
- #发现是下刀点坐标时代表曲线段闭合,进行闭合圆弧过渡
- if downPoint != None and length > 0 and point['x'] == downPoint['x'] and point['y'] == downPoint['y']:
- angle_delta = (downAngle-angle)*180/math.pi
- if angle_delta >= 180:
- angle_delta = angle_delta-360
- elif angle_delta <= -180:
- angle_delta = angle_delta+360
- if angle_delta>0:
- angle_step = ANGLE_STEP
- else:
- angle_step = -ANGLE_STEP
- count = math.floor(angle_delta/angle_step)
- remain = angle_delta-count*angle_step
- for j in range(0,count):
- x = point['x']+KNIFE_CIR*math.cos(angle+angle_step*(j+1)*math.pi/180)
- y = point['y']+KNIFE_CIR*math.sin(angle+angle_step*(j+1)*math.pi/180)
- pointsInterpArr.append({'x':int(x),'y':int(y),'z':1})
- if abs(remain) > 0.1:
- x = point['x']+KNIFE_CIR*math.cos(downAngle)
- y = point['y']+KNIFE_CIR*math.sin(downAngle)
- pointsInterpArr.append({'x':int(x),'y':int(y),'z':1})
- pre_point = point
- pre_angle = angle
-
- pre_point = pointsInterpArr[0]
- black = (0,255,0)
-
- offset_x = 10*const_ratio
- offset_y = 10*const_ratio
-
- max_x = pointsInterpArr[0]['x']
- max_y = pointsInterpArr[0]['y']
- min_x = pointsInterpArr[0]['x']
- min_y = pointsInterpArr[0]['y']
- for point in pointsInterpArr:
- if point['x']>max_x:
- max_x = point['x']
- if point['y']>max_y:
- max_y = point['y']
- if point['x']
- min_x = point['x']
- if point['y']
- min_y = point['y']
- print(max_x,max_y,min_x,min_y)
-
- for point in pointsInterpArr:
- x = int((point['x'])*const_ratio/40+offset_x)
- y = int((point['y'])*const_ratio/40+offset_y)
- if point['z'] == 1:
- cv2.line(cv_img,(pre_point['x'],pre_point['y']),(width_total*const_ratio-x,height_total*const_ratio-y),black,lineType=cv2.LINE_AA)
- pre_point = {'x':width_total*const_ratio-x,'y':height_total*const_ratio-y}
-
- def plot_file_comp(img,filepath):
- with open(filepath) as f:
- data = f.read()
- plot_plt_comp(img,data,WIDTH,HEIGHT)
-
- cv_img = numpy.ones((HEIGHT*const_ratio,WIDTH*const_ratio),dtype=numpy.uint8)
- cv_img = cv2.bitwise_not(cv_img)
- cv2.rectangle(cv_img,(0,0),(WIDTH*const_ratio-1,HEIGHT*const_ratio-1),(0,0,0))
-
- file = 'C:/Users/liuzj/Desktop/plt/rec.plt'
- plot_file(cv_img,file)
- show_img('img1',cv_img)
-
-
- cv_img2 = numpy.ones((HEIGHT*const_ratio,WIDTH*const_ratio),dtype=numpy.uint8)
- cv_img2 = cv2.bitwise_not(cv_img2)
- cv2.rectangle(cv_img2,(0,0),(WIDTH*const_ratio-1,HEIGHT*const_ratio-1),(0,0,0))
-
- plot_file_comp(cv_img2,file)
- show_img('img2',cv_img2)
-
-
-
- cv2.waitKey(0)
正方形尖角补偿轨迹:

三角形尖角补偿轨迹:

方圆尖角补偿轨迹:

-
相关阅读:
Go 语言 设计模式-生成器模式
NFT Insider #64:电商巨头eBay提交NFT相关商标申请,毕马威将在Web3和元宇宙中投入3000万美元
CPP-Templates-2nd--第十九章 萃取的实现 19.4-19.5
基于人工蜂群算法的新型概率密度模型的无人机路径规划(Matlab代码实现)
PaddleOCR系列-训练模型并部署android手机
m基于16QAM的自适应波束形成matlab仿真
计算机网络基础(二):物理层、数据链路层及网络层
最新SparkAI创作系统V2.6.2/ChatGPT网站系统H5源码+微信公众号版+AI绘画系统源码/支持GPT联网提问/支持Prompt应用
16.预处理、动态库、静态库
ZeroTier CentOS7 网关机配置
-
原文地址:https://blog.csdn.net/liuzhijun301/article/details/132889246