nichicon が 2020年12月28日10時40分16秒 に編集
コメント無し
本文の変更
スマホを使って操作できるラジコンを作りました。 ①材料 1. ESP-WROOM-02 x1 2. 3.3V1A出力のレギュレータ x1 3. 積層セラミックコンデンサー10uF x2 4. 抵抗10kΩ x2 5. 抵抗1kΩ x3 6. 小信号用ダイオード1N4148 x2 7. トランジスタ2SC3422 x2 8.サーボSG90 x1 9.タミヤ ツインモーターギヤボックス x1 ②回路図  ③プログラム ESP-WROOM-02の制御用プログラム #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h> ESP8266WebServer server(80); #define Right 12 #define Left 4 #define IRled 5 #define servo 13 #define servo_freq 50 #define servo_range 160 #define servo_center 25 #define servo_left 39 #define servo_right 11 int valueR, valueL ; #define POWER_SW 14 const char *ssid = "My_SSID"; const char *pass = "My_password"; #include "index_html2.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, timeOut = 0; int Val_C = 0; // Horn #ifdef POWER_SW void powerCnt(int sw) { pinMode(POWER_SW, OUTPUT); if (sw) { digitalWrite(POWER_SW, HIGH); return; } for (;;) { digitalWrite(POWER_SW, LOW); noInterrupts(); } } #else #define powerCnt(n) #endif 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 'C': if(Val_i == 5){ analogWrite(servo, servo_center) ; }else if(Val_i == 6){ analogWrite(servo, servo_left) ; }else if(Val_i == 7){ analogWrite(servo, servo_right) ; } break ; case 'R': valueR = Val_i ; break ; case 'L': valueL = Val_i ; break ; } if((valueR > 0)&&(valueL > 0)){ if(valueR < (valueL-10)){ digitalWrite(Right, LOW) ; digitalWrite(Left, HIGH) ; }else if(valueL < (valueR-10)){ digitalWrite(Right, HIGH) ; digitalWrite(Left, LOW) ; }else if((valueR == 0)&&(valueL == 0)){ digitalWrite(Right, LOW) ; digitalWrite(Left, LOW) ; }else{ digitalWrite(Right, HIGH) ; digitalWrite(Left, HIGH) ; } }else{ digitalWrite(Right, LOW) ; digitalWrite(Left, LOW) ; } } server.send(200, "text/plain", "\r\n\r\n\r\n"); } void setup(void) { Serial.begin(115200); analogWriteFreq(servo_freq) ; analogWriteRange(servo_range) ; pinMode(Right, OUTPUT) ; pinMode(Left, OUTPUT) ; pinMode(servo, OUTPUT) ; digitalWrite(Right, LOW) ; digitalWrite(Left, LOW) ; analogWrite(servo, servo_center) ; WiFi.softAP(ssid, pass); IPAddress myIP = WiFi.softAPIP(); server.on("/", []() { server.send(200, "text/html", index_html); }); server.on("/rc", handleRC); server.onNotFound(handleNotFound); server.begin(); } void loop(void) { server.handleClient(); delay(10); } スマホに表示する画面のプログラム const String index_html = "\ <!DOCTYPE html> \n\ <html lang='ja'> \n\ <head> \n\ <meta charset='UTF-8'> \n\ <meta name='viewport' content='width=320, initial-scale=1.0, user-scalable=no'> \n\ <title>Car Controller(JoyPad)</title> \n\ <style type='text/css'><!-- \n\ .div_CT { width:312px; text-align:center; } \n\ .btn_LX { width:100px; height:36px; text-align:center; padding:8px; border-radius:7px; background-color:#87cefa; } \n\ .btn_fire { width:250px; height:36px; text-align:center; padding:8px; border-radius:7px; background-color:#ff6347; } \n\ --></style> \n\ </head> \n\ \ <body> \n\ <div id='poss' class='div_CT'>--</div> \n\ <canvas id='canvas' width=312 height=312></canvas> \n\ <div class='div_CT'> \n\ <input id='ex_R' type=button class='btn_LX' onclick='Btn(6)' value='砲塔左'> \ <input id='ex_S' type=button class='btn_LX' onclick='Btn(5)' value='砲塔中央'> \ <input id='ex_S' type=button class='btn_LX' onclick='Btn(7)' value='砲塔右'> \ <input id='ex_S' type=button class='btn_fire' onclick='Btn(8)' value='射撃'> \ </div> \n\ <div id='send' class='div_CT'></div> \n\ \ <script type='text/javascript'> \n\ var poss = document.getElementById('poss'); \n\ var send = document.getElementById('send'); \n\ var canvas = document.getElementById('canvas'); \n\ var context = canvas.getContext('2d'); \n\ var sx = 9999, sy; \n\ var PI2 = (2 * Math.PI); \n\ var JPcr = (canvas.width / 2); \n\ var JPcx = JPcy = JPcr; \n\ var JPrr = 80; \n\ \ var cmd = 0, FLv = 0, CLv = 0, Rv = 0, Lv = 0; \n\ var xhr = new XMLHttpRequest(), reqSend = 0, reqRet = 0, idleCnt = 0; \n\ xhr.onreadystatechange = HttpRes; \n\ \ function HttpRes() { \n\ if (xhr.readyState == 4 && xhr.status == 200) reqRet = 0; \n\ } \n\ \ function HttpReq(v) { \n\ xhr.open('GET', '/rc?' + v); \n\ xhr.send(null); \n\ reqRet = 1; \n\ } \n\ \ function Btn(n) { \n\ cmd = n ; \n\ reqSend++; \n\ } \n\ \ canvas.addEventListener('touchend', function(e) { \n\ posg(0, 0); \n\ Rv = Lv = 0; \n\ reqSend = 3; \n\ }, false); \n\ \ canvas.addEventListener('touchmove', function(e) { \n\ e.preventDefault(); \n\ var xx = Math.floor(e.touches[0].pageX - canvas.offsetLeft); \n\ var yy = Math.floor(e.touches[0].pageY - canvas.offsetTop); \n\ context.beginPath(); \n\ context.arc(JPcx, JPcy, JPrr, 0, PI2, true); \n\ context.closePath(); \n\ if (!context.isPointInPath(xx, yy)) { \n\ var ratio = Math.sqrt(Math.pow(JPrr, 2) / (Math.pow(Math.abs(xx -= JPcx), 2) + Math.pow(Math.abs(yy -= JPcy), 2))); \n\ xx = (Math.floor((xx * ratio) + JPcx)); \n\ yy = (Math.floor((yy * ratio) + JPcy)); \n\ } \n\ posg((xx -= JPcx), (yy -= JPcy)); \n\ var mpower = Math.round(Math.sqrt(Math.pow(Math.abs(xx), 2) + Math.pow(Math.abs(yy), 2))); \n\ if ((yy > -16) && (yy < 16)) { \n\ Rv = ((xx < 0) ? mpower : -mpower); \n\ Lv = ((xx > 0) ? mpower : -mpower); \n\ } else { \n\ mpower = Math.floor((mpower < 16) ? 0 : ((yy > 0) ? (0 - mpower) : mpower)); \n\ Rv = Math.floor((xx < 0) ? mpower : (mpower - (mpower * Math.abs(xx) / JPrr))); \n\ Lv = Math.floor((xx > 0) ? mpower : (mpower - (mpower * Math.abs(xx) / JPrr))); \n\ } \n\ reqSend++; \n\ }, false); \n\ \ function posg(x, y) { \n\ if (sx == 9999) { \n\ context.strokeStyle = 'blue'; \n\ context.fillStyle = '#CED8F6'; \n\ context.lineWidth = 1; \n\ context.beginPath(); \n\ context.arc(JPcx, JPcy, (JPcr - 1), 0, PI2, true); \n\ context.fill(); \n\ context.stroke(); \n\ } else { \n\ context.fillStyle = '#CED8F6'; \n\ context.beginPath(); \n\ context.arc((sx + JPcx), (sy + JPcy), 72, 0, PI2, true); \n\ context.fill(); \n\ } \n\ context.strokeStyle = 'red'; \n\ context.fillStyle = 'pink'; \n\ context.lineWidth = 2; \n\ context.beginPath(); \n\ context.arc((x + JPcx), (y + JPcy), 70, 0, PI2, true); \n\ context.stroke(); \n\ context.fill(); \n\ poss.innerHTML = ((x == 0 && y == 0) ? '--' : ('X : ' + x + ', Y : ' + y)); \n\ sy = y; \n\ sx = x; \n\ } \n\ \ var timer = window.setInterval(function() { \n\ var vals = 'C=' + cmd + '&L=' + Lv + '&R=' + Rv; \n\ send.innerHTML = vals; \n\ if (reqSend) { \n\ cmd = 0; \n\ reqSend--; \n\ idleCnt = 0; \n\ } \n\ if (++idleCnt < ((20 * 1000) / 50)) { \n\ HttpReq(vals); \n\ } \n\ }, 50); \n\ \ posg(0, 0); \n\ </script> \n\ </body> \n\ </html>\n"; ④作り方 Arduino IDEでESP-WROOM-02にプログラム を書き込んで、基板に回路を作ったら制御基 板は完成です。 基板などが上手く入れば車体の形は自由なの で好きな形にしてください。 ⑤操作方法 
1. ラジコンの電源を入れて、スマホでSSIDと パスワードを入力し接続します。 2. スマホのブラウザで「192.168.4.1」を入力 し検索すると上の画像のように操作画面が 表示されます。 3. 赤い円を動かすとその向きに応じて直進、 右折、左折の動作をします。
1. ラジコンの電源を入れて、スマホでSSIDと パスワードを入力し接続します。 2. スマホのブラウザで「192.168.4.1」を入力 し検索すると上の画像のように操作画面が 表示されます。 3. 赤い円を動かすとその向きに応じて直進、 右折、左折の動作をします。
4. 円形のコントローラーの下にあるボタンを
押すと左、中央、右に砲塔を動かす事がで きます。 ※射撃ボタンには赤外線発射機能を付ける予 定でしたが不具合があるため取り除きまし
押すと左、中央、右に砲塔を動かす事がで きます。 ※射撃ボタンには赤外線発射機能を付ける予 定でしたが不具合があるため取り除きまし
た。なので押しても何も起こりません。