搜索
bottom↓
回复: 181

GRBL源码简单分析[源码+图片+xmind文档]

  [复制链接]

出40入42汤圆

发表于 2018-5-10 12:03:41 | 显示全部楼层 |阅读模式
本帖最后由 落叶知秋 于 2018-5-10 12:05 编辑

声明

  好久没发技术贴,刚好前一阵子才把文档写完,就发到论坛上来,希望对坛友有用。
  去年就开始在GitHub下载了源码开始看,但断断续续的看了将近一年才模模糊糊的看完!
  也一边看一边做文档记录,用的XMind做记录,由于免费版,导不出来Word或者PDF,
  只能导图片了,将就一下。

说明

  文档内容是看代码过程中的理解,肯定有理解不透彻的地方,如果有坛友能指出,提前感谢。
  由于软件限制和懒,文档内容以图片形式展示
  附件提供楼主看代码的GitHub版本的源代码和网络上找的stm32移植版本的源代码,没有实际上机录验证过,此处仅讨论代码

简介
  GRBL是基于Avr单片机的一个应用于3D打印机上的运动控制项目,由于楼主不会Avr,就不发在Avr版块,但不影响阅读源码
  注意:个人认为GRBL是个简易型的数控系统,但仅此而已,其中有可以学习借鉴的地方,运动控制方面的。
  GRBL里面有G代码解析、运动前瞻,T型加减速、直线插补、两轴圆弧插补等功能。

文档内容











附件





编辑原因:添加了XMind源文档文件

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入147汤圆

发表于 2018-5-10 12:46:57 | 显示全部楼层
楼主很用心啊

出0入90汤圆

发表于 2018-5-10 13:13:41 | 显示全部楼层
挺好的。如果做3D打印,可以去下载marlin,这个里面都给你做好了

出40入42汤圆

 楼主| 发表于 2018-5-10 13:42:53 | 显示全部楼层
honami520 发表于 2018-5-10 13:13
挺好的。如果做3D打印,可以去下载marlin,这个里面都给你做好了

marlin也是听说过的,里面也是引用了GRBL的代码,只不过marlin是专攻3D打印方面,grbl还可以用来做小型雕刻机

出0入0汤圆

发表于 2018-5-10 13:47:43 | 显示全部楼层
3D打印机

出0入0汤圆

发表于 2018-5-10 13:54:56 | 显示全部楼层
之前看过,没看明白,采用DDA算法按理会造成脉冲不平滑啊,不平滑很容易造成电机失步,这里面是怎么解决的?

出40入42汤圆

 楼主| 发表于 2018-5-10 14:02:52 | 显示全部楼层
采用DDA算法按理会造成脉冲不平滑啊,不平滑很容易造成电机失步


不太明白你的意思?

出0入0汤圆

发表于 2018-5-10 14:08:24 | 显示全部楼层
感谢楼主的详细说明

出0入0汤圆

发表于 2018-5-10 14:09:12 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2018-5-10 14:10:06 | 显示全部楼层
楼主好人;

出0入0汤圆

发表于 2018-5-10 14:19:37 | 显示全部楼层
落叶知秋 发表于 2018-5-10 14:02
不太明白你的意思?

比如3hz的定时器基频,要输出2hz脉冲,采用dda算法之后:
主时基: 101010101010
输出     :   101000101000

一个10代表一个高低电平,这样输出不是平滑的

出40入42汤圆

 楼主| 发表于 2018-5-10 14:27:38 | 显示全部楼层
liurangzhou 发表于 2018-5-10 14:19
比如3hz的定时器基频,要输出2hz脉冲,采用dda算法之后:
主时基: 101010101010
输出     :   101000101 ...

3Hz的定时器基频,输出2Hz脉冲,平滑的波形应该是怎样的?能请你列一下吗?

出0入0汤圆

发表于 2018-5-10 14:30:35 | 显示全部楼层
落叶知秋 发表于 2018-5-10 14:27
3Hz的定时器基频,输出2Hz脉冲,平滑的波形应该是怎样的?能请你列一下吗? ...

我用步进电机时是一个定时器管一个电机,每一步去计算下一步的延时,然后改变时基,所以没搞懂它这种用一个固定时基的怎么输出平滑脉冲

出0入0汤圆

发表于 2018-5-10 14:33:08 | 显示全部楼层
楼主厉害了,学习一下

出40入42汤圆

 楼主| 发表于 2018-5-10 14:45:41 | 显示全部楼层
liurangzhou 发表于 2018-5-10 14:30
我用步进电机时是一个定时器管一个电机,每一步去计算下一步的延时,然后改变时基,所以没搞懂它这种用一 ...

grbl脉冲输出不是固定时基的,定时器频率会随运动段变化的

出0入0汤圆

发表于 2018-5-10 14:48:48 | 显示全部楼层
好东西,学习一下

出0入119汤圆

发表于 2018-5-10 15:03:41 | 显示全部楼层
大赞!谢谢分享!

出0入0汤圆

