第9回
列挙型と状態管理
プログラムの「状態」を数値ではなく名前で扱う。
enum
enum Mode {
MANUAL,
AUTO,
ERROR
};enum class
enum class Mode {
MANUAL,
AUTO,
ERROR
};使用:
Mode mode = Mode::MANUAL;switchとの組み合わせ
switch (mode) {
case Mode::MANUAL:
break;
case Mode::AUTO:
break;
case Mode::ERROR:
break;
}状態が名前で書かれているため、case 0:のような数値よりはるかに読みやすい。
マイコンでの利用
例えば飛行制御なら、
enum class FlightMode {
MANUAL,
LEVEL_TURN,
CLIMBING_TURN,
EIGHT_TURN,
LANDING
};のように状態を管理できる。int mode = 3;のような書き方と比べ、何を表しているかがコード上で明確になる。
動かして確かめる
演習に入る前に、まずこのサンプルを動かして結果を見る。追加の部品は要らない。光るのはボードに載っている内蔵LEDで、それ以外はシリアルモニタの出力で確かめられる。code/examples/09-robot-state/を開き、pio run -t uploadで書き込んでからpio device monitorで出力を見る(手順と、外付けのLEDなどをつなぐ場合は開発環境にまとめてある)。
// 第9回:状態を enum class で管理する
#include <Arduino.h>
enum class RobotState {
STOP,
MOVE,
ERROR
};
// ボード上の内蔵LED。配線なしで光る(このボードではGPIO27のRGB LED)
const int LED_PIN = LED_BUILTIN;
RobotState state = RobotState::STOP;
/**
* @brief 状態を切り替える
* @details 切り替えをこの関数1つに通しておくと、
* どこから状態が変わったのかを追いやすい。
* @param next 次の状態
*/
void setState(RobotState next) {
state = next;
}
/**
* @brief 現在の状態に応じてLEDを制御する
*/
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(100);
digitalWrite(LED_PIN, LOW);
delay(100);
break;
}
}
void setup() {
pinMode(LED_PIN, OUTPUT);
setState(RobotState::MOVE);
}
void loop() {
updateLed();
delay(50);
}setup()でMOVEにしているのでRGB LEDが点灯する。setState()の引数をSTOPやERRORに書き換えて、見え方を比べる。
確かめること。
switchのcaseがRobotState::MOVEと名前で書かれている。case 1:より何を表しているかが読み取れるenum classなのでstate = 1;とは書けない。間違った値が入らない- 状態を増やすときは
enum classに1行足す。switchにcaseを書き忘れると、コンパイラが警告を出すことがある - 状態の切り替えを
setState()という関数1つに通している。どこから状態が変わったのかを追いやすい
演習:簡単なロボットの状態を作る
enum class RobotState {
STOP,
MOVE,
ERROR
};状態によってLEDの動作を変える。
STOP:消灯MOVE:点灯ERROR:点滅
loop()の中でswitchにより分岐させる。状態を切り替える関数も用意してみる。