【运动控制】CNC三轴小线段路径规划
CNC三轴小线段路径规划
文章目录
- CNC三轴小线段路径规划
- 一、项目说明
- 二、具体实现
- 1、速度规划
- 2、小线段插补
- 3、运动学逆解刀轴插补点
- 4、差分处理得到实际的速度和加速度
- 5、加速度滑动平均
- 6、实现的效果如图所示
- 三、Reference
写在前面,本文是作为一个练手小项目的总结,方便以后自己查看,也欢迎大家批评指正。项目地址: GitHub
一、项目说明
参照论文《An optimal feedrate model and solution algorithm for a high-speed machine of small line blocks with look-ahead 》给出的方法给五轴机床做速度规划。输入原始的刀心数据(x,y,z,i,j,k),对其进行速度规划和插补,获得插补后的数据(x,y,z,i,j,k),然后通过运动学逆解转化成刀轴数据(x,y,z,b,c)。通过差分计算实际的速度和加速度与规划的速度进行对比,最后观察平滑滤波后的实际加速度。
二、具体实现
1、速度规划
首先进行速度规划,按照如上的流程图(参考论文)对刀心的速度进行规划,计算得到每个刀心点对应的 ,具体的计算过程是先设定前瞻数,这里设定为4,然后通过判断上述循环条件,在
公式中选取对应的值作为当前的 ,具体的实现是代码中的speed_planning函数,函数的详细解释如下:
def speed_planning(traj_data, max_speed=MAX_SPEED, max_accel=MAX_ACCEL, corner_time=CORNER_TIME, period=PERIOD):""":@func: 参考《An optimal feedrate model and solution algorithm for a high-speed machine of small line blocks with look-ahead》给出的方法,进行速度规划:param traj_data: 路径信息shape(num,3) (x,y,z):param max_speed=0.05: 最大合成速率 m/s:param max_accel=0.5: 最大合成加速度 m/s^2:param corner_time=0.003: 拐弯时间 s:param period = 0.001: 插补周期 s:return:"""# 定义常量block_max = 4 # 最大前瞻数num = len(traj_data)# 开辟存储空间a = np.zeros([num])b = np.zeros([num])e = np.zeros([num])c = np.zeros([num])d = np.power(max_speed,2)Vs = np.zeros([num,1])# 节点差分dp = np.diff(traj_data, axis=0)# 初始化e[0] = db[0] = 0b[1] = 2*max_accel*np.sqrt(np.power(dp[0],2).sum())for i in range(1,num-1): # Vs中第一个速度和最后一个速度都为0j = 0if j < block_max:if i+j <num:j=j+1b[i+j] = 2*max_accel*np.sqrt(np.power(dp,2).sum())e[i+j-1] = corner_time*max_accel*max_accel / (2*(1-(dp[i+j-2,0]*dp[i+j-1,0]+dp[i+j-2,1]*dp[i+j-1,1]+dp[i+j-2,2]*dp[i+j-1,2])/(np.sqrt(np.power(dp[i+j-2],2).sum())*np.sqrt(np.power(dp[i+j-1],2).sum()))))c[i+j-1] = np.min([e[i+j-1],d])if c[i+j-1] > b[i+j]:sum = 0for k in range(i+1,i+j):sum += b[k]if sum >= c[i]:Vs[i]=np.sqrt(np.min([Vs[i-1]*Vs[i-1]+b[i], e[i]]))elif c[i+j-1] <= b[i+j]:sum = 0for k in range(i+1,i+j):sum += b[k]Vs[i] = np.sqrt(np.min([sum+c[i+j-1], Vs[i-1]*Vs[i-1]+b[i], e[i]]))elif i+j >= num:sum = 0for k in range(i+1,i+j):sum += b[k]Vs[i] = np.sqrt(np.min([sum, Vs[i-1]*Vs[i-1]+b[i], e[i]]))elif j>= block_max:sum = 0for k in range(i+1,i+j):sum += b[k]Vs[i] = np.sqrt(np.min([sum, Vs[i-1]*Vs[i-1]+b[i], e[i]]))return Vs
2、小线段插补
然后再按照上图的方法计算每一段插值时所需要的信息
具体实现函数是calc_lines_info
def calc_lines_info(path_data, plan_vels, max_speed=MAX_SPEED, max_accel=MAX_ACCEL):""":@func: 三轴小线段计算中间信息函数:param path_data: 初始路径信息 shape(n,6) (x,y,z,i,j,k):param plan_vels: 初始路径点的合成规划速度 shape(n,1):param max_speed = 0.05: 三轴最大合成速度 m/s:param max_accel = 0.5: 三轴最大合成加速度 m/s^2:return : """num = path_data.shape[0]# distances = np.zeros([num -1, 1]) #插值点间的距离shape(n-1, 3)dp = np.diff(path_data[:,0:3],axis=0)# 开辟存储空间vels_m = np.zeros([num -1])s1 = np.zeros([num -1])s2 = np.zeros([num -1])s3 = np.zeros([num -1])ta = np.zeros([num -1])td = np.zeros([num -1])tl = np.zeros([num -1])for i in range(num -1):# 计算距离# distances[i] = np.sqrt(np.power(path_data[i+1,0:3] - path_data[i,0:3],2).sum()) dis_i = np.sqrt(np.power(dp[i],2).sum())# 计算合成速度vi = plan_vels[i]vi_1 = plan_vels[i+1]# vels_m[i] = min(np.sqrt((np.power(vi,2) + np.power(vi_1,2) + 2*max_accel*distances[i])/2), max_speed)vels_m[i] = min(np.sqrt((np.power(vi,2) + np.power(vi_1,2) + 2*max_accel*dis_i)/2), max_speed)s1[i] = (np.power(vels_m[i],2) - np.power(vi,2))/2s3[i] = (np.power(vels_m[i],2) - np.power(vi_1,2))/2s2[i] = dis_i - s1[i] -s3[i]ta[i] = (vels_m[i] - vi) / max_acceltd[i] = (vels_m[i] - vi_1) / max_acceltl[i] = s2[i] / vels_m[i]return vels_m, ta, td, tl
然后我们进行单条线段的插补,函数实现是calc_axis_point
def calc_axis_point(start, end, Vi, Vi_1, Vm, timea, timed, timel, max_accel=MAX_ACCEL, period=PERIOD):""":@func: 计算一段的插补点:param start: shape(6,):param end: shape(6,):param Vm: 该段的最大速度:param Vi: 起始速度:param Vi_1: 终点速度:param timea: 加速时间:param timed: 匀速时间:param timel: 减速时间:return: 返回给定两点之间的插补点,shape(n,6)"""dist = np.sqrt(np.power(end[0:3]-start[0:3],2).sum())# 计算三轴x,y,z分别所占的比例k1 = (end[0:3]-start[0:3])[0] / np.sqrt(np.power(end[0:3]-start[0:3],2).sum())k2 = (end[0:3]-start[0:3])[1] / np.sqrt(np.power(end[0:3]-start[0:3],2).sum())k3 = (end[0:3]-start[0:3])[2] / np.sqrt(np.power(end[0:3]-start[0:3],2).sum())# 计算法向量的比例delta = (end[3:]-start[3:]) / (timea+timed+timel)# 插值周期数t_count = 1V1 = Vi #起始点速度V2 = Vi_1 #终点速度# 开辟存储空间line_points = np.zeros([1,6])dis = 0while(t_count*period <= timea+timed+timel and dis<=dist):# 计算加速时间内的插值点if t_count*period <= timea:dis += V1*period + 0.5*max_accel*period*periodV1 += max_accel*periodif V1 > Vm:V1 = Vmt_count += 1delta_vec = delta * t_count * perioddelta_xyz = np.concatenate([k1*dis, k2*dis, k3*dis], axis=0)dp = np.concatenate([delta_xyz, delta_vec], axis=0)p = start + dpline_points = np.vstack([line_points, p])# 计算匀速时间内的插值点elif timea < t_count*period <= timea+timel and timel!=0:dis += V1 * periodt_count += 1delta_vec = delta * t_count * perioddelta_xyz = np.concatenate([k1*dis, k2*dis, k3*dis], axis=0)dp = np.concatenate([delta_xyz, delta_vec], axis=0)p = start + dpline_points = np.vstack([line_points, p])# 计算减速时间内的插值点elif timea+timel < t_count*period <= timea+timel+timed:dis += V1*period - 0.5*max_accel*period*periodV1 = V1 - max_accel*periodif V1 < V2:V1 = V2t_count += 1delta_vec = delta * t_count * perioddelta_xyz = np.concatenate([k1*dis, k2*dis, k3*dis], axis=0)dp = np.concatenate([delta_xyz, delta_vec], axis=0)p = start + dpline_points = np.vstack([line_points, p])return line_points[1:]
再进行多条线段插补,函数实现是calc_axis_points
def calc_axis_points(path_data, plan_vels, max_speed=MAX_SPEED, max_accel=MAX_ACCEL, corner_time=CORNER_TIME, period=PERIOD):""":@func: 计算所有的插补点:param path_data: shape(num,6):param plan_vels: shape(num,):param max_speed = 0.05: 三轴最大合成速度 m/s:param max_accel = 0.5: 三轴最大合成加速度 m/s^2:param corner_time = 0.003: 拐弯时间 s:param period = 0.001: 固定插补周期 s:return: 所有的插补点,shape(n,6)"""vels_m, ta, td, tl = calc_lines_info(path_data, plan_vels, max_speed, max_accel)# 开辟存储空间axis_points = np.zeros([1,6])num = len(path_data) - 1for i in range(num):line_points = calc_axis_point(path_data[i], path_data[i+1], plan_vels[i], plan_vels[i+1], vels_m[i], ta[i], td[i], tl[i], max_accel, period)axis_points = np.vstack([axis_points, line_points])return axis_points[1:]
3、运动学逆解刀轴插补点
然后使用运动学逆解,求出刀轴的坐标,函数实现是inv_kinema
def inv_kinema(path_data):""":@func: 求解逆运动学:param path_data: 刀心路径点信息 shape(num,6) (x,y,z,i,j,k):return : 求解的刀轴信息 shape(num,5) (x,y,z,b,c)"""#加载数据points = read_path_data(DATA_PATH)curve_points = points[:,0:3] # 路径normal_vectors = points[:,3:] # 法向量# 旋转轴初始方向wc = sympy.Matrix([[0], [0], [1]])wb = sympy.Matrix([[0], [0.5 * sympy.sqrt(2)], [0.5 * sympy.sqrt(2)]])theta_b, theta_c ,x,y,z= sympy.symbols('theta_b theta_c x y z')# 对C旋转cRodrigues = Rodrigues(wc, theta_c)# 对B旋转bRodrigues = Rodrigues(wb, theta_b)# print(bRodrigues)zero=np.zeros((3,1))# 生成旋转矩阵ec=np.append(cRodrigues,zero,axis=1)e_bu=np.array([0,0,0,1]).reshape(1,4)e_c=np.append(ec,e_bu,axis=0).reshape(4,4)eb=np.append(bRodrigues,zero,axis=1)e_b=np.append(eb,e_bu,axis=0).reshape(4,4)# print(eb,e_b)e_x=np.array([1,0,0,x,0,1,0,0,0,0,1,0,0,0,0,1]).reshape(4,4)e_y=np.array([1,0,0,0,0,1,0,y,0,0,1,0,0,0,0,1]).reshape(4,4)e_z=np.array([1,0,0,0,0,1,0,0,0,0,1,z,0,0,0,1]).reshape(4,4)# 初始位型mt0 = np.array([1,0,0,10,0,1,0,20,0,0,1,100,0,0,0,1]).reshape(4,4)gmw=np.eye(4)gmt1=np.dot(e_x,e_y)gmt2= np.dot(gmt1,e_z)gmt3=np.dot(e_c,e_b)gmt4=np.dot(gmt3,mt0)gmt=np.dot(gmt2,gmt4)# 转移矩阵gm=np.dot(gmw,gmt)# 带入解析式,求解bx = normal_vectors[:,0]/np.linalg.norm(normal_vectors[:,0])#归一化by = normal_vectors[:,1]/np.linalg.norm(normal_vectors[:,1])bz = normal_vectors[:,2]/np.linalg.norm(normal_vectors[:,2])x = curve_points[:,0]y = curve_points[:,1]z = curve_points[:,2] print(2*bz-1)theta_b = np.arccos(2*bz-1)theta_c = np.arcsin(((bz-1)*bx+np.sqrt(2)*np.sqrt(bz-bz**2)*by)/(1-bz**2))# 存数据myfile = open("path_interpolation_xyzbc.txt", "w")myfile.write('x y z b c\n')for i in range(0, normal_vectors.__len__()):myfile.write('{:>6.3f} '.format(x[i]))myfile.write('{:>6.3f} '.format(y[i]))myfile.write('{:>6.3f} '.format(z[i]))myfile.write('{:>6.3f} '.format(theta_b[i]))myfile.write('{:>6.3f}\n'.format(theta_c[i]))myfile.close()
4、差分处理得到实际的速度和加速度
接着用速度差分查看实际的速度,函数实现是diff_vel_accel
def diff_vel_accel(axis_points, period=PERIOD):""":@func: 通过五轴插补点计算实际速度和实际加速度:param axis_points: 实际插补点:param period: 插补周期:return: 实际速度, 实际加速度"""delta_d = np.diff(axis_points[:,0:3], axis=0)dv = delta_d / periodreal_vels = np.sqrt(np.power(dv,2).sum(axis=1))delta_v = np.diff(dv, axis=0)da = delta_v / periodreal_accels = np.sqrt(np.power(da,2).sum(axis=1))# print(real_vels[0:5])# print(real_accels[0:5])# 将实际速度写入到文件real_velocities.txt中write2file('real_velocities.txt', real_vels, string = "real velocities")# 将实际加速度写入到文件real_accelerations.txt中write2file('real_accelerations.txt', real_accels, string="real accelerations")return real_vels, real_accels
5、加速度滑动平均
最后对实际的加速度进行滑动平均,与设定值进行比较,函数实现是sliding_average
def sliding_average(data, window_size):""":@func: 实现滑动平均滤波:param data: 滑动滤波的数据:param window_size: 滑动窗口大小"""filtered_data = []for i in range(len(data)):if i < window_size:filtered_data.append(sum(data[:i+1]) / (i+1))else:filtered_data.append(sum(data[i-window_size+1:i+1]) / window_size)write2file("filtered_accelerations.txt", filtered_data, string = "filtered accelerations")return filtered_data
6、实现的效果如图所示
其中,蓝色的点是原始路径点,红色的线是由插补点绘制的小线段轨迹。
三、Reference
1、《An optimal feedrate model and solution algorithm for a high-speed machine of small line blocks with look-ahead 》
相关文章:
【运动控制】CNC三轴小线段路径规划
CNC三轴小线段路径规划 文章目录CNC三轴小线段路径规划一、项目说明二、具体实现1、速度规划2、小线段插补3、运动学逆解刀轴插补点4、差分处理得到实际的速度和加速度5、加速度滑动平均6、实现的效果如图所示三、Reference写在前面,本文是作为一个练手小项目的总结…...
渗透测试之DNS域名信息探测实验
渗透测试之DNS域名信息探测实验实验目的一、实验原理1.1 域名1.2 .域名的构成1.3 域名的基本类型1.4 域名级别二、实验环境2.1 操作机器三、实验步骤1. 使用sp查询域名信息2. 进行探测实验实验目的 掌握使用nslookup进行DNS域名信息探测的原理和方式了解子域名查询网站 一、实…...
ASE140N04-ASEMI低压MOS管ASE140N04
编辑-Z ASE140N04在TO-220F封装里的静态漏极源导通电阻(RDS(ON))为4mΩ,是一款N沟道低压MOS管。ASE140N04的最大脉冲正向电流ISM为400A,零栅极电压漏极电流(IDSS)为1uA,其工作时耐温度范围为-55~175摄氏度。ASE140N04…...
Qt——QLineEdit
QLineEdit是一个单行文本编辑控件。 使用者可以通过很多函数,输入和编辑单行文本,比如撤销、恢复、剪切、粘贴以及拖放等。 通过改变QLineEdit的 echoMode() ,可以设置其属性,比如以密码的形式输入。 文本的长度可以由 maxLength(…...
前端-HTML-zxst
HTML HTML是超文本标记语言(HyperText Mark-up Language) CSS是层叠样式表(Cascading Style Sheets) JS,即JavaScript是一种具有函数优先的轻量级,解释型或即时编译型的编程语言 <!--doctype标签声明…...
终极方案,清理 docker 占用磁盘过大问题, 亲测有效!
背景 在笔者的工作测试环境中,使用过程中突然出现根磁盘快吃满了(docker也是使用的根池盘的/var/lib/docker), wtf ? 服务用不了? 当然网上找到了一些常规的清楚docker 日志文件 但是通过df -hT 查看到over…...
puzzle(1321)时间旅人
时间旅人 最强大脑同款项目。 每个指针会带动周围2圈指针一起带动,内圈8个旋转180度,外圈16个旋转90度,全部调整为朝上则胜利。 问题本质: 很明显,问题本质就是求每个格子的点击次数,最少为…...
活动预告 | 2023 Meet TVM 开年首聚,上海我们来啦!
内容一览:从去年 12 月延期至今的 TVM 线下聚会终于来了!首站地点我们选在了上海,并邀请到了 4 位讲师结合自己的工作实践,分享 TVM 相关的开发经验,期待与大家线下相聚~ 关键词:2023 Meet TVM 线下活动 自…...
CoreIDRAW 软件的强大功能及适用性
1.1 绘图功能CoreIDRAW 软件是一种特殊的设计软件和图形绘制软件,使用方便、功能强大,在网页效果、商业插画设计、海报广告设计、平面设计等各类行业中都得到广泛的应用,在服装设计行业中,也逐渐地投入使用。由于纺织服装行业在设…...
JavaScript Window History
在 Web 开发中,JavaScript Window History(浏览器窗口历史记录)是一个非常有用的对象,它提供了一个接口来与浏览器历史记录进行交互。JavaScript Window History 对象允许您访问当前会话的历史记录,以及在会话历史记录…...
2023年人力资源管理师报名和培训费用是多少
2023年考人力资源管理师各个地区的收费标准不同,报名费用在几百元左右,培训费上千,具体看各地区人力资源管理师考试报名要求。 12023人力资源管理师考试费用 人力资源管理师考试分为四个等级,各级别费用是不同的,一般来…...
2023-2-23 刷题情况
灌溉花园的最少水龙头数目 题目描述 在 x 轴上有一个一维的花园。花园长度为 n,从点 0 开始,到点 n 结束。 花园里总共有 n 1 个水龙头,分别位于 [0, 1, …, n] 。 给你一个整数 n 和一个长度为 n 1 的整数数组 ranges ,其中…...
数据归档,存储的完美储备军
数据爆炸性增长的同时,存储成为了大家首要担心的问题大家都希望自家数据保存20年、50年后仍完好无损但是,N年后的数据量已达到一个无法预测的峰值如此大量的数据在保存时极可能存在丢失、损坏等问题这时需要提前对数据进行“备份”、“归档”备份是对数据…...
ES6-11、基本全部语法
一,变量声明:let声明变量:1.变量不可重复声明,let star 罗志祥 let star 小猪结果报错2.块级作用域,{ let girl 周扬青 }在大括号内的都属于作用域内3.不存在变量提升4.不影响作用域链const声明常量:const SCHOOL …...
Spring Boot整合Thymeleaf和FreeMarker模板
虽然目前市场上多数的开发模式采用前后端分离的技术,视图层的技术在小一些的项目中还是非常有用的,所以一直也占有一席之地,如spring官方的spring.io等网站就是使用视图层技术实现的。 目前Spring Boot支持的较好的两个视图层模板引擎是Thyme…...
SQL的四种连接-左外连接、右外连接、内连接、全连接
SQL的四种连接-左外连接、右外连接、内连接、全连接 内连接inner join…on… / join…on… 展现出来的是共同的数据 select m.Province,S.Name from member m inner join ShippingArea s on m.Provinces.ShippingAreaID; 相当于:select m.Province,S.Name from m…...
“点工”的觉悟,5年时间从7K到24K的转变,我的测试道路历程~
2015年7月我从一个90%以上的人都不知道的二本院校毕业(新媒体专业),凭借自学的软件测试(点点点)在北京找到了一份月薪7000的工作,在当时其实还算不错,毕竟我的学校起点比较差,跟大部…...
【Web安全-MSF记录篇章一】
文章目录前言msfvenom生成远控木马基本系统命令webcam 摄像头命令常用的信息收集脚本注册表设置nc后门开启 rdp&添加用户获取哈希mimikatz抓取密码前言 最近打站,可以感觉到之前的学的渗透知识忘记很多。。。。。多用多看多练,简单回顾一下 msfven…...
配置Flutter开发环境
一、在Windows上搭建Flutter开发环境 1、去flutter官网下载其最新可用的安装包,下载地址:https://flutter.dev/docs/development/tools/sdk/releases 。 注意,Flutter的渠道版本一直在不断的更新,请以Flutter官网为准。 另外&…...
23年六级缓考
【【六级674】3月六级规划+许愿成功的小伙伴记得来还愿啦!!(四六级延期考2周冲刺计划)】https://www.bilibili.com/video/BV1nx4y1w7fz?vd_source=5475f4f6010a81c8e6d4789af8e1a20f 作文...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
【git】把本地更改提交远程新分支feature_g
创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...
10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...
在QWebEngineView上实现鼠标、触摸等事件捕获的解决方案
这个问题我看其他博主也写了,要么要会员、要么写的乱七八糟。这里我整理一下,把问题说清楚并且给出代码,拿去用就行,照着葫芦画瓢。 问题 在继承QWebEngineView后,重写mousePressEvent或event函数无法捕获鼠标按下事…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...
Chromium 136 编译指南 Windows篇:depot_tools 配置与源码获取(二)
引言 工欲善其事,必先利其器。在完成了 Visual Studio 2022 和 Windows SDK 的安装后,我们即将接触到 Chromium 开发生态中最核心的工具——depot_tools。这个由 Google 精心打造的工具集,就像是连接开发者与 Chromium 庞大代码库的智能桥梁…...
消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...
