溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

A4988 步進電機加速控制算法的嘗試(下)——MKE06K128實現(xiàn)篇

發(fā)布時間:2020-08-02 04:02:53 來源:網(wǎng)絡(luò) 閱讀:4060 作者:Raevo 欄目:開發(fā)技術(shù)

  之前在arduino上的實現(xiàn)的新的步進電機算法,需要移植到32位MKE06K128上。這個任務(wù)聽上去事實而非,整個Marlin固件還涉及別的部分,比如PID加熱控制模塊,舵機模塊,串口指令讀取代碼。但是我們cocky的Teamleader很反感移植Marlin。沒辦法,這一步我的理解,只要能實現(xiàn)plan_buffer_line就算完成任務(wù)。進一步簡化,只要實現(xiàn)一個軸的plan_buffer_line就算完成任務(wù)。


硬件連接部分:


  我們cocky的Teamleader是個能干的人,很快畫出并焊好了MKE06K128的電路板供我當(dāng)作開發(fā)板使用。Freescale有基于eclipse的專用開發(fā)環(huán)境Kinetis Design Studio,簡稱KDS,KDS既集成了MKE的交叉編譯器,而且以插件的形式提供了“專家系統(tǒng)”,能夠可視化的配置硬件管腳,并且生成示意圖方便review(如下圖),看上去很酷。


A4988 步進電機加速控制算法的嘗試(下)——MKE06K128實現(xiàn)篇A4988 步進電機加速控制算法的嘗試(下)——MKE06K128實現(xiàn)篇

  這個專家工具在調(diào)試硬件和快速實現(xiàn)階段也非常方便。我在電路板上接上Jlink,并且連接上A4988和步進電機,在排除掉A4988的損壞之后。編寫一個簡答的定時器程序,并把周期寫成3.2KHz(請參考arduino上的實現(xiàn)中關(guān)于3.2K的來歷),步進電機就應(yīng)該以1rad/s的速度轉(zhuǎn),如果不是,就要用示波器和萬用表排除芯片,電路板,電源和Jlink的故障可能。如果是,就為下一步編寫固件代碼打下了堅實的基礎(chǔ)。最終調(diào)試好的硬件連接圖如下:

A4988 步進電機加速控制算法的嘗試(下)——MKE06K128實現(xiàn)篇


使用jlink時注意,

  • 在系統(tǒng)上電的情況下,需要去掉jlink上供電的跳線帽,否則無法進行刷寫工作。

  • 即使脈沖寬度很窄,也可以驅(qū)動電機,而且窄脈沖的噪音很小。

  • A4988的EN路上拉到電路5V,需要軟件將其拉低,步進電機才能正常驅(qū)動,否則驅(qū)動電路不使能。


軟件實現(xiàn)部分:


  首先實現(xiàn)plan_buffer_line()函數(shù),需要編寫%Planner和%Stepper兩個模塊。前者管理隊列,后者管理步進電機的中斷響應(yīng)驅(qū)動。和Marlin固件的區(qū)別在于,這里的%Planner不必計算執(zhí)行的各個速度節(jié)點,而是只需要設(shè)置穩(wěn)定后的速度值,%Stepper會動態(tài)的計算出瞬時速度。

  隊列和隊列指針都在%Planner模塊中定義為全局變量,由于聲明了external 關(guān)鍵字,當(dāng)其他項目包含planner.h時就會引入該變量,即等效于該全局變量為全項目全局變量。

%Planner.cpp中:

block_t block_buffer[BLOCK_BUFFER_SIZE];
volatile unsigned char block_buffer_head; volatile unsigned char block_buffer_tail;

  另外設(shè)置了幾個強制內(nèi)聯(lián)函數(shù):

 FORCE_INLINE block_t *plan_get_current_block();//讀取當(dāng)前block函數(shù)
 FORCE_INLINE bool blocks_queued() { return (block_buffer_head != block_buffer_tail); }//隊列是否非空

  在這里:

#define FORCE_INLINE attribute((always_inline)) inline

  告訴編譯器,設(shè)置為強制內(nèi)聯(lián)型;對于此,Cpp的語法解釋是:

inline關(guān)鍵字僅僅是建議編譯器做內(nèi)聯(lián)展開處理,而不是強制。在gcc編譯器中,如果編譯優(yōu)化設(shè)置為-O0,即使是inline函數(shù)也不會被內(nèi)聯(lián)展開,除非設(shè)置了強制內(nèi)聯(lián)(attribute((always_inline)))屬性。

  關(guān)于內(nèi)聯(lián)函數(shù),補充一點基礎(chǔ)知識:

在內(nèi)聯(lián)函數(shù)內(nèi)不允許用循環(huán)語句和開關(guān)語句。否則會被編譯器當(dāng)作普通函數(shù)。

  在%stepper.cpp中定義了:

 block_t *current_block  //當(dāng)前運動實例

  由于沒有在stepper.h中定義相應(yīng)的extern 類型,所以該變量為模塊內(nèi)的private全局變量。

  即使是使用32位單片機,也不應(yīng)該在中斷響應(yīng)函數(shù)中進行浮點運算,否則中斷頻率會被大大拖慢。所以%stepper函數(shù)的最終結(jié)果為:

void ST_PULSE_TI_OnInterrupt(void) {
	/* Write your code here ... */
#ifndef HARDWARE_DEBUG_MODE

	if (!current_block) {
		current_block = plan_get_current_block();
	}

#define DISTANCE_COUNT_RESET current_block->rounds_count_per_mstep-=current_block->one_micro_step_mm
#define DISTANCE_IS_ONESTEP  current_block->rounds_count_per_mstep>=current_block->one_micro_step_mm
#define DRIVE_PULSE E0_STE_SetVal();	\
		E0_STE_ClrVal()
	/*==========generate a pulse when a step accumulated===========*/

	if (DISTANCE_IS_ONESTEP) {
		DRIVE_PULSE;
		DISTANCE_COUNT_RESET;
	}


	/*update the new speed and  ... */

	if (current_block) {
		if (current_block->rounds_behind + current_block->rounds_ahead
				< current_block->rounds) {
			// accumulate the rounds and the microstep_count_for_rounds

			current_block->rounds_behind += current_block->instance_rate;
			current_block->rounds_count_per_mstep +=current_block->instance_rate;

			//when speed climbing up case
			if (current_block->instance_rate < current_block->nominal_rate) {
				current_block->instance_rate += current_block->acceleration;
			}

			//when hold the nominal_rate case
			else {
				//make sure the rate remains nominal_rate
				current_block->instance_rate = current_block->nominal_rate;
			}

			// update the rounds left for all the three case.
			current_block->rounds_ahead=current_block->instance_rate/2/current_block->acceleration*current_block->instance_rate;
		}
		//when speed slipping down case

		else if (current_block->instance_rate > current_block->exit_rate) {
			current_block->rounds_behind+= current_block->instance_rate;
			current_block->rounds_count_per_mstep +=current_block->instance_rate;
			current_block->instance_rate -= current_block->acceleration;
		}

		// at the end of the block

		else if (current_block->instance_rate <= current_block->exit_rate) {
			current_block->instance_rate = 0;
			current_block->nominal_rate = 0;
			current_block->rounds_ahead = 0;
			current_block->acceleration = 0;
			current_block->rounds = 0;
			current_block->rounds_count_per_mstep = 0;
			//ST_PULSE_TI_Disable();//current_block should update
			current_block = NULL;
		}

	}

#endif

}

  浮點數(shù)主要來自兩方面,一是每個中斷響應(yīng)函數(shù)中的單位時間delta t;另一個是轉(zhuǎn)每秒這個單位中,轉(zhuǎn)往往是小數(shù)。為了消滅浮點數(shù),我們對單位進行了轉(zhuǎn)換:

void plan_buffer_line(const float e, float feed_rate) {
//void plan_buffer_line(const float x, const float y, const float z, const float e, float feed_rate, const uint8_t extruder){
// e is unit of round
// feedrate is unit of round per second
// push a block into pipeline
	block_t *block = &block_buffer[block_buffer_head];
	//update the ini value of the block
	block->nominal_rate =(unsigned int)(feed_rate*ST_PULSE_FREQ);
	block->rounds = (unsigned int)(e - position[E_AXIS])*FLOAT_FACTOR;
	block->entry_rate = 0;
	block->exit_rate = 0;
	block->acceleration = (unsigned int)(DEFAULT_ACCELERATION);
	block->direction_bits = e > position[E_AXIS] ? 1 : 0;
	block->one_micro_step_mm=(unsigned int)FLOAT_FACTOR/MICROSTEP/RESOLUTION;
	ST_PULSE_TI_Enable();
	//Enable the Interruption for stepper control and plannerS
	// Move buffer head
	block_buffer_head = next_block_index(block_buffer_head);
	//block_buffer_head=block_buffer_head+1;
	// Update position
	position[E_AXIS] = e;

 }

  其中,在configuration.h中定義了轉(zhuǎn)換宏:

#define ST_PULSE_FREQ 10000

#define FLOAT_FACTOR (ST_PULSE_FREQ*ST_PULSE_FREQ)

  由此可見,為了在計時器中斷響應(yīng)函數(shù)中不出現(xiàn)浮點數(shù),必須要給位移,速度和加速度乘以一個因子。而為了防止程序中出現(xiàn)變量超出整型大小而溢出,計時器頻率不能太高。具體的范圍,又受限于打印機的位移范圍(往往是0~200mm)。這種算法,數(shù)據(jù)結(jié)構(gòu)和處理器浮點運算性能局限性的共同作用,產(chǎn)生了最終的代碼,非常的經(jīng)典。

正是由于Team leader質(zhì)疑修改步進電機算法,我才能發(fā)現(xiàn)這么多隱藏在理所當(dāng)然中的深刻限制和工程智慧,感謝他的偏執(zhí)。同時我更加深刻理解了Marlin固件中步進電機算法的合理和經(jīng)典。

(完)

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI