DIY小車這個(gè)項(xiàng)目已經(jīng)很多了,對(duì)于前后左右等控制,司空見慣,這次嘗試一下能監(jiān)控的多功能控制小車,電腦,手機(jī)都可以!
多功能車基本功能參數(shù)和關(guān)鍵部件,視頻傳輸這塊和我們現(xiàn)在智能家具這塊無(wú)線視頻原理一樣,下面會(huì)有介紹。
1.輸入電源:2串或3串的鋰電池(帶充電器)
2.輸出5v,3.3V等電壓為負(fù)載供電
3.四個(gè)直流減速電機(jī)
4.WIFI數(shù)傳模塊
5.電機(jī)驅(qū)動(dòng)模塊
6.STM32F105主控板
7.UVC攝像頭
8.小車底盤
最后實(shí)現(xiàn)電腦或手機(jī)通過(guò)wifi和軟件控制小車動(dòng)作并實(shí)時(shí)監(jiān)控。
框圖
基本框圖:
基本編程軟件
keil5
對(duì)于單片機(jī)編程這塊,目前STM32占用非常多,涉及到庫(kù)函數(shù)和寄存器編程。
這次采用庫(kù)函數(shù)編程,采用傳統(tǒng)的標(biāo)準(zhǔn)庫(kù),HAL庫(kù)后續(xù)可以。
如上圖所示,先把框架建立好,拿一個(gè)自己用的工程,把相應(yīng)的函數(shù)添加進(jìn)去就可以了。
舵機(jī)這塊是兩個(gè),上下,左右各一個(gè),180度旋轉(zhuǎn)。
舵機(jī)的基本控制原理
控制信號(hào)由接收機(jī)的通道進(jìn)入信號(hào)調(diào)制芯片,獲得直流偏置電壓。它內(nèi)部有一個(gè)基準(zhǔn)電路,產(chǎn)生周期為20ms,寬度為1.5ms的基準(zhǔn)信號(hào),將獲得的直流偏置電壓與電位器的電壓比較,獲得電壓差輸出。最后,電壓差的正負(fù)輸出到電機(jī)驅(qū)動(dòng)芯片決定電機(jī)的正反轉(zhuǎn)。當(dāng)電機(jī)轉(zhuǎn)速一定時(shí),通過(guò)級(jí)聯(lián)減速齒輪帶動(dòng)電位器旋轉(zhuǎn),使得電壓差為0,電機(jī)停止轉(zhuǎn)動(dòng)。
舵機(jī)的控制一般需要一個(gè)20ms左右的時(shí)基脈沖,該脈沖的高電平部分一般為0.5ms-2.5ms范圍內(nèi)的角度控制脈沖部分,總間隔為2ms。以180度角度伺服為例,那么對(duì)應(yīng)的控制關(guān)系是這樣的:
0.5ms--------------0度;
1.0ms------------45度;
1.5ms------------90度;
2.0ms-----------135度;
2.5ms-----------180度;
看看程序中是怎么控制的
用STM32硬件PWM和模擬PWM都可以
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //ÅäÖÃΪPWMģʽ1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = Speed_Left-1; //ÉèÖÃͨµÀ2µÄµçÆ½Ìø±äÖµ£¬Êä³öÁíÍâÒ»¸öÕ¼¿Õ±ÈµÄPWM
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //µ±¶¨Ê±Æ÷¼ÆÊýֵСÓÚCCR1_ValʱΪ¸ßµçƽ
TIM_OC1Init(TIM5, &TIM_OCInitStructure); //ʹÄÜͨµÀ1
TIM_OC1PreloadConfig(TIM5, TIM_OCPreload_Enable);
我們改變這個(gè)值
Speed_Left-1就可以改變舵機(jī)角度。
這個(gè)是整個(gè)產(chǎn)品的核心wifi模塊
wifi數(shù)傳模塊是基于MIPS 24K 高通CPU的一款WIFI1X1芯片AR9331,其SDK采用uboot作為引導(dǎo)。是基于MIPS 架構(gòu)的,目前有x86、ARM和MIPS三種主流芯片架構(gòu),ARM集架構(gòu)的主要特點(diǎn):一是體積小、低功耗、低成本、高性能;二是大量使用寄存器且大多數(shù)數(shù)據(jù)操作都在寄存器中完成,命令執(zhí)行速度更快;三是尋址方式靈活簡(jiǎn)單,執(zhí)行效率高;四是命令長(zhǎng)度固定,可通過(guò)多流水線方式提高處理效率。
wifi模塊的工作原理
WiFi模塊通過(guò)采集掛載在USB接口的MJPG格式的攝像頭的數(shù)據(jù),并編碼封裝成http協(xié)議的視頻流,默認(rèn)推送到8080端口。Android/IOS/PC設(shè)備,連接到WiFi模塊的熱點(diǎn)后,打開控制軟件,會(huì)自動(dòng)從8080端口獲取MJPG視頻流,并進(jìn)行解碼、顯示。由此實(shí)現(xiàn)了WiFi智能小車的實(shí)時(shí)視頻傳輸功能。
這個(gè)是實(shí)際的wifi圖傳模塊
現(xiàn)在在重申一下這個(gè)模塊的工作原理和使用方法
WiFi模塊通過(guò)采集掛載在USB接口的MJPG格式的攝像頭的數(shù)據(jù),并編碼封裝成http協(xié)議的視頻流,默認(rèn)推送到8080端口。Android/IOS/PC設(shè)備,連接到WiFi模塊的熱(wifi-robots.com開頭的SSID信號(hào))后,打開控制軟件,會(huì)自動(dòng)從8080端口獲取MJPG視頻流,并進(jìn)行解碼、顯示。由此實(shí)現(xiàn)了WiFi智能小車的實(shí)時(shí)視頻傳輸功能。
我們簡(jiǎn)單恢復(fù)一下出廠設(shè)置就可以了,簡(jiǎn)單說(shuō)一下,用USB轉(zhuǎn)tll工具連接模塊配置好波特率(57600)和串口號(hào)一定注意先后順序。
1:點(diǎn)擊打開串口,此時(shí)WIFI的狀態(tài)是沒(méi)有上電的。
2:給WIFI上電此時(shí)要注意串口開始打?。ê荜P(guān)鍵)。
3:輸入命令firstboot就可以了。
這個(gè)wifi模塊怎么刷固件openwrt系統(tǒng)的。
首先通過(guò)USB口給設(shè)備供電,通過(guò)miniUSB口加上usb轉(zhuǎn)網(wǎng)口網(wǎng)線連接電腦。
準(zhǔn)備刷機(jī)工具TFTP服務(wù)端:tftp32 就是局域網(wǎng)內(nèi)可以傳文件。
超級(jí)終端:putty Telnet、SSH、rlogin、純TCP以及串行接口連接軟件。
需要相應(yīng)的固件具體教程http://www.wifi-robots.com/thread-108-1-1.html
最后我們看看USB攝像頭這塊,簡(jiǎn)單介紹一下無(wú)線監(jiān)控中的攝像頭。
1.攝像頭選擇
做本次實(shí)驗(yàn)的時(shí)候,推薦大家用 USB 免驅(qū)的攝像頭,最好是支持 MJPEG 輸出的攝像頭類型。USB 免驅(qū)攝像頭輸出 YUV 格式和輸出 MJPEG 格式,對(duì)無(wú)線監(jiān)控的效果有什么影響呢?首先大家要知道,同樣是一幀數(shù)據(jù),YUV 格式會(huì)比 MJPEG 格式的大得多,因此我們?cè)谝曨l傳輸?shù)臅r(shí)候,一般是傳輸 MJPEG 格式的數(shù)據(jù)。這樣,就有這樣一個(gè)問(wèn)題,如果攝像頭是輸出 YUV 格式,那么就意味著我們需要通過(guò)軟件將視頻數(shù)據(jù)由 YUV 格式轉(zhuǎn)換成 MJPEG格式,然后傳輸。如果攝像頭輸出的是 MJPEG 格式,那個(gè)將可以直接將得到的數(shù)據(jù)進(jìn)行傳輸。因此,使用支持 MJPEG 壓縮的攝像頭,比一般的攝像頭,做無(wú)線監(jiān)控的效果,好很多。
2.配置 OpenWrt 支持 usb 攝像頭
看看怎么配置
要支持?jǐn)z像頭,就必須配置上攝像頭的驅(qū)動(dòng),因?yàn)槭敲怛?qū)的 USB 攝像頭,因此我們必須配置上 UVC 驅(qū)動(dòng),具體如圖所示。首先,我們選中內(nèi)核模塊進(jìn)行配置:
選中 Video 支持配置:
按”y”選中 kmod-video-core:
在展開的選項(xiàng)中選中 uvc:
看看電機(jī)驅(qū)動(dòng)模塊:
基本原理如下
看看具體是怎么控制電機(jī)調(diào)速的,通過(guò)控制使能端使L298N處于工作和不工作,VSS-9引腳為芯片供電 VS-4引腳為電機(jī)供電 ENA-6引腳為通道1使能端,利用定時(shí)器的pwm輸出作用于ENA,根據(jù)脈沖占空比不同就可以得到不同的輸出電壓,從而達(dá)到調(diào)速目的。比如在VS引腳加10V的電機(jī)供電電壓,ENA端脈沖占空比為100%,那么OUT1和OUT2之間將輸出10V電壓,占空比為50%,那么輸出為5V電壓,占空比為10%,則為1V 我買的電機(jī)供電電壓為5v到12v都可以,電壓高的話也可以,長(zhǎng)時(shí)間工作的話會(huì)對(duì)電機(jī)損壞。
看看電機(jī)是怎么正反裝的
邏輯輸入端,為IN1\IN2\IN3\IN4,其中IN1、IN2控制電機(jī)M1;IN3、IN4控制電 機(jī)M2。例如IN1輸入高電平1,IN2輸入低電平0,對(duì)應(yīng)電機(jī)M1正轉(zhuǎn);IN1輸入低電平0,IN2輸入高電平1,對(duì)應(yīng)電機(jī)M1反轉(zhuǎn),調(diào)速就是改變高電平的占空比。
這是整個(gè)系統(tǒng)的核心板STM32F105
正好國(guó)慶期間可以把程序?qū)憣懀靡粋€(gè)stm32f103的模板,還是103的標(biāo)準(zhǔn)庫(kù),改一下測(cè)試再105上可以不?
主要就是串口這塊,但是奇怪的是串口通訊不正常。
波特率9600是一致的,用串口助手發(fā)送,發(fā)送FE是沒(méi)有任何反應(yīng)的,發(fā)送其他,接受的也不一樣,多年的編程,程序應(yīng)該問(wèn)題不大。
就懷疑時(shí)鐘的問(wèn)題,先軟件仿真看看,調(diào)試狀態(tài)找到RCC。
看看能看出來(lái)時(shí)鐘對(duì)不
寄存器里面的值不太了解
可以通過(guò)一個(gè)時(shí)鐘函數(shù)RCC_GetClocksFreq(&RCC_Clocks)加到主函數(shù)里,把RCC_Clocks變量加到窗口中,看看實(shí)際的時(shí)鐘頻率。
發(fā)現(xiàn)時(shí)鐘不對(duì),再網(wǎng)上查看資料說(shuō)105和103的啟動(dòng)文件不一樣。
宏定義這需要改成STM32F10X_CL。
由于105系列屬于互聯(lián)型單片機(jī),默認(rèn)晶振為25M,而我們實(shí)際為8M。
1.需要在這個(gè)stm32f10x.h文件里更改。
2.需要在這個(gè)system_stm32f10x.c文件里更改。
現(xiàn)在我們?cè)诜抡嬲{(diào)試看看實(shí)際的時(shí)鐘頻率。
主頻這個(gè)16進(jìn)制值為0x044AA200,經(jīng)過(guò)計(jì)算為72.000000。
這樣就配置ok了。
為了讓小車強(qiáng)勁有力,我們采用松下的18650電池,一個(gè)是2600MAH,兩串兩并的話就是8.4V ,總?cè)萘?0400MAH。
這是兩個(gè)電池的
加上快充充電器,網(wǎng)上買的,后續(xù)介紹。
我們現(xiàn)在準(zhǔn)備組裝小車。
這是小車底盤
組裝鋰電池
完畢。
剩下的小車組裝完畢
下面開始程序調(diào)試
小車的電機(jī)直接有電池供電,L298N驅(qū)動(dòng)。
舵機(jī)這塊有電池降壓5V供電
簡(jiǎn)單把程序這塊介紹下,主要是串口通信。
最簡(jiǎn)單的串口數(shù)據(jù)處理機(jī)制是數(shù)據(jù)接收并原樣回發(fā)的機(jī)制是:成功接收到一個(gè)數(shù),觸發(fā)進(jìn)入中斷,在中斷函數(shù)中將數(shù)據(jù)讀取出來(lái),然后立即。這一種數(shù)據(jù)處理機(jī)制是“非緩沖中斷方式”,雖然這種數(shù)據(jù)處理方式不消耗時(shí)間,但是這種數(shù)據(jù)處理方式嚴(yán)重的缺點(diǎn)是:數(shù)據(jù)無(wú)緩沖區(qū),如果先前接收的的數(shù)據(jù)如果尚未發(fā)送完成(處理完成),然后串口又接收到新的數(shù)據(jù),新接收的數(shù)據(jù)就會(huì)把尚未處理的數(shù)據(jù)覆蓋,從而導(dǎo)致“數(shù)據(jù)丟包”。
對(duì)于“數(shù)據(jù)丟包”,最簡(jiǎn)單的辦法就是使用一個(gè)數(shù)組來(lái)接收數(shù)據(jù):每接收一個(gè)數(shù)據(jù),數(shù)組下標(biāo)偏移。雖然這樣的做法能起到一定的“緩沖效果”,但是數(shù)組的空間得不到很好的利用,已處理的數(shù)據(jù)仍然會(huì)占據(jù)原有的數(shù)據(jù)空間,直到該數(shù)組“滿載”(數(shù)組的每一個(gè)元素都保存了有效的數(shù)據(jù)),將整個(gè)數(shù)組的數(shù)據(jù)處理完成后,重新清零數(shù)組,才能開啟新一輪的數(shù)據(jù)接收。
解決這個(gè)問(wèn)題采用FIFO的機(jī)制,環(huán)形緩沖區(qū)就是一個(gè)帶“頭指針”和“尾指針”的數(shù)組。“頭指針”指向環(huán)形緩沖區(qū)中可讀的數(shù)據(jù),“尾指針”指向環(huán)形緩沖區(qū)中可寫的緩沖空間。通過(guò)移動(dòng)“頭指針”和“尾指針”就可以實(shí)現(xiàn)緩沖區(qū)的數(shù)據(jù)讀取和寫入。
1.圖形和代碼分析
當(dāng)然,環(huán)形緩沖區(qū)的“頭指針”和“尾指針”可以用“頭變量”和“尾變量”來(lái)代替,因?yàn)榍袚Q數(shù)組的元素空間,除了可以用“指針偏移法”之外,還可以用“素組下標(biāo)偏移法”。當(dāng)串口接收到新的數(shù)組,則將數(shù)組保存到環(huán)形緩沖區(qū)中,同時(shí)將“尾變量”加一,以保存下一個(gè)數(shù)據(jù);應(yīng)用程序在讀取數(shù)據(jù)時(shí),“頭變量”加一,以讀取下一個(gè)數(shù)據(jù)。
#define MAX_SIZE 12 //緩沖區(qū)大小
typedef struct
{
unsigned char head; //緩沖區(qū)頭部位置
unsigned char tail; //緩沖區(qū)尾部位置
unsigned char ringBuf[MAX_SIZE]; //緩沖區(qū)數(shù)組
} ringBuffer_t;
ringBuffer_t buffer; //定義一個(gè)結(jié)構(gòu)體
2.定義一個(gè)結(jié)構(gòu)頭體則表示新的消息隊(duì)列已經(jīng)創(chuàng)建完成。新建創(chuàng)建的隊(duì)列,頭指針head和尾指針tail都是指向數(shù)組的元素0。如下圖所示,此時(shí)的消息隊(duì)列是“空隊(duì)列”。
當(dāng)如果有11個(gè)數(shù)據(jù)abcdefghijk存入緩沖隊(duì)列,則如下圖所示:
當(dāng)如果l加入隊(duì)列,則緩沖隊(duì)列處于滿載狀態(tài),如下圖所示:如果此時(shí),接收到新的數(shù)據(jù)并需要保存,則tail需要?dú)w零,將接收到的數(shù)據(jù)存到數(shù)組的第一個(gè)元素空間,如果尚未讀取緩沖數(shù)組的一個(gè)元素空間的數(shù)據(jù),則此數(shù)據(jù)會(huì)被新接收的數(shù)據(jù)覆蓋。同時(shí)head需要增加1,修改頭節(jié)點(diǎn)偏移位置丟棄早期數(shù)據(jù)。
3.讀取緩沖隊(duì)列中的11個(gè)數(shù)據(jù)后,狀態(tài)如下:
當(dāng)消息隊(duì)列中的所有數(shù)據(jù)都讀取出來(lái)后,此時(shí)環(huán)形隊(duì)列是空的,狀態(tài)如下圖所示。從圖可以總結(jié)得知,如果tail和head相等,則表示緩沖隊(duì)列是空的。
我們看看程序中是怎么做的。
這是最終的成品圖,帶超聲波避障功能。
這是電腦控制軟件
功能非常強(qiáng)大的,
這是手機(jī)APP