发表于 2018-5-10 15:04:24 | 显示全部楼层
落叶知秋 发表于 2018-5-10 14:45
grbl脉冲输出不是固定时基的,定时器频率会随运动段变化的

多谢,看来我想多了

出0入0汤圆

发表于 2018-5-10 15:28:30 | 显示全部楼层
佩服,有毅力,看完竟然还做了笔记!

出0入0汤圆

发表于 2018-5-10 16:04:04 | 显示全部楼层
谢谢楼主!有空研究一下,之前下载了源代码,一直没有时间看。

出0入0汤圆

发表于 2018-5-10 16:19:47 | 显示全部楼层
谢谢楼主的分享

出0入0汤圆

发表于 2018-5-10 17:09:04 | 显示全部楼层
楼主做了不少工作呀

出0入0汤圆

发表于 2018-5-10 17:12:15 | 显示全部楼层
tinyg2似乎是一个固定的时基,楼主有看过吗

出40入42汤圆

 楼主| 发表于 2018-5-10 17:39:10 | 显示全部楼层
liurangzhou 发表于 2018-5-10 17:12
tinyg2似乎是一个固定的时基,楼主有看过吗

听过TinyG,没有看过源码。

因为GRBL被引用的多,去年就决定先看这个,但工作原因断断续续的看,所以才有了这文档

出0入0汤圆

发表于 2018-5-10 18:53:35 | 显示全部楼层
楼主可以重点讲一下Bresenham”直线算法吗?
怎么理解的
这个GRBL源码其他地方我都看懂了,就是这里一直不是很好的理解

出0入0汤圆

发表于 2018-5-10 19:02:12 来自手机 | 显示全部楼层
赞一个,一直想作这个工作,拖延症严重

出40入42汤圆

 楼主| 发表于 2018-5-10 20:19:49 | 显示全部楼层
王涛 发表于 2018-5-10 18:53
楼主可以重点讲一下Bresenham”直线算法吗?
怎么理解的
这个GRBL源码其他地方我都看懂了,就是这里一直不 ...

Bresenham算法就是一种改进的DDA算法,最大的特点就是计算过程不带浮点数,全用整型数

其实在GRBL里面Bresenham算法的应用就体现在stepper.c的T1中断ISR里面的脉冲输出条件判断
如果细心的话,可以留意到同一个文件的st_prep_buffer()函数里面有这样一段代码
  1. for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = (pl_block->steps[idx] << 1); }
  2.           st_prep_block->step_event_count = (pl_block->step_event_count << 1);
复制代码

其实就是把各轴的单次累加比例和脉冲输出的步数阈值都*2而已,然后在ISR里面,有如下代码
  1. // Initialize Bresenham line and distance counters
  2.         st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
复制代码

就是在取初始数据时,把计数数值降到之前计算的1/2,最后判断的代码是
  1. // Execute step displacement profile by Bresenham line algorithm
  2.   #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
  3.     st.counter_x += st.steps[X_AXIS];
  4.   #else
  5.     st.counter_x += st.exec_block->steps[X_AXIS];
  6.   #endif
  7.   if (st.counter_x > st.exec_block->step_event_count) {...}
复制代码

这三处加起来就是Bresenham算法的所有了,细想一下的话可以发现,不就是下面这个图片嘛

当某个轴的计算counter大于翻转脉冲阈值的1/2时,就输出,否则就不输出,继续累加对应的比例

由于是脉冲计算,所以一般是不存在浮点输出的,Bresenham算法就是为了按照上面图片的方式取“非主要步进”轴的点
不知道这样能不能说清楚?

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2018-5-11 07:42:29 | 显示全部楼层
顶一个

出0入0汤圆

发表于 2018-5-11 08:32:28 | 显示全部楼层
楼主有心人啊!

出0入0汤圆

发表于 2018-5-11 08:32:32 | 显示全部楼层
佩服楼主,学习一下!

出0入0汤圆

发表于 2018-5-11 08:45:35 | 显示全部楼层
加减速是怎么进行的?分段?还是每个脉冲都更新时基

出40入42汤圆

 楼主| 发表于 2018-5-11 11:18:08 | 显示全部楼层
liurangzhou 发表于 2018-5-11 08:45
加减速是怎么进行的?分段?还是每个脉冲都更新时基

加减速部分文档里面有稍微提及了一下,没有细述
一是因为加减速部分跟前瞻部分是有些关联的,比如前后运动段之前的速度限制和衔接,入口初速度和出口结束速度之类的
二是因为懒得写那么多,看起来就臃肿
既然坛友有意交流这部分,那我再整理一下吧

这里先说一下,T型加减速的具体计算是在stepper.c里面的st_prep_buffer()函数里面
待我整理一下之后再回复本帖把

出0入0汤圆

发表于 2018-5-11 11:36:21 | 显示全部楼层
挺详细的 楼主真用心  谢谢

出0入4汤圆

发表于 2018-5-11 11:50:19 | 显示全部楼层
之前也有分析过源代码,谢谢楼主资料,不知有没有上位机应用方面的知识可介绍?

