電子工作

【Freenove ESP32-S3-WROOM CAMボード】ブラウザやスマホからラジコン戦車を動かす#1

ラジコン戦車

Lチカの次は、ラジコン戦車を動かす

前回は、ESP32の動作確認確認も含めて、LEDチカチカさせる実験を行いました。

【Freenove ESP32-S3-WROOM CAMボード】ブラウザやスマホからLチカのONOFF

さらに詳しく

いきなり、ラジコン戦車動かすのかよ!

実は、数年前に、Rasberry Pi(ARMプロセッサを搭載したシングルボードコンピュータ)を使って既にWebからラジコン戦車を動かしたことがありました。

既にやった事を何で再びやるのかと言えば、Rasberry Piに比較して、ESP32のボードは比較できないくらい安いからです。

つまり、頭脳となるコンピュータ部分が安く購入できるので、何かを組み上げた時も安く組み上げられるという事になります。

今のことろ、最初の目標としては、自動カーテン開閉装置を作成する事なのですが、その前に遊びながらノウハウを身に着けたいと考えています。

 

モーターを制御するドライバ使用

Rasberry Piの時も使用しましたが、「TA7291P」というパーツを使います。

ネットからデータシートを探してみました。

TA7291PTA7291P

 

 

このパーツを使用すれば、モータ電源を分けて、Vref端子により、モータへの加圧調整ができるのでスピードコントロールなどに使えますね。

 

モーター部分の配線図とブレットボード組立

配線図は、Rasberry Piの時のがあったので、そのまま使う事にしました。

ラジコン戦車 配線図

4番ピンのVrefに10KΩを接続しているのは、今回は微妙なモーター速度の調整はしないからです。

IN1IN2モーター動作
00ストップ
PWM0正転(PWM値に応じて可変)
0PWM逆転(PWM値に応じて可変)
11ブレーキ

つまり、IN1がプラスになれば、正転になり、IN2がプラスになれば、逆転するという仕組みになります。

モータ速度の調整は次の段階になったらやってみたいと思います。

ラジコン戦車 配線図

 

簡単なONOFFだけで動かす実験

CopilotのAIの力を借りて、WEB上でタンクの車輪を動かす実験をしてみました。

プログラムの方は数回の修正を重ねて簡単に出来上がりました。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
#include <WiFi.h>
#include <WebServer.h>
// WiFiの接続情報
const char* ssid = "SSID";
const char* password = "password";
const IPAddress ip(192, 168, 1, 60);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
const IPAddress dns1(192, 168, 1, 1);
// 4-5番、1-2番ピンを使ってモーターを動かす
const int mot_04 = 4;
const int mot_05 = 5;
const int mot_01 = 1;
const int mot_02 = 2;
WebServer server(80);
void setup() {
Serial.begin(115200);
// WiFi設定
if (!WiFi.config(ip, gateway, subnet, dns1)) {
Serial.println("Failed to configure!");
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi...");
}
Serial.println("Connected to WiFi");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// モーターピン設定
pinMode(mot_04, OUTPUT);
pinMode(mot_05, OUTPUT);
pinMode(mot_01, OUTPUT);
pinMode(mot_02, OUTPUT);
// 初期値
digitalWrite(mot_04, LOW);
digitalWrite(mot_05, LOW);
digitalWrite(mot_01, LOW);
digitalWrite(mot_02, LOW);
// Webサーバールート設定
server.on("/", HTTP_GET, handleRoot);
for (int i = 0; i < 4; i++) {
server.on(("/toggle_45_" + String(i)).c_str(), HTTP_GET, [i]() { toggle45(i); });
server.on(("/toggle_12_" + String(i)).c_str(), HTTP_GET, [i]() { toggle12(i); });
}
server.begin();
Serial.println("Web server started!");
}
void loop() {
server.handleClient();
}
void handleRoot() {
Serial.println("Handling root page...");
String html = "<!DOCTYPE html><html>";
html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
html += "<style>html { font-family: Helvetica; text-align: center;} .button { padding: 10px 20px; margin: 5px; }</style>";
html += "</head><body>";
html += "<h1>Motor Control</h1>";
// 現在のパターンを表示
html += "<h2>Current Patterns</h2>";
html += "<p>4 and 5: " + getRealTimeState(mot_04, mot_05) + "</p>";
html += "<p>1 and 2: " + getRealTimeState(mot_01, mot_02) + "</p>";
// 4番、5番ピンの切り替えボタン
html += "<h2>4 and 5 Control</h2>";
for (int i = 0; i < 4; i++) {
html += "<a href='/toggle_45_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>";
}
// 1番、2番ピンの切り替えボタン
html += "<h2>1 and 2 Control</h2>";
for (int i = 0; i < 4; i++) {
html += "<a href='/toggle_12_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>";
}
html += "</body></html>";
server.send(200, "text/html", html);
}
void toggle45(int pattern) {
Serial.print("Toggling 4 and 5 pins to pattern: ");
Serial.println(pattern);
digitalWrite(mot_04, pattern & 0x01); // 最下位ビット
digitalWrite(mot_05, (pattern & 0x02) >> 1); // 2番目のビット
server.sendHeader("Location", "/");
server.send(303);
}
void toggle12(int pattern) {
Serial.print("Toggling 1 and 2 pins to pattern: ");
Serial.println(pattern);
digitalWrite(mot_01, pattern & 0x01); // 最下位ビット
digitalWrite(mot_02, (pattern & 0x02) >> 1); // 2番目のビット
server.sendHeader("Location", "/");
server.send(303);
}
String getRealTimeState(int pin1, int pin2) {
String state1 = digitalRead(pin1) == HIGH ? "HIGH" : "LOW";
String state2 = digitalRead(pin2) == HIGH ? "HIGH" : "LOW";
return state1 + ", " + state2;
}
#include <WiFi.h> #include <WebServer.h> // WiFiの接続情報 const char* ssid = "SSID"; const char* password = "password"; const IPAddress ip(192, 168, 1, 60); const IPAddress gateway(192, 168, 1, 1); const IPAddress subnet(255, 255, 255, 0); const IPAddress dns1(192, 168, 1, 1); // 4-5番、1-2番ピンを使ってモーターを動かす const int mot_04 = 4; const int mot_05 = 5; const int mot_01 = 1; const int mot_02 = 2; WebServer server(80); void setup() { Serial.begin(115200); // WiFi設定 if (!WiFi.config(ip, gateway, subnet, dns1)) { Serial.println("Failed to configure!"); } WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.println("Connecting to WiFi..."); } Serial.println("Connected to WiFi"); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // モーターピン設定 pinMode(mot_04, OUTPUT); pinMode(mot_05, OUTPUT); pinMode(mot_01, OUTPUT); pinMode(mot_02, OUTPUT); // 初期値 digitalWrite(mot_04, LOW); digitalWrite(mot_05, LOW); digitalWrite(mot_01, LOW); digitalWrite(mot_02, LOW); // Webサーバールート設定 server.on("/", HTTP_GET, handleRoot); for (int i = 0; i < 4; i++) { server.on(("/toggle_45_" + String(i)).c_str(), HTTP_GET, [i]() { toggle45(i); }); server.on(("/toggle_12_" + String(i)).c_str(), HTTP_GET, [i]() { toggle12(i); }); } server.begin(); Serial.println("Web server started!"); } void loop() { server.handleClient(); } void handleRoot() { Serial.println("Handling root page..."); String html = "<!DOCTYPE html><html>"; html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"; html += "<style>html { font-family: Helvetica; text-align: center;} .button { padding: 10px 20px; margin: 5px; }</style>"; html += "</head><body>"; html += "<h1>Motor Control</h1>"; // 現在のパターンを表示 html += "<h2>Current Patterns</h2>"; html += "<p>4 and 5: " + getRealTimeState(mot_04, mot_05) + "</p>"; html += "<p>1 and 2: " + getRealTimeState(mot_01, mot_02) + "</p>"; // 4番、5番ピンの切り替えボタン html += "<h2>4 and 5 Control</h2>"; for (int i = 0; i < 4; i++) { html += "<a href='/toggle_45_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>"; } // 1番、2番ピンの切り替えボタン html += "<h2>1 and 2 Control</h2>"; for (int i = 0; i < 4; i++) { html += "<a href='/toggle_12_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>"; } html += "</body></html>"; server.send(200, "text/html", html); } void toggle45(int pattern) { Serial.print("Toggling 4 and 5 pins to pattern: "); Serial.println(pattern); digitalWrite(mot_04, pattern & 0x01); // 最下位ビット digitalWrite(mot_05, (pattern & 0x02) >> 1); // 2番目のビット server.sendHeader("Location", "/"); server.send(303); } void toggle12(int pattern) { Serial.print("Toggling 1 and 2 pins to pattern: "); Serial.println(pattern); digitalWrite(mot_01, pattern & 0x01); // 最下位ビット digitalWrite(mot_02, (pattern & 0x02) >> 1); // 2番目のビット server.sendHeader("Location", "/"); server.send(303); } String getRealTimeState(int pin1, int pin2) { String state1 = digitalRead(pin1) == HIGH ? "HIGH" : "LOW"; String state2 = digitalRead(pin2) == HIGH ? "HIGH" : "LOW"; return state1 + ", " + state2; }
#include <WiFi.h>
#include <WebServer.h>

