你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

3D打印运动控制系统源码分享

[复制链接]
一抹、苦笑 发布时间:2018-4-3 08:31

9 E& `1 k1 H' U6 e, L) U$ d
开源的3D打印系统(marlin)主要是基于8位arduino控制板板卡。无法支持彩色触摸屏。为此本人花了为时3个月的时间,将marlin从arduino移植到STM32。并命名为Dlion。
3D打印运动系统的核心主要是步进电机驱动子系统,是由中断响应函数实现的。如果是恒定速度的步进电机驱动,实现就和这句话一样简单。不过对于3D打印机系统,x,y轴的运动往往速度变化非常频繁:不仅在每次更新位置的速度不同,而且每一段位移的速度也需要经历加速,恒速和减速阶段。这是由机械系统的惯性特征决定的:如果不同动作之间的速度衔接不好,会对电路系统造成强大的电流冲击。特别是3D打印过程,这种速度的变化每次打印任务都数以万计,这就意味着电路寿命将大打折扣。
步进电机驱动子系统系统的速度衔接,基于leibRamp Algorithm,这是一个支撑步进电机速度和控制器计数器频率关系的算法理论,由IBM的工程师于1994年发表并于2004年在控制器内实现。这里算法实现的关键在于路径规划器(planner)。路径规划器的设计意味着,程序在执行步进电机的动作之前,就已经计算好了整个过程的速度曲线。后面就只是Stepper模块准确地执行。在机器层面,这样的设计减少了中断响应函数中的运算量,这对于单片机来说非常友好。同时3D打印机的机械运动相比控制器的16M主频来说要慢很多,路径规划器相比直接驱动,增加了一个运动缓存。这样就能够有效的利用控制器的高频率,里面蕴藏着“空间换取时间”的思想。
在代码层面,planner的本质在于对于一个FIFO的管理。使用C的结构体指针数据结构能够非常优雅的实现这个缓存的创建和管理:
planner.h:
  1. typedef struct {( `; O! J2 R1 u( _8 N: V
  2.   // Fields used by the bresenham algorithm for tracing the line
    ' M" u8 C+ e) V, I! `7 Y
  3.   long steps_x, steps_y, steps_z, steps_e;  // Step count along each axis% A& e7 N# d: t2 y" @7 a8 E5 j# C1 T
  4.   unsigned long step_event_count;           // The number of step events required to complete this block3 n4 M: m8 x! P# Z
  5.   long accelerate_until;                    // The index of the step event on which to stop acceleration) p8 M" `; {5 ?' p
  6.   long decelerate_after;                    // The index of the step event on which to start decelerating
    ; F" u8 Z2 o1 ]+ L# C0 p
  7.   long acceleration_rate;                   // The acceleration rate used for acceleration calculation
    0 d/ C  T: w8 J/ @8 B- ~7 g
  8.   unsigned char direction_bits;             // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
    / K0 V) z! K8 K' x6 {
  9.   float nominal_speed;                               // The nominal speed for this block in mm/sec 3 s/ c5 k! H: B1 {8 t+ G7 R
  10.   float entry_speed;                                 // Entry speed at previous-current junction in mm/sec
    $ A3 Z) c, J( ]8 c- M
  11.   float max_entry_speed;                             // Maximum allowable junction entry speed in mm/sec
    , E" Q& a0 I8 `2 M! M
  12.   float millimeters;                                 // The total travel of this block in mm7 a2 q7 ]( ^6 d% Y' D
  13.   float acceleration;                                // acceleration mm/sec^2' g% y1 ~1 K6 c! L2 L1 ~: C
  14.   unsigned char recalculate_flag;                    // Planner flag to recalculate trapezoids on entry junction
    " d: A3 R  |" A
  15.   unsigned char nominal_length_flag;                 // Planner flag for nominal speed always reached; H1 G8 s/ Q, X0 G$ A( U% f' `6 n
  16. ; ]+ t+ L( ]: U2 ]& o7 \% {0 z
  17.   // Settings for the trapezoid generator! Q: w0 ^8 h0 f: T
  18.   unsigned long nominal_rate;                        // The nominal step rate for this block in step_events/sec
    : T3 o( B1 z& O3 O/ k
  19.   unsigned long initial_rate;                        // The jerk-adjusted step rate at start of block  * p/ F- b6 g' m- ?( R8 K% e6 @! s
  20.   unsigned long final_rate;                          // The minimal rate at exit
    $ K4 o: j+ w8 G
  21.   unsigned long acceleration_st;                     // acceleration steps/sec^2
    3 Q+ [2 L  t" ~: x- b; R
  22.   unsigned long fan_speed;: C# S6 K% p" X, ?- n' d% @
  23.   #ifdef BARICUDA7 K2 B$ u+ L2 c5 O5 K
  24.   unsigned long valve_pressure;
    # B* u% l# L: K- p. o
  25.   unsigned long e_to_p_pressure;. O2 ~- C0 X! ~6 X$ D
  26.   #endif* ], N$ M( i: j% D! g7 o
  27.   volatile char busy;7 t: N4 o4 ~$ R( ?: ~$ W8 ~$ p! a
  28. } block_t;leibRamp Algorithm
    ' I7 t  L1 a$ `3 y

  29. 0 y# [/ ^$ K7 d7 K& U- O& s
  30. block_t block_buffer[BLOCK_BUFFER_SIZE];            // A ring buffer for motion instfructions* G) @+ Q, L  A9 N' s; V0 {  u
  31. volatile unsigned char block_buffer_head;           // Index of the next block to be pushed
    $ y5 w' x6 U5 ^$ `( U, _" G
  32. volatile unsigned char block_buffer_tail;
复制代码
volatile 关键字确保了队列头和队列尾被不同函数访问过程中,编译器不会因为优化和丢失更改行为。block_t类型的指针可以方便的方位结构体内任何元素。在后面的planner规划动作plan_buffer_line()中,代码可以用非常优雅的结构体指针来完成。

5 _& }8 j* t* q6 @5 Q" m9 n
' {; G" c6 c. D& v+ M$ D
" s' L1 P- P. t. \, h6 S

+ a6 o- i% x- n. @
3 n% c* s: e5 Q9 `  w
     每当3D打印机解析到位移指令的时候,plan_buffer_line()函数就被调用。在里面新的block_t首先被创建,并且排入队列的队尾;然后执行calculate_trapezoid_for_block(),计算新的block_t的关键速度节点及其对应的step数目;接着更新队列里面所有block_t的连接速度:之前队尾的block_t的收尾速度和相关速度节点会被更新。最后调用st_wake_up()保证stepper执行的中断打开。
/ b3 `. ?! b' U! ^' ~

: n( {. j% `4 f2 E) q
6 C( v# v8 B6 }: ~9 q1 u' Y
- ?& h2 @$ A  Z

; X& z( Z7 t3 K& X9 A- `- |# H
    而在%steppper中,ISR函数负责在主循环之外,执行队列里可能存在的所有block_t。在ISR中,首先由plan_get_current_block()读取队列首的block_t,然后按照结构成员的step数,调用STEP_ADDSTEP_IF_COUNTER两个宏来执行x,y,z三轴的运动。ISR每执行一次,三路各发出一个脉冲,并通过lamp ramp算法更新,根据下一个速度值来更新OCR1A寄存器来设定下一次中断响应的周期。
main.png
消化一段代码的最有效方法是对其移植或者重写。换言之,仅仅是走马观花的浏览一遍,除非自己曾经编写过类似程序,很难能透彻的领会固件代码的精髓。所以这里我决定把它分享出来给大家!
更多交流可以进3D二进制创客开源社区:523118188。
关注微信公众号获取更多资料
qrcode_for_gh_49cf119988cb_258.jpg
Dlion-开源固件源码.rar (171 Bytes, 下载次数: 23996)

# u. M& a+ f! x2 y! i) q! q2 d3 _0 C" }2 Z8 c8 j
收藏 2 评论7 发布时间:2018-4-3 08:31

举报

7个回答
起名什么的炒鸡麻烦 回答时间:2018-4-3 09:59:57
大佬啊,感谢分享
王希瑞 回答时间:2018-4-10 14:57:07
学习了,曾经研究过一段时间这个代码
王希瑞 回答时间:2018-4-10 14:57:58
有一个疑问,指令接收的速度是很快的,但是运动的过程中是很慢的,这样,缓存器是很快就被存满了啊,不会溢出的吗: x& \  K* t0 w' p3 f
yangjiyou1969 回答时间:2018-6-11 20:50:48
下载看看先,谢谢
yangjiyou1969 回答时间:2018-6-11 20:51:43
楼主,我想问一下,我想用汇编,可行吗?
kaif_w 回答时间:2018-7-28 11:11:00
好人啊
huaishan 回答时间:2020-7-11 15:06:49
下载看看先,谢谢

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版