PR

ミニ四駆の改良と基礎的なプログラミングに挑戦する

2013年5月15日(水)
藤原 敬弘

FULLERミニ四駆 プログラム編

次のプログラムがFULLERミニ四駆に搭載されているものです。このプログラムは筆者のGithubのリポジトリ mini4w_motor_driveで公開されています。

/**
 * ピンの指定
 */
const int FORWARD_PIN = 5;
const int BACKWARD_PIN = 6;

/**
 * コマンドの定義
 */
const char FORWARD = 'F';
const char BACKWARD = 'B';
const char ERROR_SIGNAL = 'E';

/**
 * スピードの調整パラメータ
 */
const int MIN_SPEED = 0;
const int MAX_SPEED = 9;
const int STOP_SPEED = 0;
const int SPEED_WEIGHT = 25;

/**
 * コマンドを保持する変数
 */
int incommingSignal;
char lastSignal;

boolean mini4wdDirection = true;

void setup() {
  Serial.begin(115200);
  pinMode(FORWARD_PIN, OUTPUT);
  pinMode(BACKWARD_PIN, OUTPUT);
}

void loop() {
  if (Serial.available() > 0) {
    char incommingSignal = Serial.read(); 

    if (String(incommingSignal).length() == 1) {
      switch (incommingSignal) {

        case FORWARD:
        case BACKWARD:
          lastSignal = incommingSignal; # FORWARDかBACKWARDだった場合、コマンドを保存して、次のスピードパラメータが来るのを待つ
          break;

        default:
          int mini4wdSpeed = incommingSignal - 48;
          if ((lastSignal == FORWARD || lastSignal == BACKWARD) &&
               mini4wdSpeed >= MIN_SPEED && mini4wdSpeed <= MAX_SPEED) { # FOWARDかBACKWARD以外で、かつ数値が渡された場合、incommingSignalの方向に従ってモーターを駆動させる
             if (goDirection(lastSignal, mini4wdSpeed)) {
               String returnValue = String(lastSignal) + String(mini4wdSpeed);
               Serial.println(returnValue);
             }
          } else {
            lastSignal = ERROR_SIGNAL;
          }
          break;

      }
    }
  }
  delay(10);
}

boolean goDirection(char mini4wdDirection, int mini4wdSpeed) {
  int mini4wdSpeedWithWeight = mini4wdSpeed * SPEED_WEIGHT;
  switch (mini4wdDirection) {
    case FORWARD:
      analogWrite(FORWARD_PIN, mini4wdSpeedWithWeight);
      analogWrite(BACKWARD_PIN, STOP_SPEED);
      break;
    case BACKWARD:
      analogWrite(BACKWARD_PIN, mini4wdSpeedWithWeight);
      analogWrite(FORWARD_PIN, STOP_SPEED);
      break;
  }
  return true;
}

FULLERミニ四駆は、前進、後退の他に速度制御を行うことができます。停止のコマンドは用意していないのですが、これは速度を0にすることで対応できるからです。
速度制御にはPWMという信号を使っています。PWMは簡単に言ってしまうと、擬似的に電圧の高さを制御する技術です。

* PWM

ArduinoではPWMを送ることが出来るピンが決まっています。

>> PWM: 3, 5, 6, 9, 10, and 11. Provide 8-bit PWM output with the analogWrite() function. (Arduino Pro Mini より)

PWM信号を送る際にはanalogWrite関数を使用します。

analogWrite([ピン番号], [0-255の数値]) # 第2引数を大きくすれば、電圧が上がる

