Ganponブログ

趣味の模型作り、ドライブ、旅行など
since Mar.2017

M5Stamp PicoでRC可動戦車

2022-10-16 10:46:25 | RC可動コントロール

2022-10-16
模型製作の合間に手持ちのM5Stamp Pico(以下 Picoと称す)でアリイのリモコン戦車をRC化してみました。
砲塔旋回も砲身上下、リコイルなどしない走るだけの仕様です。



▼M5Stamp Pico
サイズは18 x 24 x 4.4 mmの小さなユニットですが、Wi-FiもBluetoothもできます 。

しかし、PS3コントローラとペアリングできません。
過去にPicoでRCカーを作ったのですが、今回は何か設定がおかしいようです。
PicoをPS3コントローラで無線操縦するスケッチ(プログラム)のポイントを忘れていました。
そんな訳で備忘録として書き留めておくことにしました。

ペアリングできない原因は、Arduino IDEでスケッチを書き込むとき、ボードの設定が違っています。
通常はPicoを使う時のボードはSTAMP-PICOで良いです。

しかし、どう言う訳かは判りませんが、PS3コントローラとペアリングさせるには
ESP32 Pico Kitを選定する必要が有ります。


私の場合、PS3コントローラのMACアドレスを書き換えて使用しています。
(あくまでも個人責任です。)
方法は、sixaxispairtool というツールで現在のアドレスの確認、書き換えができます。
PCとPS3コントローラが接続されている状態でSixaxisPairToolを起動すると現在のBlueToothアドレスが上に表示されます。



この様にPS3コントローラのMACアドレスを書き換え、スケッチの中でも同じアドレスを書き込んでおくと、一つのコントローラで違うユニットを動かす事が出来て便利です。
勿論ユニット(ESP32やPICO)の本来のMACアドレスは変更されていません。
あくまでもこのスケッチで動かしている間だけの暫定的なものです。

▼回路図



▼【スケッチ】

/*PS3_M5PICO_tank_DRV8835_basic01b
【操作手順】
PSボタンでペアリング。

【走行コントロール】
コントローラーの左スティック上下で前後進、
右スティックの左右でステアリングを制御。
ステアリングを振っていくと回転軸側が減速していき(緩旋回から信地旋回)、一杯に倒すと回転軸側は停止。(信地旋回)
左スティック中央で右ステアリングを一杯に振ると超信地旋回(速度80%)
*/

#include <Arduino.h> // Arduino ヘッダインクルード
#include "M5Atom.h"
#include <Ps3Controller.h>

#include <FastLED.h> // LED操作用ライブラリインクルード(3.5.0を使用)
#define NUM_LEDS 1
#define DATA_PIN 27
CRGB leds[NUM_LEDS];

int cnt = 0 ;
int motor_speed;
int steering;

int AIN1 = 22; // A入力1/APHASE 左モータ AIN1
int BIN1 = 21; // B入力1/BPHASE 右モータ BIN1
int PWMApin = 25; // A入力2/AENABLE 左モータ AIN2
int PWMBpin = 26; // B入力2/BENABLE 右モータ BIN2
int PWMA = 2; //PWMAチャンネル 0=NG 1=NG 0~15
int PWMB = 3; //PWMAチャンネル 0=NG 1=NG 0~15

int pos_y;
int pos_x;
int LED_8 = 19 ; // ブレーキランプ

void onConnect() {
Serial.println("Connected.");
for (int cnt = 0; cnt < 2; cnt++) {
digitalWrite(LED_8, HIGH);
delay(500);
digitalWrite(LED_8, LOW);
delay(500);
}
}

