Delta (rostock型)3d打印机算法解读及调试步骤
三、Marlin程序解读
这里鸭哥不打算讲marlin的整个loop()函数的流程,讲讲delta机型的核心部分。对于marlin来说,delta机型和非delta机型在对于温控、看门狗、电机运动甚至空间坐标等方面都是一样的。区别在哪里呢?区别就在与delta多了一个笛卡尔坐标转换的函数 Marlin的loop()主体流程 Void loop () { Get_command() ; //从sd卡或者串口获取gcode Process_command(); //解析gcode并且执行代码 Manage_heater();//控制机器的喷头和热床的温度 Manage_inactivity();// checkHitEndstops();//检查endstop的状态 Lcd_update(); //更新lcd 上面的信息 }
在这个过程中 process_command()是控制的核心,各位仔细研读一下process_command()的代码就发现arduino的厉害了。简单说一下process_command()的流程,说白了,process_command()就是一个巨大的case 结构,这里讲讲G1命令的大致逻辑(G1命令不知道的自己搜索去): Process_command() { Case 0: //g0->g1 Case 1 : { if(Stopped == false) { get_coordinates(); // 获取当前的坐标,这里是指打印件的世界坐标哦,不是delta的xyz电机的坐标哦!普通结构的打印机则是一样的。 #ifdef FWRETRACT if(autoretract_enabled) if( !(code_seen('X') || code_seen('Y') || code_seen('Z')) && code_seen('E')) { //获取 命令中 xyze轴的参数 Float echange=destination[E_AXIS]-current_position[E_AXIS]; //这里是算最小回抽值的,如果移动距离小于最小回抽值就不回抽了。这里是一个辅助功能。简单了解可以了。 if((echange<-MIN_RETRACT && !retracted) || (echange>MIN_RETRACT && retracted)) { //move appears to be an attempt to retract or recover current_position[E_AXIS] = destination[E_AXIS]; //hide the slicer-generated retract/recover from calculations plan_set_e_position(current_position[E_AXIS]); //AND from the planner retract(!retracted); return; } } #endif //FWRETRACT prepare_move(); //执行移动命令
return; } } 从上面的代码来看呢,对于运动类的Gcode,marlin会在process_command()函数中获取xyze各轴的参数后算出目标坐标(destination[_AXIS]),也会使用get_coordinates()来获取当前坐标(current_position[E_AXIS])(再次强调,这个坐标是打印件的世界坐标),当我们知道了目标坐标和当前坐标以后,空间中移动的距离就可以算出来了(不会算的,请自觉请高中数学老师吃饭去),接下来marlin就使用perpare_move()来控制电机啦。 接下来呢很自然就要讲讲prepare_move()这个函数啦。先上代码先,代码鸭哥做了精简,只看关键的部分就是delta和普通结构的代码,先说一下plan_buffer_line()这个函数的作用的把坐标数组current_position 、 destination 放到一个内存的一个缓存区里面,然后控制电机转多少圈这样一个作用的,具体代码可以自己去看,在一旦进入这个函数以后,delta和普通机型的代码都是一样的,也就是说delta和普通结构的电机控制其实是一样的。 Difference数组 :用来储存目标坐标和当前坐标之间的距离的,(这里是包含了xyze轴的数组) Destination数组:目标坐标的数值,是从process_command()函数中G1读取XYZE参数获取的。 Current_position数组:当前坐标的数值,是从G1 命令中get_coordinates()传递过来的。如果是3个轴都归零的情况下,current_position就是储存三个坐标原点,如果开始运动了,这里的值就是上一个prepare_move()循环执行后上一次的destination的值。(这个下面会有看到赋值语句) Delta数组:delta打印机的xyz三个电机要移动的距离 void prepare_move() {
#ifdef DELTA // 设置机子是delta机型(rostock) float difference[NUM_AXIS]; //定义目标距离,用于转换坐标用的过渡变量 for (int8_t i=0; i < NUM_AXIS; i++) { difference = destination - current_position; } //计算世界坐标的距离值 //***开始计算笛卡尔距离 并且暴力直线插值来减少运算量***// float cartesian_mm = sqrt(sq(difference[X_AXIS]) + sq(difference[Y_AXIS]) + sq(difference[Z_AXIS])); if (cartesian_mm < 0.000001) { cartesian_mm = abs(difference[E_AXIS]); } if (cartesian_mm < 0.000001) { return; } float seconds = 6000 * cartesian_mm / feedrate / feedmultiply; int steps = max(1, int(delta_segments_per_second * seconds)); for (int s = 1; s <= steps; s++) { float fraction = float(s) / float(steps);//直线插值 for(int8_t i=0; i < NUM_AXIS; i++) { destination = current_position + difference * fraction; } //***结束计算笛卡尔距离 并且暴力直线插值来减少运算量***// calculate_delta(destination);//将打印件的世界坐标转换为xyz电机轴的运动量 plan_buffer_line(delta[X_AXIS], delta[Y_AXIS], delta[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder); } #endif // DELTA 。。。。。。。。。。。。 #if ! (defined DELTA || defined SCARA) // Do not use feedmultiply for E or Z only moves if( (current_position[X_AXIS] == destination [X_AXIS]) && (current_position[Y_AXIS] == destination [Y_AXIS])) { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate/60, active_extruder); //直接将destination的值发送去运动缓存里面 } else { plan_buffer_line(destination[X_AXIS], destination[Y_AXIS], destination[Z_AXIS], destination[E_AXIS], feedrate*feedmultiply/60/100.0, active_extruder); } #endif // !(DELTA || SCARA) for(int8_t i=0; i < NUM_AXIS; i++) { current_position = destination; //更新当前坐标的值为刚执行的目标坐标值 } }
Delta3D打印机代码解读及调机心得(一)
Delta3D打印机代码解读及调机心得(三)
Delta3D打印机代码解读及调机心得(四) |
你可能喜欢
人工智能与3D打印技术结合,实现小型核反应
最新《Nature》:动态界面3D打印
石墨烯增强混凝土能否推动可持续建筑? UVA
杜克大学:新型无溶剂3D打印材料,可用于医
推荐课程
神奇的3D打印
SLA3D打印工艺全套培训课程 - 软件篇
3D打印月球灯视频教程 包括完整贴图建模流
【原创发布】Cura软件修改二次开发定制视频