ESP32 Веб-сервер: Управление шаговым двигателем (HTML-форма)
В этом уроке вы узнаете, как создать веб-сервер на ESP32 для удалённого управления шаговым двигателем. Веб-сервер отображает веб-страницу с HTML-формой, которая позволяет выбрать направление и количество шагов для вращения двигателя.
Оглавление
`Управление шаговым двигателем с помощью HTML-формы (минимальная настройка)`_
Управление шаговым двигателем с помощью WebSockets (HTML, CSS, JavaScript)
На изображении ниже вы можете увидеть три проекта веб-серверов, которые мы создадим (номер 3 описан в этой публикации).
Это обучающий урок, в котором вы узнаете больше о создании веб-страниц и взаимодействии между ESP32 и клиентом. Мы покажем вам, как пошагово создать веб-страницу с HTML и отправить результаты формы на ESP32 через HTTP POST для управления шаговым двигателем.
Позже вы добавите немного CSS для стилизации веб-страницы и улучшения её внешнего вида.
Наконец, мы покажем вам, как использовать WebSockets для двунаправленной связи между сервером и клиентом. Это позволит нам отображать на веб-интерфейсе, вращается двигатель или остановлен. В этом разделе будет добавлен JavaScript для обработки WebSocket-соединения и несколько интересных анимаций на веб-странице.
Следующие статьи могут быть полезны для понимания концепций, рассмотренных в этом уроке:
Необходимые условия
Прежде чем приступить к уроку, убедитесь, что выполнены следующие предварительные условия.
1) Необходимые компоненты
Для выполнения этого урока вам понадобятся следующие компоненты:
ESP32 (рекомендуем прочитать Лучшие платы разработки ESP32)
Источник питания 5В
2) Arduino IDE и дополнение для плат ESP32
Мы будем программировать ESP32 с помощью Arduino IDE. Поэтому у вас должно быть установлено дополнение для ESP32. Следуйте следующему уроку, если вы ещё этого не сделали:
Если вы хотите использовать VS Code с расширением PlatformIO, следуйте следующему уроку, чтобы узнать, как программировать ESP32:
3) Плагин загрузки файловой системы
Для загрузки файлов HTML, CSS и JavaScript, необходимых для этого проекта, в файловую систему ESP32 (LittleFS) мы будем использовать плагин для Arduino IDE: LittleFS Filesystem uploader. Следуйте следующему уроку, чтобы установить плагин загрузки файловой системы, если вы ещё этого не сделали:
Если вы используете VS Code с расширением PlatformIO, прочитайте следующий урок, чтобы узнать, как загружать файлы в файловую систему:
4) Библиотеки
Для создания этого проекта вам необходимо установить следующие библиотеки:
ESPAsyncWebServer от ESP32Async
AsyncTCP от ESP32Async
Вы можете установить эти библиотеки через менеджер библиотек Arduino. Откройте менеджер библиотек, нажав на значок библиотеки на левой боковой панели.
Найдите ESPAsyncWebServer и установите ESPAsyncWebServer by ESP32Async.
Затем установите библиотеку AsyncTCP. Найдите AsyncTCP и установите AsyncTCP by ESP32Async.
5) Схема подключения
Следующая схема показывает соединения между шаговым двигателем и ESP32.
Примечание: Вы должны питать драйвер двигателя от внешнего источника питания 5В.
Драйвер двигателя |
ESP32 |
|---|---|
IN1 |
GPIO 19 |
IN2 |
GPIO 18 |
IN3 |
GPIO 5 |
IN4 |
GPIO 17 |
Управление шаговым двигателем с помощью HTML-формы
В этом разделе вы узнаете, как создать простую HTML-форму для управления шаговым двигателем.
Вот как это работает:
На веб-странице вы можете выбрать, хотите ли вы, чтобы двигатель вращался по часовой стрелке (Clockwise) или против часовой стрелки (Counterclockwise). Это радиокнопки. Радиокнопки обычно отображаются как маленькие кружки, которые заполняются или выделяются при выборе. В данной группе одновременно можно выбрать только одну радиокнопку.
Есть поле ввода типа number, в которое пользователь может ввести число — в данном случае количество шагов.
Наконец, кнопка GO! типа submit отправляет данные на сервер через HTTP POST-запрос.
HTML-форма и поля ввода
В этом разделе мы рассмотрим HTML-код для создания формы.
В HTML тег <form> используется для создания HTML-формы для сбора пользовательского ввода. Затем пользовательский ввод отправляется на сервер (ESP32 или ESP8266) для обработки. На основе значений, полученных из формы, ваша плата ESP может выполнять различные действия — в данном случае вращать двигатель на определённое количество шагов.
Вот HTML-код, который мы будем использовать для этого проекта.
<!DOCTYPE html>
<html>
<head>
<title>Stepper Motor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Stepper Motor Control</h1>
<form action="/" method="POST">
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" name="steps">
<input type="submit" value="GO!">
</form>
</body>
</html>
HTML-форма содержит различные элементы формы. Все элементы формы заключены внутри тега <form>. Он содержит элементы управления <input> (радиокнопки и числовое поле ввода) и метки для этих элементов управления (<label>).
Кроме того, тег <form> должен включать атрибут action, который указывает, что вы хотите сделать при отправке формы. В нашем случае мы хотим отправить данные на сервер (ESP32/ESP8266), когда пользователь нажимает кнопку submit. Атрибут method определяет HTTP-метод (GET или POST), используемый при отправке данных формы.
<form action="/" method="POST">
POST используется для отправки данных на сервер для создания/обновления ресурса. Данные, отправленные на сервер методом POST, хранятся в теле HTTP-запроса.
Радиокнопки
Радиокнопка определяется следующим образом:
<input type="radio">
Для нашего проекта нам нужны две радиокнопки, и одновременно может быть выбрана только одна. Поэтому мы можем создать группу радиокнопок. Для этого радиокнопки должны иметь одинаковое имя (значение атрибута name — в данном случае direction).
<input type="radio" name="direction">
Наконец, нам также нужен атрибут value, который указывает уникальное значение для каждой радиокнопки. Это значение не видно пользователю, но оно отправляется на сервер при нажатии на кнопку submit для определения, какая кнопка была выбрана.
В нашем примере мы создали одну радиокнопку со значением CW (для выбора вращения по часовой стрелке) и другую CCW (для выбора вращения против часовой стрелки).
<input type="radio" name="direction" value="CW">
<input type="radio" name="direction" value="CCW">
Наконец, если вы хотите, чтобы одна радиокнопка была выбрана по умолчанию, вы можете добавить ключевое слово checked. В нашем примере направление по часовой стрелке выбрано по умолчанию.
<input type="radio" name="direction" value="CW" checked>
Итак, вот как выглядят радиокнопки и соответствующие метки:
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
Поле ввода
Наконец, нам также нужно поле ввода, в которое пользователь вводит количество шагов — поле ввода типа number. Атрибут name позволяет определить, в какое поле ввода пользователь ввёл данные.
<input type="number" name="steps">
Кнопка отправки
Для завершения формы нам нужна кнопка отправки. Кнопка отправки — это input типа submit. При нажатии этой кнопки данные формы отправляются на сервер (платы ESP32 или ESP8266). Атрибут value определяет текст, отображаемый на кнопке.
<input type="submit" value="GO!">
Например, если вы выберете направление по часовой стрелке и введёте 2000 шагов, клиент отправит следующий запрос на ESP:
POST /
Host: localhost
direction=CW&steps=2000
ESP получает этот запрос и может извлечь направление и количество шагов из тела запроса.
Код
Теперь, когда вы знаете, как создать HTML-форму, давайте рассмотрим код Arduino.
HTML-текст можно сохранить в HTML-файле в файловой системе ESP32 (LittleFS) или в переменной в вашем скетче Arduino.
Поскольку HTML-текст для этого примера относительно прост и у нас нет CSS или JavaScript файлов, мы сохраним HTML-текст как переменную (index_html).
Вот код для создания веб-сервера (вставьте свои сетевые учётные данные, и код будет работать сразу).
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/stepper-motor-esp32-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>
// Stepper Motor Settings
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Search for parameters in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";
// Variables to save values from HTML form
String direction;
String steps;
// Variable to detect whether a new request occurred
bool newRequest = false;
// HTML to build the web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Stepper Motor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Stepper Motor Control</h1>
<form action="/" method="POST">
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" name="steps">
<input type="submit" value="GO!">
</form>
</body>
</html>
)rawliteral";
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
initWiFi();
myStepper.setSpeed(5);
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html);
});
// Handle request (form)
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
int params = request->params();
for(int i=0;i<params;i++){
const AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
// HTTP POST input1 value (direction)
if (p->name() == PARAM_INPUT_1) {
direction = p->value().c_str();
Serial.print("Direction set to: ");
Serial.println(direction);
}
// HTTP POST input2 value (steps)
if (p->name() == PARAM_INPUT_2) {
steps = p->value().c_str();
Serial.print("Number of steps set to: ");
Serial.println(steps);
}
}
}
request->send(200, "text/html", index_html);
newRequest = true;
});
server.begin();
}
void loop() {
// Check if there was a new request and move the stepper accordingly
if (newRequest){
if (direction == "CW"){
// Spin the stepper clockwise direction
myStepper.step(steps.toInt());
}
else{
// Spin the stepper counterclockwise direction
myStepper.step(-steps.toInt());
}
newRequest = false;
}
}
Как работает код
Продолжайте чтение, чтобы узнать, как работает код, или перейдите к разделу демонстрации.
Подключение библиотек
Сначала подключите необходимые библиотеки. WiFi, AsyncTCP и ESPAsyncWebServer для создания веб-сервера и библиотеку Stepper для управления шаговым двигателем.
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <Stepper.h>
Пины шагового двигателя и количество шагов на оборот
Определите количество шагов на оборот вашего шагового двигателя — в нашем случае это 2048:
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution
Определите пины ввода двигателя. В этом примере мы подключаемся к GPIO 19, 18, 5 и 17, но вы можете использовать любые другие подходящие GPIO.
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Инициализируйте экземпляр библиотеки stepper с именем myStepper. Передайте в качестве аргументов количество шагов на оборот и пины ввода. В случае шагового двигателя 28BYJ-48 порядок пинов: IN1, IN3, IN2, IN4 — для вашего двигателя он может отличаться.
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);
Сетевые учётные данные
Вставьте свои сетевые учётные данные в следующие строки.
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
Создайте объект AsyncWebServer с именем server на порту 80.
AsyncWebServer server(80);
Инициализация переменных
Переменные PARAM_INPUT_1 и PARAM_INPUT_2 будут использоваться для поиска параметров в HTTP POST-запросе. Помните, что он содержит направление и количество шагов.
// Search for parameters in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";
Следующие переменные будут сохранять направление и количество шагов.
String direction;
String steps;
Переменная newRequest будет использоваться для проверки, произошёл ли новый запрос. Затем в loop() мы будем вращать двигатель при получении нового запроса — когда переменная newRequest равна true.
bool newRequest = false;
HTML-форма
Переменная index_html сохраняет HTML-текст для создания веб-страницы — мы ранее рассмотрели, как работает HTML для создания веб-страницы с формой.
// HTML to build the web page
const char index_html[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<title>Stepper Motor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<h1>Stepper Motor Control</h1>
<form action="/" method="POST">
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" name="steps">
<input type="submit" value="GO!">
</form>
</body>
</html>
)rawliteral";
initWiFi()
Функция initWiFi() инициализирует WiFi.
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
В этом примере ESP настроен как Wi-Fi станция (подключается к вашему роутеру). Если у вас нет роутера поблизости, вы можете настроить плату как точку доступа. Вы можете прочитать следующий урок, чтобы узнать, как настроить плату как точку доступа:
setup()
В setup() инициализируйте Serial Monitor.
Serial.begin(115200);
Вызовите функцию initWiFi() для инициализации WiFi.
initWiFi();
И установите скорость шагового двигателя в оборотах в минуту.
myStepper.setSpeed(5);
Обработка запросов
Затем настройте обработку запросов веб-сервера. Когда вы получаете запрос по корневому (/) URL — это происходит, когда вы обращаетесь к IP-адресу ESP — отправьте HTML-текст для создания веб-страницы:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(200, "text/html", index_html);
});
Затем вам нужно обработать ситуацию, когда ESP получает POST-запрос с данными формы.
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
Сначала мы ищем параметры в HTTP POST-запросе:
int params = request->params();
for(int i=0;i<params;i++){
AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
Если один из параметров равен PARAM_INPUT_1, мы знаем, что его значение содержит направление двигателя. В этом случае мы получаем значение этого параметра и сохраняем его в переменной direction.
if (p->name() == PARAM_INPUT_1) {
direction = p->value().c_str();
Serial.print("Direction set to: ");
Serial.println(direction);
}
Мы следуем аналогичной процедуре для PARAM_INPUT_2, но сохраняем значение в переменной steps.
if (p->name() == PARAM_INPUT_2) {
steps = p->value().c_str();
Serial.print("Number of steps set to: ");
Serial.println(steps);
}
Наконец, мы отвечаем содержимым HTML-страницы — это перезагрузит страницу.
request->send(200, "text/html", index_html);
После этого мы устанавливаем переменную newRequest в true, чтобы двигатель вращался в loop().
newRequest = true;
loop()
Давайте рассмотрим секцию loop().
Если переменная newRequest равна true, мы проверяем направление вращения: CW или CCW. Если это CW, мы перемещаем двигатель на количество шагов, сохранённое в переменной steps, используя метод step() объекта myStepper.
Чтобы вращать двигатель против часовой стрелки, нужно просто передать количество шагов со знаком минус.
if (direction == "CW"){
// Spin the stepper clockwise direction
myStepper.step(steps.toInt());
}
else{
// Spin the stepper counterclockwise direction
myStepper.step(-steps.toInt());
}
После вращения двигателя установите переменную newRequest в false, чтобы можно было обнаруживать новые запросы.
newRequest = false;
Примечание: поскольку библиотека Stepper.h не является асинхронной, она не будет выполнять ничего другого, пока двигатель не прекратит вращение. Поэтому, если вы попытаетесь отправить новые запросы во время вращения двигателя, это не сработает. Мы создадим пример с использованием протокола WebSocket, который позволит нам отображать на веб-интерфейсе, вращается двигатель или нет — вы можете ознакомиться с этим уроком здесь.
Демонстрация
После ввода ваших сетевых учётных данных вы можете загрузить код на плату.
После загрузки откройте Serial Monitor на скорости 115200 бод и нажмите кнопку RESET на плате. Будет отображён IP-адрес ESP.
Откройте браузер в вашей локальной сети и введите IP-адрес ESP. Вы получите доступ к HTML-форме для управления шаговым двигателем.
Выберите направление и введите определённое количество шагов. Затем нажмите GO!. Шаговый двигатель начнёт вращаться.
Одновременно вы можете увидеть значения переменных direction и steps в Serial Monitor.
Стилизация формы с помощью CSS
В предыдущем разделе мы создали простую форму без какого-либо форматирования. Добавив немного CSS к вашему проекту, HTML-страница будет выглядеть намного лучше.
Когда ваш HTML также включает CSS, удобнее работать с отдельными файлами HTML и CSS (помимо файла скетча Arduino). Поэтому вместо написания HTML и CSS в скетче Arduino мы создадим отдельные файлы HTML и CSS.
Эти файлы затем будут загружены в файловую систему ESP32 (LittleFS) с помощью плагина LittleFS Filesystem uploader.
Организация файлов
Файлы, которые вы хотите загрузить в файловую систему ESP, должны быть помещены в папку с именем data внутри папки проекта. Мы переместим два файла в эту папку:
index.html для создания веб-страницы
style.css для стилизации веб-страницы
Вы должны сохранить файлы HTML, CSS и JavaScript внутри папки с именем data внутри папки скетча Arduino, как показано на предыдущей диаграмме. Мы загрузим эти файлы в файловую систему ESP32 (LittleFS).
Вы можете скачать все файлы проекта:
Обзор страницы
Чтобы лучше понять, как работает стилизация веб-страницы, давайте подробнее рассмотрим веб-страницу, которую мы создадим.
HTML-файл
Нам нужно внести некоторые изменения в HTML-файл, чтобы упростить форматирование с помощью CSS. Создайте файл с именем index.html и скопируйте в него следующее содержимое.
<!DOCTYPE html>
<html>
<head>
<title>Stepper Motor</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="style.css">
<link rel="icon" type="image/png" href="favicon.png">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous">
</head>
<body>
<div class="topnav">
<h1>Stepper Motor Control <i class="fas fa-cogs"></i></h1>
</div>
<div class="content">
<form action="/" method="POST">
<input type="radio" name="direction" value="CW" checked>
<label for="CW">Clockwise</label>
<input type="radio" name="direction" value="CCW">
<label for="CW">Counterclockwise</label><br><br><br>
<label for="steps">Number of steps:</label>
<input type="number" name="steps">
<input type="submit" value="GO!">
</form>
</div>
</body>
</html>
Чтобы использовать CSS-файл для стилизации HTML-страницы, вам нужно указать ссылку на таблицу стилей в вашем HTML-документе. Поэтому вам нужно добавить следующее между тегами <head> вашего документа:
<link rel="stylesheet" type="text/css" href="stylesheet.css">
Этот тег <link> сообщает HTML-файлу, что вы используете внешнюю таблицу стилей для форматирования внешнего вида страницы. Атрибут rel указывает характер внешнего файла. В данном случае это таблица стилей — CSS-файл — которая будет использоваться для изменения внешнего вида страницы.
Атрибут type установлен на «text/css», чтобы указать, что вы используете CSS-файл для стилей. Атрибут href указывает расположение файла; поскольку файл находится в той же папке, что и HTML-файл, вам нужно указать только имя файла. В противном случае вам нужно указать путь к файлу.
Теперь ваша таблица стилей подключена к HTML-документу.
Чтобы использовать иконки fontawesome на веб-странице, такие как шестерёнки, нам нужно добавить следующую строку.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
Мы создали тег <div> с классом topnav, чтобы упростить форматирование первого заголовка.
<div class="topnav">
<h1>Stepper Motor Control <i class="fas fa-cogs"></i></h1>
</div>
Затем мы включаем форму внутри тега <div> с классом content. Это упростит форматирование области, занимаемой формой.
<div class="content">
CSS-файл
Создайте файл с именем style.css со следующим содержимым для форматирования формы.
html {
font-family: Arial, Helvetica, sans-serif;
}
h1 {
font-size: 1.8rem;
color: white;
}
.topnav {
overflow: hidden;
background-color: #0A1128;
text-align: center;
}
body {
margin: 0;
}
.content {
padding: 20px;
max-width: max-content;
margin: 0 auto;
}
form{
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
input[type=number], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
input[type=submit] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: #034078;
border: none;
padding: 14px 20px;
text-align: center;
font-size: 20px;
border-radius: 4px;
transition-duration: 0.4s;
width: 100%;
color: white;
cursor: pointer;
}
input[type=submit]:hover {
background-color: #1282A2;
}
input[type="radio"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border-radius: 50%;
width: 16px;
height: 16px;
border: 2px solid #999;
transition: 0.2s all linear;
margin-right: 5px;
position: relative;
top: 4px;
}
input[type="radio"]:checked{
border: 6px solid #1282A2;
}
Селектор html включает стили, применяемые ко всей HTML-странице. В данном случае мы устанавливаем шрифт.
html {
font-family: Arial, Helvetica, sans-serif;
}
Селектор h1 включает стили для заголовка 1. В нашем случае заголовок 1 содержит текст «Stepper Motor Control». Здесь устанавливается размер шрифта и цвет текста.
h1 {
font-size: 1.8rem;
color: white;
}
Чтобы выбрать <div> с классом topnav, используйте точку (.) перед именем класса, вот так:
.topnav {
Установите цвет фона .topnav с помощью свойства background-color. Вы можете выбрать любой цвет фона. Мы используем #0A1128. Текст выровнен по центру. Кроме того, установите свойство overflow на hidden следующим образом:
.topnav {
overflow: hidden;
background-color: #0A1128;
text-align: center;
}
Довольно сложно объяснить, что делает свойство overflow. Лучший способ понять это — отрендерить вашу веб-страницу с этим свойством и без него, чтобы увидеть различия.
Отступ <body> — контейнера, включающего всю HTML-страницу — установлен в 0, чтобы он занимал всё пространство окна браузера.
body {
margin: 0;
}
Следующие строки стилизуют div content (который содержит форму): отступы и поля. Кроме того, устанавливается максимальная ширина равной максимальной ширине его содержимого (самой формы).
.content {
padding: 20px;
max-width: max-content;
margin: 0 auto;
}
Форма — это контейнер с закруглёнными углами (свойство border-radius) и светло-серым цветом фона (свойство background-color). Мы также добавляем некоторые отступы.
form{
border-radius: 5px;
background-color: #f2f2f2;
padding: 20px;
}
Затем нам нужно стилизовать каждый отдельный элемент формы. Чтобы выбрать числовое поле ввода, мы используем селектор input[type=number].
input[type=number], select {
width: 100%;
padding: 12px 20px;
margin: 8px 0;
display: inline-block;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
Примечание: селектор [attribute=value] выбирает элементы с указанным атрибутом и значением. В данном случае мы выбираем элементы input типа number.
Чтобы стилизовать кнопку отправки, используйте селектор input[type=submit].
input[type=submit] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background-color: #034078;
border: none;
padding: 14px 20px;
text-align: center;
font-size: 20px;
border-radius: 4px;
transition-duration: 0.4s;
width: 100%;
color: white;
cursor: pointer;
}
Чтобы кнопка меняла цвет при наведении мыши, вы можете использовать селектор :hover.
input[type=submit]:hover {
background-color: #1282A2;
}
Наконец, чтобы выбрать радиокнопки, используйте селектор input[type=»radio»].
input[type="radio"] {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
border-radius: 50%;
width: 16px;
height: 16px;
border: 2px solid #999;
transition: 0.2s all linear;
margin-right: 5px;
position: relative;
top: 4px;
}
Чтобы стилизовать выбранную радиокнопку, вы можете использовать селектор :checked.
input[type="radio"]:checked{
border: 6px solid #1282A2;
}
Элементы формы были стилизованы на основе примера, предоставленного веб-сайтом W3Schools. Если вы хотите лучше понять, как это работает, вы можете ознакомиться здесь.
Скетч Arduino
В этом проекте файлы HTML и CSS сохранены в файловой системе ESP32 (LittleFS). Поэтому нам нужно внести некоторые изменения в скетч.
/*
Rui Santos & Sara Santos - Random Nerd Tutorials
Complete project details at https://RandomNerdTutorials.com/stepper-motor-esp32-web-server/
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*/
#include <Arduino.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include "LittleFS.h"
#include <Arduino_JSON.h>
#include <Stepper.h>
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution
#define IN1 19
#define IN2 18
#define IN3 5
#define IN4 17
Stepper myStepper(stepsPerRevolution, IN1, IN3, IN2, IN4);
// Replace with your network credentials
const char* ssid = "REPLACE_WITH_YOUR_SSID";
const char* password = "REPLACE_WITH_YOUR_PASSWORD";
// Create AsyncWebServer object on port 80
AsyncWebServer server(80);
// Search for parameter in HTTP POST request
const char* PARAM_INPUT_1 = "direction";
const char* PARAM_INPUT_2 = "steps";
//Variables to save values from HTML form
String direction;
String steps;
bool newRequest = false;
// Initialize LittleFS
void initLittleFS() {
if (!LittleFS.begin(true)) {
Serial.println("An error has occurred while mounting LittleFS");
}
else {
Serial.println("LittleFS mounted successfully");
}
}
// Initialize WiFi
void initWiFi() {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to WiFi ..");
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
Serial.println(WiFi.localIP());
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
initWiFi();
initLittleFS();
myStepper.setSpeed(5);
// Web Server Root URL
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
server.serveStatic("/", LittleFS, "/");
server.on("/", HTTP_POST, [](AsyncWebServerRequest *request) {
int params = request->params();
for(int i=0;i<params;i++){
const AsyncWebParameter* p = request->getParam(i);
if(p->isPost()){
// HTTP POST input1 value
if (p->name() == PARAM_INPUT_1) {
direction = p->value().c_str();
Serial.print("Direction set to: ");
Serial.println(direction);
}
// HTTP POST input2 value
if (p->name() == PARAM_INPUT_2) {
steps = p->value().c_str();
Serial.print("Number of steps set to: ");
Serial.println(steps);
// Write file to save value
}
newRequest = true;
//Serial.printf("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
}
request->send(LittleFS, "/index.html", "text/html");
});
server.begin();
}
void loop() {
if (newRequest){
if (direction == "CW"){
myStepper.step(steps.toInt());
Serial.print("CW");
}
else{
myStepper.step(-steps.toInt());
}
newRequest = false;
}
}
Давайте рассмотрим изменения, которые нужно внести.
Во-первых, вам нужно подключить библиотеку LittleFS.h.
#include "LittleFS.h"
Затем вам нужно инициализировать LittleFS. Мы создали для этого функцию initLittleFS().
void initLittleFS() {
if (!LittleFS.begin(true)) {
Serial.println("An error has occurred while mounting LittleFS");
}
else {
Serial.println("LittleFSmounted successfully");
}
}
Затем вам нужно вызвать эту функцию в setup() перед инициализацией веб-сервера.
initLittleFS();
Затем, для обработки запросов, вам нужно указать, что ваш HTML-файл сохранён в LittleFS, следующим образом:
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
request->send(LittleFS, "/index.html", "text/html");
});
Когда HTML-файл загружается в вашем браузере, он делает запрос на CSS-файл. Это статический файл, сохранённый в той же директории (LittleFS). Поэтому мы можем просто добавить следующую строку для обслуживания статических файлов в директории при запросе по корневому URL. Это автоматически обслужит CSS-файл.
server.serveStatic("/", LittleFS, "/");
Загрузка кода и файлов
Перед загрузкой вы можете использовать следующую ссылку для:
Скачать все файлы проекта Arduino
После ввода ваших сетевых учётных данных сохраните код. Перейдите в Sketch > Show Sketch Folder и создайте папку с именем data.
Внутри этой папки вы должны сохранить файлы HTML и CSS.
Затем загрузите код на плату ESP32. Убедитесь, что выбрана правильная плата и COM-порт. Также убедитесь, что вы добавили свои сетевые учётные данные.
После загрузки кода вам нужно загрузить файлы. В Arduino IDE нажмите [Ctrl] + [Shift] + [P] на Windows или [Cmd] + [Shift] + [P] на MacOS, чтобы открыть палитру команд. Найдите команду Upload LittleFS to Pico/ESP8266/ESP32 и нажмите на неё.
Если у вас нет этой опции, значит вы не установили плагин загрузки файловой системы. Ознакомьтесь с этим уроком.
Важно: убедитесь, что Serial Monitor закрыт перед загрузкой в файловую систему. В противном случае загрузка не удастся.
Когда всё успешно загружено, откройте Serial Monitor на скорости 115200 бод. Нажмите кнопку EN/RST на ESP32, и он должен вывести IP-адрес ESP32.
Демонстрация
Откройте браузер в вашей локальной сети и вставьте IP-адрес ESP32. Вы получите доступ к HTML-форме для управления шаговым двигателем. Это работает аналогично примеру из предыдущего раздела, но с лучшим внешним видом.
Заключение
Этот урок уже довольно длинный. Поэтому третью часть этого урока мы включим в отдельную публикацию. В третьей части ESP32 и клиент взаимодействуют по протоколу WebSocket, и веб-страница показывает, вращается двигатель или остановлен. Мы также добавили анимацию с шестерёнками, вращающимися в том же направлении, что и двигатель.
Перейти к ЧАСТИ 3: ESP32 Веб-сервер: Управление шаговым двигателем (WebSocket).
Если вы хотите узнать больше о HTML, CSS, JavaScript и протоколах связи клиент-сервер для создания веб-серверов ESP32 и ESP8266 с нуля, обязательно ознакомьтесь с нашей электронной книгой:
Спасибо за чтение.
—
Источник: :doc:`Random Nerd Tutorials — ESP32 Web Server: Control Stepper Motor (HTML Form) <../stepper-motor-esp32-web-server/index>`