Ana içeriğe geç

Useless Machine (Yararsız Makine)

Giriş

Bu projede, klasik "useless machine" (yararsız makine) konseptini Arduino ile hayata geçireceğiz. Kullanıcı bir potansiyometreyi hareket ettirdiğinde, makine servo motor kullanarak potansiyometreyi geri iterek kendi haline dönmesini sağlıyor. Tabi bunu her seferinde cok mekanik olarak yapsa çok da eğlenceli olmaz. Bu yüzden bu basit konsepti biraz daha ileri götürüp, makineye LCD ekrana çizdiği bir yüz ve mesajlar olan bir "ruh hali sistemi" ve biraz da rastlantısallık ekledik. Böylece makine her seferinde aynı hızda ve aynı şekilde cevap vermediği için biraz daha kişilik sahibi gibi gözüküyor.

Bu projede öğrenecekleriniz:

  • Hassas servo motor kalibrasyonu - Servo'nun tam doğru açıya gelmesi için
  • Çoklu sensör füzyonu - Birden fazla sensörün birlikte karar vermesi
  • 3D baskı entegrasyonu - Mekanik tasarımla elektronik birleştirme

Önceki Bilgiler

Bu projede daha önce öğrendiğimiz birçok kavramı kullanacağız:

Gelişmiş Proje

Bu proje, 3D yazıcıyla basılması gereken bir parça içerdiği için "Gelişmiş Projeler" kategorisindedir. Servo motor adaptörünü (servo horn adapter) 3D yazıcıyla üretmeniz gerekiyor. Bunun dışında tüm elektronik parçalar kitin içinde bulunmaktadır.

Gerekli Malzemeler

Bu projede Arduino01 kiti dışında şunlara ihtiyacın olacak:

  • 3D basılmış servo kol adaptörü (STL dosyasını indir)
  • Yıldız tornavida (küçük uçlu - servo vidaları için)

Montaj ve Kalibrasyon

Video Anlatım

Servo Adaptör Montajı

Bu projenin en önemli kısmı kitte bulunan servo motorun, potansiyometreyi itebilmesini sağlamak. Bunun için özel bir servo kol adaptörü kullanıyoruz.

1. 3D Baskı:

servo_horn_adapter.STL dosyasını indirip 3D yazıcıyla basın:

  • Baskı süresi: ~5-10 dakika
  • Malzeme kullanımı: ~1 gram
  • Herhangi bir standart 3D yazıcıda basılabilir

2. Servo Kolunu Hazırlama:

Kitin içinde gelen servo kol paketinde iki farklı kol vardır. Biz ikili kolu (iki tarafı olan) kullanacağız.

İkili servo kolu

  • 2 adet küçük vida bulun (pakette gelir)
  • 3D basılmış adaptörü servo kolunun üzerine yerleştirin
  • Servo kolunun yuvarlak kısmı dışarı bakacak şekilde konumlandırın
  • Vidaları yıldız tornavida ile sıkın (çok küçük uçlu bir yıldız tornavida veya saatçi tornavidası kullanın)

3. Servo Motor Kalibrasyonu:

Servo motorun limitini doğru ayarlamak çok önemli. Eğer potansiyometrenin limitinden fazla itmeye çalışırsa servo motorun dişlileri zorlanır ve zarar görebilir.

Önemli Uyarı

Servo motor kolunu asla elinizle zorla çevirmeyin! İçindeki plastik dişliler zarar görebilir. Özellikle güç varken servoya kesinlikle dokunmayın.

Kalibrasyon Adımları:

  1. Orijinal kolu çıkarın:
  2. Arduino'ya USB ile güç vermeyin (güç kesik olmalı)
  3. Vidayı çıkarırken servo kolunu tutun (servoya zarar vermemek için)
  4. Servo motorun üzerindeki vidayı yıldız tornavida ile çıkarın
  5. Kolu yukarı doğru hafifçe çekerek çıkarın

  6. Servo Reset kodunu yükleyin:

  7. Arduino'yu USB ile bağlayın
  8. Aşağıdaki servo_reset.ino kodunu Arduino IDE'de açın
  9. Kodu Arduino'ya yükleyin
  10. Yükleme tamamlandığında servodan küçük bir hareket sesi gelecek ve LED yanıp sönmeye başlayacak

  11. Potansiyometreyi ayarlayın:

  12. Potansiyometreyi en sağ pozisyona getirins

  13. Servo kolunu takın:

  14. USB'den gücü kesin (kabloyu çekin)
  15. Hazırladığınız servo adaptörlü kolu servonun üzerine getirin
  16. Potansiyometreye temas ETMEYEN ama en yakın pozisyonu bulun
  17. Servo kolunun üzerindeki tırtıklar sayesinde birkaç derecelik hassasiyetle ayar yapabilirsiniz
  18. Kol ile potansiyometre arasında ~1mm boşluk olmalı

  19. Açıyı ince ayar yapın:

  20. Kolu taktığınız pozisyonda servo kolunu vidayla sabitleyin
  21. servo_reset.ino dosyasını tekrar açın
  22. servoMax değerini 1'er 1'er artırın (örnek: 160 → 161 → 162...)
  23. Her değişiklikten sonra kodu tekrar yükleyin
  24. Servo kol her yüklemede biraz daha potansiyometreye yaklaşacak
  25. Tam değdiği anı bulana kadar devam edin (genellikle 165-166 derece civarı)
