Raspberry Pi to Arduino Using Firmata - Featured

How to Control an Arduino from a Raspberry Pi

The “should I use a Raspberry Pi, or should I use an Arduino” question always comes up in the first stages of product development. Honestly, who wouldn’t be confused? Both boards are popular, but there are subtle differences in their optimal use cases.

The Raspberry Pi is a computer, so it uses an operating system. This creates multiple layers of abstraction that make real-time signal generation and detection unreliable. On the other hand, the Arduino can read and write electronic signals much faster and more reliably than the Raspberry Pi.

Luckily the Arduino and Raspberry Pi can be used together to take advantage of features from each board.

In this tutorial we will learn how to control the Arduino’s GPIO pins with a Python program run on the Raspberry Pi. The Arduino will be connected to the Raspberry Pi directly with a USB cable. To do this, we will use a protocol called Firmata.

Firmata

Firmata is a communication protocol that connects a microcontroller to software on a host computer. Think of Firmata as a language that the Raspberry Pi and the Arduino both understand.

Setting Up the Arduino

The easiest way to setup Firmata on the Arduino is by using the Raspberry Pi. First, we need to install the required software.

1. Connect the Raspberry Pi to the internet. Open command terminal and enter the following command:

sudo apt-get -y install arduino python-serial mercurial

2. Now, connect the Arduino to the Raspberry Pi with an A to B USB cable.

3. Open the Arduino IDE, and select the correct port for the device.

4. Next, upload the PyFirmata firmware to the Arduino by opening the sketch from File > Examples >  Firmata > Standard Firmata.

5. Finally, click the upload button.

Setting Up the Raspberry Pi

To prepare the Raspberry Pi:

1. First, install the pyFirmata files by entering this:

git clone https://github.com/tino/pyFirmata

2. Then, run the following commands:

cd pyFirmata
sudo python setup.py install

Preparing the Hardware

To demonstrate how Firmata works, we will build a project that uses a Python program on the Raspberry Pi to control the Arduino’s GPIO pins. We will connect a button and LED to the Arduino so that the LED lights up when the button is pressed.

To build this project, we need the following components:

Follow this diagram to connect the LED and push button to the Arduino. The Arduino is connected to the Raspberry Pi with an A to B USB cable like this:

How to control an Arduino with a Raspberry Pi

To learn more about the Arduino, check out our Ultimate Guide to the Arduino video course. We teach Arduino programming and circuit building techniques that will prepare you to build any project.

Python Code

Copy the code below to your Raspberry Pi and save it as a “.py” file. Run the program by typing python filename.py:

import pyfirmata

led_pin = 7
button_pin = 8

board = pyfirmata.Arduino("/dev/ttyACM0")

while True:
    if board.digital[button_pin].read(1):
        board.digital[led_pin].write(1)
    else:
        board.digital[led_pin].write(0)

Code Explanation

First, we import the pyfirmata library using import pyfirmata. Then we label the LED and button pins by storing them into variables: led_pin and button_pin. To make this program connect to the Arduino, we need to tell it the port where the Arduino is connected. Use pyfirmata.Arduino() and then create the instance by assigning the port in the board variable. In this case it’s /dev/ttyACM0.

The while loop basically acts like void setup(). We use an if statement to monitor the status of the button. If the button sends a HIGH signal, meaning it was pressed, the LED lights up. Both use the digital[].read and digital[].write methods to control the GPIO pins on the Arduino.

Now when you press the button the LED should light up. Press CTRL + C to stop the program.

Hope this tutorial has helped you to understand how to control the Arduino with a Raspberry Pi. Leave a comment below if you have any questions!

  • Minty says:

    Thanks for the great article, very cool.

    I used a similar approach myself but went with Javascript as the language of choice and used a Raspberry PI to host the database, web server, etc using NodeJS communicating with the Arduino using Firmata via Johnny Five API which worked out great, basically gives me a web front end to control all my sensors, pumps, etc. Demo of the UI is available at mintyhydro.netlify.app and the source code is in GitHub if anyone is interested.

    Reason I found your article is that I am thinking about removing the Arduino requirement and considering using a Grove Shield on the PI then reading the sensors directly from the PI so just wondered what your thoughts on that would be?

  • Heinrich says:

    Hi. I followed the instructions to the letter, but I keep getting an error when trying to run the code

    Traceback (most recent call last):
    File “/home/pi/Documents/pyFirmataProjects/FirmataFirstTest.py”, line 1, in
    import pyfirmata
    File “/usr/lib/python3/dist-packages/thonny/backend.py”, line 290, in _custom_import
    module = self._original_import(*args, **kw)
    ImportError: No module named ‘pyfirmata’

  • Michelle says:

    File “/usr/lib/python3/dist-packages/thonny/backend.py”, line 290, in
    I am not certain, but I think the error is having one extra character right before the word packages

  • Peter says:

    Can you help please? I’m getting an error message as follows when running the Python code:
    Traceback (most recent call last):
    File “/dev/pyFirmata/test_firmata.py”, line 9, in
    if board.digital[button_pin].read(1):
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    TypeError: Pin.read() takes 1 positional argument but 2 were given

    This is using Python.3.11.2 on a clean install of Debian GNU/Linux 12 (bookworm) running on a Raspberry Pi Model 4B connected by serial port to an Arduino Uno R3. Thank you in advance for any advice.

    • Peter says:

      After some digging around in the library code and some experimentation I managed to find something that worked.

      #!/usr/bin/env python3

      import pyfirmata

      led_pin = 7
      button_pin = 8

      board = pyfirmata.Arduino(“/dev/ttyACM0”)
      board.digital[button_pin]._set_mode(0)
      board.digital[button_pin].enable_reporting()

      while True:
      board.iterate()
      if board.digital[button_pin].read():
      board.digital[led_pin].write(1)
      else:
      board.digital[led_pin].write(0)

      • Peter says:

        The python indentation for the while loop and he if-else conditions has been stripped out for some reason. Please just put it back in if you copy the code.

    • Peter says:

      I forgot to mention that the error occurs without the button being pressed at all.

  • KLL-engineering says:

    Fritzing circuit picture show a
    + + Arduino USB connected to
    – – Raspberry Pi Ethernet

  • Leave a Comment

    Your email address will not be published. Required fields are marked *