Random Functions

Armed with a decent grasp of how to handle the Arduino delay functions, as well as an advanced method for creating a delay without one, let's look now at some ways to make things less precise with a little randomness. Up to this point, our timing has been fairly straightforward: turn on the LED, wait for 1 second, turn off the LED, wait for another second, and so forth. Each of our delays has been specified to a relatively accurate degree of precision so that a delay of 1000 milliseconds will be reasonably sure to give us a delay of 1 second. But what if we wanted a delay that was somewhere between 250 and 1000 milliseconds and not only that, but this value changed somewhat randomly every time it is accessed?

This is possible using a couple of the advanced Arduino functions for generating randomness. At least these functions generate something of a form of semi-randomness, which is kind of, sort of randomness. Let's now look at how we can use the random functions in our sketches as a form of timing and for some other uses, as well.

random()

The random() function returns a semi-random number up to the parameters specified. If no parameters are specified, it will return a value in the signed long data type, with a range of -2,147,483,648 to 2,147,483,647. Its syntax follows:

random(min, max)

The first parameter, if expressed, is the minimum possible value expected from the random() function. This value will be included in the possible outcomes. Likewise, the second value would be the maximum value expected. This value, however, will be excluded from the possible outcomes. So, to generate a random number with 10 possible values you could use the following statement:

int randomNumber = random(0, 10);

The possible values will include the integers 0 through 9. If this were all we wanted to do, it would be simpler to only specify the maximum value like the following:

int randomNumber = random(10);

This last statement is functionally the same as the previous one. It is even possible to receive negative random values, although if no minimum has been specified, the random() function will assume a value of 0 for its minimum value. As an example of creating a random delay, Listing 7-2 takes our blink without delay example and adds a single line to create some unpredictability.

Listing 7-2. Random Blink Without Delay

const int ledPin = 13;

int state = LOW;

unsigned long startTime = 0;
unsigned long interval = 500;

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  if (startTime + interval < millis()) {
  state = !state;
  digitalWrite(ledPin, state);
  startTime = millis();
  interval = random(250, 1001);
  }
}

While we start with an interval of 500 milliseconds for the first time through our code (inside the if statement), we have added this line at the bottom:

interval = random(250, 1001);

This will generate a random delay between a quarter second and 1 second by assigning a random value between 250 and 1000 to the variable interval, even though we do not always need to assign the random value to a variable for it to work. Instead, because the function works in a similar way as millis() in that it returns a value to the place in the program where it was called, we can use it in place of a variable. Take the following code fragment:

for (int i=0; i<=255; i+=5) {
  analogWrite(5, i);
  delay(random(50));
}
for (int i=255; i>=0; i-=5) {
  analogWrite(5, i);
  delay(random(50));
}

In this sample code we fade an LED connected to pin 5 up to full brightness and back to off again with a random delay between each step in brightness. By placing the random() function with a specified maximum of 50 inside of the delay() function, each iteration through the for loop will pause for a random time period between 0 and 49 milliseconds.

Generating random numbers in our sketches has so many possible uses that we are only scratching the surface here. One last possibility before we look at how we can make our semi-random numbers a little better, is using the random function to choose one of several possible outcomes using a switch statement. Take this modified code fragment borrowed from the last chapter:

randomNumber = random(1,4);
  switch (randomNumber) {
    case 1:
    ;
    case 2:
    ;
    case 3:
    ;
  }

In this fragment, we generate a random number that includes the possible values 1, 2, and 3 and assign that value to the variable randomNumber. Referencing this variable in the switch statement will allow for one of three randomly chosen possible outcomes to be chosen depending on the value that was generated.

randomSeed()

Now because our random numbers are only semi-random, the random() function doesn't produce the most random numbers—depending, of course, on how you look at it. That's because the Arduino microcontroller—being a stubborn little computer that is fairly deterministic—uses a set formula to create a sequence of values that, while a fairly long sequence, only appears random and will inevitably repeat. It also means that each time you power on the Arduino interface board or give it a reset, the random() function will begin with the very same numbers every time. That can be a little predictable. To take this predictability out we need to use the randomSeed() function with a syntax as follows:

randomSeed(value)

By feeding the randomSeed() function a seed value, we can kick off the random generation at a more unexpected point somewhere in the depths of the random sequence. This seed value can be either an integer or long data type while the initial call to the randomSeed() function often happens in the setup() function although this is not entirely necessary. So, consider the following single line statement:

randomSeed(42);

This line is a reasonable example of using randomSeed() to start the sequence off in a little different direction than it would without it. However, with a fixed seed value, in this case the integer 42, the sequence will still repeat exactly the same each time the sketch is ran. This can be occasionally useful, but to make things even more random we can use a reading of a disconnected, or floating, analog pin as our seed value. An example of this would be the following line:

randomSeed(analogRead(A0));

Remember earlier in this book when we discussed how a floating pin is a bad thing? In this case the odd gibberish that we get from reading an unconnected analog input pin is just the thing we need to increase the “randomness” of our random numbers. By placing the analogRead() function inside of the randomSeed() function, and pointing it to an unconnected analog in pin, A0 in this case, we will get a more arbitrary starting point for our random sequence. This also has the benefit that every time the sketch starts over by turning on or being reset, or simply the next time we call the function in the same manner, we will usually get completely different results. Remember, though, that in order for this to function properly, the pin must be disconnected from any circuitry.

image Note As of the summer of 2011, the Arduino Uno interface board is available in an SMD edition that features a smaller surface mount version of the ATmega328 microcontroller chip. A little undocumented bonus of this version of the chip is that it has an additional two ADC pins, A6 and A7. While these pins are not accessible on the Arduino pin headers, we can still use them for seed values because they are not connected to anything. The next time you need to use this function, try randomSeed(analogRead(A6)); if you have this version of the board.

That wraps up a few additional functions that we have not previously been able to talk about in a sufficient depth. As you probably have noticed, we use delays of one form or another a lot in our example code and randomness can come in handy on occasion. Let's move on from using built-in Arduino functions to writing our own by looking at our next project, which is followed by a discussion of writing and using functions.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset