Build a Robot That
Draws Your Face!
🔍 How Does It Work?
This robot combines a camera, a tiny computer, and a servo-powered drawing arm into one amazing machine. Here's the magic flow:
Pi Camera captures your face photo
Python converts the photo into pencil-sketch lines
Code turns sketch lines into robot arm movements (G-code)
Servo motors move the pen and sketch your portrait
🛒 What You'll Need
Gather these parts before you start. Most are available online or at your local electronics shop.
⚡ Circuit Diagram
Here's how to connect all the parts together. Read carefully before wiring!
🔧 Step-by-Step Build Guide
Follow these steps in order. Take your time — good robots are built carefully! 🛠️
🍓 Set Up Raspberry Pi OS
Flash Raspberry Pi OS (64-bit) onto a 16GB+ microSD card using the Raspberry Pi Imager tool. Boot it up, connect to Wi-Fi, and open a terminal.
TERMINALsudo apt-get update && sudo apt-get upgrade -y sudo apt-get install python3-pip python3-opencv -y pip3 install adafruit-circuitpython-pca9685 adafruit-circuitpython-motor pip3 install Pillow numpy opencv-python
📷 Enable Pi Camera & I²C
Enable the camera module and I²C interface so the Pi can talk to the servo driver board.
TERMINALsudo raspi-config
Navigate to: Interface Options → Camera → Enable
Then: Interface Options → I2C → Enable
Reboot when asked.
🦾 Assemble the Robot Arm
Build the 3-axis arm using your kit or 3D-printed parts. Attach servos at each joint:
- Base joint: Servo X — rotates the whole arm left/right
- Elbow joint: Servo Y — raises and lowers the arm
- Pen holder: Servo Z — lifts pen up (travel) and down (draw)
Hot-glue or clip a fine-tip marker into the pen holder at the end of the arm.
🔌 Wire Everything Up
Follow the circuit diagram above. Key things to remember:
- PCA9685 → Pi via I²C (SDA + SCL + 3.3V + GND)
- Each servo's 3-pin connector → PCA9685 channel (signal/power/ground)
- Servos powered by the separate 6V supply (V+ terminal)
📸 Python: Capture & Convert Selfie
This Python script captures a photo and converts it into a pencil-sketch style image that the robot can draw.
selfie_sketch.py# selfie_sketch.py — Capture face & make sketch import cv2 import numpy as np from picamera2 import Picamera2 from PIL import Image # ── 1. Capture selfie ────────────────────────── picam2 = Picamera2() picam2.start_preview() picam2.capture_file("selfie.jpg") picam2.stop_preview() print("📸 Selfie captured!") # ── 2. Convert to pencil sketch ──────────────── img = cv2.imread("selfie.jpg") gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Invert + blur = pencil sketch effect inv = cv2.bitwise_not(gray) blur = cv2.GaussianBlur(inv, (21, 21), 0) sketch = cv2.divide(gray, cv2.bitwise_not(blur), scale=256.0) # Threshold to get clean lines for drawing _, bw = cv2.threshold(sketch, 200, 255, cv2.THRESH_BINARY_INV) cv2.imwrite("sketch.png", bw) print("✏️ Sketch image saved as sketch.png")
🗺️ Python: Convert Sketch to Robot Paths
This script traces the sketch image into a series of (x, y) coordinates the robot arm will follow.
image_to_paths.py# image_to_paths.py — Find draw paths from sketch import cv2 import numpy as np def get_draw_paths(sketch_file): img = cv2.imread(sketch_file, cv2.IMREAD_GRAYSCALE) # Resize to match drawing area (150x150 mm robot range) img = cv2.resize(img, (150, 150)) # Find contours (the lines to draw) contours, _ = cv2.findContours( img, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE ) paths = [] for cnt in contours: if cv2.arcLength(cnt, False) > 10: # skip tiny dots path = [(pt[0][0], pt[0][1]) for pt in cnt] paths.append(path) print(f"📐 Found {len(paths)} paths to draw") return paths
Python: Control the Robot Arm
The main drawing script! It moves the servos to follow the sketch paths.
draw_face.py# draw_face.py — Make the robot draw! import board, busio, time from adafruit_pca9685 import PCA9685 from adafruit_motor import servo from image_to_paths import get_draw_paths # ── Setup I2C and servo driver ────────────────── i2c = busio.I2C(board.SCL, board.SDA) pca = PCA9685(i2c) pca.frequency = 50 # Create servo objects servo_x = servo.Servo(pca.channels[0], min_pulse=500, max_pulse=2400) servo_y = servo.Servo(pca.channels[1], min_pulse=500, max_pulse=2400) servo_z = servo.Servo(pca.channels[2], min_pulse=500, max_pulse=2400) # ── Helper functions ──────────────────────────── def pen_up(): servo_z.angle = 90 # lift pen off paper time.sleep(0.3) def pen_down(): servo_z.angle = 50 # press pen onto paper time.sleep(0.3) def move_to(x, y): # Map pixel coords (0-150) to servo angles (30-150°) angle_x = int(30 + (x / 150) * 120) angle_y = int(30 + (y / 150) * 120) servo_x.angle = angle_x servo_y.angle = angle_y time.sleep(0.05) # small delay between moves # ── Main drawing routine ──────────────────────── print("🎨 Starting to draw your face...") paths = get_draw_paths("sketch.png") pen_up() # start with pen raised for path in paths: # Travel to start of each stroke move_to(path[0][0], path[0][1]) pen_down() # Draw the stroke for (x, y) in path[1:]: move_to(x, y) pen_up() # lift between strokes print("✅ Drawing complete! Check your paper!")
selfie_sketch.py, then run draw_face.py — both in the same folder!🛠️ Troubleshooting Guide
Something not working? Don't give up! Check this table first:
| 🔴 Problem | 🟡 Likely Cause | ✅ Fix |
|---|---|---|
| Camera not detected | Camera not enabled or ribbon not seated | Run raspi-config, enable camera, re-seat ribbon, reboot |
| Servos not moving | PCA9685 not found on I²C bus | Run i2cdetect -y 1 — should show address 0x40 |
| Arm shaking a lot | Insufficient servo power | Check 6V supply amperage — needs at least 2A for 3 servos |
| Drawing looks distorted | Servo angle mapping is off | Calibrate min/max angles in move_to() function |
| Sketch image is too dark | Threshold value too low | Change threshold(sketch, 200 ...) — try 180 or 220 |
| Pen tears paper | Pen-down angle pressing too hard | Change servo_z.angle = 50 to 60 or 65 |
🚀 Make It Even Cooler!
Once your robot is drawing faces, try these awesome upgrades:
❓ Frequently Asked Questions
Basic Python helps a lot! If you can understand loops and functions, you're ready. Start with free Python tutorials on YouTube if you're new.
Arduino alone can't run OpenCV for image processing. You can use an Arduino to control the servos and connect it to a PC or laptop that handles the image processing side.
Mechanical servo arms have some wobble. Expect a fun cartoon-style sketch, not a photorealistic portrait! That's part of the charm. 😄
A simple sketch takes about 5–15 minutes depending on how many strokes the image has. You can speed it up by simplifying the threshold in the sketch code.
Absolutely! Any photo works — pets, objects, logos. Just point the camera at anything and let the robot sketch away!

Comments
Post a Comment