ESP32 튜토리얼 49/55 - Adafruit IoT를 사용하여 인터넷으로 DC 모터 제어하기 | SunFounder의 ESP32 키트
이 튜토리얼에서는 ESP32와 Adafruit IO MQTT 서비스를 사용하여 인터넷을 통해 DC 모터를 제어하는 방법을 살펴보겠습니다. DC 모터의 속도와 방향을 원격으로 조작할 수 있어 인터넷 연결이 가능한 어디서든 효율적으로 제어할 수 있습니다. 이 프로젝트는 내장 Wi-Fi를 갖춘 ESP32 마이크로컨트롤러의 기능을 보여주며, 사물인터넷(IoT) 애플리케이션에 이상적입니다.
Adafruit IO에 연결된 웹 인터페이스를 통해 모터를 시작, 정지하고 속도를 조절할 수 있는 시스템을 구현할 것입니다. 사용자는 모터 제어를 위한 특정 주제를 구독하고 그에 따라 매개변수를 조정할 수 있습니다. 과정을 더 잘 이해하려면 이 튜토리얼과 함께 제공되는 비디오(비디오 00:00)를 꼭 확인하세요.
하드웨어 설명
이 프로젝트에서는 시스템의 핵심인 ESP32 마이크로컨트롤러를 활용합니다. ESP32는 Wi-Fi 통신을 처리할 수 있어 IoT 애플리케이션에 완벽합니다. Adafruit IO 플랫폼에 연결되어 MQTT 프로토콜을 통해 메시지를 주고받을 수 있습니다.
또한 DC 모터 제어에 필수적인 L293D 모터 드라이버를 사용할 것입니다. L293D는 두 개의 DC 모터를 구동할 수 있으며 펄스 폭 변조(PWM)를 통해 방향과 속도를 모두 제어할 수 있습니다. 본질적으로 ESP32와 모터 사이의 인터페이스 역할을 하며, 모터에 필요한 더 높은 전류를 관리하면서 ESP32를 잠재적으로 손상을 줄 수 있는 역기전력 신호로부터 격리합니다.
데이터시트 세부 정보
| 제조업체 | 텍사스 인스트루먼트 |
|---|---|
| 부품 번호 | L293D |
| 로직/IO 전압 | 4.5 - 36 V |
| 공급 전압 | 4.5 - 36 V |
| 출력 전류(채널당) | 600 mA |
| 피크 전류(채널당) | 1.2 A |
| PWM 주파수 지침 | 10 kHz(일반) |
| 입력 로직 임계값 | 0.8 V(높음), 2.0 V(낮음) |
| 전압 강하 / RDS(on) / 포화 | 1.5 V 최대 |
| 열 제한 | 150 °C |
| 패키지 | DIP-16 |
| 참고 사항 / 변형 | 쿼드러플 고전류 하프-H 드라이버 |
- 연속 작동을 위해 적절한 방열판을 확보하세요.
- PWM을 사용하여 모터 속도를 효과적으로 제어하세요.
- 손상을 방지하기 위해 입력 전압 한계를 준수하세요.
- 모든 구성 요소 간의 올바른 접지 연결을 확인하세요.
- 역기전력에 주의하고 필요한 경우 다이오드를 사용하세요.
- 극성이 모터 방향에 영향을 줄 수 있으므로 배선을 다시 확인하세요.
- 전체 작동 전에 더 낮은 전압으로 테스트하세요.
- 장시간 사용 중 과열을 주시하세요.
- 기계식 스위치를 사용하는 경우 디바운싱을 확인하세요.
- ESP32가 모터 전류로 과부하되지 않도록 하세요.
배선 지침
전원 공급 장치를 연결하는 것으로 시작하세요. 외부 전원의 양극 단자를 L293D의 VCC 핀(핀 8)에 연결하고 접지를 GND 핀(핀 4)에 연결하세요. 필요한 경우 ESP32는 일반적으로 마이크로 USB 연결을 통해 별도로 전원을 공급받도록 하세요.
다음으로 모터를 L293D에 연결하세요. 모터의 한 단자는 출력 핀 3(L293D의 핀 2)에 연결하고 다른 단자는 출력 핀 6(L293D의 핀 7)에 연결해야 합니다. 제어 신호의 경우 ESP32의 핀 13을 입력 핀 2(L293D의 핀 1)에 연결하고 핀 14를 입력 핀 7(L293D의 핀 2)에 연결하세요. 활성화 핀(핀 1)도 드라이버를 활성화하기 위해 5V 공급 장치에 연결해야 합니다. 마지막으로 공통 기준을 위해 ESP32 접지가 L293D 접지에 연결되어 있는지 확인하세요.
코드 예제 및 설명
제공된 코드는 필요한 라이브러리를 초기화하고 Wi-Fi 및 MQTT 클라이언트를 설정합니다. 주요 식별자에는 motorSpeed, motorDirection, motorStart가 포함되며, Adafruit IO에서 수신된 명령에 따라 모터 작동을 관리합니다.
bool debug = false;
#define motor1A 13
#define motor2A 14
int motorSpeed = 0;
int motorDirection = 1;
int motorStart = 1;
이 발췌문에서 모터 핀과 속도, 방향, 모터의 시작/정지 상태를 제어하기 위한 초기 변수가 정의됩니다. 변수 motorSpeed는 Adafruit IO의 입력에 따라 조정됩니다.
void setup() {
Serial.begin(115200);
WiFi.begin(WLAN_SSID, WLAN_PASS);
delay(2000);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
}
설정 함수에서 직렬 통신이 시작되고 ESP32가 지정된 Wi-Fi 네트워크에 연결됩니다. 이 연결은 MQTT 통신을 활성화하는 데 중요합니다.
void loop() {
MQTT_connect();
mqtt.processPackets(500);
runMotor();
}
이 루프 함수는 MQTT 연결을 설정하고 수신된 최신 명령에 따라 모터를 제어하기 위해 들어오는 패킷을 처리합니다. runMotor() 함수는 현재 설정을 모터에 적용하기 위해 호출됩니다.
데모 / 기대 효과
설정이 완료되고 코드가 업로드되면 Adafruit IO 대시보드를 통해 모터를 제어할 수 있습니다. 슬라이더를 사용하여 모터 속도를 조정하고 토글 스위치로 방향을 변경할 수 있습니다. 모든 것이 올바르게 배선되었다면 모터는 이러한 명령에 실시간으로 응답하여 시스템의 낮은 지연 시간을 보여줍니다(비디오 00:00에서).
일반적인 문제로는 잘못된 배선으로 인한 모터 방향 반전이 있으므로, 모터가 예상대로 작동하지 않으면 연결을 다시 확인하십시오. 또한 MQTT 주제가 코드와 일치하도록 Adafruit IO에서 올바르게 설정되었는지 확인하십시오.
비디오 타임스탬프
- 00:00 시작
- 2:21 프로젝트 소개
- 4:20 DC 모터 제어 방법
- 6:39 L293D 모터 드라이버
- 11:42 MQTT란 무엇인가?
- 15:03 Adafruit IO 설정
- 19:17 배선 설명
- 22:42 코드 설명
- 35:28 프로젝트 시연
/***********************************************************************
This is Arduino sketch for ESP32 to DC Motor using MQTT service of Adafruit
Watch video instruction https://youtu.be/OUgyPXNYg3g
📚⬇️ Download and resource page https://robojax.com/RJT673
Written By Ahamd Shamshiri
on Feb 18, 2024
Adafruit MQTT Library ESP32 Adafruit IO SSL/TLS example
/// ref: https://www.electronicwings.com/esp32/esp32-mqtt-client
*/
bool debug = false;
#define motor1A 13
#define motor2A 14
// PWM settings
const int freq = 500; // PWM frequency: 500 Hz
const int resolution = 8; // PWM resolution: 8 bits
const int channelA = 0; // PWM channel for motor1A: 0
const int channelB = 1; // PWM channel for motor2A: 1
char* dir[]={"CCW", "CW"};
int motorSpeed =0;
int motorDirection =1;
int motorStart = 1;
int dutyCycle =0;
#include <WiFi.h>
#include "WiFiClientSecure.h"
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
/************************* WiFi Access Point *********************************/
#define WLAN_SSID "Book"
#define WLAN_PASS "88888888"
/************************* 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_jHpm60SEsWUdU5x472FViZjWzsY9"
/************ 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 MOTOR_SPEED = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/motor.speed");
Adafruit_MQTT_Subscribe MOTOR_DIRECTION = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/motor.direction");
Adafruit_MQTT_Subscribe MOTOR_START = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/motor.start");
/*************************** Sketch Code ************************************/
void setup() {
// Set up PWM
ledcSetup(channelA, freq, resolution);
ledcSetup(channelB, freq, resolution);
// Attach PWM channels to GPIO pins
ledcAttachPin(motor1A, channelA);
ledcAttachPin(motor2A, channelB);
Serial.begin(115200);
delay(10);
Serial.println(F("DC Motor over MQTT 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
MOTOR_SPEED.setCallback(MOTOR_SPEED_Callback);
// Setup MQTT subscription for time feed.
mqtt.subscribe(&MOTOR_SPEED);
// register callback for feed
MOTOR_DIRECTION.setCallback(MOTOR_DIRECTION_Callback);
// Setup MQTT subscription for time feed.
mqtt.subscribe(&MOTOR_DIRECTION);
// register callback for feed
MOTOR_START.setCallback(MOTOR_START_Callback);
// Setup MQTT subscription for time feed.
mqtt.subscribe(&MOTOR_START);
}
// 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("Speed: ");
// Serial.print (motorSpeed);
// Serial.print(" Dir: ");
// Serial.print (dir[motorDirection]);
// Serial.print(" Sart: ");
// Serial.println(motorStart);
// Serial.print("DutyCycle: ");
// Serial.println(dutyCycle);
// wait 0.5 seconds for subscription messages
mqtt.processPackets(500);
runMotor();//very important
// wait a couple seconds to avoid rate limit
//delay(2000);
}
void MOTOR_SPEED_Callback(char* message, uint16_t len) {
char messageBuffer[40];
//snprintf(messageBuffer, sizeof(messageBuffer), "Color status is :: %s, len :: %u", message, len);
//Serial.println(messageBuffer);
Serial.println(message);
String inString = message;//sotre the message to String
motorSpeed = inString.toInt();//convert the message to Integer
if(motorSpeed >100 || motorSpeed < 0)
{
motorSpeed = 0;
}
dutyCycle = map (motorSpeed, 0, 100, 0, 255);
}
void MOTOR_DIRECTION_Callback(char* message, uint16_t len) {
char messageBuffer[40];
//snprintf(messageBuffer, sizeof(messageBuffer), "Color status is :: %s, len :: %u", message, len);
//Serial.println(messageBuffer);
Serial.println(message);
String inString = message;//sotre the message to String
motorDirection = inString.toInt();//convert the message to Integer
}
void MOTOR_START_Callback(char* message, uint16_t len) {
char messageBuffer[40];
//snprintf(messageBuffer, sizeof(messageBuffer), "Color status is :: %s, len :: %u", message, len);
//Serial.println(messageBuffer);
Serial.println(message);
String inString = message;//sotre the message to String
motorStart = inString.toInt();//convert the message to Integer
}
void runMotor()
{
if(motorStart ==1)
{
if(debug)
{
Serial.print("Motor running:");
Serial.print(dir[motorDirection]);
Serial.print(" at ");
Serial.print(motorSpeed);
Serial.println("%");
}
if(motorDirection)
{
ledcWrite(channelA, dutyCycle);
ledcWrite(channelB, 0);
delay(50);
}else{
ledcWrite(channelA, 0);
ledcWrite(channelB, dutyCycle);
delay(50);
}
}else{
if(debug)
{
Serial.println("***Motor Stopped***");
}
ledcWrite(channelA, 0);
ledcWrite(channelB, 0);
}
}//runMotor() end
// 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
자원 및 참고자료
아직 자원이 없습니다.
파일📁
파일이 없습니다.