Chapter 18. Arduino and Raspberry Pi

18.0 Introduction

Although a Raspberry Pi is ideal for projects that need a network connection or a graphical user interface (GUI), the low-power general-purpose input/output (GPIO) and lack of any analog inputs puts it at a disadvantage to microcontroller boards such as the Arduino (Figure 18-1). Fortunately, it is possible to have the best of both worlds by connecting an Arduino to a Raspberry Pi and allowing the Arduino to interface with external electronics.

Arduino boards are superficially a little like a Raspberry Pi in that they are small and essentially are computers. However, Arduino boards are very different from the Raspberry Pi in a number of respects:

  • They do not have any interface to keyboard, mouse, or screen.

  • They have just 2 KB of RAM and 32 KB of flash memory for storing programs.

  • Their processor runs at just 16 MHz, compared with the Raspberry Pi 4’s 1.2 GHz.

This might lead you to wonder why you would use such an apparently feeble board rather than the Raspberry Pi directly.

The answer is that Arduino boards, the most common being the Arduino Uno, are better than the Raspberry Pi at interfacing with external electronics in several ways. For example, Arduino boards have the following features:

  • Fourteen digital inputs/outputs (I/Os), like the Raspberry Pi’s GPIO pins, but each pin can provide up to 40 mA, compared with the original Raspberry Pi’s 3 mA. This enables them to power more devices without the need for extra electronics.

  • Six analog inputs. This makes connecting analog sensors much easier (see Recipe 18.7).

  • Six pulse-width modulation (PWM) outputs. These outputs are hardware-timed and produce a much more accurate PWM signal than can be achieved with the Raspberry Pi, making them a lot better for controlling servo motors.

  • A huge range of plug-in shields (the Arduino name for Hardware Attached on Top [HAT] add-ons) for everything from motor control to LCD displays of various sorts.

rpck 1401
Figure 18-1. An Arduino Uno board

In many ways, using a Raspberry Pi with an Arduino to handle all the low-level stuff is a good combination, playing to the strengths of both boards.

As well as official Arduino boards, there are also very popular Arduino-compatible boards with built-in WiFi that are based on the ESP8266 and ESP32 and are low cost and great for Internet of Things (IoT) projects (Chapter 16) and home automation (Chapter 17).

18.1 Programming an Arduino from Raspberry Pi

Note

Be sure to check out the accompanying video for this recipe at http://razzpisampler.oreilly.com.

Problem

You want to run the Arduino integrated development environment (IDE) on a Raspberry Pi so that you can write and upload programs onto an Arduino.

Solution

The Arduino IDE is available for the Raspberry Pi. It is a little bit slow but usable. You will definitely want to use the superior speed of the Raspberry Pi 2, 3, or 4 when using the Arduino IDE.

Use these commands to install the Arduino IDE:

$ wget http://downloads.arduino.cc/arduino-1.8.5-linuxarm.tar.xz
$ tar -x -f arduino-1.8.5-linuxarm.tar.xz
$ cd arduino-1.8.5/
$ ./install.sh

You can now connect your Arduino Uno to your Raspberry Pi through its USB cable. From the Tools menu, select Board, and set the board type to Arduino Uno. Then, from the Serial Port option, select /dev/ttyACM0 (Figure 18-2).

To upload a test program that will make the LED on the Arduino blink, select the File menu, click Examples, and then Basic, and then click Blink. On the toolbar, click the right arrow to start the compile and upload process. If all is well, you should see a Done Uploading message in the status area at the bottom of the IDE window.

Discussion

To get the most out of using an Arduino with your Raspberry Pi, you need to learn a little Arduino programming. You might find the book Programming Arduino: Getting Started with Sketches (McGraw-Hill/Education/TAB), by yours truly, helpful.

You can, however, make use of an Arduino without needing to write any code on the Arduino side, using a project called PyFirmata. Recipe 18.3 explains how to use PyFirmata.

Figure 18-2. Selecting the serial port in the Arduino IDE

See Also

The Arduino website has many useful resources and a very responsive forum.

18.2 Communicating with an Arduino by Using the Serial Monitor

Problem

You want to display messages sent from an Arduino.

Solution

The Arduino IDE includes a feature called the serial monitor, which allows you both to send text messages to the Arduino and to see messages from the Arduino over the USB cable.

To try this out, you first need to write a very short Arduino sketch (programs are called sketches in the Arduino world). This sketch will just repeat a message, sending it every second.

The Arduino sketch is listed here. You can also find it in the arduino folder of the book’s code, ch_18_serial_test (see Recipe 3.22).

If you would prefer to write the code yourself, use File → New to create a new sketch, and copy the following text into it before uploading it to the Arduino:

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

void loop()
{
  Serial.println("Hello Raspberry Pi");
  delay(1000);
}

As soon as the sketch is uploaded to the Arduino, it will start sending the message “Hello Raspberry Pi” over serial. You won’t see this until you open the serial monitor (Figure 18-3) by clicking the icon that looks like a magnifying glass on the right side of the Arduino IDE’s toolbar.

Figure 18-3. Viewing messages with the serial monitor

The serial monitor has a drop-down list in the lower-right corner, where you can select the baud rate (speed of communication). If this isn’t already set to 9600, change it to that value.

Discussion

In Recipe 18.10, we look at writing your own custom code to communicate with Python programs running on the Raspberry Pi so that you don’t need to have the Arduino IDE running.

A more generic approach is to use something called PyFirmata, which avoids the need for any programming on the Arduino. See Recipe 18.3 for details.

See Also

Arduino is quite easy to learn; here are some links to books and online resources to get you started:

18.3 Setting Up PyFirmata to Control an Arduino from a Raspberry Pi

Problem

You want to use an Arduino as an interface board for your Raspberry Pi.

Solution

We will use two programs to achieve this link: PyFirmata on the Raspberry Pi and Firmata on the Arduino.

Connect the Arduino to a USB socket of the Raspberry Pi so that the computer can communicate with and send power to the Arduino.

Next, install the Firmata sketch onto the Arduino and the PyFirmata program onto your Raspberry Pi. This entails installing the Arduino IDE, so if you haven’t already done so, follow Recipe 18.1.

The Arduino IDE includes Firmata, so all you need to do to install Firmata onto your Arduino board is to upload a sketch. You will find the sketch at File → Examples → Firmata → StandardFirmata.

After Firmata is installed, the Arduino waits for communication from the Raspberry Pi.

Now you need to install PyFirmata, the other half of the link. This requires the use of the PySerial library, so follow Recipe 9.6 to install this.

You can now download and install PyFirmata by using this command:

$ sudo pip3 install pyfirmata

You can try out the pyfirmata library from the Python console. Enter the following commands in turn to switch on the built-in LED on Arduino pin 13 (marked with an L) and then turn it off again:

$ python3
Python 3.5.3 (default, Sep 27 2018, 17:25:39) 
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits", or "license" for more information.
>>> import pyfirmata
>>> import pyfirmata
>>> board = pyfirmata.Arduino('/dev/ttyACM0')
>>> pin13 = board.get_pin('d:13:o')
>>> pin13.write(1)
>>> pin13.write(0)
>>> board.exit()

Discussion

The preceding code first imports the PyFirmata library and then makes an instance of Arduino called board, using the USB interface (/dev/ttyACM0) as its parameter. You can then reference one of the Arduino pins (in this case, 13) and set it to be a digital output. The d is for digital, 13 is the pin number, and o is for output.

To set the output pin high, use write(1), and to set it low, use write(0). You can also use True and False in place of 1 and 0.

Figure 18-4 shows an Arduino with the rows of connections down both sides of the board.

rpck 1404
Figure 18-4. I/O pins on an Arduino Uno

You can use the pins at the top marked 0 to 13 as digital inputs or outputs. Some of these pins are also used for other things. Pins 0 and 1 are used as a Serial interface and are in use when the USB port is being used, and pin 13 is attached to the on-board LED marked with an L (just under the GND and 13 connections). The digital I/O pins 3, 5, 6, 9, 10, and 11 have a ~ symbol next to them that indicates that they can be used for PWM output (see Recipe 10.3).

