ESP-WROOM-02/32 Wi-Fi ラジコンカー(改)
ご注意:スマホの最新のブラウザではセンサー値取得が制限されているために使用できません、新しい記事「ESP-WROOM-02/32 Wi-Fi ラジコンカー(改2)」を検討してください(*- -)(*_ _)ペコリ
旧記事「ESP-WROOM-02 Wi-Fiラジコンカー」は、投稿日が「2015/09/15」とかなり古いですが、このブログ中では2番目に来訪者の多い記事です。(1番は「Scratch Boardを作る」です(^-^;)
旧記事は今でもそのままで動作しますが、久々に更新することにしました。
モータードライバーは、当時と変わらず安価で入手可能ですのでそのままにして、ソフトウェアを改訂します。
元記事では、スマホアプリや自作のリモコンでUPD通信を使って操作する方式でしたが、今回はスマホのジャイロセンサーを使って操作することにしました、ラジコンカーがWebサーバーとして動作し、スマホのブラウザから接続することになります。
(スマホは iPhone または Android)
本体への組込み
ソースファイル内のライト、警笛、左右のモータードライバへの接続にこの記事と異なるポートを使用する場合は、該当のポート番号を変更してください、また、複数台のラジコンカーを作る場合はそれぞれのSSIDを重複しないように変更してください。
これらの変更を行った後に、コンパイルして、ESP-WROOM-02またはESP-WROOM-32へ書込みます。
起動
本体は電源オンで、Wi-Fiアクセスポイントとして起動しますので、スマホで本体のSSID(ESPCar10)へパスワード(ESP12345)を入力して接続します。
接続できたら、スマホブラウザのURLに本体のIPアドレス(http://192.168.4.1)を入力して接続します。
スマホに操作画面が表示され、操作できるようになります。
操作方法
起動したときに表示される「四角の箱枠の中央にある赤い丸」がスマホを傾けることで傾けた方向に移動します、赤い丸が移動する方向に本体が移動します。
移動する速さや方向はスマホの傾きに連動していますので、傾きを変えて操作してください。
ほぼ水平にすると停止します。
「クラクション」ボタンは押すと本体に接続した圧電スピーカーを鼓動します。
「ライト」は本体に接続したLEDを点滅します、このボタンはトグル動作です。
*ライトはスマホとの通信が途絶えた場合には、0.5秒間隔で点滅します。
ESP-WROOM-02、ESP-WROOM-32での接続図は別記事にします。
ソースコード
ソースコードはこちらからダウンロードできます。
CarController.ino メイン
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 |
#ifdef ESP8266 #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> ESP8266WebServer server(80); #else #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> WebServer server(80); #endif const char *ssid = "ESPCar10"; const char *pass = "ESP12345"; #ifdef ESP32 #define LED_Light 32 #define LED_Hone 33 #define PWM_RF 27 #define PWM_RR 14 #define PWM_LF 12 #define PWM_LR 13 #else #define LED_Light 2 #define LED_Hone 15 #define PWM_RF 5 #define PWM_RR 13 #define PWM_LF 4 #define PWM_LR 12 #endif #define PWM_CH0 0 #define PWM_CH1 1 #define PWM_CH2 2 #include "index_html.h" void handleNotFound() { String message = "File Not Found\n\n" + server.uri() + " " + ((server.method() == HTTP_GET) ? "GET" : "POST") + "\nArguments: " + server.args() + "\n"; for (int i = 0; i < server.args(); i++) message += " " + server.argName(i) + ": " + server.arg(i) + "\n"; server.send(404, "text/plain", message); } int NoDat = 0; int Val_C = 0; // Horn void handleRC() { NoDat = 0; for (int i = 0; i < server.args(); i++) { int Val_i = server.arg(i).toInt(); Serial.print(server.argName(i) + "=" + server.arg(i) + ", "); switch (server.argName(i)[0]) { case 'F': digitalWrite(LED_Light, Val_i); break; case 'C': if (Val_C += Val_i) AnalogWrite(LED_Hone, 512, PWM_CH2); break; case 'R': AnalogWriteD(PWM_RF, PWM_RR, (Val_i * 16), PWM_CH0); break; case 'L': AnalogWriteD(PWM_LF, PWM_LR, (Val_i * 16), PWM_CH1); break; } } Serial.println(); server.send(200, "text/plain", "\n\n\n"); } void setup(void) { Serial.begin(115200); Serial.printf("\nStart\n"); pinMode(LED_Light, OUTPUT); digitalWrite(LED_Light, 0); pinMode(LED_Hone , OUTPUT); digitalWrite(LED_Hone , 0); pinMode(PWM_LF , OUTPUT); digitalWrite(PWM_LF , 0); pinMode(PWM_LR , OUTPUT); digitalWrite(PWM_LR , 0); pinMode(PWM_RF , OUTPUT); digitalWrite(PWM_RF , 0); pinMode(PWM_RR , OUTPUT); digitalWrite(PWM_RR , 0); WiFi.softAP(ssid, pass); IPAddress myIP = WiFi.softAPIP(); Serial.print("AP address: "); Serial.println(myIP); server.on("/", []() { server.send(200, "text/html", index_html); }); server.on("/rc", handleRC); server.onNotFound(handleNotFound); server.begin(); Serial.println("HTTP server started"); } void loop(void) { server.handleClient(); if (Val_C && --Val_C == 0) AnalogWrite(LED_Hone, 0, PWM_CH2); if (NoDat > 50) { AnalogWriteD(PWM_RF, PWM_RR, 0, PWM_CH0); AnalogWriteD(PWM_LF, PWM_LR, 0, PWM_CH1); AnalogWrite (LED_Hone, (Val_C = 0), PWM_CH2); digitalWrite(LED_Light, !digitalRead(LED_Light)); NoDat = 0; } else NoDat++; delay(10); } |
AnalogWrite.ino AnalogWrite 処理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
#define SWAP(a, b) { int c = a; a = b; b = c; } #ifdef ESP32 #define PWM_BITW 10 #define PWM_FREQ 500 const int pwmFreq[] = { PWM_FREQ, PWM_FREQ, PWM_FREQ, PWM_FREQ, PWM_FREQ, PWM_FREQ, -1 }; void AnalogWrite(int pin1, int pwm, int pwmCH) { AnalogWriteD(pin1, 0, pwm, pwmCH); } void AnalogWriteD(int pin1, int pin2, int pwm, int pwmCH) { static int sw = -1, pwmPin[4] = { -1, -1, -1, -1 }; if (sw == -1) for (sw = 0; (pwmFreq[sw] != -1); sw++) ledcSetup(sw, pwmFreq[sw], PWM_BITW); if (pwm < 0) SWAP(pin1, pin2); if (pwmPin[pwmCH] != pin1) { if (pin2 != 0) { ledcAttachPin(pin2, (pwmCH + 4)); ledcWrite((pwmCH + 4), 0); } ledcAttachPin((pwmPin[pwmCH] = pin1), pwmCH); } ledcWrite(pwmCH, (((pwm = abs(pwm)) > 1024) ? 1024 : pwm)); } #else void AnalogWrite(int pin1, int pwm, int pwmCH) { analogWrite(pin1, pwm); } void AnalogWriteD(int pin1, int pin2, int pwm, int pwmCH) { if (pwm < 0) SWAP(pin1, pin2); analogWrite(pin2, 0); analogWrite(pin1, (((pwm = abs(pwm)) > 1023) ? 1023 : pwm)); } #endif |
inde_html.h 操作画面の定義
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
const String index_html = "\ <!DOCTYPE html> \ <html lang='ja'> \ <head> \ <meta charset='UTF-8'/> \ <meta name='viewport' content='width=320, initial-scale=1.0, user-scalable=no'> \ <title>Car Controller</title> \ <style type='text/css'><!-- \ .btn_LX { width:124px; height: 36px; text-align:center; padding:8px; border-radius:7px; background-color:#CCCCCC; } \ --> \ </style> \ </head> \ <body> \ <div id='poss' style='color:black;'></div> \ <canvas id='cv' width=260 height=260></canvas> \ <div class=divCenter> \ <input type=button class='btn_LX' id='ex_R' onclick='Btn(8)' value='クラクション'> \ <input type=button class='btn_LX' id='ex_S' onclick='Btn(9)' value='ライト'> \ </div> \ \ <script type='text/javascript'> \ var xhr = new XMLHttpRequest(), reqSend = 0, reqRet = 0; \ xhr.onreadystatechange = HttpRes; \ function HttpRes() { \ if (xhr.readyState == 4 && xhr.status == 200) reqRet = 1; \ } \ \ function HttpReq(v) { \ xhr.open('GET', '/rc?' + v); \ xhr.send(null); \ reqRet = 0; \ } \ \ function nmn(n) { \ if (n > -5 && n < 5) return(0); \ if (n < -64) n = -64; \ if (n > 64) n = 64; \ return(n); \ } \ \ var vals = '', FLv = 0, CLv = 0, Rv = 0, Lv = 0; \ function Btn(n) { \ if (n == 8) { \ CLv = 20; \ reqSend++; \ } else if (n == 9) { \ FLv = ((FLv == 1) ? 0 : 1); \ document.getElementById('ex_S').style.backgroundColor = ((FLv) ? '#F0F8FF' : '#CCCCCC'); \ reqSend++; \ } \ } \ \ window.addEventListener('deviceorientation', (ev) => { \ var xx = nmn(Math.round(ev.beta )); \ var yy = nmn(Math.round(ev.gamma)); \ Rv = Lv = -xx; \ yy >>= 1; \ Rv -= yy; \ Lv += yy; \ document.getElementById('poss').innerHTML = '</br>X : ' + xx + ' , Y : ' + yy; \ posg(xx, yy); \ reqSend++; \ }); \ \ var sx = 1234, sy = 0; \ var ctx = document.getElementById('cv').getContext('2d'); \ function posg(x, y) { \ if (sx == 1234) { \ ctx.beginPath(); \ ctx.fillStyle = 'gray'; \ ctx.fillRect(0, 0, 260, 260); \ ctx.fill(); \ ctx.stroke(); \ } else { \ ctx.beginPath(); \ ctx.fillStyle = 'gray'; \ ctx.strokeStyle = 'gray'; \ ctx.lineWidth = 2; \ ctx.arc(130 + (sy * 4), 130 + (sx * 2), 18, 0, (Math.PI * 2), true); \ ctx.fill(); \ ctx.stroke(); \ } \ \ ctx.beginPath(); \ ctx.fillStyle = 'pink'; \ ctx.strokeStyle = 'red'; \ ctx.lineWidth = 2; \ ctx.arc(130 + (y * 4), 130 + (x * 2), 16, 0, (Math.PI * 2), true); \ ctx.fill(); \ ctx.stroke(); \ sy = y; \ sx = x; \ reqSend++; \ } \ \ var timer = window.setInterval(() => { \ vals = ''; \ if (reqSend > 0) { \ vals = 'F=' + FLv + '&C=' + CLv + '&L=' + Lv + '&R=' + Rv; \ CLv = 0; \ } \ reqSend = 0; \ HttpReq(vals); \ }, 50); \ \ posg(0, 0); \ </script> \ </body> \ </html>\n"; |
コメント:4
ESP-WROOM-02 Wi-Fiラジコンカー改2について聞きたいのですが、esp32でサイトのプログラムを使用し、ピンの割り当てをこのように変更し、
#define PWM_R 19 #define Dir_R 5 #define PWM_L 18 #define Dir_L 4(PWM_Rが右側のモータへpwm出力を送るためのピン、Dir_Rが右のモータの回転方向切り替えのためのピン、PWM_Lが左側のモータへpwm出力を送るためのピン、Dir_Lが左のモータの回転方向切り替えのためのピン)
実行してみたのですが、後退関連の動作(R.Lが負の値の時の動作)は正しく行われたのですが、前進関連の動作(R.Lが正の値の時の動作)ができなかったのですが、原因等わかりますでしょうか?
2023/01/23 @ 10:06 PM
rs より
ご参照ありがとうございます。
ソースコードを変更されているようですが、ご使用のモータードライバは「NJM2670D2」でしょうか?
私のソースコードは「NJM2670D2」を制御するように書かれていますので、異なるモータードライバを使用されるのであれば、そのモータードライバを使ったソースコードを探された方がよろしいかと思います。
お役に立てずに申し訳ありません。
2023/01/23 @ 11:41 PM
goji より
ご返信ありがとうございます。NJM2670D2ではないドライバを使用していますが、後退関連の動作はうまくいっており、あとは前進の際にも4.5番ピンを出力できるようにすれば、動きそうです。私のドライバを使ったソースコードがなかったため、こちらで頑張ってみます。
2023/01/23 @ 11:53 PM
rs より
DRV8835用に書き換えてみましたので差分をお送りします。
下記宛に空メールをお願いします。
goji2100@gmail.com(全部半角にしてください)
2023/01/24 @ 01:44 AM
goji より