servo_reset.ino - Örnek kalibrasyon
1
2
3
4
5
6
7
int servoMaks = 160; // Buradan başlayın
// Test edin, potansiyometreye değmediyse:
int servoMaks = 161; // 1 artırın, tekrar yükleyin
// Hala değmediyse:
int servoMaks = 162; // Tekrar 1 artırın
// ...devam edin...
int servoMaks = 166; // Tam değdiği açıyı bulun!
  1. Değeri kaydedin:
  2. Bulduğunuz servoMaks değerini bir yere not edin (örnek: 166)
  3. Bu değeri ana kodda kullanacağız

Devre Bağlantısı

Bu projede kitin hemen hemen tüm sensörlerini kullanıyoruz! Pin bağlantıları şöyle:

Komponent Arduino Pini Nereden Öğrendik
Servo motor Pin 9 Proje 07
Potansiyometre A0 Proje 04
PIR sensörü A2 Proje 12
Ultrasonik Echo Pin 5 Proje 06
Ultrasonik Trigger Pin 6 Proje 06
LCD ekran I2C (SDA/SCL) Proje 08
LED Pin 10 Kalibrasyon için

Kodun Açıklaması

Bu projede iki ayrı kod kullanıyoruz:

  1. servo_reset.ino: Servo kalibrasyonu için yardımcı kod
  2. useless_machine.ino: Ana proje kodu

Servo Reset Kodu

Bu kod servo kalibrasyonu için kullanılır. Servo motorların nasıl çalıştığını Proje 07'de öğrenmiştik. Burada servonun hassas kalibrasyonu için özel bir yardımcı kod kullanıyoruz.

servo_reset.ino
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <Servo.h>

Servo benimServo;
int ledPini = 10;
int servoPini = 9;

// Bu değeri birer birer arttırarak potansiyometreyi en sağa itecek
// ancak servonun zorlanmayacağı değeri bulacağız.
int servoMaks = 160;

void setup() {
  benimServo.attach(servoPini);
  pinMode(ledPini, OUTPUT);
  benimServo.write(servoMaks);  // Servo'yu maksimum açıya getir
}

void loop() {
  // LED'i yanıp söndür (kalibrasyon tamamlandı göstergesi)
  digitalWrite(ledPini, HIGH);
  delay(500);
  digitalWrite(ledPini, LOW);
  delay(500);
}

Kod çok basit: servoMaks değişkenini 1'er 1'er artırarak servo kolunun potansiyometreye tam değdiği açıyı bulacağız.

Ana Proje Kodu

Ana kodumuz servo kontrolü, sensör okumları ve ruh hali sistemi gibi birçok fonksiyonu içeriyor.

useless_machine.ino
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#include <Servo.h>
#include <Adafruit_LiquidCrystal.h>
#include <HCSR04.h>

Adafruit_LiquidCrystal lcd(0x21);
Servo benimServo;
float lux = 0.0f;
float oncekiLux = 0.0f;
int pirPini = A2;
int servoPini = 9;
int potPini = A0;
int suankiRuhHali = -1; // -1: reset, 0: mutlu, 1: sinirli
int servoAcisi = 0;
int servoHizi = 1;
int unsigned long ruhHaliDegisimZamani = 0;
const byte tetikPini = 6;
const byte yankiPini = 5;
UltraSonicDistanceSensor mesafeSensoru(tetikPini, yankiPini);

// ============ AYARLAR ============
int servoMin = 40;
// BURAYA KALİBRASYONDA BULDUĞUNUZ DEĞER GİRECEKSİNİZ!
int servoMaks = 165;
int potEsik = 950;
int servoHizMaks = 15; // Bunu çok artırırsanız servo yakalayamaz. Max 15 uygun
int ruhHaliDegisimServoBekleme = 1000; // Kit sinirlendikten sonra servo en erken ne zaman hareket edecek

