没有合适的资源?快使用搜索试试~ 我知道了~
首页GRBL源代码分析.pdf
GRBL源代码分析.pdf
1星 需积分: 48 152 下载量 167 浏览量
更新于2023-03-03
评论 13
收藏 4.3MB PDF 举报
CNC源代码分析,讲解每个环节的原理以及算法处理,代码比较强悍精炼,可以学习商用均可,适合所有行业人员
资源详情
资源评论
资源推荐
GRBL源代码分析
原创地址:xufeixueren的博客的博客https://blog.csdn.net/xufeixueren/article/details/79663068
这段日子喜事连连,暂时把写博客的事情放下了,有时候想想好久没有写博客了,要不要写点啥呢。转念
一想,好像也没有啥值得写的心得体会,加上最近忙着结婚的事情,也就把写博客的事搁置了。周五本来
是要上班的,但是公司大厦供电系统维护,所以调休一天。借着安静的周五,加上最近一个多月研究GRBL
源代码的心得,写下这篇博客,供后来者参考学习。网上关于GRBL源代码分析的资料几乎找不到,这篇博
客里的内容大多是自己对源代码的理解,也有一部分是QQ群里的同行的心得。博客里没有写到,或者写的
不对的地方,欢迎大家留言共同探讨,共同进步。
GRBL的核心是带有梯形加减速过程的DDA直线插补算法的实现,整个GRBL源代码中包含了以下内容:
(1)串口中断接收上位机的指令,包括自定义的系统命令和G代码指令;
(2)串口指令解析,自定义的系统命令直接执行,G代码指令调用相关操作,这里只关注直线段、圆弧指
令的解析;
(3)圆弧拆分成直线段进行插补的方法;
(4)多条直线段之间转角速度优化的前瞻速度控制的方法;
(5)单条线段梯形加减速过程换算成定时器定时不同时间长短来输出脉冲的方法;
(6)限位条件的判断及轴自动归位的方法;
(7)其它spindle、coolant接口等,这些我也不知道干嘛用的,推测是给用户二次开发预留的接口。
下面详细介绍这些模块的实现细节,串口接收、指令解析这些很容易理解,就简单说说;spindle、coolant
这些还没有琢磨透,好像用到的情况也不多,不做描述;重点还是关注圆弧拆分线段、转角速度优化、线
段梯形加减速插补和自动归位的实现方法。
一、串口接收
串口配置成中断接收和中断发送模式,并创建了串口接收环形队列和串口发送环形队列,中断接收的数
据存放在串口接收环形队列里,串口需要发送的数据放到串口发送环形队列里。当串口产生中断时,如果
接收中断标志位置位,说明接收到数据,把数据读出放到接收队列,如果发送中断标志置位,说明发送寄
存器空,把发送队列里的数据写入发送寄存器里。这就是串口处理的流程,具体的实现难度不大,就不详
细解释源码了 。
二、串口接收到的数据解析
串口接收到的数据放在串口接收环形队列里,主程序里每次从接收队列里读出一个字节,以''或''为标
志截取一行完整的指令,如果指令以'$'开始,说明是自定义的系统指令,其它的是G代码指令。如果是系统
自定义指令,就调用uint8_t system_execute_line(char *line)函数,里面包含了一些读取软件版本信息、读取默
认配置参数信息和把外部设置的参数信息写入eeprom里,轴归位操作等功能。如果是G代码指令,就调用
uint8_t gc_execute_line(char *line)函数,里面包含了很多G代码的指令解析过程,由于重点放在研究直线插补
算法上,没有对G代码解析源码深入分析,这里只关注里面的执行圆弧和直线插补的代码,即只需要关心
void mc_line(float *target, float feed_rate, uint8_t invert_feed_rate)和void mc_arc(float *position, float *target, float
*offset, float radius, float feed_rate,uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)两个
函数即可。
三、圆弧拆分成多线段
GRBL中把圆弧拆分成多条逼近的直线段,然后对直线段进行插补,这种方法也就是俗称的把复杂曲线拆
分成多条逼近的直线的插补方法。圆弧拆分成直线段的方法,在void mc_arc(float *position, float *target, float
*offset, float radius, float feed_rate,uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)函数
里实现,下面对该函数进行详细介绍:
position,圆弧起始点位置坐标,为了后面解释方便,这里设为(x0,y0,z0)
target,圆弧终点坐标,这里设为(x1,y1,z1)
offset,圆心相对于起始点的偏移向量,这里设为(rx,ry,yz),那么圆心坐标为(x0+rx,y0+ry,z0+rz)
radius,圆弧半径长度
feed_rate,轴的进给速率
invert_feed_rate,进给速率含义标志位,这里默认为零,表示进给速率的单位是min/mm,即分钟/毫米
axis_0,圆弧所在平面的第一个轴,可以是x/y/z中任意一个
axis_1,圆弧所在平面的第二个轴,可以是x/y/z中任意一个
axis_linear,除了圆弧平面之外的第三个轴,即与圆弧平面垂直的轴
void mc_arc(float *position, float *target, float *offset, float radius, float feed_rate,
uint8_t invert_feed_rate, uint8_t axis_0, uint8_t axis_1, uint8_t axis_linear)
{
//圆弧所在平面的圆心坐标
float center_axis0 = position[axis_0] + offset[axis_0];
float center_axis1 = position[axis_1] + offset[axis_1];
//圆心指向圆弧起始点的向量坐标
float r_axis0 = -offset[axis_0];
float r_axis1 = -offset[axis_1];
//圆心指向圆弧终点的向量坐标
float rt_axis0 = target[axis_0] - center_axis0;
float rt_axis1 = target[axis_1] - center_axis1;
//计算圆心到圆弧起始点向量b(r_axis0 ,r_axis1)和圆心到圆弧终点向量c(rt_axis0 ,rt_axis1)的夹角的正切
值,注意夹角a的方向是起始点向量b逆时针转向终点向量c的角,这个在后面判断角度值符号时会用到。根
据向量夹角余弦公式,推出向量夹角正切公式,套入向量b和向量c的坐标,即可得出tana。下面公式中的
atan2是反正切函数,a=atan2(y,x),即角度a=y/x的正切值
float angular_travel = atan2(r_axis0*rt_axis1-r_axis1*rt_axis0, r_axis0*rt_axis0+r_axis1*rt_axis1);
if (gc_state.modal.motion == MOTION_MODE_CW_ARC) {
//如果圆弧顺时针移动,角度应该是负值,如果计算出的角度为正值,需要在计算出的角度基础上减
去2*pi(pi为圆周率)
if (angular_travel >= 0) { angular_travel -= 2*M_PI; }
} else {
//如果圆弧逆时针移动,角度应该是正值,如果计算出的角度为负值,需要在计算出的角度基础上加
上2*pi(pi为圆周率)
if (angular_travel <= 0) { angular_travel += 2*M_PI; }
}
//计算起点到终点的圆弧可以划分多少条小线段,计算方法:总共的弧长/每条小线段的长
度,angular_travel是圆弧的弧度,radius是圆弧的半径,那么它们的乘积angular_travel*radius就是圆弧的弧
长,再乘以0.5就是弧长的一半。settings.arc_tolerance是圆弧上两点之间连接的小线段到这段圆弧的最大距
离,即圆弧上的小线段到弧顶的最大距离,这里设为h,
,有图可知,假设线段|AB|长度的一半为k,那么有勾股定理可知,r*r=k*k+(r-h)*(r-h)。知道了r和h,那么
k*k=h*(2*r-h)。这样总共的小线段个数也就出来了,这就是下面这个公式的含义。
uint16_t segments = floor(fabs(0.5*angular_travel*radius)/
sqrt(settings.arc_tolerance*(2*radius - settings.arc_tolerance)) );
}
......
//这里是计算圆心与每条小线段所夹的角T,即上图中角AOB的余弦值和正弦值,由于角度很小,这里采
用了三角函数的泰勒级数展开公式计算cosT和sinT。cosT的二阶泰勒级数为1-T*T/2,sinT的三阶泰勒级数
为T-T*T*T/6,为了计算方便,cos_T 被放大了两倍,后面又乘上了0.5复原了。有cosT和sinT的泰勒级数公
式,cosT被放大了两倍,可以推出sinT=T*(4+cosT)/6,即下面计算sinT的公式的来源。
float cos_T = 2.0 - theta_per_segment*theta_per_segment;
float sin_T = theta_per_segment*0.16666667*(cos_T + 4.0);
cos_T *= 0.5;
//循环累加每一条小线段,圆的极坐标公式为x=r*cosa,y=r*sina,假设当前线段的起始坐标为(rcosa,rsina),
下一条线段比当前线段移动的角度已知为T,那么下一条线段的起始坐标为(rcos(a+T),rsin(a+T)),运算得到
rcos(a+T)=r*cosa*cosT-r*sina*sinT,rsin(a+T)=r*sina*cosT+r*cosa*sinT。由于我们知道当前线段的坐标为
(r_axis0,r_axis1),又知道sinT和cosT的值,下一条线段的起始坐标根据公式可立即求出。
for (i = 1; i<segments; i++) {
if (count < N_ARC_CORRECTION) {
//这就是用上述公式求下一条线段的起始坐标的具体计算。当累计计算线段数超过
N_ARC_CORRECTION个数时,要调用N_ARC_CORRECTION个线段总共转动的角度来计算最终的坐标移
动值,这样可以消除因每次使用sinT、cosT的近似泰勒值运算的累积误差
r_axisi = r_axis0*sin_T + r_axis1*cos_T;
r_axis0 = r_axis0*cos_T - r_axis1*sin_T;
r_axis1 = r_axisi;
count++;
} else {
//调用N_ARC_CORRECTION个线段总共转动的角度来计算最终的坐标移动值
cos_Ti = cos(i*theta_per_segment);
sin_Ti = sin(i*theta_per_segment);
r_axis0 = -offset[axis_0]*cos_Ti + offset[axis_1]*sin_Ti;
r_axis1 = -offset[axis_0]*sin_Ti - offset[axis_1]*cos_Ti;
count = 0;
}
// 计算出下一条线段的起始坐标,也就是当前线段的终点坐标,前面已知当前线段的起始坐标,这样就
可以把线段的坐标传递给直线插补函数mc_line进行线段插补了
position[axis_0] = center_axis0 + r_axis0;
position[axis_1] = center_axis1 + r_axis1;
position[axis_linear] += linear_per_segment;
//线段插补
mc_line(position, feed_rate, invert_feed_rate);
......
}
}
//把圆弧终点作为最后一条线段的终点坐标进行直线插补,确保圆弧上所有的点包含进了直线里
mc_line(target, feed_rate, invert_feed_rate);
剩余11页未读,继续阅读
qq_31268507
- 粉丝: 1
- 资源: 6
上传资源 快速赚钱
- 我的内容管理 收起
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
会员权益专享
最新资源
- 数据结构1800题含完整答案详解.doc
- 医疗企业薪酬系统设计与管理方案.pptx
- 界面与表面技术界面理论与表面技术要点PPT学习教案.pptx
- Java集合排序及java集合类详解(Collection、List、Map、Set)讲解.pdf
- 网页浏览器的开发 (2).pdf
- 路由器原理与设计讲稿6-交换网络.pptx
- 火电厂锅炉过热汽温控制系统设计.doc
- 企业识别CIS系统手册[收集].pdf
- 物业管理基础知识.pptx
- 第4章财务预测.pptx
- 《集成电路工艺设计及器件特性分析》——实验教学计算机仿真系.pptx
- 局域网内共享文件提示没有访问权限的问题借鉴.pdf
- 第5章网络营销策略.pptx
- 固井质量测井原理PPT教案.pptx
- 毕业实习总结6篇.doc
- UGNX建模基础篇草图模块PPT学习教案.pptx
资源上传下载、课程学习等过程中有任何疑问或建议,欢迎提出宝贵意见哦~我们会及时处理!
点击此处反馈
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功
评论3