开源的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:
typedef struct {
// Fields used by the bresenham algorithm for tracing the line
long steps_x, steps_y, steps_z, steps_e; // Step count along each axis
unsigned long step_event_count; // The number of step events required to complete this block
long accelerate_until; // The index of the step event on which to stop acceleration
long decelerate_after; // The index of the step event on which to start decelerating
long acceleration_rate; // The acceleration rate used for acceleration calculation
unsigned char direction_bits; // The direction bit set for this block (refers to *_DIRECTION_BIT in config.h)
float nominal_speed; // The nominal speed for this block in mm/sec
float entry_speed; // Entry speed at previous-current junction in mm/sec
float max_entry_speed; // Maximum allowable junction entry speed in mm/sec
float millimeters; // The total travel of this block in mm
float acceleration; // acceleration mm/sec^2
unsigned char recalculate_flag; // Planner flag to recalculate trapezoids on entry junction
unsigned char nominal_length_flag; // Planner flag for nominal speed always reached
// Settings for the trapezoid generator
unsigned long nominal_rate; // The nominal step rate for this block in step_events/sec
unsigned long initial_rate; // The jerk-adjusted step rate at start of block
unsigned long final_rate; // The minimal rate at exit
unsigned long acceleration_st; // acceleration steps/sec^2
unsigned long fan_speed;
#ifdef BARICUDA
unsigned long valve_pressure;
unsigned long e_to_p_pressure;
#endif
volatile char busy;
} block_t;leibRamp Algorithm
block_t block_buffer[BLOCK_BUFFER_SIZE]; // A ring buffer for motion instfructions
volatile unsigned char block_buffer_head; // Index of the next block to be pushed
volatile unsigned char block_buffer_tail; |