ESP32 Robot Arm – Điều khiển cánh tay robot qua Web IoT kèm code mẫu

Chào các bạn, trong dự án lần này, IoTZone sẽ hướng dẫn bạn về chủ đề ESP32 Robot Arm. Chúng ta sẽ tạo một cánh tay robot từ ESP32, có khả năng kết nối với WiFi và điều khiển chúng hoạt động thông qua trang Web dễ dàng.

Ngoài ra, bạn sẽ được hướng dẫn cách thiết kế trang Web cũng như cách kết nối và hoạt động của cánh tay robot. Nếu bạn đam mê về lĩnh vực Robotics hoặc điều khiển từ xa, tự động hóa thì đây là dự án lý tưởng, giúp bạn mở ra những khả năng sáng tạo mới cho nhiều ứng dụng khác nhau.

Cùng theo dõi nhé!

Thành phần

  • Mạch ESP32
  • Zero PCB
  • Female & Male Header Pins
  • Dây Jumper
  • Micro-USB Female Jack

Lắp ráp khung cánh tay robot

Bạn có thể tìm các khung ESP32 Robot Arm 3D đang có trên thị trường hiện nay và lắp ráp theo hướng dẫn để có mô hình mình muốn nhé!

Trên thị trường có khá nhiều mẫu mã và kích cỡ cánh ray robot khác nhau, nhưng nhìn chung thì chúng sẽ có một số thành phần chính như:

  • Động cơ Servo (Có thể là MG90s, MG995…)
  • Các mảnh lắp ghép 3D
  • Một số loại đai ốc và bu lông

Dưới đây là một hình ảnh mẫu về cánh tay robot đã lắp ráp xong từ các mảnh ghép 3D:

Mô hình 3D của esp32 robot arm

Kết nối phần cứng

Việc kết nối phần cứng chuẩn bị cho dự án ESP32 Robot Arm khá đơn giản, bạn chỉ cần kết nối các thiết bị Servo với nguồn điện và nối với ESP32.

Hiện tại, IoTZone đang dùng Micro-USB female connector hoạt động ở mức điện áp 5V để cung cấp đủ điện cho Servo hoạt động. Hack của Micro USB có thể kết nối với bất kỳ USB generic Adaptor nào.

Chúng ta sử dụng cùng 1 nguồn điện bên ngoài để cấp điện cho ESP32, trong đó +ve được kết nối với IN và -ve được kết nối với GND trên ESP32:

Kết nối phần cứng cho dự án IoT ESP32 Robot Arm

Mỗi một chân tín hiệu điều khiển của từng Servo được kết nối với mỗi chân tín hiệu điều khiển của ESP32.

Trong dự án này, mình dùng 6 động cơ Servo, trong đó gồm 3 Servo MG995 và 3 Servo SG90. Mình kết nối chúng lần lượt với các chân Digital Pin 14, 27, 26, 25, 33 và 32 của mạch ESP32. Bạn cũng có thể sử dụng các chân GPIO khác, nhưng đảm bảo chúng hỗ trợ xung tín hiệu PWM và trong code bạn nhớ gọi lại tên các chân này nhé!

Lưu ý: Không cấp nguồn trực tiếp cho Servo từ ESP32, vì chúng sẽ làm hỏng mạch của bạn đấy!

Bạn kết nối tất cả phần cứng lại với nhau bằng cách sử dụng các Male/Female headers gắn riêng trên bảng điều khiển và dây nối mà không cần hàn trực tiếp. Nếu hàn trực tiếp luôn, bạn nhớ tránh hiện tượng đoản mạch nhé!

Kết nối phần cứng cho dự án IoT ESP32 Robot Arm

Sau khi hoàn thành tất cả phần trên, chúng ta hãy tiến hành lập trình ESP32 Robot Arm nhé! Dưới đây là hình ảnh mô hình khi đã kết nối hoàn tất:

Kết nối phần cứng cho dự án IoT ESP32 Robot Arm

