黃金蝙蝠生態館互動式機台開發

Submitted by gloomcheng on 二, 02/27/2018 - 16:38

黃生蝙蝠生態館原本有一台播放蝙蝠聲音的互動裝置,就是按下按鈕後就會播放對應的蝙蝠聲音,趁著這次展間重新整修,館長打算也翻修一下這台互動裝置,希望改造成按下按鈕可以播放蝙蝠聲音及聲波變化影片的互動式機台。

在有限的成本和時間壓力下(哪次的專案沒有成本和時間壓力呢?冏),決定用 Raspberry Pi(樹莓派)來打造一部多媒體機台(原名 Multiple Media Kiosk,一般簡稱 Kiosk),使用 Raspberry Pi 的優點除了成本較低廉外,還有就是可以結合 Chromium(Chrome 瀏覽的開源版本)來製作 Kiosk 互動式機台。

接下來,就來看看我們需要準備什麼:

機台

想當然爾,我們要有一個機台,才能將螢幕、Raspberry Pi 及按鈕整合在成為一個完整的互動式機台。那麼,身為一個程式設計師的我,自然是沒有木作功夫的技術點數,所以機台這項工作就直接發包給木工師傅囉!

螢幕

嗯,身為一個程式設計師的我,當然也不具備無中生出螢幕的能力,好在上網買螢幕便宜又快速,就直接上網點一點就好(還可以順便上淘寶)

按鈕與控制板

除了買按鈕之外,更重要的是要有一個控制板,負責轉換按鈕的電子訊號並透過 USB 傳送給 Raspberry Pi 處理。由於控制板比較難單獨買到,所以建置就直接買 DIY 套裝組,內附有控制板、八個按鈕、搖桿及連接線,這次的互動機台用不到搖桿,不過可以留著下次用 Raspberry Pi 組裝一台遊戲機

Kiosk 機台設置及互動程式開發

最難的部分都處理完了,接下來就簡單了!

Kiosk 安裝與設置

首先,我們求助 Google 大神就可以找到許多篇使用 Raspberry Pi + Chromium 建置 Kiosk 的機台,Raspberry Pi 等於是一台如信用卡般大小的電腦主機,所以我們其實就是用一台小型的電腦,使其在開機之後自動打開瀏覽器,並開啟我們設置好的頁面。

在這個想法下,我們得注意的是,必須讓 Raspberry Pi 在開機後,控制 Chromium 自動進入全螢幕畫面(這樣才不會看到瀏覽器上方的工具列),而且最好是把 Chromium 自動更新的功能停用,雖然相當來說會有安全性的問題,但可以讓機台的使用者得到較佳的操作體驗(不然就會看到瀏覽器自動跳出更新通知)。至於安全性的問題就只能靠勤來補拙了。

互動程式開發

我們在 Kiosk 上看到的畫面,實際上就是透過 Chromium 打開網頁所呈現的,所以互動機台上提供的畫面、功能,其實都是網頁程式就可以開發出來的。原本預想互動程式開發應該不難,畢竟

  1. HTML5 已具備 <video> 標記,可以直接處理影片內容(蝙蝠聲波變化的影片)
  2. HTML5 也已經支援 Game Pad 的訊號輸入

原本以為 Game Pad 整合的部分比較難處理,所以一開始就先花時間找到一篇教學文章,根據文章內提供的程式碼來試作(如下),想說解決了這道關卡,後面就簡單了。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
        <title></title>
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width">
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
    </head>
    <body>
 
    <div id="gamepadPrompt"></div>
 
    <script>
    function canGame() {
        return "getGamepads" in navigator;
    }
 
    $(document).ready(function() {
        if(canGame()) {
            var prompt = "To begin using your gamepad, connect it and press any button!";
            $("#gamepadPrompt").text(prompt);
 
            $(window).on("gamepadconnected", function() {
                $("#gamepadPrompt").html("Gamepad connected!");
                console.log("connection event");
            });
 
            $(window).on("gamepaddisconnected", function() {
                console.log("disconnection event");
                $("#gamepadPrompt").text(prompt);
            });
        }
    });
    </script>
    </body>
</html>

不過,現實永遠不是像憨人想得如此美好。沒想到,在將程式整合到互動機台時,居然是在影片播放時出了問題,一下子 lag,一下子黑屏,連連發生的影像遲延,實在稱不上是提供了好的使用體驗,只好回頭思考到底哪裡出了問題。

一開始,蝙蝠聲波的影片是採用 mp4 格式,但因為 mp4 輸出的檔案較大,判斷會佔用太多記憶體,所以改用 mkv 格式,mkv 格式與 mp4 的編碼格式相同且檔案極小,猜想應該可以解決問題了。不料,透過瀏覽器播放影片還是會常有當掉的情況發生。

mkv 格式這條路不通後,隨即想到可以嘗試改用 webm 格式,因為 webm 是專為網頁應用而生的影音格式,料想瀏覽器的支持程度應該比較好,但實測後發現播放時非常不順,常有停頓的狀況發現,在進一步追查時看到 Raspberry Pi 論壇上的一篇文章也在討論類似的問題,大意是說,不要使用 HTML video 標記來播放影音,雖然在 Chromium 瀏覽器有開啟 GPU 硬體加速,但畢竟是嵌到瀏覽器在播放,效能是受瀏覽器而有影響。

既然透過瀏覽器這條路行不通,但 Kiosk 還是需要用瀏覽器來當作進入系統後的操作畫面,轉個念,想到既然瀏覽器這條路行不通,那是否可以直接從 command line 呼叫 omxplayer 播放影片,這一試驚為天人,沒想到在 command line 下指令直接播放 mp4 格式的影片超順的。那麼,接下來就是怎麼用 HTML 去呼叫 shell command 來直接播放影片,不過單純用 HTML 是無法直接呼叫 shell 的,這時就得透過 PHP 來達成了。

所以,我寫了一隻 PHP 程式,功能很單純,就是純粹接受參數並呼叫 omxplayer 播放對應的影片(也就是判斷使用者按了哪個按鈕,由 PHP 去呼叫 omxplayer 播放對應的影片),而在原本的網頁程式部分,則透過 jQuery 呼叫 PHP 程式,並傳遞影片編號的參數給 PHP 程式

在做完程式修改的工作後,基本上已經可以順暢地播放影片,堪稱完美,只是在實測過程中發現偶爾會有同時送出多部影片且同時播放的現象(就是當使用者同時按下多個按鈕時會發生,好在直接透過 omxplayer 播放不會當機,只會稍微停頓一下就恢復了),仔細一想其關鍵應該是送了多次 AJAX request 了,於是參考這篇文章加了個變數來避免同時接受多個 AJAX request。

另外,在播放時會遇到「* failed to open vchiq instance」錯誤訊息,解法是修改「/dev/vchiq」的權限,不過在重開機後權限又會被設回原樣,於是在 kiosk.sh(開機後會自動執行的 shell script)加了 chmod 的設定。

後語

組裝機台的過程並不長,相關的程式開發也不算複雜,不過為了達到「使用者體驗良好」,雖然只是影片播放不順暢的問題(一般都會被歸究是主機效能不好而直接忽略不處理),我們反覆查找了許多討論文章、嘗試許多改善方法,就是為了讓互動式機台是可以經得起考驗的(尤其是面對一群小朋友的殘虐式使用下)。