Arduino random()関数について
Arduino IDE
のrandom()
関数は、擬似乱数(疑似的にランダムな数値)を生成するための関数です。想像しやすい物ではサイコロやクリスマスツリーの装飾LEDの点灯タイミングなど、ランダムな値を使う際に便利です。以下、random()
関数の使い方や例について詳しく説明していきます。
1. random() 関数の基本
random()
関数には3つの形式があります。
random()
random(max)
random(min, max)
基本的な使い方
random()
random()
だけを使うと、0から大きな数値までのランダムな整数値が生成されます。random(max)
random(max)
とすると、0からmax -1
までの整数値がランダムに生成されます。例えば、random(10)
の場合、0から9のいずれかがランダムに返ります。random(min, max)
random(min, max)
とすると、min
からmax
-1までの範囲のランダムな整数値が返されます。例えば、random(5, 15)
の場合、5から14の間でランダムな整数が生成されます。
※MAXの値 -1になる点に注意してください。
2. 使用例
void setup() {
Serial.begin(9600); // シリアルモニタの初期化
}
void loop() {
int randomValue1 = random(10); // 0から9までのランダムな整数を生成
int randomValue2 = random(5, 15); // 5から14までのランダムな整数を生成
Serial.print("Random (0-9): ");
Serial.println(randomValue1);
Serial.print("Random (5-14): ");
Serial.println(randomValue2);
delay(1000); // 1秒待機
}
3. 擬似乱数の初期化:randomSeed()
Arduinoの乱数生成は、マイクロコントローラの特性上、完全にランダムなものではなく、疑似的なものらしいです。毎回同じシード(初期値)から乱数を生成するため、再起動するたびに同じ乱数列が生成されます。この問題を解決するためには、randomSeed()
関数を使ってシード値を変更します。
例えば、アナログピンから得られる環境ノイズを使ってランダム性を確保する方法です。
例:randomSeed()の使い方
void setup() {
Serial.begin(9600);
// アナログ0ピンの値でシードを初期化(ランダム性を向上)
randomSeed(analogRead(0));
}
void loop() {
int randomValue = random(100); // 0から99までのランダムな整数を生成
Serial.println(randomValue);
delay(500);
}
randomSeed(analogRead(0));
によって、アナログピン0の入力値に基づいてシードを設定します。これは、電気的なノイズやわずかな変動を利用して、疑似乱数列の開始位置を変える役割を果たします。
randomSeed補足
randomSeed(analogRead(0));
は、基本的に Pro Micro、UNO、Mega など、どのArduinoボードでも同様に動作します。例えば、analogRead(0)
はアナログピン0を読み取って、その値を乱数のシードとして使用するので、ボードに関係なくランダムシードを設定するために使えます。
randomSeed(analogRead(0));
の動作analogRead(0)
はアナログ入力ピン0の値を読み取ります。通常、アナログ入力ピンは特に外部接続がない限りノイズが混じった不安定な値を読み取るため、その値を乱数のシードとして使うことで、毎回異なる乱数列を得ることができます。- ボード間の違い
ボードによってアナログ入力の精度や動作が若干異なることもありますが、analogRead()
自体は標準の関数であり、どのボードでも基本的には同じ動作をします。そのため、UNO、Mega、Pro Micro いずれでも問題なく動作するはずです(検証していません)。 - アナログ入力のノイズ
アナログ入力ピン0に特に何も接続しない場合、ピンは浮いている状態になるため、ノイズが読み取られます。このため、毎回異なるシードが得られ、乱数列が毎回変わります。
もしピンに固定の電圧(例えばVccやGND)が接続されている場合、その値に基づいた乱数が生成されることになるので注意が必要です。 - シードの初期化のタイミング
シードが同じ場合、乱数列も同じになるため、randomSeed(analogRead(0));
をsetup()
内で呼び出して使うことを推奨します。
こうすることにより、ボードがリセットされるたびに異なる乱数列を得ることができます。
4. random()の応用例
以下は、複数のLEDをランダムに点灯させる例です。
const int ledPins[] = {2, 3, 4, 5}; // 使用するLEDのピン番号
const int ledCount = sizeof(ledPins) / sizeof(ledPins[0]);
void setup() {
for (int i = 0; i < ledCount; i++) {
pinMode(ledPins[i], OUTPUT); // 各LEDピンを出力に設定
}
randomSeed(analogRead(0)); // シードの初期化
}
void loop() {
int randomLed = random(ledCount); // 0からledCount-1までのランダムな数値
digitalWrite(ledPins[randomLed], HIGH); // ランダムに選ばれたLEDを点灯
delay(100);
digitalWrite(ledPins[randomLed], LOW); // LEDを消灯
delay(100);
}
5. random()の注意点
- シードの設定がないと、毎回同じ乱数列が生成される
randomSeed()
を使わない場合、random()
は同じシーケンスで乱数を生成します。シードの設定により、よりランダムな値を生成できるようになります。サイコロを作るときにいかさまサイコロになってしまいます。 - 連続的な生成の注意
random()
を短い間隔で呼び出すと、値が偏る場合があるとのことです。適度なdelay
を入れることで結果の変化が分かりやすくなります。
まとめ
random(max)
とrandom(min, max)
を使って任意の範囲で乱数を生成可能。randomSeed()
でシードを初期化し、乱数のパターンを変えることができる。- ランダムな動作(LED点灯など)や、サイコロのようなランダムな動作の制御に便利。
サンプルスケッチ
random()
関数を使って、1から6までの値をランダムに生成し、サイコロの目として表示するスケッチを作成します。簡易版としてシリアルモニターで目を確認する方法と、LEDでサイコロの目を表示する方法の2つを紹介します。
1. シリアルモニターで出目を表示するサイコロ
まずは、サイコロの出目をシリアルモニターに表示する基本的なスケッチです。random(1, 7)
を使って、1から6までの数値をランダムに生成します。
void setup() {
Serial.begin(9600); // シリアルモニタの初期化
randomSeed(analogRead(0)); // シードの初期化
}
void loop() {
// 1から6の間のランダムな整数を生成
int diceRoll = random(1, 7);
// サイコロの出目をシリアルモニターに出力
Serial.print("サイコロの出目: ");
Serial.println(diceRoll);
delay(1000); // 1秒間隔で出目を更新
}
random(1, 7)
によって1から6の間の整数がランダムに生成されます。
(最大値 -1になる為、最大値は7)- シードは
randomSeed(analogRead(0))
で初期化しています。
(いかさまサイコロにならないように) - サイコロを振るような動作を1秒ごとに繰り返します。
(興味がある方は、更にランダムでサイコロを振るタイミングも設定してみては?)
2. LEDでサイコロの出目を表示するスケッチ
次に、6個のLEDを使って、サイコロの目を表示するスケッチです。LEDの配置によってサイコロの目を再現します。
必要な部品
- 7個のLED
- Arduinoボード
- 抵抗(各LEDに必要)
スケッチ
// LEDピンの配列
const int ledPins[] = {2, 3, 4, 5, 6, 7, 8}; // 各LEDピンを定義
const int ledCount = 7;
void setup() {
// 各LEDピンを出力モードに設定
for (int i = 0; i < ledCount; i++) {
pinMode(ledPins[i], OUTPUT);
}
randomSeed(analogRead(0)); // シードの初期化
}
void loop() {
// サイコロの目をランダムに生成
int diceRoll = random(1, 7);
// LEDを一旦全て消灯
for (int i = 0; i < ledCount; i++) {
digitalWrite(ledPins[i], LOW);
}
// サイコロの目に応じてLEDを点灯
switch (diceRoll) {
case 1: // 中央のみ点灯
digitalWrite(ledPins[6], HIGH);
break;
case 2: // 左上と右下を点灯
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[5], HIGH);
break;
case 3: // 左上、中央、右下を点灯
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[6], HIGH);
digitalWrite(ledPins[5], HIGH);
break;
case 4: // 4隅を点灯
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[2], HIGH);
digitalWrite(ledPins[3], HIGH);
digitalWrite(ledPins[5], HIGH);
break;
case 5: // 4隅と中央を点灯
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[2], HIGH);
digitalWrite(ledPins[3], HIGH);
digitalWrite(ledPins[5], HIGH);
digitalWrite(ledPins[6], HIGH);
break;
case 6: // 上下の中央と4隅を点灯
digitalWrite(ledPins[0], HIGH);
digitalWrite(ledPins[1], HIGH);
digitalWrite(ledPins[2], HIGH);
digitalWrite(ledPins[3], HIGH);
digitalWrite(ledPins[4], HIGH);
digitalWrite(ledPins[5], HIGH);
break;
}
delay(1000); // 1秒待機して次の出目に更新
}
解説
ledPins[]
の配列には7つのLEDのピン番号を定義しています。- サイコロの目に応じて、
switch
文で各目に対応するLEDを点灯させます。
このスケッチで7個のLEDで表示するサイコロが作れます。
サイコロを振るまでの間の時間に、さらにランダムでLEDを点滅させるとサイコロを振っている感じが出るかもしれません。
興味のある人はお試しください!
コメント