Hướng dẫn lập trình ESP32 Robot Arm

ESP32 có sẵn khả năng kết nối WiFi, trong dự án lần này chúng ta sẽ tận dụng tính năng đó để điều khiển cánh tay robot bằng trang Web của mình. Bạn cũng sẽ được hướng dẫn cách tạo một trang Web để điều khiển chuyển động của Robot Arm.

Phần 1: Mở đầu

  1. Khởi tạo các thư viện cần thiết là servo.h (dùng để điều khiển động cơ Servo bằng xung tín hiệu PWM) và WiFi.h (kết nối WiFi)
  2. Tạo 6 objects khác nhau cho Servo class, mỗi object có một tên riêng vì chúng ta đang dùng 6 Servo khac nhau.
  3. Khai báo 6 biến khác nhau để gán các chân điều khiển của vi điều khiển, dựa trên kết nối phần cứng của mô hình ESP32 Robot Arm đã làm ở bước trước.
  4. Cấu hình thông tin mạng WiFi.
  5. Sau đó, một phiên bản của WiFiServer đã được tạo, được đặt tên là Server với số cổng HTTP là cổng 90. Ngoài ra, chương trình còn khai báo các biến để lưu trữ vị trí thanh trượt (dùng để điều khiển Servo):
#include <WiFi.h>
#include <Servo.h>
Servo ObjServo1; // Make object of Servo motor from Servo library
Servo ObjServo2;
Servo ObjServo3;
Servo ObjServo4;
Servo ObjServo5;
Servo ObjServo6;
// Objects được tạo cho mỗi một Servo riêng mà chúng ta muốn điều khiển
static const int ServoGPIO1 = 33; // Xác định chân GPIO mà các Servo đã kết nối
static const int ServoGPIO2 = 25;
static const int ServoGPIO3 = 26;
static const int ServoGPIO4 = 27;
static const int ServoGPIO5 = 14;
static const int ServoGPIO6 = 12;
// Biến chứa thông tin tên và mật khẩu WiFi
const char* ssid = "IN1b"; // Điền tên mạng WiFi
const char* password = "in@india"; // Điền mật khẩu mạng WiFi
// Cấu hình cổng Server thành cổng 80 mặc định
WiFiServer server(80);
// Các biến lưu trữ giá trị của thanh trượt để điều khiển Servo
String valueString1 = String(0);
String valueString2 = String(0);
String valueString3 = String(0);
String valueString4 = String(0);
String valueString5 = String(0);
String valueString6 = String(0);

Phần 2: Setup()

Tạo một Serial Monitor với tốc độ baud là 115200.

Sau đó, gắn từng động cơ Servo bằng các chân điều khiển GPIO tương ứng của ESP32, giúp tạo giao tiếp giữa động cơ và ESP32 để điều khiển động cơ.

Tiến hành kết nối WiFi bằng cách cung cấp tên (SSID) và mật khẩu WiFi. Sau khi kết nối thành công, trên màn hình Serial sẽ hiển thị địa chỉ IP.

Khi đó, WiFi Server bắt đầu dùng lệnh server.begin():

void setup() {
  Serial.begin(115200); // Xác định giao tiếp Serial với tốc độ 115200
  ObjServo1.attach(ServoGPIO1); // Attach ObjServo1 to ServoGPIO1 pin
  ObjServo2.attach(ServoGPIO2);
  ObjServo3.attach(ServoGPIO3);
  ObjServo4.attach(ServoGPIO4);
  ObjServo5.attach(ServoGPIO5);
  ObjServo6.attach(ServoGPIO6);
  Serial.print("Making connection to "); // Hiển thị thông báo trên Serial Monitor
  Serial.println(ssid);
  WiFi.begin(ssid, password);
    while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  // In địa chỉ IP trên Serial Monitor
  Serial.println("");
  Serial.println("WiFi connected.");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
  server.begin(); // Start the server
}

3. Loop()

