基于FreeCAD的dxf转机械手代码的一种实现方法

news2024/11/28 11:35:06

dxf文件在2D图形中使用广泛,将图形文件自动转换为机械手可识别的轨迹代码是机械手全自动化中一个软件衔接节点。理想的轨迹自动化转换程序可以在电脑里面直接虚拟仿真生成机械手轨迹,简化现场人员机械手示教流程,在效率和远程支持上有着实际的应用前景。

但是类似dxf格式的图形文件无法直接被机械手使用,原因是:一 存在格式解析问题;二 dxf文件需要针对不同应用进行一些参数调整和轨迹增删后才具备实用价值。开发一套能够将CAD图形文件转换为库卡机械手可识别的src格式文本的软件是有其实际的实用性。本文讨论借用现有的FreeCAD进行显示,通过编写插件解析的方式来实现dxf文件转库卡机械手src。

首先要了解dxf文件的特点:

dxf文件是以entity为单位的基本形状的组合体,较简单的图形应用中则主要以line和circle这样的基本单元,其中的line只有起点和终点,circle则由中心点,半径,起始和结束角组成。理想的dxf文件应该是人眼观察到的每个单元头尾相连构成一个完整的2D/3D图形,但是实际中图形文件可能隐含非常短的小线段或很小的面积(作图人员的随意)、各个单元的数据也可能没有按照头尾相连的顺序(里面的元素是按照作图人员画图顺序存放的),对于要求精度不高且对机械手运行速度有要求的应用场景,机械手轨迹无需考虑这些小段和面积(过多的细线段会导致更多的点发给机械手,导致机械手运行速度降低),需要算法对dxf文件的entity进行过滤、排序才可用于后续分析。

3D的stp文件则存在一个在3D曲面上选取线的问题,由于3d曲面也是由多个面组成,对面(face)的过滤规则可以考虑选用面的‘脊’来作为轨迹路线,比如限定基于Z轴方向最高的面作为轨迹选取面,可以通过求取该面两边的中值作为轨迹点的值。但是这种假设要求提供的图形必须按照这个规律做好预处理,否则无法正确提取轨迹。

不同应用对生成的轨迹要求不同,我对已知机械手的轨迹分为三类:

1 巡边类  该类轨迹并非是dxf文件展示的图形,而是由dxf的轨迹数据结合特定特征点比如拐角通过算法生成额外的空间补偿数据组合生成(自动插入额外点)。这类需求一般对走位的精度要求不高,但是要求能够自行生成dxf文件提供的额外的插补点位置,同时要求在保证合适精度前提下尽量减少点的数目以确保机械手运行速度。实现对应功能该类算法需要考虑:机械手执行速度、额外的轨迹补偿点。比如下图左上角两个空中轨迹点就是巡边过程中算法在空间插入的额外轨迹点:

2 画图类  一般是机械手在一个面上进行类似画图的移动操作,该类轨迹为以非闭合多段线为主,多数对精度有要求,故需要尽可能还原原始轨迹数据点且不能自行插入额外数据。比如下图就是机械手点的轨迹图:

 3 3D 轨迹类  这类作业面为非平面,故需要对3D的图形进行分析和3D的空间轨迹规划。

三类文件的共性需求包括:

中点重新定位   生成的机械手轨迹坐标选取到目标本身是合理的,这样图形坐标系和机械手坐标系才可以进行关联和转换,在提供的dxf文件多数坐标系零点并非构建在目标物体身上,故需要进行偏移转换。

旋转  由于现场目标物体的摆放位置可能具有一定的旋转,生成的轨迹坐标也需要支持旋转功能。

进出点 对于闭合曲线,必须能够定义机械手进入和退出的点位信息。

单独编辑功能  用户应该可以自行修改生成点位的位置信息。

考虑到同时要支持2D和3D且图形编辑需要尽可能的自由性,可以选用开源软件FreeCAD作为主体软件,通过编写FreeCAD的插件实现上述各类图形文件的解析过程。不同于原始dxf信息,我们直接使用被FreeCAD转化过的图形元素。

技能要求

1 python编程含调试

2 平面和立体几何

3 了解机械手的运动特点

4 了解几种轨迹的路线要求

下面简单介绍一下python如何和FreeCAD的dxf文件进行交互。

objs=App.ActiveDocument.Objects  --->获取当前激活的dxf文档的对象数组

 Gui.activateWorkbench("DraftWorkbench")-->切换到draft工作环境

Gui.ActiveDocument.ActiveView.setAxisCross(True)-->显示坐标轴

 sel = FreeCADGui.Selection.getSelection()--->获取图形元素,注意dxf图像中不同层会放到sel数组不同的元素里。

Draft.move(sel[0],FreeCAD.Vector(offset_x,offset_y,0),copy=False)--->重定位图形到新的坐标位置

Draft.rotate(sel[0], rotation-current_angle, FreeCAD.Vector(0.0, 0.0, 0.0), axis=FreeCAD.Vector(0.0, 0.0, 1.0), copy=False)  旋转图形到指定角度

w0 =sel[0][0].Shape  获取shape

shape是由许多edge组成,比如下面代码段可以提取长度超过1的edges。

for e in w0.Edges:

            if e.Length >=1:

                useful_edges.append(e)

对提取的edges数组可以进行拼接:
cedges=OpenSCAD2Dgeom.findConnectedEdges(useful_edges,eps=1)

对拼接的cedges进行分析拆出里面具体元素的信息:

for edges in cedges:

            tmp_points=[]

            last_points=None  #used for decide if that segment should be reversed.

            for e in edges:

                typ=None

                center=None

                if (str(e.Curve)[1:5] == "Line"):

                    points = [e.Vertexes[0].Point, e.Vertexes[1].Point]

                    typ='LIN'

                elif (str(e.Curve)[0:6]  == "Circle"):

                    points=e.discretize(Number=3)

                    typ='CIRC'

                    center=e.Curve.Center

                if last_points!=None:

                    if self.pointsequals(last_points[-1],points[-1]):

                        points.reverse()

                last_points=points

                tmp_points.append((typ,accurate_vertexs(points),center))

            if revers ==0:

                for i in tmp_points:

                    i[1].reverse()

                tmp_points.reverse()

            contour_points=[]

            end_point=None

            end_angle=None

            for cp in tmp_points:  #calculate the angle

                if cp[0]=='LIN':

                    v=cp[1][1].sub(cp[1][0])

                    angle=self.get_relative_angle(v)

                    contour_points.append((cp[0],cp[1][0],round(angle,2)))

                    end_point=cp[1][1]

                    end_angle=angle

                    #self.place_arrow(cp[1][0],angle)

                elif cp[0]=='CIRC':

                    clockwise=self.Is3PointClockWise(cp[2],cp[1][0],cp[1][1])

                    v1=cp[1][0].sub(cp[2])

                    v2=cp[1][1].sub(cp[2])

                    v3=cp[1][1].sub(cp[1][0])

                    angle1=v2.getAngle(v1)*180/pi

                    rangle=self.get_relative_angle(v3)

                    if clockwise:

                        angle1=rangle+angle1/2

                    else:

                        angle1=rangle-angle1/2

                    v1=cp[1][1].sub(cp[2])

                    v2=cp[1][2].sub(cp[2])

                    v3=cp[1][2].sub(cp[1][1])

                    angle2=v2.getAngle(v1)*180/pi

                    rangle=self.get_relative_angle(v3)

                    if clockwise:

                        angle2=angle2/2+rangle

                    else:

                        angle2=rangle-angle2/2

                    contour_points.append((cp[0],cp[1][0],round(angle1,2),cp[1][1],round(angle2,2)))

                    end_point=cp[1][2]

                    end_angle=round(angle2,2)

                    #self.place_arrow(cp[1][0],angle1)

                    #self.place_arrow(cp[1][1],angle2)

            self.progressBar.setValue(cedges.index(edges)+1)

            contour_points.append(('LIN',end_point,end_angle)) #since there are only one point available, we use 'lin' to implement it.

            layout_contours.append(contour_points)

        layout_contours=self.sortTracks(layout_contours)

进一步对layout_contours数据分析并转化为机械手的代码(这里以库卡机械手为例):

def get_layout_data(self):

        targetData=''

        index=0

        seq=0

        point=layout_contours[0][0][1]

        angle=layout_contours[0][0][2]

        stmp='LIN {E6POS: X '+str(point.x)+', Y '+str(point.y)+', Z 30.000, A '+str(angle) +', B 0.000, C 0.000, E1 0.000} C_VEL'+';'

        targetData=targetData+stmp+'\n'

        seq+=1

        stmp='LIN {E6POS: X '+str(point.x)+', Y '+str(point.y)+', Z 0.000, A '+str(angle)+', B 0.000, C 0.000, E1 0.000} C_VEL'+';'+str(seq)

        targetData=targetData+stmp+'\n'

        seq+=1

        for tr in layout_contours:

            targetData+=';*******************track:'+str(layout_contours.index(tr))+'*************************'+'\n'

            for e in tr:

                if e[0]=='LIN':

                    point=e[1]

                    angle=e[2]

                    stmp='LIN {E6POS: X '+str(point.x)+', Y '+str(point.y)+', Z 0.000, A '+str(angle)+', B 0.000, C 0.000, E1 0.000} C_VEL'+';'+str(seq)

                    targetData=targetData+stmp+'\n'

                    seq+=1

                elif e[0]=='CIRC':

                    point1=e[1]

                    angle1=e[2]

                    point2=e[3]

                    angle2=e[4]

                    stmp ='CIRC {POS: X ' + str(point1.x) + ', Y ' + str(point1.y) + ', Z 0.0, A ' +str(angle1) + ', B 0.0, C 0.0},'+'{POS: X ' + str(point2.x) + ', Y ' + str(point2.y) + ', Z 0.0, A ' + str(angle2) + ', B 0.0, C 0.0} C_VEL' + ';' + str(seq)

                    targetData=targetData+stmp+'\n'

                    seq+=2

        targetData=targetData+'END\n'

        return targetData

转换过程由于需要输入参数,可以自己设计一个界面:

 最后生成的src文件大致如下:

 

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

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

相关文章