// Sinirli mesajlar dizisi
char* mesajDizisi[] = {
  "     ELLEME",
  "  DOKUNMA SUNA",
  "     YAPMA!",
  "     iBiS",
  "   BIRAK SUNU",
  " GUZEL KARDESIM.",
  "  KAYDIRMA SUNU",
  "    KURCALAMA",
  "   OYNAMA"
};
int mesajSayisi = 9;

// Kite ne kadar yakın bir nesne varsa servoyu çalıştırmayacak
// Eğer gereksiz tetikleniyorsa bu değeri düşürebilirsiniz
int mesafeSensoruEsik = 25.0f;

void setup() {
  Serial.begin(9600);
  benimServo.attach(servoPini);
  servoHareketEttir(servoMin);  // Başlangıçta servo geri çekilmiş olsun
  pinMode(pirPini, INPUT);
  lcd.begin(16, 2);
}

void loop() {
  potDegeriKontrolEt();      // Potansiyometre değerini kontrol et
  servoHareketiniYonet();    // Servo hareketini yönet
  delay(50);                 // 50ms bekle (saniyede 20 kontrol)
}

// Servo motoru belirtilen açıya hareket ettir
void servoHareketEttir(int aci){
  // Açıyı minimum ve maksimum değerler arasında sınırla
  if(aci < servoMin) { aci = servoMin; }
  if(aci > servoMaks) { aci = servoMaks; }

  benimServo.write(aci);
  servoAcisi = aci;
}

// Potansiyometre değerini oku ve gerekiyorsa ruh halini değiştir
void potDegeriKontrolEt(){
  int potDegeri = analogRead(potPini);

  // Hysteresis kullanıyoruz (Proje 09'da öğrenmiştik)
  // ±20'lik tolerans ile kararlı okuma sağlıyoruz

  if(suankiRuhHali != 1 && potDegeri < (potEsik - 20)){
    // Potansiyometre aşağı itildi → Sinirli
    ruhHaliDegistir(1);
  }
  else if(suankiRuhHali != 0 && potDegeri > (potEsik + 20)){
    // Potansiyometre yukarı çıktı → Mutlu
    ruhHaliDegistir(0);
  }
}

// Ruh halini değiştir ve LCD'yi güncelle
void ruhHaliDegistir(int yeniRuhHali){
  if(yeniRuhHali == 0){
    // ========== MUTLU MOD ==========

    // Gülen surat çiziyoruz
    lcd.setCursor(6, 0);
    lcd.print(" :)");

    // İkinci satırı temizliyoruz
    lcd.setCursor(0, 1);
    lcd.print("                ");
  }
  else if(yeniRuhHali == 1){
    // ========== SİNİRLİ MOD ==========

    // Şimdiden random bir servo hızı seçeceğiz
    // Hareket daha sonra servoHareketiniYonet()'te gerçekleşecek
    rastgeleServoHizi();

    // Sinirli surat çiziyoruz
    lcd.setCursor(6, 0);
    lcd.print(">(:");

    // Ve bir de laf atıyoruz
    lcd.setCursor(0, 1);
    lcd.print(mesajDizisi[random(0, mesajSayisi)]);
  }

  ruhHaliDegisimZamani = millis();  // Mod değişim zamanını kaydet
  suankiRuhHali = yeniRuhHali;
}

// Rastgele servo hızı seç
void rastgeleServoHizi(){
  /*
   * Rastgele hız seçerken max hızdan daha yüksek bir rastgele sayı 
   * üretip sonra servoHizMaks değeriyle sınırlandırıcaz.
   * Bunun nedeni yavaş hareketlerin daha düşük
   * ihtimalle olmasını sağlamak. Çünkü öyle daha komik bence :)
   */
  servoHizi = random(1, servoHizMaks * 2);
  if(servoHizi > servoHizMaks){
    servoHizi = servoHizMaks;
  }
}

