刻字机尖角补偿

1 刻字机尖角补偿原理

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

如上图所示,切割俩条相邻线段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的转角为β-α。

2 尖角补偿python程序实现

python 复制代码
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:
            min_x = point['x']
        if point['y']<min_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:
            min_x = point['x']
        if point['y']<min_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:
            min_x = point['x']
        if point['y']<min_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)

正方形尖角补偿轨迹:

三角形尖角补偿轨迹:

方圆尖角补偿轨迹:

相关推荐
TangKenny24 分钟前
计算网络信号
java·算法·华为
景鹤24 分钟前
【算法】递归+深搜:814.二叉树剪枝
算法
iiFrankie28 分钟前
SCNU习题 总结与复习
算法
Dola_Pan1 小时前
C++算法和竞赛:哈希算法、动态规划DP算法、贪心算法、博弈算法
c++·算法·哈希算法
小林熬夜学编程2 小时前
【Linux系统编程】第四十一弹---线程深度解析:从地址空间到多线程实践
linux·c语言·开发语言·c++·算法
阿洵Rain2 小时前
【C++】哈希
数据结构·c++·算法·list·哈希算法
姜西西_2 小时前
动态规划 之 斐波那契数列模型 算法专题
算法·动态规划
格里菲斯8583 小时前
算法练习记录
算法
阿芯爱编程3 小时前
平衡二叉树
java·后端·算法
幼儿园园霸柒柒3 小时前
第七章: 7.3求一个3*3的整型矩阵对角线元素之和
c语言·c++·算法·矩阵·c#·1024程序员节