`
chchcome
  • 浏览: 6880 次
  • 性别: Icon_minigender_1
  • 来自: 济南
最近访客 更多访客>>
社区版块
存档分类
最新评论

marlin代码解析

 
阅读更多

一、前言
Delta机型是一种并联式运动结构的3d打印机,delta机型实际上是分为两大类,一种是工业上用的并联式机器人;另外一种是rostock 的运动结构。这两种结构做出来的打印机给人的感觉都是非常cool的。所以大伙都偏好这类型的打印机,目前主流的固件marlin 和repetier都支持rostock结构的3d打印机。这里鸭哥就谈谈自己对rostock机型的运动算法的理解,继而从运动算法中推算一下如何调试一台rostock的参数。
二、基础知识
要理解rostock的全部运动算法所要涉及的数学知识不是太多,如果不记得的话,是时候找高中数学老师喝喝茶吃个小饭啦。
1)三角函数 sin cos 这个是理解rostock计算过程的基础知识
2)笛卡尔空间坐标转换/线性代数,这个嘛是属于进阶内容,如果懂那就更好啦,如果不懂也没关系,在把所有的外界条件全部设置为理想情况下,这个笛卡尔空间坐标转换可以不用精通的。(包括鸭哥也不敢说对笛卡尔空间坐标转换和线性代数精通哦)
3)marlin程序的结构逻辑结构(对于arduino ide /arduino程序基本教程,这里就不展开了,不懂的小白们可以先学一下arduino的基础教程先,饭要一口一口得出,路要一步一步的走)
三、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 fromcalculations
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[i]、 destination[i] 放到一个内存的一个缓存区里面,然后控制电机转多少圈这样一个作用的,具体代码可以自己去看,在一旦进入这个函数以后,delta和普通机型的代码都是一样的,也就是说delta和普通结构的电机控制其实是一样的。
Difference[i]数组 :用来储存目标坐标和当前坐标之间的距离的,(这里是包含了xyze轴的数组)
Destination[i]数组:目标坐标的数值,是从process_command()函数中G1读取XYZE参数获取的。
Current_position[i]数组:当前坐标的数值,是从G1 命令中get_coordinates()传递过来的。如果是3个轴都归零的情况下,current_position就是储存三个坐标原点,如果开始运动了,这里的值就是上一个prepare_move()循环执行后上一次的destination[i]的值。(这个下面会有看到赋值语句)
Delta[i]数组:delta打印机的xyz三个电机要移动的距离

void prepare_move()
{


#ifdef DELTA //设置机子是delta机型(rostock)
float difference[NUM_AXIS]; //定义目标距离,用于转换坐标用的过渡变量
for (int8_t i=0; i < NUM_AXIS; i++) {
difference[i] = destination[i] - current_position[i];
} //计算世界坐标的距离值
//***开始计算笛卡尔距离 并且暴力直线插值来减少运算量***//
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[i] = current_position[i] + difference[i] * 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[i]的值发送去运动缓存里面
}
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[i] = destination[i]; //更新当前坐标的值为刚执行的目标坐标值
}
}
好,看了一大段代码后小结一下。对于普通结构来说,G1 每次将新读取gcode代码参数传递给prepare_move()函数中destination[i]数组以后,prepare_move()就会将其传递到plan_buffer_line()进行电机的运动。而delta结构呢,就相对复杂一点,G1命令读取了gcode代码参数后也是传递到prepare_move()函数中destination[i],然后marlin要计算目标坐标与当前坐标的笛卡尔距离,然后通过固定时间间隔的方式来将笛卡尔距离分成若干个小直线,通过这样的方式来就减少cpu的浮点预算量,然后再通过calculate_delta[i]函数来将简化后的destination[i]换算成三个电机的运动坐标,并传递到delta[i]中,接下来就是plan_buffer_line()了。
最后!到了最后了!来看看calculate_delta()函数,这个函数的主要用途是将打印件的世界坐标转换为三个垂直的电机轴的运动坐标哦。注意:新的marlin支持SCARA结构的delta,那里也有个calculate_delta()的函数,不过那个跟rostock有点差异。所以我们还是看rostock的吧。
void calculate_delta(float cartesian[3])
{
delta[X_AXIS] =sqrt(delta_diagonal_rod_2
-sq(delta_tower1_x-cartesian[X_AXIS])
-sq(delta_tower1_y-cartesian[Y_AXIS])
) +cartesian[Z_AXIS];
delta[Y_AXIS] = sqrt(delta_diagonal_rod_2
-sq(delta_tower2_x-cartesian[X_AXIS])
-sq(delta_tower2_y-cartesian[Y_AXIS])
) +cartesian[Z_AXIS];
delta[Z_AXIS] =sqrt(delta_diagonal_rod_2
-sq(delta_tower3_x-cartesian[X_AXIS])
-sq(delta_tower3_y-cartesian[Y_AXIS])
) +cartesian[Z_AXIS];
/*
SERIAL_ECHOPGM("cartesian x=");SERIAL_ECHO(cartesian[X_AXIS]);
SERIAL_ECHOPGM("y="); SERIAL_ECHO(cartesian[Y_AXIS]);
SERIAL_ECHOPGM("z="); SERIAL_ECHOLN(cartesian[Z_AXIS]);

SERIAL_ECHOPGM("deltax="); SERIAL_ECHO(delta[X_AXIS]);
SERIAL_ECHOPGM("y="); SERIAL_ECHO(delta[Y_AXIS]);
SERIAL_ECHOPGM("z="); SERIAL_ECHOLN(delta[Z_AXIS]);
*/
}

代码很简单delta[i]是指电机轴的运动坐标,cartesian[i]是指打印件的世界坐标,从上面的程序来看就是从prepare_move()中经过插值简化的destination[i]。大伙随便看一个轴的换算
delta[X_AXIS] =sqrt(delta_diagonal_rod_2
-sq(delta_tower1_x-cartesian[X_AXIS])
-sq(delta_tower1_y-cartesian[Y_AXIS])
) +cartesian[Z_AXIS];
delta_diagonal_rod_2 是推杆长的平方
delta_tower1_x 是左前柱的x坐标值,是由radius这个参数算出来的
delta_tower1_y 是左前柱的y坐标值,是由radius这个参数算出来的
具体怎么算就看下面这个函数
void recalc_delta_settings(float radius, float diagonal_rod)
{
delta_tower1_x= -SIN_60*radius; // front lefttower
delta_tower1_y= -COS_60*radius; 
delta_tower2_x= SIN_60*radius; // front right tower
delta_tower2_y= -COS_60*radius; 
delta_tower3_x= 0.0; // back middle tower
delta_tower3_y= radius;
delta_diagonal_rod_2= sq(diagonal_rod);
}

好了回顾一下marlin的delta机型参数是需要什么?
推杆的长度、电机轴上滑块的宽度、喷头支架的宽度,还有三个电机的圆半径。对不对?忘了?!不要紧,给你看看代码
//=================================================================
//========================Delta Settings =============================
//=================================================================
// Enable DELTA kinematics and most of the default configuration forDeltas
#define DELTA

// Make delta curves from many straight lines (linearinterpolation).
// This is a trade-off between visible corners (not enough segments)
// and processor overload (too many expensive sqrt calls).
#define DELTA_SEGMENTS_PER_SECOND 200

// NOTE NB all values for DELTA_* values MUST be floating point, soalways have a decimal point in them

// Center-to-center distance of the holes in the diagonal push rods.
#define DELTA_DIAGONAL_ROD 250.0 // mm //杆长

// Horizontal offset from middle of printer to smooth rod center.
#define DELTA_SMOOTH_ROD_OFFSET 175.0 // mm //电机轴的圆半径

// Horizontal offset of the universal joints on the end effector.
#define DELTA_EFFECTOR_OFFSET 33.0 // mm // 装喷嘴的平台的中心到杆连接处的距离

// Horizontal offset of the universal joints on the carriages.
#define DELTA_CARRIAGE_OFFSET 18.0 // mm //电机轴滑块的距离

// Effective horizontal distance bridged by diagonal push rods.
#define DELTA_RADIUS(DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET)
通过上述的参数可以算出一个DELTA_RADIUS,这个delta_radius就是上面“delta_tower1_x 是左前柱的x坐标值,是由radius这个参数算出来的”里面的radius了。
至此所有有关与delta的运动的代码已经通读了一遍。下面就开始分析分析代码和运动的关系了。

四、Rostock运动分析
下面是Rostock的结构示意图,分析的第一步是简化整个结构,这里就需要将XY电机的两个竖轴投影到Z轴的平面上,下图中红色线框画出来的就是z轴的平面,同时我们可以不考虑XY电机的推杆的运动情况,因为可以XY电机轴的运动可以通过投影在z轴平面上的虚拟轴笛卡尔空间变换转换回去的。



 
投影好了以后接下来把z轴放平,那么单独考虑z轴情况,这个情况是在坐标原点的z电机轴与推杆的情况。为了简化过程,鸭哥已经把z轴滑块,喷头平台都设定为0 了。那么,z电机轴方向便形成了一个三角形,推杆、radius和z轴电机上的电机坐标,这个时候三角函数出来啦! 推杆2 = radius 2+ 电机坐标 2 在这三角形中推杆是不变的,另外三角形始终都会是一个直角三角形。一定要记住这几个条件哦。



 
好,现在我们假设喷头只在x轴上运动,z轴y轴都不动。如果打印件的世界坐标移动dX距离,rostock需要考虑的问题就是怎么讲dX转换为z轴电机的移动距离了。下图就是用来表示这种情况。由于推杆长度是不变的,那么

推杆2 = radius 2+ 电机坐标 2 就变成下面这样
推杆2 = (radius +dX)2+ (电机坐标-dx) 2
Radius的距离换成destination[x],电机坐标换成delta[x]
推杆2 = (destination[x +dX])2+(delta[x-dx]) 2



 
Marlin中calculate_delta()这个函数其实就是算 

推杆2 = (destination[x +dX])2+(delta[x-dx]) 2
这个等式明白啦,打印件X轴和Y轴的运动分析就明白啦。
另外,再看看打印件z轴的运动分析,还是看看源代码

delta[X_AXIS] =sqrt(delta_diagonal_rod_2
-sq(delta_tower1_x-cartesian[X_AXIS])
-sq(delta_tower1_y-cartesian[Y_AXIS])
) +cartesian[Z_AXIS];
Cartesian[z]是没有在sqrt函数里面的,而是直接加在delta[x]的值上面的。
所以,在调机的时候应该先调z轴,这里就是原因。因为在XYZ三个轴的坐标中只有Z轴是直接通过同步轮和电机脉冲就可以调准的。调准了z轴以后再调XY轴才是对的。
五、调机心得
下面是鸭哥的调机的一些心得,与大家分享一下。首先是调机的顺序:
1)选择同步轮可以选择GT2 20齿/40齿 。因为GT2是2mm齿距,整数齿可以使脉冲数为整数,同时也减少三角函数运算中浮点运算的压力,同时也简化自己的调整步骤。
2)调机时先调z轴运动方向的精度,这个是直接用同步轮和脉冲数就可以调好的。
3)z轴调好以后就调整x轴或者Y轴的,看看运动的路径是不是呈现平面状态,如果喷头运动路径是弧线这个时候就要调整radius了,增加或者减少radius的值来调整运动路径是一个平面
4)完成上述步骤以后就可以试打了,这个时候就可以看看XY轴的打印误差是多少了。如果杆长等硬件参数都比较准确的话那打印误差不会有多少的。如果XY轴有误差的话就要根据误差大小来等量调整radius这个变量。对应代码是
// Horizontal offset from middle of printer to smooth rod center.
#define DELTA_SMOOTH_ROD_OFFSET 175.0 // mm //电机轴的圆半径

等量修改,比如X轴偏大0.1mm,那么 调整量就是175.0-0.1= 174.9 了哦。这样反复几次就基本调好了。


六、后记
本文是鸭哥的一些心得体会,是个人对marlin还有rostock的一些了解,当然也许会有这样那样的错误和不足,鸭哥非常欢迎大神高手批评指正。本文首发于珠海创客空间网站,欢迎转载,著名出处。欢迎修改,修改的地方用另外的文字著名就可以了。

  • 大小: 39 KB
  • 大小: 43.6 KB
  • 大小: 20.5 KB
分享到:
评论

相关推荐

    Marlin代码(详细注释)

    在Marlin代码中,G代码解析通常在`parser.c`或`parser.h`文件中实现。每个G代码命令都有对应的处理函数,比如`G0`和`G1`用于直线移动,`G2`和`G3`代表圆弧运动。这些函数会分析G代码的参数,如X、Y、Z坐标,速度,...

    Marlin代码精读

    ### Marlin代码精读 #### Marlin是什么? Marlin是一款非常流行的开源3D打印机固件,它被广泛应用于各种3D打印设备上。Marlin融合了Sprinter与Grbl两个固件的优点,不仅功能强大而且支持多种硬件平台,是3D打印机...

    marlinsourcecode马琳固件精读.zip_Marlin详解台湾_marlin code_marlin固件 解析_ma

    3. **G代码解析**:Marlin接收并解析G代码指令,这是3D打印的标准指令集,如移动、加热、冷却等操作。 4. **床校准**:支持多种校准算法,如自动床平面校准(ABL),确保打印平台与喷嘴之间的距离均匀。 5. **切片...

    marlin source code 马琳固件精读 高清PDF讲解

    首先,从整体上介绍Marlin的架构,包括它的主要模块和功能,如运动控制、温度管理、G代码解析等。这些模块是3D打印过程中的关键部分,理解和掌握它们对于优化打印质量和速度至关重要。 在运动控制部分,讲解了如何...

    Marlin-1.1.9_ch341SER_forthu1r_marlin代码1.9_marlin1.19_marlin固件_源

    Marlin 1.1.9是Marlin 1.1.x系列的一个迭代,其中包含了对之前版本的改进和增强,例如提升打印速度、优化G代码解析效率和提高温度控制精度。 5. **源代码**:在提供的压缩包中,包含的是Marlin固件的源代码,这意味...

    3D打印机固件-Marlin-1.1.9_Marlin1.1.9_3D打印机固件-Marlin-1.1.9_

    Marlin是一款专为Fused Deposition Modeling (FDM) 3D打印机设计的实时控制固件,其核心功能包括运动控制、温度管理、G代码解析与执行等。Marlin提供了一个灵活的框架,允许用户根据自己的打印机硬件进行定制和调整...

    Marlin-CNC_Mill_1_firmware_marlin_MILL_

    5. **G代码解析**:Marlin能解析标准G代码指令,包括基本的运动命令、切削深度控制、速度调节等,还支持一些特定的扩展功能,如镜像、旋转、复制等。 6. **错误恢复**:如果在加工过程中发生中断,Marlin可以记住...

    Marlin-1.1.1_2560marlin固件_马林1.1固件_marlin-stable_

    4. **G代码处理**:Marlin可以解析并执行G代码,这是3D打印机的指令语言。1.1.1版本对G代码的处理进行了优化,提高了打印速度,同时保持了打印质量。 5. **床平准**:固件内置了多种床平准方法,如自动床平准(ABL...

    3D打印源码MarLin精简移植到STM32F103上

    7. **G代码解析**:MarLin需要解析来自上位机的G代码指令,将其转化为具体的电机运动命令。这部分涉及字符串处理和数学运算,对STM32的计算能力有一定要求。 8. **温度控制**:3D打印通常需要控制喷头和热床的温度...

    3d打印固件Marlin-Marlin_v1

    - **G代码解析**:Marlin_v1能解析G代码指令,包括速度控制、层高设定、曲线平滑等。 - **安全特性**:例如过热保护和电源故障恢复。 3. **安装与配置**:Marlin_v1的安装通常需要通过Arduino IDE进行,用户需要...

    Marlin Marlin V1

    3. **高级功能**:Marlin固件包含了如G代码解析、温度控制、床校平、自动调平等一系列功能。G代码是3D打印的基本指令语言,Marlin能高效解析并执行这些指令,确保打印过程的精确性。温度控制则涵盖了喷头和热床的...

    21ic下载_marlin固件.zip

    3. **G代码解析**:Marlin支持标准的G代码指令,能够解析和执行打印任务中的各种操作,如移动、挤出、加热等。 4. **安全特性**:内置过热、过流等保护机制,保护打印机硬件不受损害。例如,当检测到温度过高时,会...

    marlin固件.zip

    此版本已经包含了基本的3D打印功能,如G代码解析、层冷却、自动调平等,并对打印速度和精度进行了优化。对于初学者和拥有较旧打印机的用户来说,这是一个可靠的选择。 Marlin 1.0.x 是Marlin的另一个关键版本,它在...

    Marlin-Marlin_v1.zip_marlin_marlin firmware

    3. **G代码解析**:Marlin能够理解和执行G代码,这是3D打印的标准指令集。它能解析来自切片软件(如Slic3r、Cura等)生成的G代码,执行打印任务。 4. **加速度控制**:固件支持动态加速度调整,可根据打印情况自动...

    Marlin固件_aqewrgqaewrgbaewrga_

    4. **G代码解析**:Marlin能够理解和执行G代码,这是3D打印的标准指令语言。它处理速度控制、温度调节、喷头移动等任务。 5. **温度管理**:固件内置了加热床和喷头的温度控制,可以设置预热温度,监控实时温度,并...

    3D打印机固件Marlin

    - **G代码解析**:Marlin能高效解析G代码,执行复杂的打印指令。 - **断电恢复**:在电源中断后,Marlin能记住打印进度,继续未完成的打印。 - **层高调整**:用户可以根据需求自定义每层的高度,以获得更精细的...

    marlin 固件配置程序

    #### 三、Marlin固件结构解析 **1. 配置文件(Configuration.h)** `Configuration.h`是Marlin固件中非常重要的一个配置文件,其中定义了大量与打印机相关的配置选项,包括电机步进设置、热床温度控制、运动速度参数...

    Marlin-Marlin_v1.rar_3D打印机开发包_Marlin_v1_marlin

    3. **G代码解析**:Marlin能解析标准的G代码指令,将这些指令转化为驱动电机和控制加热元件的命令。 4. **切片参数校准**:允许用户根据实际3D打印机硬件调整参数,比如步进电机的步距角、加速设置等,以实现最佳...

    marlin马林主板改CNC雕刻机相关软件

    主板解析G代码后,控制电机运动来执行雕刻任务。学习G代码的基本指令对于理解和调试CNC系统至关重要。 7. **安装与配置**:将Marlin固件烧录到STM32主板,需要使用像Arduino IDE或PlatformIO这样的开发环境,配合...

    Marlin Stable

    Marlin Stable固件包含了一系列功能,如G代码解析、床平面校准、切片层处理、线性预测插补等。这些功能使得3D打印更加精确和高效。G代码是3D打印机理解和执行的指令集,Marlin能有效地解析和执行这些指令,确保模型...

Global site tag (gtag.js) - Google Analytics