// Servo hareketini yönet (ana kontrol mantığı)
void servoHareketiniYonet(){
  if(suankiRuhHali == 0){
    // MUTLU → Servo geri çekilsin
    if(servoAcisi != servoMin){
      servoHareketEttir(servoMin);
    }
  }
  else if(suankiRuhHali == 1){
    // SİNİRLİ → Sensörleri kontrol et ve hareket et

    int pirOkuma = digitalRead(pirPini);
    Serial.println(pirOkuma);

    float mesafeSensoruOkuma = mesafeSensoru.measureDistanceCm();
    Serial.println(mesafeSensoruOkuma);

    // ÇOKLU SENSÖR FÜZYONU: Üç koşul birden sağlanmalı
    // 1. PIR: Hareket yok (pirOkuma == 0)
    // 2. Mesafe: 25cm'den uzak (güvenlik)
    // 3. Zaman: En az 1 saniye geçmiş (doğal davranış)

    if(pirOkuma == 0 &&
       mesafeSensoruOkuma > mesafeSensoruEsik &&
       millis() > (ruhHaliDegisimZamani + ruhHaliDegisimServoBekleme))
    {
      // Koşullar tamam → Potansiyometreye doğru ilerle
      servoHareketEttir(servoAcisi + servoHizi);
    }
    else {
      // Koşul sağlanmadı → Geri kaç!
      if(servoAcisi != servoMin){
        servoHareketEttir(servoMin);
        ruhHaliDegisimZamani = millis();
        rastgeleServoHizi();  // Tahmin edilemez olsun
      }
    }
  }
}

Kod Detayları:

Ruh Hali Sistemi (State Machine)

Proje 08'de öğrendiğimiz durum makinesi konseptini kullanarak makineye bir "ruh hali" ekledik. Makine üç farklı durumda olabilir:

  • -1 (Reset): İlk başlangıç durumu
  • 0 (Mutlu): Potansiyometre yukarıda, servo geri çekilmiş, LCD'de :) var
  • 1 (Sinirli): Potansiyometre aşağıda, servo potansiyometreye doğru ilerliyor, LCD'de >:( var

Her durum değişiminde LCD'deki emoji ve mesajlar da güncelleniyor.

Hysteresis ile Kararlı Okuma

Proje 09 - Termostat'ta öğrendiğimiz hysteresis kavramını burada da kullanıyoruz. Potansiyometre değerinin tam eşik noktasında (950) dalgalanması durumunda makine sürekli mod değiştirmesin diye:

  • < 930 olunca → Sinirli
  • > 970 olunca → Mutlu
  • 930-970 arası → Değişiklik yok (ölü bölge)

Histerezis Diyagramı

Bu sayede küçük dalgalanmalar durum değişimine sebep olmaz. Detaylı açıklama için Proje 09'a bakabilirsin.

Çoklu Sensör Füzyonu

Bu projenin en ilginç kısmı: Servo hareket kararını tek bir sensör değil, üç farklı sensör birlikte veriyor:

  1. PIR Sensörü (Proje 12): Kullanıcı hareket ediyorsa servo geri kaçsın
  2. Mesafe Sensörü (Proje 06): 25cm'den yakın engel varsa çarpma olmasın
  3. Zaman Kontrolü: Mod değişiminden en az 1 saniye sonra hareket et (daha doğal davranış)

Üç koşul birden sağlanırsa servo ilerler, yoksa geri çekilir. Buna "sensör füzyonu" deniyor - birden fazla sensörün verilerini birleştirerek daha akıllı kararlar vermek.

Programı Yükleme

Yükleme Sırası:

  1. İlk önce servo_reset.ino ile kalibrasyonu yapın
  2. Bulduğunuz açı değerini useless_machine.ino dosyasının 23. satırına yazın
  3. useless_machine.ino dosyasını yükleyin
  4. LCD ekranda :) görmelisiniz - makine mutlu!

Çalışma Mantığı

Proje çalışmaya başladığında:

  1. Başlangıç: Servo geri çekilmiş durumda (servoMin açısında), LCD'de gülen yüz var
  2. Potansiyometreyi çevirin: Kullanıcı potansiyometreyi aşağı iterse (analog okuma < 930)
  3. Makine sinirlenir: LCD'de kızgın yüz ve rastgele bir mesaj belirir
  4. Servo ilerler: Eğer sensörler hareket algılamazsa, servo potansiyometreye doğru ilerler
  5. Kullanıcı hareket ederse: PIR sensörü hareketi algılar, servo geri çekilir
  6. Potansiyometre geri döner: Servo potansiyometreyi iterek geri döndürür
  7. Makine mutlu olur: Potansiyometre eşiğin üstüne çıkınca (> 970), makine tekrar mutlu olur

Sorun Giderme

Geliştirme Fikirleri

Projeyi daha da ileri götürmek isterseniz:

  • Daha fazla ruh hali ekleyin (örnek: "uykulu", "şaşkın")
  • Servo hareketine easing (yavaşlama/hızlanma) ekleyin
  • Piezo buzzer ile sesli geri bildirim ekleyin
  • Farklı servo hız kalıpları oluşturun (hızlı-yavaş-hızlı gibi)

Özet

Bu proje, hem yazılım hem donanım hem de mekanik tasarımın bir araya geldiği eğlenceli (ve yararsız) bir örnek. Elinize sağlık!