Search Code

ESP32 บทเรียน 30/55 - ควบคุมเซอร์โวผ่านเว็บโดยใช้ MQTT ผ่านบริการ Adafruit IO | ชุดเรียนรู้ IoT ESP32 ของ SunFounder

ESP32 บทเรียน 30/55 - ควบคุมเซอร์โวผ่านเว็บโดยใช้ MQTT ผ่านบริการ Adafruit IO | ชุดเรียนรู้ IoT ESP32 ของ SunFounder

ในบทช่วยสอนนี้ เราจะเรียนรู้วิธีการควบคุมตำแหน่งของเซอร์โวมอเตอร์โดยใช้ไมโครคอนโทรลเลอร์ ESP32 และโปรโตคอล MQTT ผ่านเว็บ โดยใช้บริการ Adafruit IO คุณจะสามารถกำหนดตำแหน่งเซอร์โวที่มุมต่างๆ เช่น 0°, 90° หรือ 180° จากระยะไกลได้ โปรเจกต์นี้แสดงให้เห็นถึงความสามารถของ ESP32 ซึ่งมี Wi-Fi และ Bluetooth ในตัว ทำให้เป็นเครื่องมือที่ทรงพลังสำหรับแอปพลิเคชัน IoT

ESP32-30_MQTT_diagram-0

ในโปรเจกต์นี้ เราจะตั้งค่า MQTT broker โดยใช้ Adafruit IO สร้างแดชบอร์ดเพื่อควบคุมเซอร์โว และเชื่อมต่อ ESP32 เข้ากับมัน ตำแหน่งเซอร์โวจะสามารถปรับได้ผ่านแถบเลื่อนบนแดชบอร์ด ทำให้สามารถควบคุมแบบเรียลไทม์จากอุปกรณ์ใดๆ ที่เชื่อมต่ออินเทอร์เน็ตได้ (ในวิดีโอที่ 5:30)

อธิบายฮาร์ดแวร์

ส่วนประกอบหลักของโปรเจกต์นี้ประกอบด้วยไมโครคอนโทรลเลอร์ ESP32 และเซอร์โวมอเตอร์ ESP32 เป็นไมโครคอนโทรลเลอร์ที่อเนกประสงค์พร้อมความสามารถ Wi-Fi และ Bluetooth ในตัว ทำให้เหมาะสำหรับแอปพลิเคชัน IoT มันสื่อสารกับบริการ Adafruit IO โดยใช้โปรโตคอล MQTT ซึ่งมีน้ำหนักเบาและมีประสิทธิภาพสำหรับการส่งข้อความผ่านอินเทอร์เน็ต

เซอร์โวมอเตอร์เป็นแอคชูเอเตอร์แบบหมุนที่ช่วยให้ควบคุมตำแหน่งเชิงมุมได้อย่างแม่นยำ มันทำงานโดยรับสัญญาณพัลส์ไวด์มอดูเลชัน (PWM) ซึ่งกำหนดตำแหน่งของมัน ในโปรเจกต์นี้ เราจะเชื่อมต่อเซอร์โวเข้ากับหนึ่งในพินดิจิทัลบน ESP32 ทำให้เราสามารถควบคุมมุมของมันจากระยะไกลได้

รายละเอียดจาก Datasheet

ผู้ผลิต 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 จากนั้นเชื่อมต่อสายไฟ (โดยปกติเป็นสีแดง) ของเซอร์โวเข้ากับพิน 5V บน ESP32 สุดท้าย เชื่อมต่อสายสัญญาณ (มักเป็นสีเหลืองหรือสีขาว) เข้ากับพินดิจิทัล 25 บน ESP32 ตรวจสอบให้แน่ใจว่าการเชื่อมต่อแน่นหนาเพื่อป้องกันการหลุดระหว่างการทำงาน

หากคุณใช้แบตเตอรี่ในการจ่ายไฟให้ 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 broker

ในฟังก์ชัน 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!");
}

สิ่งที่คุณอาจต้องการ

แหล่งข้อมูลและเอกสารอ้างอิง

ไฟล์📁

ไฟล์อื่น ๆ