ESP32 ve Arduino

ESP32 Step Motor MQTT: Canlı İlerleme Güncellemeleriyle Konum Kontrolü

Bir NEMA 17 step motoru ESP32, AccelStepper ve A4988 ya da DRV8825 sürücüyle MQTT konum komutlarından sürün ve uygulamaların motorun nerede olduğunu bilmesi için canlı ilerleme yayınlayın.

Bir esp32 step motor mqtt kurulumunda A4988 sürücü ve ESP32 kartıyla NEMA 17 motor
Bunu kendi MQTT broker’ınızda çalıştırınFree planla özel, yönetilen bir MQTT broker alın ve hazır kod örnekleriyle başlayın.
Ücretsiz deneyin Kod örnekleri Kart gerekmez

Bir ESP32 step motor MQTT kontrolcüsü; bir kamera kaydırıcısını, bir dozaj pompasını, bir panjuru veya küçük bir lineer ekseni ağın herhangi bir yerinden konumlandırmanızı sağlar. Bu eğitimde AccelStepper kütüphanesiyle bir A4988 veya DRV8825 sürücü üzerinden bir NEMA 17 motoru sürecek, MQTT üzerinden mutlak ve göreli hareketleri kabul edecek ve motor çalışırken canlı ilerleme yayınlayacaksınız. Zor kısım MQTT değil, ağ işini yaparken adım darbelerini akıcı tutmaktır; sketch bunu motoru kendi çekirdeğinde çalıştırarak çözer.

Komutlar, Topic'ler ve İlerleme Raporları

Step motorlar açık döngülüdür: ESP32 gönderdiği adımları sayar ve motor kilitlenmediği sürece bu sayı konumdur. Bu, cihazın enkoder olmadan konumu doğru şekilde bildirebilmesi anlamına geldiği için onları MQTT kontrolü için ideal kılar.

Topic Yön Retained Payload
connectmq/demo/<id>/stepper/cmd Uygulamadan ESP32'ye Hayır JSON komut, aşağıya bakın
connectmq/demo/<id>/stepper/progress ESP32'den uygulamalara Evet {"pos":1200,"target":3200,"pct":37,"moving":true}
connectmq/demo/<id>/status ESP32'den uygulamalara Evet online / offline
Komut Örnek Etki
Mutlak hareket {"cmd":"moveTo","pos":3200} 3200. adıma git
Göreli hareket {"cmd":"move","steps":-400} 400 adım geri git
Hız {"cmd":"speed","max":1500,"accel":800} Maks. adım/s ve adım/s²
Durdur {"cmd":"stop"} Kontrollü bir duruşa yavaşla
Sıfırla {"cmd":"zero"} Mevcut konumu 0 olarak tanımla
Serbest bırak {"cmd":"disable"} Bobin akımını kapat

Tipik 1,8 derecelik bir motor ve 1/16 mikro adımla bir tur 3200 adımdır. Tur başına 8 mm ilerleyen bir trapez vidada bu, milimetre başına 400 adım eder; bu da uygulamanıza koymak için kullanışlı bir dönüşümdür.

Donanım

  • ESP32 geliştirme kartı.
  • NEMA 17 step motor (bipolar, dört kablolu).
  • İdeal olarak vidalı klemensli bir taşıyıcı kart üzerinde A4988 veya DRV8825 sürücü modülü.
  • Motora uygun 12 V ile 24 V arası bir kaynak ve sürücünün motor besleme girişine paralel 100 µF bir kondansatör.
Sürücü pini Bağlantı
STEP ESP32 GPIO 25
DIR ESP32 GPIO 26
EN ESP32 GPIO 27 (low = etkin)
MS1, MS2, MS3 (A4988) / M0, M1, M2 (DRV8825) 1/16 (A4988) veya 1/32 (DRV8825) mikro adım için high'a bağlayın
VDD / GND (lojik) ESP32 3V3 / GND
VMOT / GND Motor kaynağı
1A, 1B, 2A, 2B Motor bobinleri
RESET + SLEEP Birbirine köprüleyin

