ESP32 Tutorial 30/55 - Control Servo Over the web using MQTT using Adafruit IO Service | SunFounder's ESP32 IoT Leaning kit
In this tutorial, we will learn how to control the position of a servo motor using the ESP32 microcontroller and MQTT protocol over the web. By leveraging the Adafruit IO service, you will be able to position the servo at various angles such as 0°, 90°, or 180° remotely. This project demonstrates the capabilities of the ESP32, which includes built-in Wi-Fi and Bluetooth, making it a powerful tool for IoT applications.

In this project, we will set up an MQTT broker using Adafruit IO, create a dashboard to control the servo, and connect the ESP32 to it. The servo position will be adjustable via a slider on the dashboard, allowing for real-time control from any internet-enabled device (in video at 5:30).
Hardware Explained
The primary components of this project include the ESP32 microcontroller and the servo motor. The ESP32 is a versatile microcontroller with integrated Wi-Fi and Bluetooth capabilities, making it ideal for IoT applications. It communicates with the Adafruit IO service using the MQTT protocol, which is lightweight and efficient for transmitting messages over the internet.
The servo motor is a rotary actuator that allows for precise control of angular position. It operates by receiving a pulse-width modulation (PWM) signal that dictates its position. In this project, we will connect the servo to one of the digital pins on the ESP32, allowing us to control its angle remotely.
Datasheet Details
| Manufacturer | Parallax |
|---|---|
| Part number | SG90 |
| Logic/IO voltage | 3.3 V - 5 V |
| Supply voltage | 4.8 V - 6.0 V |
| Output current (per channel) | 1 A max |
| PWM frequency guidance | 50 Hz |
| Input logic thresholds | 0.3 V - 0.7 V |
| Voltage drop / RDS(on) / saturation | 0.2 V max |
| Thermal limits | Operating temperature: -10°C to 60°C |
| Package | Plastic case |
| Notes / variants | Mini servo, 180° rotation |
- Ensure proper voltage supply to the servo (4.8 V - 6.0 V).
- Use a common ground between the ESP32 and servo.
- Monitor the PWM signal to avoid exceeding the servo's limits.
- Securely connect the servo to avoid disconnections during operation.
- Update the Adafruit MQTT library to ensure compatibility.
MQTT Diagrams
Wiring Instructions