void setup() {
Serial.begin(115200);
M5.begin(false, false , true); //SerialEnable, I2CEnable ,DisplayEnable
FastLED.addLeds<SK6812, DATA_PIN, RGB>(leds, NUM_LEDS); // GRB ordering is typical
leds[0] = 0xf00000; //green
FastLED.show();

ledcSetup(PWMA, 5000, 8); //チャンネル,周波数,解像度(8bit=256段階)
ledcAttachPin(PWMApin, PWMA); //ledPinをPWMCHチャンネルに接続
ledcSetup(PWMB, 5000, 8); //チャンネル,周波数,解像度(8bit=256段階)
ledcAttachPin(PWMBpin, PWMB); //ledPinをPWMCHチャンネルに接続

//pinMode(PWMApin, OUTPUT);
//pinMode(PWMBpin, OUTPUT);
pinMode(AIN1, OUTPUT);
pinMode(BIN1, OUTPUT);
pinMode(LED_8, OUTPUT);

Ps3.attachOnConnect(onConnect);
Ps3.begin("00:11:22:33:44:55"); //SixaxisPairToolで変更したMACアドレスに修正
Serial.println("PS3 Ready");
}

void loop() {
if (Ps3.isConnected()) {
//走行コントロール
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 >= 117 && pos_x <= 137 && pos_y >= 117 && pos_y <= 137) {
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 = 165;
motor_run(motor_speed, 0, motor_speed, 1, 0);
}

//左超信地旋回
else if (pos_x <= 10 && pos_y >= 102 && pos_y <= 152) {
motor_speed = 165;
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
*/

ledcWrite(PWMA, D0); //(チャンネル,解像度)
digitalWrite(AIN1, D1);
ledcWrite(PWMB, D2); //(チャンネル,解像度)
digitalWrite(BIN1, D3);
digitalWrite(LED_8, D4);
}




ESP32 Dev ModuleでRC戦車コントロール(IR対戦仕様)

2022-06-08 22:40:35 | RC可動コントロール

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);
}
}

 

 
 

 

 


ESP32 Dev ModuleでRC可動戦車コントロール

2022-05-29 11:42:56 | RC可動コントロール

2002-05-29
前回、ArduinoでコントロールしていたものをM5Stamp PICOに換装する検討をしました。
結果、出力端子が足りないことも有って、RCカーで実現させました。
I2Cモータドライバを使用したり、子機と通信して対応すれば良さそうですが。。。。

今回はM5の親方に当たるESP32でRC可動戦車のコントロールを検討してみます。
プログラミングは使い慣れたArduino IDEを使用します。
利用できないライブラリーも有りますが、かなりの点でこれまで作ったスケッチが再利用できます。

▼画像上がESP32 Dev Modele、下がM5Stamp picoです。

▼ESP32をArduino IDEで使うための環境設定は他のブログなどを参照するとして、
ボードの設定は下記のとおりです。(細かな設定は変更していません)

▼ESP32にDCモータ2個、MP3プレーヤ、サーボモータ3個(1個は連続回転改造済み)を接続しています。
基板上にはDRV8835モータドライバ(秋月電子)、4個のLED、スイッチ、5V出力昇圧コンバータをセットしています。
電源は3.7v LiPoバッテリです。
MP3プレーヤはJQ6500を使っています。(スケッチは変更要ですがDFPlayer miniでも動作確認済みです)

▼回路図
画像をクリックすると拡大します

▼スケッチ(Arduino-IDE)
(注)文字化け対策として、"<" は"◀"、">"は"▶"として書き換えています。

/*PS3_ESP32_tank_JQ6500mp3_DRV8835_v6.0
*/

#include ◀Arduino.h▶ // Arduino ヘッダインクルード
//#include "SoftwareSerial.h"   // EspSoftwareSerial
//#include "DFRobotDFPlayerMini.h"
#include ◀JQ6500_Serial.h▶

//SoftwareSerial mySoftwareSerial(16, 17); // RX, TX  EspSoftwareSerial
HardwareSerial Serial_df(2); // use HardwareSerial UART2 (16pin=RX, 17pin=TX)
JQ6500_Serial mp3(Serial_df);

