1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ESP32でラジコンを作ってみた

Last updated at Posted at 2024-02-18

概要

ESP32にweb serverを立て、同一ネットワーク内の機器から操作できるラジコンを作りました。
具体的な構成は以下の通りです。
image.png

動画

コード

操作する側が目にするhtmlとESP32上で動くプログラムで構成されます。

ホスト側

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>RC Controller</title>
  <style>
    .button-container {
      text-align: center;
    }
    .button {
      display: inline-block;
      padding: 10px 20px;
      font-size: 16px;
      cursor: pointer;
      text-align: center;
      text-decoration: none;
      outline: none;
      border: none;
      border-radius: 5px;
      background-color: #3498db;
      color: #ffffff;
      margin: 10px;
    }
    .button:hover {
      background-color: #2980b9;
    }
  </style>
</head>
<body>
  <h1>RC Controller</h1>
  <div class="button-container">
    <button class="button" id="forward" onmousedown="changeState('forward')" onmouseup="changeState('forward')">Forward</button><br>
    <button class="button" id="left" onmousedown="changeState('left')" onmouseup="changeState('left')">Left</button>
    <button class="button" id="stop" onmousedown="changeState('stop')" onmouseup="changeState('stop')">Stop</button>
    <button class="button" id="right" onmousedown="changeState('right')" onmouseup="changeState('right')">Right</button><br>
    <button class="button" id="backward" onmousedown="changeState('backward')" onmouseup="changeState('backward')">Backward</button>
  </div>

  <script>
    const states = {
      'forward': false,
      'backward': false,
      'left': false,
      'right': false,
      'stop': false
    };

    function changeState(target) {
      if (states.hasOwnProperty(target)) {
        states[target] = !states[target];
      }
      fetch('/control', {
        method: 'PUT',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({command: target, state: states[target]})
      }).then(data => {
        console.log('Success:', data);
      })
      .catch(error => {
        console.error('Error:', error);
      });
    }
  </script>
</body>
</html>

ESP32側

#include <WiFi.h>
#include <WebServer.h>
#include <ArduinoJson.h>

const int IN1 = 15, IN2 = 16, IN3 = 17, IN4 = 18;
const char *ssid = "ssid";
const char *pass = "pass";
WebServer Server(80);

void send_message() {
  Serial.println("send_message");
  String html = "<!DOCTYPE html><html lang=\"en\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>RC Controller</title><style>.button-container {text-align: center;}.button {display: inline-block;padding: 10px 20px;font-size: 16px;cursor: pointer;text-align: center;text-decoration: none;outline: none;border: none;border-radius: 5px;background-color: #3498db;color: #ffffff;margin: 10px;}.button:hover {background-color: #2980b9;}</style></head><body><h1>RC Controller</h1><div class=\"button-container\"><button class=\"button\" id=\"forward\" onmousedown=\"changeState('forward')\" onmouseup=\"changeState('forward')\">Forward</button><br><button class=\"button\" id=\"left\" onmousedown=\"changeState('left')\" onmouseup=\"changeState('left')\">Left</button><button class=\"button\" id=\"stop\" onmousedown=\"changeState('stop')\" onmouseup=\"changeState('stop')\">Stop</button><button class=\"button\" id=\"right\" onmousedown=\"changeState('right')\" onmouseup=\"changeState('right')\">Right</button><br><button class=\"button\" id=\"backward\" onmousedown=\"changeState('backward')\" onmouseup=\"changeState('backward')\">Backward</button></div><script>const states = {'forward': false,'backward': false,'left': false,'right': false,'stop': false};function changeState(target) {if (states.hasOwnProperty(target)) {states[target] = !states[target];}fetch('/control', {method: 'PUT',headers: {'Content-Type': 'application/json'},body: JSON.stringify({command: target, state: states[target]})}).then(data => {console.log('Success:', data);}).catch(error => {console.error('Error:', error);});}</script></body></html>";
  Server.send(200, "text/html", html);
}

void send_not_found() {
  Serial.println("send_not_found");
  Server.send(404, "text/plain", "404 not found...");
}

void change_state() {
  String body = Server.arg("plain"); // ボディの取得
  StaticJsonDocument<200> doc;
  DeserializationError error = deserializeJson(doc, body);
  if (error) {
    Serial.print("deserializeJson() failed: ");
    Serial.println(error.c_str());
    return;
  }
  const char* command = doc["command"];
  bool state = doc["state"];
  
  Serial.print("Command: ");
  Serial.println(command);
  Serial.print("State: ");
  Serial.println(state ? "true" : "false");

  if(!state){
    stop();
  }else{
    if (strcmp(command, "stop") == 0) {
        stop();
    } else if (strcmp(command, "forward") == 0) {
        forward();
    } else if (strcmp(command, "backward") == 0) {
        backward();
    } else if (strcmp(command, "left") == 0) {
        turn_left();
    } else if (strcmp(command, "right") == 0) {
        turn_right();
    } else {
        // デフォルトの処理
    }
  }

  Server.send(200, "text/plain", "PUT request received");
}

void setup() {
  // put your setup code here, to run once:
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  pinMode(IN3, OUTPUT);
  pinMode(IN4, OUTPUT);

  Serial.begin(115200);             
  delay(100);                         
  Serial.println("\n*** Starting ***");
  //  無線 LAN に接続
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, pass);             
  Serial.println("Connecting...");
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    if (WiFi.status() == WL_CONNECT_FAILED) {
      Serial.println("Can't connect");
    }
  }
  Serial.println("Connected");
  Serial.println(WiFi.localIP());
  Server.on("/", HTTP_GET, send_message);
  Server.on("/control", HTTP_PUT, change_state);
  Server.onNotFound(send_not_found);
  Server.begin();
}

void forward() {
  Serial.println("forward");
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}

void backward() {
  Serial.println("backward");
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, HIGH);
}

void stop() {
  Serial.println("stop");
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}

void brake() {
  Serial.println("brake");
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, HIGH);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, HIGH);
}

void turn_left() {
  Serial.println("turn_left");
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, HIGH);
  digitalWrite(IN4, LOW);
}

void turn_right() {
  Serial.println("turn_right");
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  digitalWrite(IN3, LOW);
  digitalWrite(IN4, LOW);
}

void loop() {
  // put your main code here, to run repeatedly:
  Server.handleClient();
  delay(1);
}

編集から操作までの流れ

  1. arduino ideで編集
  2. htmlを作成し改行を無くしダブルクォーテーションをエスケープする
  3. 1をsend_message()内のhtml変数に代入しなおす
  4. 書き込み (これ以降ホストとESP32を切り離してもいい)
  5. シリアルモニタに表示されるIPにアクセス
  6. 操作

最後に

ChatGPTの力で1日かからずプログラムが完成しました。Bluetoothで無線操作できるように改良していきます。ありがとうございました。

追記
bluetoothラジコンもライントレーサ (超低性能)も作れました。工作は楽しい!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?