李英杰
摘 要:此嵌入式智能小車的組成主要包括ARM硬件體系下的控制系統、電機驅動電路、紅外探測電路、超聲波避障電路等。系統以嵌入式Linux微控制器為核心,通過紅外探測電路傳感器采集不同的信號做出判斷,繼而改變電機的運動方向和運動速度。實現小車的前進、后退、左轉、右轉、自動循跡和避障功能,攝像頭舵機的水平和垂直方向上的轉動。利用Qt Creator生成客戶端工程,通過PC端的WiFi連接,控制智能小車的運動,同時小車上的攝像頭可以將實時的畫面?zhèn)骰貋怼?/p>
關鍵詞:嵌入式Linux微控制器;自動循跡;避障;無線網絡連接控制;Qt Creator
在當前的環(huán)境中,隨著科技的進步,智能化車輛或者與智能化車輛相關的產品已經開始作為各式各樣自動控制系統中的重要設備之一,這其中主要包括了物流配送或者交通運輸等系統。而機器人在復雜地形中行進時自動循跡和避障是一項必不可少也是最基本的功能。因此,自動避障系統和自動循跡的研發(fā)就應運而生。我們的自動避障小車就是基于這一系統開發(fā)而成的。 意義隨著科技的發(fā)展,對于未知空間和人類所不能直接到達的地域的探索逐步成為熱門,這就使機器人的自動避障有了重大的意義。小車可以通過傳感器來獲取當前道路狀況,然后將傳感器獲取到的數據傳輸到處理器,處理器再結合小車當前的行駛狀態(tài),迅速地進行計算,對小車的行駛的方向和行車的速度進行快速的調整改變,進而對目標道路進行迅速準確的跟蹤。
1 術語定義
server_video:C視頻服務器(mjpeg圖片)
client_video:QT視頻客戶端
通信協議:
client:發(fā)送“pic”
server:回復“XXXXlen”(xxxx代表圖片的數據量,單位為字節(jié))
client:根據接收到的數據量進行圖片的循環(huán)接收,接收完畢,顯示在客戶端
小車IP:192.168.1.1
小車控制端端口:2001
小車視頻端端口:8888
小車控制命令:
停止 FF 00 00 00 FF
前進 FF 00 01 00 FF
后退 FF 00 02 00 FF
左轉 FF 00 03 00 FF
右轉 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位數據位 1位停止位
2 系統概述
編寫能使小車運動和攝像等程序。用已有的小車模型,調試好WiFi模塊和其硬件和軟件,利用這樣的方法來實現電腦端來通過路由器在無線傳輸的方式對小車進行控制,從而驅動WiFi小車的運動和攝影等一系列指令。
具體要求如下:
a)控制客戶端數據發(fā)送給小車。
b)前進:四個車輪能夠同時朝著前進的方向進行運動,保證速度一致;
c)后退:四個車輪能夠同時朝著后退的方向進行運動,保證速度一致;
d)左轉:左邊的兩個輪子靜止,而右邊的兩個輪子前進
e)右轉:右邊的兩個輪子靜止,而左邊的兩個輪子前進
f)通過無線網對小車攝像頭采集的信息來傳送。
g)服務器圖片的存儲和鏈接客戶端并將圖片發(fā)送給客戶端。
h)連續(xù)接受圖片并且打印成連續(xù)照片顯示。
3 總體設計
3.1 系統框架
3.2 結構體描述
部分一:
參數說明:參數類型為V4L2的能力描述類型struct v4l2_capability;
返回值說明:執(zhí)行成功時,函數返回值為0;函數執(zhí)行成功后,struct v4l2_capability結構體變量中的返回當前視頻設備所支持的功能:例如支持視頻捕獲功能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
部分二:
設置視頻設備的視頻數據格式,例如設置視頻圖像數據的長、寬,圖像格式(JPEG、YUYV格式);
參數說明;參數類型為V4L2的視頻數據格式類型struct v4l2_format;
返回值說明:執(zhí)行成功是,函數返回值為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ū)(申請V4L2視頻驅動分配內存),V4L2是頻頻設備的驅動層,位于內核空間,所以通過VIDIOC_REQBBUFS控制命令字申請的內存位于內核空間,應用程序不能直接訪問,需要通過調用mmap內存映射函數把內核空間內存映射到用戶空間后,應用程序通過訪問用戶空間地址來訪問內核空間。
參數說明:參數類型為V4L2的申請緩沖區(qū)數據結構體類型struct v4l2_requestbuffers;
返回值說明:執(zhí)行成功時,函數返回值為0;V4L2驅動層分配好了視頻緩沖區(qū)。接下來可以為視頻捕獲分配內存:
struct v4l2_requestbuffers req;
if (ioctl(fd, VIDIOC_REQBUFS, &req;) == -1) {
return -1;
}
v4l2_requestbuffers 結構如下:
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個緩存,下一步通過調用VIDIOC_QUERYBUF命令來獲取這些緩存的地址,然后使用mmap函數轉換成應用程序中的絕對地址,最后把這段緩存放入緩存隊列:
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有一個數據緩存,存放req.count數量的緩存數據。數據緩存采用FIFO的方式,當應用程序調用緩存數據時,緩存隊列將最先采集到的視頻數據緩存送出,并重新采集一張視頻數據。這個過程需要用到兩個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 視頻采集介紹
使用攝像頭采集視頻數據,將采集到的數據保存到相應的數據結構之中。視頻采集模塊通過建立視頻驅動模塊,處理應用程序和設備驅動之間的幀緩沖區(qū)的同步。例如,一個視頻顯示驅動必須始終顯示視頻數據,直到應用程序給它另一幀視頻數據去顯示,它才會將上一幀緩沖區(qū)返回給應用程序。執(zhí)行這種同步最有效的方式就是定義一個單獨的API調用來負責緩沖區(qū)交換。同樣一個視頻捕獲驅動必須始終返回最新捕獲的視頻數據,這要求驅動在下一次緩沖區(qū)交換發(fā)生之前至少保留一個幀緩沖區(qū)。該模塊具有采集壓縮速度快、圖象質量好、產生的JPEG文件小、接口通信速率高等特點,適合需要嵌入式圖象采集的各種應用,特別是無線或低速率網絡通信下的圖象應用。
4.2視頻采集相關接口
//初始化視頻采集設備
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);
//關閉視頻監(jiān)控
int camera_exit(int fd);
//控制數據轉發(fā)
QString str=this->ui->lineEdit->text();
QByteArray arr; QDataStream dst(&arr;,QIODevice::ReadWrite
dst< this->socket->write(arr); 5 客戶端顯示模塊 5.1 功能描述 客戶端顯示模塊主要是將服務器中的數據信號經過處理傳送到linux顯示設備上來,實現視頻流的顯示,來使客戶及使用者實現數據的采集功能和以此進行數據分析。 5.2 流程圖 5.3 相關代碼 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 主要思想 每次獲取圖片之前,先進性圖片數據的解析,存放到一個定義的字符串數組中,之后進行讀操作。在進行都操作時,先讀取前24個字節(jié)利用strstr函數得到第一次出現len的地址將其值賦值為/0,就可以取出/0之前的數據得到此次接收圖片的大小,然后根據大小讀取數據,最終當收到一副圖片的數據時完成顯示,因為視頻相當于多幅圖片的連續(xù)播放,故定義一個定時器使圖片循環(huán)顯示。 5.5 運行 使用Qt運行客戶端程序,并將IP設置為:192.168.1.1(路由板IP),端口號設置為:8888 點擊START按鈕,我們就可以看到攝像頭采集到的視頻信息。 參考文獻: [1] 梁明亮,孫逸潔.嵌入式智能小車的設計與實現[J].制造業(yè)自動化,第34卷11期 [2] 董宗祥,石紅瑞,楊杰.嵌入式測控智能小車的設計與實現 [J].計算機計量與控制,2010.18(2) [3] 邢曉敏,楊正祥.嵌入式智能小車設計[J] .自動化應用.2017(05) [4] 陳俊如.基于Android控制臺的智能小車系統設計[J] . 科技創(chuàng)新與應用.2018(08)