UNO R3

// Programming Tutorial

Arduino Uno
+ Python
Sketches

Learn to write Arduino sketches in C++ and orchestrate them with Python — from a blinking LED to real-time serial communication.

Start Tutorial View Projects
Python 3.10+ Arduino IDE 2.x pyserial Beginner Friendly

What You Will Build

This tutorial teaches you to write Arduino sketches (C++) and then use Python on your PC to send commands and read data over a USB serial port. By the end you will have a fully functional LED control system driven by Python.

Key insight: Arduino runs its own C++ sketch independently. Python communicates with it via the serial port — you're orchestrating hardware from a high-level language without replacing the sketch.

Architecture Diagram

Python Script pyserial your-pc.py USB Serial 9600 baud Arduino Uno C++ Sketch serial read/write pin control ATmega328P GPIO 5V logic Hardware LED · Buzzer Sensors · Motors

Environment Setup

STEP 01

Install Arduino IDE 2

Download and install the Arduino IDE 2.x from the official website. Connect your Arduino Uno via USB. The IDE auto-detects the port on most systems.

BASH — verify board detection
# On Linux/macOS — list serial ports
ls /dev/tty*

# Typical Arduino Uno output:
/dev/ttyACM0    # Linux
/dev/cu.usbmodem14101  # macOS

# On Windows (PowerShell):
Get-WMIObject Win32_SerialPort

On Linux, add your user to the dialout group: sudo usermod -aG dialout $USER, then log out and back in.

STEP 02

Install Python Dependencies

We use pyserial to communicate with the Arduino over USB serial, and optionally rich for prettier terminal output.

BASH — pip install
pip install pyserial rich

# Verify installation
python -c "import serial; print(serial.__version__)"
# Expected: 3.5 or higher

STEP 03

Hardware: LED + Resistor Circuit

Wire a standard 5mm LED with a 220Ω resistor between Pin 13 and GND. Most Uno boards have a built-in LED on Pin 13 — no external wiring required for the first sketch.

Arduino PinComponentNotes
Pin 13LED anode (+) via 220Ω resistorBuilt-in LED also on this pin
GNDLED cathode (−)Any GND pin works
5VPower rail (optional)For external components
A0–A5Analog input (sensors)10-bit ADC, 0–5 V range
D2–D13Digital I/OPWM on 3, 5, 6, 9, 10, 11 (~)

Writing Your First Sketch

Every Arduino sketch has two required functions: setup() runs once at power-on, and loop() runs continuously. Our sketch will listen for single-character commands sent by Python over the serial port.

Sketch 1 — Blink (Baseline)

Upload this to confirm your hardware works before adding serial communication.

C++ — blink.ino
// blink.ino — classic first sketch
const int LED_PIN = 13;

void setup() {
  pinMode(LED_PIN, OUTPUT);  // set pin as output
}

void loop() {
  digitalWrite(LED_PIN, HIGH); // LED ON
  delay(1000);                 // wait 1 second
  digitalWrite(LED_PIN, LOW);  // LED OFF
  delay(1000);
}

Sketch 2 — Serial Command Listener

This is the sketch Python will talk to. It reads a character from the serial port: 'H' → LED on, 'L' → LED off, 'S' → read analog sensor.

C++ — serial_control.ino
// serial_control.ino
// Commands: H=LED on, L=LED off, S=read analog A0

const int LED_PIN    = 13;
const int SENSOR_PIN = A0;
char      cmd;

void setup() {
  Serial.begin(9600);          // open serial at 9600 baud
  pinMode(LED_PIN, OUTPUT);
  Serial.println("READY");    // handshake signal
}

void loop() {
  if (Serial.available() > 0) {
    cmd = (char) Serial.read();

    switch (cmd) {
      case 'H':
        digitalWrite(LED_PIN, HIGH);
        Serial.println("LED_ON");
        break;

      case 'L':
        digitalWrite(LED_PIN, LOW);
        Serial.println("LED_OFF");
        break;

      case 'S': {
        int val = analogRead(SENSOR_PIN);  // 0–1023
        Serial.print("SENSOR:");
        Serial.println(val);
        break;
      }

      default:
        Serial.println("ERR:UNKNOWN_CMD");
    }
  }
}

Upload the sketch via Arduino IDE → Upload (Ctrl+U) before running any Python script. The sketch stays on the board even after power-off.


Communicating via Python

pyserial lets Python open a virtual COM port and exchange bytes with the running Arduino sketch. The pattern is always: open port → wait for handshake → send command → read response.

Basic Connection

