关闭

【龙印】3d打印固件Marlin中bresenham算法注解

标签: 龙芯1c3d打印机
1683人阅读 评论(3) 收藏 举报
分类:

本文为在用龙芯1c做3D打印机过程中的笔记。龙芯1c做的3d打印机简称“龙印”,交流论坛地址是“http://www.openloongson.org/”

参考了以下两篇博文,再其基础上增加了对marlin源码的注解和我的一些理解。

http://blog.sina.com.cn/s/blog_6ad165790102vo09.html

http://blog.sina.com.cn/s/blog_679933490102vv8z.html


先来看一下marlin中bresenham算法的相关代码。源码位于源文件“Marlin\stepper.cpp”中的函数ISR(TIMER1_COMPA_vect)内。如下

  // If there is no current block, attempt to pop one from the buffer
  if (!current_block) {
    // Anything in the buffer?
    current_block = plan_get_current_block();
    if (current_block) {
      current_block->busy = true;
      trapezoid_generator_reset();
      counter_x = -(current_block->step_event_count >> 1);
      counter_y = counter_z = counter_e = counter_x;
      step_events_completed = 0;

      #if ENABLED(Z_LATE_ENABLE)
        if (current_block->steps[Z_AXIS] > 0) {
          enable_z();
          OCR1A = 2000; //1ms wait
          return;
        }
      #endif

      // #if ENABLED(ADVANCE)
      //   e_steps[current_block->active_extruder] = 0;
      // #endif
    }
    else {
      OCR1A = 2000; // 1kHz.
    }
  }

  if (current_block != NULL) {

    // Update endstops state, if enabled
    #if ENABLED(HAS_Z_MIN_PROBE)
      if (check_endstops || z_probe_is_active) update_endstops();
    #else
      if (check_endstops) update_endstops();
    #endif

    // Take multiple steps per interrupt (For high speed moves)
    for (int8_t i = 0; i < step_loops; i++) {
      #ifndef USBCON
        customizedSerial.checkRx(); // Check for serial chars.
      #endif

      #if ENABLED(ADVANCE)
        counter_e += current_block->steps[E_AXIS];
        if (counter_e > 0) {
          counter_e -= current_block->step_event_count;
          e_steps[current_block->active_extruder] += TEST(out_bits, E_AXIS) ? -1 : 1;
        }
      #endif //ADVANCE

      #define _COUNTER(axis) counter_## axis
      #define _APPLY_STEP(AXIS) AXIS ##_APPLY_STEP
      #define _INVERT_STEP_PIN(AXIS) INVERT_## AXIS ##_STEP_PIN

      #define STEP_ADD(axis, AXIS) \
        _COUNTER(axis) += current_block->steps[_AXIS(AXIS)]; \
        if (_COUNTER(axis) > 0) { _APPLY_STEP(AXIS)(!_INVERT_STEP_PIN(AXIS),0); }

      STEP_ADD(x,X);
      STEP_ADD(y,Y);
      STEP_ADD(z,Z);
      #if DISABLED(ADVANCE)
        STEP_ADD(e,E);
      #endif

      #define STEP_IF_COUNTER(axis, AXIS) \
        if (_COUNTER(axis) > 0) { \
          _COUNTER(axis) -= current_block->step_event_count; \
          count_position[_AXIS(AXIS)] += count_direction[_AXIS(AXIS)]; \
          _APPLY_STEP(AXIS)(_INVERT_STEP_PIN(AXIS),0); \
        }

      STEP_IF_COUNTER(x, X);
      STEP_IF_COUNTER(y, Y);
      STEP_IF_COUNTER(z, Z);
      #if DISABLED(ADVANCE)
        STEP_IF_COUNTER(e, E);
      #endif

      step_events_completed++;
      if (step_events_completed >= current_block->step_event_count) break;
}

阅读这段代码的主要麻烦在宏STEP_ADD和STEP_IF_COUNTER。

符号“##”的作用是把前后的宏参数拼接在一起。

我们来分析“STEP_ADD(x,X)”

STEP_ADD(x,X)=_COUNTER(x) += current_block->steps[_AXIS(AXIS)]; \

    if (_COUNTER(x) > 0) { _APPLY_STEP(X)(!_INVERT_STEP_PIN(X),0); }

其中,_COUNTER(x)=counter_x

_APPLY_STEP(X)=X_APPLY_STEP

_INVERT_STEP_PIN(X)=INVERT_X_STEP_PIN

_AXIS(AXIS)也类似,搜索源码会发现有“#define _AXIS(AXIS) AXIS ##_AXIS”。

STEP_IF_COUNTER也类似。

经过整理后bresenham算法可以表示为


这个代码很清晰了,可是怎么也看不出有个什么算法,哈哈。

 

bresenham算法是光栅化的画直线算法。直线光栅化是指用像素点来模拟直线,比如下图用蓝色的像素点来模拟红色的直线。


蓝色点是怎么得到的呢?取与理想中的红点最近的xy轴的交点作为蓝点。

算法是怎么与marlin源码结合的呢?


假设需要从点(0,0,0)到点(31,21,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;

 

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 = 16;

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

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

 

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

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

counter_y = counter_y - current_block->step_event_count = 6 - 31 = -25;

 

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

因为条件counter_z > 0为false,所以Z电机不动

counter_z = counter_z - current_block->step_event_count = -10 - 31 = -41;

 

 

第二步

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

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

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

 

counter_y = counter_y + current_block->steps[Y_AXIS] = -25 + 21 = -4;

因为条件counter_y > 0为false,所以Y电机不动

counter_y = counter_y - current_block->step_event_count = -4 - 31 = -35;

 

counter_z = counter_z + current_block->steps[Z_AXIS] = -41 + 5 = -36;

因为条件counter_z > 0为false,所以Z电机不动

counter_z = counter_z - current_block->step_event_count = -36 - 31 = 67;

 

 

第三步

同理,X电机向前走一步,Y和Z电机不动

……

 

综上所述,本例中X电机运行的步数是current_block->steps[X_AXIS]的值,而Y电机只运行了一步,Z电机原地不动。

概括为,只有长轴对应电机的实际运行步数才是block中的steps值,另外的两个轴根据block中对应的steps值是否大于长轴steps值得一半来决定是否前进一步。大于则前进一步,否则原地不动。

Block_t中的long steps[NUM_AXIS]是gcode指令的相对目标坐标,即每条gcode指令执行完后挤出头所在的坐标与当前位置的坐标差,只是把单位换为了步进电机的步数。不过这不是xyze电机实际运行的步数,实际的步数是通过bresenham算法计算出来的。

注意:marlin源码中实现的bresenham算法和理论的bresenham算法不一样的地方,是每次步进一个单位时,不是以1/2个步进单位作为衡量标准,而是以1/2个step_event_count作为标准。这个可能和切片软件有关,切片时保证了挤出头只沿一个轴移动,也就是上面所说的长轴。





1
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:27236次
    • 积分:734
    • 等级:
    • 排名:千里之外
    • 原创:47篇
    • 转载:1篇
    • 译文:0篇
    • 评论:15条
    最新评论