出0入134汤圆

发表于 2018-5-11 12:27:35 | 显示全部楼层
这学习笔记真棒!

出40入42汤圆

 楼主| 发表于 2018-5-11 13:39:14 | 显示全部楼层
PICTURE 发表于 2018-5-11 11:50
之前也有分析过源代码,谢谢楼主资料,不知有没有上位机应用方面的知识可介绍? ...

GRBL有对应的通信交互协议,但没有项目直接配套的上位机,但有不少人为其开发了对应的上位机,也有开源的
我没有研究过GRBL配套的上位机,只是知道其有对应的通信机制。

出40入42汤圆

 楼主| 发表于 2018-5-11 16:30:14 | 显示全部楼层
RAMILE 发表于 2018-5-11 15:33
xmind 文件压缩包损坏

撸主重新下载并解压,文件无损坏。重新下载试下吧

出40入42汤圆

 楼主| 发表于 2018-5-11 16:31:39 | 显示全部楼层
liurangzhou 发表于 2018-5-11 08:45
加减速是怎么进行的?分段?还是每个脉冲都更新时基

结构体说明
GRBL里面的速度规划是带运动段前瞻的,所以有规划运动段数据和微小运动段的区分
这里的“规划运动段”对应的数据结构是plan_block_t,前瞻和加减速会使用到,也就是通过解析G代码后出来的直接直线数据或是圆弧插补出来的拟合直线数据
“微小运动段”对应的数据结构是segment_t,加减速的终端数据持有者,也就是plan_block_t数据经过了加减速后的计算数据
plan_block_t的数据还有一个临时的数据缓冲区,st_block_buffer,作用如上所述,其中存储的是脉冲发生ISR里面需要用到的数据
stepper.c里面有个静态变量static st_prep_t prep,这个变量是plan_block_t数据转换为segment_t数据时的一个缓冲,即从plan_block_t里面提取相关数据,然后生成新的segment_t数据

加减速处理
加减速处理在stepper.c的st_prep_buffer()函数里,流程为:
1.segment_t缓冲区有空余位置才会进行加减速数据生成,否则退出函数;有接收到停止运动指令,同样停止生成数据

2.从规划器的plan_block_t队列里面找到当前要进行分解的运动段,此处会分为“系统运动段”和“普通运动段”,就是一般操作和G代码解析的区分

3.判断prep里面的重新计算标志是否有效,有效则重新计算当前的运动段分解
什么时候会需要重新计算呢?一般是调整了速度修调(Ratio)之后,会对未被执行的运动段重新进行计算

4.如果不需要重新计算了,则直接把plan_block_t里面对应的Bresenham算法需要用到的脉冲输出阈值和总步数,记录到st_block_buffer里面

5.此时开始根据plan_block_t里面的数据和系统当前状态来确定加减速的状态,这里有好几个条件分支,其中牵扯到前瞻计算的初始速度和终止速度,以及系统的速度修调率。
  5.1如果检测到系统有进给保持(HOLD)状态指令,则直接进入全减速状态(RAMP_DECEL)
  5.2如果速度修调被降低了,则判断当前运动段的距离够不够减速到对应的终止速度,不够则进入全减速状态(RAMP_DECEL),如果是足够的,则进入半减速状态(RAMP_DECEL_OVERRIDE),如果是进入了规划的减速段,则也进入全减速状态(RAMP_DECEL)
  5.3如果是速度修调被升高了,或是一开始进入加速运动,则要进入加速状态(RAMP_ACCEL)
  5.4如果是加速到了目标速度,则应该进入匀速状态(RAMP_CRUISE)
  5.5其中,在加速状态的时候,可以计算出要进行梯形加减速还是三角形加减速

6.在确定了当前运动段的加减速状态后,则根据该状态进行segment_t微小运动段的分解计算,分解计算是依靠一个固定的时基DT_SEGMENT来进行的
注意,该固定时基只在计算segment_t数据时使用,跟脉冲发生的时间没有直接关系

7.分解微小运动段的方法是:根据加减速状态和pl_block的速率,算出在DT_SEGMENT单元时间内的进给量(即应输出的脉冲量)
  7.1半减速处理(RAMP_DECEL_OVERRIDE):首先计算减速到目标速度的时间,然后算出减速状态下的进给,再把加减速状态设置为匀速状态(RAMP_CRUISE),剩下的时间会在循环条件里再次进入匀速状态计算进给
  7.2全加速处理(RAMP_ACCEL):计算全加速下,是否会到达运动段的加速段目标位置,如果还可以加速,则继续处于全加速状态,否则看加减速是梯形条件还是三角形条件,如果是梯形则进入匀速状态(RAMP_CRUISE),如果是三角形则进入全减速状态(RAMP_DECEL)
  7.3匀速处理(RAMP_CRUISE):计算匀速段是否结束了,是则进入全减速状态(RAMP_DECEL),否则保持该状态;另外,如果匀速状态在DT_SEGMENT时间内就结束了,同样地,把剩余时间在全减速状态再计算一次进给量
  7.4全减速处理(RAMP_DECEL):如果剩余的距离还可以继续减速,则保持该状态,然后计算出该次的进给量;如果剩余的距离可以在该次减速中完成,则要算出完成减速的时间量和进给量,然后退出该运动段pl_block的加减速
  7.5另外,加减速处理中有“最小步”的输出要求,如果在1个DT_SEGMENT内,没有达到“最小步”的要求,则继续累加1个DT_SEGMENT的时间,知道满足“最小步”输出要求,才退出步骤7

