Welcome to part 6 in our series where we go through the basics of programming. This edition is about two unrelated topics: defines and random numbers.
Be sure to check out the previous episodes:
- Part 1: Skimming the Surface
- Part 2: Conditional Statements
- Part 3: Loops
- Part 4: Arrays and Lists
- Part 5: Functions and Scope
Defines does not exist in Python, so this is going to be an Arduino/C++-only topic in context of this series.
Defines can be used for several things, but first we’ll show you the basic syntax.
#define MY_CONSTANT 42
Here’s a define that we call
MY_CONSTANT. This is the so called identifier. It’s common to name constants like this in all caps. Wherever we write
MY_CONSTANT elsewhere in the code, the compiler will replace that with
42, which is the token-string.
Defines are often used as constants. You can of course use variables for this, but as the name suggest: variables can change and you can’t guarantee that they don’t. Defines never change.
You can also of course just punch in the constant number where you need it, but if you want to change it after having used the same number 50 different places in your code you’re gonna have a bad time. With defines you only need to change the value of the constant one place in your code.
Another neat thing with defines vs. variables as constants is that defines doesn’t take up nearly as much memory as a variable. This can have a large impact when programming on microcontrollers, for instance.
As More Complex Macros
You can use defines as more than constants. Instead of
42 in the example above you can have more complex macros, even with parameters. An example:
#define multiply(f1, f2) (f1 * f2) int a = multiply(2,3);
There is no actual function called
multiply(). Instead, the token-string
(f1 * f2) is just pasted in with the numbers specified in the parameter list. This saves both memory and a bit of runtime, but can get nasty-looking and disorganized when your code grows. Use with care.
Bottom line: The token string (which can be anything) is pasted into the code wherever you write its belonging identifier.
Getting random numbers is often very useful in programming, especially in games and elsewhere where you want a nondeterministic behaviour.
Ways to get a random number is very specific to language and platform, and we will as usual look at how to do this on an Arduino and in Python.
These algorithms are just pseudo-random. The numbers they spit out are based on another number called a seed. With a specific seed you will get the same (very long) sequence of random numbers everytime you run the program. A work-around for this potential issue is to frequently set the seed at the beginning to a number generated from something independent of your program. The clock in the OS is often used for this. On embedded systems you can use something like the noise from an analog-to-digital converter (ADC). In this case: the noisier, the better. You can connect an unshielded wire to the ADC pin to boost the noise. On Arduino’s 10-bit ADC you will still only get a maximum of 1024 different sequences.
On the other hand, if you want the same sequence every time you run the program, you can just explicitly use a known constant seed.
Getting random numbers in pure C++ and on an Arduino is quite different. Arduino has its own built-in functions for random numbers, and these are the ones we’ll look at.
The function to use to get a random number in Arduino is called
random(). This function takes either one or two integer parameters.
int a = random(100); int b = random(5,20);
a becomes a random number from 0 to, but not including, 100.
b becomes a random number from 5 to, but not including, 20.
random() returns integers, so if you want floating point numbers you have to increase the range and divide the result, for instance like this:
float b = random(500,2000)/100.0;
Notice the decimal in
100.0. Writing this number as a decimal number is necessary to get a decimal number in return from the division.
This function takes a long or int as a parameter. This number is the seed which decides the random sequence.
void setup() function you can write
randomSeed(analogRead(0)); to not get the same random sequence every time you run the program.
Note: When you call
randomSeed() the random sequence will start from the beginning every time, even though it’s the same seed as before.
In Python you have many random-related functions. For a complete list, visit this page. We will look at a couple of these functions.
This is almost identical to Arduino’s
random() function with two parameters. The only difference is that it includes the max parameter in the return range.
import random for i in range(0,10): print random.randint(0,9)
This code will print 10 random numbers from (and including) 0 to (and including) 9.
This function returns a random floating point number in the range [0.0,1.0), which means including 0.0, but not 1.0. No parameters are needed for this function.
import random for i in range(0,10): print random.random()*15 + 5
This code will print 10 floating point numbers between (and including) 5.0 up to (but not including) 20.
Equivalent to Arduino’s
randomSeed() function. The main practical difference between Python and Arduino when it comes to seeding is that Python uses the current system time at runtime to generate a seed if no explicit seed is provided. This results in a higher amount of possible random sequences than with the previously mentioned 10-bit ADC way of generating seeds on the Arduino.
Defines are a neat tool for constants and other macros where you want something pasted in multiple places in your code. They clean up the code so that you easily can modify all the constant parameters of your program in one place. Defines can also be used as more than constants.
Retrieving truly random numbers is not as easy as you might think. These algorithms are only pseudo-random which means that they produce a long sequence of “random” numbers based on a seed. This seed can be generated by something independent of your program to get different sequences (almost) every time the program runs.
We’re not done with this series yet, so stay tuned!