From 2158454ba016564a07bdbbd7539ba92e927ada35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Sat, 23 May 2026 18:27:48 +0300 Subject: [PATCH] feat: initialize PlatformIO project and implement robotic arm controller using Bluepad32 and servos --- .gitignore | 1 + README.md | 79 ++++++++++++++++++ include/README | 37 +++++++++ lib/README | 46 +++++++++++ platformio.ini | 26 ++++++ src/main.cpp | 218 +++++++++++++++++++++++++++++++++++++++++++++++++ test/README | 37 +++++++++ 7 files changed, 444 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 include/README create mode 100644 lib/README create mode 100644 platformio.ini create mode 100644 src/main.cpp create mode 100644 test/README diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03f4a3c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.pio diff --git a/README.md b/README.md new file mode 100644 index 0000000..09ad830 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# 🦾 4-Axis Robot Arm & Bluetooth Gamepad Control System + +Bu proje, **ESP32** geliştirme kartı kullanarak **Gen Game New S7 Bluetooth Gamepad** ile 4 servo motorlu bir robot kolun otonom ve hassas kontrolünü sağlar. + +Yazılım altyapısı kurulmuş, derlenmiş ve ESP32 kartınıza başarıyla yüklenmiştir. Projeyi hemen test etmek için aşağıdaki adımları sırasıyla uygulayabilirsiniz. + +--- + +## 🚀 Şu Anda Yapmanız Gerekenler (Adım Adım) + +### 1️⃣ Adım: Donanım Bağlantılarını Yapın (Wiring) +Servo motorların sinyal kablolarını (genellikle turuncu veya sarı) ESP32'nin aşağıdaki ilgili GPIO pinlerine bağlayın: + +| Servo Motor | ESP32 GPIO Pini | Gamepad Kontrolü | +| :--- | :---: | :--- | +| **Taban (Base)** | **GPIO 13** | Sol Analog Çubuk (Sağ / Sol - X Ekseni) | +| **Omuz (Shoulder)** | **GPIO 12** | Sol Analog Çubuk (Yukarı / Aşağı - Y Ekseni) | +| **Dirsek (Elbow)** | **GPIO 14** | Sağ Analog Çubuk (Yukarı / Aşağı - Y Ekseni) | +| **Kıskaç (Gripper)**| **GPIO 27** | **A Butonu** (Aç - 180°), **B Butonu** (Kapat - 0°) | + +> ⚠️ **ÖNEMLİ GÜÇ UYARISI:** +> Servo motorlar yüksek akım çeker. ESP32'nin zarar görmemesi ve servoların titrememesi (jitter) için: +> * Servoların **kırmızı (VCC)** ve **kahverengi/siyah (GND)** kablolarını harici bir **5V - 6V (en az 2A - 3A)** güç kaynağına bağlayın. +> * **ÇOK ÖNEMLİ:** Harici güç kaynağının **GND (-)** kutbunu, ESP32'nin **GND** pinine mutlaka ortaklayın (birleştirin). + +--- + +### 2️⃣ Adım: Seri Port Monitörünü Açın +ESP32'nin durumunu izlemek ve bağlantıyı doğrulamak için PlatformIO Seri Monitörünü açın: +1. VS Code'da en alttaki mavi barda yer alan **Fiş (Serial Monitor)** ikonuna tıklayın veya terminale şu komutu yazın: + ```bash + python -m platformio device monitor + ``` +2. Haberleşme hızı kodda **115200 baud** olarak ayarlanmıştır. Monitör açıldığında şu mesajı görmelisiniz: + ```text + Sistem Baslatildi. Gamepad baglantisi bekleniyor... + ``` + +--- + +### 3️⃣ Adım: Gamepad'i Eşleştirin (Pairing) +**Gen Game New S7** gamepad'inizi ESP32 ile eşleştirmek oldukça basittir. ESP32 şu an sürekli Bluetooth taraması yapmaktadır: + +1. Gamepad kapalıyken, eşleştirme moduna almak için: + * **`X` + `HOME (GEN GAME)`** butonlarına aynı anda basın ve birkaç saniye basılı tutun. + * Gamepad üzerindeki LED'ler hızlıca yanıp sönmeye başlayacaktır (bu, arama modunda olduğunu gösterir). +2. ESP32, gamepad'i algıladığında otomatik olarak eşleşecek ve bağlanacaktır. +3. Bağlantı kurulduğunda: + * Gamepad'in üzerindeki LED **sabit yanmaya** başlayacaktır. + * Seri Monitör ekranında **`Gamepad Baglandi`** yazısını göreceksiniz. + +--- + +### 4️⃣ Adım: Robot Kolu Test Edin! +Bağlantı kurulduktan sonra aşağıdaki kontrolleri kullanarak robot kolunuzu hareket ettirebilirsiniz: + +* 🕹️ **Sol Çubuğu Sola/Sağa itin:** Taban motoru döner. Bıraktığınızda motor o anki açısında kalır. +* 🕹️ **Sol Çubuğu Yukarı/Aşağı itin:** Omuz motoru aşağı/yukarı hareket eder. +* 🕹️ **Sağ Çubuğu Yukarı/Aşağı itin:** Dirsek motoru aşağı/yukarı hareket eder. +* 🔴 **A Butonuna basın:** Kıskaç tamamen açılır (180 derece). +* 🟢 **B Butonuna basın:** Kıskaç tamamen kapanır (0 derece). + +--- + +## 🛠️ Olası Sorun Giderme (Troubleshooting) + +* **Servolar hiç hareket etmiyor veya titriyor:** + * Harici güç kaynağınızın gücü yetersiz olabilir veya harici güç kaynağının GND kutbu ile ESP32'nin GND pini birleştirilmemiştir. Bağlantıları kontrol edin. +* **Gamepad eşleşmiyor veya bağlanmıyor:** + * Gamepad'i kapatıp tekrar `X + HOME` kombinasyonu ile açın. + * ESP32'yi üzerindeki **EN (Reset)** butonuna basarak yeniden başlatın. +* **Hareketler çok hızlı veya çok yavaş:** + * `src/main.cpp` dosyasındaki `const float SPEED_SCALE = 0.3;` değerini değiştirerek hareket hızını hassas bir şekilde ayarlayabilirsiniz (Örn: daha yavaş ve hassas hareket için `0.1` yapın). + +--- + +### 📂 Proje Dosyalarınızın Konumu +* 📄 **PlatformIO Yapılandırması:** [platformio.ini](file:///d:/Works/2026/robotkol/platformio.ini) +* 📄 **C++ Kod Dosyası:** [src/main.cpp](file:///d:/Works/2026/robotkol/src/main.cpp) diff --git a/include/README b/include/README new file mode 100644 index 0000000..49819c0 --- /dev/null +++ b/include/README @@ -0,0 +1,37 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the convention is to give header files names that end with `.h'. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/lib/README b/lib/README new file mode 100644 index 0000000..9379397 --- /dev/null +++ b/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into the executable file. + +The source code of each library should be placed in a separate directory +("lib/your_library_name/[Code]"). + +For example, see the structure of the following example libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional. for custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +Example contents of `src/main.c` using Foo and Bar: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +The PlatformIO Library Dependency Finder will find automatically dependent +libraries by scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..5faf84e --- /dev/null +++ b/platformio.ini @@ -0,0 +1,26 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32dev] +platform = espressif32 +board = esp32dev +framework = arduino +platform_packages = + framework-arduinoespressif32@https://github.com/maxgerhardt/pio-framework-bluepad32/archive/refs/heads/master.zip +monitor_speed = 115200 +lib_deps = + madhephaestus/ESP32Servo + ricardoquesada/Bluepad32 for NINA-W10 boards +lib_ignore = + Bluepad32 for NINA-W10 boards + + + + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..537d3dd --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,218 @@ +#include +#include +#include + +// Gamepad'lerin listesini tutmak için dizi (Bluepad32 birden fazla cihaz destekler) +ControllerPtr myControllers[BP32_MAX_GAMEPADS]; + +// Servo motor nesnelerimiz +Servo baseServo; // Taban (GPIO 13) +Servo shoulderServo; // Omuz (GPIO 12) +Servo elbowServo; // Dirsek (GPIO 14) +Servo gripperServo; // Kıskaç (GPIO 27) + +// Pin tanımlamaları +const int BASE_PIN = 13; +const int SHOULDER_PIN = 12; +const int ELBOW_PIN = 14; +const int GRIPPER_PIN = 27; + +// Başlangıç açıları (Genel olarak orta konumlarda başlatıyoruz) +float baseAngle = 90.0; +float shoulderAngle = 90.0; +float elbowAngle = 90.0; +float gripperAngle = 0.0; // Kıskaç kapalı veya açık başlangıç açısı + +// Joystick deadzone (ölü bölge) eşiği +const int DEADZONE = 50; + +// Yumuşak ve kontrollü hareket için açı değişim katsayısı (Hız) +const float SPEED_SCALE = 0.3; + +// Gamepad bağlandığında tetiklenecek callback fonksiyonu +void onConnectedController(ControllerPtr ctl) { + bool foundEmptySlot = false; + for (int i = 0; i < BP32_MAX_GAMEPADS; i++) { + if (myControllers[i] == nullptr) { + myControllers[i] = ctl; + foundEmptySlot = true; + Serial.println("Gamepad Baglandi"); + break; + } + } +} + +// Gamepad bağlantısı koptuğunda tetiklenecek callback fonksiyonu +void onDisconnectedController(ControllerPtr ctl) { + for (int i = 0; i < BP32_MAX_GAMEPADS; i++) { + if (myControllers[i] == ctl) { + myControllers[i] = nullptr; + Serial.println("Gamepad Baglantisi Kesildi"); + break; + } + } +} + +// Gamepad verilerini işleyen fonksiyon +void processGamepad(ControllerPtr ctl) { + // Sol ve Sağ analog çubuk değerlerini alıyoruz + // Bu değerler tipik olarak -512 ile 512 arasındadır + int lx = ctl->axisX(); + int ly = ctl->axisY(); + int ry = ctl->axisRY(); + + // Buton basış durumlarını takip etmek için static değişkenler + static bool prevA = false; + static bool prevB = false; + static bool prevX = false; + static bool prevY = false; + static int prevLx = 0; + static int prevLy = 0; + static int prevRy = 0; + + bool curA = ctl->a(); + bool curB = ctl->b(); + bool curX = ctl->x(); + bool curY = ctl->y(); + + // Buton A Loglaması + if (curA != prevA) { + if (curA) { + Serial.println("[INPUT] A Butonuna Basildi -> Kiskac Aciliyor (180 derece)"); + } else { + Serial.println("[INPUT] A Butonu Birakildi"); + } + prevA = curA; + } + + // Buton B Loglaması + if (curB != prevB) { + if (curB) { + Serial.println("[INPUT] B Butonuna Basildi -> Kiskac Kapatiliyor (0 derece)"); + } else { + Serial.println("[INPUT] B Butonu Birakildi"); + } + prevB = curB; + } + + // Buton X Loglaması + if (curX != prevX) { + if (curX) { + Serial.println("[INPUT] X Butonuna Basildi"); + } else { + Serial.println("[INPUT] X Butonu Birakildi"); + } + prevX = curX; + } + + // Buton Y Loglaması + if (curY != prevY) { + if (curY) { + Serial.println("[INPUT] Y Butonuna Basildi"); + } else { + Serial.println("[INPUT] Y Butonu Birakildi"); + } + prevY = curY; + } + + // Joystick hareketlerini loglama (terminali kirletmemek icin sadece bariz degisimlerde log atar) + if (abs(lx - prevLx) > 30 || abs(ly - prevLy) > 30 || abs(ry - prevRy) > 30) { + if (abs(lx) > DEADZONE || abs(ly) > DEADZONE || abs(ry) > DEADZONE) { + Serial.printf("[JOYSTICK] lx: %d, ly: %d, ry: %d | Aci -> Taban: %.1f, Omuz: %.1f, Dirsek: %.1f\n", + lx, ly, ry, baseAngle, shoulderAngle, elbowAngle); + } + prevLx = lx; + prevLy = ly; + prevRy = ry; + } + + // 1. TABAN (GPIO 13) - Sol Analog X ekseni ile kontrol edilir + if (abs(lx) > DEADZONE) { + baseAngle += (lx / 512.0) * SPEED_SCALE; + } + + // 2. OMUZ (GPIO 12) - Sol Analog Y ekseni ile kontrol edilir + // Joystick'i yukarı ittiğimizde (ly negatif değer aldığında) açının artmasını istiyoruz, + // bu yüzden çıkarma işlemi yapıyoruz. + if (abs(ly) > DEADZONE) { + shoulderAngle -= (ly / 512.0) * SPEED_SCALE; + } + + // 3. DİRSEK (GPIO 14) - Sağ Analog Y ekseni ile kontrol edilir + if (abs(ry) > DEADZONE) { + elbowAngle -= (ry / 512.0) * SPEED_SCALE; + } + + // 4. KISKAÇ (GPIO 27) - Gamepad A ve B butonları ile kontrol edilir + // A butonu kıskaçı tamamen açsın (180 derece), B butonu tamamen kapatsın (0 derece) + if (ctl->a()) { + gripperAngle = 180.0; + } else if (ctl->b()) { + gripperAngle = 0.0; + } + + // Servoların fiziksel sınırlarını (0 - 180 derece arası) constrain ile garanti altına alıyoruz + baseAngle = constrain(baseAngle, 0.0, 180.0); + shoulderAngle = constrain(shoulderAngle, 0.0, 180.0); + elbowAngle = constrain(elbowAngle, 0.0, 180.0); + gripperAngle = constrain(gripperAngle, 0.0, 180.0); + + // Güncel açıları servolara yazıyoruz + baseServo.write((int)baseAngle); + shoulderServo.write((int)shoulderAngle); + elbowServo.write((int)elbowAngle); + gripperServo.write((int)gripperAngle); +} + +void setup() { + // Seri haberleşmeyi başlat (115200 baud) + Serial.begin(115200); + while (!Serial) { + delay(1); // Seri portun hazır olmasını bekle + } + + // ESP32'nin donanımsal PWM zamanlayıcılarını tahsis et + ESP32PWM::allocateTimer(0); + ESP32PWM::allocateTimer(1); + ESP32PWM::allocateTimer(2); + ESP32PWM::allocateTimer(3); + + // Servoların frekansını ayarla (Standart servo motorlar 50 Hz'de çalışır) + baseServo.setPeriodHertz(50); + shoulderServo.setPeriodHertz(50); + elbowServo.setPeriodHertz(50); + gripperServo.setPeriodHertz(50); + + // Servoları ilgili GPIO pinlerine ata (Standart pulse aralıkları: 500-2400 mikrosaniye) + baseServo.attach(BASE_PIN, 500, 2400); + shoulderServo.attach(SHOULDER_PIN, 500, 2400); + elbowServo.attach(ELBOW_PIN, 500, 2400); + gripperServo.attach(GRIPPER_PIN, 500, 2400); + + // İlk konumlarına (başlangıç açılarına) getir + baseServo.write((int)baseAngle); + shoulderServo.write((int)shoulderAngle); + elbowServo.write((int)elbowAngle); + gripperServo.write((int)gripperAngle); + + // Bluepad32 kütüphanesini başlat ve callback fonksiyonlarını bağla + BP32.setup(&onConnectedController, &onDisconnectedController); + + Serial.println("Sistem Baslatildi. Gamepad baglantisi bekleniyor..."); +} + +void loop() { + // Bluetooth bağlantı durumunu ve gamepad verilerini günceller (Zorunlu) + BP32.update(); + + // Bağlı olan tüm gamepad'leri işle + for (int i = 0; i < BP32_MAX_GAMEPADS; i++) { + ControllerPtr myController = myControllers[i]; + if (myController && myController->isConnected()) { + processGamepad(myController); + } + } + + // Servo hareketlerinin kararlı ve yumuşak olması için küçük bir gecikme (~60Hz güncelleme hızı) + delay(15); +} diff --git a/test/README b/test/README new file mode 100644 index 0000000..fa285b7 --- /dev/null +++ b/test/README @@ -0,0 +1,37 @@ +🦾 ROBOT KOL PROJESİ HIZLI BAŞLANGIÇ KILAVUZU +========================================== + +Tebrikler! Robot kol kontrol yazılımınız başarıyla derlendi ve ESP32 kartınıza (COM3 portu üzerinden) yüklendi. + +Şu anda yapmanız gereken adımlar sırasıyla şunlardır: + +1. DONANIM BAĞLANTILARI (WIRING) +-------------------------------- +Servo sinyal kablolarını (genellikle sarı/turuncu) ESP32'nin şu pinlerine bağlayın: +* TABAN SERVO --> GPIO 13 +* OMUZ SERVO --> GPIO 12 +* DİRSEK SERVO --> GPIO 14 +* KISKAÇ SERVO --> GPIO 27 + +* ÖNEMLİ: Servolar için harici 5V-6V (en az 2A) güç kaynağı kullanın ve güç kaynağının eksisini (GND) ESP32'nin GND pini ile birleştirin. + +2. GAMEPAD EŞLEŞTİRME (PAIRING) +-------------------------------- +1. Gamepad kapalıyken X ve HOME (GEN GAME) butonlarına aynı anda basılı tutarak gamepad'i arama moduna alın (LED'ler hızlıca yanıp sönmelidir). +2. ESP32 otomatik olarak bağlanacaktır. Bağlantı sağlandığında gamepad LED'i sabit kalacaktır. + +3. KONTROL ŞEMASI +----------------- +* SOL ANALOG (Sola/Sağa): Taban Servo (GPIO 13) +* SOL ANALOG (Yukarı/Aşağı): Omuz Servo (GPIO 12) +* SAĞ ANALOG (Yukarı/Aşağı): Dirsek Servo (GPIO 14) +* A BUTONU: Kıskaçı Aç (180 derece) (GPIO 27) +* B BUTONU: Kıskaçı Kapat (0 derece) (GPIO 27) + +4. İZLEME (MONITOR) +------------------- +Seri monitörü açarak (115200 baud) bağlantı loglarını izleyebilirsiniz: +"Gamepad Baglandi" uyarısını ekranınızda göreceksiniz. + +Detaylı rehber, görsel tablolar ve sorun giderme adımları için ana dizindeki README.md dosyasını inceleyebilirsiniz: +--> d:\Works\2026\robotkol\README.md