8.要注意的是,步骤5是segment_t根据pl_block_t的状态初始化自己数据的流程,里面有步骤7计算时需要用到的初始数据
步骤7是计算一个完整segment_t数据的流程,里面有输出脉冲的条件数据,比如在多长的时间内输出多少个脉冲
然后就是初始化T1定时器计数,并且触发ISR,在ISR中计算脉冲输出条件

9.另外,1个pl_block_t可以分解成很多个segment_t,如果segment_t的缓冲满了,pl_block_t还没有结束,则暂停生成segment_t,等缓冲区空闲了再计算,否则会一直生成segment_t;
相反,也有可能1个pl_block_t就对应1个segment_t,且segment_t可能会在DT_SEGMENT内就完成了pl_block_t的目标距离,时间是以实际计算的为准

10.脉冲输出的时基,即T1定时器的溢出中断计数,是根据segment_t的需要输出脉冲数和segment_t使用的时间(不一定是DT_SEGMENT)来直接计算的。在单个segment_t的脉冲输出期间,T1的溢出中断时间间隔一致,但一般不同的segment_t会有不同的T1时间间隔

出0入0汤圆

发表于 2018-5-11 17:05:01 | 显示全部楼层
落叶知秋 发表于 2018-5-10 20:19
Bresenham算法就是一种改进的DDA算法,最大的特点就是计算过程不带浮点数,全用整型数

其实在GRBL里面Br ...

非常感谢楼主的回复

pl_block->step_event_count 是完成这个block所需走的步数,就是steps[x], steps[y], steps[z], 的最大值,即是三个轴中的最长轴。如果某个轴是最长轴,意味着这个轴的步进电机每个中断都有脉冲输出。
其他两个轴的输出如何判断的这里没有理解。

出40入42汤圆

 楼主| 发表于 2018-5-11 18:00:43 | 显示全部楼层
王涛 发表于 2018-5-11 17:05
非常感谢楼主的回复

pl_block->step_event_count 是完成这个block所需走的步数,就是steps[x], steps[y] ...

这个问题是属于DDA算法的范畴了,这样说吧:
假设从P0点(0,0,0)插补到P1点(2,4,8),坐标分别对应X,Y,Z,则最长轴是Z,每个周期应该Z步数增加1个单位,总共需要8个周期
再假设event_step = 8,step_x = 2,step_y = 4,step_z = 8,cnt_x = cnt_y = cnt_z = 0;
要Z每个周期都输出脉冲,则有:
cnt_x += step_x;
if (cnt_x >= event_step) {输出X脉冲,cnt_x -= event_step} //这里会在第4和第8个周期分别输出脉冲
cnt_y += step_y;
if (cnt_y >= event_step) {输出Y脉冲,cnt_y -= event_step} //这里会在第2/4/6/8个周期分别输出脉冲
cnt_z += step_z;
if (cnt_z >= event_step) {输出Z脉冲,cnt_z -= event_step} //每个周期都输出脉冲
你按照每个周期来算一下就知道,X/Y/Z会按照插值法来输出脉冲了,这个就是DDA的一个例子

出0入0汤圆

发表于 2018-5-11 18:07:19 | 显示全部楼层
本帖最后由 王涛 于 2018-5-11 18:09 编辑
落叶知秋 发表于 2018-5-11 18:00
这个问题是属于DDA算法的范畴了,这样说吧:
假设从P0点(0,0,0)插补到P1点(2,4,8),坐标分别对应X,Y,Z, ...



谢谢,分析。
下面是Bresenham's line and circle algorithm数学模型
可是看了半天代码分析和这个模型就是关联不起来。
https://www.cs.helsinki.fi/group/goa/mallinnus/lines/bresenh.html


(x, y +ε)的下一个点为(x, y + ε + m),这里ε为累加误差。

可以看出,当ε+m < 0.5时,绘制(x + 1, y)点,否则绘制(x + 1, y + 1)点。

每次绘制后,ε将更新为新值:
            ε = ε + m ,如果(ε + m) < 0.5
            ε = ε + m – 1, 其他情况

这里判别条件的  (ε + m) < 0.5

    即 2*(ε + m) < 1

    即 2*(ε + dy / dx) < 1  (由于m = dy / dx)

    即 2*(ε* dx + dy) < dx (同乘以dx)

    令ξ = ε*dx 可得

            ξ = ξ + dy, 如果2*(ξ + dy) < dx
            ξ = ξ + dy – dx, 其他情况
    可以看到,此时运算已经全变为整数了。以下为算法的伪代码:
            ξ ← 0, y ← y1
            For x ← x1 to x2 do
                Plot Point at (x, y)
                If (2(ξ + dy) < dx)
                    ξ ←ξ + dy
                Else
                    y ← y + 1,ξ ←ξ + dy – dx
                End If
            End For

