Delta (rostock型)3d打印機(jī)算法解讀及調(diào)試步驟 一、前言 Delta機(jī)型是一種并聯(lián)式運(yùn)動(dòng)結(jié)構(gòu)的3d打印機(jī),delta機(jī)型實(shí)際上是分為兩大類,一種是工業(yè)上用的并聯(lián)式機(jī)器人;另外一種是rostock 的運(yùn)動(dòng)結(jié)構(gòu)。這兩種結(jié)構(gòu)做出來(lái)的打印機(jī)給人的感覺都是非常cool的。所以大伙都偏好這類型的打印機(jī),目前主流的固件marlin 和repetier都支持rostock結(jié)構(gòu)的3d打印機(jī)。這里鴨哥就談?wù)勛约簩?duì)rostock機(jī)型的運(yùn)動(dòng)算法的理解,繼而從運(yùn)動(dòng)算法中推算一下如何調(diào)試一臺(tái)rostock的參數(shù)。 二、基礎(chǔ)知識(shí) 要理解rostock的全部運(yùn)動(dòng)算法所要涉及的數(shù)學(xué)知識(shí)不是太多,如果不記得的話,是時(shí)候找高中數(shù)學(xué)老師喝喝茶吃個(gè)小飯啦。 1)三角函數(shù) sin cos 這個(gè)是理解rostock計(jì)算過(guò)程的基礎(chǔ)知識(shí) 2)笛卡爾空間坐標(biāo)轉(zhuǎn)換/線性代數(shù),這個(gè)嘛是屬于進(jìn)階內(nèi)容,如果懂那就更好啦,如果不懂也沒(méi)關(guān)系,在把所有的外界條件全部設(shè)置為理想情況下,這個(gè)笛卡爾空間坐標(biāo)轉(zhuǎn)換可以不用精通的。(包括鴨哥也不敢說(shuō)對(duì)笛卡爾空間坐標(biāo)轉(zhuǎn)換和線性代數(shù)精通哦) 3)marlin程序的結(jié)構(gòu)邏輯結(jié)構(gòu)(對(duì)于arduino ide /arduino程序基本教程,這里就不展開了,不懂的小白們可以先學(xué)一下arduino的基礎(chǔ)教程先,飯要一口一口得出,路要一步一步的走) 三、Marlin程序解讀這里鴨哥不打算講marlin的整個(gè)loop()函數(shù)的流程,講講delta機(jī)型的核心部分。對(duì)于marlin來(lái)說(shuō),delta機(jī)型和非delta機(jī)型在對(duì)于溫控、看門狗、電機(jī)運(yùn)動(dòng)甚至空間坐標(biāo)等方面都是一樣的。區(qū)別在哪里呢?區(qū)別就在與delta多了一個(gè)笛卡爾坐標(biāo)轉(zhuǎn)換的函數(shù) Marlin的loop()主體流程 Void loop () { Get_command() ; //從sd卡或者串口獲取gcode Process_command(); //解析gcode并且執(zhí)行代碼 Manage_heater();//控制機(jī)器的噴頭和熱床的溫度 Manage_inactivity();// checkHitEndstops();//檢查endstop的狀態(tài) Lcd_update(); //更新lcd 上面的信息 }
在這個(gè)過(guò)程中 process_command()是控制的核心,各位仔細(xì)研讀一下process_command()的代碼就發(fā)現(xiàn)arduino的厲害了。簡(jiǎn)單說(shuō)一下process_command()的流程,說(shuō)白了,process_command()就是一個(gè)巨大的case 結(jié)構(gòu),這里講講G1命令的大致邏輯(G1命令不知道的自己搜索去): Process_command() { Case 0: //g0->g1 Case 1 : { if(Stopped == false) { get_coordinates(); // 獲取當(dāng)前的坐標(biāo),這里是指打印件的世界坐標(biāo)哦,不是delta的xyz電機(jī)的坐標(biāo)哦!普通結(jié)構(gòu)的打印機(jī)則是一樣的。 #ifdef FWRETRACT if(autoretract_enabled) if( !(code_seen('X') ||code_seen('Y') || code_seen('Z')) && code_seen('E')) { //獲取 命令中 xyze軸的參數(shù) Float echange=destination[E_AXIS]-current_position[E_AXIS];//這里是算最小回抽值的,如果移動(dòng)距離小于最小回抽值就不回抽了。這里是一個(gè)輔助功能。簡(jiǎn)單了解可以了。 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(); //執(zhí)行移動(dòng)命令
return; } } 從上面的代碼來(lái)看呢,對(duì)于運(yùn)動(dòng)類的Gcode,marlin會(huì)在process_command()函數(shù)中獲取xyze各軸的參數(shù)后算出目標(biāo)坐標(biāo)(destination[_AXIS]),也會(huì)使用get_coordinates()來(lái)獲取當(dāng)前坐標(biāo)(current_position[E_AXIS])(再次強(qiáng)調(diào),這個(gè)坐標(biāo)是打印件的世界坐標(biāo)),當(dāng)我們知道了目標(biāo)坐標(biāo)和當(dāng)前坐標(biāo)以后,空間中移動(dòng)的距離就可以算出來(lái)了(不會(huì)算的,請(qǐng)自覺請(qǐng)高中數(shù)學(xué)老師吃飯去),接下來(lái)marlin就使用perpare_move()來(lái)控制電機(jī)啦。 接下來(lái)呢很自然就要講講prepare_move()這個(gè)函數(shù)啦。先上代碼先,代碼鴨哥做了精簡(jiǎn),只看關(guān)鍵的部分就是delta和普通結(jié)構(gòu)的代碼,先說(shuō)一下plan_buffer_line()這個(gè)函數(shù)的作用的把坐標(biāo)數(shù)組current_position、 destination 放到一個(gè)內(nèi)存的一個(gè)緩存區(qū)里面,然后控制電機(jī)轉(zhuǎn)多少圈這樣一個(gè)作用的,具體代碼可以自己去看,在一旦進(jìn)入這個(gè)函數(shù)以后,delta和普通機(jī)型的代碼都是一樣的,也就是說(shuō)delta和普通結(jié)構(gòu)的電機(jī)控制其實(shí)是一樣的。 Difference數(shù)組 :用來(lái)儲(chǔ)存目標(biāo)坐標(biāo)和當(dāng)前坐標(biāo)之間的距離的,(這里是包含了xyze軸的數(shù)組) Destination數(shù)組:目標(biāo)坐標(biāo)的數(shù)值,是從process_command()函數(shù)中G1讀取XYZE參數(shù)獲取的。 Current_position數(shù)組:當(dāng)前坐標(biāo)的數(shù)值,是從G1 命令中g(shù)et_coordinates()傳遞過(guò)來(lái)的。如果是3個(gè)軸都?xì)w零的情況下,current_position就是儲(chǔ)存三個(gè)坐標(biāo)原點(diǎn),如果開始運(yùn)動(dòng)了,這里的值就是上一個(gè)prepare_move()循環(huán)執(zhí)行后上一次的destination的值。(這個(gè)下面會(huì)有看到賦值語(yǔ)句) Delta數(shù)組:delta打印機(jī)的xyz三個(gè)電機(jī)要移動(dòng)的距離
void prepare_move() {
#ifdef DELTA //設(shè)置機(jī)子是delta機(jī)型(rostock) float difference[NUM_AXIS]; //定義目標(biāo)距離,用于轉(zhuǎn)換坐標(biāo)用的過(guò)渡變量 for (int8_t i=0; i < NUM_AXIS; i++) { difference = destination - current_position; } //計(jì)算世界坐標(biāo)的距離值 //***開始計(jì)算笛卡爾距離 并且暴力直線插值來(lái)減少運(yùn)算量***// 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; } //***結(jié)束計(jì)算笛卡爾距離 并且暴力直線插值來(lái)減少運(yùn)算量***// calculate_delta(destination);//將打印件的世界坐標(biāo)轉(zhuǎn)換為xyz電機(jī)軸的運(yùn)動(dòng)量 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的值發(fā)送去運(yùn)動(dòng)緩存里面 } 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; //更新當(dāng)前坐標(biāo)的值為剛執(zhí)行的目標(biāo)坐標(biāo)值 } } 好,看了一大段代碼后小結(jié)一下。對(duì)于普通結(jié)構(gòu)來(lái)說(shuō),G1 每次將新讀取gcode代碼參數(shù)傳遞給prepare_move()函數(shù)中destination數(shù)組以后,prepare_move()就會(huì)將其傳遞到plan_buffer_line()進(jìn)行電機(jī)的運(yùn)動(dòng)。而delta結(jié)構(gòu)呢,就相對(duì)復(fù)雜一點(diǎn),G1命令讀取了gcode代碼參數(shù)后也是傳遞到prepare_move()函數(shù)中destination,然后marlin要計(jì)算目標(biāo)坐標(biāo)與當(dāng)前坐標(biāo)的笛卡爾距離,然后通過(guò)固定時(shí)間間隔的方式來(lái)將笛卡爾距離分成若干個(gè)小直線,通過(guò)這樣的方式來(lái)就減少cpu的浮點(diǎn)預(yù)算量,然后再通過(guò)calculate_delta函數(shù)來(lái)將簡(jiǎn)化后的destination換算成三個(gè)電機(jī)的運(yùn)動(dòng)坐標(biāo),并傳遞到delta中,接下來(lái)就是plan_buffer_line()了。 最后!到了最后了!來(lái)看看calculate_delta()函數(shù),這個(gè)函數(shù)的主要用途是將打印件的世界坐標(biāo)轉(zhuǎn)換為三個(gè)垂直的電機(jī)軸的運(yùn)動(dòng)坐標(biāo)哦。注意:新的marlin支持SCARA結(jié)構(gòu)的delta,那里也有個(gè)calculate_delta()的函數(shù),不過(guò)那個(gè)跟rostock有點(diǎn)差異。所以我們還是看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]); */ }
代碼很簡(jiǎn)單delta是指電機(jī)軸的運(yùn)動(dòng)坐標(biāo),cartesian是指打印件的世界坐標(biāo),從上面的程序來(lái)看就是從prepare_move()中經(jīng)過(guò)插值簡(jiǎn)化的destination。大伙隨便看一個(gè)軸的換算 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 是推桿長(zhǎng)的平方 delta_tower1_x 是左前柱的x坐標(biāo)值,是由radius這個(gè)參數(shù)算出來(lái)的 delta_tower1_y 是左前柱的y坐標(biāo)值,是由radius這個(gè)參數(shù)算出來(lái)的 具體怎么算就看下面這個(gè)函數(shù) 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機(jī)型參數(shù)是需要什么? 推桿的長(zhǎng)度、電機(jī)軸上滑塊的寬度、噴頭支架的寬度,還有三個(gè)電機(jī)的圓半徑。對(duì)不對(duì)?忘了?!不要緊,給你看看代碼 //================================================================= //========================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 //桿長(zhǎng)
// Horizontal offset from middle of printer to smooth rod center. #define DELTA_SMOOTH_ROD_OFFSET 175.0 // mm //電機(jī)軸的圓半徑
// Horizontal offset of the universal joints on the end effector. #define DELTA_EFFECTOR_OFFSET 33.0 // mm // 裝噴嘴的平臺(tái)的中心到桿連接處的距離
// Horizontal offset of the universal joints on the carriages. #define DELTA_CARRIAGE_OFFSET 18.0 // mm //電機(jī)軸滑塊的距離
// Effective horizontal distance bridged by diagonal push rods. #define DELTA_RADIUS(DELTA_SMOOTH_ROD_OFFSET-DELTA_EFFECTOR_OFFSET-DELTA_CARRIAGE_OFFSET) 通過(guò)上述的參數(shù)可以算出一個(gè)DELTA_RADIUS,這個(gè)delta_radius就是上面“delta_tower1_x 是左前柱的x坐標(biāo)值,是由radius這個(gè)參數(shù)算出來(lái)的”里面的radius了。 至此所有有關(guān)與delta的運(yùn)動(dòng)的代碼已經(jīng)通讀了一遍。下面就開始分析分析代碼和運(yùn)動(dòng)的關(guān)系了。
四、Rostock運(yùn)動(dòng)分析下面是Rostock的結(jié)構(gòu)示意圖,分析的第一步是簡(jiǎn)化整個(gè)結(jié)構(gòu),這里就需要將XY電機(jī)的兩個(gè)豎軸投影到Z軸的平面上,下圖中紅色線框畫出來(lái)的就是z軸的平面,同時(shí)我們可以不考慮XY電機(jī)的推桿的運(yùn)動(dòng)情況,因?yàn)榭梢訶Y電機(jī)軸的運(yùn)動(dòng)可以通過(guò)投影在z軸平面上的虛擬軸笛卡爾空間變換轉(zhuǎn)換回去的。 投影好了以后接下來(lái)把z軸放平,那么單獨(dú)考慮z軸情況,這個(gè)情況是在坐標(biāo)原點(diǎn)的z電機(jī)軸與推桿的情況。為了簡(jiǎn)化過(guò)程,鴨哥已經(jīng)把z軸滑塊,噴頭平臺(tái)都設(shè)定為0 了。那么,z電機(jī)軸方向便形成了一個(gè)三角形,推桿、radius和z軸電機(jī)上的電機(jī)坐標(biāo),這個(gè)時(shí)候三角函數(shù)出來(lái)啦! 推桿2 = radius 2+ 電機(jī)坐標(biāo) 2 在這三角形中推桿是不變的,另外三角形始終都會(huì)是一個(gè)直角三角形。一定要記住這幾個(gè)條件哦。 好,現(xiàn)在我們假設(shè)噴頭只在x軸上運(yùn)動(dòng),z軸y軸都不動(dòng)。如果打印件的世界坐標(biāo)移動(dòng)dX距離,rostock需要考慮的問(wèn)題就是怎么講dX轉(zhuǎn)換為z軸電機(jī)的移動(dòng)距離了。下圖就是用來(lái)表示這種情況。由于推桿長(zhǎng)度是不變的,那么 推桿2 = radius 2+ 電機(jī)坐標(biāo) 2 就變成下面這樣 推桿2 = (radius +dX)2+ (電機(jī)坐標(biāo)-dx) 2 Radius的距離換成destination[x],電機(jī)坐標(biāo)換成delta[x] 推桿2 = (destination[x +dX])2+(delta[x-dx]) 2
Marlin中calculate_delta()這個(gè)函數(shù)其實(shí)就是算 推桿2 = (destination[x +dX])2+(delta[x-dx]) 2 這個(gè)等式明白啦,打印件X軸和Y軸的運(yùn)動(dòng)分析就明白啦。 另外,再看看打印件z軸的運(yùn)動(dòng)分析,還是看看源代碼 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]是沒(méi)有在sqrt函數(shù)里面的,而是直接加在delta[x]的值上面的。 所以,在調(diào)機(jī)的時(shí)候應(yīng)該先調(diào)z軸,這里就是原因。因?yàn)樵赬YZ三個(gè)軸的坐標(biāo)中只有Z軸是直接通過(guò)同步輪和電機(jī)脈沖就可以調(diào)準(zhǔn)的。調(diào)準(zhǔn)了z軸以后再調(diào)XY軸才是對(duì)的。 五、調(diào)機(jī)心得下面是鴨哥的調(diào)機(jī)的一些心得,與大家分享一下。首先是調(diào)機(jī)的順序: 1)選擇同步輪可以選擇GT2 20齒/40齒 。因?yàn)镚T2是2mm齒距,整數(shù)齒可以使脈沖數(shù)為整數(shù),同時(shí)也減少三角函數(shù)運(yùn)算中浮點(diǎn)運(yùn)算的壓力,同時(shí)也簡(jiǎn)化自己的調(diào)整步驟。 2)調(diào)機(jī)時(shí)先調(diào)z軸運(yùn)動(dòng)方向的精度,這個(gè)是直接用同步輪和脈沖數(shù)就可以調(diào)好的。 3)z軸調(diào)好以后就調(diào)整x軸或者Y軸的,看看運(yùn)動(dòng)的路徑是不是呈現(xiàn)平面狀態(tài),如果噴頭運(yùn)動(dòng)路徑是弧線這個(gè)時(shí)候就要調(diào)整radius了,增加或者減少radius的值來(lái)調(diào)整運(yùn)動(dòng)路徑是一個(gè)平面 4)完成上述步驟以后就可以試打了,這個(gè)時(shí)候就可以看看XY軸的打印誤差是多少了。如果桿長(zhǎng)等硬件參數(shù)都比較準(zhǔn)確的話那打印誤差不會(huì)有多少的。如果XY軸有誤差的話就要根據(jù)誤差大小來(lái)等量調(diào)整radius這個(gè)變量。對(duì)應(yīng)代碼是 // Horizontal offset from middle of printer to smooth rod center. #define DELTA_SMOOTH_ROD_OFFSET 175.0 // mm //電機(jī)軸的圓半徑
等量修改,比如X軸偏大0.1mm,那么 調(diào)整量就是175.0-0.1= 174.9 了哦。這樣反復(fù)幾次就基本調(diào)好了。
六、后記 本文是鴨哥的一些心得體會(huì),是個(gè)人對(duì)marlin還有rostock的一些了解,當(dāng)然也許會(huì)有這樣那樣的錯(cuò)誤和不足,鴨哥非常歡迎大神高手批評(píng)指正。本文首發(fā)于珠海創(chuàng)客空間網(wǎng)站,歡迎轉(zhuǎn)載,著名出處。歡迎修改,修改的地方用另外的文字著名就可以了。
|
你可能喜歡
開源3D建模軟件FreeCAD 1.0正式發(fā)布,支持W
人工智能與3D打印技術(shù)結(jié)合,實(shí)現(xiàn)小型核反應(yīng)
最新《Nature》:動(dòng)態(tài)界面3D打印
石墨烯增強(qiáng)混凝土能否推動(dòng)可持續(xù)建筑? UVA
推薦課程
神奇的3D打印
SLA3D打印工藝全套培訓(xùn)課程 - 軟件篇
3D打印月球燈視頻教程 包括完整貼圖建模流
【原創(chuàng)發(fā)布】Cura軟件修改二次開發(fā)定制視頻