back to top

Yapay Zeka ile Arduino El Atarisi Yapımı | Tetris ve Sanal Bebek Projesi

Arduino projelerinde kod yazmak bazen karmaşık olabilir. Peki, kodun tamamını, devre şemasını ve hatta hata ayıklama süreçlerini tamamen Yapay Zeka tasarlayabilir mi? Sorduğumuz bu soruya cevap aradık ve projemizde, ChatGPT ve Google Gemini kullanarak sıfırdan bir el atarisi tasarladık.

Elimizdeki malzemelerle Tetris ve Sanal Bebek (Tamagotchi) oyunlarını nasıl hayata geçirdiğimizi, yapay zekanın karşılaştığı sorunları nasıl çözdüğünü ve sizin de bu projeyi nasıl yapabileceğinizi göstermek istedik.

Projenin Amacı Nedir?

Projemiz, bir satır bile kod yazmadan sadece doğru “prompt”ları (istemi) kullanarak çalışan elektronik bir ürün ortaya çıkarmayı amaçlıyor. Oyunun tüm senaryosu, donanım seçimi, devre şeması, kodlama detayları ve hata ayıklamaları ChatGPT ve Gemini tarafından sağlanıyor. Biz ise sadece uyguluyoruz!

Proje için Kullandığımız Malzemeler

Yapay zeka ile arduino tabanlı el atarisi projemizi gerçekleştirmek için aşağıdaki donanımlara ihtiyacınız olacak:

Devre Kurulumu ve Şema

İlk adımda ChatGPT’ye elimizdeki malzemeleri listeledik ve bir devre şeması oluşturmasını istedik. Elimizde harici dirençler olmadığını gördüğünde, ChatGPT bize harika bir çözümle geldi: INPUT_PULLUP.

Arduino’nun dahili pull-up dirençlerini kullanarak butonları bağlamamızı önerdi. İşte yapay zekanın önerdiği ve bizim uyguladığımız devre şeması:

Tüm bağlantı detayları aşağıdaki gibidir:

OLED Ekran Bağlantısı:

  • VCC → 5V
  • GND → GND
  • SDA → A4
  • SCL → A5

Buton Bağlantıları:

  • 1.buton → D2 (Sol)
  • 2.buton → D3 (Sağ)
  • 3.buton → D4 (Rotasyon / Eylem)
  • 4.buton → D5 (Aşağı / Durum)

Tüm GND hatları ortak, Pull-Up için butonlar GND’ye doğru bağlandı

Devreyi kurduktan sonra yine ChatGPT’den bir “Button Test” kodu istedik. Tuşların doğru çalışıp çalışmadığını, breadboard üzerindeki yerleşimini bu basit kodla doğruladık.

Bölüm 1: ChatGPT ile Tetris Oyunu

Devremiz hazır olduğuna göre ilk oyunumuz olan Tetris için ChatGPT’ye başvurduk. Süreç sandığımızdan biraz daha heyecanlı geçti. Gerekli prompt’u vererek, elimizdeki donanımlarla uyumlu olacak şekilde kodlama yaptırmak istedik.

Proje Kodları

Aşağıdaki kodları Arduino IDE’ye kopyalayıp yükleyebilirsiniz. Yüklemeden önce Adafruit_GFX ve Adafruit_SSD1306 kütüphanelerinin yüklü olduğundan emin olun.

1. Tetris Oyunu Kodu (ChatGPT)

Bu kod, Arduino’nun belleğini verimli kullanmak için PROGMEM yapısını kullanır.

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <avr/pgmspace.h>

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define BLOCK_SIZE 5

#define FIELD_WIDTH 10
#define FIELD_HEIGHT 24

#define BTN_LEFT   2
#define BTN_RIGHT  3
#define BTN_ROTATE 4
#define BTN_DOWN   5

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);

bool field[FIELD_WIDTH][FIELD_HEIGHT];

int currentPiece;
int rotation;
int blockX;
int blockY;

unsigned long lastFall = 0;
int fallSpeed = 400;