出40入42汤圆

 楼主| 发表于 2018-5-11 19:33:44 | 显示全部楼层
王涛 发表于 2018-5-11 18:07
谢谢,分析。
下面是Bresenham's line and circle algorithm数学模型
可是看了半天代码分析和这个模型就 ...


其实也没有很难理解,把你提到的公式里面的字母换一下就好结合GRBL的代码理解了

  1.             ξ ← 0, y ← y1
  2.             For x ← x1 to x2 do
  3.                 Plot Point at (x, y)
  4.                 If (2(ξ + dy) < dx)
  5.                     ξ ←ξ + dy
  6.                 Else
  7.                     y ← y + 1,ξ ←ξ + dy – dx
  8.                 End If
  9.             End For
复制代码

把上面代码里的ξ看做非主步进轴的计数值,比如X为主步进轴,dx是step_x,dy是step_y,那么event_step = max(step_x,step_y)
然后ξ是cnt_y,cnt_x就不用了,因为每次cnt_x都等于event_step,即X轴每次都输出脉冲
这样把上面的代码翻译一下

  1.             For x ← x1 to x2 do //X主步进轴,每次都输出1个脉冲
  2.                 Plot Point at (x, y) //打印函数,此处无意义
  3.                 If (2(cnt_y + step_y) < event_step)
  4.                     cnt_y += step_y
  5.                 Else
  6.                     y ← y + 1 //输出1个脉冲
  7.                    cnt_y  += step_y – event_step
  8.                 End If
  9.             End For
复制代码

是不是跟GRBL的T1的ISR函数代码片段差不多?

出0入0汤圆

发表于 2018-5-11 22:25:54 | 显示全部楼层
落叶知秋 发表于 2018-5-11 16:31
结构体说明
GRBL里面的速度规划是带运动段前瞻的,所以有规划运动段数据和微小运动段的区分
这里的“规划 ...

非常感谢楼主的详细解答,也就是说加减速是以DT_SEGMENT单元时间进行逼近,在这个单元时间内速度是一定的,加速过程都相当于走楼梯一步一步上去,而不是每一个脉冲输出之后即更新一个时基

出0入0汤圆

发表于 2018-5-11 22:44:42 来自手机 | 显示全部楼层
不错,好好研究下。

出0入0汤圆

发表于 2018-5-11 22:50:01 | 显示全部楼层
不懂,顶下

出0入0汤圆

发表于 2018-5-12 06:54:22 来自手机 | 显示全部楼层
楼主很细心,也很乐于给大家分享自己的心得。这个帖子记下了。

出5入0汤圆

发表于 2018-5-12 07:39:57 来自手机 | 显示全部楼层
不懂,顶下楼主细心热心

出40入42汤圆

 楼主| 发表于 2018-5-12 08:33:42 | 显示全部楼层
liurangzhou 发表于 2018-5-11 22:25
非常感谢楼主的详细解答,也就是说加减速是以DT_SEGMENT单元时间进行逼近,在这个单元时间内速度是一定的 ...

我看代码觉得差不多这个意思,但不一定是正确的哦

出0入0汤圆

发表于 2018-5-12 09:33:15 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2018-5-12 12:38:53 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2018-5-12 15:10:14 | 显示全部楼层
谢楼主,需要仔细看

出0入0汤圆

发表于 2018-5-12 15:54:27 | 显示全部楼层
不错,顶一下!

出0入0汤圆

发表于 2018-5-12 16:03:48 | 显示全部楼层
谢谢楼主分享,感觉有点复杂,慢慢看看。

出0入0汤圆

发表于 2018-5-12 18:41:57 | 显示全部楼层
感谢分享,顶一下

出0入0汤圆

发表于 2018-5-12 22:35:58 | 显示全部楼层
谢谢分享

出0入0汤圆

发表于 2018-5-13 22:17:14 | 显示全部楼层
谢谢分享!

出0入0汤圆

发表于 2018-5-13 22:32:52 来自手机 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2018-5-13 22:42:03 | 显示全部楼层
谢谢分享~

出0入0汤圆

发表于 2018-5-14 08:26:15 | 显示全部楼层
楼主,你用的是什么软件,生成的文件目录树?很直观逻辑很清晰

出40入42汤圆

 楼主| 发表于 2018-5-14 08:35:04 | 显示全部楼层
lichaoming520 发表于 2018-5-14 08:26
楼主,你用的是什么软件,生成的文件目录树?很直观逻辑很清晰

楼主位有说明,用XMind,一款思维导图软件

出0入0汤圆

发表于 2018-5-14 08:51:55 | 显示全部楼层
感谢分享

出0入0汤圆

