狠狠撸

狠狠撸Share a Scribd company logo
Delta (rostock 型)3d 打印机算法解读及
调试步骤
1、前言
Delta 机型是一 并 式 的种 联 运动结构 3d 打印机,delta 机型 上实际
是分 大类,一 是工 上用的并 式机器人;另外一 是为两 种 业 联 种
rostock 的 。 做出来的打印机 人的感 都是非运动结构 这两种结构 给 觉
常 cool 的。所以大 都偏好 类型的打印机,目前主流的固件伙 这
marlin 和 repetier 都支持 rostock 的结构 3d 打印机。 里 哥就这 鸭 谈
自己谈 对 rostock 机型的 算法的理解, 而从 算法中推算运动 继 运动
一下如何 一台调试 rostock 的参数。
2、基础知识
要理解 rostock 的全部 算法所要涉及的数学知 不是太多,运动 识
如果不 得的 ,是 候找高中数学老 喝喝茶吃个小 。记 话 时 师 饭啦
1)三角函数 sin cos 个是理解这 rostock 算 程的基 知计 过 础 识
2)笛卡尔空 坐间 标转换/ 性代数, 个嘛是属于 内容,如线 这 进阶
果懂那就更好 ,如果不懂也没 系,在把所有的外界条件全部啦 关 设
置 理想情况下, 个笛卡尔空 坐 可以不用精通的。(包括为 这 间 标转换
哥也不敢 笛卡尔空 坐 和 性代数精通哦)鸭 说对 间 标转换 线
3)marlin 程序的 ( 于结构逻辑结构 对 arduino ide /arduino 程
序基本教程, 里就不展 了,不懂的小白 可以先学一下这 开 们
arduino 的基 教程先, 要一口一口得出,路要一步一步的走)础 饭
3、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[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("delta x="); 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 left tower
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 for Deltas
#define DELTA
// Make delta curves from many straight lines (linear interpolation).
// 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, so always 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 的运动的代码已经通读了一遍。下面就开始分析分析代码和运动
的关系了。
4、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 才是 的。轴 对
5、调机心得
下面是 哥的 机的一些心得,与大家分享一下。首先是 机的鸭 调 调
序:顺
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 了哦。 反 几次就基本 好了。这样 复 调
6、后记
本文是 哥的一些心得体会,是个人鸭 对 marlin 有还 rostock 的一
些了解,当然也 会有 那 的 和不足, 哥非常 迎大神许 这样 样 错误 鸭 欢
高手批 指正。本文首 于珠海 客空 网站, 迎 ,著名出评 发 创 间 欢 转载 处。
迎修改,修改的地方用另外的文字著名就可以了。欢

More Related Content

What's hot (15)

竞赛中颁++语言拾遗
竞赛中颁++语言拾遗竞赛中颁++语言拾遗
竞赛中颁++语言拾遗
乐群 陈
?
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹
twMVC
?
基于贬罢惭尝5的肠补苍惫补蝉实例分享
基于贬罢惭尝5的肠补苍惫补蝉实例分享基于贬罢惭尝5的肠补苍惫补蝉实例分享
基于贬罢惭尝5的肠补苍惫补蝉实例分享
xizhilang6688
?
Maze Game
Maze GameMaze Game
Maze Game
blank zheng
?
11.第十一章用惭补迟濒补产计算多元函数的积分
11.第十一章用惭补迟濒补产计算多元函数的积分11.第十一章用惭补迟濒补产计算多元函数的积分
11.第十一章用惭补迟濒补产计算多元函数的积分
Xin Zheng
?
第三章 栈和队列
第三章 栈和队列第三章 栈和队列
第三章 栈和队列
Wang Yizhe
?
Processing 04
Processing 04Processing 04
Processing 04
信嘉 陳
?
06.第六章用惭补迟濒补产计算二重积分
06.第六章用惭补迟濒补产计算二重积分06.第六章用惭补迟濒补产计算二重积分
06.第六章用惭补迟濒补产计算二重积分
Xin Zheng
?
12.第十二章用惭补迟濒补产计算第二类积分
12.第十二章用惭补迟濒补产计算第二类积分12.第十二章用惭补迟濒补产计算第二类积分
12.第十二章用惭补迟濒补产计算第二类积分
Xin Zheng
?
Ian 20151002 es2015
Ian 20151002 es2015Ian 20151002 es2015
Ian 20151002 es2015
LearningTech
?
Ch10 習題
Ch10 習題Ch10 習題
Ch10 習題
hungchiayang1
?
颁程式-函式与巨集
颁程式-函式与巨集颁程式-函式与巨集
颁程式-函式与巨集
艾鍗科技
?
颁语言分支流程
颁语言分支流程颁语言分支流程
颁语言分支流程
吳錫修 (ShyiShiou Wu)
?
竞赛中颁++语言拾遗
竞赛中颁++语言拾遗竞赛中颁++语言拾遗
竞赛中颁++语言拾遗
乐群 陈
?
twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹twMVC#27 | C# 7.0 新功能介紹
twMVC#27 | C# 7.0 新功能介紹
twMVC
?
基于贬罢惭尝5的肠补苍惫补蝉实例分享
基于贬罢惭尝5的肠补苍惫补蝉实例分享基于贬罢惭尝5的肠补苍惫补蝉实例分享
基于贬罢惭尝5的肠补苍惫补蝉实例分享
xizhilang6688
?
11.第十一章用惭补迟濒补产计算多元函数的积分
11.第十一章用惭补迟濒补产计算多元函数的积分11.第十一章用惭补迟濒补产计算多元函数的积分
11.第十一章用惭补迟濒补产计算多元函数的积分
Xin Zheng
?
第三章 栈和队列
第三章 栈和队列第三章 栈和队列
第三章 栈和队列
Wang Yizhe
?
06.第六章用惭补迟濒补产计算二重积分
06.第六章用惭补迟濒补产计算二重积分06.第六章用惭补迟濒补产计算二重积分
06.第六章用惭补迟濒补产计算二重积分
Xin Zheng
?
12.第十二章用惭补迟濒补产计算第二类积分
12.第十二章用惭补迟濒补产计算第二类积分12.第十二章用惭补迟濒补产计算第二类积分
12.第十二章用惭补迟濒补产计算第二类积分
Xin Zheng
?
颁程式-函式与巨集
颁程式-函式与巨集颁程式-函式与巨集
颁程式-函式与巨集
艾鍗科技
?

Similar to Delta (rostock) (20)

EOS_2015_Fall Team1 - 拉亞計畫
EOS_2015_Fall  Team1 - 拉亞計畫EOS_2015_Fall  Team1 - 拉亞計畫
EOS_2015_Fall Team1 - 拉亞計畫
nctusee
?
础谤诲耻颈苍辞程式快速入门
础谤诲耻颈苍辞程式快速入门础谤诲耻颈苍辞程式快速入门
础谤诲耻颈苍辞程式快速入门
吳錫修 (ShyiShiou Wu)
?
第2讲 课件
第2讲  课件第2讲  课件
第2讲 课件
p26chan
?
第2讲 课件
第2讲  课件第2讲  课件
第2讲 课件
p26chan
?
ncuma_pylab.pptx
ncuma_pylab.pptxncuma_pylab.pptx
ncuma_pylab.pptx
NCU MCL
?
础谤谤补测蝉的厂辞谤迟算法分析
础谤谤补测蝉的厂辞谤迟算法分析础谤谤补测蝉的厂辞谤迟算法分析
础谤谤补测蝉的厂辞谤迟算法分析
Zianed Hou
?
矩陣 轉換
矩陣   轉換矩陣   轉換
矩陣 轉換
River Wang
?
程式人杂誌 -- 2014 年7月號
程式人杂誌 -- 2014 年7月號程式人杂誌 -- 2014 年7月號
程式人杂誌 -- 2014 年7月號
鍾誠 陳鍾誠
?
Ch5 範例
Ch5 範例Ch5 範例
Ch5 範例
hungchiayang1
?
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
LearnWeb Taiwan
?
Ppt 1-50
Ppt 1-50Ppt 1-50
Ppt 1-50
hungchiayang1
?
Ch1 教學
Ch1 教學Ch1 教學
Ch1 教學
hungchiayang1
?
Hi Haskell
Hi HaskellHi Haskell
Hi Haskell
Jifeng Deng
?
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍
dennis zhuang
?
数据结构复习笔记 静态链表
数据结构复习笔记 静态链表数据结构复习笔记 静态链表
数据结构复习笔记 静态链表
mengyingchina
?
苍肠耻尘补冲数值积分法.辫辫迟虫
苍肠耻尘补冲数值积分法.辫辫迟虫苍肠耻尘补冲数值积分法.辫辫迟虫
苍肠耻尘补冲数值积分法.辫辫迟虫
NCU MCL
?
Ch7 範例
Ch7 範例Ch7 範例
Ch7 範例
hungchiayang1
?
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
Justin Lin
?
EOS_2015_Fall Team1 - 拉亞計畫
EOS_2015_Fall  Team1 - 拉亞計畫EOS_2015_Fall  Team1 - 拉亞計畫
EOS_2015_Fall Team1 - 拉亞計畫
nctusee
?
第2讲 课件
第2讲  课件第2讲  课件
第2讲 课件
p26chan
?
第2讲 课件
第2讲  课件第2讲  课件
第2讲 课件
p26chan
?
ncuma_pylab.pptx
ncuma_pylab.pptxncuma_pylab.pptx
ncuma_pylab.pptx
NCU MCL
?
础谤谤补测蝉的厂辞谤迟算法分析
础谤谤补测蝉的厂辞谤迟算法分析础谤谤补测蝉的厂辞谤迟算法分析
础谤谤补测蝉的厂辞谤迟算法分析
Zianed Hou
?
程式人杂誌 -- 2014 年7月號
程式人杂誌 -- 2014 年7月號程式人杂誌 -- 2014 年7月號
程式人杂誌 -- 2014 年7月號
鍾誠 陳鍾誠
?
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
D3.js 與 Vue 框架的結合,讓圖表更具表現力(LearnWeb Taiwan Meetup #14)
LearnWeb Taiwan
?
Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍Ihome inaction 篇外篇之fp介绍
Ihome inaction 篇外篇之fp介绍
dennis zhuang
?
数据结构复习笔记 静态链表
数据结构复习笔记 静态链表数据结构复习笔记 静态链表
数据结构复习笔记 静态链表
mengyingchina
?
苍肠耻尘补冲数值积分法.辫辫迟虫
苍肠耻尘补冲数值积分法.辫辫迟虫苍肠耻尘补冲数值积分法.辫辫迟虫
苍肠耻尘补冲数值积分法.辫辫迟虫
NCU MCL
?
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7lambda/closure – JavaScript、Python、Scala 到 Java SE 7
lambda/closure – JavaScript、Python、Scala 到 Java SE 7
Justin Lin
?

Delta (rostock)

  • 1. Delta (rostock 型)3d 打印机算法解读及 调试步骤 1、前言 Delta 机型是一 并 式 的种 联 运动结构 3d 打印机,delta 机型 上实际 是分 大类,一 是工 上用的并 式机器人;另外一 是为两 种 业 联 种 rostock 的 。 做出来的打印机 人的感 都是非运动结构 这两种结构 给 觉 常 cool 的。所以大 都偏好 类型的打印机,目前主流的固件伙 这 marlin 和 repetier 都支持 rostock 的结构 3d 打印机。 里 哥就这 鸭 谈 自己谈 对 rostock 机型的 算法的理解, 而从 算法中推算运动 继 运动 一下如何 一台调试 rostock 的参数。 2、基础知识 要理解 rostock 的全部 算法所要涉及的数学知 不是太多,运动 识 如果不 得的 ,是 候找高中数学老 喝喝茶吃个小 。记 话 时 师 饭啦 1)三角函数 sin cos 个是理解这 rostock 算 程的基 知计 过 础 识 2)笛卡尔空 坐间 标转换/ 性代数, 个嘛是属于 内容,如线 这 进阶
  • 2. 果懂那就更好 ,如果不懂也没 系,在把所有的外界条件全部啦 关 设 置 理想情况下, 个笛卡尔空 坐 可以不用精通的。(包括为 这 间 标转换 哥也不敢 笛卡尔空 坐 和 性代数精通哦)鸭 说对 间 标转换 线 3)marlin 程序的 ( 于结构逻辑结构 对 arduino ide /arduino 程 序基本教程, 里就不展 了,不懂的小白 可以先学一下这 开 们 arduino 的基 教程先, 要一口一口得出,路要一步一步的走)础 饭 3、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 的状态
  • 3. 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]; //这里是算最小回抽值的,如果移动距离小于最小回抽 值就不回抽了。这里是一个辅助功能。简单了解可以了。
  • 4. 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()来 取当前坐获
  • 5. (标 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 三个 机要移 的距离电 动
  • 6. 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);//直线插值
  • 7. 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]的值发送去运动缓存里面 }
  • 8. 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]中,接
  • 9. 下来就是 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("delta x="); 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]。大 随便看一个 的 算伙 轴 换
  • 10. 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 left tower 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 for Deltas #define DELTA // Make delta curves from many straight lines (linear interpolation). // 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, so always have a decimal point in them // Center-to-center distance of the holes in the diagonal push rods.
  • 11. #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 的运动的代码已经通读了一遍。下面就开始分析分析代码和运动 的关系了。 4、Rostock 运动分析 下面是 Rostock 的结构示意图,分析的第一步是简化整个结构,这里就需要将 XY 电 机的两个竖轴投影到 Z 轴的平面上,下图中红色线框画出来的就是 z 轴的平面,同时我们 可以不考虑 XY 电机的推杆的运动情况,因为可以 XY 电机轴的运动可以通过投影在 z 轴平 面上的虚拟轴笛卡尔空间变换转换回去的。
  • 12. 投影好了以后接下来把 z 放平,那么 独考轴 单 虑 z 情况,轴 这 个情况是在坐 原点的标 z 机 与推杆的情况。 了 化 程, 哥电 轴 为 简 过 鸭 已 把经 z 滑 , 平台都 定轴 块 喷头 设 为 0 了。那么,z 机 方向便形电 轴 成了一个三角形,推杆、radius 和 z 机上的 机坐 , 个 候轴电 电 标 这 时 三角函数出来 ! 推杆啦 2 = radius 2 + 机坐电 标 2 在 三角形中推杆这 是不 的,另外三角形始 都会是一个直角三角形。一定要 住 几变 终 记 这 个条件哦。
  • 13. 好, 在我 假 只在现 们 设喷头 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
  • 14. Marlin 中 calculate_delta() 个函数其 就是算这 实 推杆 2 = (destination[x +dX]) 2 + (delta[x-dx]) 2 个等式明白 ,打印件这 啦 X 和轴 Y 的 分析就明白 。轴 运动 啦 另外,再看看打印件 z 的 分析, 是看看源代轴 运动 还 码
  • 15. 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 才是 的。轴 对 5、调机心得 下面是 哥的 机的一些心得,与大家分享一下。首先是 机的鸭 调 调 序:顺 1) 同步 可以选择 轮 选择 GT2 20 齿/40 。因齿 为 GT2 是 2mm 距,整数 可以使脉冲数 整数,同 也 少三角函数 算中浮齿 齿 为 时 减 运 点 算的 力,同 也 化自己的 整步 。运 压 时 简 调 骤 2) 机 先调 时 调 z 方向的精度, 个是直接用同步 和脉轴运动 这 轮 冲数就可以 好的。调 3)z 好以后就 整轴调 调 x 或者轴 Y 的,看看 的路径是不轴 运动 是呈 平面状 ,如果 路径是弧 个 候就要 整现 态 喷头运动 线这 时 调 radius 了,增加或者 少减 radius 的 来 整 路径是一个平面值 调 运动 4)完成上述步 以后就可以 打了, 个 候就可以看看骤 试 这 时 XY
  • 16. 的打印 差是多少了。如果杆 等硬件参数都比 准 的 那打印轴 误 长 较 确 话 差不会有多少的。如果误 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 了哦。 反 几次就基本 好了。这样 复 调 6、后记 本文是 哥的一些心得体会,是个人鸭 对 marlin 有还 rostock 的一 些了解,当然也 会有 那 的 和不足, 哥非常 迎大神许 这样 样 错误 鸭 欢 高手批 指正。本文首 于珠海 客空 网站, 迎 ,著名出评 发 创 间 欢 转载 处。 迎修改,修改的地方用另外的文字著名就可以了。欢