/* TETROMINO'LAR FLASH'TA */
const uint8_t tetromino[7][4][16] PROGMEM = {
  // I
  {
    {0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0},
    {0,0,1,0, 0,0,1,0, 0,0,1,0, 0,0,1,0},
    {0,0,0,0, 1,1,1,1, 0,0,0,0, 0,0,0,0},
    {0,1,0,0, 0,1,0,0, 0,1,0,0, 0,1,0,0}
  },
  // O
  {
    {0,1,1,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,1,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,1,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,1,0, 0,1,1,0, 0,0,0,0, 0,0,0,0}
  },
  // T
  {
    {0,1,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,0,0, 0,1,1,0, 0,1,0,0, 0,0,0,0},
    {0,0,0,0, 1,1,1,0, 0,1,0,0, 0,0,0,0},
    {0,1,0,0, 1,1,0,0, 0,1,0,0, 0,0,0,0}
  },
  // L
  {
    {1,0,0,0, 1,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,1,0, 0,1,0,0, 0,1,0,0, 0,0,0,0},
    {0,0,0,0, 1,1,1,0, 0,0,1,0, 0,0,0,0},
    {0,1,0,0, 0,1,0,0, 1,1,0,0, 0,0,0,0}
  },
  // J
  {
    {0,0,1,0, 1,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,1,0,0, 0,1,0,0, 0,1,1,0, 0,0,0,0},
    {0,0,0,0, 1,1,1,0, 1,0,0,0, 0,0,0,0},
    {1,1,0,0, 0,1,0,0, 0,1,0,0, 0,0,0,0}
  },
  // S
  {
    {0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
    {0,1,0,0, 0,1,1,0, 0,0,1,0, 0,0,0,0},
    {0,1,1,0, 1,1,0,0, 0,0,0,0, 0,0,0,0},
    {0,1,0,0, 0,1,1,0, 0,0,1,0, 0,0,0,0}
  },
  // Z
  {
    {1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,0,1,0, 0,1,1,0, 0,1,0,0, 0,0,0,0},
    {1,1,0,0, 0,1,1,0, 0,0,0,0, 0,0,0,0},
    {0,0,1,0, 0,1,1,0, 0,1,0,0, 0,0,0,0}
  }
};

void setup() {
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  display.clearDisplay();
  display.setRotation(1);

  pinMode(BTN_LEFT, INPUT_PULLUP);
  pinMode(BTN_RIGHT, INPUT_PULLUP);
  pinMode(BTN_ROTATE, INPUT_PULLUP);
  pinMode(BTN_DOWN, INPUT_PULLUP);

  randomSeed(analogRead(A0));

  for (int x = 0; x < FIELD_WIDTH; x++)
    for (int y = 0; y < FIELD_HEIGHT; y++)
      field[x][y] = false;

  spawnPiece();
}

void loop() {
  handleInput();

  if (millis() - lastFall > fallSpeed) {
    if (canMove(blockX, blockY + 1, rotation)) {
      blockY++;
    } else {
      lockBlock();
      clearLines();
      spawnPiece();
    }
    lastFall = millis();
  }

  drawGame();
}

void spawnPiece() {
  currentPiece = random(0, 7);
  rotation = 0;
  blockX = 3;
  blockY = 0;
}

bool canMove(int x, int y, int r) {
  for (int i = 0; i < 16; i++) {
    if (pgm_read_byte(&tetromino[currentPiece][r][i])) {
      int nx = x + (i % 4);
      int ny = y + (i / 4);

      if (nx < 0 || nx >= FIELD_WIDTH || ny >= FIELD_HEIGHT)
        return false;
      if (ny >= 0 && field[nx][ny])
        return false;
    }
  }
  return true;
}

void lockBlock() {
  for (int i = 0; i < 16; i++) {
    if (pgm_read_byte(&tetromino[currentPiece][rotation][i])) {
      int nx = blockX + (i % 4);
      int ny = blockY + (i / 4);
      field[nx][ny] = true;
    }
  }
}

void clearLines() {
  for (int y = FIELD_HEIGHT - 1; y >= 0; y--) {
    bool full = true;
    for (int x = 0; x < FIELD_WIDTH; x++)
      if (!field[x][y]) full = false;

    if (full) {
      for (int ty = y; ty > 0; ty--)
        for (int x = 0; x < FIELD_WIDTH; x++)
          field[x][ty] = field[x][ty - 1];
      for (int x = 0; x < FIELD_WIDTH; x++)
        field[x][0] = false;
      y++;
    }
  }
}

void handleInput() {
  if (digitalRead(BTN_LEFT) == LOW && canMove(blockX - 1, blockY, rotation)) {
    blockX--; delay(120);
  }
  if (digitalRead(BTN_RIGHT) == LOW && canMove(blockX + 1, blockY, rotation)) {
    blockX++; delay(120);
  }
  if (digitalRead(BTN_DOWN) == LOW && canMove(blockX, blockY + 1, rotation)) {
    blockY++; delay(60);
  }
  if (digitalRead(BTN_ROTATE) == LOW) {
    int r = (rotation + 1) % 4;
    if (canMove(blockX, blockY, r)) rotation = r;
    delay(150);
  }
}

void drawGame() {
  display.clearDisplay();

  for (int x = 0; x < FIELD_WIDTH; x++)
    for (int y = 0; y < FIELD_HEIGHT; y++)
      if (field[x][y])
        display.fillRect(x * BLOCK_SIZE, y * BLOCK_SIZE,
                         BLOCK_SIZE, BLOCK_SIZE, SSD1306_WHITE);

  for (int i = 0; i < 16; i++) {
    if (pgm_read_byte(&tetromino[currentPiece][rotation][i])) {
      display.fillRect(
        (blockX + i % 4) * BLOCK_SIZE,
        (blockY + i / 4) * BLOCK_SIZE,
        BLOCK_SIZE, BLOCK_SIZE, SSD1306_WHITE
      );
    }
  }

  display.display();
}

Karşılaşılan Sorunlar ve Çözümler

ChatGPT kodu yazdı ancak ilk denemede bazı sorunlar yaşadık:

  1. Görüntü Sorunu: Bloklar ekranda Tetris şekilleri yerine kareler olarak görünüyordu.
  2. Ekran Yönü: Ekranımız breadboard üzerinde yatay olarak konumlanmıştı ancak oyun oynarken dikey pozisyonda olan ekranımızda bloklar yatay formatta hareket ediyor ya da hiç gözükmüyordu.
  3. RAM Sorunu: Arduino Nano’nun belleği yetersiz kaldı ve oyun başlamadı.

Sorunlar ortaya çıktıkça ChatGPT ile bir “takım arkadaşı” gibi çalıştık. Sorunları ona ilettik, o da bize RAM dostu (PROGMEM kullanarak verileri Flash belleğe taşıyan) ve ekranı display.setRotation(1); koduyla döndüren yeni bir versiyon hazırladı.

Sonunda tamamen çalışan bir Tetris oyunu yazmayı başardık.

Bölüm 2: Gemini ile Sanal Bebek Oyunu

İkinci oyun için Google’ın yapay zekası Gemini‘yi denemeye karar verdik. ChatGPT’nin kurduğu devre düzenini hiç bozmadan, Gemini’ye şu promptu verdik: “Kurulmuş olan donanımı kullanarak benim için bir Sanal Bebek (Tamagotchi) oyunu tasarla. Özellikleri; yemek yeme, oyun oynama ve uyuma olsun.”

Gemini, tek seferde derlenen ve çalışan bir kod verdi!

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

// --- EKRAN AYARLARI ---
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET    -1 
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

// --- BUTON PINLERI ---
const int BTN_FEED = 2;  // Yemek
const int BTN_PLAY = 3;  // Oyun
const int BTN_SLEEP = 4; // Uyku
const int BTN_STATUS = 5;// Durum Göster

// --- OYUN DEĞİŞKENLERİ ---
int hunger = 100;    // Açlık (100 = Tok, 0 = Açlıktan öldü)
int happiness = 100; // Mutluluk (100 = Çok mutlu)
int energy = 100;    // Enerji (100 = Çok enerjik)

unsigned long lastTime = 0;       // Zamanlayıcı için
unsigned long animTimer = 0;      // Animasyon zamanlayıcısı
const int decayTime = 5000;       // Her 5 saniyede bir ihtiyaçlar artar
bool isSleeping = false;          // Uyuyor mu?
bool showStatus = false;          // İstatistik ekranı açık mı?
int currentFrame = 0;             // Animasyon karesi

// --- BASİT BITMAPLER (16x16 Pixel Tavşan İfadeleri) ---
// Not: Daha karmaşık resimler için "Image2CPP" sitesini kullanabilirsin.
const unsigned char PROGMEM rabbit_idle[] = {
  0x00, 0x00, 0x0C, 0x30, 0x1E, 0x78, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC, 0x3D, 0xBC,
  0x3C, 0x3C, 0x18, 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x3F, 0xFC, 0x1F, 0xF8, 0x0F, 0xF0, 0x00, 0x00
};

const unsigned char PROGMEM rabbit_eat[] = {
  0x00, 0x00, 0x0C, 0x30, 0x1E, 0x78, 0x3F, 0xFC, 0x3F, 0xFC, 0x3D, 0xBC, 0x3C, 0x3C, 0x3F, 0xFC,
  0x3F, 0xFC, 0x30, 0x0C, 0x38, 0x1C, 0x1C, 0x38, 0x0E, 0x70, 0x07, 0xE0, 0x03, 0xC0, 0x00, 0x00
};

const unsigned char PROGMEM rabbit_sleep[] = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x30, 0x1E, 0x78, 0x3F, 0xFC, 0x3F, 0xFC, 0x3F, 0xFC,
  0x3F, 0xFC, 0x1F, 0xF8, 0x0F, 0xF0, 0x07, 0xE0, 0x03, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

void setup() {
  Serial.begin(9600);

  // Butonları INPUT_PULLUP yapıyoruz (Çünkü GND'ye bağlılar)
  pinMode(BTN_FEED, INPUT_PULLUP);
  pinMode(BTN_PLAY, INPUT_PULLUP);
  pinMode(BTN_SLEEP, INPUT_PULLUP);
  pinMode(BTN_STATUS, INPUT_PULLUP);

  // Ekran Başlatma
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Genelde adres 0x3C'dir
    Serial.println(F("SSD1306 baslatilamadi!"));
    for(;;);
  }
  
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
  display.setCursor(10, 20);
  display.println(F("SANAL TAVSAN"));
  display.println(F("YUKLENIYOR..."));
  display.display();
  delay(2000);
}