发表于 2018-5-14 13:26:17 | 显示全部楼层
阅读代码,理解框架,不错

出0入0汤圆

发表于 2018-5-14 14:43:10 | 显示全部楼层
落叶知秋 发表于 2018-5-10 20:19
Bresenham算法就是一种改进的DDA算法,最大的特点就是计算过程不带浮点数,全用整型数

其实在GRBL里面Br ...

多谢楼主的分析,有点明白了。
可是下面的代码有什么意思呢。为什么要先扩大2倍后有缩小2倍?

for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = (pl_block->steps[idx] << 1); }
          st_prep_block->step_event_count = (pl_block->step_event_count << 1);


其实就是把各轴的单次累加比例和脉冲输出的步数阈值都*2而已,然后在ISR里面,有如下代码
// Initialize Bresenham line and distance counters
        st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);


就是在取初始数据时,把计数数值降到之前计算的1/2,最后判断的代码是

出40入42汤圆

 楼主| 发表于 2018-5-14 14:46:49 | 显示全部楼层
王涛 发表于 2018-5-14 14:43
多谢楼主的分析,有点明白了。
可是下面的代码有什么意思呢。为什么要先扩大2倍后有缩小2倍?

因为GRBL里面的counter是无符号数值,所以在实际代码中是做了1/2 event_step的初值偏移和step_axis与event_step的2倍放大的,为了不出现负值运算
实际代码的意思是跟上面的伪代码差不多的

出0入0汤圆

发表于 2018-5-14 15:08:11 | 显示全部楼层
楼主有心了,谢谢分享

出0入0汤圆

发表于 2018-5-14 16:03:24 | 显示全部楼层
落叶知秋 发表于 2018-5-14 14:46
因为GRBL里面的counter是无符号数值,所以在实际代码中是做了1/2 event_step的初值偏移和step_axis与even ...


源代码中ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING 自适应多轴平滑步进(AMASS)是被定义过的的了,也就是step_event_count被扩大了 st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL;多倍,
而后又 st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);然后在缩小    st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level;倍。
实际上是这里只是赋值 st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1)为什么要这样做


#ifndef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
          for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = (pl_block->steps[idx] << 1); }
          st_prep_block->step_event_count = (pl_block->step_event_count << 1);
        #else
          // With AMASS enabled, simply bit-shift multiply all Bresenham data by the max AMASS
          // level, such that we never divide beyond the original data anywhere in the algorithm.
          // If the original data is divided, we can lose a step from integer roundoff.
          for (idx=0; idx<N_AXIS; idx++) { st_prep_block->steps[idx] = pl_block->steps[idx] << MAX_AMASS_LEVEL; }
          st_prep_block->step_event_count = pl_block->step_event_count << MAX_AMASS_LEVEL;
        #endif

// Initialize Bresenham line and distance counters
        st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
      }
      st.dir_outbits = st.exec_block->direction_bits ^ dir_port_invert_mask;

      #ifdef ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING
        // With AMASS enabled, adjust Bresenham axis increment counters according to AMASS level.
        st.steps[X_AXIS] = st.exec_block->steps[X_AXIS] >> st.exec_segment->amass_level;
        st.steps[Y_AXIS] = st.exec_block->steps[Y_AXIS] >> st.exec_segment->amass_level;
        st.steps[Z_AXIS] = st.exec_block->steps[Z_AXIS] >> st.exec_segment->amass_level;
      #endif

出40入42汤圆

 楼主| 发表于 2018-5-14 16:10:15 | 显示全部楼层
王涛 发表于 2018-5-14 16:03
源代码中ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING 自适应多轴平滑步进(AMASS)是被定义过的的了,也就是ste ...
st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1)为什么要这样做

这个是之前说过的,为了去掉负数运算

ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING 自适应多轴平滑步进(AMASS)

这个请看楼主位最后一张图片的右下角部分

出0入0汤圆

发表于 2018-5-14 16:58:15 | 显示全部楼层
落叶知秋 发表于 2018-5-14 16:10
这个是之前说过的,为了去掉负数运算

ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING 自适应多轴平滑步进(AMASS)
这里是为了在低速时加快中断的处理速度这里我理解。我想问的是 st.counter_x = st.counter_y = st.counter_z 赋值为0行不行。 st.counter_x = st.counter_y = st.counter_z =0;

出40入42汤圆

 楼主| 发表于 2018-5-14 17:24:37 | 显示全部楼层
王涛 发表于 2018-5-14 16:58
ADAPTIVE_MULTI_AXIS_STEP_SMOOTHING 自适应多轴平滑步进(AMASS)
这里是为了在低速时加快中断的处理速 ...

不行。。。字数补丁

出0入4汤圆

发表于 2018-5-15 10:34:36 | 显示全部楼层
本帖最后由 jetta2014 于 2018-5-15 10:48 编辑

刚准备玩下GRBL,就看到楼主的大作了,先谢啦!
补充一下,grbl 1.1f XMind文档.rar无法打开!

出0入0汤圆

