李英杰
摘 要:此嵌入式智能小車的組成主要包括ARM硬件體系下的控制系統(tǒng)、電機驅(qū)動電路、紅外探測電路、超聲波避障電路等。系統(tǒng)以嵌入式Linux微控制器為核心,通過紅外探測電路傳感器采集不同的信號做出判斷,繼而改變電機的運動方向和運動速度。實現(xiàn)小車的前進、后退、左轉(zhuǎn)、右轉(zhuǎn)、自動循跡和避障功能,攝像頭舵機的水平和垂直方向上的轉(zhuǎn)動。利用Qt Creator生成客戶端工程,通過PC端的WiFi連接,控制智能小車的運動,同時小車上的攝像頭可以將實時的畫面?zhèn)骰貋怼?/p>
關(guān)鍵詞:嵌入式Linux微控制器;自動循跡;避障;無線網(wǎng)絡(luò)連接控制;Qt Creator
在當前的環(huán)境中,隨著科技的進步,智能化車輛或者與智能化車輛相關(guān)的產(chǎn)品已經(jīng)開始作為各式各樣自動控制系統(tǒng)中的重要設(shè)備之一,這其中主要包括了物流配送或者交通運輸?shù)认到y(tǒng)。而機器人在復(fù)雜地形中行進時自動循跡和避障是一項必不可少也是最基本的功能。因此,自動避障系統(tǒng)和自動循跡的研發(fā)就應(yīng)運而生。我們的自動避障小車就是基于這一系統(tǒng)開發(fā)而成的。 意義隨著科技的發(fā)展,對于未知空間和人類所不能直接到達的地域的探索逐步成為熱門,這就使機器人的自動避障有了重大的意義。小車可以通過傳感器來獲取當前道路狀況,然后將傳感器獲取到的數(shù)據(jù)傳輸?shù)教幚砥?,處理器再結(jié)合小車當前的行駛狀態(tài),迅速地進行計算,對小車的行駛的方向和行車的速度進行快速的調(diào)整改變,進而對目標道路進行迅速準確的跟蹤。
1 術(shù)語定義
server_video:C視頻服務(wù)器(mjpeg圖片)
client_video:QT視頻客戶端
通信協(xié)議:
client:發(fā)送“pic”
server:回復(fù)“XXXXlen”(xxxx代表圖片的數(shù)據(jù)量,單位為字節(jié))
client:根據(jù)接收到的數(shù)據(jù)量進行圖片的循環(huán)接收,接收完畢,顯示在客戶端
小車IP:192.168.1.1
小車控制端端口:2001
小車視頻端端口:8888
小車控制命令:
停止 FF 00 00 00 FF
前進 FF 00 01 00 FF
后退 FF 00 02 00 FF
左轉(zhuǎn) FF 00 03 00 FF
右轉(zhuǎn) FF 00 04 00 FF
可以參考如下格式保存命令
static unsigned char cmd[5] = {0xff,0x00,0x01,0x00,0xff}; //up
static unsigned char cmd[5] = {0xff,0x00,0x02,0x00,0xff}; //down
static unsigned char cmd[5] = {0xff,0x00,0x03,0x00,0xff}; //left
static unsigned char cmd[5] = {0xff,0x00,0x04,0x00,0xff}; //right
static unsigned char cmd[5] = {0xff,0x00,0x00,0x00,0xff}; //stop
波特率:9600 無校驗 8位數(shù)據(jù)位 1位停止位
2 系統(tǒng)概述
編寫能使小車運動和攝像等程序。用已有的小車模型,調(diào)試好WiFi模塊和其硬件和軟件,利用這樣的方法來實現(xiàn)電腦端來通過路由器在無線傳輸?shù)姆绞綄π≤囘M行控制,從而驅(qū)動WiFi小車的運動和攝影等一系列指令。
具體要求如下:
a)控制客戶端數(shù)據(jù)發(fā)送給小車。
b)前進:四個車輪能夠同時朝著前進的方向進行運動,保證速度一致;
c)后退:四個車輪能夠同時朝著后退的方向進行運動,保證速度一致;
d)左轉(zhuǎn):左邊的兩個輪子靜止,而右邊的兩個輪子前進
e)右轉(zhuǎn):右邊的兩個輪子靜止,而左邊的兩個輪子前進
f)通過無線網(wǎng)對小車攝像頭采集的信息來傳送。
g)服務(wù)器圖片的存儲和鏈接客戶端并將圖片發(fā)送給客戶端。
h)連續(xù)接受圖片并且打印成連續(xù)照片顯示。
3 總體設(shè)計
3.1 系統(tǒng)框架
3.2 結(jié)構(gòu)體描述
部分一:
參數(shù)說明:參數(shù)類型為V4L2的能力描述類型struct v4l2_capability;
返回值說明:執(zhí)行成功時,函數(shù)返回值為0;函數(shù)執(zhí)行成功后,struct v4l2_capability結(jié)構(gòu)體變量中的返回當前視頻設(shè)備所支持的功能:例如支持視頻捕獲功能V4L2_CAP_VIDEO_CAPTURE、V4L2_CAP_STREAMING等
Struct v4l2_capability
{
_u8 driver[16];
_u8 card[32];
_u8 bus_info[32];
_u32 version;
_u32 capabilities;
_u32 reserved[4];
};
Capabilities 常用值;
V4L2_CAP_VIDEO_CAPTURE
部分二:
設(shè)置視頻設(shè)備的視頻數(shù)據(jù)格式,例如設(shè)置視頻圖像數(shù)據(jù)的長、寬,圖像格式(JPEG、YUYV格式);
參數(shù)說明;參數(shù)類型為V4L2的視頻數(shù)據(jù)格式類型struct v4l2_format;
返回值說明:執(zhí)行成功是,函數(shù)返回值為0;
struct v4l2_format
{
enum v4l2_buf_type type;
union
{
struct v4l2_pix_format pix;
struct v4l2_window win;
struct v4l2_vbi_format vbi;
__u8 raw_data[200];
} fmt;
};
struct v4l2_pix_format{
_u32 width;
_u32 height;
_u32 pixelformat;
Enum v4l2 field field;
_u32 bytesperline;
_u32 sizeimage;
Enum v4l2 _colorspace colorspace;
_u32 priv;
};
部分三:
功能:請求V4L2驅(qū)動分配視頻緩沖區(qū)(申請V4L2視頻驅(qū)動分配內(nèi)存),V4L2是頻頻設(shè)備的驅(qū)動層,位于內(nèi)核空間,所以通過VIDIOC_REQBBUFS控制命令字申請的內(nèi)存位于內(nèi)核空間,應(yīng)用程序不能直接訪問,需要通過調(diào)用mmap內(nèi)存映射函數(shù)把內(nèi)核空間內(nèi)存映射到用戶空間后,應(yīng)用程序通過訪問用戶空間地址來訪問內(nèi)核空間。
參數(shù)說明:參數(shù)類型為V4L2的申請緩沖區(qū)數(shù)據(jù)結(jié)構(gòu)體類型struct v4l2_requestbuffers;
返回值說明:執(zhí)行成功時,函數(shù)返回值為0;V4L2驅(qū)動層分配好了視頻緩沖區(qū)。接下來可以為視頻捕獲分配內(nèi)存:
struct v4l2_requestbuffers req;
if (ioctl(fd, VIDIOC_REQBUFS, &req;) == -1) {
return -1;
}
v4l2_requestbuffers 結(jié)構(gòu)如下:
struct v4l2_requestbuffers
{
__u32 count;
enum v4l2_buf_type type; //V4L2_BUF_TYPE_VIDEO_CAPTURE
enum v4l2_memory memory;//V4L2_MEMORY_MMAP 或V4L2_MEMORY_USERPTR
__u32 reserved[2];
};
部分四:
使用VIDIOC_REQBUFS,我們獲取了req.count個緩存,下一步通過調(diào)用VIDIOC_QUERYBUF命令來獲取這些緩存的地址,然后使用mmap函數(shù)轉(zhuǎn)換成應(yīng)用程序中的絕對地址,最后把這段緩存放入緩存隊列:
typedef struct VideoBuffer {
void *start;
size_t length;
} VideoBuffer;
VideoBuffer* buffers = calloc( req.count, sizeof(*buffers) );
struct v4l2_buffer buf;
for (numBufs = 0; numBufs < req.count; numBufs++) {
memset( &buf;, 0, sizeof(buf) );
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = numBufs;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf;) == -1)
{
return -1;
}
buffers[numBufs].length = buf.length;
buffers[numBufs].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED,fd, buf.m.offset);
if (buffers[numBufs].start == MAP_FAILED) {
return -1;
}
if (ioctl(fd, VIDIOC_QBUF, &buf;) == -1) {
return -1;
}
}
部分五:
V4L2有一個數(shù)據(jù)緩存,存放req.count數(shù)量的緩存數(shù)據(jù)。數(shù)據(jù)緩存采用FIFO的方式,當應(yīng)用程序調(diào)用緩存數(shù)據(jù)時,緩存隊列將最先采集到的視頻數(shù)據(jù)緩存送出,并重新采集一張視頻數(shù)據(jù)。這個過程需要用到兩個ioctl命令,VIDIOC_DQBUF和VIDIOC_QBUF:
struct v4l2_buffer buf;
memset(&buf;,0,sizeof(buf));
buf.type=V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory=V4L2_MEMORY_MMAP;
buf.index=0;
if (ioctl(cameraFd, VIDIOC_DQBUF, &buf;) == -1)
{
return -1;
}
if (ioctl(cameraFd, VIDIOC_QBUF, &buf;) == -1) {
return -1;
}
4 視頻采集模塊
4.1 視頻采集介紹
使用攝像頭采集視頻數(shù)據(jù),將采集到的數(shù)據(jù)保存到相應(yīng)的數(shù)據(jù)結(jié)構(gòu)之中。視頻采集模塊通過建立視頻驅(qū)動模塊,處理應(yīng)用程序和設(shè)備驅(qū)動之間的幀緩沖區(qū)的同步。例如,一個視頻顯示驅(qū)動必須始終顯示視頻數(shù)據(jù),直到應(yīng)用程序給它另一幀視頻數(shù)據(jù)去顯示,它才會將上一幀緩沖區(qū)返回給應(yīng)用程序。執(zhí)行這種同步最有效的方式就是定義一個單獨的API調(diào)用來負責緩沖區(qū)交換。同樣一個視頻捕獲驅(qū)動必須始終返回最新捕獲的視頻數(shù)據(jù),這要求驅(qū)動在下一次緩沖區(qū)交換發(fā)生之前至少保留一個幀緩沖區(qū)。該模塊具有采集壓縮速度快、圖象質(zhì)量好、產(chǎn)生的JPEG文件小、接口通信速率高等特點,適合需要嵌入式圖象采集的各種應(yīng)用,特別是無線或低速率網(wǎng)絡(luò)通信下的圖象應(yīng)用。
4.2視頻采集相關(guān)接口
//初始化視頻采集設(shè)備
int camera_init(char *devpath, unsigned int *width, unsigned int *height, unsigned int *size)
//開啟視頻監(jiān)控
int camera_start(int fd);
//采集視頻信息
int camera_dqbuf(int fd, void *buf, unsigned int *size, unsigned int *index);
//停止視頻采集
int camera_stop(int fd);
//關(guān)閉視頻監(jiān)控
int camera_exit(int fd);
//控制數(shù)據(jù)轉(zhuǎn)發(fā)
QString str=this->ui->lineEdit->text();
QByteArray arr; QDataStream dst(&arr;,QIODevice::ReadWrite
dst< this->socket->write(arr); 5 客戶端顯示模塊 5.1 功能描述 客戶端顯示模塊主要是將服務(wù)器中的數(shù)據(jù)信號經(jīng)過處理傳送到linux顯示設(shè)備上來,實現(xiàn)視頻流的顯示,來使客戶及使用者實現(xiàn)數(shù)據(jù)的采集功能和以此進行數(shù)據(jù)分析。 5.2 流程圖 5.3 相關(guān)代碼 int init_lcd(char *pathname); int tcp_client_init(); int tcp_client_connect(int sockfd,char *ip,const int port); int tcp_client_recv(int sockfd,void *buf,int count); int showrgb(int fd,unsigned,int width,int height); int close_lcd(int fd); 5.4 主要思想 每次獲取圖片之前,先進性圖片數(shù)據(jù)的解析,存放到一個定義的字符串數(shù)組中,之后進行讀操作。在進行都操作時,先讀取前24個字節(jié)利用strstr函數(shù)得到第一次出現(xiàn)len的地址將其值賦值為/0,就可以取出/0之前的數(shù)據(jù)得到此次接收圖片的大小,然后根據(jù)大小讀取數(shù)據(jù),最終當收到一副圖片的數(shù)據(jù)時完成顯示,因為視頻相當于多幅圖片的連續(xù)播放,故定義一個定時器使圖片循環(huán)顯示。 5.5 運行 使用Qt運行客戶端程序,并將IP設(shè)置為:192.168.1.1(路由板IP),端口號設(shè)置為:8888 點擊START按鈕,我們就可以看到攝像頭采集到的視頻信息。 參考文獻: [1] 梁明亮,孫逸潔.嵌入式智能小車的設(shè)計與實現(xiàn)[J].制造業(yè)自動化,第34卷11期 [2] 董宗祥,石紅瑞,楊杰.嵌入式測控智能小車的設(shè)計與實現(xiàn) [J].計算機計量與控制,2010.18(2) [3] 邢曉敏,楊正祥.嵌入式智能小車設(shè)計[J] .自動化應(yīng)用.2017(05) [4] 陳俊如.基于Android控制臺的智能小車系統(tǒng)設(shè)計[J] . 科技創(chuàng)新與應(yīng)用.2018(08)