void loop() {
  // Zaman Kontrolü (İhtiyaçların azalması)
  if (millis() - lastTime > decayTime) {
    lastTime = millis();
    if (!isSleeping) { // Uyurken daha az acıkır
      hunger -= 5;
      happiness -= 5;
      energy -= 2;
    } else {
      energy += 10; // Uyurken enerji dolar
      hunger -= 2;  // Uyurken yavaş acıkır
    }
    
    // Sınırları kontrol et (0 ile 100 arası)
    hunger = constrain(hunger, 0, 100);
    happiness = constrain(happiness, 0, 100);
    energy = constrain(energy, 0, 100);
  }

  // BUTON OKUMA
  // Not: PULLUP olduğu için basılınca LOW (0) olur.
  if (digitalRead(BTN_FEED) == LOW) {
    feedPet();
    delay(200); // Debounce (buton sekmesini önlemek için)
  }
  if (digitalRead(BTN_PLAY) == LOW) {
    playPet();
    delay(200);
  }
  if (digitalRead(BTN_SLEEP) == LOW) {
    toggleSleep();
    delay(200);
  }
  if (digitalRead(BTN_STATUS) == LOW) {
    showStatus = !showStatus; // Durum ekranını aç/kapat
    delay(200);
  }

  // ÇİZİM İŞLEMLERİ
  display.clearDisplay();

  if (hunger <= 0 || happiness <= 0) {
    drawGameOver();
  } else if (showStatus) {
    drawStatus();
  } else {
    drawGameScreen();
  }

  display.display();
}