//DFRobotDFPlayerMini myDFPlayer;
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 = A5; //  A入力2/AENABLE 左モータ AIN2  IO33
int PWMBpin = A19; //  B入力2/BENABLE 右モータ BIN2 IO26 (IO0は起動時不安定)
int PWMA = 2;  //PWMAチャンネル 0=NG 1=NG 0~15
int PWMB = 3;  //PWMBチャンネル 0=NG 1=NG 0~15 


void  setup() {
  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);
  //mySoftwareSerial.begin(9600);
  Serial_df.begin(9600); // RX2 = 16, TX2 = 17
  mp3.reset();
  mp3.setVolume(22);

  //Ps3.begin("00:11:22:33:44:55"); //SixaxisPairToolで調べたmac adresに修正
  //Ps3.begin("0c:b8:15:f5:8a:a2");  // PS3-Eコントローラ ESP32-1
  Ps3.begin("0c:b8:15:f5:26:9a");  // PS3-Eコントローラ ESP32-2
  Serial.println("PS3 Ready");

  //if (!myDFPlayer.begin(mySoftwareSerial)) {  
  //Use softwareSerial to communicate with mp3.
  /* if (!myDFPlayer.begin(Serial_df)) {  
  //Use HardwareSerial to communicate with mp3.
     Serial.println(F("Unable to begin:"));
     Serial.println(F("1.Please recheck the connection!"));
     Serial.println(F("2.Please insert the SD card!"));
     while (true) {
       delay(0); // Code to compatible with ESP8266 watch dog.
     }
    }
    Serial.println(F("DFPlayer Mini online."));
    myDFPlayer.volume(20);  //Set volume value. From 0 to 30
  */

  ledcSetup(PWMA, 5000, 8);  //チャンネル,周波数,解像度(8bit=256段階)
  ledcAttachPin(PWMApin, PWMA); //ledPinをPWMCHチャンネルに接続
  ledcSetup(PWMB, 5000, 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);

  //myDFPlayer.play(3);  //エンジン始動
  mp3.playFileByIndexNumber(3);
  delay(2000);

}

void  loop() {
  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
      //digitalWrite(LED_5, HIGH);  //check
      //delay(100);
      //digitalWrite(LED_5, LOW);  //check
      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);
        //myDFPlayer.loop(5);  //Loop 5th mp3  アイドリング
        mp3.playFileByIndexNumber(5);
        mp3.setLoopMode(MP3_LOOP_ONE);
        delay(d_time);
      } else {
        //myDFPlayer.disableLoop();    //アイドリング停止
        mp3.setLoopMode(MP3_LOOP_ONE_STOP);
        s = 0;
        delay(500);
      }
    }

    if (Ps3.event.button_down.r3) {
      //myDFPlayer.disableLoop();    //アイドリング停止
      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);  //主砲発光
      //myDFPlayer.play(26);
      mp3.playFileByIndexNumber(26);
      delay(100);
      servo3.write(angle_servo3 - 30);  // 砲身リコイル
      delay(20);
      motor_run(180, 1, 180, 1, 1);  // 車体リコイル
      delay(80);
      motor_run(0, 0, 0, 0, 1);
      for (int ang3 = (angle_servo3 - 30); ang3 ◀= angle_servo3; ang3 += 1 ) {
        servo3.write(ang3);
        delay(20);
      }
      digitalWrite(LED_3, LOW);
      motor_run(60, 0, 60, 0, 1);
      delay(290);
      motor_run(0, 0, 0, 0, 1);
      delay(100);
      if (s == 1) {
        //myDFPlayer.loop(5);  //Loop 5th mp3  アイドリング
        mp3.playFileByIndexNumber(5);
        mp3.setLoopMode(MP3_LOOP_ONE);
        delay(d_time);
      }
    }

    if (Ps3.event.button_down.l1) {   //銃撃
      //myDFPlayer.play(24);
      mp3.playFileByIndexNumber(24);
      delay(100);
      for ( k = 0; k ◀ 6; k++) {
        digitalWrite(LED_4, HIGH);   //発光
        delay(80);
        digitalWrite(LED_4, LOW);
        delay(120);
      }
      if (s == 1) {
        //myDFPlayer.loop(5);  //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);
  }
}

 

 

 