// WiFiの接続情報
const char* ssid = "SSID";
const char* password = "password";
const IPAddress ip(192, 168, 1, 60);
const IPAddress gateway(192, 168, 1, 1);
const IPAddress subnet(255, 255, 255, 0);
const IPAddress dns1(192, 168, 1, 1);

// 4-5番、1-2番ピンを使ってモーターを動かす
const int mot_04 = 4;
const int mot_05 = 5;
const int mot_01 = 1;
const int mot_02 = 2;

WebServer server(80);

void setup() {
  Serial.begin(115200);

  // WiFi設定
  if (!WiFi.config(ip, gateway, subnet, dns1)) {
    Serial.println("Failed to configure!");
  }
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    Serial.println("Connecting to WiFi...");
  }

  Serial.println("Connected to WiFi");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  // モーターピン設定
  pinMode(mot_04, OUTPUT);
  pinMode(mot_05, OUTPUT);
  pinMode(mot_01, OUTPUT);
  pinMode(mot_02, OUTPUT);

  // 初期値
  digitalWrite(mot_04, LOW);
  digitalWrite(mot_05, LOW);
  digitalWrite(mot_01, LOW);
  digitalWrite(mot_02, LOW);

  // Webサーバールート設定
  server.on("/", HTTP_GET, handleRoot);
  for (int i = 0; i < 4; i++) {
    server.on(("/toggle_45_" + String(i)).c_str(), HTTP_GET, [i]() { toggle45(i); });
    server.on(("/toggle_12_" + String(i)).c_str(), HTTP_GET, [i]() { toggle12(i); });
  }
  server.begin();
  Serial.println("Web server started!");
}

void loop() {
  server.handleClient();
}

void handleRoot() {
  Serial.println("Handling root page...");
  String html = "<!DOCTYPE html><html>";
  html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">";
  html += "<style>html { font-family: Helvetica; text-align: center;} .button { padding: 10px 20px; margin: 5px; }</style>";
  html += "</head><body>";
  html += "<h1>Motor Control</h1>";

  // 現在のパターンを表示
  html += "<h2>Current Patterns</h2>";
  html += "<p>4 and 5: " + getRealTimeState(mot_04, mot_05) + "</p>";
  html += "<p>1 and 2: " + getRealTimeState(mot_01, mot_02) + "</p>";

  // 4番、5番ピンの切り替えボタン
  html += "<h2>4 and 5 Control</h2>";
  for (int i = 0; i < 4; i++) {
    html += "<a href='/toggle_45_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>";
  }

  // 1番、2番ピンの切り替えボタン
  html += "<h2>1 and 2 Control</h2>";
  for (int i = 0; i < 4; i++) {
    html += "<a href='/toggle_12_" + String(i) + "'><button class='button'>Pattern " + String(i) + "</button></a>";
  }

  html += "</body></html>";
  server.send(200, "text/html", html);
}

void toggle45(int pattern) {
  Serial.print("Toggling 4 and 5 pins to pattern: ");
  Serial.println(pattern);
  digitalWrite(mot_04, pattern & 0x01); // 最下位ビット
  digitalWrite(mot_05, (pattern & 0x02) >> 1); // 2番目のビット
  server.sendHeader("Location", "/");
  server.send(303);
}

void toggle12(int pattern) {
  Serial.print("Toggling 1 and 2 pins to pattern: ");
  Serial.println(pattern);
  digitalWrite(mot_01, pattern & 0x01); // 最下位ビット
  digitalWrite(mot_02, (pattern & 0x02) >> 1); // 2番目のビット
  server.sendHeader("Location", "/");
  server.send(303);
}

String getRealTimeState(int pin1, int pin2) {
  String state1 = digitalRead(pin1) == HIGH ? "HIGH" : "LOW";
  String state2 = digitalRead(pin2) == HIGH ? "HIGH" : "LOW";
  return state1 + ", " + state2;
}

 

ブレッドボードを小さいサイズ2枚にしてマイコン部分とモーター部分を分けました。

ラジコン戦車 ブレッドボード配線

最初なかなか動かなかったのですが、自分がブレッドボードの使い方を間違っていました。

ブレッドボードの真ん中を境に、a-eとf-jまでの2系統だったようです。自分は、a-jまで1系統だと思い込んでしまって配線ができてなかったようです。

実際に動かして、WEBから固定IP経由でアクセスするとちゃんと動くようになりました。

ラジコン戦車

ESP32の端子、1、2番ピンと、4、5番ピンを使ってモーターの制御をしてみました。

戦車のモーター位置の関係で、4、5番ピンの位置を逆にしないと、車体が回転してしまいました。

これで、WEBから戦車を動かす事に成功しましたが、次回は、もっとシンプルに、前進、後進、右回転、左回転などのボタンを使って視覚的に戦車を制御してみたいと思います。

-電子工作
-, , , , , ,

Translate »
S