Bir ESP32 servo MQTT projesi, ucuz bir hobi servosunu panjurlar, vanalar, kamera pan başlıkları veya evcil hayvan besleyicileri için uzaktan kontrol edilen bir aktüatöre dönüştürür. Bu eğitimde bir servoyu MQTT açı komutlarıyla hareket ettirecek, ani sıçramalar yerine yumuşakça hızlandıracak, mekanik limitleri firmware'de uygulayacak ve herhangi bir dashboard'un okuyabileceği konum geri bildirimi yayınlayacaksınız. Her adımı hesap açmadan broker.connectmq.com üzerinde deneyebilirsiniz.
Ne Yapacaksınız?
ESP32 bir topic'te komutları dinler ve ilerlemeyi başka bir topic'te bildirir. Komutlar yalın bir açı veya hız içeren küçük bir JSON nesnesi olabilir:
| Topic | Yön | Retained | Örnek payload |
|---|---|---|---|
connectmq/demo/<id>/servo/set |
Uygulamadan ESP32'ye | Hayır | 90 veya {"angle":45,"speed":60} |
connectmq/demo/<id>/servo/position |
ESP32'den uygulamalara | Evet | {"angle":72,"target":45,"moving":true} |
connectmq/demo/<id>/status |
ESP32'den uygulamalara | Evet | online / offline |
Baştan dürüst bir kısıtlama: standart bir hobi servosu gerçek mil konumunu bildirmez. Burada yayınlanan geri bildirim, firmware'in komut verdiği ve servo hedefe doğru ilerledikçe güncellenen açıdır. Bu, dashboard'lar ve bir komutun kabul edildiğini doğrulamak için yeterlidir. Gerçekten ölçülmüş konuma ihtiyacınız varsa geri bildirim kablolu bir servoya veya harici bir enkodere ihtiyacınız vardır; bu da ayrı bir projedir.
Donanım ve Güç
- ESP32 geliştirme kartı.
- SG90 (mikro, plastik dişli) veya MG996R (standart boy, metal dişli) gibi bir hobi servosu.
- Mikro servodan büyük her şey için, en az servonun kilitlenme (stall) akımına uygun ayrı bir 5 V kaynak.
- Servo beslemesine paralel, servoya yakın 470 µF ile 1000 µF arası bir elektrolitik kondansatör.
| Servo kablosu | Bağlantı |
|---|---|
| Kahverengi / siyah (GND) | Kaynak GND'si ve ESP32 GND'si |
| Kırmızı (V+) | 5 V kaynak |
| Turuncu / sarı (sinyal) | ESP32 GPIO 18 |
Ortak toprak isteğe bağlı değildir: o olmadan sinyalin bir referansı olmaz ve servo rastgele seğirir. Bir MG996R'yi ESP32'nin 5 V pininden beslemek, servo projelerindeki brownout resetlerinin en yaygın nedenidir; çünkü servo her harekete başladığında büyük bir akım sıçraması çeker. ESP32'den gelen 3,3 V sinyal neredeyse tüm hobi servoları tarafından kabul edilir.
Kütüphaneler
esp32 kart paketini ve Arduino Library Manager'dan şu kütüphaneleri kurun:
- MQTT için Nick O'Leary'nin PubSubClient kütüphanesi.
- Servoları ESP32'nin LEDC PWM donanımı üzerinden süren, Kevin Harrington ve John K. Bennett'in ESP32Servo kütüphanesi.
- JSON komut biçimini ayrıştırmak için Benoit Blanchon'un ArduinoJson kütüphanesi (sürüm 7).
Standart Arduino Servo kütüphanesi ESP32'yi desteklemez, bu yüzden doğru seçim ESP32Servo'dur. Bu kartta MQTT'ye yeni misiniz? Kart kurulumunu ve ilk yayını kapsayan ESP32 IoT eğitimi ile başlayın.
ESP32 Servo MQTT Sketch'i
#include <WiFi.h>
#include <PubSubClient.h>
#include <ESP32Servo.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 = "servo-4c81d2"; // her cihaz için benzersiz
const String BASE = String("connectmq/demo/") + DEVICE_ID;
const int SERVO_PIN = 18;
const int MIN_ANGLE = 10; // SİZİN mekanizmanızın mekanik limitleri
const int MAX_ANGLE = 170;
const int MIN_US = 500; // 0 derece için darbe genişliği
const int MAX_US = 2400; // 180 derece için darbe genişliği
Servo servo;
WiFiClient net;
PubSubClient mqtt(net);
float currentAngle = 90;
int targetAngle = 90;
float speedDegPerSec = 90; // varsayılan hızlanma hızı
unsigned long lastStep = 0, lastReport = 0, lastAttempt = 0;
bool wasMoving = false;
void publishPosition(bool force) {
bool moving = (int)round(currentAngle) != targetAngle;
if (!force && millis() - lastReport < 250) return;
lastReport = millis();
char buf[96];
snprintf(buf, sizeof(buf), "{\"angle\":%d,\"target\":%d,\"moving\":%s}",
(int)round(currentAngle), targetAngle, moving ? "true" : "false");
String topic = BASE + "/servo/position";
mqtt.publish(topic.c_str(), buf, true);
}
void onMessage(char* topic, byte* payload, unsigned int length) {
JsonDocument doc;
int angle;
if (deserializeJson(doc, payload, length) == DeserializationError::Ok && doc.is<JsonObject>()) {
if (!doc["angle"].is<int>()) return;
angle = doc["angle"];
if (doc["speed"].is<float>()) speedDegPerSec = constrain(doc["speed"].as<float>(), 5.0f, 600.0f);
} else if (doc.is<int>()) {
angle = doc.as<int>(); // "90" gibi yalın sayı
} else {
return;
}
targetAngle = constrain(angle, MIN_ANGLE, MAX_ANGLE);
if (!servo.attached()) servo.attach(SERVO_PIN, MIN_US, MAX_US);
Serial.printf("Target %d deg at %.0f deg/s\n", targetAngle, speedDegPerSec);
publishPosition(true);
}
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 + "/servo/set").c_str(), 1);
publishPosition(true);
return true;
}
void setup() {
Serial.begin(115200);
ESP32PWM::allocateTimer(0);
servo.setPeriodHertz(50); // standart servo çerçevesi
servo.attach(SERVO_PIN, MIN_US, MAX_US);
servo.write((int)currentAngle);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
mqtt.setServer(MQTT_HOST, MQTT_PORT);
mqtt.setCallback(onMessage);
mqtt.setSocketTimeout(5);
}
void stepServo() {
unsigned long now = millis();
float dt = (now - lastStep) / 1000.0f;
lastStep = now;
float diff = targetAngle - currentAngle;
if (fabs(diff) < 0.5f) {
currentAngle = targetAngle;
if (wasMoving) {
servo.write(targetAngle);
publishPosition(true); // son konum raporu
wasMoving = false;
}
return;
}
float stepSize = speedDegPerSec * dt;
currentAngle += constrain(diff, -stepSize, stepSize);
servo.write((int)round(currentAngle));
wasMoving = true;
publishPosition(false); // seyreltilmiş ilerleme
}
void loop() {
stepServo();
if (WiFi.status() != WL_CONNECTED) return;
if (!mqtt.connected()) {
if (millis() - lastAttempt > 5000) { lastAttempt = millis(); connectMqtt(); }
return;
}
mqtt.loop();
}
Neden sıçramak yerine hızlandırma?
servo.write(170) doğrudan çağrıldığında servo tam hızda yeni açıya çarpar. Bir vanayı veya kapağı hareket ettiren bir mekanizmada bu, plastik dişlileri zorlar ve kaynaktan büyük bir akım sıçraması çeker. stepServo() fonksiyonu, geçen süreye göre her döngüde komut verilen açıyı biraz ilerletir; böylece loop() ne kadar hızlı çalışırsa çalışsın hız sabit kalır. Saniyede 60 derecelik bir hız kontrollü görünür; 300 ise çevik hissettirir.
Limitler neden firmware'de?
MIN_ANGLE ve MAX_ANGLE, servonun sürdüğü şeyin fiziksel hareket aralığıyla eşleşmelidir. Bir uygulama 0 gönderirse ve mekanizmanız 8 derecede sıkışıyorsa, servo kilitlenir, ısınır ve bir şey kırılana kadar kilitlenme akımını çeker. Cihazda sınırlama yapmak, dashboard'daki bir yazım hatasının donanıma asla zarar veremeyeceği anlamına gelir. Her MQTT komutunu güvenilmeyen bir girdi olarak ele alın.
Komut Gönderin ve Geri Bildirimi İzleyin
Cihaz önekine abone olun:
mosquitto_sub -h broker.connectmq.com -p 1883 -i watch-4c81d2 -v -t "connectmq/demo/servo-4c81d2/#"
Ardından servoyu hareket ettirin:
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-4c81d2 -t "connectmq/demo/servo-4c81d2/servo/set" -m 150
mosquitto_pub -h broker.connectmq.com -p 1883 -i cmd-4c81d2 -t "connectmq/demo/servo-4c81d2/servo/set" -m '{"angle":30,"speed":40}'
Servo hareket ederken konum akışını göreceksiniz; akış "moving":false ile biter:
connectmq/demo/servo-4c81d2/servo/position {"angle":90,"target":150,"moving":true}
connectmq/demo/servo-4c81d2/servo/position {"angle":113,"target":150,"moving":true}
connectmq/demo/servo-4c81d2/servo/position {"angle":150,"target":150,"moving":false}
İlerleme raporları saniyede dörde sınırlandırılmıştır. Bu, sizi herkese açık broker'ın client başına saniyede 10 mesaj limitinin rahatça altında tutar ve akıcı bir dashboard göstergesi için fazlasıyla yeterlidir. Ücretsiz herkese açık MQTT broker'ın herkes tarafından okunabildiğini unutmayın; burası bir test tezgâhıdır, ön kapınızı açan bir servonun yeri değildir.
Güvenmeden Önce Servoyu Kalibre Edin
Farklı üreticilerin, hatta aynı modelin farklı partilerinin servoları darbe genişliğini açıya biraz farklı eşler. Etrafına bir braket kurmadan önce kalibrasyona beş dakika ayırın:
- Kolun serbestçe dönebilmesi için tüm mekanizmayı sökün.
- Geçici olarak
MIN_ANGLEdeğerini 0,MAX_ANGLEdeğerini 180 yapın, ardından0gönderin ve dinleyin. Servo vızıldıyorsa veya uçta itmeye devam ediyorsaMIN_USdeğerini 50 artırın ve sessizce durana kadar tekrar deneyin. 180için tekrarlayın; uç konum sessiz olana kadarMAX_USdeğerini düşürün.90gönderin ve kolun "merkez" olmasını beklediğiniz yeri gösterip göstermediğini kontrol edin. Göstermiyorsa yazılımda telafi etmek yerine kolu dişli mile yeniden oturtun.- Mekanizmayı takın,
{"angle":20,"speed":15}gibi düşük bir hızla her uca doğru yavaşça ilerleyin ve sıkışmaya başladığı yerleri not edin.MIN_ANGLEveMAX_ANGLEdeğerlerini bu noktaların birkaç derece içine ayarlayın.
Son değerleri sabitlerin yanına bir yorum olarak yazın. Bir yıl sonra bozulan bir servoyu değiştirdiğinizde hangi sayıları yeniden kontrol edeceğinizi bilirsiniz. Kalibrasyon, geri bildirim topic'inin ölçüyormuş gibi yapmak yerine komut verilen açıyı dürüstçe bildirmesinin de nedenidir: sayı "firmware'in servoya gitmesini söylediği yer" anlamına gelir ve bu sayıyı gerçekle eşleştiren şey kalibrasyondur.
Sorun Giderme
- Servo dururken titriyor. Genellikle güç gürültüsü. Büyük kondansatörü ekleyin, servo kablolarını kısaltın ve sinyal kablosunu motor kablolarından uzak tutun. Servo yük tutmuyorsa, darbeleri tamamen durdurmak için hedefe ulaştığında
servo.detach()çağırabilirsiniz; sketch bir sonraki komutta yeniden bağlar. - Servo hareket ettiğinde ESP32 yeniden başlıyor. Brownout. Servo için ortak topraklı ayrı bir kaynak kullanın.
- Hareket aralığı yalnızca yaklaşık 90 derece. Servo daha geniş bir darbe aralığı bekliyor.
MIN_USveMAX_USdeğerlerini küçük adımlarla ayarlayın; pek çok servo kabaca 500 ile 2500 mikrosaniye kullanır, ancak servonun gerçek uç noktalarının ötesine geçmek onu vızıldatır ve zorlar. - Servo hareket ediyor ama geri bildirim hiç gelmiyor. Yayınların PubSubClient'ın varsayılan buffer'ından büyük olmadığını ve
mqtt.loop()fonksiyonunun yeterince sık çalıştığını kontrol edin.loop()içindeki herhangi bir engelleyicidelay()hem hızlandırmayı hem de MQTT'yi bozar. - Komutlar yok sayılıyor. JSON bir tam sayı
angleiçermelidir."angle":"90"gibi string'ler bilerek reddedilir. - İki servo birbirini etkiliyor. Her birinin kendi pini olmalıdır;
ESP32ServoPWM kanallarını otomatik olarak ayırır, ancak kullanmayı planladığınız timer'lar içinallocateTimerçağırın.
Demodan Gerçek Bir Dağıtıma
Servo çalıştığında onu herkese açık alandan çıkarın. ConnectMQ portalında bir broker oluşturun, üretilen kullanıcı adını, parolayı ve client ID'yi kopyalayın ve WiFiClientSecure kullanarak 8883 portunda TLS üzerinden bağlanın. ESP32 MQTT SSL rehberi sertifika kurulumunu adım adım gösterir.
Hareket eden her şey için erişilebilirlik önemlidir. ConnectMQ gibi yönetilen bir MQTT broker, her cihaza kendi kimlik bilgilerini verir ve hızları ayarlarken portalın canlı topic gezgininde servo/position izlemenizi sağlar. Aynı komut ve durum deseni doğrudan ESP32 ve MQTT ile röle kontrolüne ve daha fazla tork veya hassas konumlandırmalı sürekli dönüş gerektiğinde bir sonraki adım olan MQTT ile sürülen step motorlara taşınır.
ConnectMQ ile Başlayın
app.connectmq.com adresinde kaydolun ve ücretsiz bir Serverless broker oluşturun, kredi kartı gerekmez. Hemen TLS kimlik bilgilerini, servo komutları göndermek için tarayıcı içi bir MQTT client'ını ve konum geri bildirimini canlı izleyebileceğiniz bir dashboard'u elde edersiniz.
Sık Sorulan Sorular
Bir hobi servosu gerçek konumunu MQTT üzerinden bildirir mi?
Hayır. Standart bir servonun konum çıkışı yoktur, bu yüzden ESP32 komut verdiği açıyı bildirir. Ölçülmüş konum için geri bildirimli bir servo kullanın veya ESP32'nin ADC'si ile okunan bir enkoder ya da potansiyometre ekleyin.
Hangi ESP32 pinleri bir servoyu sürebilir?
PWM, LEDC çevre biriminden geldiği için çıkış verebilen her GPIO çalışır. Yalnızca giriş olan 34 ile 39 arası pinlerden ve 0, 2, 12 ve 15 gibi strapping pinlerinden kaçının.
Tek bir ESP32 MQTT üzerinden kaç servo kontrol edebilir?
Orijinal ESP32'de 16 LEDC kanalı bulunur (S3 gibi daha yeni varyantlarda daha az), bu yüzden prensipte çok sayıda servo mümkündür; asıl sınır güç kaynağı ve kablolamadır. Her servo için bir topic kullanın; örneğin servo/1/set ve servo/2/set.
Servo komutları QoS 1 kullanmalı mı?
Evet, QoS 1 makul bir varsayılandır. Mutlak bir açı komutu idempotenttir, bu yüzden yinelenen bir teslimat yalnızca aynı hedefi yeniden ayarlar.



