Search Code

ESP32 튜토리얼 30/55 - Adafruit IO 서비스를 사용하여 MQTT를 통해 웹에서 서보 제어하기 | SunFounder의 ESP32 IoT 학습 키트

ESP32 튜토리얼 30/55 - Adafruit IO 서비스를 사용하여 MQTT를 통해 웹에서 서보 제어하기 | SunFounder의 ESP32 IoT 학습 키트

이 튜토리얼에서는 ESP32 마이크로컨트롤러와 MQTT 프로토콜을 사용하여 웹을 통해 서보 모터의 위치를 제어하는 방법을 배웁니다. Adafruit IO 서비스를 활용하면 0°, 90°, 180°와 같은 다양한 각도로 서보를 원격으로 위치시킬 수 있습니다. 이 프로젝트는 내장 Wi-Fi와 Bluetooth를 갖춘 ESP32의 성능을 보여주며, IoT 애플리케이션을 위한 강력한 도구입니다.

ESP32-30_MQTT_diagram-0

이 프로젝트에서는 Adafruit IO를 사용하여 MQTT 브로커를 설정하고, 서보를 제어할 대시보드를 만들고, ESP32를 연결합니다. 서보 위치는 대시보드의 슬라이더를 통해 조정할 수 있어 인터넷에 연결된 모든 기기에서 실시간으로 제어할 수 있습니다(비디오 5:30 참조).

하드웨어 설명

이 프로젝트의 주요 구성 요소는 ESP32 마이크로컨트롤러와 서보 모터입니다. ESP32는 통합 Wi-Fi와 Bluetooth 기능을 갖춘 다재다능한 마이크로컨트롤러로, IoT 애플리케이션에 이상적입니다. MQTT 프로토콜을 사용하여 Adafruit IO 서비스와 통신하며, 이 프로토콜은 인터넷을 통해 메시지를 전송하는 데 가볍고 효율적입니다.

서보 모터는 각도 위치를 정밀하게 제어할 수 있는 회전 액추에이터입니다. 위치를 지시하는 펄스 폭 변조(PWM) 신호를 수신하여 작동합니다. 이 프로젝트에서는 서보를 ESP32의 디지털 핀 중 하나에 연결하여 각도를 원격으로 제어할 수 있게 합니다.

데이터시트 세부 정보

제조업체 Parallax
부품 번호 SG90
로직/IO 전압 3.3 V - 5 V
공급 전압 4.8 V - 6.0 V
출력 전류(채널당) 최대 1 A
PWM 주파수 권장 사항 50 Hz
입력 로직 임계값 0.3 V - 0.7 V
전압 강하 / RDS(on) / 포화 최대 0.2 V
열 제한 작동 온도: -10°C ~ 60°C
패키지 플라스틱 케이스
참고 사항 / 변형 미니 서보, 180° 회전

 

  • 서보에 적절한 전압(4.8 V - 6.0 V)을 공급하세요.
  • ESP32와 서보 사이에 공통 접지를 사용하세요.
  • 서보의 한계를 초과하지 않도록 PWM 신호를 모니터링하세요.
  • 작동 중 분리를 방지하기 위해 서보를 안전하게 연결하세요.
  • 호환성을 보장하기 위해 Adafruit MQTT 라이브러리를 업데이트하세요.

MQTT 다이어그램

ESP32-30_MQTT_diagram-2
ESP32-30_MQTT_diagram
ESP32-28_dht_temperature-sensor-main

배선 지침

ESP32-17-Sevo_motor-wiring

서보 모터를 ESP32에 배선하려면 먼저 서보의 접지선을 ESP32의 접지 핀에 연결하세요. 다음으로 서보의 전원선(보통 빨간색)을 ESP32의 5V 핀에 연결하세요. 마지막으로 신호선(보통 노란색 또는 흰색)을 ESP32의 디지털 핀 25에 연결하세요. 작동 중 분리를 방지하기 위해 연결이 안전한지 확인하세요.

배터리를 사용하여 ESP32에 전원을 공급하는 경우 배터리 전압이 ESP32와 서보 모두에 허용 가능한 범위 내에 있는지 확인하세요. 또한 배선이 코드에서 사용된 핀 정의와 일치하는지 다시 확인하여 문제를 방지하세요(비디오 12:45 참조).

