刻字机尖角补偿

2023-09-14 20:17:14

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程序实现

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)

正方形尖角补偿轨迹:

三角形尖角补偿轨迹:

方圆尖角补偿轨迹:

更多推荐

3.k8s dashboard设置域名登录案例(ingress版本为1.3.1)

文章目录前言一、安装ingress1.1下载ingress部署文件1.2查看是否安装成功二、配置dashboard域名映射2.1.在windows和linux添加上域名映射2.2生成tls证书2.3新增ingress配置2.3验证总结前言前面搭建了集群,配置了账号密码登录,现在配置k8sdashboard的域名登录,这

Augmented Large Language Models with Parametric Knowledge Guiding

本文是LLM系列文章,针对《AugmentedLargeLanguageModelswithParametricKnowledgeGuiding》的翻译。参数知识引导下的增强大型语言模型摘要1引言2相关工作3LLM的参数化知识引导4实验5结论摘要大型语言模型(LLM)凭借其令人印象深刻的语言理解和生成能力,显著提高了自

GPT4RoI: Instruction Tuning Large Language Model on Region-of-Interest

在图像-文本对上调整大语言模型(LLM)的指令已经实现了前所未有的视觉-语言多模态能力。然而,他们的视觉语言对齐仅建立在图像级别上,缺乏区域级别对齐限制了他​​们在细粒度多模态理解方面的进步。在本文中,我们提出对感兴趣区域进行指令调整。关键设计是将边界框重新表述为空间指令的格式。将空间指令和语言嵌入提取的视觉特征的交错

计算机网络基础知识(非常详细)

1.网络模型1.1OSI七层参考模型七层模型,亦称OSI(OpenSystemInterconnection)参考模型,即开放式系统互联,是网络通信的标准模型。一般称为OSI参考模型或七层模型。它是一个七层的、抽象的模型体,不仅包括一系列抽象的术语或概念,也包括具体的协议。物理层:负责传输原始的比特流,数模转换、模数转

Postman应用——Collection、Folder和Request

文章目录Collection新建CollectionCollection重命名保存Request到Collection在Collection下创建Request删除CollectionFolder新建FolderFolder重命名保存Request到Folder在Folder下创建Request在Folder下创建Fo

MySQL数据库详解 一:安装MySQL数据库及基本管理

文章目录1.数据库的基本概念1.1数据库的组成1.1.1数据1.1.2表1.1.3数据库1.2当前主流数据库及其特点1.3数据库类型1.3.1关系数据库1.3.1.1关系数据库的组成1.3.1.2非关系数据库2.安装MySQL2.1yum安装2.2编译安装MySQL2.2.1前置准备2.2.2编译安装2.2.3修改my

成集云 | 用友U8集成聚水潭ERP(用友U8主管供应链)| 解决方案

源系统成集云目标系统方案介绍用友U8是一套企业级的解决方案,可满足不同的制造、商务模式下,不同运营模式下的企业经营管理。它全面集成了财务、生产制造及供应链的成熟应用,并延伸客户管理至客户关系管理(CRM),以及零售、分销领域实现了全面整合。聚水潭是一款以SaaSERP为核心,集多种商家服务为一体的SaaS协同平台,为全

Flink-CDC 抽取SQLServer问题总结

Flink-CDC抽取SQLServer问题总结背景flink-cdc抽取数据到kafka中,使用flink-sql进行开发,相关问题总结flink-cdc配置SQLServercdc参数1.创建CDC使用的角色,并授权给其查询待采集数据数据库--a.创建角色createroleflink_role;--b.授权给角色

保证接口幂等性

什么是幂等性幂等性是系统服务对外一种承诺,承诺只要调用接口成功,外部多次调用对系统的影响是一致的。声明为幂等的服务会认为外部调用失败是常态,并且失败之后必然会有重试。什么情况下需要幂等以SQL为例:SELECTcol1FROMtab1WHERcol2=2,无论执行多少次都不会改变状态,是天然的幂等。UPDATEtab1

什么是 BSD 协议?

BSD开源协议是一个给于使用者很大自由的协议。可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。当你发布使用了BSD协议的代码,或者以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件:如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。如果再发布的只是二进制类

【Redis】使用rpm包安装redis

背景说明公司环境处于内网,某同事需要安装redis,如果使用通过源码编译安装redis,很多编译工具如gcc就需要先安装,但处于内网安装起来不太方便,当然也不是不可以。我们此处就选用通过redis的rpm包进行安装。rpm包查找及下载找一台可以上互联网的干净服务器(干净的目的是防止以前有些包安装过,就不会再下载),最好

热文推荐