Motoru uzun süreli çalıştırmak üzere bağlamadan önce akım limitini sürücünün trimpotuyla ayarlayın. Fazla akım sürücüyü ve motoru aşırı ısıtır; az akım adım kaçırır. Sürücü enerjiliyken motoru asla takıp çıkarmayın, çünkü endüktif sıçrama sürücüyü anında yok edebilir.

Kütüphaneler

  • Nick O'Leary'nin PubSubClient kütüphanesi.
  • İvme profilleri ve engellemeyen adım darbeleri üreten Mike McCauley'in AccelStepper kütüphanesi.
  • ArduinoJson sürüm 7.

Motor Neden Kendi Görevinde Çalışır?

AccelStepper donanımsal bir timer kullanmaz. stepper.run() fonksiyonunu olabildiğince sık çağırmanız gerekir ve her çağrı, zamanı gelmişse en fazla bir adım üretir. Saniyede 2000 adımda her yarım milisaniyede bir adımın zamanı gelir. Wi-Fi meşgulken mqtt.loop() birkaç milisaniye engellerse veya bir yeniden bağlanma saniyelerce engellerse motor takılır ya da hareketin ortasında durur.

ESP32'nin iki çekirdeği vardır. Arduino'nun loop() fonksiyonu çekirdek 1'de, Wi-Fi yığını ise esas olarak çekirdek 0'da çalışır. Sketch, düşük öncelikle çekirdek 0'a sabitlenmiş ve run() çağırmaktan başka bir şey yapmayan bir FreeRTOS görevi oluşturur; loop() ise MQTT'yi yönetir. Mutex kullanmayan bir tasarım işi basit tutar: MQTT tarafı "bekleyen" istekleri volatile değişkenlere yazar ve motor görevi bunları alır. Bu desene daha derin bir bakış için MQTT ile ESP32 FreeRTOS görevleri yazısına bakın.

Eksiksiz ESP32 Step Motor MQTT Sketch'i

#include <WiFi.h>
#include <PubSubClient.h>
#include <AccelStepper.h>
#include <ArduinoJson.h>

const char* WIFI_SSID     = "YOUR_WIFI";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";
const char* MQTT_HOST     = "broker.connectmq.com";
const uint16_t MQTT_PORT  = 1883;
const char* DEVICE_ID     = "stepper-a19c44";
const String BASE = String("connectmq/demo/") + DEVICE_ID;

const int STEP_PIN = 25, DIR_PIN = 26, EN_PIN = 27;
const long SOFT_MIN = 0, SOFT_MAX = 32000;          // adım cinsinden hareket limitleri

AccelStepper stepper(AccelStepper::DRIVER, STEP_PIN, DIR_PIN);
WiFiClient net;
PubSubClient mqtt(net);

// MQTT tarafından motor görevine istekler
volatile bool reqMove = false, reqStop = false, reqZero = false;
volatile bool reqEnable = false, reqDisable = false;
volatile long reqTarget = 0;
volatile float reqMaxSpeed = 1000, reqAccel = 500;
volatile bool reqSpeed = true;

// Raporlama için motor görevinden anlık görüntü
volatile long curPos = 0, curTarget = 0;
volatile bool moving = false;
long moveStart = 0;
unsigned long lastReport = 0, lastAttempt = 0;
bool wasMoving = false;

void motorTask(void*) {
  for (;;) {
    if (reqSpeed)   { stepper.setMaxSpeed(reqMaxSpeed); stepper.setAcceleration(reqAccel); reqSpeed = false; }
    if (reqEnable)  { stepper.enableOutputs(); reqEnable = false; }
    if (reqMove)    { stepper.moveTo(reqTarget); reqMove = false; }
    if (reqStop)    { stepper.stop(); reqStop = false; }          // yavaşlar
    if (reqZero)    { stepper.setCurrentPosition(0); reqZero = false; }
    if (reqDisable) { stepper.stop(); stepper.setCurrentPosition(stepper.currentPosition()); stepper.disableOutputs(); reqDisable = false; }

    stepper.run();
    curPos = stepper.currentPosition();
    curTarget = stepper.targetPosition();
    moving = stepper.distanceToGo() != 0;
    if (!moving) vTaskDelay(1);                        // boştayken işlemciyi bırak
  }
}

