Merhaba arkadaşlar! Bu ay da yeni bir Arduino yazısı ile karşınızdayım! Geçen yazımda Arduino’nun ne olduğundan bahsetmiş ve giriş niteliğinde bir ders yazmıştım. Bu ay kaldığım yerden devam edip daha eğlenceli bir uygulama yapacağım. Lafı çok uzatmadan konuya gireyim…

Bu yazıda bahsedeceğim uygulama Flappy Bird benzeri bir oyun olacak. Fakat bu oyunda kontrol cihazı olarak Arduino’ya bağlayacağımız bir basınç sensörü kullanacağız. Ne kadar kuvvetli bastırırsak kuşumuz o kadar yüksek uçacak. Evet, çok yaratıcı bir fikir değil fakat amacım sensör kullanımını ve Unity ile bağlantı kurmayı öğretmek olduğu için bence gayet yeterli.

İhtiyaç duyacağınız malzemeler; bir adet 10000 Ohm resistör ve bir adet FSR (Force Sensing Resistor) basınç sensörü 4 - 5. Basınç sensörünü hemen hemen her robotik malzeme satan internet sitesinden veya elektronikçiden 15 - 25 tl arası bir fiyata bulabilirsiniz. Ek olarak basit bir düğme ve led alırsanız önce yapacağım alıştırma niteliğindeki ufak uygulamayı da yapabilirsiniz. Ayrıca breadboard alırsanız çok rahat edersiniz.

Sensöre geçmeden önce Arduino’dan veri okuyup Unity’ye aktarma alıştırması yapalım. Öncelikle resimde gördüğünüz, basit bir led devresi kuralım. Bu devrede düğmeye bastığımız zaman led yanacaktır.

Devreyi kısaca anlatayım; sol taraftaki kablo topraklama kablosu (halk arasında eksi olarak da bilinir), hemen yanındaki kırmızı kablo ise güç kablosu (ya da 5 volt, ya da artı). sağ tarafta yine kırmızı kablo artı, mavi ise eksi. Devreyi doğru kurduysanız düğmeye bastığınız anda led yanacaktır (burada breadboard’u anlatmayacağım, daha önce kullanmadıysanız başlamadan önce bağlatılarını iyice araştırın).

Sonraki adımda düğmeye bastığımızı Arduino’ya anlatmamız gerekecek. Bunun için istediğimiz bir pini seçelim (dijial pin olursa daha iyi olur). Bu pin aracığılığı ile veriyi okuyacağız. Şimdi yeni bir kablo alalım (yeşil kablo) ve bir ucunu ledin pozitif bacağına, diğerini ise seçtiğimiz pine bağlayalım. Bu verileri okumak için şöyle bir kod yazmamız icap ediyor:

int input = 7;

    void setup()
    {
            pinMode(input, INPUT);
            digitalWrite(input, LOW);
            Serial.begin(9600);
    }

    void loop()
    {
              Serial.println(digitalRead(input));
              delay(20);
    }

Burada yeni olarak digitalRead() fonksiyonu var, onun amacı da oldukça açık, yukarıda tanımladığımız “input” numaralı pinin değerini okuyor. Bu kodu kartınıza yükleyip “Serial Monitor”üne bakarsanız düğmeye basmıyorken 0’lar, basıyorken ise 1’ler göreceksiniz.

Sıradaki iş bu veriyi Unity’ye aktarmak. Bu yazıyı yazarken Unity3D 4.6 beta versiyonunu kullanıyorum fakat 3.0’dan sonraki herhangi bir sürümde de çalışacaktır. Unity’de yeni bir proje açın ve Edit > Project Settings > Player’da Other Settings’in altındaki Api Compatibility Level’ı .NET 2.0 Subset’ten .NET 2.0’a çekin. Sıra geldi Unity’de C# kodu yazmaya:

using UnityEngine;
    using System.Collections;
    using System.IO.Ports;

    public class Test : MonoBehaviour
    {
            SerialPort sp = new SerialPort("COM3", 9600);

            void Start ()
            {
                    sp.Open();
                sp.ReadTimeout = 25;
        }

        void Update ()
            {
                    Debug.Log(sp.ReadLine());
            }
    }

Burada Unity’ye kod yazmanın detaylarına girmeyeceğim. Normalden farklı olarak yaptığımız şey “using System.IO.Ports;” satırını eklemek, daha sonra “SerialPort sp = new SerialPort(“COM3”, 9600);” şeklinde bir seri port tanımlamak. Buraya yazdığım “COM3”, port numarası ve taktığınız USB’ye göre değişecektir. Geçen derste de bahsettiğim gibi Tools > Serial Port’tan bakarak o anda kullandığınız portu görebilirsiniz.

Start’ta seri portu sp.Open() diye açtıktan sonra sp.ReadTimeout’u 25’e ayarlıyoruz. Bunun anlamı Unity seri porttan gelecek veriyi 25 milisaniye kadar bekleyecek, bu süre içerisinde herhangi bir veri gelmezse TimeOut hatası verecektir. Hatırlarsanız Arduino’daki kodumuzun sonunda delay(20) yazıyordu, bu da Arduino’nun aşağı yukarı 20 milisaniyede bir veri göndereceğini anlatıyor. Her şeyi doğru ayarladıysak TimeOut hatası almıyor olmamız lazım.