发表于 2018-5-15 14:20:34 | 显示全部楼层
这个分析很强,图文并茂

出0入0汤圆

发表于 2018-5-17 09:30:43 | 显示全部楼层
这个楼主确实是花了精力的!全顶起来

出0入0汤圆

发表于 2018-5-17 17:06:12 | 显示全部楼层
很用心,学习了。多谢分享
mark一下:3D打印机流程图

出0入0汤圆

发表于 2018-5-17 17:52:39 | 显示全部楼层
顶楼主

出0入0汤圆

发表于 2018-5-17 18:11:54 | 显示全部楼层
这个必须赞

出0入0汤圆

发表于 2018-5-18 00:04:44 来自手机 | 显示全部楼层
楼主确实是花了精力的,也非常有心,赞!

出0入0汤圆

发表于 2018-5-18 05:24:03 | 显示全部楼层
顶一个,楼主很有心花了不少精力!

出0入0汤圆

发表于 2018-5-18 08:15:58 | 显示全部楼层
之前看过一段时间,只是用于应用,没去理解底层那么深,楼主很用心。顶~~~

出40入42汤圆

 楼主| 发表于 2018-5-18 12:02:18 来自手机 | 显示全部楼层
jetta2014 发表于 2018-5-15 10:34
刚准备玩下GRBL,就看到楼主的大作了,先谢啦!
补充一下,grbl 1.1f XMind文档.rar无法打开! ...

重新下载试试?论坛只能上传压缩文件,源文件上传不了。还不行的话,我之后再重新上传一个

出0入0汤圆

发表于 2018-5-18 14:32:04 | 显示全部楼层
做的好,做的好,做的好,做的好,

出0入0汤圆

发表于 2018-5-19 12:01:19 | 显示全部楼层
本帖最后由 王涛 于 2018-5-19 12:29 编辑
落叶知秋 发表于 2018-5-14 17:24
不行。。。字数补丁




楼主你好这是一个关于marlin源码bresenham算法光栅化的画直线算法的分析。这个算法的误差E只和dx和dy有关系。

grbl1.1源代码中
        //Initialize Bresenham line and distance counters
        st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
       我们这里假定X轴是最长轴恒为真,也就是么个每个中断都有脉冲输出,
       那么Y轴的判断就是根据
       ξ‘’+dy-0.5step_event_count >0

       这里 ξ‘’=0.5dX//  ξ‘’   就是st.counter_y  等于st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);

      st.counter_y=0.5st.exec_block->step_event_count//(st.exec_block->step_event_count >> 1);
      
      st.counter_y += st.steps[Y_AXIS];
      
     if (st.counter_y > st.exec_block->step_event_count) {
    st.step_outbits |= (1<<Y_STEP_BIT);
    st.counter_y -= st.exec_block->step_event_count;
    if (st.exec_block->direction_bits & (1<<Y_DIRECTION_BIT)) { sys_position[Y_AXIS]--; }
    else { sys_position[Y_AXIS]++; }
  }
      
这里的判断条件为啥是  if (st.counter_y > st.exec_block->step_event_count)而不是  if (st.counter_y > 0.5st.exec_block->step_event_count) ?????

但是下面的逻辑又是对的
请教上面的问题
假设需要从点(0,0,0)到点(31,21,5),从(0,0,0)到(31,21,5)最终的执行结果是X轴步进电机移动31步、Y轴步进电机移动21步、Z轴步进电机移动了5步。
那么代码执行的详细情况如下

current_block->steps[X_AXIS] = 31;

current_block->steps[Y_AXIS] = 21;

current_block->steps[Z_AXIS] = 5;

current_block->step_event_count = 31;

//st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
counter_x = (current_block->step_event_count>>1) = 15;

counter_y = counter_z = counter_e = counter_x;



第一步

Counter_x = counter_x + current_block->steps[X_AXIS] = 15 + 31 = 46;

因为条件counter_x > current_block->step_event_count为true, 所以X电机向前走一步

counter_x = counter_x - current_block->step_event_count = 46 - 31; = 15;



counter_y = counter_y + current_block->steps[Y_AXIS] = 15 + 21 = 36;

因为条件counter_y > current_block->step_event_count为true,所以Y电机向前走一步

counter_y = counter_y - current_block->step_event_count = 36 - 31 = 5;



counter_z = counter_z + current_block->steps[Z_AXIS] = 15 + 5 = 20;

因为条件counter_z > current_block->step_event_count为false,所以Z电机不动





第二步

Counter_x = counter_x + current_block->steps[X_AXIS] = 15 + 31 = 46;

因为条件counter_x > current_block->step_event_count为true, 所以X电机向前走一步

counter_x = counter_x - current_block->step_event_count = 46 - 31 = 15;



counter_y = counter_y + current_block->steps[Y_AXIS] = 5 + 21 = 26;

因为条件counter_y > current_block->step_event_count为false,所以Y电机不动





counter_z = counter_z + current_block->steps[Z_AXIS] = 20 + 5 = 25;

