Important characteristics of Arduino boards
Arduino boards are simple-to-use yet complex devices with many technical characteristics. It can be difficult to know what all of these characteristics mean, to understand which ones really matter for your project, and what the advantages and disadvantages are that come with them. In this section, we will shed light on the most relevant characteristics of Arduino boards to help you understand what choices you need to make when choosing between boards.
Input voltage and operating voltage
There are two voltages you need to pay attention to: the board’s input voltage and its operating voltage. The input voltage is the voltage that you can supply to the board’s power connector (if it has one) to power it. For example, for the Arduino Uno, the recommended input voltage range is between 7V and 12V. It is capable of handling input voltages between 6V and 20V, but anything outside the recommended voltage range can cause undesirable side effects, such as power instability or overheating. The supplied input voltage is converted by an onboard voltage regulator to the operating voltage.
The operating voltage is what powers the microcontroller, and it determines the voltage of its output signals and its compatibility with input signals. This compatibility aspect is why it is so important to keep the operating voltage in mind when selecting your Arduino board. If you use an Arduino board with an operating voltage of 3.3V and connect it to a sensor with 5V output signals, the higher voltage from the sensor can damage your Arduino’s microcontroller. If you use an Arduino board that runs on an operating voltage of 5V and connect it to a sensor that uses a 3.3V signal, you run the risk of damaging the sensor with the higher voltage from your Arduino. However, there are boards, sensor modules, and other peripherals that run at an operating voltage of 3.3V but are 5V compatible, meaning that you can safely connect them to a 5V Arduino without the risk of damage.
Because you are much less likely to damage a 5V-compatible Arduino board, 5V boards are considered more robust. Being a 5V board is one of the features that make the Arduino Uno such a robust, beginner-friendly board.
The input voltage is typically less relevant for a robotics project since your robot will likely have a power system that generates the operating voltage(s) for all the components. This way, you can power your Arduino, your sensors, and all other devices with their operating voltages directly without having to use their own internal voltage regulators.
When you select components for your robot, there are three scenarios with regard to their operating voltages you can find yourself in, ordered from most to least preferable:
- You can find versions of all the components you need (Arduino board, sensors, actuators, motor drivers, displays) that have the same operating voltage, either 5V or 3.3V. This is the best case, as it makes your power system simple: you only need to provide one logic voltage. This virtually eliminates the risk of damage from voltage-level mismatches.
- You have some components that run on 5V and some that run on 3.3V, but all their interfaces are 5V compatible. In this case, you need a power system that can provide both 3.3V and 5V, but you can at least safely interconnect all the interfaces of your robot’s components without risking any damage.
- Your components run on different operating voltages, and the voltage levels of their interfaces are not compatible with one another. This is not a big problem; it just makes things a little more complicated. In addition to providing the correct operating voltage of either 3.3V or 5V, you will also need to add dedicated level shifters between the incompatible devices you want to connect. It is easy to find breakout boards with several bidirectional level shifters that translate 3.3V signals on one side to 5V signals on the other, but having to add them increases system complexity.
Besides the voltage levels of their interfaces, the type of interfaces that an Arduino board provides is a very important characteristic when choosing a suitable board for your robot.
Interfaces
Much of what makes Arduino boards so incredibly useful is the ability to easily interface with a very large variety of other components such as sensors, actuators, other Arduinos, or a PC. To this end, having the interfaces you need for your project is often the most important criterion when selecting an Arduino board. Even though you can add additional interfaces to your Arduino Uno with shields and other extension boards, selecting a board that has the required interfaces natively makes for a less complex system overall. Let us look at the kind of interfaces you can choose from when selecting the right Arduino board for your robot, category by category. This section will discuss the interfaces shown in the overview diagram in Figure 4.1:
Figure 4.1 – Overview of the Arduino interfaces covered in this section
There are several other interfaces we could discuss, but for the purpose of DIY robots, this selection covers the most relevant ones, and then some.
Digital interfaces
We have already looked at the most common digital interfaces when we learned about sensor interfaces in Chapter 2, Making Robots Perceive the World with Sensors: Inter-Integrated Circuit (I2C), Serial Peripheral Interface (SPI), and the Universal Asynchronous Receiver/Transmitter (UART)-based Serial interface. Different Arduino boards differ in the number of these interfaces they provide.
I2C and SPI are buses, which means that a single I2C or SPI interface can connect to multiple targets (such as sensors), and thus one of these interfaces is often sufficient even if your robot has multiple I2C or SPI sensors. For I2C, this comes with the caveat that you need to make sure that all your sensors have unique I2C addresses. If this is not the case, the best solution is to use an Arduino board with multiple I2C interfaces such that you can split your sensors across buses with only unique addresses. Otherwise, you will need to use additional hardware such as I2C splitters (or multiplexers) or I2C address translators to circumvent the problem, at the cost of adding additional components and complexity to your project.
In contrast to I2C and SPI, the UART-based Serial interface is a point-to-point (P2P) connection that can only interface with one peripheral at a time. Each Arduino board has at least one Serial port that is needed for programming. You will want to avoid using this interface for anything else (such as a GPS sensor). Otherwise, you need to disconnect your sensor every time you want to program your robot or use the Arduino IDE’s serial monitor. So, whenever your Arduino needs to communicate with a peripheral over UART, you should choose a board that has at least two serial interfaces. While you can use SoftwareSerial
for initial testing (like we did for our experiment with the GPS receiver), this can have several side effects that are hard to debug, and it is good practice to avoid using software Serial in your robot program.
If you have a board with multiple serial ports, they will be marked with TX0 and RX0, TX1 and RX1, and so on. The familiar calls to serial functions such as this refer to serial port 0:
Serial.begin(115200);
To use Serial port 1, all you need to do is replace Serial
with Serial1
in all calls to the serial interface, like so:
Serial1.begin(115200);
Digital pins that can serve as external interrupt inputs when their voltage level changes from high to low or from low to high are the interface of choice for a variety of sensors. They enable very efficient handling of events that happen at a high frequency, such as decoding pulse width modulation (PWM) signals or counting the steps of an incremental encoder. They can also be useful to react incredibly fast (with minimal latency) to any kind of digital input—for example, an emergency stop signal. When you select your Arduino board, you want to make sure it has enough interrupt-capable pins for your needs. It is close to impossible to make up for the lack of interrupt pins without substantial sacrifices in terms of system complexity or code performance.
Especially on the more basic Arduino boards, interrupt pins are a very scarce resource: the Arduino Uno—for example—only has two of them, just enough to sample a single quadrature encoder at full resolution. On more powerful boards with microcontrollers that are based on modern architectures such as the Arduino Due, all digital pins can serve as interrupt inputs.
Other digital interfaces that are available on some Arduino boards that we have not mentioned so far are Controller-Area-Network (CAN) and Ethernet. These are used much more rarely in standalone Arduino robots, but they are supported by the Arduino IDE.
CAN is a common bus interface for industrial-grade components such as hydraulic valves or servo motor controllers. To communicate over CAN, these components usually use higher-level application layer protocols on top of raw CAN messages, such as CANOpen or DeviceNet. Native CAN hardware on Arduino boards is not as well supported by the Arduino software tools as the other interfaces, and the CAN application layer protocols are not easy to implement in Arduino code. Furthermore, an additional CAN transceiver is required to connect an Arduino with a CAN interface to a CAN bus. All of this makes CAN an unpopular choice for DIY projects. This interface is instead used mainly for projects geared toward more industrial applications.
Ethernet is an extremely powerful and versatile P2P connection, but it is not often used in DIY robots. However, the Arduino IDE comes with the Ethernet.h
library that lets you use certain Ethernet hardware modules with SPI interfaces right out of the box. While network connectivity can be a powerful feature for a mobile robot, it is usually better implemented over a Wi-Fi interface than over Ethernet. An exception can be the need for reliable, tethered communication over long distances. Applications with this requirement include underwater robots to explore flooded caves or water cavities under ice—not a very common domain for DIY robotics. That being said, wired Ethernet can be extremely useful if your robot is part of a stationary DIY home automation system that you want to control from anywhere.
Analog interfaces
Analog inputs are great to interface with simple sensors. If you are planning to use analog sensors in your robot, the two things to look out for when selecting your Arduino board are as follows:
- The number of analog inputs (enough for your robot?)
- The resolution of the Arduino’s onboard Analog-to-Digital Converter (ADC)
The Arduino Uno’s ADC has a resolution of 10 bits, or 1,024 unique values, as we already learned. If you use a high-quality analog sensor, you might want to be able to sample its output voltage with a higher resolution. Some Arduino boards have 12-bit ADCs (4,096 unique values), and the very high-end Arduino Portenta H7 even sports a 16-bit ADC, resolving an input voltage into 65,536 unique values.
If you want to read an analog value from pin A0
for example, the call to analogRead(A0)
defaults to a 10-bit resolution, returning a value between 0
and 1023
. If you are using a board with a higher-resolution ADC, you need to set the analog resolution accordingly before calling analogRead()
to take advantage of the more capable hardware. If pin A0
is connected to a 12-bit ADC, this would look like so:
// Set ADC resolution to 12 Bit. analogReadResolution(12); int adc_val = analogRead(A0);
Keep in mind that using an Arduino with a higher-resolution ADC does not automatically give you a better sensor signal. Using a better ADC only pays off when the signal coming from your sensor is of equally high resolution and has low noise.
Another analog interface that we have only briefly mentioned so far is true analog output, enabled by a Digital-to-Analog Converter (DAC). While we have used the analogWrite()
function to command RC servos and modify the speed of DC motors, this function does not actually produce an analog output signal. It produces a very much digital PWM signal. The Arduino Uno’s microcontroller does not include DAC hardware; however, some other Arduino boards do. The associated pins, labeled DAC, can generate an output voltage between GND and the board’s operating voltage. This can be a useful feature to drive speakers to generate sound or to interface with analog circuits built from operational amplifiers.
If you use the analogWrite()
function with any of the DAC pins of your board, it will generate a true analog output voltage instead of a PWM signal. Similar to modifying the resolution of analogRead()
for more capable Arduino boards, you can also modify the resolution of analogWrite()
for boards that support higher PWM (or DAC) resolutions than the default 8-bit. For example, to set the output voltage of the DAC1
pin of the Arduino Due with its 12-bit DAC to half the operating voltage (V_o
) while using the full 12-bit resolution (4,096 unique values), you would do the following:
// Set DAC resolution to 12 Bit and generate 50% V_o. analogWriteResolution(12); analogWrite(DAC1, 2047);
Analog outputs are an advanced and relatively rarely used feature in Arduino robots, but it is good to keep in mind that there are Arduino boards available that offer this capability should you ever need it. As usual, the Arduino IDE and core library make it easy to use.
Wireless interfaces
All interfaces that we have discussed so far are wired interfaces, but there is—of course—the class of wireless interfaces too. These are particularly useful for mobile robots that need to maintain contact with a base station or remote control but should not be hindered by a tether that can break, get stuck, or get entangled.
Most microcontrollers do not have any wireless hardware built in (as opposed to I2C and SPI interfaces, for example). Managing wireless communication is typically a complex task that requires dedicated hardware, such as a Wi-Fi module. Your Arduino microcontroller can communicate with this wireless hardware over a wired interface, such as SPI or UART Serial, and the wireless module takes care of the complexities of handling the wireless transmission. The most used wireless interfaces in DIY Arduino robots are Wi-Fi, Bluetooth, and Zigbee. There are official Arduino boards that include Wi-Fi and Bluetooth hardware, and Arduino also makes a Zigbee shield. Let us briefly look at each of these interfaces and scenarios in which you might want to add them to your robot:
- Wi-Fi is an extremely powerful and versatile wireless interface that allows you to connect your Arduino robot to a local network and even to the internet. It is an excellent choice when you want to give your robot a browser-based interface, or when you want to enable multiple robots to communicate with each other wirelessly. The Arduino IDE comes with the
WiFi.h
library that works with Wi-Fi-enabled Arduino boards such as the Arduino Uno WiFi, or with the Arduino WiFi Shield. - Bluetooth—and its more modern and versatile version Bluetooth Low Energy (BLE)—is an excellent choice when you want to create a simple connection between your robot and your smartphone. In its simplest form, you can use a Bluetooth interface as a wireless bridge for your Arduino’s serial interface. There are apps that make it easy to create a GUI on your smartphone that lets you send simple commands to your Arduino. Your Arduino program can then parse these commands using the utility functions for the Serial interface. For using many of the more advanced features of BLE on a board that supports it, you can use the
ArduinoBLE
library. - Zigbee devices such as the popular XBee transceivers are a family of versatile wireless modules that enable a range of applications, including P2P connections and mesh networks. What makes them particularly interesting for us is that they can offer a much greater radio range than Wi-Fi or Bluetooth, especially outdoors. In addition, in their most basic configuration, they can act as an easy-to-use wireless bridge for a UART Serial connection, either between two Arduino boards or between your Arduino robot and your PC. You can use Zigbee modules to implement a long-distance radio control or let software on your PC control your robot remotely, or stream telemetry data from your robot back to your PC for real-time visualization. Due to their long-range outdoors, Zigbee modules are great for flying or swimming robots, or any other robots that cover large distances and need to maintain a downlink to a base station.
This brief overview should give you a good idea of the wireless interfaces you can choose from when planning your robot and selecting your Arduino hardware, and you can always refer back to Figure 4.1 for a general overview of all the interfaces. We will cover all wireless interfaces in much more detail with examples in Chapter 11, Adding Wireless Interfaces to Your Robot.
CPU
Different Arduino boards have different microcontrollers with different CPU architectures. The beauty of the Arduino toolchain lies in the fact that we do not have to worry much about these differences. If it is an Arduino board, we can be sure that the processor architecture, no matter how advanced, is supported by the Arduino IDE. Programming even the most advanced boards will work just as easily as programming a simple Arduino Uno.
Some of the more advanced Arduino features such as CAN and BLE are only available on certain architectures. In these cases, the documentation of the respective library will tell you which board types are supported. You can look at the documentation of the BLE library as an example of this (look for the section titled Compatibility): https://www.arduino.cc/reference/en/libraries/arduinoble/. When you are planning a more advanced robot project for which you will need a library that only supports certain processor architectures, you need to select an Arduino board that is listed in this library’s documentation.
The Arduino IDE does not come with support for all architectures right out of the box since most users will not need them, but you can easily install the necessary files to use any board you want by clicking on Tools | Board | Boards Manager.... In the Boards Manager, you can search for the board you want to use and install the required files with one click. After this step, you will find your board in the Tools | Board drop-down menu.
You can also quickly open the Boards Manager by clicking on the board icon on the left side of the IDE, shown in Figure 4.2:
Figure 4.2 – Shortcut to the Boards Manager
Apart from the specific architecture, the two most important characteristics of an Arduino’s CPU are its bit width or register size and its clock speed. Together, they determine how fast the CPU can run your program.
Register size
A CPU does some amount of computation every clock cycle. The instruction it executes and the data it operates on are stored in the CPU’s registers. Registers are small blocks of memory that the CPU can access extremely fast. The larger the CPU’s registers, the more work it can do per cycle. The earliest practical microcontroller CPUs, and many that are still in use today, have a register size of 8 bits. This is small and makes them relatively slow. It also means that operations on a 16-bit data type such as an Arduino int
type take more than one clock cycle, and this can lead to trouble when the value of that integer changes unexpectedly between CPU cycles—for example, due to an interrupt execution. The ATmega328P on your Arduino Uno is an example of an 8-bit processor that is still perfectly adequate for many microcontroller applications.
More capable Arduino boards such as the Arduino Due have 32-bit CPU architectures that can do significantly more in one processor cycle.
Clock rate
The CPU clock rate determines how many operations the CPU will perform per second. Most Arduino boards are clocked at 16 MHz. This means they can perform 16 million CPU operations per second (which sounds like a lot but is very slow compared to modern PC CPUs that clock in the GHz range, performing billions of operations per second).
A higher clock rate allows you to run more advanced programs on an Arduino board. Processing image data, fast sensor fusion, advanced signal processing of multiple sensors, or any other application that involves complex calculations with floating-point numbers might require a fast CPU.
Memory
Most Arduino boards have three types of memory: Flash, Static Random Access Memory (SRAM), and Electronically Erasable Programmable Read-Only Memory (EEPROM). Figure 4.3 shows an overview of these three types of memory that are connected to the CPU with its registers:
Figure 4.3 – The three main types of memory inside an Arduino microcontroller
Let us look at what each of these is used for and what it means for selecting the right Arduino board for your robot.
Flash
Flash memory is non-volatile memory. Its contents will persist across power cycles. Your Arduino uses its Flash memory primarily to store the program that you write for it in the Arduino IDE. In addition, the Flash memory stores the Arduino bootloader that allows you to program the board via USB instead of having to use the in-circuit serial programming (ICSP) interface each time. Often, programs that we write for DIY Arduino robots are small (in the sense that the compiler turns them into small binaries), and thus we can make do with a small Flash memory. The Arduino Uno—for example—has a small Flash memory of only 32 KB, and that is often enough. But if your programs get bigger or you use many external libraries in your program, you might reach the limits of your Uno’s Flash memory. In this case, the IDE will warn you, or if your program is too big, the compilation will fail altogether. The solution to this is to either optimize your code or switch to a board with more Flash, such as the Arduino Mega 2560, which has 256 KB of Flash memory.
SRAM
SRAM is where your Arduino creates and maintains variables that you declare and use in your program. SRAM is volatile memory, meaning that its contents are deleted after a system power cycle. When you power on your Arduino, it is safest to assume that the content of the SRAM is random.
Note
The random initial content of SRAM is why it is good coding practice to always initialize variables rather than assuming a certain value after declaration.
A small SRAM can become problematic when you use many large variables in your program. It is quite common to run out of SRAM on an Arduino Uno (that only has 2 KB of it) due to the use of long String
variables, such as help texts that you want your code to print on the Serial monitor. Another common reason to run out of SRAM is the use of lookup tables that you might want to speed up certain calculations. Running out of SRAM can make your program behave unpredictably, which is very undesirable and hard to debug. If, during compilation, the IDE tells you that you are nearing the limits of your board’s SRAM, you can try reducing the use of large variables (for example, by shortening strings) or switching to a different Arduino board with more SRAM. The Arduino Mega 2560—for example—has 8 KB of it, four times as much as the Arduino Uno. Another workaround is to use the PROGMEM
keyword to instruct the compiler to store certain constant
variables in Flash memory. This is an advanced technique that you only need to consider if all your other options are exhausted. You can learn more about it and see the example code here: https://www.arduino.cc/reference/en/language/variables/utilities/progmem/.
EEPROM
EEPROM is a non-volatile memory that you can use to store parameters or any other data between power cycles, even for extended periods of time. It is like a tiny hard drive within your Arduino. The Arduino Uno has 1 KB of EEPROM, and you can easily write to and read from it with the EEPROM
library. The difficulty of using data from EEPROM lies in ensuring that it is valid. If you tell your robot to use parameters that are at a certain EEPROM address, but, for any reason, the data at this EEPROM address has been overwritten, unintentionally altered, never initialized, or deleted, your robot could behave in unintended ways because of that. One way to check the EEPROM content for validity is to calculate and maintain an EEPROM checksum or cyclic redundancy check (CRC).
Additional hardware
Some Arduino boards come with additional hardware besides the microcontroller and interface modules that can make building your robot easier. When you have specific hardware in mind that you will need for your robot, such as an inertial measurement unit (IMU) or temperature sensor, it is always worth looking for an Arduino board that might already have it integrated to simplify your design and spare you the cost of additional hardware. More examples of such additions are real-time clocks to keep accurate track of time even when the Arduino loses power, battery management systems for an attached lithium battery, or SD card readers. A battery management system automatically charges the battery when the Arduino is powered externally and runs the board from the battery when external power is disconnected. An SD card reader can be incredibly useful to save substantial amounts of logging data that your robot might collect on its mission (for example, as GPS data) for later analysis. The Arduino IDE comes with the SD
library, which makes it easy to write to and read from SD cards via the Arduino’s SPI interface.
Size
The physical size of your robot design might constrain the size budget that you have for your Arduino board. Fortunately, Arduino boards come in a variety of form factors, and especially some third-party Arduino-compatible boards are incredibly small. It is preferable though to use a bigger over a smaller board whenever possible, as it is usually easier to work with the bigger boards. You might have noticed that there is a lot of unused space on your Arduino Uno, and it would be easy to squeeze the same functionality into a much smaller board. The reason it is so big is simply for better usability. The Arduino Nano packs almost the same functionality as the Arduino Uno into roughly half the board size.
If you are constrained in terms of board size but not so much in height, you can also consider using an Arduino Uno with shields for additional functionality such as Ethernet or SD card access. However, it is best to not use more than one shield in each application. Shields often use the same pins and might unexpectedly interfere with each other’s functionality.
Cost
One of the factors that make the Arduino ecosystem so attractive and accessible is the low cost of the hardware. However, not all Arduino boards are equally cost-effective. At the time of writing, the Arduino Nano Every is the most affordable board in the official Arduino store for a little more than $10. This makes it especially great for school projects or when you want to build a swarm of identical robots. On the other side of the spectrum lie very powerful Arduino boards such as the Portenta H7, which can cost upward of $100.
If you are looking for an affordable board, it is always worth considering sources outside of the official Arduino store. Because many of Arduino’s designs are open source, there are many great alternatives that are virtually identical but cost a fraction of the original product. Support through the IDE might not be quite as good, and you might need to install additional drivers to account for different (more cost-effective) USB-to-Serial hardware, but it can be worth the trouble to save on one of the more expensive components of your robot.