On the other side of the board, there is a set of connectors that supplies power at 5V and 3.3V, as well as six analog inputs marked A0 to A5.

An Arduino Uno on its own uses about 50 mA, which, given that the Raspberry Pi itself is probably using about 10 times that, makes it perfectly possible to power the Arduino from the USB connection of the Raspberry Pi. However, if you start attaching a lot of external electronics to the Arduino, and the current consumption increases, you might want to power the Arduino from its own power adapter by using the DC barrel socket. This will accept 7V to 12V DC.

The only real downside of using Firmata is that, because all instructions have to come from the Raspberry Pi, it doesn’t make much use of Arduino’s ability to run independently. For advanced projects, you will probably end up writing your own Arduino code that receives instructions from the Raspberry Pi and/or sends messages to the Raspberry Pi while it gets on with other tasks.

See Also

The following recipes look at using the full range of Arduino pin features with PyFirmata: 18.4, 18.5, 18.6, 18.7, and 18.8.

You can find the official PyFirmata documentation at PyFirmata’s GitHub page.

18.4 Writing Digital Outputs on an Arduino from a Raspberry Pi

Problem

You want to control Arduino digital outputs from Python on a Raspberry Pi.

Solution

In Recipe 18.3, you flashed the built-in LED (labeled with an L) on the Arduino board. Here, you build on this to attach an external LED and write a short Python program to make it blink.

To make this recipe, you will need the following:

As an alternative to using a breadboard and an LED, you could plug in one color channel of a Squid RGB LED (Recipe 9.10).

Connect the breadboard to the Arduino, as shown in Figure 18-5.

F14b05
Figure 18-5. Wiring diagram for an Arduino and an LED

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The Python script that follows makes the LED blink at a rate of about 1 Hz.

You can find this program in the Python section of the book downloads, where it is called ch_18_ardu_flash.py (see Recipe 3.22):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
led_pin = board.get_pin('d:10:o')

while True:
    led_pin.write(1)
    time.sleep(0.5)
    led_pin.write(0)
    time.sleep(0.5)

Discussion

This is very similar to connecting an LED to a Raspberry Pi (Recipe 10.1). However, since Arduino outputs can supply a lot more current than Raspberry Pi outputs, you can use a smaller value resistor and make the LED a bit brighter. Arduino Uno outputs are also 5V rather than 3.3V.

If you want the user interface (UI) to control the LED like you set it up to do in Recipe 10.8 (and as shown in Figure 18-6), it’s pretty straightforward to modify the code. You can find the modified program, called ch_18_ardu_gui_switch.py, in the book’s downloads. Remember, this will not work from the Secure Shell (SSH) command line. You need to have access to the Raspberry Pi’s graphical environment so that you can see the UI.

Figure 18-6. A UI for turning things on and off

See Also

For controlling an LED directly from a Raspberry Pi, see Recipe 10.1.

18.5 Using PyFirmata with TTL Serial

Problem

You want to use PyFirmata over the serial connection (RXD and TXD on the GPIO connector) rather than by USB.

Solution

Use a level converter to connect the RXD pin of the Raspberry Pi to the Tx pin of the Arduino, and the TXD pin of the Raspberry Pi to the Rx pin of the Arduino.

To make this recipe, you will need the following:

If you are using the level converter module (rather than making your own level converter), connect the breadboard as shown in Figure 18-7.

F14b07
Figure 18-7. Wiring diagram, using a level converter module for serial communication with an Arduino

If, on the other hand, you are using the pair of resistors, connect the breadboard as shown in Figure 18-8.

The Arduino Rx input is fine with just 3.3V from the Raspberry Pi TXD pin; however, the 5V coming from the Arduino Tx pin must be dropped to the 3V expected by the Raspberry Pi.