▼私が購入した物(VKLSVAN 2個セット JQ6500:現在在庫切れ)ではないですが。。。。

 


ミニ四駆 ランドクルーザー 製作&RC化 (M5Stamp PICO編)

2022-05-16 22:00:37 | RC可動コントロール

2022-05-16

またまた寄り道です。

▼下記ブログでで書いた様にRC化の新しいツールを勉強中です。
いろいろ試している中で、何とかRCカーに利用できるところまでできました。

 

1/72 T-2 ブルーインパルス 製作(その3) - Ganponブログ

2022-05-11早い方なら1日で完成させる1/72ジェット機ですが、あまり進んでおりません。まさに牛の歩みです。▼主翼と水平尾翼を取付け、接合部を均し、不要な穴(赤丸)をイ...

goo blog

 

 

▼という事で、2年前にArduino pro miniで完成しているミニ四駆ランクルに換装しました。

 

「RC化ミニ四駆」のブログ記事一覧-Ganponブログ

「RC化ミニ四駆」のブログ記事一覧です。趣味の模型作り、ドライブ、旅行などsince Mar.2017【Ganponブログ】

goo blog

 

▼画像の上がArduino pro mini+ミニUSBホストシールド(Bluetooth USBアダプタ装着)、
下がM5Stamp PICOです。

▼M5Stamp PICOをセット。

換装して動作確認すると動かない。
プログラムや接続などチェックすると、リード線がはんだ付け部であちこち切れていました。
こんな事を繰り返して、やっと完成。

以下に、備忘録としてプログラムと回路を残します。

 

【スケッチを書き込む準備】

(注1)サーボを制御するために「ESP32Servo.h」をインストール。

(注2)ESP32ライブラリV1.0.4をインストール。

(注3)下記スケッチをM5Stamp PICOに書き込み実行。

void setup(void) {
Serial.begin(115200);
uint8_t btmac[6];
delay(500);
esp_read_mac(btmac, ESP_MAC_BT);
Serial.printf("[Bluetooth] Mac Address = %02X:%02X:%02X:%02X:%02X:%02X\r\n", btmac[0], btmac[1], btmac[2], btmac[3], btmac[4], btmac[5]);
}
void loop() {
}

シリアルモニタにアドレスが表示されるのでメモしておく。

次に、SixaxisPairTool でPS3のコントローラにMac Addressを書き込む
1. PS3コントローラをMiniUSBケーブルでPCに繋ぐ。
2. SixaxisPairToolを実行し、メモしたアドレスを入力してUpdateボタンを押すと書き込みが完了。

(参考)「ESP32でPS3コントローラを使う」をキーにネット検索すると参考になる記述が見つかります。

 

▼スケッチ(プログラム)/Arduino IDE用

(注)gooブログの文字化け対策: 「◀」は「<」に、「▶」は「>」に置換してください。

 

#include ◀Arduino.h▶ // Arduino ヘッダインクルード
#include "M5Atom.h"

#include ◀FastLED.h▶ // LED操作用ライブラリインクルード(3.5.0を使用)
#define NUM_LEDS 1
#define DATA_PIN 27
CRGB leds[NUM_LEDS];

#include ◀Ps3Controller.h▶

#include ◀ESP32Servo.h▶
Servo servo1; // create four servo objects
int servo1Pin = 26;
int servo_pos = 90;
int ang = 40;

int d_time = 10;
float ratio = 0.6;
int pos_y;
int pos_x;
float motor_speed;
float steering;

int PWMApin = 25; // A入力2/AENABLE 左モータ AIN2
int PWMA = 11; //PWMAチャンネル 11
int AIN1 = 22; // A入力1/APHASE 左モータ AIN1

