~ / projects / robot-arm

Voice Controlled Robot Arm

A robotic arm I designed in Fusion 360, 3D printed, and wired myself. It moves when I speak to it: a Raspberry Pi turns my voice into text and sends it over USB serial to an Arduino, which drives five servo motors.

  • Arduino
  • Raspberry Pi
  • Fusion 360
  • PySerial
  • Speech Recognition
  • 3D Printing
TimelineMar 2025 – Jun 2025
StatusComplete
My roleSolo project: CAD, printing, wiring, code
ToolsFusion 360, Arduino, Raspberry Pi, Python, C++

Overview

I wanted to build a robot arm that didn't need a controller. Instead you just tell it where to go. The project combined everything I like doing: mechanical design, 3D printing, electronics, and embedded programming.

Voice command→ Raspberry Pi
speech recognition
→ USB serial
(PySerial)
→ Arduino
parses command
→ 5 servos move

The Raspberry Pi listens through a microphone and turns speech into text with Google's speech recognition. It sends that text to an Arduino Uno over USB. The Arduino matches the text to a command and sets each servo to the position I asked for. Each joint has ten preset positions, 18° apart.

CAD & 3D printing

I designed every part in Fusion 360 and printed them. I started with the claw. A servo turns a gear, and the gear opens and closes the two prongs through a pair of linkages. I generated the gears with Fusion's Spur Gear add-in, so I could set the tooth count and size as parameters.

Claw V1 CAD assembly
Claw V1: base, drive gear, joints, and prongs (Mar 2025)
Updated claw base CAD
Updated claw base with a hole for the motor and a standoff to support it (Apr 2025)

Then I worked down the arm: a rotating base driven by a servo, a base arm joint, a middle arm joint, and a wrist. Each joint holds the servo that drives the next one. A few iterations made a big difference:

  • Straight arm joints (V2): easier to print, and the arms no longer clip each other as they rotate.
  • Center cutout (V3): the next joint bolts straight onto the servo horn, so I didn't need an extra bridging part.
  • Redesigned base: mounts directly to the bottom rotation servo, with a larger opening so the arm servo fits reliably.
Arm base CAD
Base with an upright mount for the servo that turns the base arm joint
Middle arm joint V3 CAD
Middle arm joint V3: the center cutout lets the next joint bolt straight onto the servo
Full robot arm CAD assembly
Full robot arm assembly in Fusion 360
Engineering drawing of the claw assembly
Engineering drawing of the claw assembly

Electronics

The arm uses five servo motors. Each has a red power wire, a black ground wire, and an orange signal wire that goes to the Arduino. I wired the servos in parallel to the battery supply. In parallel, every servo sees the same 6 V. In series I would have needed 30 V to run all five.

There were two ways to connect the Pi and the Arduino: directly through the GPIO pins with UART, or through a USB cable. The GPIO route needs a level shifter, because the Arduino's 5 V logic could damage the Pi's 3.3 V pins. I used USB instead. The Pi detects the Arduino as a serial device (/dev/ttyACM0), and no extra hardware is needed.

Software

Raspberry Pi (Python)

I set up the Pi in a Python virtual environment and installed the SpeechRecognition, PyAudio, and pyserial libraries there. The script opens a serial connection to the Arduino, then loops forever: listen, convert speech to text, and send the text with a newline at the end.

import speech_recognition as sr
import serial
import time

arduino = serial.Serial('/dev/ttyACM0', 9600)   # baud rate must match the Arduino
time.sleep(2)
recognizer = sr.Recognizer()

while True:
    with sr.Microphone(device_index=2) as source:
        audio = recognizer.listen(source)
        command = recognizer.recognize_google(audio)
        print(command)
        arduino.write((command + "\n").encode())

Arduino (C++)

The Arduino sketch uses the Servo library and attaches each servo to its own pin. In loop() it waits for Serial.available(), then reads the incoming text with Serial.readStringUntil('\n') and calls trim() to remove stray spaces. A chain of if statements maps each spoken command to a servo angle.

Arduino servo setup code
Arduino setup: servo pins and serial at 9600 baud
Arduino command if statements
Command mapping: ten positions per joint, 18° apart

Testing

I tested in stages, so when something broke I knew which part caused it. First a single servo from the Arduino IDE. Then voice control of the base. Then commanding each joint to a specific position.

Base servo test from the Arduino IDE
Rotating the base with a voice command
Moving the arm to commanded positions

Challenges & lessons learned

Breaking the Pi's software setup. Raspberry Pi OS blocks installing Python packages system-wide and shows an externally-managed-environment error. While I tried fixes from several different sources, the installs conflicted and the Pi stopped working properly. I had to wipe the SD card, reinstall the OS, and start the code over.

Raspberry Pi terminal showing an externally-managed-environment error
The error that started it all
What I do now: install libraries inside a Python virtual environment (venv), reboot after every install, and change one thing at a time.

UART vs. USB. My first attempt sent commands over UART through the GPIO pins, and it didn't work. Switching to PySerial over USB was simpler, needed no level shifter, and worked on the first try.

Designing for printing. Straightening the arm joints and letting each joint mount directly to a servo cut down on print failures, extra parts, and parts colliding as the arm moved.

The finished arm

Voice-controlled arm moving between commanded positions
Full demo of the finished arm
Assembled red 3D-printed robot arm
The assembled robot arm
Robot arm on the desk next to its Arduino
The arm with its Arduino and wiring