You will need to set up PyFirmata (see Recipe 18.3). The Arduino side of the project remains exactly the same as Recipe 18.4, where USB is used instead of the serial connection. There is one change that you need to make to the Python program running on the Raspberry Pi: change the device name from /dev/ttyACM0 to /dev/ttyS0 because the serial port has a different device name from the USB interface.

F14b08
Figure 18-8. Wiring diagram, using a pair of resistors for serial communication with an Arduino

The following Python script makes the LED blink at a rate of about 1 Hz (you can find the code in ch_18_ardu_flash_ser.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyS0')
led_pin = board.get_pin('d:13:o')

while True:
    led_pin.write(1)
    time.sleep(0.5)
    led_pin.write(0)
    time.sleep(0.5)

Discussion

The level conversion is necessary because the Raspberry Pi serial port connections, RXD and TXD, operate at 3.3V, whereas the Arduino Uno operates at 5V. Although it is OK for the 5V Arduino to use a 3.3V signal, the reverse is not true, and a 5V signal connected to the 3.3V RXD pin is likely to damage the Raspberry Pi.

See Also

You can also easily adapt the other examples that use PyFirmata (Recipes 18.5 through 18.8) to use a serial rather than a USB connection, simply by changing the device name in the Python program.

18.6 Reading Arduino Digital Inputs Using PyFirmata

Problem

You want to read Arduino digital inputs from Python on a Raspberry Pi.

Solution

Use PyFirmata to read a digital input on the Arduino.

To make this recipe, you will need the following:

Connect the breadboard, fastening the components to the Arduino as shown in Figure 18-9. If you prefer, you could also use a Squid Button switch instead of a breadboard (Recipe 9.11).

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script prints out a message every time the switch is pressed (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_switch.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
switch_pin = board.get_pin('d:4:i')
it = pyfirmata.util.Iterator(board)
it.start()
switch_pin.enable_reporting()

while True:
    input_state = switch_pin.read()
    if input_state == False:
        print('Button Pressed')
        time.sleep(0.2)
F14b09
Figure 18-9. Wiring diagram for an Arduino and a push switch

When you run it, nothing happens for a second or two while the Firmata sketch starts and establishes communication with the Raspberry Pi. But after it starts, a message appears each time you press the button:

$ sudo python ardu_switch.py
Button Pressed
Button Pressed
Button Pressed

Discussion

PyFirmata uses the concept of an Iterator to monitor the Arduino input pin. The reasons for this are bound up in the implementation of Firmata. This means that you can’t simply read the value of an Arduino input pin on demand; instead, you need to create a separate Iterator thread that manages the reading of the switch by using these commands:

it = pyfirmata.util.Iterator(board)
it.start()

You then also need to enable reporting for the pin you are interested in by using the following command:

switch_pin.enable_reporting()

A side effect of this mechanism is that when you press Ctrl-C to exit the program, it won’t exit properly. There is no nice way to kill the Iterator thread other than to open another Terminal window or SSH session and kill the process (Recipe 3.28).

If the only Python process running is this program, you can kill it by using this command:

$ sudo killall python

Simply disconnecting the Arduino from the Raspberry Pi, which will break the communication link, will also cause the Python program to exit.

See Also

This is very similar to connecting a switch directly to a Raspberry Pi (Recipe 12.1), and if you have just one switch, there is no real benefit in using an Arduino like this.

18.7 Reading Arduino Analog Inputs Using PyFirmata

Problem

You want to read Arduino analog inputs from Python on a Raspberry Pi.

Solution

Use PyFirmata to read an analog input on the Arduino.

To make this recipe, you will need the following:

Connect the breadboard to the Arduino as shown in Figure 18-10.

F14b10
Figure 18-10. Wiring diagram for an Arduino and a trimpot

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script will display both the raw reading from the analog input and the voltage at the analog input (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_adc.py [see Recipe 3.22]):

import pyfirmata
import time

board = pyfirmata.Arduino('/dev/ttyACM0')
analog_pin = board.get_pin('a:0:i')
it = pyfirmata.util.Iterator(board)
it.start()
analog_pin.enable_reporting()

while True:
    reading = analog_pin.read()
    if reading != None:
        voltage = reading * 5.0
        print("Reading=%f	Voltage=%f" % (reading, voltage))
        time.sleep(1)

The analog reading will be a value between 0.0 and 1.0:

$ sudo python ardu_adc.py
Reading=0.000000    Voltage=0.000000
Reading=0.165200    Voltage=0.826000
Reading=0.784000    Voltage=3.920000
Reading=1.000000    Voltage=5.000000

Discussion

The program is very similar to that of Recipe 18.6. You must use an Iterator, and the same problems of stopping the program apply.

The if statement is needed because if the first read is made before the actual reading from the analog input has happened, the read will return None rather than a number. The if statement effectively causes the program to ignore any null readings.

See Also

To use digital inputs, see Recipe 18.6.

18.8 Analog Outputs (PWM) with PyFirmata

Problem

You want to control the brightness of an LED by using PWM through an Arduino.

Solution

Use PyFirmata to send commands to an Arduino to generate a PWM signal on one of its outputs.

To make this recipe, you will need the following:

Connect the breadboard to the Arduino as shown in Figure 18-11.

If you haven’t already done so, follow Recipe 18.3 to set up PyFirmata.

F14b11
Figure 18-11. Wiring diagram for Arduino PWM control of an LED

The following Python script prompts you to enter a value for the PWM power and then set the LED brightness accordingly (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_pwm.py [see Recipe 3.22]):

import pyfirmata

board = pyfirmata.Arduino('/dev/ttyACM0')
led_pin = board.get_pin('d:10:p')

while True:
    duty_s = input("Enter Brightness (0 to 100):")
    duty = int(duty_s)
    led_pin.write(duty / 100.0)

With the value entered as 100, the LED should be at full brightness. The brightness decreases as the number decreases:

$ python3 ch_18_ardu_pwm.py
Enter Brightness (0 to 100):100
Enter Brightness (0 to 100):50
Enter Brightness (0 to 100):10
Enter Brightness (0 to 100):5

Discussion

The sketch for this is actually very straightforward. You define the output as PWM output using this command:

led_pin = board.get_pin('d:10:p')

The p is for PWM. But remember, this works only on Arduino pins marked with a ~ symbol.

We can also modify the slider control (Figure 18-12) so that it will operate through PyFirmata. You can download this sketch as ch_18_ardu_gui_slider.

Figure 18-12. A user interface for controlling LED brightness

See Also

Although an Arduino can deliver 40 mA to an output—roughly 10 times the current available on a Raspberry Pi GPIO pin—that’s still not enough to directly drive a motor or high-power LED module. To do that, you would need to use the circuit described in Recipe 11.4, modified to use an Arduino output pin rather than a Raspberry Pi GPIO pin.

18.9 Controlling a Servo Using PyFirmata

Problem

You want to control the position of a servo motor by using an Arduino.

Solution

Use PyFirmata to send commands to an Arduino to generate the pulses necessary to control the position of a servo motor.

To make this recipe, you will need the following:

Connect the breadboard as shown in Figure 18-13.

F14b13
Figure 18-13. Wiring diagram for an Arduino controlling a servo motor

If you have not already done so, follow Recipe 18.3 to set up PyFirmata.

The following Python script prompts you to enter a value for the servo’s angle and then set the arm of the servo motor accordingly (you can find the program in the Python section of this book’s downloads, where it is called ch_18_ardu_servo.py [see Recipe 3.22]):

import pyfirmata

board = pyfirmata.Arduino('/dev/ttyACM0')
servo_pin = board.get_pin('d:11:s')

while True:
    angle_s = input("Enter Angle (0 to 180):")
    angle = int(angle_s)
    servo_pin.write(angle)

With the value entered as 0, the servo should be at one end of its travel. Changing this to 180 sends it to the other end, and 90 puts it somewhere in the middle:

$ python3 ch_18_ardu_servo.py
Enter Angle (0 to 180):0
Enter Angle (0 to 180):180
Enter Angle (0 to 180):90

Discussion

The sketch for this is actually very straightforward. You define the output as a servo output by using this command:

servo_pin = board.get_pin('d:11:s')

The s is for servo. This can be used on any of the Arduino digital pins.

If you’ve built Recipe 11.1, you might notice that, by comparison, there is no jitter of the servo when used with an Arduino in this way.

See Also

The straight Raspberry Pi–only solution to using a servo motor is described in Recipes 11.1, 11.2, and 11.3.

18.10 Using Small Arduino Boards with a Raspberry Pi

Problem

You want to use an Arduino board with a Raspberry Pi, but you would like something more compact.

Solution

Use one of the small breadboard-friendly Arduino boards.

Figure 18-14 shows an Arduino Pro Mini board. Boards like this have the great advantage that they can be plugged directly into the breadboard along with other components needed for the project. The Pro Mini board is also available in a 3.3V version, which avoids any need for level conversion when you’re using it with a Raspberry Pi.

rpck 1417
Figure 18-14. An Arduino Pro Mini and programming interface

Discussion

Some of these boards, such as the Pro Mini shown in Figure 18-14, require a USB programming interface. You can program them from the Raspberry Pi, or from another computer if that proves problematic.

In addition to official Arduino boards, you can also find many low-cost clones that would make a great companion to the Raspberry Pi.

See Also

WiFi-enabled boards are ideal for IoT and home automation; see Recipe 18.11.

Here are some other boards to consider:

18.11 Using Small WiFi-Enabled Arduino-Compatibles (ESP8266)

Problem

You want to be able to program an ESP8266 WiFi-enabled board like the Wemos D1 Mini from your Raspberry Pi.

Solution

Install board support for the ESP8266 into your Arduino IDE on your Raspberry Pi and then program the board using a USB lead.

The ESP8266 WiFi-enabled microcontroller chip has found its way onto many low-cost boards. One of the most popular of these is the Wemos D1 (Figure 18-15).

Figure 18-15. The Wemos D1 Mini

This board is similar to the Arduino Pro Mini and even costs about the same, but it includes a USB programming interface and WiFi hardware, making it a tremendous value for the money. To add support for it to the Arduino IDE, you need to do the following.

Assuming that you have followed Recipe 18.1 and installed the Arduino IDE (version 1.8.5 or later) on your Raspberry Pi (Raspberry Pi 3 or 4 preferred for speed), open the Preferences option from the File menu, and then click the button at the end of the Additional Boards Manager URLs line (Figure 18-16).

Figure 18-16. Adding a URL to the Boards Manager URL

Then, in the text area that appears for Additional Boards Manager URLs, enter the URL http://arduino.esp8266.com/stable/package_esp8266com_index.json and click OK, and then, OK again to close the Preferences panel.

For the second part of the installation, open the Boards Manager from the Tools → Board menu. In the Search area, enter esp8266 (Figure 18-17).

Figure 18-17. Searching for ESP8266 boards in the Boards Manager.

This should find the board type of esp8266 by ESP8266 Community. Select this board type and then click Install.

This adds new board types to your Boards menu, including the Wemos D1 and lots of other ESP8266-based boards.

Discussion

You can test this out by connecting a Wemos D1 Mini to your Raspberry Pi with a USB lead and then loading the Arduino Blink sketch from the File → Examples → 01.Basics menu.

Select a board type of WeMos D1 R1 (Figure 18-18), make sure the port is set to /dev/ttyUSB0, and then click the upload button. When the compile and upload process has finished, the LED built into the Wemos D1 should begin to blink.

Figure 18-18. Selecting a board type of WeMos R1

The compiler has to do a lot more work compiling for the ESP8266, and you will notice that, even on a Raspberry Pi 4, it takes quite a long time to finish. If you want to speed things up, you can follow the aforementioned steps and add ESP8266 support to your laptop or desktop computer.

See Also

The ESP8266 chip used in the Wemos D1 Mini is a very close relative of the chip used in the Sonoff web switch from Recipe 17.3, and the Sonoff can (if you really want to do so) be reprogrammed as if it were a D1 Mini.

For more conventional small Arduinos, see Recipe 18.10.

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

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