How to communicate between a Raspberry Pi and an Arduino over serial

Based on contributions by Jasonbrowne.

Use this setup when you want a Raspberry Pi to act as the “brain” (Wi-Fi, higher-level logic, vision, etc.) while an Arduino handles real-time control of motors and servos. The two boards talk to each other over a USB serial connection, the same way a PC and Arduino would (see How to control an Arduino from Python over a serial connection for the general pattern).

What you need

  • Raspberry Pi (any model with a USB port)
  • Arduino board
  • USB cable between the Pi and the Arduino
  • pyserial on the Raspberry Pi: pip install pyserial
  • A stepper motor (for the example below) or other actuator

Steps

1. Connect the boards

Connect the Raspberry Pi to the Arduino with a USB cable. The Pi will recognize the Arduino as a serial device, typically /dev/ttyUSB0 or /dev/ttyACM0. Check which one with ls /dev/tty* before and after plugging in the Arduino.

2. Write the Arduino sketch

The Arduino listens for text commands over serial and drives the hardware. This example moves a stepper motor up or down one revolution per command:

#include <Stepper.h>

const int stepsPerRevolution = 200; // Adjust for your stepper motor
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11); // Motor pins

void setup() {
    Serial.begin(9600); // Start serial communication
    myStepper.setSpeed(60); // Set motor speed
    Serial.println("Arduino ready");
}

void loop() {
    if (Serial.available() > 0) {
        String command = Serial.readStringUntil('\n');

        if (command == "up") {
            myStepper.step(stepsPerRevolution); // Move motor one revolution forward
            Serial.println("Moved up");
        } else if (command == "down") {
            myStepper.step(-stepsPerRevolution); // Move motor one revolution backward
            Serial.println("Moved down");
        }
    }
}

:warning: Check: pins 8–11 and 9600 baud are just this example’s values — match them to your own wiring and adjust stepsPerRevolution to your motor’s datasheet.

3. Write the Raspberry Pi (Python) side

Wrap the serial connection in a small class so the rest of your code doesn’t need to deal with the port directly:

# arduino.py
import serial
import time


class ArduinoConnection:
    def __init__(self, port="/dev/ttyUSB0", baudrate=9600):
        self.serial = serial.Serial(port, baudrate, timeout=1)
        time.sleep(2)  # Wait for the Arduino to reset after opening the port

    def move_manual(self, direction):
        if direction in ["up", "down"]:
            self.serial.write(f"{direction}\n".encode())
            feedback = self.serial.readline().decode().strip()
            print(f"Arduino says: {feedback}")

    def close(self):
        self.serial.close()

4. Use it from your main script

from arduino import ArduinoConnection

if __name__ == "__main__":
    arduino = ArduinoConnection()
    arduino.move_manual("up")
    arduino.move_manual("down")
    arduino.close()

Troubleshooting

  • Wrong serial device: if you have other USB-serial devices connected, /dev/ttyUSB0 might not be the Arduino. Run ls /dev/tty* with the Arduino unplugged, then plugged in, to see which device appears.
  • Permission denied opening the port on Linux: see the permissions fix in How to read a weight scale over RS-232/serial in Python.
  • Give the Arduino ~2 seconds after opening the serial port before sending commands — it resets when the port opens, and commands sent too early are lost.

Related


Rewritten and consolidated (Sept 2026) from the original student how-to’s: How to Communicate Between a Raspberry Pi and an Arduino.