// --- EYLEM FONKSİYONLARI ---

void feedPet() {
  if (isSleeping) return; // Uyurken yemek yiyemez
  hunger += 20;
  if(hunger > 100) hunger = 100;
  
  // Yemek yeme animasyonu (Basit mesaj)
  display.clearDisplay();
  display.drawBitmap(56, 20, rabbit_eat, 16, 16, SSD1306_WHITE);
  display.setCursor(35, 50);
  display.print(F("NAM NAM!"));
  display.display();
  delay(1000);
}

void playPet() {
  if (isSleeping) { // Uyandır
    isSleeping = false;
    return;
  }
  if (energy < 10) { // Çok yorgunsa oynamaz
     display.clearDisplay();
     display.setCursor(30, 30);
     display.print(F("COK YORGUN!"));
     display.display();
     delay(1000);
     return;
  }
  
  happiness += 15;
  energy -= 10; // Oyun oynamak yorar
  hunger -= 5;  // Oyun oynamak acıktırır
  
  if(happiness > 100) happiness = 100;
  
  display.clearDisplay();
  display.drawBitmap(56, 20, rabbit_idle, 16, 16, SSD1306_WHITE);
  display.setCursor(30, 50);
  display.print(F("YASASIN!"));
  display.display();
  delay(1000);
}