Son olarak da veriyi alıp almadığımızı anlamak için Debug.Log(sp.ReadLine()) ile gelen satırı okuyoruz. SerialPort’un ReadLine() haricinde birçok veri okuma fonksiyonu var (ReadChar(), Read() gibi) ancak şu anda işimize yarayacak olan ReadLine(). Bu fonksiyon gelen verileri satır satır okuyacaktır, yani bir ” \n” karakteri bekleyecektir fakat biz Serial.println() fonksiyonunu kullandığımız için gelecek her verinin sonuna yeni satır sembolü (“\n”) otomatik olarak eklenecektir.

Yazdığımız C# scriptini oyun sahnesindeki herhangi bir objeye atın ve oyunu başlatın. Her şey doğru ise Unity’nin konsolunda aynı Serial Monitor’deki gibi bir çıktı göreceksiniz. Bu noktada dikkat etmeniz gereken şey Serial Monitor’un kapalı olması. Aynı anda birden fazla program bir seri porta erişemiyor. Ayrıca oyunu ilk başlattığınız anda bir takım hatalar almanız mümkün, paniğe kapılmadan önce oyunu durdurun ve Arduino’nun üstündeki reset tuşuna basın ya da USB’den çıkarıp takın ve bir daha deneyin.

Buraya kadar herşey tamamsa artık sensörü takmaya hazırız demek. Az önce yaptığımızdan farklı olarak okumayı dijital pinden değil de analog pinden yapacağız. Arduino’ya şu kodu yükleyin:

int analog = 0;
    void setup() 
    {
            pinMode(analog, INPUT);
            digitalWrite(analog, LOW);
            Serial.begin(9600);
    }

    void loop() 
    {
            Serial.println(map(analogRead(analog), 0, 1023, -400, 400));
            delay(20);
    }

Gördüğünüz gibi yeni kodun tek farkı 0. analog girişini okuyoruz. Buradan okuyacağımız değer 0 ile 1023 arasında olacak. 0 değeri 5 voltluk bir potansiyel farka denk gelecek. FSR sensörleri normalde sonsuz direnç gibi davranır, kuvvet uygulandıkça da direnci düşer. Grafiğini aşağıdan veya datasheet’inden bulabilirisiniz:

Kuracağınız devre şu şekilde olacaktır:

Koda fazladan map() fonksiyonunu ekledik. Bu fonksiyon 0 ile 1023 arasındaki değerleri alıp oran orantı kullanarak -400, 400 aralığına yansıtacak. Yani bizim göreceğimiz değer -400 ile 400 arasında olacak. Bunun sebebini birazdan anlayacaksınız.

Şimdi Serial Monitor’u açın ve sensöre bastırıp değişiklikleri görün.

Gelelim Unity’de sahnemizi hazırlamaya.

Sahneye sınır görevi görecek iki adet küp, oyuncuyu temsil edecek bir küre ve ışık kaynağı koymanız yeterli. Oyuncu y koordinatında -4, 4 arasında hareket edecek, Arduino’ya attığımız koddaki map() fonksiyonu tam olarak burada lazım olacak. Şimdi oyuncu kodunu yazdığımız zaman işimiz bitecek:

using UnityEngine;
    using System.Collections;
    using System.IO.Ports;

    public class Player : MonoBehaviour
    {
            SerialPort sp = new SerialPort("COM3", 9600);
            float input = 0;

            void Start()
            {
                    sp.Open();
                    sp.ReadTimeout = 25;
            }
            void OnGUI()
            {
                    GUI.Label(new Rect(100, 100, 100, 50), input.ToString());
            }

            void Update()
            {
                    input = float.Parse(sp.ReadLine());
                    transform.position = Vector3.Lerp(transform.position, new Vector3(0, input / 100, 0), 0.5f);
            }
    }

Bu kodda bir öncekinden farklı olarak gui ekledim ki okuduğumuz değeri konsoldan değil oyun içinden görelim. Update’in içinde gelen satırı okuyup input isimli bir float’a atıyoruz, bir sonraki satırda ise oyuncunun y pozisyonunu input / 100’e, yani -4, 4 arası bir rakama atıyoruz. Burada Vector3.Lerp() kullanmamızın amacı topun dengesiz hareketler yapmadan gideceği noktaya yavaş yavaş gitmesi. sp.RealLine()’dan okuduğunuz verileri konsola bastırıp incelerseniz gelen değerlerin çok ani artışlar / düşüşler gösterdiğini gözlemleyebilirsiniz. Lerp fonksiyonu oyuncunun bu değerlere “ışınlanmasını” engelleyecek ve düzgün bir hareket görmemizi sağlayacaktır. Her şey doğru gittiyse sensöre bastırdığınız zaman oyuncu yukarı çıkacaktır.

Arduino ile yapılacak bir şey kalmadığı için oyunun devamını tasarlama, geliştirme işini sizlere bırakıyorum. Burada anlattığım şekildeki gibi sadece basınç sensörünü değil, hareket sensöründen ışık sensörlerine kadar hemen hemen her sensörü kullanabilirsiniz. Bu şekilde çeşitli tasarımlar yaparak çok orijinal ve yenilikçi oyunlar / kontrol sistemleri geliştirebilirsiniz.

Önümüzdeki aylarda bir de Unity’den Arduino kontrolünü anlatıp bu yazı serisini bitiririm. Kendinize çok iyi bakmanız dileği ile, hoşçakalın.

Kaynakça: