Bu kılavuzda, bir step motoru kontrol etmek için bir web sayfası görüntüleyen ESP8266 NodeMCU kartı ile bir web sunucusunun nasıl oluşturulacağını öğreneceksiniz. Web sayfası, adım sayısını girmenize ve saat yönünde veya saat yönünün tersine yön seçmenize olanak tanır. Ek olarak, motorun o anda dönüp dönmediğini veya durup durmadığını da gösterir. İstemci ile sunucu arasındaki iletişim WebSocket protokolü ile sağlanır. Tüm istemciler mevcut motor durumuyla güncellenir.
Gerekli Malzemeler;
- 28BYJ-48 Step Motor + ULN2003 Motor Sürücü
- ESP8266
- Bağlantı Kabloları
- 5V Adaptör
Dosya Sistemi Yükleme Eklentisi;
Bu projeyi ESP8266 dosya sistemine (LittleFS) oluşturmak için gereken HTML, CSS ve JavaScript dosyalarını yüklemek için Arduino IDE: LittleFS Dosya Sistemi yükleyicisi için bir eklenti kullanacağız . Henüz yapmadıysanız, dosya sistemi yükleyici eklentisini kurmak için sonraki öğreticiyi izleyin.
Arduino IDE’de ESP8266 NodeMCU LittleFS Dosya Sistemi Yükleyicisini Kurun.
Kütüphaneler;
Bir mikrodenetleyici ile step motorları kontrol etmenin farklı yolları vardır. Step motoru ESP8266 ile kontrol etmek için AccelStepper kitaplığını kullanacağız . Bu kitaplık, motoru tanımlı sayıda adımla kolayca hareket ettirmenize, hızını, ivmesini ve çok daha fazlasını ayarlamanıza olanak tanır. Kütüphane, yöntemlerinin nasıl kullanılacağını açıklayan harika belgelere sahiptir. Buradan kontrol edebilirsiniz.
AccelStepper.h
MultiStepper.h
Kütüphaneyi Arduino IDE’nize kurmak için sonraki adımları izleyin.
- Git Sketch > Kütüphane Dahil > Kitaplıkları yönet …
- “Accelstepper” için arama yapın.
- Mike McCauley’nin AccelStepper kitaplığını kurun. 1.61.0 sürümünü kullanıyoruz.
Web sunucusunu oluşturmak için aşağıdaki kitaplıkları yüklemeniz gerekir:
ESPAsyncTCP (.zip klasörü)
ESPAsyncWebServer (.zip klasörü)
ESPAsyncWebServer ve ESPAsynTCP kitaplıkları, Arduino Kitaplık Yöneticisi aracılığıyla kurulamaz. Kütüphane dosyalarını indirmek için önceki bağlantılara tıklamanız gerekir. Ardından, Arduino IDE’nizde Sketch > Include Library > Add .zip Library’ye gidin ve az önce indirdiğiniz kitaplıkları seçin.
Şematik Diyagram;
Aşağıdaki şematik diyagram, step motor ile ESP8266 arasındaki bağlantıları göstermektedir.
Not: ULN2003 motor sürücüsüne harici bir 5V güç kaynağı kullanarak güç vermelisiniz.
Motor sürücüsü | ESP8266 |
IN1 | GPIO 5 |
IN2 | GPIO 4 |
IN3 | GPIO 14 |
IN4 | GPIO 12 |
Projeye Genel Bakış;
Aşağıdaki resim, bu proje için oluşturacağınız web sayfasını göstermektedir.
- Web sayfası, motorun hareket etmesini istediğiniz adım sayısını girebileceğiniz ve yönü seçebileceğiniz bir form gösterir: saat yönünde veya saat yönünün tersine.
- Ayrıca motor durumunu da gösterir: motor dönüyor veya motor duruyor . Ek olarak, motor döndüğü sürece dönen bir dişli simgesi vardır. Dişli, seçilen yöne göre saat yönünde veya saat yönünün tersine döner.
- Sunucu ve istemci, WebSocket protokolünü kullanarak iletişim kurar.
- GO’ya tıkladığınızda ! düğmesine bastığınızda, WebSocket protokolü aracılığıyla tüm bilgileri içeren bir mesaj gönderen bir Javascript işlevini çağırır: adımlar ve yön ( 3 ). Mesaj aşağıdaki formattadır:
steps&direction
Yani 2000 adım ve saat yönünü gönderirseniz, aşağıdaki mesajı gönderecektir:
2000&CW
- Aynı zamanda web sayfasındaki motor durumunu değiştirecek ve dişli doğru yönde dönmeye başlayacaktır ( 2 ).
- Ardından sunucu mesajı ( 4 ) alır ve motoru buna göre döndürür ( 5 ).
- Motor dönmeyi bıraktığında ( 6 ), ESP istemci(ler)e yine WebSocket protokolü aracılığıyla motorun durduğunu bildiren bir mesaj gönderir ( 7 ).
- Müşteri(ler) bu talebi alır ve motor durumunu web sayfasında ( 8 ) günceller.
Dosyalarınızı Düzenleme;
ESP dosya sistemine yüklemek istediğiniz dosyalar adlı bir klasöre yerleştirilmelidir. veriproje klasörü altında. Üç dosyayı bu klasöre taşıyacağız:
- index.html web sayfasını oluşturmak için;
- stil.css web sayfasını biçimlendirmek için;
- script.js websocket iletişimini yönetmek ve dişli animasyonunu başlatmak/durdurmak için.
HTML, CSS ve JavaScript dosyalarını adlı bir klasöre kaydetmelisiniz. veriönceki şemada gösterildiği gibi Arduino eskiz klasörünün içinde. Bu dosyaları ESP8266 dosya sistemine (LittleFS) yükleyeceğiz.
ESP8266 dosya sistemine (LittleFS) Projesi Tüm Dosyalar
HTML Dosyası;
<!DOCTYPE html> <html> <head> <title>Stepper Motor</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" type="text/css" href="style.css"> <link rel="icon" type="image/png" href="favicon.png"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> </head> <body> <div class="topnav"> <h1>Stepper Motor Control <i class="fas fa-cogs"></i></h1> </div> <div class="content"> <form> <input type="radio" id="CW" name="direction" value="CW" checked> <label for="CW">Clockwise</label> <input type="radio" id="CCW" name="direction" value="CCW"> <label for="CW">Counterclockwise</label><br><br><br> <label for="steps">Number of steps:</label> <input type="number" id="steps" name="steps"> </form> <button onclick="submitForm()">GO!</button> <p>Motor state: <span id="motor-state">Stopped</span></p> <p><i id="gear" class="fas fa-cog"></i> </p> </div> </body> <script src="script.js"></script> </html>
JavaScript kullanarak değiştirmek istediğimiz HTML öğelerine kimlikler ekledik; radyo düğmeleri ve giriş alanı:
- saat yönünde radyo düğmesi: id=”CW”
- ters yönde radyo düğmesi: id=”CCW”
- adımlar giriş alanı: id=”steps”
<input type="radio" id="CW" name="direction" value="CW" checked> <label for="CW">Clockwise</label> <input type="radio" id="CCW" name="direction" value="CCW"> <label for="CW">Counterclockwise</label><br><br><br> <label for="steps">Number of steps:</label> <input type="number" id="steps" name="steps">
Form sonuçlarını WebSocket protokolü ile sunucuya (ESP8266) göndermek istiyoruz. Bu yüzden, tıklandığında (onclick) çağırır. SubmitForm() JavaScript bölümünde daha sonra göreceğiniz gibi sonuçları sunucuya gönderen kullanıcı tanımlı javascript işlevi.
<button onclick="submitForm()">GO!</button>
Ayrıca, motor durumunu görüntülemek için bir paragraf da ekledik. iki <span> arasındaki Motor-State id sindeki metni değiştirebilirsiniz. Javascript tetiklemektedir.
<p>Motor state: <span id="motor-state">Stopped</span></p>
Son olarak, bir dişliyi gösteren bir paragraf var. id=”gear”. Dişliyi hareket ettirmek için bu kimliğe ihtiyacımız var.
<p><i id="gear" class="fas fa-cog"></i> </p>
JavaScript dosyasına başvurmanız gerektiğini unutmayın (Script.js) aşağıdaki gibi HTML dosyasında:
<script src="script.js"></script>
CSS Dosyası;
Style.css adlı bir dosya oluşturun aşağıdaki içerikleri ekleyin.
html { font-family: Arial, Helvetica, sans-serif; } h1 { font-size: 1.8rem; color: white; } p{ font-size: 20px; text-align: center; } .topnav { overflow: hidden; background-color: #0A1128; text-align: center; } body { margin: 0; } .content { padding: 20px; max-width: max-content; margin: 0 auto; } input[type=number], select { width: 100%; padding: 12px 20px; margin: 8px 0; display: inline-block; border: 1px solid #ccc; border-radius: 4px; box-sizing: border-box; } form{ border-radius: 5px; background-color: #f2f2f2; padding: 20px; } button { background-color: #034078; border: none; padding: 14px 20px; text-align: center; font-size: 20px; border-radius: 4px; transition-duration: 0.4s; width: 100%; color: white; cursor: pointer; } button:hover { background-color: #1282A2; } input[type="radio"] { -webkit-appearance: none; -moz-appearance: none; appearance: none; border-radius: 50%; width: 16px; height: 16px; border: 2px solid #999; transition: 0.2s all linear; margin-right: 5px; position: relative; top: 4px; } input[type="radio"]:checked{ border: 6px solid #1282A2; } #motor-state{ font-weight: bold; color: red; } #gear{ font-size:100px; color:#2d3031cb; } .spin { -webkit-animation:spin 4s linear infinite; -moz-animation:spin 4s linear infinite; animation:spin 4s linear infinite; } .spin-back { -webkit-animation:spin-back 4s linear infinite; -moz-animation:spin-back 4s linear infinite; animation:spin-back 4s linear infinite; } @-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } @-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } @-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } } @-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } } @keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }
Motor durumu metnini yazı tipi ağırlığını biçimlendiriyoruz (bold) ve renk (red). CSS’de belirli bir kimliğe atıfta bulunmak için şunu kullanın: (ÖRn: #motor durumu).
#motor-state{ font-weight: bold; color: red; }
Aşağıdaki satırlar gear simgesinin rengini ve boyutunu biçimlendirir; kimliğinin gear, bu yüzden ona atıfta bulunuyoruz #gear:
#gear{ font-size:100px; color:#2d3031cb; }
Ardından, iki sınıfı biçimlendiriyoruz döndürmek ve geri dönüşhenüz herhangi bir HTML öğesine atfedilmemiş. atfedeceğizdöndürmek ve geri dönüş motor hareket etmeye başladığında JavaScript kullanarak dişliye sınıflar.
Bu sınıflar, animasyondişliyi döndürme özelliği. hakkında daha fazla bilgi edinmek içinanimasyonmülk çalışır, bu hızlı eğiticiye bir göz atmanızı öneririz.
.spin { -webkit-animation:spin 4s linear infinite; -moz-animation:spin 4s linear infinite; animation:spin 4s linear infinite; } .spin-back { -webkit-animation:spin-back 4s linear infinite; -moz-animation:spin-back 4s linear infinite; animation:spin-back 4s linear infinite; } @-moz-keyframes spin { 100% { -moz-transform: rotate(360deg); } } @-webkit-keyframes spin { 100% { -webkit-transform: rotate(360deg); } } @keyframes spin { 100% { -webkit-transform: rotate(360deg); transform:rotate(360deg); } } @-moz-keyframes spin-back { 100% { -moz-transform: rotate(-360deg); } } @-webkit-keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); } } @keyframes spin-back { 100% { -webkit-transform: rotate(-360deg); transform:rotate(-360deg); } }
JavaScript Dosyası;
Script.js adlı bir dosya oluşturun aşağıdaki içerikleri ekleyiniz.
var gateway = `ws://${window.location.hostname}/ws`; var websocket; window.addEventListener('load', onload); var direction; function onload(event) { initWebSocket(); } function initWebSocket() { console.log('Trying to open a WebSocket connection…'); websocket = new WebSocket(gateway); websocket.onopen = onOpen; websocket.onclose = onClose; websocket.onmessage = onMessage; } function onOpen(event) { console.log('Connection opened'); } function onClose(event) { console.log('Connection closed'); document.getElementById("motor-state").innerHTML = "motor stopped" setTimeout(initWebSocket, 2000); } function submitForm(){ const rbs = document.querySelectorAll('input[name="direction"]'); direction; for (const rb of rbs) { if (rb.checked) { direction = rb.value; break; } } document.getElementById("motor-state").innerHTML = "motor spinning..."; document.getElementById("motor-state").style.color = "blue"; if (direction=="CW"){ document.getElementById("gear").classList.add("spin"); } else{ document.getElementById("gear").classList.add("spin-back"); } var steps = document.getElementById("steps").value; websocket.send(steps+"&"+direction); } function onMessage(event) { console.log(event.data); direction = event.data; if (direction=="stop"){ document.getElementById("motor-state").innerHTML = "motor stopped" document.getElementById("motor-state").style.color = "red"; document.getElementById("gear").classList.remove("spin", "spin-back"); } else if(direction=="CW" || direction=="CCW"){ document.getElementById("motor-state").innerHTML = "motor spinning..."; document.getElementById("motor-state").style.color = "blue"; if (direction=="CW"){ document.getElementById("gear").classList.add("spin"); } else{ document.getElementById("gear").classList.add("spin-back"); } } }
Bu proje için JavaScript’in nasıl çalıştığını görelim.
Gateway WebSocket arayüzüne giriş noktasıdır. window.location.hostname bilgisayar adı geçerli sayfa adresini alır (web sunucusu IP adresi)
var gateway = `ws://${window.location.hostname}/ws`;
Websocket adlı yeni bir global değişken oluşturun.
var websocket;
Direction adlı başka bir global değişken oluşturun yön bu motorun mevcut yönünü tutacaktır: saat yönünde, saat yönünün tersine veya durdurulmuş.
var direction;
Onload ekliyoruz.
window.addEventListener('load', onload);
Arduino Kroki
Aşağıdaki kodu Arduino IDE’ye kopyalayın. Ağ kimlik bilgilerinizi girin ve hemen çalışacaktır.
#include <Arduino.h> #include <ESP8266WiFi.h> #include <ESPAsyncWebServer.h> #include "LittleFS.h" #include <AccelStepper.h> #define IN1 5 #define IN2 4 #define IN3 14 #define IN4 12 AccelStepper stepper(AccelStepper::HALF4WIRE, IN1, IN3, IN2, IN4); String message = ""; // Replace with your network credentials const char* ssid = "REPLACE_WITH_YOUR_SSID"; const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Create AsyncWebServer object on port 80 AsyncWebServer server(80); // Create a WebSocket object AsyncWebSocket ws("/ws"); //Variables to save values from HTML form String direction ="STOP"; String steps; bool notifyStop = false; // Initialize LittleFS void initFS() { if (!LittleFS.begin()) { Serial.println("An error has occurred while mounting LittleFS"); } else{ Serial.println("LittleFS mounted successfully"); } } // Initialize WiFi void initWiFi() { WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); Serial.print("Connecting to WiFi .."); while (WiFi.status() != WL_CONNECTED) { Serial.print('.'); delay(1000); } Serial.println(WiFi.localIP()); } void notifyClients(String state) { ws.textAll(state); } void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) { AwsFrameInfo *info = (AwsFrameInfo*)arg; if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) { data[len] = 0; message = (char*)data; steps = message.substring(0, message.indexOf("&")); direction = message.substring(message.indexOf("&")+1, message.length()); Serial.print("steps"); Serial.println(steps); Serial.print("direction"); Serial.println(direction); notifyClients(direction); notifyStop = true; if (direction == "CW"){ Serial.print("CW"); stepper.move(steps.toInt()); } else{ Serial.print("CCW"); stepper.move(-steps.toInt()); } } } void onEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) { switch (type) { case WS_EVT_CONNECT: Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str()); //Notify client of motor current state when it first connects notifyClients(direction); break; case WS_EVT_DISCONNECT: Serial.printf("WebSocket client #%u disconnected\n", client->id()); break; case WS_EVT_DATA: handleWebSocketMessage(arg, data, len); break; case WS_EVT_PONG: case WS_EVT_ERROR: break; } } void initWebSocket() { ws.onEvent(onEvent); server.addHandler(&ws); } void setup() { // Serial port for debugging purposes Serial.begin(115200); initWiFi(); initWebSocket(); initFS(); stepper.setMaxSpeed(1000); stepper.setAcceleration(100); // Web Server Root URL server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){ request->send(LittleFS, "/index.html", "text/html"); }); server.serveStatic("/", LittleFS, "/"); server.begin(); } void loop() { if (stepper.distanceToGo() == 0 && notifyStop == true){ direction = "stop"; notifyClients(direction); notifyStop = false; } ws.cleanupClients(); stepper.run(); }
Kodu ve Dosyaları Yükle;
Ağ kimlik bilgilerinizi girdikten sonra kodu kaydedin. Çizim > Çizim Klasörünü Göster’e gidin ve data adlı bir klasör oluşturun.
Bu klasörün içine HTML, CSS ve JavaScript dosyalarını kaydetmelisiniz.
Ardından, kodu ESP8266 kartınıza yükleyin. Doğru kartın ve COM bağlantı noktasının seçili olduğundan emin olun. Ayrıca, ağ kimlik bilgilerinizi eklediğinizden emin olun.
Kodu yükledikten sonra dosyaları yüklemeniz gerekir. Gidin Araçlar > ESP8266 LittleFS Veri Yükleme ve dosyalar için beklemek yüklenmesine.
Her şey başarıyla yüklendiğinde, Seri Monitörü 115200 baud hızında açın. ESP8266 RST düğmesine basın, ESP8266 IP adresini yazdırmalıdır.
Yerel ağınızda bir web tarayıcısı veya birden fazla web tarayıcı penceresi açın ve motoru kontrol etmek için web sayfasına erişin. Motoru kontrol etmek için formu gönderin.
Web sayfasındaki dişli doğru yönde dönmeye başlar ve fiziksel motor çalışmaya başlar.
Durduğunda web sayfasındaki vites ve motor durumu buna göre değişir.
Birden fazla istemcinin bağlı olması durumunda, tüm istemcilerin motor durumunu neredeyse anında güncellediklerine dikkat edin.