int LED_3 = 19 ; // ブレーキランプ
int LED_2 = 18 ; // フォグランプ
int LED_8 = 21 ; // ヘッドランプ

void onConnect() {
Serial.println("Connected.");
for (int cnt=0; cnt ◀ 2; cnt++) {
digitalWrite(LED_8,HIGH);
delay(500);
digitalWrite(LED_8,LOW);
delay(500);
}
}

void setup() {
Serial.begin(115200);
M5.begin(false, false , true); //SerialEnable, I2CEnable ,DisplayEnable
//M5.begin(true, false, true); //SerialEnable, I2CEnable ,DisplayEnable
FastLED.addLeds◀SK6812, DATA_PIN, RGB▶(leds, NUM_LEDS); // GRB ordering is typical
leds[0] = 0xf00000; //green

ledcSetup(PWMA, 5000, 8); //チャンネル,周波数,解像度(8bit=256段階)
ledcAttachPin(PWMApin, PWMA); //ledPinをPWMCHチャンネルに接続

pinMode(AIN1, OUTPUT);
pinMode(LED_2, OUTPUT);
pinMode(LED_3, OUTPUT);
pinMode(LED_8, OUTPUT);

servo1.setPeriodHertz(50); // Standard 50hz servo PWMサイクル:20mS
servo1.attach(servo1Pin, 500, 2400); // (servo1Pin, minUs, maxUs)
servo1.write(servo_pos);

Ps3.attachOnConnect(onConnect);
Ps3.begin("00:11:22:33:44:55"); // PS3コントローラ BlueTooth Mac Address
//SixaxisPairToolで調べたCurrent Masterの値に置き換える
Serial.println("Ready");
}

void loop() {
if (Ps3.isConnected()) {
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 (Ps3.event.button_down.triangle) {
ratio = 1; //高速モード
}

if (Ps3.event.button_down.cross) {
ratio = 0.7; //低速モード
}

if (pos_x ▶= 152 ) { // R
steering = map(pow(pos_x, 2), 23104, 65025, 0, 55 );
servo1.write(servo_pos - steering);
} else {
if (pos_x ◀= 103 ) { //L
steering = map(pow(pos_x, 2), 10609, 0, 0, 55 );
servo1.write(servo_pos + steering);
}
else {
servo1.write(servo_pos);
}
}

//左スティックがセンター付近は停止(ブレーキ)
if ( pos_y ▶ 117 && pos_y ◀ 137 ) {
motor_run(0, 0, 1);
}

//前進
else if (pos_y
//左スティック中央(117)から最上部(0)の値をモーターのスピード0から255に変換
motor_speed = ratio * map(pow(pos_y, 2), 13689, 0, 0, 255 );
motor_run(motor_speed, 1, 0);
}

//後進
else if ( pos_y ▶ 137) {
//motor_speed = ratio * map(pos_y, 137, 255, 0, 255);
motor_speed = ratio * map(pow(pos_y, 2), 18769, 65025, 0, 255 );
motor_run(motor_speed, 0, 0);
}

//ヘッドライト
if (Ps3.event.button_down.right) { //点灯
digitalWrite(LED_8, HIGH);
}

if (Ps3.event.button_down.left) { //消灯
digitalWrite(LED_8, LOW);
}

//フォグランプ
if (Ps3.event.button_down.up) { //点灯
digitalWrite(LED_2, HIGH);
}

if (Ps3.event.button_down.down) { //消灯
digitalWrite(LED_2, LOW);
}
}
}


void motor_run(float D0, int D1, int D4) {
/* D0 : モータスピード(左)
D1 : モータA(左)1 = HIGH / 0 = LOW
D4 : LED_3 ON/OFF 1 = HIGH / 0 = LOW
*/
//analogWrite(PWMA, D0);
ledcWrite(PWMA, D0); //(チャンネル,解像度)
digitalWrite(AIN1, D1);
digitalWrite(LED_3, D4);
}


 

▼回路図

画像をクリックすると拡大します

▼Arduino IDE ボードの設定