刻字机尖角补偿

news2024/12/24 21:53:37

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)

正方形尖角补偿轨迹:

三角形尖角补偿轨迹:

方圆尖角补偿轨迹:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1011854.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据Flink(七十七):SQL窗口的Over Windows

文章目录 SQL窗口的Over Windows 一、​​​​​​​时间区间聚合

Say0l的安全开发-代理扫描工具-Sayo-proxyscan【红队工具】

写在前面 终于终于&#xff0c;安全开发也练习一年半了&#xff0c;有时间完善一下项目&#xff0c;写写中间踩过的坑。 安全开发的系列全部都会上传至github&#xff0c;欢迎使用和star。 工具链接地址 https://github.com/SAY0l/Sayo-proxyscan 工具简介 SOCKS4/SOCKS4…

网络安全中的欺骗攻击与防御技术

在Internet上计算机之间相互进行的交流建立在两个前提之下&#xff1a;认证、信任。 认证是网络上的计算机用于相互间进行识别的一种鉴别过程&#xff0c;经过认证的过程&#xff0c;获准相互交流的计算机之间就会建立起相互信任的关系。信任和认证具有逆反关系&#xff0c;即…

振弦传感器信号转换器在岩土工程监测中的注意事项

振弦传感器信号转换器在岩土工程监测中的注意事项 振弦传感器是岩土工程中常用的一种监测设备&#xff0c;用于监测土体和岩体的振动情况。而振弦传感器信号转换器则是将传感器所获得的振动信号转换为人类可读的数据&#xff0c;以方便监测人员进行数据分析和工程决策。 然而&a…

[php] 文件上传的一个项目emmm

项目完整地址 <!DOCTYPE html> <html lang"zh"> <head><meta charset"UTF-8"><title>上传文件</title><link href"./css/bootstrap.min.css" rel"stylesheet"><style>font-face {fo…

亚马逊云科技创新加速周:以数智化手段加速中国企业出海之旅

近年来&#xff0c;越来越多的中国企业正在走向国际市场&#xff0c;中国企业如何在出海浪潮下稳重求进&#xff1f;9月18日-9月22日&#xff0c;新一期亚马逊云科技合作伙伴加速周将为您带来“智荟出海”专题。“智荟出海计划”是亚马逊云科技发布的一项合作计划&#xff0c;旨…

Golang 基础面试题 01

Golang 面试题合集.png 背景 在之前的文章中分享了 k8s 相关的面试题&#xff0c;本文我们重点来讨论和 k8s 密切相关的 Go 语言面试题。 这几年随着云原生的兴起&#xff0c;大部分后端开发者&#xff0c;特别是 Java 开发者都或多或少的想学习一些 Go 相关的技能&#xff0c;…

Postman使用_接口导入导出

文章目录 Postman导入数据Collections导出数据Environments导出数据Postman导出所有数据 Postman导入数据 可以导入collections&#xff08;接口集&#xff09;、Environments&#xff08;环境配置&#xff09;通过分享的链接或导出的JSON文件导入数据&#xff08;还可以从第三…

微信小程序——认识微信小程序

认识小程序 小程序与普通网页开发的区别 运行环境不同 网页运行在浏览器环境中&#xff0c;小程序运行在微信环境中API不同 由于运行环境不同&#xff0c;所以小程序中&#xff0c;无法调用DOM和BOM的API。但是&#xff0c;小程序中可以调用微信环境提供的各种API&#xff0c…

C++之生成详细汇编代码(二百一十六)

简介&#xff1a; CSDN博客专家&#xff0c;专注Android/Linux系统&#xff0c;分享多mic语音方案、音视频、编解码等技术&#xff0c;与大家一起成长&#xff01; 优质专栏&#xff1a;Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 人生格言&#xff1a; 人生…

Python绘制柱状图之可视化神器Pyecharts

文章目录 安装Pyecharts绘制基本柱状图自定义柱状图调整柱状图颜色添加数据标签调整柱状图样式添加动画效果堆叠柱状图横向柱状图 更多类型的柱状图堆叠柱状图百分比堆叠柱状图极坐标柱状图 结论 &#x1f389;欢迎来到AIGC人工智能专栏~Python绘制柱状图之可视化神器Pyecharts…

让AI为您自动生成独特的商品标题,商品描述和营销文案

做外贸的朋友你知道吗&#xff1f;AI可为您自动生成独特的商品标题&#xff0c;商品描述和营销文案 AI生成的商品标题是一项强大的工具&#xff0c;尤其在外贸和跨境电商行业中&#xff0c;它可以帮助您轻松创造引人注目的标题&#xff0c;吸引潜在客户。以下是一个针对外贸和…

JDK 动态代理

动态代理机制 Java 里面&#xff0c;动态代理是通过 Proxy.newProxyInstance()方法来实现的&#xff0c;它需要传入被动态代理的接口类 // 生成代理文件写入磁盘 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");ITrad…

DP专题5 不同路径||

题目&#xff1a; 思路&#xff1a; 这道题&#xff0c;思路跟 不同路径| 思路一样&#xff0c;只是不同的是&#xff0c;有障碍物这一块&#xff0c;我们的二维dp数组初始化的时候&#xff0c;要注意&#xff0c;机器人只能向右和向下&#xff0c;所以初始化第一行和第一列的…

黑龙江省DCMM认证、CSMM认证、CMMM认证、知识产权等政策奖励

2023年8月28日 为深入落实党的二十大精神&#xff0c;认真落实省第十三次党代会关于创新龙江建设的部署要求&#xff0c;全面贯彻新发展理念&#xff0c;融入和服务构建新发展格局&#xff0c;实施创新驱动发展战略&#xff0c;着力建设创新龙江&#xff0c;不断塑造振兴发展新…

基于Yolov8网络进行目标检测(二)-安装和自定义数据集

关于Yolov8的安装在前一个环节忽略了&#xff0c;其实非常简单&#xff0c;只需要以下两个步骤&#xff1a; 1、安装pytorch pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 2、安装ultralytics pip install ultralytics 为什…

功率放大器驱动压电陶瓷有哪些应用

功率放大器在压电陶瓷材料领域的应用。首先&#xff0c;介绍了压电陶瓷的基本概念和特性。然后&#xff0c;阐述了功率放大器的基本原理和分类。接着&#xff0c;分析了功率放大器在压电陶瓷材料领域的应用&#xff0c;包括声波发生器、超声波清洗器、超声波切割器、医疗超声波…

企业架构LNMP学习笔记44

小工具&#xff1a; memcached_tool.php软件&#xff0c;可以查看memcached运行状态、key&#xff08;item&#xff09;的数量、内存使用量等。 1&#xff09;上传memcached_tool.php到web服务器上&#xff1a; 上传到虚拟机主机可以访问的目录即可。需要php的运行环境&…

C语言——指针进阶(三)

目录 一.前言摘要 二.排序函数qsort的模拟实现 三.指针和数组笔试题解析 一.前言摘要 讲述关于strlen和sizeof对于各种数组与指针的计算规则与用法。另外还有qsort函数的模拟实现&#xff08;可以排序任意类型变量&#xff09; 二.排序函数qsort的模拟实现 目标&#xff1a;…

如何选择适合企业的SQL开发工具

在当今数字化时代&#xff0c;数据是企业的核心资产之一。随着数据规模和数据类型的不断增长&#xff0c;数据库管理变得愈发复杂和关键。许多企业用户在数据库管理方面都面临着一系列难题&#xff1a; 核心数据库被随意变更&#xff1a;核心库的波动通常会对企业核心业务产生重…