2021 神经网络压缩 (李宏毅

首先,为什么需要对神经网络模型进行压缩呢?我们在之前的课程中介绍过很多大型的深度学习模型,但当我们想要将这些大模型放在算力比较小的边缘设备或者其他IoT设备里面,就需要对大模型进行压缩。 Lower latency:低时延 …

刷题笔记之八(字符串通配符+参数解析+计算日期到天数)

目录 1. dateadd(datepart,number,date)函数是在日期中添加或减去指定的时间间隔 2. DML数据库操作语言负责数据的增删查改 3. 修改表结构的关键字都是alter table 表名,再加修改的语句 4. between and条件查询范围前闭后闭 5. 使用索引…

目标检测(1)—— 基础知识和常用数据集

一、什么是目标检测 一张图片,经过网络后得到输出,检测出感兴趣目标的一个位置,比如下图的车在什么地方,狗在什么地方;还要输出相应位置的目标是什么类别的。 目标检测:位置+类别 矩形框&…

vue 的 render 函数的用法:new Vue({ render: h => h(App), }).$mount(‘#app‘)

render函数的作用 render函数是vue通过js渲染dom结构的函数createElement,约定可以简写为h 官方文档中是这样的,createElement 是 Vue.js 里面的 函数, 这个函数的作用就是生成一个 VNode节点, render 函数得到这个 VNode 节点之后…

记一次内网靶机实战

文章目录0x00 边界服务器0x01 一层网络0x01-01 fscan内网扫描0x01-02 配置frp设置socks5代理0x01-03 访问内网的(10.10.135.66)0x01-04 访问内网的(10.10.135.35)0x01-05 访问内网的(10.10.135.190)0x02二层…

稀疏数组

章节目录:一、稀疏数组1.1 需求引出1.2 基本介绍1.3 应用实例二、结束语一、稀疏数组 1.1 需求引出 假设我们有个五子棋程序,使用1来表示黑子,2表示蓝子,0表示没有棋盘落子,并且需要对棋盘数据进行存储。 前端棋盘示意…

546、Zookeeper详细入门教程系列 -【Zookeeper内部原理】 2022.11.06

目录一、Zookeeper内部原理1.1 节点类型(Znode)1.2 Stat结构体1.3 监听器原理1.4 选举机制1.5 写数据流程二、最后三、参考链接一、Zookeeper内部原理 1.1 节点类型(Znode) 持久:客户端和服务器断开后,创…

汇编语言程序设计 --- 一元二次方程ax2+bx+c=0求解(含注释详细源代码 + 实验报告)

目录一、实验内容二、实验说明三、实验报告要求四、实验目的五、 程序流程图六、内存变化情况七、实验报告 源程序代码 (详细注释)一、实验内容 一元二次方程ax2bxc0求解。 二、实验说明 1、要求在数据段中定义a、b、c、x,a、b、c初值不限…

【晶振专题】案例:为什么对着STM32低速32.768K晶振哈口气就不起振了?

本案例发现在一个工装产品上,首批一共做了10几台样机。发现有的样机在开机的时候读取不到RTC,有的样机却可以。读不到RTC是概率性出现的,发生在第一次上电的情况。开始他怀疑是环境问题,会不会和温度有关,于是同事在家做了大量的实验,发现对晶振吹口气就能让晶振不起振,…

01-nacos在Windows系统单机,集群的安装

一 ,什么是Nacos?官网 Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos 提供了一组简单易用的特性集,能够快速实现动态服务发现、服务…

Flutter教程之在 Flutter 中显示 TextField 上的日期选择器(教程含源码)

首先我们必须知道它是什么 Flutter 中的日期选择器——Flutter 日期范围选择器是一个轻量级的小部件,它允许用户轻松选择单个日期、多个日期或一个日期范围。日期选择器提供月、年、十年和世纪视图选项,以快速导航到所需的日期。 让我们实现它… 日期选择器—— 我们将在 …

机场调度管理系统(客户端+服务器端+Java+MySQL)

目 录 1 绪论 1 1.1 项目背景 1 1.2 项目目的 1 1.3 项目可行性分析 2 2 技术介绍 3 2.1 Java技术 3 2.1.1 Java技术简介 3 2.1.2 Java面向对象的特征 3 2.2Javascript和jQuery技术 4 2.1.1 Javascript 简介 4 2.2.2 jQuery-easyui简介 4 2.3Jsp技术 5 2.4 Mysql 5 3 需求分析…

python基础05——字典:dict及集合:set,看这篇文章就够了

目录1字典: dict 无序可变序列1.1 创建1.1.1 用{ }创建字典1.1.2 用dict创建字典1.1.3 用zip创建字典1.1.4 用fromkeys创建字典1.2 查询1.2.1 通过键访问字典的值1.2.1.1 直接取键 dict[ ]1.2.1.2 get()1.2.2 查看字典的键和值1.2.2.1 返回所有的键 dict.keys()1.2.2.2 返回所有…

分布式搜索———黑马旅游

案例功能实现 : ● 酒店搜索和分页 ● 酒店结果过滤 ● 我周边的酒店 ● 酒店竞价排名 资源链接 hoteld-demo工程:https://pan.baidu.com/s/1YlKz6vxcm7VWXAWPlUiBqg 提取码:GY66 进入hoteld-demo工程,启动服务,打开浏览器进入…

uniapp微信小程序半屏跳转小程序

1、资料设置申请绑定 进入微信小程序 设置 -> 第三方设置 -> 半屏小程序管理 添加需要绑定的小程序的appid 等待审核,审核通过后开始写代码 2、代码编写 (1)、以前的跳转方式是uni.navigateToMiniProgram 换成wx.openEmbeddedMiniP…

Spring核心思想

文章目录1. Spring核心思想1.1 Spring是什么1.2 什么是容器1.3 什么是loC1.3.1 传统开发1.3.2 如何解决传统开发中耦合度高的问题1.3.3 控制反转程序的编写1.4 理解Spring loC1.5 什么是DI1. Spring核心思想 1.1 Spring是什么 我们通常说的Spring是Spring Framework(Spring框…

一个非常实用的分布式 JVM 监控工具

介绍 该项目为了方便开发者更快监控多个远程主机jvm,如果你的项目是Spring boot那么很方便集成,jar包引入即可,不是Spring boot也不用气馁,你可以快速自行初始化一个Spirng boot程序引入jar包即可 效果展示 整体架构 git地址 ht…

Kafka由浅入深(6) Sender线程执行源码解析

一、KafkaProducer消息流程图 1.1 KafkaProducer 消息架构图 1.2 KafkaProducer 消息架构分为两部分 第一部分是KafkaProducer主线程 主要逻辑提供消息拦截器、序列化器、和分区器的默认实现和对外自定义扩展功能,已经将消息追加并缓存到累加器RecordAccumulator…

NeurIPS 2022 | 涨点神器!利用图像辅助三维点云分析的训练新范式

原文链接:https://www.techbeat.net/article-info?id4212 作者:颜旭 点云作为一种基本的三维表征形式,活跃在自动驾驶、机器人感知等多种任务上。尽管三维点云分析在近年来取得了良好的发展,但由于点云其本身往往是无序、无纹理以…

OpenCV笔记--人脸识别算法Eigenfaces和Fisherfaces

目录 1--前言 2--处理ORL数据集 3--Eigenfaces复现过程 4--Fisherfaces复现过程 5--分析 1--前言 ①SYSU模式识别课程作业 ②配置:基于Windows11、OpenCV4.5.5、VSCode、CMake(参考OpenCV配置方式) ③原理及源码介绍:Face…