PYTHON — connect.py
import serial
import time

# ── configuration ──────────────────────────────────
PORT     = "/dev/ttyACM0"  # Windows: "COM3", macOS: "/dev/cu.usbmodem..."
BAUD     = 9600
TIMEOUT  = 2               # seconds before read() gives up

# ── open serial port ───────────────────────────────
with serial.Serial(PORT, BAUD, timeout=TIMEOUT) as ard:
    time.sleep(2)              # wait for Arduino reset after connect
    handshake = ard.readline().decode("utf-8").strip()
    print(f"Arduino says: {handshake}")  # expects "READY"

LED Controller Script

PYTHON — led_controller.py
import serial, time, sys

def send_command(port, cmd: str) -> str:
    """Send a single-char command and return the response line."""
    port.write(cmd.encode("utf-8"))
    return port.readline().decode("utf-8").strip()


def main():
    port_name = sys.argv[1] if len(sys.argv) > 1 else "/dev/ttyACM0"

    with serial.Serial(port_name, 9600, timeout=2) as ard:
        time.sleep(2)                       # allow board reset
        print(ard.readline().decode().strip())  # print "READY"

        # ── blink 5 times from Python ─────────────────
        for i in range(5):
            resp = send_command(ard, "H")   # LED on
            print(f"  [{i+1}/5] {resp}")
            time.sleep(0.5)

            resp = send_command(ard, "L")   # LED off
            print(f"  [{i+1}/5] {resp}")
            time.sleep(0.5)

        # ── read analog sensor ────────────────────────
        print("\n── Sensor reading ──")
        resp = send_command(ard, "S")
        print(resp)   # e.g. "SENSOR:512"


if __name__ == "__main__":
    main()

Interactive Terminal Controller

A simple REPL loop so you can type commands in real time.

PYTHON — repl.py
import serial, time

PORT = "/dev/ttyACM0"

with serial.Serial(PORT, 9600, timeout=1) as ard:
    time.sleep(2)
    print(ard.readline().decode().strip())
    print("Commands: H=on  L=off  S=sensor  Q=quit")

    while True:
        cmd = input(">> ").strip().upper()
        if cmd == "Q":
            print("Disconnecting."); break
        if cmd in ("H", "L", "S"):
            ard.write(cmd.encode())
            print(" ← ", ard.readline().decode().strip())
        else:
            print("Unknown command")

Project Ideas

PROJECT A

Temperature Logger

Wire an NTC thermistor to A0. Modify the sketch to return temperature strings ("TEMP:23.4"). In Python, log the values to a CSV with datetime timestamps and plot with matplotlib.

Use threading in Python to poll the sensor every second while the main thread handles user input.

PROJECT B

PWM LED Dimmer

Extend the sketch to accept numeric brightness values ('B:128\n') and call analogWrite(LED_PIN, value). In Python, send smoothly interpolated brightness curves — sunrise simulation, breathing effect, etc.

C++ — pwm extension
case 'B': {
  int brightness = Serial.parseInt();  // reads integer after 'B'
  brightness     = constrain(brightness, 0, 255);
  analogWrite(9, brightness);          // PWM pin 9
  Serial.print("PWM:");
  Serial.println(brightness);
  break;
}

PROJECT C

Web Dashboard with Flask

Wrap the serial logic in a Flask server exposing a REST API (/led/on, /led/off, /sensor). Build a minimal HTML front-end that controls the Arduino from a browser tab on any device on your local network.

PYTHON — flask_bridge.py (excerpt)
from flask import Flask, jsonify
import serial, time, threading

app = Flask(__name__)
ard = serial.Serial("/dev/ttyACM0", 9600, timeout=1)
time.sleep(2); ard.readline()  # consume READY

lock = threading.Lock()

def cmd(c):
    with lock:
        ard.write(c.encode())
        return ard.readline().decode().strip()

@app.route("/led/<state>")
def led(state):
    r = cmd("H" if state == "on" else "L")
    return jsonify(response=r)

@app.route("/sensor")
def sensor():
    return jsonify(data=cmd("S"))

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

Common Issues

SymptomCauseFix
SerialException: [Errno 13]Permission deniedsudo usermod -aG dialout $USER
No response from ArduinoWrong baud rateMatch Serial.begin() and pyserial baud
Garbage charactersReset during readAdd time.sleep(2) after Serial()
Port busy / in useArduino IDE Serial Monitor openClose the IDE Serial Monitor first
Empty readline()timeout too shortIncrease timeout=2 or higher
COM port not found (Windows)Driver not installedInstall CH340 or FTDI driver