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

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 Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

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