Anda di sini

Pemrograman

Implementasi Perangkat Lunak Govinda Rover Mark 2

Aditya Suranata - 21 Februari 2016 11:49:33 0

Setelah perangkat keras terintegrasi dengan baik, maka dapat dilanjutkan dengan pemasangan komponen perangkat lunak. Sesuai dengan urutan dan pembagian perangkat lunak pada desain, seperti terlihat pada Gambar 4.8 yaitu firmware mikrokontroler, sistem operasi & software server dan antarmuka web, maka modul pertama yang diimplemetasi adalah firmware mikrokontroler yang terdiri dari bagian flow control dan fungsi untuk mengontrol arah pergerakan, kecepatan, penerangan, penunjuk dan arah kepala robot.

Gambar 4.8 Struktur Keseluruhan Modul Perangkat Lunak

Dilanjutkan dengan implementasi software server yang terdiri dari web framework yang menangani semua aktifitas yang berkaitan dengan web, proses-proses yang menangani komunikasi serial, kamera, peripheral, dan jaringan. Terkahir implemetasi antarmuka web yang dapat mendukung teknologi layar sentuh dan responsif terhadap berbagai macam perangkat dengan ukuran layar berbeda.

Implementasi Firmware Mikrokontroler

Program pada modul mikrokontroler diprogram menggunakan Arduino IDE. Bahasa Arduino menggunakan bahasa abstraksi yang mirip dengan bahasa C dan dikonversi ke C/C++ ketika dikompilasi. Berikut adalah potongan kode program pada firmware mikrokontroler untuk menjelaskan alur program.

if(Serial.available() > 0) {
    char mode = Serial.read();
    switch(mode) {
        case 'q': {
            //kirim sandi deteksi otomatis
            //parameter: -
            //return: str(sandi)
            break;
        }
        case 'k': {
            //fungsi pergerakan robot, kanan kiri maju dan mundur
            //parameter: int(arah) -
            //1=Maju,2Mundur,3=Kanan,4=Kiri, 5-10,0=Stop
            //return: -
            break;
        }
        case 'p': {
            //fungsi pengatur kecepatan motor (PWM)
            //parameter: int(pwmKanan) - 0=Min,255Max |
            //int(pwmKiri) - 0=Min,255Max
            //return: -
            break;
        }
        case 'f' : {
            //saklar flash
            //parameter: -
            //return: int(flag_flash) - 0=Mati,1=Hidup
            break;
        }
        case 'r' : {
            //saklar red laser
            //parameter: -
            //return: int(flag_rlaser) - 0=Mati,1=Hidup
            break;
        }
        case 'g' : {
            //saklar green laser
            //parameter: -
            //return: int(flag_glaser) - 0=Mati,1=Hidup
            break;
        }
        case 'm' : {
            //fungsi kontrol servo untuk arah kepala robot
            //parameter: int(servoLaserX) - 0=Min,255Max |
            //int(servoLaserY) - 0=Min,255Max
            //return: -
            break;
        }
    }}

Firmware mikrokontroler mendengarkan komunikasi serial dalam fungsi loop() dan ketika terdapat data akan diteruskan ke switch case untuk menentukan tipe perintah. Data yang dikirim berupa karakter yang mewakili masing-masing fungsi. Selanjutnya, setelah masuk ke salah satu case, fungsi pada blok case tersebut akan dijalankan. Apabila fungsi pada case memerlukan data tambahan, misal untuk case p yang memerlukan nilai PWM motor kanan dan kiri, sebuah fungsi loop() lain akan dijalankan untuk mendengarkan komunikasi serial hingga karakter end stream diterima, yang dalam kode program menggunakan karakter "o". Misal, mengirim string("p") kemudian dilanjutkan dengan string(255o255o) akan membuat nilai PWM motor kanan dan kiri bernilai 255.

Untuk fungsi deteksi otomatis alamat port serial ketika setiap kali Arduino dinyalakan, firmware mikrokontroler menggunakan metode query sandi. Metode ini bekerja dengan cara mendengarkan permintaan query port locator dari Raspberry Pi dimana Raspberry Pi akan membuat daftar alamat perangkat serial yang tersedia dan mengirimkan query ke masing-masing perangkat hingga ditemukan perangkat yang mengirim jawaban balik berupa sandi yang sesuai, sehingga Raspberry Pi dapat mengenali Arduino secara otomatis tanpa memerlukan pengguna untuk menentukan alamat port secara manual.

Implementasi Software Server

Software server diimplementasi menggunakan bahasa Python 2.7, namun sebelum dapat mulai membangun program menggunakan editor Notepad++ dan remote debugging menggunakan SSH dengan Putty yang terbukti ringan dan handal, langkah pertama yang harus dilakukan adalah memasang dan konfigurasi sistem operasi. Dalam platform ini, sistem operasi yang digunakan adalah Linux Debian yang dibangun khusus untuk perangkat keras Raspberry Pi yaitu Raspbian Wheezy. Instalasi sistem operasi dimulai dengan mengunduh image sistem operasi rilis terbaru dari situs resmi Raspberry Pi (http://www.raspberrypi.org/downloads/), kemudian dilakukan penulisan image ke kartu SD menggunakan Win32 Disk Imager seperti terlihat pada Gambar 4.9. Pada antarmuka Win32 Disk Imager, langkah pertama adalah menentukan file image sistem operasi yang digunakan, dalam platform ini menggunakan image dengan versi rilis 2014-09-09-wheezy-raspbian.img. Setelah memilih file image, dilanjutkan dengan memilih drive letter dari kartu SD yang akan digunakan. Disarankan untuk menggunakan kartu SD dengan kapasitas minimal 8GB dengan kelas 10. Ini akan membantu banyak dalam hal performa dan memberikan ruang cukup banyak untuk menyimpan file nantinya. Perlu diperhatikan ketika menulis image, memilih drive letter harus dengan hati-hati, karena kartu yang akan ditulis akan diformat dan menghilangkah data yang ada sebelumnya.

Gambar 4.9 Menulis Image Sistem Operasi dengan Win32 Disk Imager

Setelah melakukan penulisan image sistem operasi, maka proses instalasi dilanjutkan dengan konfigurasi sistem operasi. Pada halaman F.A.Q dari Raspberry Pi (http://www.raspberrypi.org/help/faqs/) telah dijelaskan proses konfigurasi sistem operasi Raspbian Wheezy, mulai dari seting data login, lokasi, bahasa dan waktu , ekspansi ruang penyimpanan, konfigurasi jaringan dan lainnya. Setelah sistem operasi berjalan, pekerjaan selanjutnya adalah menyiapkan lingkungan kerja untuk mendukung pembangunan program menggunakan Python.

Aplikasi software server dibangun menggunakan Python Tornado sebagai web framework. Paket pustaka Python Tornado mesti dipasang secara manual mengingat sistem operasi hanya menyediakan paket dasar Python 2.7. Python Tornado dapat dipasang dengan menggunakan tool paket yang tersedia baik dari sistem operasi (menggunakan apt-get) maupun Python sendiri yaitu "pip". Berikut merupakan perintah untuk menginstal paket Python Tornado:

#update daftar paket
sudo apt-get update -y
#update perangkat lunak sistem dan aplikasi
sudo apt-get dist-upgrade -y
#install pip
sudo apt-get install python-pip
#install tornado
sudo pip install tornado

Setelah paket Tornado terpasang, dilanjutkan dengan membuat struktur direktori tempat file proyek akan disimpan. Berikut adalah struktur dasar dari direktori proyek yang terletak di /home/pi/bin/grindira:

+---cert
+---static
| +---css
| | +---images
| +---DCIM
| | +---thumbs
| +---fonts
| +---img
| +---js
| +---motion
| +---MOVIE
| +---thumbs
+---template
+---js

Pada root direktori (/home/pi/bin/grindira) terdapat file script Python yang merupakan kode program dari perangkat lunak server. Direktori "cert" digunakan untuk menyimpan file sertifikat SSL dari domain web apabila server diaktifkan dalam mode SSL/HTTPS. Kedua direktori "static" berisi file statik berupa file css, gambar, js dan font yang digunakan oleh template web pada antarmuka. Dan terkahir direktori "template" berisi file HTML dan JS dinamis yang merupakan file template yang di-parsing oleh Tornado.

Menghubungkan Robot Ke Jaringan Wi-Fi

Untuk menghubungkan robot secara otomatis ke jarigan Wi-Fi, platform Govinda Rover meggunakan pengatur jaringan nirkabel yang disediakan oleh sistem operasi yaitu "wpa_supplicant" sebagai daemon. Sesuai dengan arahan manual dari program "wpa_supplicant", konfigurasi jaringan nirkabel disimpan pada file konfigurasi yang terletak di /etc/wpa_supplicant/wpa_supplicant.conf. Format konfigurasi dari file tersebut didapat dari program "wpa_passphrase" yang akan membuat konfigurasi secara otomatis hanya dengan memberikannya argumen SSID dan key dari jaringan yang akan dihubungi. Berikut merupakan contoh perintah untuk membuat konfigurasi "wpa_supplicant", yang selanjutnya output yang dikeluarkan disalin dan ditempel pada file konfigurasi "wpa_supplicant".

$wpa_passphrase "Access Point 1" SandiAP1

Output dari perintah tersebut menghasilkan string konfigurasi untuk wpa_supplicant terlihat sebagai berikut:

network={
        ssid="Access Point 1"
        #psk="SandiAP1"
        psk=f5a08c9c7b8c1ac02293cf84626bed3454887123cde57710de1e5c5f23577f91
}

Melalui kelas networkingProcess(), program "wpa_supplicant" dijalankan melalui Pipe, menggunakan paket subprocess. Berikut merupakan potongan kode pemanggilan program "wpa_supplicant" pada script Python:

import subprocess_compat as subprocess
w = subprocess.check_output(['/sbin/wpa_supplicant', '-Dwext', '-i'+self.interface, '-c', '/etc/wpa_supplicant/wpa_supplicant.conf', '-B'],stderr=subprocess.STDOUT)

Dengan demikian, "wpa_supplicant" akan berjalan di latar belakang dan secara otomatis akan megatur jaringan nirkabel.

Tornado Web Framework Sebagai Server

Modul utama dari paket Tornado adalah tornado.web, yang mana mengimplementasikan sebuah framwork pengembangan web yang sangat ringan. tornado.web dibangun menggunakan non-blocking HTTP server dan modul I/O tingkat rendah. Untuk memberikan bayangan, berikut merupakan potongan kode dasar untuk mengimplementasikan program "Hello, world" di Tornado:

import tornado.httpserver
import tornado.ioloop
import tornado.web
class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, world")
application = tornado.web.Application([
    (r"/", MainHandler),
])
if __name__ == "__main__":
    http_server = tornado.httpserver.HTTPServer(application)
    http_server.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

Pada perangkat lunak server Govinda Rover, Tornado tidak hanya digunakan sebagai HTTP server, namun juga merangkap beberapa handler termasuk WebSocket. Berikut merupakan potongan kode pada file "main.py" yang merupakan file utama dimana fungsi main() untuk menjalankan server berada:

tornado.options.parse_command_line()
    app = tornado.web.Application(
        handlers=[
            (r"/", IndexHandler),
            (r"/js/sihir.js", SihirHandler),
            (r"/js/websocket.js", WSSHandler),
            (r"/ws", WebSocketHandler),
            (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': static}),
            (r'/rec/(.*)', recHandler, {'path': 'rec'}),
        ], queue_serialProc=taskQ_serialProc, queue_cameraProc=taskQ_cameraProc, queue_peripheralProc=taskQ_peripheralProc, queue_networkingProc=taskQ_networkingProc, queue_fmProc=taskQ_fmProc, debug=debug, logging=None, template_path=template
    )
    if(port == '443'):
        httpServer = tornado.httpserver.HTTPServer(app,ssl_options=SSL_OPTIONS)
    else:
        httpServer = tornado.httpserver.HTTPServer(app)
        httpServer.listen(port,address=listen)

Sesuai dengan kofigurasi yang diset oleh pengguna pada file konfigurasi (/home/pi/bin/grindira/grindira.conf), untuk nomer port dimana server akan dijalankan, apabila pengguna memilih nomer port diluar port 443 maka server akan dijalankan pada layanan tanpa enkripsi. Apabila menggunakan port 443, pengguna diperlukan untuk menyediakan file sertifikat SSL pada direktori SSL dan menulis lokasi file sertifikat serta nama domain pada file konfigurasi untuk mengaktifkan SSL. tornado.web.Application juga menerima parameter tambahan berupa obyek multiprocessing.Queue() yang digunakan untuk bertukar informasi atau berkomunikasi antar proses dalam instan kalang tornado.ioloop.IOLoop.instance() diantarnya yaitu mainLoop untuk instan utama, cameraLoop untuk instan kamera & stream, networkingLoop untuk jaringan, dan serialLoop untuk komunikasi serial. Dari lima handler yang diset, satu yang berbeda adalah WebSocket handler, handler ini menggunakan parameter tornado.websocket.WebSocketHandler, berikut adalah potongan kode kelas WebSocketHandler dengan URL "/ws":

class WebSocketHandler(tornado.websocket.WebSocketHandler):
    def check_origin(self, origin):
        #domain cek untuk memastikan aman dari CSRF
        return parsed_origin.netloc.endswith(domain)
    def open(self):
        #lakukan rutin untuk pre otentikasi
        #(klien pertama kali membuka koneksi)
        pass
    def on_message(self, message):
        #ketika pesan diterima dari klien
        pass
    def on_close(self)
        #ketika klien terputus
        pass

Kelas WebSocketHandler terdiri dari empat buah fungsi yang di-override dari kelas aslinya. Pertama adalah fungsi check_origin() untuk mengeset security check dari Tornado untuk memastikan keaslian domain. Kedua fungsi open() berisi segala rutin yang harus dilakukan ketika klien pertama kali membuka koneksi, seperti mengeset atribut klien dan mendaftarkannya ke daftar guest yang menunggu proses otentikasi untuk bisa menggunakan layanan. Fungsi ketiga adalah on_message(), dalam fungsi ini pesan yang dikirim oleh klien akan ditangani, dan dilakukan validasi apakah klien yang mengirim pesan yang berupa perintah memiliki hak untuk menjalankan perintah tersebut, seperti proses login, mengeset atribut pasca login, routing perintah sesuai dengan proses tujuan (apakah ke kamera, jaringan atau lainnya) dan rutin lain. Terkahir adalah fungsi on_close(), dimana merupakan fungsi yang berisi rutin yang mesti dijalankan ketika klien terputus dari layanan. Seperti clean-up memori, mematikan proses atau layanan yang tidak perlu ketika tidak terdapat klien yang terhubung dan lainnya.

Empat lainnya merupakan handler tornado.web.RequestHandler diantaranya "/" yang merupakan handler untuk index dimana pertama kali klien mendarat ketika membuka antarmuka web. Tiga lainnya adalah handler untuk file statik dan template, seperti JavaScript dan file multimedia (foto dan video) hasil perekaman.

Modul RaspiCam dengan Picamera

Modul RaspiCam yang digunakan pada proyek ini menggunakan pustaka Picamera yang ditulis dalam bahasa Python untuk mendukung penggunaan segala fungsi pada modul RaspiCam. Picamera merupakan pustaka terlengkap dengan dokumentasi terbaik dalam bahasa Python untuk modul RaspiCam. Implementasi dari perangkat lunak Picamera ditanamkan pada kelas cameraProcess() yang mana dijalankan bersama dengan ketiga proses lainnya ketika server dijalankan. Berikut merupakan potongan kode instansiasi Picamera:

import  picamera
camera = picamera.PiCamera()
def outputs():
    for i in range(1):
        yield stream
        stream.seek(0)
        if(self.flag_motion_detect):
            #lakukan perhitungan deteksi gerakan
            #kirim hasilnya ke web
            pass
        if(self.flag_stream_image):
            #lakukan pengambilan Gambar untuk disiarkan ke web
            pass
camera.capture_sequence(outputs(), 'jpeg', use_video_port=True, quality=self.quality)

Metode camera.capture_sequence() memungkinkan untuk melihat siaran dari kamera sekaligus melakukan perekaman video secara live dengan mengeset parameter user_video_port() dengan nilai True. Ini akan sangat membantu ketika diperlukan untuk mengambil video sekaligus melihat umpan dari kamera. Picamera juga mendukung pengesetan nilai atau parameter kamera on the fly ketika program berjalan. Seperti mengeset nilai kontras, mode AWB, ISO dan lainnya dengan memanggil masing-masing metode seperti camera.brightness = 100 atau camera.contrast = 50.

Untuk mengakomodasi perubahan bandwidth yang tersedia pada jaringan, juga tersedia fungsi untuk mengubah resolusi dari gambar yang disiarkan ke antarmuka. Tabel 4.1 menampilkan daftar resolusi yang didukung oleh platform.

Tabel 4.1 Daftar Resolusi Kamera yang Didukung Oleh Platform

Dengan mengganti resolusi siar melalui antarmuka untuk menyesuaikan dengan ketersediaan sumber daya jaringan maka dapat membantu memberikan performa terbaik pada antarmuka.

Menyiarkan Gambar ke Web via WebSocket

Menyiarkan gambar hasil capture ke web browser menggunakan protokol selain HTTP biasa seperti WebSocket memerlukan sedikit usaha tambahan. Dalam implementasi cameraProcess, gambar yang telah di tangkap disiarkan ke web dengan cara mengubah format gambar ke dalam bentuk string ketika dikirim, baru kemudian dirubah kembali ke bit menggunakan JavaScript untuk ditampilkan pada antarmuka. Berikut merupakan potongan kode dari fungsi penyiar gambar ke web:

import base64
if(self.flag_stream_image):
            #lakukan pengambilan Gambar untuk disiarkan ke web
            #putar stream ke awal sebelum dibaca
            stream.seek(0)
            #baca stream untuk mendapatkan data Gambar
            image = stream.read()
            #konversi ke string base64
            image = base64.b64encode(image)
            #siapkan JSON Query untuk dikirim ke klien
            rpl = {
                'task' : 'feed',
                'role' : '*',
                'data' : {
                    'camFeed' : {
                        'type': 'image/jpeg',
                        'data': image
                    }
                }
            }
            #kirim ke klien
            self.resultQ.put(rpl)
            # reset stream untuk pengambilan selanjutnya
            stream.seek(0)
            stream.truncate()

Setelah data gambar didapatkan, data gambar yang masih berupa image stream string dikonversi menjadi string base64 agar dapat ditransfer ke klien melalui WebSocket dengan menggunakan fungsi base64.b64encode(). Setelah data gambar berbentuk data yang dapat ditransfer via WebSocket, data gambar dimasukan ke format perintah berupa JSON agar dapat dikirim ke klien melalui fungsi self.resultQ.put().

Menggunakan OpenCV untuk Motion Detection

Membuat fungsi deteksi gerakan (motion detection) menggunakan pustaka OpenCV cukup mudah. Prinsip umum yang banyak digunakan adalah dengan metode differential image. Metode ini membedakan dua buah Gambar dengan cara menguranginya, dan menentukan nilai perubahan berdasarkan jumlah selisih dari hasil pengurangan tersebut untuk dibandingkan dengan batasan tertentu dimana gerakan dianggap ada. Berikut merupakan potongan kode dari fungsi deteksi gerakan:

import cv2
def detect_motion(self, image):
    try:
        #resize frame agar resolusi tetap sama
        resize_resolution = (100, 95)
        image = cv2.resize(image, resize_resolution)
        # jika self.avg1 tidak ada, inisialisasi
        try:
            self.avg1
        except:
            self.avg1 = np.float32(image)
        #hitung rata2
        cv2.accumulateWeighted(image, self.avg1, 0.7)
        res1 = cv2.convertScaleAbs(self.avg1)
        #pergerakan rata2 - frame sekarang
        difference = cv2.absdiff(res1, image)
        #sum level deteksi
        detection_level = np.sum(difference) / 1000
        #kembalikan nilai level deteksi untuk dibandingkan
        #dengan threshold, untuk mentukan ada tidaknya gerakan
        return detection_level
    except Exception, err:
        pass

Fungsi tersebut mengembalikan nilai perbedaan antara frame-frame yang diolah sehingga dapat dibandingkan untuk menentukan adanya gerakan. Selanjutnya, apabila terdeteksi gerakan, maka dapat dilakukan aksi lanjutan berupa menyimpan frame gambar yang dianggap terdapat perubahan dan melampirkan gambar tersebut untuk dikirim via email.

Implementasi Antarmuka Web

Antarmuka web menggunakan lingkungan standar pengembangan web responsif. Seperti penggunaan Bootstrap sebagai front-end developement framework, jQuery dan pustaka JavaScript lainnya. Untuk memudahkan pengguna dalam mengoperasikan perangkat Govinda Rover, antarmuka menyediakan dua buah jenis kontrol untuk pergerakan robot. Untuk perangkat yang mendukung fungsi layar sentuh, pengguna dapat memanfaatkan fungsi touch pada HTML5, memberikan pengalaman kontrol seperti joystick sehingga memudahkan pengontrolan. Untuk perangkat non layar sentuh, kontrol yang digunakan dapat menggunakan keyboard shortcut, maupun mouse untuk mengklik kontrol pada antarmuka.

Antarmuka terhubung dengan server melalui protokol HTTP untuk meminta file template, setelah template selesai dimuat, selanjutnya protokol baru dibuka yaitu WebSocket. Segala aktifitas yang berhubungan dengan request/response dilakukan melalui WebSocket. HTTP hanya digunakan untuk meminta template dan file multimedia hasil perekaman (diluar siaran langsung gambar dari kamera). Berikut merupakan potongan kode WebSocket pada antarmuka:

jQuery(document).ready(function($) {
    var socket = new ReconnectingWebSocket( {% raw wsUrl %} );
    socket.onopen = function(){  
        //lakukan inisialisasi
        //doLogin()
        //init()
        //etc
    };
    socket.onmessage = function (message) {
        pushData = JSON.parse(message.data);
        //parsing pushData sesuai query
    };
    socket.onclose = function(){
        onClose();
    };
    sendMessage = function(message) {
        socket.send(message);
        return "Terkirim: " + message;
    }
}); 

Pada platform ini, WebSocket diinstansiasi mengguakan pustaka khusus ReconnectingWebSocket.js yang mengabstraksi fungsi WebSocket asli pada web browser. Pustaka ini digunakan karena mendukung fungsi umum untuk menjaga koneksi tetap bekerja, seperti menghubungkan diri ulang secara otomatis apabila terjadi kegagalan koneksi. Obyek socket diinstantsiasi pada baris var socket = new ReconnectingWebSocket( {% raw wsUrl %} ); dimana argumen alamat server ({% raw wsUrl %}) dibuat secara dinamis melalui Tornado Web Template untuk menyesuaikan nama domain dan ada tidaknya proteksi SSL.

Pada dasarya, WebSocket memiliki tiga event handler yang bisa digunakan untuk menjalankan rutin berdasarkan event. Pertama adalah socket.onopen(), pada event ini segala inisialisasi ketika klien pertama kali terhubung ke server dilakukan, seperti meminta otentikasi dan pengesetan atribut klien. Kedua socket.onmessage(), dijalankan ketika klien menerima pesan dari server, pesan ini seperti pesan jawaban permintaan otentikasi, maupun umpan balik dari perintah yang dikirim oleh klien, atau jika terdapat data baru yang tersedia di server dan harus di broadcast ke klien akan langsung dikirim tanpa harus diminta oleh klien terlebih dahulu. Fungsi keempat adalah fungsi untuk mengirim pesan ke server socket.send() yang di abstraksi menjadi sendMessage(). Pesan yang dikirim berupa JSON string yang berisi data perintah, id pegirim dan nilai atau argumen bila ada.

Menampilkan Umpan Kamera

Seperti yang dijelaskan pada bagian sebelumnya mengenai gambar hasil tangkapan langsung kamera yang disiarkan secara langsung ke antarmuka web melalui protokol WebSocket, sehingga format gambar yang dikirim tidak dapat langsung ditampilkan pada web browser seperti menampilkan gambar dari URL HTTP. Untuk menampilkan gambar yang dikirim dalam format string base64, diperlukan fungsi tambahan untuk mengubah kembali format gambar tersebut ke format yang dapat dibaca oleh web browser. Berikut merupakan potongan kode JavaScript yang digunakan untuk menampilkan:

if(pushData.camFeed){
     //console.log('memuat camfeed');
     var type = pushData.camFeed.type;
     var data = pushData.camFeed.data;
     $("#camera-canvas").attr("src",'data:'+type+';base64,'+data);
}

Server mengirim data gambar berupa obyek JSON yang terdiri dari data gambar pushData.camFeed.data dan format gambar pushData.camFeed.type. Selanjutnya data tersebut dimuat ke atribut dari DOM (Document Object Model) pada HTML menggunakan jQuery dengan data gambar yang berbentuk string base64 sebagai sumbernya dan tipe gambar untuk menentukan format gambar yang dikirim oleh server, yang secara bawaan adalah JPEG. Dengan cara ini, setiap kali server mengirim gambar untuk disiarkan pada antarmuka, gambar akan secara otomatis terupdate dan terlihat seperti siaran video, meskipun pada dasarnya merupakan file JPEG yang ditampilkan dengan cepat.

HTML5 Multi-touch untuk Kontrol Joystick

Web Browser moderen yang mendukung fungsi layar sentuh dapat dimanfaatkan fungsinya sebagai kontrol layaknya kontrol pada video game. Kontrol semacam ini akan memudahkan pengguna yang memiliki ukuran layar kecil dan menengah seperti ponsel pintar dan komputer tablet yang tidak memiliki keyboard fisik dan mouse untuk melakukan pengontrolan gerak robot hanya dengan menggunakan jari-jari mereka pada layar.

Untuk implementasi teknik ini, cara natural pertama adalah menemukan cara bagaimana mendapatkan data sentuhan dalam JavaScript. Sebenarnya solusinya cukup sederhana, terdapat tiga buah event yang di-broadcast oleh DOM elemen manapun yang bisa disentuh, yaitu touchstart, touchmove dan touchend. Namun sebelum hal tersebut dapat dilakukan, harus dipastikan terlebih dahulu apakah lingkungan antarmuka mendukung adanya fungsi sentuh. Caranya adalah dengan dengan mengecek apakah createTouch merupakan bagian dari properti dokumen.

var touchable = 'createTouch' in document;

Jika touchable bernilai true, beberapa event listener dapat ditambahkan ke elemen kanvas seperti berikut:

if(touchable) {
    canvas.addEventListener( 'touchstart', onTouchStart, false );
    canvas.addEventListener( 'touchmove', onTouchMove, false );
    canvas.addEventListener( 'touchend', onTouchEnd, false );
}

Selajutnya masing-masing fungsi didefinisikan dengan spesifik:

function onTouchStart(event) {
    //Lakukan inisialisasi ketika jari pertama kali
    //menyentuh elementFromPoint
    //Cegah browser melakukan tindakan default
    e.preventDefault();
    //dump data sentuh ke array touch
    touches = e.changedTouches;
    //set pointer ke titik sentuh
    setPointer();   
    //Gambar kanvas dengan lingkaran sentuh
    drawPointer();
    //lakukan perhitungan pemanggilan fugsi
    startDetak();
}
function onTouchMove(event) {
    e.preventDefault();
    touches = e.changedTouches;
    //Gambar kanvas sesuai pergerakan
    drawCanvas();
}
function onTouchEnd(event) {
    e.preventDefault();
    //clear nilai kontrol ke awal
    difX = '';
    difY = '';
    h_difX = '';
    h_difY = '';
    c.clearRect(0,0,canvas.width, canvas.height);
    //hentikan gerakan robot
    sendMoveTo('x');
    //hentikan detak pemanggilan fungsi
    stopDetak();
}

Dalam setiap touch listener, event merupakan obyek yang menyediakan semua data sentuh, dan berisikan tiga buah array diantaranya adalah:

  1. event.touches: semua data sentuhan yang sedang berlangsung.
  2. event.targetTouches: semua data sentuhan yang aslinya berasal dari elemen DOM target.
  3. event.changedTouches: hanya data sentuhan bergerak yang memicu event.

Untuk touchstart dan touchend, changedTouches biasanya hanya berisi satu touch event (kecuali jika dua jari menyentuhan pada waktu yang benar-benar bersamaan). Setiap array berisi obyek data setuhan dengan properti sebagai berikut:

  1. identifier: sebuah nomer unik yang memungkinkan untuk melacak touch event ketika sentuhan berpindah.
  2. target: DOM elemen yang mem-broadcast event tersebut.
  3. clientX, clientY: posisi sentuhan relatif ke viewport.
  4. screenX, screenY: posisi sentuhan relatif ke layar.
  5. pageX, pageY: posisi sentuhan relatif ke halaman penuh.

Pemanggilan event.preventDefault(); pada event touchmove diperlukan untuk mematikan scrolling otomatis pada perangkat berlayar sentuh. Gambar 4.10. menampilkan bagaimana teknik ini bekerja pada antarmuka Govinda Rover.

Gambar 4.10 Fungsi Kontrol Multi-touch pada Antarmuka Govinda Rover

Gambar 4.10 menunjukan dua buah lingkaran kontrol, yang mana yang pertama kali disentuh akan berwarna merah dan biru pada lingkaran luarnya (sisi kiri) dan berfungsi sebagai kontrol untuk pergerakan roda robot. Titik yang disentuh kedua kali sementara lingkaran pertama masih disentuh akan memunculkan lingkaran kedua yang berwana merah dan oranye (sisi kanan) merupakan kontrol untuk merubah arah kamera (modul kepala). Ketika kedua lingkaran dilepas, pergerakan robot secara otomatis akan terhenti. Lingkaran dapat muncul pada bagian manapun pada antarmuka. Lingkaran kecil yang berwarna kuning menandakan koordinat atau tingkat akselerasi.

Keyboard Shortcut untuk Mengontrol Robot

Untuk perangkat non layar sentuh, penggunakan keyboard shortcut dan mouse sebagai kontrol merupakan cara terbaik. Pada antarmuka Govinda Rover telah ditanamkan fungsi keyboard shortcut untuk mengakses fungsi-fungsi pergerakan dan kendali robot menggunakan pustaka JavaScript Mousetrap. Pustaka ini cukup mudah digunakan, berikut merupakan potongan kode dimana Mousetrap digunakan untuk membuat keyboard shortcut untuk mengendalikan robot:

/* KEY SHORTCUT */
Mousetrap.bind('f', function() { toggleFlash(); }, 'keyup');
Mousetrap.bind('r', function() { toggleRLaser(); }, 'keyup');
Mousetrap.bind('g', function() { toggleGLaser(); }, 'keyup');
Mousetrap.bind('m', function() { toggleMotionDetection(); }, 'keyup');
Mousetrap.bind('c', function() { toggleStream(); }, 'keyup');
Mousetrap.bind('n', function() { toggleNetStat(); }, 'keyup');
Mousetrap.bind('p', function() { setRelayPower(); }, 'keyup');

Fungsi bind() pada Mousetrap memerlukan tiga buah argumen, pertama adalah karakter pada keyboard yang akan di-listen, kedua fungsi yang dipanggil ketika terdapat event, dan ketiga merupakan event yang akan memicu pemanggilan fungsi pada key yang terdiri dari event keyup, keypress dan keydown. Tabel 4.2 menampilkan daftar keyboard shortcut yang terdapat pada antarmuka Govinda Rover:

Tabel 4.2 Daftar Keyboard Shortcut Pada Antarmuka Govinda Rover

880
Daftar Artikel Terkait
Image

Aditya Suranata

Aditya suka menulis, bukan hanya sekedar hobi, menulis menjadi medianya untuk mencurahkan pikiran dan perasaan. Di TutorKeren.com kebanyakan menyumbang tulisan sesuai dengan minat dan keahliannya yaitu pada kategori pemrograman dan elektronika. Selain itu juga gemar menulis mengenai hal-hal umum, seperti ilmu alam, sosial dan beberapa pengalamannya yang mungkin bisa berguna untuk orang lain.

Artikel Menarik Lainnya
Mari Gabung

Halo Emo 51 , Ada yang ingin disampaikan? Jangan sungkan untuk gabung diskusi ini. Silahkan Login dulu atau Daftar baru.