200美元“造”出一臺可由語音控制外加能進行人臉識別的自主飛行無人機

OReillyData發表於2016-11-16

繼“如何用100美元和TensorFlow來造一個能‘看’東西的機器人” 之後,Lukas又一最新力作。

結合深度學習和便宜硬體的更多探奇。

在“造”出能進行物體識別的機器人後,下一步就很清晰了,我要“造”一個能飛的東西!我決定搞一個能自主飛行的無人機,並要它能識別人臉和響應語音指令。

選擇一臺成品無人機

開始“黑入”一臺無人機的最難的部分就是如何開始。我最初的選擇是用零件組裝一臺無人機。但和我完成的大部分的DIY專案一樣,從零開始一般都耗費了太多的時間,還不如直接買一個成品。實話實說,我自己組裝的無人機從來沒有正常的飛行過。而買一臺成品機就既省事又省錢。

絕大部分無人機廠商都宣稱提供API介面,但對於業餘玩家來說就沒有一個明確的最佳選擇。大部分能提供貌似可用的API介面的無人機都要超過1000美元。這對於入門級的玩家來說就太貴了。

但經過搜尋,我發現Parrot AR 無人機2.0版(見圖1)是一個低端可“黑”入無人機的極佳選擇。新的售價是200美元,不過很多人在買了以後就不怎麼再玩了,所以在eBay上花130美元或更少就能買到一個不錯的二手貨。

640?wx_fmt=jpeg

圖1:我車庫裡的無人機收藏。最左邊的就是Parrot AR無人機。圖片由Lukas Biewald授權使用

論飛行穩定性,Parrot AR型不如更貴的Parrot Bebop 2型(550美元)。但是Parrot AR型所帶的叫node-ar-drone的node.js客戶端庫是非常好用的。

Parrot AR型的另外一個優點是它非常皮實、耐摔。在測試自主飛行程式碼的時候,我的無人機頻繁地撞到牆、傢俱、植物甚至是我們家的客人,並墜落。但它還是依舊能正常飛行。

比起“造”能在地上跑的機器人,“造”無人機最不爽的一點就是它的電池可用時間太短了。基本上是充電幾小時,飛行十幾分鍾。所以我建議多買兩塊電池,迴圈充電使用。

給我的無人機開發程式

我經過實踐發現,Javascript內在的事件驅動的特性使得它成為一種非常好的控制無人機的語言。請相信我,無人機飛行的時候,是有非常多的非同步事件發生。我寫Node.JS的時間並不長,但在這個專案過程中,我對它的印象非常深刻。上一次我正兒八經地為機器人寫程式用的是C語言。處理C語言的執行緒和異常是一件非常讓人頭疼的事,所以我儘量避免再使用它。我希望有人能為其他的機器人平臺開發出JavaScript的介面,因為這會讓為機器人開發程式(完全無法預知會發生什麼事)變得更簡單更有趣。

架構設計

我決定在我的筆記本上執行控制邏輯,同時在雲端執行機器學習的部分。這種架構設計比在樹莓派板上直接執行神經網路的延遲要低。我認為這種架構對於業餘無人機專案而言是合適的。

微軟、谷歌、IBM和亞馬遜都提供快速且便宜的機器學習API。最終我選擇了微軟的認知服務API來完成這個專案,因為它是唯一提供定製化的人臉識別功能的API。

圖2裡展示了整個無人機專案的系統架構。

640?wx_fmt=jpeg

圖2:智慧無人機的系統架構。圖片由Lukas Biewald授權使用

開始動手

預設地,Parrot AR無人機2.0版自己可以提供一個無線網路,供客戶端接入,但是這個功能卻極度煩人。每次你要實驗點東西,你都需要從本地網路斷開,再連到無人機的無線網裡。好訊息是,有一個叫ardrone-wpa2的專案,非常有用,用它你可以“黑”進無人機,並讓無人機連到你自己的無線網路裡。

Telnet到無人機作業系統上並遊蕩一番是挺有趣的。Parrot無人機使用的是一個簡化版的Linux作業系統。你上次Telnet到某個系統上是什麼時間哪?下面的命令例子就演示瞭如何開啟一個終端並直接登入到無人機的作業系統上。

% script/connect “The Optics Lab” -p “particleorwave” -a 192.168.0.1 -d 192.168.7.43

% telnet 192.168.7.43

通過命令列來控制飛行

在安裝了node庫之後,下一步就是生成一個node.js的命令列執行環境,然後就可以開始控制你的無人機了:

var arDrone = require(‘ar-drone’);

var client = arDrone.createClient({ip: ‘192.168.7.43’});

client.createRepl();

drone> takeoff()