因为条件counter_z > current_block->step_event_count为false,所以Z电机不动






第三步

同理

……

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出40入42汤圆

 楼主| 发表于 2018-5-19 16:26:35 来自手机 | 显示全部楼层
王涛 发表于 2018-5-19 12:01
楼主你好这是一个关于marlin源码bresenham算法光栅化的画直线算法的分析。这个算法的误差E只和dx和dy有 ...

之前已经回复过你了,避免负数运算,且不可能是有浮点运算的。。。为了避免浮点,放大了两倍;为了避免负数运算,初始值做了1/2的偏置

出0入0汤圆

发表于 2018-5-20 08:44:34 | 显示全部楼层
落叶知秋 发表于 2018-5-19 16:26
之前已经回复过你了,避免负数运算,且不可能是有浮点运算的。。。为了避免浮点,放大了两倍;为了避免负 ...

楼主你好,我太笨了,还是不能理解,楼主好人做到底能否结合源代码给我分析一下,先谢谢了。

出0入0汤圆

发表于 2018-5-20 09:04:25 | 显示全部楼层
楼主精神值得学习!

出0入0汤圆

发表于 2018-5-20 09:51:57 | 显示全部楼层
楼主用心了。我之前研究过用Python源码,做一个小激光打印机,失败了,这个是好资料。

出40入42汤圆

 楼主| 发表于 2018-5-20 10:05:32 来自手机 | 显示全部楼层
王涛 发表于 2018-5-19 12:01
楼主你好这是一个关于marlin源码bresenham算法光栅化的画直线算法的分析。这个算法的误差E只和dx和dy有 ...

st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
这个是给计数器赋了个初值0.5*event_count,本来应该是0的,按照算法来写的话。
然后判断的时候,if (counter_y > event_count),本来按照算法应该是if (counter_y > 0.5*event_count)的,但结合上面的赋初值处理,可以变成这样:
if (counter_y+0.5*event_count > 0.5*event_count+0.5*event_count),
这里就跟按照算法来写是一样的,只不过两边都有了个0.5*event_count的初值。

出0入0汤圆

发表于 2018-5-20 11:16:20 | 显示全部楼层
本帖最后由 王涛 于 2018-5-20 11:40 编辑
落叶知秋 发表于 2018-5-20 10:05
st.counter_x = st.counter_y = st.counter_z = (st.exec_block->step_event_count >> 1);
这个是给计数 ...


也就是说误差counter_y本来应该是0的,按照算法来写的话。这个里给计数器赋了个初值0.5*event_count。所以判断条件为是  if (st.counter_y > st.exec_block->step_event_count)


出40入42汤圆

 楼主| 发表于 2018-5-20 11:25:56 来自手机 | 显示全部楼层
王涛 发表于 2018-5-20 11:16
也就是说误差counter_y本来应该是0的,按照算法来写的话。这个里给计数器赋了个初值0.5*event_count。所 ...

counter_y是计数器,单次event_step多少就累加多少,为什么要0.5呢?这些比例换算之前已经算好了

出0入0汤圆

发表于 2018-5-20 11:56:57 | 显示全部楼层
本帖最后由 王涛 于 2018-5-20 12:09 编辑
落叶知秋 发表于 2018-5-20 11:25
counter_y是计数器,单次event_step多少就累加多少,为什么要0.5呢?这些比例换算之前已经算好了 ...


对了误差counter_y本来应该是0的。这里给赋了个初值0.5*event_count。
谢谢了我明白了。
这个问题我迷糊了好几个月了

http://www.openedv.com/thread-230376-1-2.html

出100入101汤圆

发表于 2018-5-20 15:59:03 | 显示全部楼层
大神,厉害!

出0入0汤圆

发表于 2018-8-15 23:14:38 | 显示全部楼层
多谢分享

出0入0汤圆

发表于 2018-8-16 10:48:52 | 显示全部楼层
楼主,这个给力

出0入0汤圆

发表于 2018-8-24 16:06:03 | 显示全部楼层
mark一下:小型雕刻机 3D打印机

出0入0汤圆

发表于 2018-8-24 20:44:07 | 显示全部楼层
楼主分析的真透彻,可厉害了!

出0入0汤圆

发表于 2018-9-11 22:32:12 | 显示全部楼层
感谢分析,非常有帮助

出0入8汤圆

发表于 2018-9-12 10:14:32 | 显示全部楼层
非常感谢分享,好好学习一下!

出0入0汤圆

发表于 2018-9-17 23:24:36 | 显示全部楼层
刚好看了一阵子grbl,还不是很熟悉,正在摸索。等了解了再加入讨论。

出0入0汤圆

发表于 2018-9-18 13:02:43 | 显示全部楼层
谢谢分享~~~~~~~

出0入0汤圆

发表于 2018-9-27 10:55:47 | 显示全部楼层
mark:GRBL源码简单分析 支持

出0入0汤圆

发表于 2018-9-27 12:33:14 | 显示全部楼层
谢谢分享!
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-3-29 23:50

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表