void publishProgress(bool force) {
  if (!force && millis() - lastReport < 250) return;
  lastReport = millis();
  long total = labs(curTarget - moveStart);
  int pct = total == 0 ? 100 : (int)(100 * labs(curPos - moveStart) / total);
  char buf[128];
  snprintf(buf, sizeof(buf), "{\"pos\":%ld,\"target\":%ld,\"pct\":%d,\"moving\":%s}",
           curPos, curTarget, constrain(pct, 0, 100), moving ? "true" : "false");
  mqtt.publish((BASE + "/stepper/progress").c_str(), buf, true);
}

void requestMove(long target) {
  target = constrain(target, SOFT_MIN, SOFT_MAX);
  moveStart = curPos;
  reqTarget = target;
  reqEnable = true;
  reqMove = true;
}

void onMessage(char* topic, byte* payload, unsigned int length) {
  JsonDocument doc;
  if (deserializeJson(doc, payload, length)) return;
  const char* cmd = doc["cmd"] | "";

  if (!strcmp(cmd, "moveTo") && doc["pos"].is<long>())        requestMove(doc["pos"].as<long>());
  else if (!strcmp(cmd, "move") && doc["steps"].is<long>())   requestMove(curPos + doc["steps"].as<long>());
  else if (!strcmp(cmd, "stop"))                              reqStop = true;
  else if (!strcmp(cmd, "zero") && !moving)                   reqZero = true;
  else if (!strcmp(cmd, "disable"))                           reqDisable = true;
  else if (!strcmp(cmd, "speed")) {
    reqMaxSpeed = constrain(doc["max"] | 1000.0f, 50.0f, 4000.0f);
    reqAccel = constrain(doc["accel"] | 500.0f, 50.0f, 10000.0f);
    reqSpeed = true;
  } else return;
  Serial.printf("cmd=%s\n", cmd);
}

bool connectMqtt() {
  String status = BASE + "/status";
  if (!mqtt.connect(DEVICE_ID, nullptr, nullptr, status.c_str(), 1, true, "offline")) {
    Serial.printf("MQTT failed, state=%d\n", mqtt.state());
    return false;
  }
  mqtt.publish(status.c_str(), "online", true);
  mqtt.subscribe((BASE + "/stepper/cmd").c_str(), 1);
  publishProgress(true);
  return true;
}

void setup() {
  Serial.begin(115200);
  stepper.setEnablePin(EN_PIN);
  stepper.setPinsInverted(false, false, true);        // EN active-low
  stepper.disableOutputs();
  disableCore0WDT();                                  // motor görevi hareketler sırasında çekirdek 0'ı meşgul tutar
  xTaskCreatePinnedToCore(motorTask, "motor", 4096, nullptr, 1, nullptr, 0);

  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
  mqtt.setServer(MQTT_HOST, MQTT_PORT);
  mqtt.setCallback(onMessage);
  mqtt.setSocketTimeout(5);
}

void loop() {
  if (WiFi.status() == WL_CONNECTED) {
    if (!mqtt.connected()) {
      if (millis() - lastAttempt > 5000) { lastAttempt = millis(); connectMqtt(); }
    } else {
      mqtt.loop();
      if (moving) { publishProgress(false); wasMoving = true; }
      else if (wasMoving) { publishProgress(true); wasMoving = false; }   // son rapor
    }
  }
  delay(2);
}