true

drone> client.animate(‘yawDance, 1.0)

如果你按照我上面所說的一步一步地實驗到這裡,你的無人機肯定已經墜落過了——至少好幾次。我已經無數次地把我的無人機的保護外殼給它粘回機身上,直到它徹底解體,隨後我只好再買了一個新的。我不得不說,其實Parrot AR型在沒有保護外殼的時候飛行得更好。但這種方式會使無人機變得很危險。因為沒有保護外殼的話,一旦無人機撞到東西,它的螺旋槳就會直接打到物體上,並留下刮痕。

從網頁上控制無人機飛行

為無人機開發一個基於網頁的控制頁面挺簡單且效果不錯。用如下所示的express.js框架就可以搭建一個很小巧的網頁伺服器。

var express = require(‘express’);

app.get(‘/’, function (req, res) {

res.sendFile(path.join(__dirname + ‘/index.html’));

});

app.get(‘/land’, function(req, res) {

client.land();

});

app.get(‘/takeoff’, function(req, res) {

client.takeoff();

});

app.listen(3000, function () {

});

我用下面的程式碼來通過一個按鈕傳送AJAX請求。

<html>

<script language=’javascript’>

function call(name) {

var xhr = new XMLHttpRequest();

xhr.open(‘GET’, name, true);

xhr.send();

}

</script>

<body>

<a onclick=”call(‘takeoff’);”>Takeoff</a>

<a onclick=”call(‘land’);”>Land</a>

</body>

</html>

從無人機上匯出視訊流

我發現把無人機上的攝像頭拍攝的視訊匯出的最佳方法就是:建立一個持續的連線,並把攝像頭拍攝的PNG圖片傳送到我的網站的網頁上。通過使用AR無人機的庫(見下面的程式碼),網頁伺服器不斷地把無人機攝像頭拍攝的PNG畫面拉取出來。

var pngStream = client.getPngStream();

pngStream

.on(‘error’, console.log)

.on(‘data’, function(pngBuffer) {

sendPng(pngBuffer);

}

function sendPng(buffer) {

res.write(‘–daboundary\nContent-Type: image/png\nContent-length: ‘ + buff

er.length + ‘\n\n’);

res.write(buffer);

});

對從無人機獲取的影象進行人臉識別

微軟的Azure Face API系統很容易上手,且功能強大。你上傳你朋友的照片給它,這個系統就能識別出他們是誰。它也能猜測人物的年齡和性別。我發現這兩個功能的識別準確率是驚人的高。整個識別的延遲大概是200毫秒。識別1000次請求花費1.5美元。對我而言,這個價格對於這種應用是相當合理的。下面是我的程式碼,它實現了傳送圖片給API來做人臉識別的功能。

var oxford = require(‘project-oxford’),

oxc = new oxford.Client(CLIENT_KEY);

loadFaces = function() {

chris_url = “https://media.licdn.com/mpr/mpr/shrinknp_400_400/AAEAAQAAAAAAAALyAAAAJGMyNmIzNWM0LTA5MTYtNDU4Mi05YjExLTgyMzVlMTZjYjEwYw.jpg”;

lukas_url = “https://media.licdn.com/mpr/mpr/shrinknp_400_400/p/3/000/058/147/34969d0.jpg”;

oxc.face.faceList.create(‘myFaces’);

oxc.face.faceList.addFace(‘myFaces’, {url => chris_url, name=> ‘Chris’});

oxc.face.faceList.addFace(‘myFaces’, {url => lukas_url, name=> ‘Lukas’});

}

oxc.face.detect({

path: ‘camera.png’,

analyzesAge: true,

analyzesGender: true

}).then(function (response) {

if (response.length > 0) {

drawFaces(response, filename)

}

});

我用了ImageMagick庫來對我收集的PNG圖片做打標籤,效果相當好。對於這個部分其實可以有很多的擴充套件可能。比如用一個情感API來識別人臉所表現出來的情感。

運用語音來控制無人機

進行語音識別部分開發的難點並不是識別本身,而是如何把語音流從執行在我本地伺服器上的網頁裡轉換成微軟Speech API可以使用格式。下面的程式碼就是實現這個功能的。一旦你能把語音儲存成單聲道和以正確的取樣頻率取樣後,這個語音識別API就能很方便地識別語音內容。這個API的花費是1000次請求4美元。對於業餘應用來說,基本相當於是免費了。

RecordRTC是一個很好的庫,可以用來作為以網頁為客戶端的語音採集的新手入門的工具。在客戶端,我就加入了儲存語音檔案的程式碼。