void toggleSleep() {
  isSleeping = !isSleeping;
}

// --- ÇİZİM FONKSİYONLARI ---

void drawGameScreen() {
  // Üst bilgi çubuğu
  display.drawLine(0, 10, 128, 10, SSD1306_WHITE);
  display.setCursor(0, 0);
  if (isSleeping) display.print(F("Zzz..."));
  else display.print(F("Mutlu"));
  
  // Tavşan Çizimi
  // Ekranın ortasına yerleştir
  if (isSleeping) {
     display.drawBitmap(56, 24, rabbit_sleep, 16, 16, SSD1306_WHITE);
  } else {
     display.drawBitmap(56, 24, rabbit_idle, 16, 16, SSD1306_WHITE);
  }
  
  // Alt kısma küçük ipuçları
  display.setCursor(0, 55);
  display.print(F("1:Yem 2:Oyun 3:Uyu"));
}

void drawStatus() {
  display.setCursor(30, 0);
  display.print(F("-- DURUM --"));
  
  display.setCursor(0, 15);
  display.print(F("ACLIK: "));
  drawBar(50, 15, hunger);

  display.setCursor(0, 30);
  display.print(F("MUTLULUK:"));
  drawBar(50, 30, happiness);
  
  display.setCursor(0, 45);
  display.print(F("ENERJI:  "));
  drawBar(50, 45, energy);
}

void drawBar(int x, int y, int value) {
  // Basit bir bar çubuğu çizer
  display.drawRect(x, y, 60, 8, SSD1306_WHITE); // Çerçeve
  int width = map(value, 0, 100, 0, 56); // Değeri genişliğe çevir
  display.fillRect(x+2, y+2, width, 4, SSD1306_WHITE); // İçini doldur
}

void drawGameOver() {
  display.setCursor(35, 20);
  display.setTextSize(1);
  display.println(F("OYUN BITTI"));
  display.setCursor(20, 40);
  display.print(F("Tavsan kacti :("));
  display.setTextSize(1);
}

Oyunun Özellikleri:

  • Açlık, Mutluluk ve Enerji barları var.
  • Zamanla bu ihtiyaçlar azalıyor.
  • Tavşan karakteri uyuduğunda enerji topluyor, yemek yediğinde karnı doyuyor.
  • Animasyonlar ve menü geçişleri oldukça akıcı.

Yapay Zeka Destekli Oyun Geliştirmenin Avantajları

  • Hızlı prototipleme: Saatler yerine dakikalar içinde proje geliştirme
  • Hata çözüm desteği: Kodlarda sorun çıktığında anlık destek
  • Donanım uyumu: Elde olan parçalarla sistem çalışabilir mi? Çözüm sizde değil, yapay zekada!
  • Kreatif gelişim: Beklemediğin oyun fikirleri ve animasyonlar

Video ile Adım Adım İlerle

Kodu Yapay Zeka Yazarsa Maker Ne Yapar?

Yapay zeka, projeyi sizin adınıza tasarlayabilir. Ama uygulamak, test etmek, oynamak ve eğlenmek tamamen size ait. Projede gördük ki, ChatGPT ve Gemini gibi yapay zeka araçları şahane birer proje arkadaşı!

Sıra Sizde!

Projemizdeki el atarisini siz de kurup kendi oyunlarınızı yapay zeka desteğiyle tasarlamaya ne dersiniz? Siz hangi oyunları kodlayarak oynamak isterdiniz? Fikirlerinizi yorumlarda bekliyoruz…

Son Çıkan Yazılar

CEVAP VER

Lütfen yorumunuzu giriniz!
Lütfen isminizi buraya giriniz