第9回 解答例

RobotStateで状態管理する

演習の解答例。まず自分で書いてから読むこと。

解答

#include <Arduino.h>

enum class RobotState {
    STOP,
    MOVE,
    ERROR
};

const int LED_PIN = LED_BUILTIN;
const int ERROR_BLINK_MS = 100;

RobotState state = RobotState::STOP;

void setState(RobotState next) {
    state = next;
}

void updateLed() {
    switch (state) {
    case RobotState::STOP:
        digitalWrite(LED_PIN, LOW);
        break;

    case RobotState::MOVE:
        digitalWrite(LED_PIN, HIGH);
        break;

    case RobotState::ERROR:
        // 点滅させる
        digitalWrite(LED_PIN, HIGH);
        delay(ERROR_BLINK_MS);
        digitalWrite(LED_PIN, LOW);
        delay(ERROR_BLINK_MS);
        break;
    }
}

void setup() {
    pinMode(LED_PIN, OUTPUT);
    setState(RobotState::MOVE);
}

void loop() {
    updateLed();
    delay(50);
}

なぜenum classなのか

数値で状態を持つと、次のようなコードが書けてしまう。

int state = 0;   // 0=STOP, 1=MOVE, 2=ERROR ... コメントがないと読めない

state = 7;       // 存在しない状態。コンパイラは何も言わない

enum classなら、

RobotState state = RobotState::STOP;

state = 7;                  // コンパイルエラー
state = RobotState::MOVE;   // これしか書けない
  • 存在しない状態を代入できない
  • switchの各caseが何を表すか名前で読める
  • MANUALのような名前が他のenumと衝突しない(enumとの違い)

状態を切り替える

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

        switch (command) {
        case 's':
            setState(RobotState::STOP);
            break;

        case 'm':
            setState(RobotState::MOVE);
            break;

        case 'e':
            setState(RobotState::ERROR);
            break;

        default:
            break;
        }
    }

    updateLed();
}

→ 第9回の本文に戻る