今回製作したミニ四駆にもこのPWM信号を使うことができます。5Vにセットされている制御ピンをPWM信号に置き換えます。

    /**
     * ピンの定義
     *
     * signal1とsignal2で使用するピンに名前を付ける。
     */
     const int SIGNAL1_1 = 4;
     const int SIGNAL1_2 = 5;
     const int SIGNAL2_1 = 2;
     const int SIGNAL2_2 = 3;

     /**
      * 転送速度の定義
      */
     const int SERIAL_TRANS = 115200;

    /**
     * 速度の設定 
     *
     * 0-255の値を指定する
     */
    const int SPEED = 100;

    /**
     * setup関数
     *
     * シリアル通信を使うため、初期化する。
     * モーターの制御に使用するピンをOUTPUTに指定する。
     */
    void setup() {
        Serial.begin(SERIAL_TRANS);
        pinMode(SIGNAL2_1, OUTPUT);
        pinMode(SIGNAL2_1, OUTPUT);
        pinMode(SIGNAL1_1, OUTPUT);
        pinMode(SIGNAL1_2, OUTPUT);
    }

    /**
     * signal1関数
     *
     * モーターの制御をわかりやすくするため、シグナル関数を用意する。
     * signal1関数とsignal2関数を使って、モーターの正転、逆転、停止を制御する。
     *
     * signal1関数とsignal2関数に同時に1を渡すと、FETモジュールが壊れるので注意する。
     */
    void signal1(int value) {
        switch (value) {
            case 0:
                digitalWrite(SIGNAL1_1, HIGH);
                digitalWrite(SIGNAL1_2, LOW);
                break;
            case 1:
                digitalWrite(SIGNAL1_1, LOW);
                analogWrite(SIGNAL1_2, SPEED); # ここをanalogWriteに変更
                break;
        }
    }

    /**
     * signal2関数
     *
     * モーターの制御をわかりやすくするため、シグナル関数を用意する。
     * signal1関数とsignal2関数を使って、モーターの正転、逆転、停止を制御する。
     *
     * signal1関数とsignal2関数に同時に1を渡すと、FETモジュールが壊れるので注意する。
     */
    void signal2(int value) {
        switch (value) {
            case 0:
                digitalWrite(SIGNAL2_1, HIGH);
                digitalWrite(SIGNAL2_2, LOW);
                break;
            case 1:
                digitalWrite(SIGNAL2_1, LOW);
                analogWrite(SIGNAL2_2, SPEED); # ここをanalogWriteに変更
                break;
        }
    }

    /**
     * stop関数
     *
     * 停止コマンドが来た場合のステータスの変更を行う。
     */
    void stop() {
        signal1(0);
        signal2(0);
    }

    /**
     * forward関数
     *
     * 前進コマンドが来た場合のステータスの変更を行う。
     */
    void forward() {
        signal1(1);
        signal2(0);
    }

    /**
     * back関数
     *
     * 後退コマンドが来た場合のステータスの変更を行う。
     */
    void back() {
        signal1(0);
        signal2(1);
    }

    /**
     * loop関数
     *
     * コマンドを受け取り、forward / back / stop のいずれかの適切な関数を呼ぶ。
     */
    void loop() {
        if (Serial.available() > 0) {
            char c = Serial.read();
            if (c == 'f') {
                forward();
            } else if (c == 'b') {
                back();
            } else if (c == 's') {
                stop();
            }
        }
    }

定数SPEEDを変更することで、モーターの速度を変化させることができます。このサンプルはBluetooth経由でスピードを制御するプログラムではありません。自身でコマンドを定義し、Bluetooth経由で速度制御できるようにしてみてください。

別のアイデアですが、ミニ四駆を急停止することもできます。停止コマンドに一定時間の逆転を加えるのですが、このように制御することで、単にモーターの回転を止めるよりも、ミニ四駆を素早く停止させることができます。サンプルプログラムは載せませんので、課題のつもりで試してみてください。

FULLER株式会社

1986年生まれ。北海道苫小牧市出身。苫小牧工業高等専門学校卒業。
Fuller, Inc. CTO
Webプログラマ、よく利用する言語はPython。Pythonコミュニティによく出没する。
趣味でArduinoやRaspberry Piなどを使って、便利なものを自作する。

twitter: @wutali / github: https://github.com/wutali

連載バックナンバー

Think IT会員サービス無料登録受付中

Think ITでは、より付加価値の高いコンテンツを会員サービスとして提供しています。会員登録を済ませてThink ITのWebサイトにログインすることでさまざまな限定特典を入手できるようになります。

Think IT会員サービスの概要とメリットをチェック

他にもこの記事が読まれています