Tại đây, hệ thống ESP32 Robot Arm sẽ lắng nghe các kết nối mà Client (máy khách) gửi đến bằng cách gọi server.available().

Nếu có 1 Client kết nối, hệ thống sẽ tạo 1 đối tượng WiFiClient có tên là “client” để xử lý việc liên lạc với Client đó.

Bên trong khối if (client), chương trình thiết lập các tiêu đề phản hồi HTTP và bắt đầu xây dựng 1 trang Web HTML để gửi đến Client:

void loop() {
  WiFiClient client = server.available();                                    // Lắng nghe các Client gửi đến
  if (client) {                                                                                    // Nếu có 1 Client mới kết nối
    String header = client.readStringUntil('\r');
    client.println("HTTP/1.1 200 OK");
    client.println("Content-type:text/html");
    client.println("Connection: close");
    client.println();
    // Hiển thị trang Web HTML
    client.println("<!DOCTYPE html><html>");
    client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
    client.println("<link rel=\"icon\" href=\"data:,\">");
    client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");
    client.println(".slider { width: 300px; }");
    client.println(".button { font-size: 24px; padding: 10px 20px; }</style>");
    client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");
    client.println("</head><body>");

Trang Web HTML mà IoTZone bao gồm 6 bộ phần tử:

  • 1 tiêu đề (H1)
  • 1 hiển thị vị trí (‘span’)
  • 1 phạm vi đầu vào (‘input’)
  • 2 nút (‘button’)

Mỗi bộ trên tương ứng với 1 động cơ Servo. Màn hình hiển thị sẽ hiển thị vị trí hiện tại của động cơ Servo, và phạm vi input cho phép người dùng điều chỉnh vị trí. Các nút button cho phép người dùng tăng hoạt giảm vị trí của 5 đơn vị:

    // Slider 1
    client.println("<h1>ESP32 RoboArm Conrol</h1>");
    client.println("<p>Position 1: <span id=\"servoPos1\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider1\" onchange=\"servo(this.value, 1)\" value=\"" + valueString1 + "\"/>");
    client.println("<button class=\"button\" onclick=\"decrementValue(1)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"incrementValue(1)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");
    // Slider 2
    client.println("<p>Position 2: <span id=\"servoPos2\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider2\" onchange=\"servo(this.value, 2)\" value=\"" + valueString2 + "\"/>");
    client.println("<button class=\"button\" onclick=\"decrementValue(2)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"incrementValue(2)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");
    // Slider 3
    client.println("<p>Position 3: <span id=\"servoPos3\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider3\" onchange=\"servo(this.value, 3)\" value=\"" + valueString3 + "\"/>");
    client.println("<button class=\"button\" onclick=\"incrementValue(3)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"decrementValue(3)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");
    // Slider 4
    client.println("<p>Position 4: <span id=\"servoPos4\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider4\" onchange=\"servo(this.value, 4)\" value=\"" + valueString4 + "\"/>");
    client.println("<button class=\"button\" onclick=\"incrementValue(4)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"decrementValue(4)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");
    // Slider 5
    client.println("<p>Position 5: <span id=\"servoPos5\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider5\" onchange=\"servo(this.value, 5)\" value=\"" + valueString5 + "\"/>");
    client.println("<button class=\"button\" onclick=\"decrementValue(5)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"incrementValue(5)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");
    // Slider 6
    client.println("<p>Position 6: <span id=\"servoPos6\"></span></p>");
    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider6\" onchange=\"servo(this.value, 6)\" value=\"" + valueString6 + "\"/>");
    client.println("<button class=\"button\" onclick=\"decrementValue(6)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");
    client.println("<button class=\"button\" onclick=\"incrementValue(6)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

Trong đoạn HTML cũng bao gồm 1 vài đoạn Javascript để xử lý các tương tác của người dùng với thanh trượt slider và nút button. Chúng sẽ cập nhật vị trí khi giá trị thanh trượt thay đổi và gửi yêu cầu AJAX tới Server khi người dùng tương tác với slider hoặc button:

  client.println("<script>");
    client.println("var slider1 = document.getElementById(\"servoSlider1\");");
    client.println("var servoP1 = document.getElementById(\"servoPos1\");");
    client.println("slider1.oninput = function() { servoP1.innerHTML = this.value; }");
    client.println("var slider2 = document.getElementById(\"servoSlider2\");");
    client.println("var servoP2 = document.getElementById(\"servoPos2\");");
    client.println("slider2.oninput = function() { servoP2.innerHTML = this.value; }");
    client.println("var slider3 = document.getElementById(\"servoSlider3\");");
    client.println("var servoP3 = document.getElementById(\"servoPos3\");");
    client.println("slider3.oninput = function() { servoP3.innerHTML = this.value; }");
    client.println("var slider4 = document.getElementById(\"servoSlider4\");");
    client.println("var servoP4 = document.getElementById(\"servoPos4\");");
    client.println("slider4.oninput = function() { servoP4.innerHTML = this.value; }");
    client.println("var slider5 = document.getElementById(\"servoSlider5\");");
    client.println("var servoP5 = document.getElementById(\"servoPos5\");");
    client.println("slider5.oninput = function() { servoP5.innerHTML = this.value; }");
    client.println("var slider6 = document.getElementById(\"servoSlider6\");");
    client.println("var servoP6 = document.getElementById(\"servoPos6\");");
    client.println("slider6.oninput = function() { servoP6.innerHTML = this.value; }");
    client.println("$.ajaxSetup({timeout: 1000});");
    client.println("function servo(pos, servoNum) {");
    client.println("$.get(\"/?servo=\" + servoNum + \"&value=\" + pos + \"&\");");
    client.println("}");
    client.println("function incrementValue(servoNum) {");
    client.println("var slider = document.getElementById(\"servoSlider\" + servoNum);");
    client.println("slider.value = parseInt(slider.value) + 5;");
    client.println("servo(slider.value, servoNum);");
    client.println("}");
    client.println("function decrementValue(servoNum) {");
    client.println("var slider = document.getElementById(\"servoSlider\" + servoNum);");
    client.println("slider.value = parseInt(slider.value) - 5;");
    client.println("servo(slider.value, servoNum);");
    client.println("}");  
    client.println("</script>");
    client.println("</body></html>");

Nếu yêu cầu HTTP nhận được từ Client chứa chuỗi “GET /?servo=”, điều này đồng nghĩa với việc Client đã gửi yêu cầu thay đổi vị trí góc Servo. Chương trình ESP32 Robot Arm trích xuất số và giá trị Servo từ các yêu cầu, chuyển đổi thành số nguyên và gọi hàm setServoPosition() để đưa Servo quay tới góc mà Client muốn.

Sau khi nhận được yêu cầu từ Client, chương trình ESP32 Robot Arm sẽ ngắt kết nối với Client bằng client.stop() và in thông báo trên Serial, để Client biết đã bị ngắt kết nối:

    if (header.indexOf("GET /?servo=") >= 0) {
      int servoPosition = header.indexOf("servo=") + 6;
      int valuePosition = header.indexOf("&value=");
      int servoNum = header.substring(servoPosition, valuePosition).toInt();
      int value = header.substring(valuePosition + 7).toInt();
      // Set the servo position
      setServoPosition(servoNum, value);
    }
    client.stop(); // Disconnect the client
    Serial.println("Client disconnected.");
    Serial.println("");
  }
}

Hàm setServoPosition() là một hàm giúp lấy số và giá trị Servo, chúng dùng các câu lệnh chuyển đổi để xác định chúng là Servo nào và đặt giá trị về vị trí góc được chỉ định.

Ngoài ra, chúng cũng cập nhật biến valueString tương ứng để theo dõi vị trí góc hiện tại của từng Servo:

void setServoPosition(int servoNum, int value) {
  switch (servoNum) {
    case 1:
      ObjServo1.write(value);
      valueString1 = String(value);
      break;
    case 2:
      ObjServo2.write(value);
      valueString2 = String(value);
      break;
    case 3:
      ObjServo3.write(value);
      valueString3 = String(value);
      break;
    case 4:
      ObjServo4.write(value);
      valueString4 = String(value);
      break;
    case 5:
      ObjServo5.write(value);
      valueString5 = String(value);
      break;
    case 6:
      ObjServo6.write(value);
      valueString6 = String(value);
      break;
  }
}

Demo dự án ESP32 Robot Arm

Điện áp tối đa của cả 2 loại Servo mình đang dùng trong dự án cánh tay robot lần này là khoảng 7,2V. Bằng việc dùng Micro USB, bạn có thể dùng bất kỳ bộ chuyển đổi 5V generic nào có cường độ dòng điện đầu ra tối thiểu là 2 Ampe, đủ để cung cấp điện cho các động cơ Servo.

Bạn cần phải kiểm tra kỹ việc sắp xếp giữa các cực nguồn +ve và -ve bên ngoài, trước khi cấp nguồn cho bo mạch nhé!

Bên cạnh đó, bạn cần đổi thông tin mạng WiFi để thiết lập kết nối với mạng Internet, hoàn thành dự án IoT này.

Bây giờ, bạn hãy upload code ESP32 Robot Arm vào mạch, mở màn hình Serial trong Arduino và chọn tốc độ baud là 115200. Khi kết nối thành công, trên màn hình hiển thị địa chỉ IP như sau:

Lấy địa chỉ IP ESP32 phục vụ dự án ESP32 Robot Arm
Lấy địa chỉ IP ESP32 phục vụ dự án ESP32 Robot Arm

Sau đó, bạn mở điện thoại hoặc laptop, truy cập vào bất kỳ trình duyệt Internet nào và dán địa chỉ IP vừa nhận được vào thanh tìm kiếm. Trên màn hình sẽ hiển thị một giao diện Web gồm các nút nhấn và thanh trượt slider để bạn điều khiển cánh tay robot của mình qua Internet.

Lưu ý: Hãy đảm bảo tất cả thiết bị được kết nối cùng 1 mạng WiFi, nếu không thì bạn sẽ không thấy trang Web nào.

Dưới đây là demo của dự án IoT ESP32 Robot Arm này:

Demo dự án IoT ESP32 Robot Arm

Bạn hãy thử kéo thanh trượt hoặc nhấn vào các nút trên trang Web để thay đổi vị trí góc quay của Servo nhé! Lúc đó cánh tay robot cũng thay đổi theo.

Dưới đây là đoạn code đầy đủ, bạn có thể dùng nó để nạp vào mạch ESP32 của mình (nhớ đổi thông tin mạng WiFi và một số thông tin khác nhé!)

Chương trình đầy đủ

#include <WiFi.h>

#include <Servo.h>

 

Servo ObjServo1; // Make object of Servo motor from Servo library

Servo ObjServo2;

Servo ObjServo3;

Servo ObjServo4;

Servo ObjServo5;

Servo ObjServo6;

 

// Objects are made for every servo motor we want to control through this library

 

static const int ServoGPIO1 = 33; // define the GPIO pin with which servo 1 is connected

static const int ServoGPIO2 = 25;

static const int ServoGPIO3 = 26;

static const int ServoGPIO4 = 27;

static const int ServoGPIO5 = 14;

static const int ServoGPIO6 = 12;

 

// Variables to store network name and password

const char* ssid = "IN1b"; // Enter your network name

const char* password = "in@india"; // Enter your network password

 

// Set the server port number to default 80

WiFiServer server(80);

 

// Variables to store slider positions

String valueString1 = String(0);

String valueString2 = String(0);

String valueString3 = String(0);

String valueString4 = String(0);

String valueString5 = String(0);

String valueString6 = String(0);

 

void setup() {

  Serial.begin(115200); // Define serial communication with baud rate of 115200

 

  ObjServo1.attach(ServoGPIO1); // Attach ObjServo1 to ServoGPIO1 pin

  ObjServo2.attach(ServoGPIO2);

  ObjServo3.attach(ServoGPIO3);

  ObjServo4.attach(ServoGPIO4);

  ObjServo5.attach(ServoGPIO5);

  ObjServo6.attach(ServoGPIO6);

 

  Serial.print("Making connection to "); // Display message on serial monitor

  Serial.println(ssid);

  WiFi.begin(ssid, password);

 

  while (WiFi.status() != WL_CONNECTED) {

    delay(500);

    Serial.print(".");

  }

 

  // Print the IP address value on serial monitor

  Serial.println("");

  Serial.println("WiFi connected.");

  Serial.println("IP address: ");

  Serial.println(WiFi.localIP());

 

  server.begin(); // Start the server

}

 

void loop() {

  WiFiClient client = server.available(); // Listen for incoming clients

 

  if (client) { // If a new client connects

    String header = client.readStringUntil('\r');

    client.println("HTTP/1.1 200 OK");

    client.println("Content-type:text/html");

    client.println("Connection: close");

    client.println();

 

    // Display the HTML web page

    client.println("<!DOCTYPE html><html>");

    client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");

    client.println("<link rel=\"icon\" href=\"data:,\">");

    client.println("<style>body { text-align: center; font-family: \"Trebuchet MS\", Arial; margin-left:auto; margin-right:auto;}");

    client.println(".slider { width: 300px; }");

    client.println(".button { font-size: 24px; padding: 10px 20px; }</style>");

    client.println("<script src=\"https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js\"></script>");

    client.println("</head><body>");

 

    // Slider 1

    client.println("<h1>ESP32 RoboArm Conrol</h1>");

    client.println("<p>Position 1: <span id=\"servoPos1\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider1\" onchange=\"servo(this.value, 1)\" value=\"" + valueString1 + "\"/>");

    client.println("<button class=\"button\" onclick=\"decrementValue(1)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"incrementValue(1)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    // Slider 2

    client.println("<p>Position 2: <span id=\"servoPos2\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider2\" onchange=\"servo(this.value, 2)\" value=\"" + valueString2 + "\"/>");

    client.println("<button class=\"button\" onclick=\"decrementValue(2)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"incrementValue(2)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    // Slider 3

    client.println("<p>Position 3: <span id=\"servoPos3\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider3\" onchange=\"servo(this.value, 3)\" value=\"" + valueString3 + "\"/>");

    client.println("<button class=\"button\" onclick=\"incrementValue(3)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"decrementValue(3)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    // Slider 4

    client.println("<p>Position 4: <span id=\"servoPos4\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider4\" onchange=\"servo(this.value, 4)\" value=\"" + valueString4 + "\"/>");

    client.println("<button class=\"button\" onclick=\"incrementValue(4)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"decrementValue(4)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    // Slider 5

    client.println("<p>Position 5: <span id=\"servoPos5\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider5\" onchange=\"servo(this.value, 5)\" value=\"" + valueString5 + "\"/>");

    client.println("<button class=\"button\" onclick=\"decrementValue(5)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"incrementValue(5)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    // Slider 6

    client.println("<p>Position 6: <span id=\"servoPos6\"></span></p>");

    client.println("<input type=\"range\" min=\"0\" max=\"180\" class=\"slider\" id=\"servoSlider6\" onchange=\"servo(this.value, 6)\" value=\"" + valueString6 + "\"/>");

    client.println("<button class=\"button\" onclick=\"decrementValue(6)\"style=\"font-size: 24px; padding: 10px 20px;\">-</button>");

    client.println("<button class=\"button\" onclick=\"incrementValue(6)\"style=\"font-size: 24px; padding: 10px 20px;\">+</button>");

 

    client.println("<script>");

    client.println("var slider1 = document.getElementById(\"servoSlider1\");");

    client.println("var servoP1 = document.getElementById(\"servoPos1\");");

    client.println("slider1.oninput = function() { servoP1.innerHTML = this.value; }");

 

    client.println("var slider2 = document.getElementById(\"servoSlider2\");");

    client.println("var servoP2 = document.getElementById(\"servoPos2\");");

    client.println("slider2.oninput = function() { servoP2.innerHTML = this.value; }");

 

    client.println("var slider3 = document.getElementById(\"servoSlider3\");");

    client.println("var servoP3 = document.getElementById(\"servoPos3\");");

    client.println("slider3.oninput = function() { servoP3.innerHTML = this.value; }");

 

    client.println("var slider4 = document.getElementById(\"servoSlider4\");");

    client.println("var servoP4 = document.getElementById(\"servoPos4\");");

    client.println("slider4.oninput = function() { servoP4.innerHTML = this.value; }");

 

    client.println("var slider5 = document.getElementById(\"servoSlider5\");");

    client.println("var servoP5 = document.getElementById(\"servoPos5\");");

    client.println("slider5.oninput = function() { servoP5.innerHTML = this.value; }");

 

    client.println("var slider6 = document.getElementById(\"servoSlider6\");");

    client.println("var servoP6 = document.getElementById(\"servoPos6\");");

    client.println("slider6.oninput = function() { servoP6.innerHTML = this.value; }");

 

    client.println("$.ajaxSetup({timeout: 1000});");

    client.println("function servo(pos, servoNum) {");

    client.println("$.get(\"/?servo=\" + servoNum + \"&value=\" + pos + \"&\");");

    client.println("}");

 

    client.println("function incrementValue(servoNum) {");

    client.println("var slider = document.getElementById(\"servoSlider\" + servoNum);");

    client.println("slider.value = parseInt(slider.value) + 5;");

    client.println("servo(slider.value, servoNum);");

    client.println("}");

 

    client.println("function decrementValue(servoNum) {");

    client.println("var slider = document.getElementById(\"servoSlider\" + servoNum);");

    client.println("slider.value = parseInt(slider.value) - 5;");

    client.println("servo(slider.value, servoNum);");

    client.println("}");

   

    client.println("</script>");

    client.println("</body></html>");

 

    if (header.indexOf("GET /?servo=") >= 0) {

      int servoPosition = header.indexOf("servo=") + 6;

      int valuePosition = header.indexOf("&value=");

 

      int servoNum = header.substring(servoPosition, valuePosition).toInt();

      int value = header.substring(valuePosition + 7).toInt();

 

      // Set the servo position

      setServoPosition(servoNum, value);

    }

 

    client.stop(); // Disconnect the client

    Serial.println("Client disconnected.");

    Serial.println("");

  }

}

 

void setServoPosition(int servoNum, int value) {

  switch (servoNum) {

    case 1:

      ObjServo1.write(value);

      valueString1 = String(value);

      break;

    case 2:

      ObjServo2.write(value);

      valueString2 = String(value);

      break;

    case 3:

      ObjServo3.write(value);

      valueString3 = String(value);

      break;

    case 4:

      ObjServo4.write(value);

      valueString4 = String(value);

      break;

    case 5:

      ObjServo5.write(value);

      valueString5 = String(value);

      break;

    case 6:

      ObjServo6.write(value);

      valueString6 = String(value);

      break;

  }

}

Lời kết

Chúc bạn hoàn thành dự án ESP32 Robot Arm này! Đây là một dự án thú vị phải không? IoTZone còn có nhiều hướng dẫn và dự án sáng tạo khác với ESP32, bạn có thể tham khảo nhé!

Ngoài ra, nếu cần tìm mua ESP32 giá rẻ chất lượng, hãy truy cập ngay Shop IoTZone để tìm lựa chọn phù hợp với mình.

IoTZone – Chuyên cung cấp thiết bị điện tử & tài liệu cho Makers

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *