2017年3月12日 星期日

[Arduino] 亂數

我們常常會需要用隨機的方式處理一件事情,最常見的就是樂透開獎。不同的是,樂透開獎採用機械式產生亂數,它是用風吹亂漂浮的球,當閘門打開時球順著管道飛出並掉落到盤中,完成隨機取樣的工作;而在 Arduino 的互動裝置中,我們也可以隨機產生一個數值,讓這個互動裝置隨機做出不同的反應。

如果您會 C 語言的亂數用法,那麼用 Arduino 隨機取出一個數值自然就難不倒您。


Arduino 提供兩個亂數相關的函式:random 、randomSeed

random 有兩個用法:

1. random(最大值)
random(100); 表最小值是 0,最大值是 100。但這個實際上只會產生 0~99 的整數。

2. random(最小值,最大值)
random(20, 50); 表最小值是 20,最大值是 50。但這個實際上只會產生 20~49 的整數。


程式碼

我們可以將下列程式碼 Upload 到 Arduino 裏,藉以觀察它產生的亂數是哪些。

void setup() {
  Serial.begin(9600);
}

void loop() {
  int i = random(100);
  Serial.println(i);
  delay(1000);
}

您可以打開序列埠監控視窗(Serial monitor),將可以看到如下畫面:


但是,如果您重覆關閉並開啟這個視窗,您會發現到它雖然有隨機產生一些數值,但這些數值在出現的順序上並沒有改變。這是因為 random 這個函式初始會以一個所謂的亂數種子(Random Seed)來產生產生亂數,在我們並未改變這個亂數種子之前,亂數會以一定的順序產生。然而,這並非我們真正需要的亂數,因為它數值的出現是可預期的。

要改變上述狀況,在使用 random 函式之前,可以先使用 randomSeed 函式指定
一個亂數種子。我們從類比腳位取出一個數值(它的值介於 0~1023 之間)當作亂數種子。所以程式可以改成這樣

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  int i = random(100);
  Serial.println(i);
  delay(1000);
}

您可以多次開關序列埠監控視窗(Serial monitor),將可以發現到每次開啟視窗時產生的數值都不一樣了,這才是我們真正需要的。


產生 0~100 之間 2 的倍數的亂數

將每次隨機產生的數值乘以 2,就可以產生 2 的倍數的亂數,程式碼如下:

void setup() {
  Serial.begin(9600);
  randomSeed(analogRead(A0));
}

void loop() {
  int i = random(50) * 2;
  Serial.println(i);
  delay(1000);
}


延伸問題

1.如何模擬普克牌洗排,隨機排列1~13的順序。
2.如何模擬普克牌洗排,隨機排列4種花色1~13的順序,花色可以A~D表示,例如A12表黑桃Q,B7表紅心7...。


相關連結

Arduino Reference Random https://www.arduino.cc/en/Reference/Random


1 則留言: