Arşiv

Posts Tagged ‘Servo’

IMA Juno’yu Kıpırdatmak

IMA Juno denilen ve bluetooth üzerinden kontrol edilebilen aşağıdaki 2 tekerli şirin robotun STL dosyası ve Arduino kodu kendi sitesinde sunulmaktadır. Tekerleri ve şasisi dahil plastik aksamının tamamı 3 boyutlu yazıcıdan alınan bu robotun Google Play Store’daki kendi Android uygulaması bluetooth eşleşmesi yapılmasına rağmen Juno’yu algılamadı ve dolayısıyla çalıştırmadı.

IMA Juno görseli IMA Juno görseli üstten

Bu çalışmada Juno’yu hareket ettirebilmek için “Arduino ile Bluetooth Kontrollü Araba Uygulaması” Juno’ya göre revize edildi. Bluetooth kontrollü araba ile Juno arasındaki donanımsal en büyük fark Juno’da DC motor yerine 360 derecelik servo motor kullanılmasıydı. Bunun için Arduino kodunun servo motorlara göre tekrardan düzenlenmesi gerekti. Servo motorların kullanımı ile ilgili ufak bir araştırma ile bilinmesi gereken temel noktalardan bazıları şöyle sıralanabilir:

  • Servo kütüphanesi write() fonksiyonu değeri; standart servoda milin dönme açısını belirlerken 360 derecelik servoda milin dönme hızını belirler.
  • write() fonksiyonu değeri 90 ise 360’lık servo hareket etmez.
  • write() fonksiyonu değeri 0-90 arası ise mil bir yöne, 90-180 arası ise diğer yöne hareket eder. 0 ve 180 servonun en hızlı döndüğü uç değerlerdir.
  • Servo.h kütüphanesi koda eklendiğinde Arduino Uno’da 9. ve 10. pinlerin PWM özelliği servo motorun bu pinlere bağlanıp bağlanmadığına bakılmaksızın pasif hale getirilir.
  • FS90R’nin (360’lık servo) yüksüz 4.8V’de çektiği akım 100mA iken 6V’da 120mA’dir.
  • Servolar fazla akım çekebileceğinden bir ve ikiden fazla sürülmesi gerektiğinde ayrı bir kaynaktan (Arduino’nun +5V pininden değil) beslenmesi gerekmektedir.

IMA Juno için devre tasarımı aşağıdaki gibi değiştirildi:

IMA Juno devre tasarımı

Revize edilmiş Arduino kodumuz ise şöyledir:

/*** IMA Juno Alternative ***/ 
#include <Servo.h>

Servo solServo, sagServo;

/*Servo veri pinleri*/
int solServoPin = 9; //Sol servo motor veri pini
int sagServoPin = 10; //Sağ servo motor veri pini
 
String satir = ""; //Seri porttan okunan satir
int yon = 0; //Gelen yön verisi
int hiz = 0; //Gelen hiz verisi
int semiColonPos = 0; //Noktalı virgül pozisyonu

int solServoHizi = 0; //Sol servo motor hizi
int sagServoHizi = 0; //Sağ servo motor hizi

/*Ledler*/
int solLed = 4;
int sagLed = 5;
int arkaSolLed = 6;
int arkaSagLed = 7;

 
void setup() {  

  solServo.attach(solServoPin);
  sagServo.attach(sagServoPin);

  pinMode(solLed, OUTPUT);
  pinMode(sagLed, OUTPUT);
  pinMode(arkaSolLed, OUTPUT);
  pinMode(arkaSagLed, OUTPUT);

  digitalWrite(solLed, HIGH);
  digitalWrite(sagLed, HIGH);
  digitalWrite(arkaSolLed, HIGH);
  digitalWrite(arkaSagLed, HIGH);
      
  Serial.begin(9600);
  //Zaman aşımı süresi appinventor timer süresi (15ms) 
  //ile uyumlu hale getiriliyor
  Serial.setTimeout(15); 
}

void loop() {  
  if (Serial.available()>0)
  {
    satir = Serial.readString(); //15ms zaman aşımı
    /*
     * Gönderilen veri Yön;Hız formatındadır.
     * Yön için: 1-> Sağa, 2->Sola, 3->İleri, 4->Geri, 0->Dur
     * Hız için değer aralığı 0..90'dır.
    */
    semiColonPos = satir.indexOf(';');    
    yon = satir.substring(0,semiColonPos).toInt();  
    hiz = satir.substring(semiColonPos+1).toInt();   

    solServoHizi = yon == 4 ? 90 - hiz : 90 + hiz;
    sagServoHizi = yon == 4 ? 90 + hiz : 90 - hiz;  
  
    switch (yon)
    {
      case 1: //Sağa dön
        solServo.write(solServoHizi);
        sagServo.write(90);
        Serial.print("Sağa dönüyorum");   
             
        break;
      case 2: //Sola dön
        solServo.write(90);
        sagServo.write(sagServoHizi);
        Serial.print("Sola dönüyorum"); 
        
        break;
      case 3: //İleri
        solServo.write(solServoHizi);
        sagServo.write(sagServoHizi);
        Serial.print("İleri gidiyorum"); 
        
        break;
      case 4: //Geri
        solServo.write(solServoHizi);
        sagServo.write(sagServoHizi);
        Serial.print("Geri gidiyorum");   
          
        break;
      case 0: //Dur
        solServo.write(90);
        sagServo.write(90); 
        Serial.print("Durdum"); 
        
        break;
    } 
    
   ledYak();     
  } 
  
} 


void ledYak()
{
  switch (yon)
  {
    case 1: //Sağa dön
      digitalWrite(solLed, LOW);      
      digitalWrite(sagLed, HIGH);      
      digitalWrite(arkaSolLed, LOW);
      digitalWrite(arkaSagLed, LOW);
            
      break;
    case 2: //Sola dön
      digitalWrite(solLed, HIGH);
      digitalWrite(sagLed, LOW);
      digitalWrite(arkaSolLed, LOW);
      digitalWrite(arkaSagLed, LOW);
 
      break;
    case 3: //İleri
      digitalWrite(solLed, LOW);
      digitalWrite(sagLed, LOW);
      digitalWrite(arkaSolLed, LOW);
      digitalWrite(arkaSagLed, LOW);
      
      break;
    case 4: //Geri
      digitalWrite(solLed, LOW);
      digitalWrite(sagLed, LOW);
      digitalWrite(arkaSolLed, LOW);
      digitalWrite(arkaSagLed, LOW);
      
      break;
    case 0: //Dur
      digitalWrite(solLed, LOW);
      digitalWrite(sagLed, LOW);
      digitalWrite(arkaSolLed, HIGH);
      digitalWrite(arkaSagLed, HIGH);
      
      break;     
    }      
}

Juno’nun tekerlerinin ikisinin de aynı yönde dönmesi için sol ve sağ servoların hız değerlerinin birbirinin tersi yönde olacak şekilde hesaplanmış olduğuna dikkat edelim.

Android tarafında ise Appinventor kodunda çok ufak 2 değer değişikliği yapılmıştır. Bluetooth kontrollü arabada analogWrite() için 0-255 arası hız değeri gönderilirken Juno’da 0-90 arası hız değeri gönderilmektedir. Ayrıca hız artışı 15’ten 5’e düşürülmüştür. Bunun haricinde Appinventor Android uygulama bileşenleri ve Android uygulamasının çalışması “Bluetooth Kontrollü Araba Uygulaması – 2. Kısım” ile tamamen aynıdır. İlgili yazıdan Android uygulamasının çalışması incelenebilir.

Uygulama arayüzü ve bileşenleri şöyledir:

Juno Android arayüz görüntüsü Juno Android bileşenleri görüntüsü

Appinventor kod blokları aşağıdaki gibidir (değişiklikler kırmızı daire ile gösterilmiştir):

Android Appinvetor kod blokları

Uygulama görüntüleri:

Juno foto 4 Juno foto 3 Juno foto 2 Juno foto 1

Uygulama videosu:

APK dosyası linki: Dosyayı indirmek için buraya tıklayınız.

Uygulamayı pdf formatında indirmek için buraya tıklayınız.

Kaynakça
https://www.exploremaking.com
https://www.thingiverse.com/thing:1720394
https://github.com/exploremaking/Juno/blob/master/Juno.ino
https://www.arduino.cc/en/Reference/Servo
https://www.arduino.cc/en/Reference/ServoWrite
http://ctc-dev.verkstad.cc/en/course-literature/continuous-rotation-servo/
https://core-electronics.com.au/continuous-rotation-micro-servo-fs90r.html
https://media.digikey.com/pdf/Data%20Sheets/Adafruit%20PDFs/2442_Web.pdf

Arduino ve Python ile Basit Radar Uygulaması – 2. Kısım

Arduino ve Python ile basit radar uygulamasının ilk kısmında ölçülen mesafe bilgileri; ilgili açı bilgisi ile beraber seri porta gönderilmişti. Bu kısımda ise seri porta gönderilen bilgilerin Python ile okunup parse edilerek (ayrıştırılarak) grafiğe dönüştürülmesi anlatılmaktadır.

Arduino tarafında seri porta gönderilen veriler şöyle görülmektedir:

Verileri parse edip grafikleştiren Python kaynak kodumuz ise şu şekildedir:

# -*- coding: utf-8 -*-
import serial, turtle

#Arduino'nun bilgisayara bağlı olduğu seri porta bağlan
ser = serial.Serial(port='COM6', baudrate=9600, timeout=0)

print("connected to: " + ser.portstr)

#Grafik çizmek için turtle nesnesinin özellikleri
turtle.speed(0)
turtle.pensize(1)
turtle.pencolor("black")
turtle.fillcolor("green")

#Mesafe ve açı bilgilerini yazmak için
#ikinci turtle nesnesi ve özellikleri
trt2 = turtle.Turtle()
trt2.speed(0)
trt2.penup()
trt2.hideturtle()

#Mesafe bilgilerini grafikleştirmeden önce
#ekrana uzaklıklara ait temsili
#yarım daireleri çiz
def yarimDaireCiz():  
  turtle.clear()
  turtle.pencolor("black")   

  turtle.penup()
  turtle.goto(0,-20)
  turtle.write("0")    
  turtle.goto(100,-20)
  turtle.write("10cm")
  turtle.goto(200,-20)
  turtle.write("20cm")
  turtle.goto(300,-20)
  turtle.write("30cm")
  turtle.goto(400,-20)
  turtle.write("40cm")

  turtle.goto(-100,-20)
  turtle.write("10cm")
  turtle.goto(-200,-20)
  turtle.write("20cm")
  turtle.goto(-300,-20)
  turtle.write("30cm")
  turtle.goto(-400,-20)
  turtle.write("40cm")

  turtle.penup()
  turtle.home()    
  turtle.forward(400)     
  turtle.seth(90)    
  turtle.pendown()
  turtle.begin_fill()
  turtle.circle(400,180)
  turtle.end_fill()
  turtle.seth(0)    

  turtle.penup()
  turtle.home()    
  turtle.forward(300)    
  turtle.seth(90)    
  turtle.pendown()    
  turtle.circle(300,180)    
  turtle.seth(0)

  turtle.penup()
  turtle.home()    
  turtle.forward(200)    
  turtle.seth(90)    
  turtle.pendown()    
  turtle.circle(200,180)    
  turtle.seth(0)

  turtle.penup()
  turtle.home()    
  turtle.forward(100)        
  turtle.seth(90)    
  turtle.pendown()    
  turtle.circle(100,180)    
  turtle.seth(0)  
        
#Seri porttan okunup parse edilen
#aci ve mesafe bilgilerini
#cizgiye dönüştür  
def cizgiCiz(aci, mesafe):    
  turtle.penup()    
  turtle.home()  
  turtle.seth(aci) 
  turtle.forward(mesafe*10) # 1cm = 10birim
  turtle.pencolor("red")
  turtle.pendown()
  turtle.forward(400-mesafe*10)        

#Parse edilen aci ve mesafe bilgilerini
#ekrana yaz
def mesafeYaz(aci, mesafe):
  trt2.clear()
  trt2.goto(-50,-40)
  trt2.write("Açı: "+str(aci)+" - Mesafe: "+str(mesafe)+ " cm")  

#Seri porttan okunan bilgileri parse et      
def veriAyikla(veri):
  veriler = veri.split(";")
  aci = veriler[0].split(":")
  mesafe = veriler[1].split(":")    
  aci = int(aci[1])
  mesafe = int(mesafe[1])  

  mesafeYaz(str(aci),str(mesafe))

  
  if mesafe>=40 or mesafe == 0:
    mesafe = 41
    
  if aci == 0 or aci == 180:
    yarimDaireCiz()
   
  cizgiCiz(aci, mesafe)

#Seri porttan sürekli veri oku
line = ""
while True:
  for c in ser.read():                
    if c == '\n':
      veriAyikla(line)         
      line = ""
      break
    else:
      line += c

ser.close()

Programda öncelikle Arduino’nın veri gönderdiği -uygulamamızda USB’den bilgisayara bağlı olan- porta bağlanıyoruz. (Port bilgilerini ve baudrate değerini uygun şekilde değiştirmelisiniz)

Turtle modülü kullanımı kolay ve basit çizim işlemlerinde kullanılabilen bir python modülür. Programda iki tane turtle nesnesi kullanılmıştır. “turtle” mesafe bilgilerine göre çizgi çizmek için, “trt2” ise mesafe ve açı bilgilerini ekrana yazmak için kullanılan nesnedir. Seri port bağlantısının ardından turtle nesneleri ve özellikleri tanımlanmıştır.

yarimDaireCiz() fonksiyonu ekrana uzaklıklara ait temsili yarım daireler çizmek için kullanılmaktadır. Radar uygulama alanı 40 cm olarak düşünülmüştür. 1 cm 10 birim baz alınarak yarım daireler bu fonksiyon ile ekrana çizilmektedir. Gelen açı değeri her 0 ve 180 derece olduğunda yarimDaireCiz() program içinden çağırılmaktadır. Önce ekran temizlenmekte ardından yarım daireler çizilmektedir. Fonksiyon bir nevi arka plan oluşturmaktadır.

cizgiCiz() fonksiyonu ise parse edilen mesafe ve açı bilgilerini parametre olarak almaktadır. Bu verilerle ekrana istenilen açıda gelen mesafe bilgisi bazlı çizgi çizmektedir. “turtle” nesnesi çizgi çizmeden gelen mesafeye göre önce ileri gitmekte (santim başına 10 birim) ardından 40cm’den kalan mesafe kadar kırmızı çizgi çizmektedir.

Programda yer alan diğer 2 fonksiyondan biri mesafeYaz() ve diğeri ise veriAyikla() fonksiyonudur. mesafeYaz() fonksiyonu parametre olarak gönderilen açı ve mesafe bilgilerini “trt2” nesnesiyle ekrana yazmaktadır.

veriAyikla() fonksiyonu ise seri porttan okunup kendisine gönderilen veriyi parse etmektedir. Öncelikle “;” ardından “:” karakterinden ayrıştırma yaparak açı ve mesafe bilgilerini elde eder. Ekrana uzun çizgi çizilmemesi ve radar uygulama alanı 40 cm düşünüldüğü için mesafe 40’tan fazla ise 40’a eşitlenmektedir. Mesafeye göre çizgi çizilmeden önce de (cizgiCiz() fonksiyonu çalıştırılmadan önce) açı değeri 0 veya 180 ise yarimDaireCiz() bu fonksiyon içinden çağırılmaktadır.

Program akışı, seri port bağlantısı ve turtle nesnelerinin özelliklerinin tanımlanmasının ardından sürekli olarak seri porttan 1 byte veri okuma işlemi ile devam eder. Okunan karakter satır sonu (\n) değilse devamlı “line” değişkeninin sonuna eklenir. Satır sonu karakteri gönderilmişse (açı ve mesafe bilgisi artık tamamlanmışsa) “line” değişkeninde birleştirilmiş veri parse edilmesi için veriAyikla() fonksiyonuna gönderilir. Önce açı ve mesafe bilgileri elde edilir. Sonrada açı ve mesafe bazlı çizgi çizilir. Döngü kesintisiz devam eder.

Uygulama ekran görüntüsü şöyledir:

Arduino ve Python ile Basit Radar Ekran Görüntüsü

 

Kaynakça
https://elinux.org/Serial_port_programming
https://stackoverflow.com/questions/16077912/python-serial-how-to-use-the-read-or-readline-function-to-read-more-than-1-char
http://pyserial.readthedocs.io/en/latest/shortintro.html
https://docs.python.org/2/library/turtle.html