proje_resim2Merhaba arkadaşlar bu yazımda yine sizlere basit ama kullanışlı bir uygulama ile karşınızdayım. Uygulama olarak bir Android telefondaki dahili ivme ( accelerometer ) sensörünü kullanarak bir oyuncak arabamı ileri geri ilerletmeye çalışacağım. Uygulamayı basit seviyede tutmak istedim. Sistemimizde Java bulunacak bir bilgisayar yardımı ile local network sayesinde Android sensöründen gelen bilgiyi ez430-RF2500 kartına aktarıp devamında eşlenik aygıta veriyi gönderip arabamıza hareket kazandıracağız.
Kafanızı fazla karıştırmadan şemaya bakalım .

Şema :
proje_sema

Şemayı anlatacak olursam ; bir android telefonumuz bulunmaktadır. Wifi özelliği ile router/modem ‘e bağlanmıştır. Bir bilgisayarımız bulunmakta ve aynı local ağa bağlayabilmek için wifi ile modeme bağlıyoruz. Aynı zamanda ez430-RF2500 kitimizin debugger’lı olan kısmını bilgisayara bağlıyoruz. Akabinde motor devremize’de target kısmını bağlayacağız.

Kısa algoritmadan bahsedecek olursak. Android telefonda öncelikli ivme ölçerden eksen bilgileri alınacaktır. Alınan bilgiler  soket bağlantısı üzerinden eksen bilgisi gönderilmektedir.Bilgisayarda JAVA üzerinden bir server kurulur ve belirlenen Port açılır. Bağlantı beklenir telefon üzerinden gelecek bağlantı ve bilgi beklenir. Bilgi sağlandığı takdirde veriler okunur.

Okunan bilgiler Uart üzerinden ez430-RF2500 debugger’a aktarmaktadır. RF2500 debugger’lı kısım başlangıçta Uart’tan bilgi beklemektedir. Bilgi geldiği takdirde target’a üzerinde bulunan modül yardımı ile bilgiyi aktarmaktadır. Target modül bekleme durumda olup RF bağlantı sağlandıktan sonra bilgiyi almaktadır. Bilgiye göre motor devresine bilgiyi sağlayacak portları aktif yada pasif etmektedir. Bu işlemler sırasında debugger ve target düşük güç modunda çalışmaktadır.

Motor kontrol devresi bir aktiflik biti kontrolü yapmaktadır. Aktiflik durumu sağlandığı an ( Pin = 1) belirlenen giriş portlarından bilgi dijital seviye kontrolü yapmaktadır. Kontrol sonrasında motorun uçlarına pozitif yada negatif alternansta çıkışlar uygulamaktadır. Bu devrede motor gücünü isteğinize bağlı olarak bataryadan yada pil’den sağlayabilirsiniz.

Buraya kadar basitçe anlattıktan sonra Android kısmından başlayarak  bütün işlemlerimizi yapalım.

Android tarafında yapılacaklar listesi :

  • Grafiksel arayüz tasarımı
  • Görsel tanımlamalar
  • Sensör bilgisi okuma
  • Sensör bilgisi sentezleme
  • Soket üzerinden veri aktarılması

Eclipse’de bir android projesi oluşturmayı detaylı olarak genel kapsamlı olarak önceki yazılarımda  Android başlıkları altında anlatmış bulunmaktayım. Daha detaylı olarak bilgi almak isteyen arkadaşlar mail yolu ile bana ulaşmalarını isteyeceğim.

Yapılacaklar listesinin uygulaması :

  • Grafiksel arayüz tasarımı

Grafik arayüz için 2 adet TextView ekranımıza aktarıyoruz.

1

  • Görsel tanımlamalar

Önceki tanımlamada belirlediğimiz textView ‘leri aktarıyoruz.
1.TextView tanımlaması :

TextView uygunlukKontrol = (TextView)findViewById(R.id.textView1);

2.TextView tanımlaması : Not: Bu tanımlama genel olarak projenin başlangıç kısmında class altında tanımlayacağız. Daha sonra Activity altında tanımlayacağız.

Class altında tanımlama :

public class MainActivity_motorControl extends Activity implements SensorEventListener{
   TextView sensorVeri;
...
...

 

protected void onCreate(Bundle savedInstanceState) {
...
...
   sensorVeri = (TextView)findViewById(R.id.textView2);
...
...
  • Sensör bilgisi okuma

Sensör bilgisi okuma detaylı olarak anlattığım link : http://www.mcu-turkey.com/android-sensorler-ve-kullanimi/

Bu linkteki accelerometer kısmını incelemenizi tavsiye edeceğim. İşlemimizde temel olarak sensörler ve kullanımı başlık altındaki şablona oturtulacaktır.

  • Sensör bilgisinin sentezlenmesi

Okuduğumuz bilgi belirli kordinatları ( x , y , z ) içermektedir. Biz projemizde telefonunuzu yatay şekilde tuttuğunuz zaman ileri yada geri ivmelendirmenizi sonucu elde edilen bilgiyi sentezleme işlemine odaklanacağız. Sensör bilgilerini elde edebilmek için uygulamayı yan döndürmemiz gerekmektedir.

Yan döndürmek nedir ?
samsung-galaxy-s2-tekno-note
Kodumuzu yan yatıracak kodu Activity içindeki OnCreate altına ekleyelim.

protected void onCreate(Bundle savedInstanceState) {
....
    this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
....

Yan yatırıldığı zaman eksen bilgilerimiz :
2

Burada ileri geri komutlarını “X” ekseninde gerçekleştireceğiz. Tam olarak anlayabilmeniz için bir sonraki resme bakınız.
Yönlendirme şekillerimizi yandan gösterilimi :

2

Bu işlemde belirlediğimiz kıstaslardan bir tanesi olarak söylediğimiz gibi X değerlerinin bize dönüş değerlerini kontrol etmektir. Burada daha hassas bir değere ulaşabilirsiniz. İlk olarak okuduğumuz bilgiyi ikinci textView’imize aktaralım daha sonra sentezleme komutunu gösterelim.

	@Override
	public void onSensorChanged(SensorEvent event) {
		// Veriyi görmek için text'in içine yazıyoruz.
		sensorVeri.setText("X : " + event.values[0] + "\nY : " + event.values[1] + "\nZ : "
                + event.values[2]);

 

	        float degerFloat = event.values[0] ; // Veri float'a dönüştürülüyor.
		// Sürekli girmeleri engellemek için gondermeDegeri gondermeDeğeri sorgulanır
		// Belirli aralıkları geçirmek için X ekseni yani degerFloat sorgulanır.
		// -1 <= iken *İleri  | 0 >= ve 7 <= iken *Dur | 8 >= iken *Geri bitleri gönderilir.
		if(degerFloat <= -1 && gondermeDegeri == 1){  			gondermeAyarlari('1'); 		                 	gondermeDegeri = 0; 		                 }else if(degerFloat >= 8 && gondermeDegeri == 1){
			gondermeAyarlari('2');
			gondermeDegeri = 0;
		}else if(degerFloat <= 7 && degerFloat >= 0 && gondermeDegeri == 0 ){
			gondermeAyarlari('0');
			gondermeDegeri = 1;
		}

Sentezleme işlemi sırasında sürekli işlemi gerçekleştirmemek için bir filitre tasarladım. Bu filitre sadece bir kere girmesi görevini üstlenmektedir. Bir kez oluşturduktan biti temizler ve tersler. Durum sağlandıktan sonra gonderme işlemini yapacak fonksiyon çağırılır ve veri üzerine yazılır.

  • Soket üzerinden veri aktarılması

Telefon üzerinden bilgimizi göndermek için soket yapısını kullanacağız. Soket yapısı IP + PORT toplamından oluşmaktadır. TCP/IP protokollerini içermektedir. Port tanımlamalarını sağlayabilmek için bu fonksiyonu çağırmalıyız.

public void gondermeAyarlari(char gonderilecekdeger){
		try {
			String text = ""; // Veri saklayıcısı
			Socket soket = new Socket(IPADRES, 8000); // Soketten bağlanılıyor.
			// Yazıcı tanımlaması
			PrintWriter out = new PrintWriter(new OutputStreamWriter(
										soket.getOutputStream()), true);
			out.println(gonderilecekdeger); // Veri gönderilmesi
			out.flush();
			out.close(); // Yazıcı Kapatılıyor
			soket.close(); // Soket kapatılıyor
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

Gönderme işlemini sağlayabilmek için bunu sensör sentezlemesi içerisinde tanımlamamız gerekmektedir. Bir önceki sekmede gonderilecekdeger kısmı buradan gelmektedir. Tabi bu kısımda önemle dikkat edilmesi gereken bir husus bulunmaktadır. IPADRES tanımlamasını kendi bilgisayarınızın ip’sini kontrol ederek tanımlamanız gerekmektedir.

IPADRES Tanımlaması :

public class MainActivity_motorControl extends Activity implements SensorEventListener{
	...
        ...
	public static String IPADRES = "192.168.0.12"; // IP ADRES tanımlaması
        ...
        ...

Sonuç olarak Android kısmını genel olarak ele almış bulunmaktayız. Sıradaki konu bilgisayarımızda yazacağımız Java kodumuz üzerine olacak. Şimdi başlacak olursak;

JAVA kısmında yapılacaklar aslında çokta detaylı değildir. Önceki yazdığım yazılarda olduğu gibi aynı şekildedir. Sadece ek olarak Seri port bağlantısı sağladığınız takdirde port’tan veriyi yazmamızı kolaylaştıran fonksiyonumuzu tanıtmamız yeterlidir.

Başlangıçtaki kodumuz :

public class motorControl {
	public static final int PORT = 8000;// PORT NO
	public static void main(String[] args) throws IOException {

		// Sunucu soketi aciliyor.
		while (true) {
			ServerSocket sunucuSoketi = new ServerSocket(PORT);
			System.out.println("Sunucu baslatildi");

			try {
				// Baglantiyi gelene kadar bekle ve kabul et
				Socket kullaniciSoketi = sunucuSoketi.accept();

				try {

					System.out.println("Baglanti kabul edildi : "
							+ kullaniciSoketi);
					// Okuyucu
					BufferedReader bufci = new BufferedReader(
							new InputStreamReader(
									kullaniciSoketi.getInputStream()));
					String veri = bufci.readLine(); // Saklanan bilgi
					Thread.sleep(100);

					System.out.println("Veri okundu - " + veri);
					sunucuSoketi.close();
					System.out.println("Soket Kapatiliyor...");

				} catch (Exception e) {
					System.out.println("Hata : " + e.toString());}

			} catch (Exception e) {
				System.out.println("Hata : " + e.toString());
			}
		}
	}

Burada önceki konulardakinden hiçbir değişiklik yapmadan koyduk. Seri porttan veri alabilmemiz için Java geliştiricileri tarafından geliştirilen kütüphanemizi projemize eklememiz gerekmektedir.

Java Serial kütüphanemiz : RXTXcomm
Bu kütüphaneyi projeye sağ tıklayarak özelliklerden “Java Build Path” altında “Libraries” te “Add External Jar’s” diyerek ekleyiniz.

Ayrıyetten Windows kullanıcıları ekstra olarak Windows/system32 altına linkteki dosyaları aktarmanız gerekmektedir. Linux kullanıcıları rxtxcomm kütüphanesini terminalden eklemeleri halinde çalışmaktadır. Beaglebone’da bu durumu yapmak isteyen arkadaşlara daha detaylı başka bir yazıda paylaşmak istiyorum. Konfigurasyon yapmamız gerekir.

Windows kullanıcılarının indirmesi gereken dosya : rxtxKonfigrasyon

Seri bağlantımızı sağlayacak kodumuz :

public static void writeToPort(char deger) throws Exception
    {
		CommPortIdentifier pid;
	    SerialPort serial;
	    OutputStream outstream;
	// Port tanımlanıyor.
        CommPortIdentifier pid1=CommPortIdentifier.getPortIdentifier(seriPort);
        serial=(SerialPort)pid1.open("uygulama",1000);
        // Bandrate = 9600 - 8 databiti - 1 stop biti ve parity kapatılarak port açılıyor.
        serial.setSerialPortParams(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
        serial.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
        outstream=serial.getOutputStream();
        outstream.write(deger); // Veri (char) yazıcıdan yazılıyor.
        outstream.close();	// Yazıcı kapatılıyor.
        serial.close(); // Seri port kapatılıyor.
    }

Bu kod diziminde en çok dikkat etmeniz gereken kısım seriPort tanımlaması yapılan kısımdadır. Cihazınıza ez430-RF2500 debugger’lı kısım hangi porttan bağlı olduğunu önceden tespit etmelisiniz. Benim “COM6” dan bağlanmaktadır. Sizlerde bunu kontrol ediniz.

Tanımlamamızı yine her zamanki gibi class altında public bir şekilde tanımlamalıyız. Çünkü aksi halde çağırma işlemini yapamayız. C kullanıcıları algılayabilmek için daha cok define etmek olarak düşünebilirler.

serialPort tanımlama :

public class motorControl {
	...
	public static String seriPort = "COM6"; // Port tanımlanıyor.
        ...
        ...

SerialPort’tan veri göndermek oldukça basite indirmiş bulunmaktayız. Şuanda writeToPort fonksiyonumuza belirli bir char değer yüklediğimiz takdirde direk değeri gönderecektir. Burada string göndermenizde gayet olağandır. Sadece yapmanız gereken soket’teki gibi bir yazıcı tanımlamanızdır. Ben işlemimizde milisaniyeler önemli olduğu için yazıcıda zaman kaybetmekten kaçınma amacıyla böyle bir yola başvurdum.

İşlem sırasında ,

  • ‘ 1 ‘ = İleri
  • ‘ 2 ‘  = Geri
  • ‘ 0 ‘  = Dur

komutlarını içermektedir.

serialPorttan veri göndermek :

writeToPort('1'); // İLERİ için 1

yapmanız gereken göründüğü gibi bu kodu okuma işlemi yapıldıktan sonraki kısıma eklemektir.

Main kodumuz :

public static void main(String[] args) throws IOException {

		// Sunucu soketi aciliyor.
		while (true) {
			ServerSocket sunucuSoketi = new ServerSocket(PORT);
			System.out.println("Sunucu baslatildi");

			try {
				// Baglantiyi gelene kadar bekle ve kabul et
				Socket kullaniciSoketi = sunucuSoketi.accept();

				try {

					System.out.println("Baglanti kabul edildi : "
							+ kullaniciSoketi);
					// Okuyucu
					BufferedReader bufci = new BufferedReader(
							new InputStreamReader(
									kullaniciSoketi.getInputStream()));
					String veri = bufci.readLine(); // Saklanan bilgi
					Thread.sleep(100);

					System.out.println("Veri okundu - " + veri);
					//Veri yazılıyor.
					if(veri.equals("0")){
					  writeToPort('0');
					  System.out.println("yazildi 0");
					}else if(veri.equals("1")){
						  writeToPort('1');
						  System.out.println("yazildi 1");
					}else if(veri.equals("2")){
						  writeToPort('2');
						  System.out.println("yazildi 2");
					}

					sunucuSoketi.close();
					System.out.println("Soket Kapatiliyor...");

				} catch (Exception e) {
					System.out.println("Hata : " + e.toString());}

			} catch (Exception e) {
				System.out.println("Hata : " + e.toString());
			}
		}
	}

Son olarak işlemimiz bir sonsuz döngüde olup soket açılıp server görevi üstlendikten sonra istek olduğu takdirde veri alışı yapıp serial port’tan gönderme işlemini yapmakta ve soketi ve okuyucuları kapatmaktadır. Temel görevi budur.

Java kısmınıda bitirdik sıra geldi ez430-RF2500 kodlarımıza. Bu konuda açıkcası Fatih arkadaşımızın yazılarını ve çizgi-tagem tarafından yayınlanan eğitim videosunu başarılı bulmaktayım. Bende buradan faydalandım çoğunlukla. Buna ek olarak birde Erhan arkadaşımızın yazısını göstermek isterim sizlere kiti oldukça iyi tanıtmaktadırlar.
Fatih’in makalesi : http://www.mcu-turkey.com/15690/
Erhan’ın makalesi : http://www.mcu-turkey.com/rf2500-ile-kablosuz-iletisim-uygulamasi/

Makaleleri ve eğitimi iyice izlediyseniz yada yeterli bilgiye sahipseniz konuya devam edebilirsiniz. Öncelikle projede hangi modülün nerede bulunacağını söylemek istiyorum.

kit1

Üst kısımda bulunan Debugger ve Target – 1 modüllerini birleştirip bilgisayarımıza takıyoruz. Java’dan göndereceğimiz veriler modülümüze seri veri yolu ile aktarılacak donanımsal ortamı sağlamış oluyoruz. Target-2 ve Batarya modülü birleşik olduğu gibi olacaktır. Modülün yapacağı iş motor’a aktarılacak gücü sağlayan motor sürücü devresinin lojik seviyelerden anlayabileceği şekilde portlarımızı yönlendirmektir.

Bu konuda ilk olarak motor devresinin bizim kitimiz üzerine gireceği portları gösterebilmemiz için jumper girişlerine soketler lehimliyoruz. Ben bu işlemi Target – 2 üzerinde yapmış bulunmaktayım. Durumu resimle destekleyecek olursak :

IMG_20130211_165046 IMG_20130211_165152 IMG_20130211_165230

Port tanımlamalarımızı sağlayabilmemiz için portlarımızı incelememiz gerekmektedir. Ben portları daha iyi görebilmek için port tanımlamalarını tekbir resime sığdırdım.

ez430-RF2500 Port Tanımlamaları :

pin_tanim

Kullanacağımız pinleri siyah kutucuklara almış bulunmaktayım. Bu pinleri motor devresinden daha sonra daha iyi anlayacaksınız. Genel amaçlı olarak söyleyecek olursak yapacağımız durum 3 , 4 , 5. pinleri çıkış yapıp gelen veriler doğrultusunda pinleri lojiksel seviyeleri kontrol etmektir.

Şimdi motor devesine yoğunlaşalım. Motor devresi için ST markasının LD293D entegresini tercih etim.

LD293D Datasheet : L293D

Entegrenin genel özelliği lojiksel giriş seviyelerini çıkışa yönlendirmektir. Sayısal devreler yada Lojik devreler dersi alan arkadaşlara basit ama kullanışlı bir bilgi ile bu konuyu anlayacaktırlar.

13
Bu çıkışlardan biz Enable1 pinini 1 yapmamız ve Inputları istediğimiz yöne çevirebilmemiz için çıkışları kontrol etmeliyiz. Enable1 ve Enable2 pinleri ters yönlü olmalıdır. Aksi halde çıkış elde edemeyeceksiniz. Çıkışa gitmeden Vs üzerinden gücü çıkışa , girişteki alternanslarla kontrol ediyoruz.
Entegrenin Devreye bağlanış şeması :

LD293_baglanti_semasiGücünüzü motorunuza uygun şekilde kullanmaya dikkat ediniz. Entegre 12V ‘tan sonra ısınmaya baslamaktadır. 600mA ‘den fazla akım vermemeye çalışınız. Sizler için devreye uygun olacak şekilde pcb’sini çizmiş bulunmaktayım.

L293D PCB : sema

Sıra geldi RF2500 üzerindeki pin konfigurasyonlarımıza ilk olarak üstteki resimden göreceğiniz gibi P1.0’dan P1.2 ‘ye kadar pinler tanımlanmış bulunmaktadır. Bu pinleri gerekli tanımlamaları

  • P1.0  – Enable
  • P1.1  – Input1
  • P1.2  – Input2

Pinlerini temsil etmektedir. L293D nin sürekli çıkış sağlayabilmesi için Enable pininin sürekli çıkış (Lojik 1- HIGH) olması gerekmektedir. P1.1 ve P1.2 pinlerinin bu bağlamda isteğimize göre ” İleri – Geri ” sağlayabilmek için çıkışlarımızı birinin HIGH diğerini LOW şekilde ayarlamaları yapmalıyız.

RF2500 de kod olarak main.c içerisinde görünümü :

  P2OUT = 0x00; // P2.0 bitler temizleniyor.
  P2DIR = BIT0 + BIT1 + BIT2; //P2.0 P2.1 P2.2 çıkış ayarlanıyor
  P2OUT = BIT0; // P2.0 - ENABLE Pin çıkış ayarlanıyor

Debugger’dan veri geldikten sonra yapılacak işlem :

switch(buffer[1]) // buffer[1] veridir.
  {
  case '1' :
            P2OUT_bit.P2 = 0; // P2.2 = 0 yapılıyor.
            P2OUT_bit.P1 = 1; // P2.1 = 1 yapılıyor.

            break;
  case '2' :
            P2OUT_bit.P1 = 0; // P2.1 = 0 yapılıyor.
            P2OUT_bit.P2 = 1; // P2.2 = 1 yapılıyor.

            break;
  default  :
              P2OUT_bit.P1 = 0; // P2.2 = 0 yapılıyor.
              P2OUT_bit.P2 = 0; // P2.2 = 0 yapılıyor.
              break;
  }

Burada buffer[1] veri alındığı an içerisine eklenmektedir. Bu veriyi eğer telefonumuz “İleri” yani ‘1’ olarak gönderdiği takdirde portları 1 – 0 , “Geri” yani ‘2’ olarak gönderdiğinde portları 0 – 1 , herhangi bir değer “Dur” yani ‘0’ gönderdiği takdirde 0 – 0 yaparak işlemimizi tamamlıyoruz. Bu sayede motorumuzu ileri yada geri gidecek şekilde kontrol etmiş oluyoruz.

Rx – Tx konusunda Fatih yeterli bilgileri vermiş ben üzerine ek olarak proje doğrultusunda bilgiler vermek istiyorum. Kitimizi LPM4 modunda sürekli bekleme durumuna sokuyoruz. Eğer veri gelirse uyanıp işlemlerini yapması ardından nihayetinde tekrar düşük güç tüketim moduna sokuyoruz. Bu işlemler sırasında olduğundan fazla tasarruf sağlıyoruz. Buda bize bir katkı sağlamaktadır.

Projeden Kareler :

IMG_20130211_185301IMG_20130211_185452
IMG_20130211_190402

IMG_20130211_190312

IMG_20130211_190509

Dökümantasyon :

Proje : motorControl_Proje

SONUÇ :

Umarım beğenmişsinizdir. Küçük bir aksaklık oldu bataryamı sarj edememiştim mecburen dışarıdan prizden bağladım enerjimi ; tabi bu arada vidyoda bir süre isteklerimi yapmıyor gibi görünmüş oldu. Kablolar tekerleri arasına gelmiş ve güç kablosu cıkmış. Düzenledim son bölümünde sorunsuzca çalışıyordu. Müziğide sizler için seçtim. Açıkcası tesadüfen buldum.

Arkadaşlar projemizin sonuna geldik takip edip uygulayan arkadaşlara yardımcı olabildiysek ne mutlu. Uygulamayı gerçekleştiremeyen arkadaşlar burada yorum olarak yazarsanız yardımcı olabilirim. Verdiğim dökümantasyonda herhangi problem yoktur. Direk oradan oluşturmuş bulunmaktayım.İyi çalışmalar.Kendinize iyi bakınız.

______
Gökhan TARIM
tarim.gokhan@gmail.com