Dikkat edilmeye değer birkaç ayrıntı var. Motor görevi yalnızca boştayken vTaskDelay(1) ile işlemciyi bırakır; bu yüzden bir hareket sırasında çekirdek 0'da tam hızda çalışır; öncelik 1'de olduğu için daha yüksek öncelikte çalışan Wi-Fi görevlerinin işlerini yapmasına yine izin verir. Meşgul görev uzun hareketler sırasında çekirdek 0'ın idle görevini aç bıraktığı için disableCore0WDT() o çekirdek için idle görev watchdog kontrolünü kapatır; bu olmadan birkaç saniye süren hareketlerde görev watchdog uyarıları görürsünüz. Yazılımsal limitler her hedefi sınırlar; böylece yanlış yazılmış bir "pos":320000 bir taşıyıcıyı şaseye çarptıramaz. Ve "moving":false içeren son ilerleme raporu her zaman gönderilir; bu da uygulamalara temiz bir "hareket tamamlandı" sinyali verir.

Bir Hareket Çalıştırın ve İlerlemeyi İzleyin

mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-a19c44 -v -t "connectmq/demo/stepper-a19c44/#"
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-a19c44 -t "connectmq/demo/stepper-a19c44/stepper/cmd" -m '{"cmd":"speed","max":1600,"accel":1200}'
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-a19c44 -t "connectmq/demo/stepper-a19c44/stepper/cmd" -m '{"cmd":"moveTo","pos":6400}'

Abone, hareket tamamlanana kadar saniyede dört kez ilerleme yazdırır:

connectmq/demo/stepper-a19c44/stepper/progress {"pos":312,"target":6400,"pct":4,"moving":true}
connectmq/demo/stepper-a19c44/stepper/progress {"pos":2101,"target":6400,"pct":32,"moving":true}
connectmq/demo/stepper-a19c44/stepper/progress {"pos":6400,"target":6400,"pct":100,"moving":false}

Hareketin ortasında {"cmd":"stop"} gönderin; motor aniden durmak yerine yapılandırılmış ivmeyi kullanarak yumuşakça yavaşlar, bu da kayışları ve kaplinleri korur. Saniyede dört raporluk hız, sizi ücretsiz herkese açık MQTT broker'da client başına izin verilen saniyede 10 mesajın rahatça altında tutar.

Referanslama (Homing) ve Güvenlik Kontrol Listesi

Açık döngülü konum, referans noktası kadar iyidir. Açılıştan sonra ESP32 taşıyıcının nerede olduğunu bilmez; bu yüzden bildirilen konum, motor nerede bulunuyorsa orada 0'dan başlar.

  1. Bir limit anahtarı ekleyin ve bir referanslama rutini uygulayın: anahtara doğru yavaşça ilerleyin, tetiklendiğinde durun, ardından zero gönderin.
  2. Production firmware'inde referanslanana kadar mutlak hareketleri reddedin ve ilerleme JSON'unda bir homed bayrağı yayınlayın.
  3. Referanslamadan sonra bile yazılımsal limitleri mekanik hareket aralığının içinde tutun.
  4. Eksenin tutma torkuna ihtiyacı yoksa boştayken çıkışları devre dışı bırakın; güç tasarrufu sağlar ve sürücü ile motoru serin tutar.
  5. Birine zarar verebilecek her şey için kopan bağlantıyı bir durma koşulu olarak ele alın. Last Will'i, komutların gelmesi durursa hareketi durduran yerel mantıkla birleştirin.
  6. Acil durdurmalar için asla yalnızca MQTT'ye güvenmeyin. Motor gücünü kesen donanımsal bir acil stop, kabul edilebilir tek güvenlik cihazıdır.

Sorun Giderme

  • Motor uğulduyor ama dönmüyor. Bobin çiftleri yanlış bağlanmış veya ivme yük için çok yüksek. Çiftleri bir multimetreyle kontrol edin ve accel değerini yarıya indirin.
  • Motor dönüyor ama yüksek hızlarda adım kaçırıyor. Besleme gerilimini sürücü limitleri içinde artırın, akım limitini ayarlayın veya max değerini düşürün.
  • MQTT mesajları geldiğinde takılma. Motor kendi görevi yerine loop() içinde çalışıyor ya da görev ağır işlerle aynı çekirdeğe sabitlenmiş.
  • Sürücü çok ısınıyor. Akım limiti çok yüksek; bir soğutucu ekleyin ve akımı düşürün.
  • Birçok hareketten sonra konum kayıyor. Kilitlenmelerden kaynaklanan adım kayıpları; geri bildirim olmadığı için periyodik olarak referanslayın.

