機器人、人工智能和機器學習領域正在迅速發(fā)展,它肯定會在不久的將來改變人類的生活方式。機器人被認為通過傳感器和機器學習處理來理解現實世界并與之交互。圖像識別是一種流行的方式,機器人被認為是通過相機觀察現實世界來理解物體的一種方式,就像我們一樣。在這個項目中,讓我們利用樹莓派的力量來構建一個機器人,它可以跟蹤球并跟隨它,就像踢足球的機器人一樣。
OpenCV是一個非常著名的開源工具,用于圖像處理,但在本教程中,為了簡單起見,我們使用處理IDE。由于ARM的處理也發(fā)布了用于處理的GPIO庫,因此我們不必再在python和處理之間切換即可使用Raspberry Pi。聽起來很酷吧?因此,讓我們開始吧。
所需硬件:
樹莓派
帶帶狀電纜的攝像頭模塊
機器人底盤
帶輪齒輪的減速電機
L293D 電機驅動器
移動電源或任何其他便攜式電源
編程要求:
樹莓派的監(jiān)視器或其他顯示器
Pi 的鍵盤或鼠標
處理 ARM 軟件
注意:在編程過程中,必須通過電線將顯示器連接到Pi,因為只有這樣才能查看相機的視頻
在樹莓派上設置處理:
如前所述,我們將使用處理環(huán)境來編程我們的樹莓派,而不是使用 python 的默認方式。因此,請按照以下步驟操作:
第 1 步:-將樹莓派連接到顯示器、鍵盤和鼠標,然后將其打開。
第 2 步:-確保您的Pi已連接到有效的互聯網連接,因為我們即將下載一些內容。
第 3 步:-單擊“處理 ARM”,下載 Raspberry Pi 的處理 IDE。下載將以 ZIP 文件的形式進行。
第 4 步:-下載后,將ZIP文件夾中的文件解壓縮到首選目錄中。我剛剛在桌面上提取了它。
第 5 步:-現在,打開提取的文件夾,然后單擊名為“處理”的文件。它應該打開一個窗口,如下所示。
第 6 步:-這是我們將輸入代碼的環(huán)境。對于熟悉Arduino的人來說,不要感到震驚,是的,IDE看起來確實與Arduino相似,程序也是如此。
第 7 步:-我們需要兩個庫才能讓我們的球跟隨程序工作,安裝然后只需單擊 Sketch -> 導入庫 -> 添加庫。將打開以下對話框。
第 8 步:-使用左上角的文本框搜索樹莓派并按回車鍵,您的搜索結果應如下所示。
第 9 步:-搜索名為“GL 視頻”和“硬件 I/O”的庫,然后單擊安裝以安裝它們。確保安裝這兩個庫。
步驟10:-根據您的互聯網,安裝將需要幾分鐘。完成后,我們就可以使用處理軟件了。
電路圖:
這個樹莓派球跟蹤項目的電路圖如下所示。
如您所見,該電路涉及PI相機,電機驅動器模塊和一對連接到Raspberry Pi的電機。整個電路由移動電源供電(在上述電路中由AAA電池表示)。
由于樹莓派上沒有提到引腳細節(jié),我們需要使用下圖驗證引腳
為了驅動電機,我們需要四個引腳(A,B,A,B)。這四個引腳分別從 GPIO14、4、17 和 18 連接。橙色和白色的電線共同構成了一個電機的連接。所以我們有兩個這樣的對用于兩個電機。
如圖所示,電機連接到L293D電機驅動器模塊,驅動器模塊由移動電源供電。確保移動電源的接地連接到樹莓派的接地,只有這樣您的連接才能正常工作。
這就是我們完成硬件連接的事情,讓我們回到我們的處理環(huán)境并開始編程以教我們的機器人如何跟蹤球。
樹莓派球跟蹤程序:
本頁末尾給出了該項目的完整處理程序,您可以直接使用。下面,我解釋了代碼的工作原理,以便您可以將其用于其他類似的項目。
程序概念非常簡單。雖然這個項目的目的是跟蹤一個球,但我們實際上不會這樣做。我們只是使用球的顏色來識別球。眾所周知,視頻只不過是連續(xù)的圖片幀。所以我們把每張照片分成像素。然后我們將每個像素顏色與球的顏色進行比較;如果找到了一場比賽,那么我們可以說我們已經找到了球。有了這些信息,我們還可以識別球在屏幕上的位置(像素顏色)。如果位置在最左邊,我們將機器人向右移動,如果位置最右,我們將機器人向左移動,以便像素位置始終保持在屏幕的中心。您可以觀看Daniel shiffman的計算機視覺視頻以獲得清晰的圖片。
與往常一樣,我們首先導入下載的兩個庫。這可以通過以下兩行完成。硬件 I/O 庫用于直接從處理環(huán)境訪問 PI 的 GPIO 引腳,glvideo 庫用于訪問樹莓派相機模塊。
import processing.io.*;
import gohai.glvideo.*;
在設置功能中,我們初始化輸出引腳以控制電機,并從pi相機獲取視頻并將其調整為尺寸為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 函數。它檢查當前顏色與軌道顏色的接近程度。
float d = dist(r1, g1, b1, r2, g2, b2);
對于完全匹配,dist 的值將為零。因此,如果 dist 的值小于指定值(世界紀錄),那么我們假設我們已經找到了軌道顏色。然后我們獲取該像素的位置并將其存儲在最近的 X 和最近的 Y 變量中,以找到球的位置
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);
最后,我們可以比較最近的X和最近的Y的位置,并以顏色到達屏幕中心的方式調整電機。下面的代碼用于向右轉動機器人,因為發(fā)現顏色的X位置在屏幕的左側(<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)控和啟動處理代碼。您應該會在一個小窗口中看到視頻源。現在,將球帶入框架并單擊球以指示機器人它應該跟蹤這種特定顏色。現在在屏幕上移動球,您應該注意到輪子在旋轉。
如果一切按預期工作,請將機器人釋放到地面并開始使用它。確保房間均勻照明以獲得最佳效果。
/*
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];
}
?
評論
查看更多