文獻(xiàn)標(biāo)識(shí)碼: B
文章編號(hào): 0258-7998(2012)08-0033-04
隨著數(shù)字信息技術(shù)的不斷發(fā)展,人們對(duì)伺服控制系統(tǒng)的實(shí)時(shí)性、穩(wěn)定性和復(fù)雜性的要求越來(lái)越高,單靠順序結(jié)構(gòu)的軟件設(shè)計(jì)已經(jīng)不容易滿(mǎn)足上述要求。目前很多伺服控制系統(tǒng)的控制器采用PC/104結(jié)構(gòu)或依賴(lài)上位計(jì)算機(jī),根據(jù)實(shí)際的控制系統(tǒng)需要擴(kuò)展相應(yīng)的控制電路,使得系統(tǒng)體積大、成本高、可靠性不易保證,且用戶(hù)交互性不好。嵌入式Linux操作系統(tǒng)由于具有代碼開(kāi)源、可移植性、軟硬件可裁剪性、資源豐富及支持多種硬件平臺(tái)和接口等特點(diǎn),并且從2.6版本以后的Linux實(shí)時(shí)性有了很大的提高,正被越來(lái)越多地應(yīng)用于伺服控制系統(tǒng)中。通過(guò)嵌入式Linux操作系統(tǒng)對(duì)控制系統(tǒng)的軟硬件資源進(jìn)行分配、調(diào)度、控制和協(xié)調(diào),能夠充分發(fā)揮控制系統(tǒng)的性能。ARM處理器以其體積小、低功耗、低成本、高性能、文檔豐富及嵌入式軟件多等優(yōu)點(diǎn)而得到廣泛的應(yīng)用。因此,本文以ARM9和CPLD為硬件平臺(tái),在嵌入式Linux操作系統(tǒng)下設(shè)計(jì)了直流伺服控制系統(tǒng)。
1 硬件平臺(tái)
系統(tǒng)原理框圖[1]如圖1所示。系統(tǒng)以ARM作為主控芯片,主要負(fù)責(zé)運(yùn)行操作系統(tǒng)并實(shí)現(xiàn)控制算法、人機(jī)交互和多機(jī)通信等。CPLD EPM570T144主要負(fù)責(zé)從ARM接收數(shù)據(jù),產(chǎn)生相應(yīng)的PWM波;接收編碼器輸出信號(hào),并對(duì)其進(jìn)行處理,得到編碼器的值,將其送給ARM,從而實(shí)現(xiàn)電機(jī)的閉環(huán)控制。CPLD和ARM之間通過(guò)地址總線(xiàn)(13根)、數(shù)據(jù)總線(xiàn)(16根)、控制總線(xiàn)(片選、讀寫(xiě)使能信號(hào)等)與GPIO口(作為外部中斷使用)連接,即CPLD類(lèi)似于ARM的一個(gè)外部存儲(chǔ)器(CPLD掛接在ARM的bank1存儲(chǔ)空間上,地址空間為0x08000000~0x10000000),ARM和CPLD的數(shù)據(jù)交換類(lèi)似于對(duì)存儲(chǔ)器的讀寫(xiě)操作。這種總線(xiàn)方式擴(kuò)展,使得系統(tǒng)數(shù)據(jù)交換快速、操作簡(jiǎn)單。控制板通過(guò)JTAG、UART、USB和網(wǎng)口與上位機(jī)連接,在目標(biāo)板和上位機(jī)之間建立交叉開(kāi)發(fā)環(huán)境,可在控制板和上位機(jī)之間實(shí)現(xiàn)程序下載調(diào)試、文件傳輸和通信等,便于系統(tǒng)軟件開(kāi)發(fā)和調(diào)試。
2 CPLD程序設(shè)計(jì)
CPLD程序分為電機(jī)辨向、四倍頻、編碼器脈沖計(jì)數(shù)、PWM波生成和總線(xiàn)數(shù)據(jù)讀寫(xiě)5個(gè)模塊,如圖2所示。采用VHDL語(yǔ)言,依據(jù)自底向上設(shè)計(jì)的方法,以便于程序開(kāi)發(fā)和移植。
采用增量式編碼器,需對(duì)編碼器輸出的ABZ碼進(jìn)行處理[2],經(jīng)過(guò)辨向、倍頻、計(jì)數(shù)后得到編碼器值。ARM與CPLD之間通過(guò)雙向總線(xiàn)交換數(shù)據(jù),CPLD讀取ARM寫(xiě)入數(shù)據(jù)總線(xiàn)的數(shù)據(jù),產(chǎn)生對(duì)應(yīng)的PWM波。當(dāng)CPLD中的編碼器值可讀后,CPLD采用中斷方式通知ARM,然后將編碼器值寫(xiě)到數(shù)據(jù)總線(xiàn)上供ARM讀取。由于CPLD與ARM的其他外設(shè)共用數(shù)據(jù)總線(xiàn),所以在CPLD對(duì)總線(xiàn)進(jìn)行操作時(shí)要特別注意,除了CPLD往總線(xiàn)上寫(xiě)數(shù)據(jù)外,其他時(shí)刻都應(yīng)該將總線(xiàn)置為高阻態(tài),以讓出總線(xiàn)的使用權(quán),否則其他外設(shè)(如網(wǎng)口、ADC接口等)會(huì)因CPLD一直占用總線(xiàn)而不能正常工作。
CPLD應(yīng)用計(jì)數(shù)法產(chǎn)生PWM波[3],CPLD時(shí)鐘頻率為100 MHz,設(shè)置PWM總計(jì)數(shù)值為8 000。CPLD根據(jù)ARM給定的0~8 000的計(jì)數(shù)值對(duì)時(shí)鐘計(jì)數(shù),產(chǎn)生兩路反相的PWM波。為防止功率放大器的H橋同一側(cè)上下同時(shí)導(dǎo)通,一般設(shè)置有3~5 μs的死區(qū),本設(shè)計(jì)中設(shè)置為5 μs的死區(qū)。
3 設(shè)備驅(qū)動(dòng)設(shè)計(jì)
3.1 設(shè)備驅(qū)動(dòng)簡(jiǎn)介
設(shè)備驅(qū)動(dòng)是連接應(yīng)用程序與硬件設(shè)備的橋梁,驅(qū)動(dòng)程序?yàn)閼?yīng)用程序提供了接口函數(shù),用戶(hù)在應(yīng)用程序中調(diào)用相應(yīng)的接口函數(shù)便可實(shí)現(xiàn)對(duì)硬件設(shè)備的操作,因此,驅(qū)動(dòng)程序的開(kāi)發(fā)是嵌入式系統(tǒng)開(kāi)發(fā)的關(guān)鍵環(huán)節(jié)。Linux設(shè)備驅(qū)動(dòng)分為字符設(shè)備驅(qū)動(dòng)、塊設(shè)備驅(qū)動(dòng)和網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)[4]。本文中控制板上移植了Linux2.6操作系統(tǒng),該操作系統(tǒng)下需設(shè)計(jì)ARM讀寫(xiě)CPLD的數(shù)據(jù)及對(duì)CPLD產(chǎn)生的中斷信號(hào)響應(yīng)的驅(qū)動(dòng),這一要求采用字符設(shè)備驅(qū)動(dòng)來(lái)實(shí)現(xiàn)。應(yīng)用程序通過(guò)系統(tǒng)調(diào)用對(duì)設(shè)備文件進(jìn)行諸如read、write等操作時(shí),系統(tǒng)調(diào)用通過(guò)設(shè)備文件的主設(shè)備號(hào)找到相應(yīng)的設(shè)備驅(qū)動(dòng)程序,然后讀取設(shè)備驅(qū)動(dòng)程序中初始化的file_operations結(jié)構(gòu)體,獲取相應(yīng)操作(read/write等)對(duì)應(yīng)的函數(shù)指針,接著把控制權(quán)交給該函數(shù)。因此,編寫(xiě)設(shè)備驅(qū)動(dòng)程序的主要工作就是編寫(xiě)這些文件操作的接口函數(shù),并填充file_operations的各個(gè)域。
3.2 設(shè)備驅(qū)動(dòng)程序設(shè)計(jì)
為便于開(kāi)發(fā)和調(diào)試,設(shè)備驅(qū)動(dòng)使用模塊的方式動(dòng)態(tài)加載到內(nèi)核中去。加載模塊的方式與以往的應(yīng)用程序開(kāi)發(fā)有很大的不同。以往在開(kāi)發(fā)應(yīng)用程序時(shí)都有一個(gè)main()函數(shù)作為程序的入口點(diǎn),而在驅(qū)動(dòng)開(kāi)發(fā)時(shí)卻沒(méi)有main()函數(shù),模塊在調(diào)用insmod命令時(shí)被加載,此時(shí)的入口點(diǎn)為module_init()函數(shù),在該函數(shù)中完成設(shè)備的注冊(cè)、設(shè)備文件的創(chuàng)建和相關(guān)內(nèi)存及寄存器的地址映射。同樣,模塊在調(diào)用rmmod命令時(shí)被卸載,此時(shí)的入口點(diǎn)為module_exit()函數(shù),在該函數(shù)中將不用的資源返還給操作系統(tǒng),把注冊(cè)的設(shè)備、創(chuàng)建的設(shè)備文件及IO內(nèi)存映射等注銷(xiāo)掉。在設(shè)備完成注冊(cè)和加載之后,用戶(hù)的應(yīng)用程序就可以對(duì)該設(shè)備進(jìn)行一定的操作,如read、write等。而驅(qū)動(dòng)就是用于實(shí)現(xiàn)這些操作,在用戶(hù)應(yīng)用程序調(diào)用相應(yīng)入口函數(shù)時(shí)執(zhí)行相關(guān)的操作,module_init()入口點(diǎn)函數(shù)則不需要完成其他如read、wirte之類(lèi)的功能。驅(qū)動(dòng)程序需要定義和實(shí)現(xiàn)open、read、write等函數(shù),并填充到file_operations結(jié)構(gòu)中,file_operations結(jié)構(gòu)把應(yīng)用程序中的系統(tǒng)調(diào)用與驅(qū)動(dòng)中對(duì)應(yīng)的函數(shù)聯(lián)系在一起。file_operations結(jié)構(gòu)體如下所示:
static struct file_operations cpld_drv_fops = {
.owner = THIS_MODULE,
.write = cpld_drv_write,
.read = cpld_drv_read,
.open = cpld_drv_open,
.release = cpld_drv_close,
.fasync = cpld_drv_fasync,
};
其中,write()函數(shù)實(shí)現(xiàn)向CPLD中寫(xiě)入數(shù)據(jù),read()函數(shù)實(shí)現(xiàn)ARM從CPLD讀取數(shù)據(jù)。設(shè)備驅(qū)動(dòng)運(yùn)行在內(nèi)核空間,而應(yīng)用程序運(yùn)行在用戶(hù)空間,設(shè)備驅(qū)動(dòng)程序不能直接訪(fǎng)問(wèn)用戶(hù)空間的地址,在read()和write()函數(shù)中分別調(diào)用內(nèi)核函數(shù)copy_to_user()和copy_from_user()實(shí)現(xiàn)數(shù)據(jù)的轉(zhuǎn)移。read函數(shù)實(shí)現(xiàn)讀取CPLD中的編碼器值,write函數(shù)實(shí)現(xiàn)將產(chǎn)生PWM波的計(jì)數(shù)值寫(xiě)入CPLD中,這兩個(gè)函數(shù)實(shí)現(xiàn)了內(nèi)核空間與用戶(hù)空間的數(shù)據(jù)交換。從驅(qū)動(dòng)程序結(jié)構(gòu)看,驅(qū)動(dòng)程序由三部分組成:結(jié)構(gòu)體struct file_operations及其成員函數(shù)的實(shí)現(xiàn)、設(shè)備初始化module_init()和設(shè)備注銷(xiāo)module_exit()。
讀寫(xiě)CPLD需要對(duì)內(nèi)存進(jìn)行讀寫(xiě)操作[5]。CPLD產(chǎn)生的讀中斷信號(hào)連接到ARM的GPF1口,CPLD的使能信號(hào)由ARM的GPF0產(chǎn)生,因此需要配置相應(yīng)的寄存器。驅(qū)動(dòng)程序中需要對(duì)內(nèi)存和寄存器進(jìn)行操作,本操作系統(tǒng)下不能直接對(duì)內(nèi)存和寄存器的物理地址進(jìn)行操作,需先將相應(yīng)的內(nèi)存和寄存器的物理地址映射到內(nèi)核的虛擬地址空間,通過(guò)對(duì)映射后的虛擬地址進(jìn)行操作實(shí)現(xiàn)對(duì)寄存器和內(nèi)存的操作。
ARM對(duì)CPLD的讀操作采用異步通知和內(nèi)核中斷方式[5]實(shí)現(xiàn),這樣可減少系統(tǒng)開(kāi)支。首先在驅(qū)動(dòng)的open()函數(shù)中調(diào)用request_irq()函數(shù)注冊(cè)內(nèi)核中斷,并在內(nèi)核中實(shí)現(xiàn)中斷處理函數(shù),在內(nèi)核中斷處理函數(shù)中調(diào)用kill_fasyn()函數(shù)給指定的應(yīng)用程序發(fā)送信號(hào),通知應(yīng)用程序CPLD中的編碼器值可讀。當(dāng)CPLD無(wú)可讀中斷產(chǎn)生時(shí),將read()函數(shù)放入等待隊(duì)列,主程序一直處于睡眠狀態(tài),而不是應(yīng)用程序主動(dòng)去調(diào)用read()函數(shù)來(lái)等待中斷的產(chǎn)生,即采用異步通知方式,調(diào)用內(nèi)核中的fasync_helper()函數(shù)來(lái)實(shí)現(xiàn)。當(dāng)CPLD有可讀中斷產(chǎn)生時(shí),在中斷處理函數(shù)中通過(guò)kill_fasync()函數(shù),向進(jìn)程發(fā)送信號(hào)SIGIO,觸發(fā)應(yīng)用程序中signal聲明的異步觸發(fā)函數(shù),使用POLL_IN表明有數(shù)值可以讀取。另外,要注意,在進(jìn)入中斷服務(wù)程序后,首先通過(guò)中斷自旋鎖spin_lock_irq()關(guān)閉所有中斷,以防止其他中斷源中斷kill_fasync的工作,在中斷服務(wù)程序結(jié)束時(shí),再通過(guò)spin_unlock_irq()打開(kāi)中斷。中斷處理函數(shù)部分代碼如下:
spinlock_t lock;
static irqreturn_t eint1_irq(int irq, void *dev_id)
//中斷服務(wù)程序
{
spin_lock_irq(&lock);//關(guān)閉中斷
kill_fasync (&eint1_async, SIGIO, POLL_IN);
//產(chǎn)生中斷后,驅(qū)動(dòng)向應(yīng)用程序發(fā)送數(shù)據(jù)可讀信號(hào)
spin_unlock_irq(&lock);//開(kāi)中斷
return IRQ_RETVAL(IRQ_HANDLED);
}
4 應(yīng)用程序設(shè)計(jì)
在應(yīng)用程序[6]中,通過(guò)函數(shù)signal()注冊(cè)信號(hào)處理函數(shù),以接收內(nèi)核發(fā)來(lái)的數(shù)據(jù)可讀信號(hào)。為了打開(kāi)設(shè)備文件的異步觸發(fā)機(jī)制,用戶(hù)程序需指定當(dāng)前進(jìn)程為內(nèi)核發(fā)送信號(hào)的接收進(jìn)程,可以通過(guò)fcntl系統(tǒng)調(diào)用的F_SETOWN命令來(lái)設(shè)置該值。用戶(hù)程序還必須通過(guò)另一個(gè)fcntl命令設(shè)置設(shè)備的FASYNC標(biāo)志,打開(kāi)異步觸發(fā)機(jī)制。只要內(nèi)核中有CPLD可讀中斷產(chǎn)生,輸入文件就會(huì)產(chǎn)生一個(gè)SIGIO信號(hào),信號(hào)發(fā)送給應(yīng)用程序,應(yīng)用程序調(diào)用信號(hào)處理函數(shù)。在信號(hào)處理函數(shù)中讀取編碼器的值,通過(guò)控制算法得到控制數(shù)據(jù)(即PWM波計(jì)數(shù)值),然后將PWM波的計(jì)數(shù)值寫(xiě)入到CPLD中。主程序流程圖如圖3所示,部分代碼如下:
int main(int argc, char **argv)
{
int Oflags;
signal(SIGIO, signal_fun);//注冊(cè)信號(hào)處理函數(shù)
Init(argc,argv); //打開(kāi)設(shè)備,控制參數(shù)初始化
…
fcntl(fd_cpld, F_SETOWN, getpid());
//指定當(dāng)前進(jìn)程為接收信號(hào)進(jìn)程
Oflags=fcntl(fd_cpld, F_GETFL);//返回當(dāng)前的信號(hào)標(biāo)志
fcntl(fd_cpld, F_SETFL, Oflags | FASYNC);
//打開(kāi)異步觸發(fā)機(jī)制
while(1)
{
sleep(1000);//進(jìn)程睡眠,等待內(nèi)核發(fā)送中斷信號(hào)
}
……
return 0;
}
由于Linux是多任務(wù)系統(tǒng),各個(gè)進(jìn)程間采用一定的調(diào)度算法調(diào)度,進(jìn)程間會(huì)不時(shí)地切換,因此編寫(xiě)程序時(shí)要特別考慮系統(tǒng)進(jìn)程調(diào)度的問(wèn)題??刂瞥绦?qū)?shí)時(shí)性有一定的要求,因此,要將控制程序進(jìn)程設(shè)置為實(shí)時(shí)進(jìn)程且要具有較高的進(jìn)程調(diào)度優(yōu)先級(jí),同時(shí)控制程序中要盡量少地使用系統(tǒng)調(diào)用,以保證控制系統(tǒng)的實(shí)時(shí)性。
5 實(shí)驗(yàn)結(jié)果
控制板通過(guò)串口、網(wǎng)口與計(jì)算機(jī)(裝有Linux系統(tǒng))建立交叉編譯環(huán)境,程序在計(jì)算機(jī)上編譯調(diào)試。利用網(wǎng)線(xiàn)通過(guò)nfs(網(wǎng)絡(luò)文件系統(tǒng))服務(wù),在計(jì)算機(jī)和控制板之間實(shí)現(xiàn)網(wǎng)絡(luò)文件共享,可直接在控制板上訪(fǎng)問(wèn)計(jì)算機(jī)上的共享文件、執(zhí)行計(jì)算機(jī)上編譯好的程序,無(wú)需將計(jì)算機(jī)上編譯好的程序下載到板子上。這種交叉開(kāi)發(fā)的方式將程序和實(shí)驗(yàn)數(shù)據(jù)直接存儲(chǔ)在計(jì)算機(jī)上,可節(jié)省控制板上的存儲(chǔ)空間,便于程序開(kāi)發(fā)和進(jìn)行實(shí)驗(yàn)數(shù)據(jù)分析。
實(shí)驗(yàn)過(guò)程中,首先要對(duì)電機(jī)參數(shù)進(jìn)行辨識(shí)。電機(jī)參數(shù)辨識(shí)的方法[7-8]很多,本實(shí)驗(yàn)采用階躍響應(yīng)法測(cè)得電機(jī)的模型參數(shù),近似為一階慣性環(huán)節(jié)。編碼器為增量式編碼器,電機(jī)轉(zhuǎn)一圈產(chǎn)生20 000個(gè)碼,即一個(gè)碼值對(duì)應(yīng)0.018°,編碼器值采樣周期為2 ms。將電機(jī)一個(gè)采樣周期內(nèi)轉(zhuǎn)過(guò)的角度值除以采樣周期作為速度反饋值,將電機(jī)轉(zhuǎn)過(guò)的角度進(jìn)行累加得到位置反饋值,電機(jī)最高轉(zhuǎn)速為900°/s,最低轉(zhuǎn)速為9°/s,采用PI控制[9-10]。圖4為系統(tǒng)速度階躍響應(yīng)曲線(xiàn),速度響應(yīng)誤差為每1個(gè)采樣周期1個(gè)碼值。圖5為系統(tǒng)位置階躍曲線(xiàn),設(shè)定速度環(huán)最大速度為180°/s。位置環(huán)采用抗積分飽和算法,以消除因積分飽和引起的過(guò)大的超調(diào),位置階躍穩(wěn)態(tài)誤差為0。圖6是系統(tǒng)的速度正弦跟蹤曲線(xiàn),正弦引導(dǎo)函數(shù)為:v=180°sin(0.8πt),跟蹤誤差在正反轉(zhuǎn)速度換向處跟蹤誤差較大。
實(shí)驗(yàn)結(jié)果表明,基于ARM9和CPLD硬件平臺(tái),在嵌入式Linux操作系統(tǒng)下,系統(tǒng)能夠?qū)崿F(xiàn)等速跟蹤、位置定點(diǎn)和正弦跟蹤等功能,滿(mǎn)足控制實(shí)時(shí)性要求,可實(shí)現(xiàn)伺服控制。系統(tǒng)體積小、成本低、功耗小、接口豐富、便于開(kāi)發(fā),且Linux系統(tǒng)具有很好的文件管理功能,有助于實(shí)驗(yàn)數(shù)據(jù)的存儲(chǔ)和導(dǎo)出,便于實(shí)驗(yàn)結(jié)果分析。系統(tǒng)進(jìn)一步完善后可將控制程序設(shè)計(jì)成圖形界面,利用觸摸屏輸入和顯示伺服控制結(jié)果,則可實(shí)現(xiàn)控制結(jié)果實(shí)時(shí)顯示,可視化效果好,整個(gè)系統(tǒng)可脫離計(jì)算機(jī)工作,具有廣泛的應(yīng)用價(jià)值。
參考文獻(xiàn)
[1] 李金洪,楊小軍.基于DSP和FPGA的經(jīng)緯儀控制系統(tǒng)設(shè)計(jì)[J].電子技術(shù)應(yīng)用,2010,36(7):48-51.
[2] 鈔靖,王小椿,姜虹.基于FPGA的光電編碼器四倍頻電路設(shè)計(jì)[J].儀表技術(shù),2007(6):17-21.
[3] 耿偉松,于海東.基于CPLD的PWM發(fā)生器設(shè)計(jì)[J].制造業(yè)自動(dòng)化,2010,32(6):151-153.
[4] 韋東山.嵌入式Linux應(yīng)用開(kāi)發(fā)完全手冊(cè)[M].北京:人民郵電出版社,2008.
[5] 宋寶華.Linux設(shè)備驅(qū)動(dòng)詳解[M].北京:人民郵電出版社,2008.
[6] 孫程建.基于Linux的嵌入式數(shù)控系統(tǒng)底層軟件設(shè)計(jì)[D].武漢:武漢科技大學(xué),2007.
[7] 王帥,陳濤,李洪文,等.光電跟蹤伺服系統(tǒng)的頻率特性測(cè)試與模型辨識(shí)[J].光學(xué)精密工程,2009,17(1):78-83.
[8] 王偉國(guó),陳濤,沈湘衡.直流伺服系統(tǒng)機(jī)械時(shí)間常熟測(cè)試方法的研究[J].儀器儀表學(xué)報(bào),2005,26(8):66-70.
[9] 李洪文.基于內(nèi)模PID控制的大型望遠(yuǎn)鏡伺服系統(tǒng)[J].光學(xué)精密工程,2009(2):327-332.
[10] 劉金錕.先進(jìn)PID控制及其MATLAB仿真[M].北京:電子工業(yè)出版社,2003.