코드 예제 및 설명

제공된 코드에서는 먼저 ESP32 및 MQTT에 필요한 라이브러리를 포함합니다. 서보 객체를 정의하고 const int servoPin = 25;로 연결된 핀을 지정합니다. 기본 각도도 const int defaultServoAngle = 90;로 설정되며, 이는 ESP32가 부팅될 때의 초기 위치가 됩니다.


Servo myServo;
const int servoPin = 25;
const int defaultServoAngle = 90;
int servoAngle = defaultServoAngle;

이 스니펫은 핀 25에서 서보를 초기화하고 기본 각도를 90°로 설정합니다. servoAngle 변수는 MQTT 브로커에서 수신된 메시지에 따라 업데이트됩니다.

setup() 함수에서는 Wi-Fi에 연결하고 MQTT 클라이언트를 설정합니다. Adafruit IO의 자격 증명은 여기에 정의되며, 사용자 이름과 키가 포함됩니다:


#define AIO_USERNAME "robojax"
#define AIO_KEY "aio_xmIW58uNNsjJCSOqzZ9QoHyq29wu"

이 섹션은 Adafruit IO 서비스에 대한 연결을 설정합니다. 코드를 구현할 때 이러한 값을 자신의 Adafruit IO 자격 증명으로 반드시 교체하세요.

마지막으로 메인 루프는 MQTT 서버에 대한 연결이 활성 상태로 유지되고 수신 메시지를 처리하도록 보장합니다. 서보 위치는 수신된 각도에 따라 업데이트됩니다:


mqtt.processPackets(500);
int pulseWidth = map(servoAngle, 0, 180, minPulseWidth, maxPulseWidth);
myServo.writeMicroseconds(pulseWidth);

이 코드는 서보 각도를 해당 펄스 폭으로 매핑하여 서보 모터로 전송합니다. processPackets() 함수는 ESP32가 수신된 MQTT 메시지를 처리할 수 있게 하여, Adafruit IO 대시보드를 통해 전송된 명령에 서보가 반응하도록 보장합니다.

시연 / 기대 효과

모든 것이 설정되면, 생성한 슬라이더를 사용하여 Adafruit IO 대시보드에서 서보를 제어할 수 있어야 합니다. 슬라이더를 움직이면 서보가 실시간으로 각도를 조정합니다. ESP32가 Wi-Fi에 연결되어 있고 MQTT 연결이 안정적인지 확인하세요. 서보가 반응하지 않으면 배선과 서보 전원 공급 장치를 확인하십시오(비디오 20:15 참조).

서보의 범위 제한에 유의하십시오. 0°에서 180° 범위를 벗어난 값을 보내면 예기치 않게 동작할 수 있습니다. 코드에는 각도를 이 범위 내로 제한하여 이러한 상황을 방지하는 검사가 포함되어 있습니다.

비디오 타임스탬프

  • 00:00 시작
  • 1:54 프로젝트 소개
  • 2:52 MQTT 소개
  • 6:50 Adafruit IO 설정
  • 9:54 서보 배선
  • 11:07 코드 설명
  • 18:59 ESP32 보드 및 COM 포트 선택
  • 22:10 프로젝트 시연

이미지

ESP32-17-Sevo_motor-schematic
ESP32-17-Sevo_motor-schematic
ESP32-17-Sevo_motor-wiring
ESP32-17-Sevo_motor-wiring
ESP32-28_dht_temperature-sensor-main
ESP32-28_dht_temperature-sensor-main
ESP32-30_MQTT_diagram
ESP32-30_MQTT_diagram
ESP32-30_MQTT_diagram-0
ESP32-30_MQTT_diagram-0
ESP32-30_MQTT_diagram-2
ESP32-30_MQTT_diagram-2
831-ESP32 Tutorial 30/55- ESP32 to control Servo motor using MQTT service of Adafruit
언어: C++
/***********************************************************************
 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!");
}

필요할 수 있는 것들

자원 및 참고자료

파일📁

다른 파일들