2022-06-08
ESP32 Dev ModuleでRC可動戦車コントロールの第2段、今回はIR対戦仕様の実験です。
Arduino用に作成したスケッチをESP32用に変更します。
ESP32用のIR送受信のライブラリは IRremoteESP8266.h を使います。
コマンドは少し変更するだけで利用できました。
注意が必要なのは、自分の送信した赤外線信号の反射を誤受信しない様に、
送信の前後は受信中止にしておくことが必要ということです。
Arduino用は受信再開コマンドだけでよかったのですが、ESP32用は受信中止コマンドも必要でした。
▼M26実装基板と同じ形に組上げました。
左下がモータドライバーDVR8835(秋月電子)、右下は5V出力DC昇圧コンバータ(Amazon)。
ESP32の左側にJQ6500(MP3プレーヤー)のUSBコネクタが覗いています。
▼ギヤードモータx2、サーボモータx3(内1個は連続回転仕様)、
LED、赤外線LED、赤外線受光素子、スピーカなどを接続。
▼IR対戦用送受信チェッカ
▼テスト機器全景
▼実験中の動画です。
追伸:画像撮影後ですが、技適取得済の正規PS3コントローラの中古を○○カリで入手しました。
▼回路
回路図中でブレーキ、ヘッドライトのLEDは1個で書いてありますが、
実態は太線枠内の様に左右2個です。
IR発光LEDの電流はトランジスタ(2SC1815など)を介して増幅しています。
▼スケッチ(プログラム)
文字化けするので、「<」は「◀」、「>」は「▶」で表示しています。
/*PS3_ESP32_tank_JQ6500mp3_DRV8835_IR_v6.0a 2022-06-07 【操作方法】 PS3コントローラで操縦します。 車体の電源をONし、コントローラのPSボタンでペアリング開始。 インジケータランプ4個高速点滅後に1個点灯でペアリング完了。 コントローラーの左スティック上下で前後進、右スティックの左右でステアリングを制御。 ステアリングを切っていくと緩旋回、一杯切るとで信地旋回する。 また、左スティック中央でステアリング左右一杯で超信地旋回。 △ボタンで砲身UP、✕ボタンで砲身DOWN、□ボタンでセンター位置になる。 左スティック左右で砲塔旋回。離した位置で止まる。 R1ボタンで主砲発射。L1ボタンで機銃射撃。 RIGHTボタンでヘッドライト点灯、LEFTボタンで消灯。 砲撃時のリコイルアクション車体+砲身 IR発光、受光装置を付けるとIR対戦可能。 メインCPU: ESP32 DevKitC モータドライバ:DRV8835 MP3プレイヤー:JQ6500 MP3プレイヤーモジュール */ #include ◀Arduino.h▶ // Arduino ヘッダインクルード #include ◀JQ6500_Serial.h▶ #include ◀IRremoteESP8266.h▶ #include ◀IRsend.h▶ const uint16_t kIrLed = 4; //IRsend Pin IRsend irsend(kIrLed); // Set the GPIO to be used to sending the message. uint16_t rawData[5] = {4150, 1000, 2050, 2000, 1000}; #include ◀IRrecv.h▶ #include ◀IRutils.h▶ const uint16_t kRecvPin = 13; IRrecv irrecv(kRecvPin); decode_results results; //結果格納変数 //const long sign_hit = 0x4CB0FADD; const uint32_t value = 0x4CB0FADD; HardwareSerial Serial_df(2); // use HardwareSerial UART2 (16pin=RX, 17pin=TX) JQ6500_Serial mp3(Serial_df); void printDetail(uint8_t type, int value); #include ◀Ps3Controller.h▶ #include ◀ESP32Servo.h▶ Servo servo1; // create four servo objects int servo1Pin = 27; Servo servo2; int servo2Pin = 14; Servo servo3; int servo3Pin = 12; int LED_1 = 23; //ブレーキランプ int LED_2 = 22; //ヘッドライト int LED_3 = 19; //砲撃 int LED_4 = 18; //銃撃 int k = 0; int s = 0; int d_time = 100; int angle_servo1 = 90; // 上下 int anglenow = angle_servo1 ; int angle_servo3 = 90; // リコイル int motor_speed; float steering; int pos_y; int pos_x; int pos_lx; int AIN1 = 32; // A入力1/APHASE 左モータ AIN1 int BIN1 = 25; // B入力1/BPHASE 右モータ BIN1 int PWMApin = 33; //A5; // A入力2/AENABLE 左モータ AIN2 IO33 A5 int PWMBpin = 26; //A19; // B入力2/BENABLE 右モータ BIN2 IO26 (IO0は起動時不安定)A19 int PWMA = 2; //PWMAチャンネル 0=NG 1=NG 0~15 int PWMB = 3; //PWMBチャンネル 0=NG 1=NG 0~15 int cnt = 0; void setup() { irsend.begin(); irrecv.enableIRIn(); // Start the receiver servo1.setPeriodHertz(50); // Standard 50hz servo PWMサイクル:20mS servo1.attach(servo1Pin, 500, 2400); // (servo1Pin, minUs, maxUs) servo2.setPeriodHertz(50); // Standard 50hz servo PWMサイクル:20mS servo2.attach(servo2Pin, 900, 2100); // (servo1Pin, minUs, maxUs) servo3.setPeriodHertz(50); // Standard 50hz servo PWMサイクル:20mS servo3.attach(servo3Pin, 500, 2400); // (servo1Pin, minUs, maxUs) Serial.begin(115200); Serial_df.begin(9600); // RX2 = 16, TX2 = 17 mp3.reset(); mp3.setVolume(22); Ps3.begin("00:11:22:33:44:55"); //SixaxisPairToolで調べたmac addressに修正 Serial.println("PS3 Ready"); ledcSetup(PWMA, 12000, 8); //チャンネル,周波数,解像度(8bit=256段階) ledcAttachPin(PWMApin, PWMA); //ledPinをPWMCHチャンネルに接続 ledcSetup(PWMB, 12000, 8); //チャンネル,周波数,解像度(8bit=256段階) ledcAttachPin(PWMBpin, PWMB); //ledPinをPWMCHチャンネルに接続 pinMode(AIN1, OUTPUT); pinMode(BIN1, OUTPUT); pinMode(LED_1, OUTPUT); pinMode(LED_2, OUTPUT); pinMode(LED_3, OUTPUT); pinMode(LED_4, OUTPUT); LEDtenmetsu(LED_2); servo1.write(angle_servo1); // 0 - 180 delay(100); servo2.write(90); // 0 - 180 delay(100); servo3.write(angle_servo3); // 0 - 180 delay(100); //エンジン始動 mp3.playFileByIndexNumber(3); delay(2000); } void loop() { //被弾チェック HitCHK(); if (Ps3.isConnected()) { pos_lx = Ps3.data.analog.stick.lx; pos_lx = pos_lx + 128; //砲塔旋回 if ( pos_lx ▶ 230) { //右旋回 servo2.write(80); } else if (pos_lx ◀ 25) { //左旋回 servo2.write(100); } else { //停止 servo2.write(90); } //砲身上下 if ( Ps3.event.button_down.square) { // center if (anglenow ▶ 90) { for (anglenow = anglenow; anglenow ▶= 90; anglenow -= 1) { servo1.write(anglenow); delay(40); } //delay(100); } else { for (anglenow = anglenow; anglenow ◀= 90; anglenow += 1) { servo1.write(anglenow); delay(40); } //delay(100); } } if ( Ps3.event.button_down.triangle) { // up for (anglenow = anglenow; anglenow ◀= 135; anglenow += 1 ) { servo1.write(anglenow); delay(40); } //delay(100); } if ( Ps3.event.button_down.cross) { // down for (anglenow = anglenow; anglenow ▶= 45; anglenow -= 1 ) { servo1.write(anglenow); delay(40); } //delay(100); } if (Ps3.event.button_down.circle) { if (s == 0) { s = 1; //myDFPlayer.play(3); //エンジン始動 mp3.playFileByIndexNumber(3); delay(2000); mp3.playFileByIndexNumber(5); mp3.setLoopMode(MP3_LOOP_ONE); delay(d_time); } else { //アイドリング停止 mp3.setLoopMode(MP3_LOOP_ONE_STOP); s = 0; delay(500); } } if (Ps3.event.button_down.r3) { //アイドリング停止 mp3.setLoopMode(MP3_LOOP_ONE_STOP); s = 0; } if (Ps3.event.button_down.right) { digitalWrite(LED_2, HIGH); // Headlight ON } if (Ps3.event.button_down.left) { digitalWrite(LED_2, LOW); // Headlight off } if (Ps3.event.button_down.r1) { //砲撃 + リコイル(砲身&車体) digitalWrite(LED_3, HIGH); //主砲発光 fire(); mp3.playFileByIndexNumber(26); delay(50); servo3.write(angle_servo3 - 30); // 砲身リコイル delay(20); motor_run(180, 1, 180, 1, 1); // 車体リコイル delay(80); motor_run(0, 0, 0, 0, 1); digitalWrite(LED_3, LOW); for (int ang3 = (angle_servo3 - 30); ang3 ◀= angle_servo3; ang3 += 1 ) { servo3.write(ang3); delay(20); } motor_run(60, 0, 60, 0, 1); delay(290); motor_run(0, 0, 0, 0, 1); delay(100); if (s == 1) { //Loop 5th mp3 アイドリング mp3.playFileByIndexNumber(5); mp3.setLoopMode(MP3_LOOP_ONE); delay(d_time); } } if (Ps3.event.button_down.l1) { //銃撃 mp3.playFileByIndexNumber(24); //delay(20); for ( k = 0; k ◀ 6; k++) { digitalWrite(LED_4, HIGH); //発光 delay(80); digitalWrite(LED_4, LOW); delay(120); } if (s == 1) { //Loop 5th mp3 アイドリング mp3.playFileByIndexNumber(5); mp3.setLoopMode(MP3_LOOP_ONE); delay(d_time); } } //走行コントロール pos_y = Ps3.data.analog.stick.ly; pos_x = Ps3.data.analog.stick.rx; pos_y = pos_y + 128; pos_x = pos_x + 128; /* //左スティックがセンター付近は停止(ブレーキ) if (pos_x ▶ 102 && pos_x ◀ 152 && pos_y ▶ 102 && pos_y ◀ 152) { motor_run(0, 0, 0, 0, 1); } */ //前進 if (pos_y ◀= 102 && pos_x ▶= 102 && pos_x ◀= 152) { motor_speed = map(pos_y, 102, 0, 0, 255); motor_run(motor_speed, 0, motor_speed, 0, 0); } //後進 else if ( pos_y ▶= 152 && pos_x ▶= 102 && pos_x ◀= 152) { motor_speed = map(pos_y, 152, 255, 0, 255) ; motor_run(motor_speed, 1, motor_speed, 1, 0); } //前進右緩旋回、信地旋回 //else if ( pos_y ◀= 102 && pos_x ▶ 152 && pos_x ◀= 245) { else if ( pos_y ◀= 102 && pos_x ▶= 152) { motor_speed = map(pos_y, 102, 0, 0, 255); steering = motor_speed * (1.00 - (map(pos_x, 152, 255, 0, 255) / 255.00)); motor_run(motor_speed, 0, steering, 0, 0); } //前進左緩旋回、信地旋回 //else if ( pos_y ◀= 102 && pos_x ◀ 102 && pos_x ▶= 10) { else if ( pos_y ◀= 102 && pos_x ◀= 102) { motor_speed = map(pos_y, 102, 0, 0, 255); steering = motor_speed * (1.00 - (map(pos_x, 102, 0, 0, 255) / 255.00)); motor_run(steering, 0, motor_speed, 0, 0); } //後進右緩旋回、信地旋回 //else if ( pos_y ▶= 152 && pos_x ▶ 152 && pos_x ◀= 245) { else if ( pos_y ▶= 152 && pos_x ▶= 152 ) { motor_speed = map(pos_y, 152, 255, 0, 255); steering = motor_speed * (1.00 - (map(pos_x, 152, 255, 0, 255) / 255.00)); motor_run(motor_speed, 1, steering, 1, 0); } //後進左緩旋回、信地旋回 //else if ( pos_y ▶= 152 && pos_x ◀ 102 && pos_x ▶= 10) { else if ( pos_y ▶= 152 && pos_x ◀= 102 ) { motor_speed = map(pos_y, 152, 255, 0, 255); steering = motor_speed * (1.00 - (map(pos_x, 102, 0, 0, 255) / 255.00)); motor_run(steering, 1, motor_speed, 1, 0); } //右超信地旋回 else if (pos_x ▶= 245 && pos_y ▶= 102 && pos_y ◀= 152) { motor_speed = 204; motor_run(motor_speed, 0, motor_speed, 1, 0); } //左超信地旋回 else if (pos_x ◀= 10 && pos_y ▶= 102 && pos_y ◀= 152) { motor_speed = 204; motor_run(motor_speed, 1, motor_speed, 0, 0); } else { //停止(ブレーキ) motor_run(0, 0, 0, 0, 1); } } } void motor_run(int D0, int D1, int D2, int D3, int D4) { //D0 : モータスピード(左) //D1 : モータA(左)1 = HIGH / 0 = LOW //D2 : モータスピード(右) //D3 : モータB(右)1 = HIGH / 0 = LOW //D4 : LED_3 ON/OFF 1 = HIGH / 0 = LOW //analogWrite(PWMA, D0); ledcWrite(PWMA, D0); //(チャンネル,解像度) digitalWrite(AIN1, D1); //analogWrite(PWMB, D2); ledcWrite(PWMB, D2); //(チャンネル,解像度) digitalWrite(BIN1, D3); digitalWrite(LED_1, D4); } void LEDtenmetsu(int LED) { for (int i = 0; i ◀ 2; i++) { digitalWrite(LED, HIGH); delay(500); digitalWrite(LED, LOW); delay(500); } } void fire() { irrecv.disableIRIn(); // 自らの送信を誤受信しないように受信を停止 irsend.sendRaw(rawData, 5, 38); //irsend.sendRaw(data buf, length, hertz) delay(50); irrecv.enableIRIn(); // 受信を再開する } void HitCHK() { if (irrecv.decode(&results)) { // 受信コードの値が if (results.value == value) { // 0x4CB0FADDだったら被弾 mp3.playFileByIndexNumber(17); Hit(); //被弾 } irrecv.resume(); delay(500); } } // ====被弾==== void Hit() { motor_run(180, 1, 180, 0, 0); delay(100); motor_run(0, 0, 0, 0, 1); delay(50); motor_run(180, 0, 180, 1, 0); delay(80); motor_run(0, 0, 0, 0, 1); delay(50); cnt++; if ( cnt ▶= 5 ) { mp3.playFileByIndexNumber(18); motor_run(0, 0, 0, 0, 0); for ( int i = 0; i ◀ 15 ; i++) { digitalWrite(LED_2, HIGH); delay(1000); digitalWrite(LED_2, LOW); delay(1000); } //復活までに15秒 cnt = 0; } else { delay(1000); } } |
※コメント投稿者のブログIDはブログ作成者のみに通知されます