app.post(‘/audio’, function(req, res) {

var form = new formidable.IncomingForm();

// 設定允許客戶在一個請求裡上傳多個檔案

form.multiples = true;

form.uploadDir = path.join(__dirname, ‘/uploads’);

form.on(‘file’, function(field, file) {

filename = “audio.wav”

fs.rename(file.path, path.join(form.uploadDir, filename));

});

// 記錄發生的錯誤日誌

form.on(‘error’, function(err) {

console.log(‘An error has occured: \n’ + err);

});

// 一旦所有檔案上傳完成,才給客戶端發相應

form.on(‘end’, function() {

res.end(‘success’);

});

// 解析出請求裡包含的表單資料

form.parse(req)

speech.parseWav(‘uploads/audio.wav’, function(text) {

console.log(text);

controlDrone(text);

});

});

我使用FFmpeg工具來降低音訊的取樣率,並把多聲道合併成單聲道,以供微軟API使用。

exports.parseWav = function(wavPath, callback) {

var cmd = ‘ffmpeg -i ‘ + wavPath + ‘ -ar 8000 -ac 1 -y tmp.wav’;

exec(cmd, function(error, stdout, stderr) {

console.log(stderr); // command output is in stdout

});

postToOxford(callback);

});

儘管我開發的功能就是這些,但是還是可以繼續擴充套件。比如用微軟的文字變語音的API來讓無人機說話!

開發自主搜尋路徑

我使用ardrone-autonomy庫來為無人機開發自主搜尋路徑。在此過程中,我無數次地把無人機弄得撞到了客廳的傢俱和植物上。最後,我妻子很“客氣”地建議我去車庫裡繼續我的專案,因為那裡沒多少可以撞的東西。但是車庫的地方有點小,使得操控空間有限。

640?wx_fmt=jpeg

圖3:在我的“實驗室”裡試飛無人機。圖片由Lukas Biewald授權使用

在我能有一個更大的實驗空間後,我會嘗試更智慧的搜尋演算法。不過,現在我還是隻會讓無人機做起飛和旋轉的動作,以此來搜尋發現人,並識別是敵還是友。

var autonomy = require(‘ardrone-autonomy’);

var mission = autonomy.createMission({ip: ‘10.0.1.3’, frameRate: 1, imageSize: ‘640:320’});

console.log(“Here we go!”)

mission.takeoff()

.zero()         // 把當前狀態作為參考基準

.altitude(1)

.taskSync(console.log(“Checkpoint 1”))

.go({x: 0, y: 0, z: 1, yaw: 90})

.taskSync(console.log(“Checkpoint 2”))

.hover(1000)

.go({x: 0, y: 0, z: 1, yaw: 180})

.taskSync(console.log(“Checkpoint 3”))

.hover(1000)

.go({x: 0, y: 0, z: 1, yaw: 270})

.taskSync(console.log(“Checkpoint 4”));

.hover(1000)

.go({x: 0, y: 0, z: 1, yaw: 0

.land()

全都搞定後的效果

看下面的視訊。我讓無人機起飛並去找我的朋友Chris:

結論

在一切都配置妥當之後,就可以通過API來控制無人機,獲得拍攝到的視訊圖片,這一切都爽爆了!隨著新的影象識別技術可供使用,可能的應用必將越來越多。比如,讓無人機根據房屋平面圖來刷牆。雖然Parrot無人機並不是設計來為在狹小空間(比如我的房子)裡安全飛行的,但隨著無人機越來越皮實,價格變得更低,我相信真正有用的應用將會進入爆發期。

微軟的認知服務雲API是相當得好用且便宜。最初我比較擔心無人機所用的廣角攝像頭所拍攝的圖片會影響人臉識別的準確度,另外螺旋槳的噪聲可能會對語音識別產生干擾。但整體而言,這兩個API的表現遠超我的期望。同時處理延遲也低於我的預期。從架構設計角度來看,在雲端執行機器學習實時影象處理似乎是一個奇怪的選擇,但它可能會成為未來很多應用的架構選擇。

 

640?wx_fmt=jpeg

Lukas Biewald

Lukas Biewald是CrowdFlower的創始人兼CEO。CrowdFlower始於2009年,是一個資料增強的平臺,可以幫助企業獲得隨需的人力來收集、產生訓練資料,以及參與人-機器學習迴圈的工作。 在從史丹佛大學拿到數學學士和電腦科學碩士學位後,Lukas領導了雅虎日本的搜尋相關團隊。隨後他去了Powerset,作為一個資深資料科學家進行工作。2008年Powerset被微軟收購。Lukas還被《公司》雜誌評選為30位30歲以下的著名人士。 Lukas還是一位專家級的圍棋選手。

640?wx_fmt=png

相關文章