このコードには、コンパイルエラーを引き起こす致命的な問題と、コードの可読性やメンテナンス性を損なう問題の2種類があります。
1. 未定義の関数 (コンパイルエラー)
コードは moveForward() や ledOn() といった関数を呼び出していますが、これらの関数がどこにも定義されていません。そのため、このままではコンパイルできません。
モーターの制御やLEDの点灯を行うための具体的な処理を、これらの関数として実装する必要があります。
2. 赤外線コードの扱いの問題 (ロジックと可読性)
コードの冒頭で BTN_UP などの定数を定義していますが、switch 文の中では 0x02 のような直接的な値(マジックナンバー)が使われており、せっかく定義した定数が全く使われていません。
これは、コードを読む人が 0x02 という値が何を意味するのかすぐに理解できないため、非常に読みにくく、間違いの原因にもなります。
IrReceiver.decodedIRData.command が返すのは、赤外線信号のコマンド部分(8ビット)です。したがって、定数をこの8ビットの値で定義し直し、switch 文でその定数名を使うように修正するべきです。
修正・完成版コード
上記の問題点を修正し、不足している関数を実装した完成版のコードを以下に示します。このコードをコピーして使用すれば、意図通りに動作するはずです。
C++
#include <IRremote.hpp>
// ピン定義
const int motor1A = 6;
const int motor1B = 7;
const int motor2A = 4;
const int motor2B = 5;
const int redLED = 10;
const int greenLED = 9;
const int blueLED = 8;
const int irReceiverPin = 2;
// 赤外線コード定義(コマンド部分のみに修正)
#define BTN_1 0x30
#define BTN_2 0x18
#define BTN_3 0x7A
#define BTN_4 0x10
// ... 他のボタンも同様に8ビットのコマンド部分を定義 ...
#define BTN_UP 0x02
#define BTN_DOWN 0x98
#define BTN_RIGHT 0x90
#define BTN_LEFT 0xE0
#define BTN_OK 0xA8 // 元のコードの0xFFA857に対応
void setup() {
Serial.begin(9600); // デバッグ用にシリアル通信を開始
IrReceiver.begin(irReceiverPin, ENABLE_LED_FEEDBACK);
pinMode(motor1A, OUTPUT);
pinMode(motor1B, OUTPUT);
pinMode(motor2A, OUTPUT);
pinMode(motor2B, OUTPUT);
pinMode(redLED, OUTPUT);
pinMode(greenLED, OUTPUT);
pinMode(blueLED, OUTPUT);
}
void loop() {
if (IrReceiver.decode()) {
// 受信したコードを16進数でシリアルモニタに表示
Serial.println(IrReceiver.decodedIRData.command, HEX);
// 定義した定数名を使って処理を分岐
handleIR(IrReceiver.decodedIRData.command);
IrReceiver.resume(); // 次の信号を受信するためにリセット
}
}
// ========== ここから下に関数を追加 ==========
// モーターを停止する関数
void stopMotors() {
digitalWrite(motor1A, LOW);
digitalWrite(motor1B, LOW);
digitalWrite(motor2A, LOW);
digitalWrite(motor2B, LOW);
}
// 前進する関数
void moveForward(int duration) {
digitalWrite(motor1A, HIGH);
digitalWrite(motor1B, LOW);
digitalWrite(motor2A, HIGH);
digitalWrite(motor2B, LOW);
delay(duration);
stopMotors();
}
// 後進する関数
void moveBackward(int duration) {
digitalWrite(motor1A, LOW);
digitalWrite(motor1B, HIGH);
digitalWrite(motor2A, LOW);
digitalWrite(motor2B, HIGH);
delay(duration);
stopMotors();
}
// 右に曲がる関数(その場で回転)
void turnRight(int duration) {
digitalWrite(motor1A, HIGH);
digitalWrite(motor1B, LOW);
digitalWrite(motor2A, LOW);
digitalWrite(motor2B, HIGH);
delay(duration);
// stopMotors(); // この後のmoveForwardのために停止しない
}
// 左に曲がる関数(その場で回転)
void turnLeft(int duration) {
digitalWrite(motor1A, LOW);
digitalWrite(motor1B, HIGH);
digitalWrite(motor2A, HIGH);
digitalWrite(motor2B, LOW);
delay(duration);
// stopMotors(); // この後のmoveForwardのために停止しない
}
// LEDを指定時間点灯させる関数
void ledOn(int pin, int duration) {
digitalWrite(pin, HIGH);
delay(duration);
digitalWrite(pin, LOW);
}
// 赤外線信号を処理する関数
void handleIR(unsigned long code) {
switch (code) {
case BTN_UP: // 前
ledOn(blueLED, 1000);
moveForward(1000);
break;
case BTN_DOWN: // 後
ledOn(greenLED, 1000);
moveBackward(1000);
break;
case BTN_RIGHT: // 右
ledOn(redLED, 100);
turnRight(100);
moveForward(100);
break;
case BTN_LEFT: // 左
ledOn(redLED, 100);
turnLeft(100);
moveForward(100);
break;
// 数字ボタンの処理
case BTN_1:
ledOn(redLED, 1000);
break;
case BTN_2:
ledOn(blueLED, 1000);
break;
case BTN_3:
ledOn(greenLED, 1000);
break;
case BTN_4:
// 2つのLEDを同時に点灯させるには少し工夫が必要
digitalWrite(redLED, HIGH);
digitalWrite(blueLED, HIGH);
delay(1000);
digitalWrite(redLED, LOW);
digitalWrite(blueLED, LOW);
break;
default: // 定義されていないボタンが押された場合
stopMotors(); // とりあえず停止
break;
}
}