プロジェクト 18: BT スピードコントロールロボット

(1)説明:

前のプロジェクトでは、Bluetooth を使用してスマートタンクを制御する方法を学びました。前で使用したモーターの PWM 値は 200 でした(速度は 200)。

このレッスンでは、Bluetooth を使用してスマートカーの速度を調整します。200 の固定速度に限定されません。左右のモーターの速度値をそれぞれ格納するために 2 つの変数を定義します。これまでの学習を通じて、この値の範囲は 0 から 255 までしか取れないことがわかっています。

(2)フローチャート:

(3)接続図:

8x16 LED ドットマトリクスの GND、VCC、SDA、SCL はそれぞれ拡張ボードの -(GND)、+(VCC)、SDA、SCL に接続されています。

(4)テストコード:

(注意: コードをアップロードする際は、Bluetooth モジュールを必ず取り外してください。アップロード完了後に Bluetooth を再接続できます。そうしないとコードが書き込めない場合があります。)

/*
  Keyestudio Mini Tank Robot V3 (Popular Edition)
  lesson 18
  bluetooth control speed tank
  http://www.keyestudio.com
*/

// 配列:画像データの保存に使用。自分で計算するかモジュールツールから取得できます
unsigned char start01[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
unsigned char front[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x12, 0x09, 0x12, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char back[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x48, 0x90, 0x48, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char left[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x28, 0x10, 0x44, 0x28, 0x10, 0x44, 0x28, 0x10, 0x00};
unsigned char right[] = {0x00, 0x10, 0x28, 0x44, 0x10, 0x28, 0x44, 0x10, 0x28, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char STOP01[] = {0x2E, 0x2A, 0x3A, 0x00, 0x02, 0x3E, 0x02, 0x00, 0x3E, 0x22, 0x3E, 0x00, 0x3E, 0x0A, 0x0E, 0x00};
unsigned char clear[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
unsigned char speed_a[] = {0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0xff, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00, 0x00};
unsigned char speed_d[] = {0x00, 0x00, 0x00, 0x04, 0x08, 0x10, 0x20, 0x40, 0xff, 0x40, 0x20, 0x10, 0x08, 0x04, 0x00, 0x00};
#define SCL_Pin  A5  // クロックのピンを A5 に設定
#define SDA_Pin  A4  // データピンを A4 に設定

#define ML_Ctrl 4  // 左モーターの方向制御ピンを定義
#define ML_PWM 6   // 左モーターの PWM 制御ピンを定義
#define MR_Ctrl 2  // 右モーターの方向制御ピンを定義
#define MR_PWM 5   // 右モーターの PWM 制御ピンを定義
char ble_val;      // 右モーターの PWM 制御ピンを定義
byte speeds_L = 200; // 左モーターの初期速度は 200
byte speeds_R = 200; // 右モーターの初期速度は 200
String speeds_l, speeds_r; // PWM の文字列を受信して整数の PWM 値に変換する

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

  pinMode(ML_Ctrl, OUTPUT);
  pinMode(ML_PWM, OUTPUT);
  pinMode(MR_Ctrl, OUTPUT);
  pinMode(MR_PWM, OUTPUT);

  pinMode(SCL_Pin, OUTPUT);
  pinMode(SDA_Pin, OUTPUT);
  matrix_display(clear); // 画面をクリア
  matrix_display(start01);  // スタート画像を表示
}

void loop() 
{
  if (Serial.available() > 0) 
  {
    ble_val = Serial.read();
    Serial.println(ble_val);
    switch (ble_val) 
    {
      case 'F':  // 前進コマンド
        Car_front();
        break;
      case 'B':  // 後退コマンド
        Car_back();
        break;
      case 'L':  // 左折コマンド
        Car_left();
        break;
      case 'R':  // 右折コマンド
        Car_right();
        break;
      case 'S':  // 停止コマンド
        Car_Stop();
        break;
      case 'u':  // u で始まり # で終わる文字列を受信し、整数値に変換する
        speeds_l = Serial.readStringUntil('#');
        speeds_L = String(speeds_l).toInt();
        break;
      case 'v':  // v で始まり # で終わる文字列を受信し、整数値に変換する
        speeds_r = Serial.readStringUntil('#');
        speeds_R = String(speeds_r).toInt();
        break;
    }
  }
}

/***************モーターを動かす関数***************/

void Car_back() 
{
  digitalWrite(MR_Ctrl, LOW);
  analogWrite(MR_PWM, speeds_R);
  digitalWrite(ML_Ctrl, LOW);
  analogWrite(ML_PWM, speeds_L);
  matrix_display(back);  // 後退
}

void Car_front() 
{
  digitalWrite(MR_Ctrl, HIGH);
  analogWrite(MR_PWM, 255 - speeds_R);
  digitalWrite(ML_Ctrl, HIGH);
  analogWrite(ML_PWM, 255 - speeds_L);
  matrix_display(front);  // 前進画像を表示
}

void Car_left() 
{
  digitalWrite(MR_Ctrl, HIGH);
  analogWrite(MR_PWM, 255 - speeds_R);
  digitalWrite(ML_Ctrl, LOW);
  analogWrite(ML_PWM, speeds_L);
  matrix_display(left);  // 左折画像を表示
}

void Car_right() 
{
  digitalWrite(MR_Ctrl, LOW);
  analogWrite(MR_PWM, speeds_R);
  digitalWrite(ML_Ctrl, HIGH);
  analogWrite(ML_PWM, 255 - speeds_L);
  matrix_display(right);  // 右折画像を表示
}

void Car_Stop() 
{
  digitalWrite(MR_Ctrl, LOW);
  analogWrite(MR_PWM, 0);
  digitalWrite(ML_Ctrl, LOW);
  analogWrite(ML_PWM, 0);
  matrix_display(STOP01);  // 停止画像を表示
}

// ドットマトリクス画面表示に使用する関数
void matrix_display(unsigned char matrix_value[])
{
  IIC_start();  // データ転送開始条件を呼び出す関数
  IIC_send(0xc0);  // アドレスを選択
  for (int i = 0; i < 16; i++) // パターンデータは 16 バイト
  {
    IIC_send(matrix_value[i]); // パターンデータを転送
  }
  IIC_end();   // パターンデータ転送を終了
  IIC_start();
  IIC_send(0x8A);  // 表示制御、パルス幅を 4/16 に選択
  IIC_end();
}

// データ転送開始の条件
void IIC_start()
{
  digitalWrite(SDA_Pin, HIGH);
  digitalWrite(SCL_Pin, HIGH);
  delayMicroseconds(3);
  digitalWrite(SDA_Pin, LOW);
  delayMicroseconds(3);
  digitalWrite(SCL_Pin, LOW);
}

// データ転送終了のサイン
void IIC_end()
{
  digitalWrite(SCL_Pin, LOW);
  digitalWrite(SDA_Pin, LOW);
  delayMicroseconds(3);
  digitalWrite(SCL_Pin, HIGH);
  delayMicroseconds(3);
  digitalWrite(SDA_Pin, HIGH);
  delayMicroseconds(3);
}

// データを転送する
void IIC_send(unsigned char send_data)
{
  for (byte mask = 0x01; mask != 0; mask <<= 1) // 各文字は 8 桁あり、1 つずつ検出される
  {
    if (send_data & mask)  // 各ビット(0 または 1)に応じてハイまたはローレベルを設定
    {
      digitalWrite(SDA_Pin, HIGH);
    } 
    else 
    {
      digitalWrite(SDA_Pin, LOW);
    }
    delayMicroseconds(3);
    digitalWrite(SCL_Pin, HIGH); // クロックピン SCL_Pin をハイにしてデータ転送を停止
    delayMicroseconds(3);
    digitalWrite(SCL_Pin, LOW); // クロックピン SCL_Pin をローにして SDA の信号を変化させる
  }
}

(5)テスト結果:

テストコードのアップロードが完了したら、DIP スイッチを右端に切り替えて電源を入れ、APP と Bluetooth をペアリングすると、APP でスマートカーの動きを制御できます。また、左右のモーターのスピードダイヤルを引くことでカーの速度を調整できます。

(プロジェクト 17 の機能一覧表を参照してください)