機器人、人工智能和機器學習領域正在迅速發(fā)展,它肯定會在不久的將來改變?nèi)祟惖纳罘绞?。機器人被認為通過傳感器和機器學習處理來理解現(xiàn)實世界并與之交互。圖像識別是一種流行的方式,機器人被認為是通過相機觀察現(xiàn)實世界來理解物體的一種方式,就像我們一樣。在這個項目中,讓我們利用樹莓派的力量來構(gòu)建一個機器人,它可以跟蹤球并跟隨它,就像踢足球的機器人一樣。
OpenCV是一個非常著名的開源工具,用于圖像處理,但在本教程中,為了簡單起見,我們使用處理IDE。由于ARM的處理也發(fā)布了用于處理的GPIO庫,因此我們不必再在python和處理之間切換即可使用Raspberry Pi。聽起來很酷吧?因此,讓我們開始吧。
所需硬件:
樹莓派
帶帶狀電纜的攝像頭模塊
機器人底盤
帶輪齒輪的減速電機
L293D 電機驅(qū)動器
移動電源或任何其他便攜式電源
編程要求:
樹莓派的監(jiān)視器或其他顯示器
Pi 的鍵盤或鼠標
處理 ARM 軟件
注意:在編程過程中,必須通過電線將顯示器連接到Pi,因為只有這樣才能查看相機的視頻
在樹莓派上設置處理:
如前所述,我們將使用處理環(huán)境來編程我們的樹莓派,而不是使用 python 的默認方式。因此,請按照以下步驟操作:
第 1 步:-將樹莓派連接到顯示器、鍵盤和鼠標,然后將其打開。
第 2 步:-確保您的Pi已連接到有效的互聯(lián)網(wǎng)連接,因為我們即將下載一些內(nèi)容。
第 3 步:-單擊“處理 ARM”,下載 Raspberry Pi 的處理 IDE。下載將以 ZIP 文件的形式進行。
第 4 步:-下載后,將ZIP文件夾中的文件解壓縮到首選目錄中。我剛剛在桌面上提取了它。
第 5 步:-現(xiàn)在,打開提取的文件夾,然后單擊名為“處理”的文件。它應該打開一個窗口,如下所示。
第 6 步:-這是我們將輸入代碼的環(huán)境。對于熟悉Arduino的人來說,不要感到震驚,是的,IDE看起來確實與Arduino相似,程序也是如此。
第 7 步:-我們需要兩個庫才能讓我們的球跟隨程序工作,安裝然后只需單擊 Sketch -> 導入庫 -> 添加庫。將打開以下對話框。
第 8 步:-使用左上角的文本框搜索樹莓派并按回車鍵,您的搜索結(jié)果應如下所示。
第 9 步:-搜索名為“GL 視頻”和“硬件 I/O”的庫,然后單擊安裝以安裝它們。確保安裝這兩個庫。
步驟10:-根據(jù)您的互聯(lián)網(wǎng),安裝將需要幾分鐘。完成后,我們就可以使用處理軟件了。
電路圖:
這個樹莓派球跟蹤項目的電路圖如下所示。
如您所見,該電路涉及PI相機,電機驅(qū)動器模塊和一對連接到Raspberry Pi的電機。整個電路由移動電源供電(在上述電路中由AAA電池表示)。
由于樹莓派上沒有提到引腳細節(jié),我們需要使用下圖驗證引腳
為了驅(qū)動電機,我們需要四個引腳(A,B,A,B)。這四個引腳分別從 GPIO14、4、17 和 18 連接。橙色和白色的電線共同構(gòu)成了一個電機的連接。所以我們有兩個這樣的對用于兩個電機。
如圖所示,電機連接到L293D電機驅(qū)動器模塊,驅(qū)動器模塊由移動電源供電。確保移動電源的接地連接到樹莓派的接地,只有這樣您的連接才能正常工作。
這就是我們完成硬件連接的事情,讓我們回到我們的處理環(huán)境并開始編程以教我們的機器人如何跟蹤球。
樹莓派球跟蹤程序:
本頁末尾給出了該項目的完整處理程序,您可以直接使用。下面,我解釋了代碼的工作原理,以便您可以將其用于其他類似的項目。
程序概念非常簡單。雖然這個項目的目的是跟蹤一個球,但我們實際上不會這樣做。我們只是使用球的顏色來識別球。眾所周知,視頻只不過是連續(xù)的圖片幀。所以我們把每張照片分成像素。然后我們將每個像素顏色與球的顏色進行比較;如果找到了一場比賽,那么我們可以說我們已經(jīng)找到了球。有了這些信息,我們還可以識別球在屏幕上的位置(像素顏色)。如果位置在最左邊,我們將機器人向右移動,如果位置最右,我們將機器人向左移動,以便像素位置始終保持在屏幕的中心。您可以觀看Daniel shiffman的計算機視覺視頻以獲得清晰的圖片。
與往常一樣,我們首先導入下載的兩個庫。這可以通過以下兩行完成。硬件 I/O 庫用于直接從處理環(huán)境訪問 PI 的 GPIO 引腳,glvideo 庫用于訪問樹莓派相機模塊。
import processing.io.*;
import gohai.glvideo.*;
在設置功能中,我們初始化輸出引腳以控制電機,并從pi相機獲取視頻并將其調(diào)整為尺寸為320 * 240的窗口。
void setup() {
size(320, 240, P2D);
video = new GLCapture(this);
video.start();
trackColor = color(255, 0, 0);
GPIO.pinMode(4, GPIO.OUTPUT);
GPIO.pinMode(14, GPIO.OUTPUT);
GPIO.pinMode(17, GPIO.OUTPUT);
GPIO.pinMode(18, GPIO.OUTPUT);
}
void draw就像無限循環(huán),只要程序終止,這個循環(huán)中的代碼就會被執(zhí)行。如果有可用的攝像機源,我們會讀取從中發(fā)出的視頻
void draw() {
background(0);
if (video.available()) {
video.read();
}}
然后我們開始將視頻幀拆分為像素。每個像素都有一個紅色、綠色和藍色的值。這些值存儲在變量 r1、g1 和 b1 中
for (int x = 0; x < video.width; x ++ ) {
for (int y = 0; y < video.height; y ++ ) {
int loc = x + y*video.width;
// What is current color
color currentColor = video.pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
要最初檢測球的顏色,我們必須單擊顏色。點擊后,球的顏色將存儲在名為trackColor的變量中。
void mousePressed() {
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*video.width;
trackColor = video.pixels[loc];
}
一旦我們有了軌道顏色和當前顏色,我們必須比較它們。此比較使用的是 dist 函數(shù)。它檢查當前顏色與軌道顏色的接近程度。
float d = dist(r1, g1, b1, r2, g2, b2);
對于完全匹配,dist 的值將為零。因此,如果 dist 的值小于指定值(世界紀錄),那么我們假設我們已經(jīng)找到了軌道顏色。然后我們獲取該像素的位置并將其存儲在最近的 X 和最近的 Y 變量中,以找到球的位置
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
}
我們還在找到的顏色周圍畫一個橢圓,以指示已找到該顏色。位置的值也打印在控制臺上,這在調(diào)試時會有很大幫助。
if (worldRecord < 10) {
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(closestX, closestY, 16, 16);
println(closestX,closestY);
最后,我們可以比較最近的X和最近的Y的位置,并以顏色到達屏幕中心的方式調(diào)整電機。下面的代碼用于向右轉(zhuǎn)動機器人,因為發(fā)現(xiàn)顏色的X位置在屏幕的左側(cè)(<140)
if (closestX<140)
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.LOW);
delay(10);
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
println("Turn Right");
}
同樣,我們可以檢查 X 和 Y 的位置,以控制電機在所需方向上。
樹莓派球跟蹤機器人的工作:
一旦你準備好了硬件和程序,就該找點樂子了。在地面上測試我們的機器人之前,我們應該確保一切正常。連接您的 Pi 以監(jiān)控和啟動處理代碼。您應該會在一個小窗口中看到視頻源。現(xiàn)在,將球帶入框架并單擊球以指示機器人它應該跟蹤這種特定顏色。現(xiàn)在在屏幕上移動球,您應該注意到輪子在旋轉(zhuǎn)。
如果一切按預期工作,請將機器人釋放到地面并開始使用它。確保房間均勻照明以獲得最佳效果。
/*
Processing Raspberry Pi program for Ball following Robot
Project by: B.Aswnith Raj
Dated on: 18-11-2017
#This project would not have been possible without the help of Daniel Shiffman and Gottfried Haider
*/
import processing.io.*;
import gohai.glvideo.*;
GLCapture video;
color trackColor;
void setup() {
size(320, 240, P2D);
video = new GLCapture(this);
video.start();
trackColor = color(255, 0, 0);
GPIO.pinMode(4, GPIO.OUTPUT);
GPIO.pinMode(14, GPIO.OUTPUT);
GPIO.pinMode(17, GPIO.OUTPUT);
GPIO.pinMode(18, GPIO.OUTPUT);
}
void draw() {
background(0);
if (video.available()) {
video.read();
}
video.loadPixels();
image(video, 0, 0);
float worldRecord = 500;?
int closestX = 0;
int closestY = 0;
// Begin loop to walk through every pixel
for (int x = 0; x < video.width; x ++ ) {
for (int y = 0; y < video.height; y ++ ) {
int loc = x + y*video.width;
// What is current color
color currentColor = video.pixels[loc];
float r1 = red(currentColor);
float g1 = green(currentColor);
float b1 = blue(currentColor);
float r2 = red(trackColor);
float g2 = green(trackColor);
float b2 = blue(trackColor);
// Using euclidean distance to compare colors
float d = dist(r1, g1, b1, r2, g2, b2); // We are using the dist( ) function to compare the current color with the color we are tracking.
// If current color is more similar to tracked color than
// closest color, save current location and current difference
if (d < worldRecord) {
worldRecord = d;
closestX = x;
closestY = y;
}
}
}
if (worldRecord < 10) {?
// Draw a circle at the tracked pixel
fill(trackColor);
strokeWeight(4.0);
stroke(0);
ellipse(closestX, closestY, 16, 16);
println(closestX,closestY);
if (closestX<140)
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.LOW);
delay(10);
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
println("Turn Right");?
}
else if (closestX>200)
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.LOW);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
delay(10);
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
println("Turn Left");?
}
else if (closestY<170)
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.LOW);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.LOW);
delay(10);
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
println("Go Frwd");?
}
else
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
}?
}
else
{
GPIO.digitalWrite(4, GPIO.HIGH);
GPIO.digitalWrite(14, GPIO.HIGH);
GPIO.digitalWrite(17, GPIO.HIGH);
GPIO.digitalWrite(18, GPIO.HIGH);
}
}
void mousePressed() {
// Save color where the mouse is clicked in trackColor variable
int loc = mouseX + mouseY*video.width;
trackColor = video.pixels[loc];
}
?
評論
查看更多