To wire the servo motor to the ESP32, start by connecting the ground wire of the servo to the ground pin on the ESP32. Next, connect the power wire (usually red) of the servo to the 5V pin on the ESP32. Finally, connect the signal wire (often yellow or white) to digital pin 25 on the ESP32. Ensure that the connections are secure to prevent any disconnections during operation.
If you are using a battery to power the ESP32, make sure that the battery voltage is within the acceptable range for both the ESP32 and the servo. Additionally, double-check that the wiring matches the pin definitions used in your code to avoid any issues (in video at 12:45).
Code Examples & Walkthrough
In the provided code, we first include the necessary libraries for the ESP32 and MQTT. We define the servo object and specify the pin it is connected to with const int servoPin = 25;. The default angle is also set with const int defaultServoAngle = 90;, which will be the initial position when the ESP32 boots up.
Servo myServo;
const int servoPin = 25;
const int defaultServoAngle = 90;
int servoAngle = defaultServoAngle;
This snippet initializes the servo on pin 25 and sets its default angle to 90°. The variable servoAngle will be updated based on the messages received from the MQTT broker.
In the setup() function, we connect to Wi-Fi and set up the MQTT client. The credentials for Adafruit IO are defined here, including the username and key:
#define AIO_USERNAME "robojax"
#define AIO_KEY "aio_xmIW58uNNsjJCSOqzZ9QoHyq29wu"
This section establishes the connection to the Adafruit IO service. Make sure to replace these values with your own Adafruit IO credentials when implementing the code.
Finally, the main loop ensures that the connection to the MQTT server remains active and processes incoming messages. The servo position is updated based on the received angle:
mqtt.processPackets(500);
int pulseWidth = map(servoAngle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
This code maps the servo angle to the corresponding pulse width and sends it to the servo motor. The processPackets() function allows the ESP32 to handle incoming MQTT messages, ensuring the servo reacts to commands sent via the Adafruit IO dashboard.
Demonstration / What to Expect
Once everything is set up, you should be able to control the servo from the Adafruit IO dashboard using the slider you created. As you move the slider, the servo will adjust its angle in real-time. Ensure that your ESP32 is connected to Wi-Fi, and the MQTT connection is stable. If the servo does not respond, check the wiring and the power supply to the servo (in video at 20:15).
Be aware of the range limits for the servo; sending a value outside of 0° to 180° may cause it to behave unexpectedly. The code includes checks to prevent such occurrences by clamping the angle within this range.
Video Timestamps
- 00:00 Start
- 1:54 Project introduction
- 2:52 Introduction to MQTT
- 6:50 Adafruit IO setup
- 9:54 Wiring of servo
- 11:07 Code explained
- 18:59 Selecting ESP32 board and COM port
- 22:10 Project demonstration
/***********************************************************************
This is Arduino sketch for ESP32 to control Servo motor using MQTT service of Adafruit
www.Robojax.com
Written By Ahamd Shamshiri
on Feb 2nd, 2024
Watch video instruction for this code on YouTube https://youtu.be/T4DhWNg2Rb8
Adafruit MQTT Library ESP32 Adafruit IO SSL/TLS example
this code can be downloaded from https://robojax.com/RJT671
/// ref: https://www.electronicwings.com/esp32/esp32-mqtt-client
*/
#include <ESP32Servo.h>
// Define the servo and the pin it is connected to
Servo myServo;
const int servoPin = 25;
const int defaultServoAngle = 90;
int servoAngle =defaultServoAngle;
// Define the minimum and maximum pulse widths for the servo
const int minPulseWidth = 500; // 0.5 ms
const int maxPulseWidth = 2500; // 2.5 ms
#include <WiFi.h>
#include "WiFiClientSecure.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
/************************* WiFi Access Point *********************************/
#define WLAN_SSID "Barqasaa"
#define WLAN_PASS "wan9&Jang~5"
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER "io.adafruit.com"
// Using port 8883 for MQTTS
#define AIO_SERVERPORT 8883
// Adafruit IO Account Configuration
// (to obtain these values, visit https://io.adafruit.com and click on Active Key)
// #define AIO_USERNAME "YOUR_ADAFRUIT_IO_USERNAME"
// #define AIO_KEY "YOUR_ADAFRUIT_IO_KEY"
#define AIO_USERNAME "robojax"
#define AIO_KEY "aio_xmIW58uNNsjJCSOqzZ9QoHyq29wu"
/************ Global State (you don't need to change this!) ******************/
// WiFiFlientSecure for SSL/TLS support
WiFiClientSecure client;
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
// io.adafruit.com root CA
const char* adafruitio_root_ca = \
"-----BEGIN CERTIFICATE-----\n"
"MIIEjTCCA3WgAwIBAgIQDQd4KhM/xvmlcpbhMf/ReTANBgkqhkiG9w0BAQsFADBh\n"
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
"d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH\n"
"MjAeFw0xNzExMDIxMjIzMzdaFw0yNzExMDIxMjIzMzdaMGAxCzAJBgNVBAYTAlVT\n"
"MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j\n"
"b20xHzAdBgNVBAMTFkdlb1RydXN0IFRMUyBSU0EgQ0EgRzEwggEiMA0GCSqGSIb3\n"
"DQEBAQUAA4IBDwAwggEKAoIBAQC+F+jsvikKy/65LWEx/TMkCDIuWegh1Ngwvm4Q\n"
"yISgP7oU5d79eoySG3vOhC3w/3jEMuipoH1fBtp7m0tTpsYbAhch4XA7rfuD6whU\n"
"gajeErLVxoiWMPkC/DnUvbgi74BJmdBiuGHQSd7LwsuXpTEGG9fYXcbTVN5SATYq\n"
"DfbexbYxTMwVJWoVb6lrBEgM3gBBqiiAiy800xu1Nq07JdCIQkBsNpFtZbIZhsDS\n"
"fzlGWP4wEmBQ3O67c+ZXkFr2DcrXBEtHam80Gp2SNhou2U5U7UesDL/xgLK6/0d7\n"
"6TnEVMSUVJkZ8VeZr+IUIlvoLrtjLbqugb0T3OYXW+CQU0kBAgMBAAGjggFAMIIB\n"
"PDAdBgNVHQ4EFgQUlE/UXYvkpOKmgP792PkA76O+AlcwHwYDVR0jBBgwFoAUTiJU\n"
"IBiV5uNu5g/6+rkS7QYXjzkwDgYDVR0PAQH/BAQDAgGGMB0GA1UdJQQWMBQGCCsG\n"
"AQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEAMDQGCCsGAQUFBwEB\n"
"BCgwJjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuZGlnaWNlcnQuY29tMEIGA1Ud\n"
"HwQ7MDkwN6A1oDOGMWh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEds\n"
"b2JhbFJvb3RHMi5jcmwwPQYDVR0gBDYwNDAyBgRVHSAAMCowKAYIKwYBBQUHAgEW\n"
"HGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwDQYJKoZIhvcNAQELBQADggEB\n"
"AIIcBDqC6cWpyGUSXAjjAcYwsK4iiGF7KweG97i1RJz1kwZhRoo6orU1JtBYnjzB\n"
"c4+/sXmnHJk3mlPyL1xuIAt9sMeC7+vreRIF5wFBC0MCN5sbHwhNN1JzKbifNeP5\n"
"ozpZdQFmkCo+neBiKR6HqIA+LMTMCMMuv2khGGuPHmtDze4GmEGZtYLyF8EQpa5Y\n"
"jPuV6k2Cr/N3XxFpT3hRpt/3usU/Zb9wfKPtWpoznZ4/44c1p9rzFcZYrWkj3A+7\n"
"TNBJE0GmP2fhXhP1D/XVfIW/h0yCJGEiV9Glm/uGOa3DXHlmbAcxSyCRraG+ZBkA\n"
"7h4SeM6Y8l/7MBRpPCz6l8Y=\n"
"-----END CERTIFICATE-----\n";
/****************************** Feeds ***************************************/
// Setup a feed called 'test' for publishing and 'test2' for subscription.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
Adafruit_MQTT_Subscribe SERVO = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/servo-angle-1");
/*************************** Sketch Code ************************************/
void setup() {
// Attach the servo to the specified pin and set its pulse width range
myServo.attach(servoPin, minPulseWidth, maxPulseWidth);
// Set the PWM frequency for the servo
myServo.setPeriodHertz(50); // Standard 50Hz servo
Serial.begin(115200);
delay(10);
Serial.println(F("Adafruit IO MQTTS (SSL/TLS) Example"));
// Connect to WiFi access point.
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);
delay(1000);
WiFi.begin(WLAN_SSID, WLAN_PASS);
delay(2000);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Set Adafruit IO's root CA
client.setCACert(adafruitio_root_ca);
// register callback for feed
SERVO.setCallback(servoCallback);
// Setup MQTT subscription for time feed.
mqtt.subscribe(&SERVO);
}
// uint32_t x=0;
void loop() {
// Ensure the connection to the MQTT server is alive (this will make the first
// connection and automatically reconnect when disconnected). See the MQTT_connect
// function definition further below.
MQTT_connect();
Serial.print("Angle: ");
Serial.println(servoAngle);
// wait 0.5 seconds for subscription messages
mqtt.processPackets(500);
//from lesson 17
int pulseWidth = map(servoAngle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);
delay(15);
// wait a couple seconds to avoid rate limit
//delay(2000);
}
void servoCallback(char* message, uint16_t len) {
char messageBuffer[40];
snprintf(messageBuffer, sizeof(messageBuffer), "Servo status is :: %s, len :: %u", message, len);
Serial.println(messageBuffer);
Serial.println(message);
String inString = message;//sotre the message to String
servoAngle = inString.toInt();//convert the message to Integer
if(servoAngle >180 || servoAngle < 0)
{
servoAngle =0;
}
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
int8_t ret;
// Stop if already connected.
if (mqtt.connected()) {
return;
}
Serial.print("Connecting to MQTT... ");
uint8_t retries = 3;
while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000); // wait 5 seconds
retries--;
if (retries == 0) {
// basically die and wait for WDT to reset me
while (1)
;
}
}
Serial.println("MQTT Connected!");
}
Common Course Links
Common Course Files
|||您可能需要的东西
-
全球速卖通从AliExpress购买SG90伺服电机180或360。s.click.aliexpress.com
资源与参考
-
文档ESP32教程 17/55- SunFunder伺服电机文档docs.sunfounder.com
-
外部SG90 servo on Amazon USAamzn.to
文件📁
其他文件
-
SG90 Seroo 电机数据表
robojax-servo-SG90_datasheet.pdf0.12 MB