Production: Kimlik Bilgileri, TLS ve İzleme

Hareket cihazları özel kimlik bilgilerini ve şifrelemeyi hak eder. ConnectMQ portalında bir broker oluşturun, üretilen kullanıcı adını, parolayı ve client ID'yi kullanın ve 8883 portunda WiFiClientSecure'a geçin; SSL/TLS üzerinden ESP32 MQTT rehberi sertifika kurulumunu kapsar. ConnectMQ gibi barındırılan bir MQTT broker, hızları ayarlarken stepper/progress topic'ini izleyebileceğiniz canlı bir topic gezgini ve sürücü sıcaklığı gibi sayısal telemetriyi kendi topic'inde yayınlarsanız ona yönlendirebileceğiniz eşik uyarı kuralları da sunar. Daha basit aktüatörler için aynı komut ve durum deseni MQTT üzerinden ESP32 servo kontrolünde de yer alır; bu ilk ESP32 projenizse başlangıç noktası ESP32 IoT eğitimidir.

ConnectMQ ile Başlayın

app.connectmq.com adresinde ücretsiz bir Serverless broker oluşturun, kredi kartı gerekmez. Bir dakikada TLS kimlik bilgilerini, hareket komutları göndermek için tarayıcı içi bir client'ı ve motorunuzun ilerlemesinin canlı görünümünü elde edersiniz.

Sık Sorulan Sorular

ESP32 MQTT mesajları aldığında step motorum neden takılıyor?

AccelStepper, run() fonksiyonunun çok sık çağrılmasını gerektirir. loop() fonksiyonunu ağ işlemleriyle paylaştığında her gecikme adım kaçırmaya neden olur. Motoru yukarıda gösterildiği gibi ayrı bir FreeRTOS görevinde çalıştırın veya timer tabanlı bir step motor kütüphanesi kullanın.

Bu sketch ile bir 28BYJ-48 motoru kontrol edebilir miyim?

Evet, bir ULN2003 kartıyla. AccelStepper nesnesini DRIVER yerine AccelStepper::HALF4WIRE ve dört pinle (IN1, IN3, IN2, IN4 sırasıyla) oluşturun; MQTT kısmı aynı kalır.

Bildirilen konum ne kadar doğru?

ESP32'nin gönderdiği tam adım sayısıdır. Motor hiç kilitlenmediği sürece gerçek konumla eşleşir; bir anahtara karşı referanslama birikmiş her hatayı ortadan kaldırır.

Motor komutları için hangi QoS'u kullanmalıyım?

Komutlar için QoS 1 kullanın. Mutlak hareketlerin (moveTo) iki kez alınması güvenlidir; yinelenen göreli bir hareket ise iki kez hareket ettirir. Bu yüzden teslimatın tekrarlanabileceği durumlarda mutlak konumları tercih edin.

İlgili yazılar

ESP32 NTP MQTT Zaman Damgası: Her Mesaja Doğru Zaman Ekleyin

ESP32 saatini NTP ile eşitleyin, ISO 8601 ve epoch milisaniye zaman damgalarını biçimlendirin ve bunları MQTT payload'larına ekleyin; böylece ölçümler geç yayınlansa bile gerçek alınma zamanlarını korur.

6 dk okuma

Tüm yazılar →

Özel MQTT broker’ınız birkaç tık uzağınızda

Hesabınızı oluşturun, broker kimlik bilgilerinizi alın ve ilk cihazınızı bağlayın — kurulacak, yamalanacak ya da ölçeklendirilecek sunucu yok.