AI-Based Exam Paper Evaluator

AI-Based Exam Paper Evaluator | Kids Robotics & AI Project 📝

AI-Based
Exam Paper
Evaluator

Build a robot that reads answer sheets and grades them automatically — just like a real AI teacher! 🤖📝

⏱️ 4–5 Hours 🎓 Ages 13+ 💰 Under $70 🐍 Python + Arduino 🧠 Real AI / NLP 🏆 Science Fair Gold
📄 Exam Paper
Q1
Q2
Q3
Q4
Q5
~
Score78 / 100
AI Graded
About This Project

What Makes This Project Amazing? 🌟

This is not just a robotics project — it's a real AI system! You'll combine a camera, a microcontroller, and Python code to build something that can actually READ handwriting and GRADE answers. The same technology powers real grading systems used in universities around the world!

👁️
Computer Vision

The camera "sees" and captures the answer sheet as an image

🔤
OCR Technology

Tesseract OCR converts handwritten/printed text into digital words

🧠
NLP Matching

Python compares answers using smart text similarity algorithms

Arduino Output

LED, buzzer, and LCD display the score in real time

📊
Score Calculation

AI calculates percentage, grade, and pass/fail automatically

🔗
Serial Communication

Python sends results to Arduino via USB serial port

How It Works

The AI Pipeline ⚙️

Seven steps happen in seconds when you press the scan button!

📄
Place Paper
Under camera
📸
Camera Captures
OpenCV snapshot
🔤
OCR Reads
Tesseract extracts text
🧠
NLP Compares
Matches answer key
📊
Score Calculated
% and grade
📡
Sent to Arduino
Via serial USB
Result Shown
LCD + LED + Buzzer

📊 LIVE EVALUATION EXAMPLE

Q1 — What is photosynthesis?10/10
Q2 — Name the planets8/10
Q3 — Newton's laws6/10
Q4 — Water cycle stages9/10
Q5 — Cell structure4/10

TOTAL SCORE

74%
Grade: B

37 / 50 marks
✅ PASS

Shopping List

What You Need 🛒

Most software is free and open-source! The hardware is affordable and reusable for many future projects.

🎛️
Arduino Uno / Mega
Displays results via LEDs + LCD
📷
USB Webcam (720p+)
Captures the answer sheet image
💻
Computer with Python 3
Runs the AI evaluation software
📟
16×2 LCD + I2C Module
Shows score and grade
🟢
Green LED × 2
Lights up for PASS result
🔴
Red LED × 2
Lights up for FAIL result
🔊
Piezo Buzzer
Different tones for pass/fail
🔘
Push Button × 1
Triggers the scan cycle
♻️
220Ω Resistors × 4
Protect the LEDs
🧶
Jumper Wires × 20
Connect everything
🔲
Breadboard
Build the circuit without soldering
🖨️
USB-B Cable
Connect Arduino to computer

💿 Free Software to Install

Python 3.10+
python.org — free download
Tesseract OCR
github.com/tesseract-ocr
Arduino IDE 2.x
arduino.cc — free download
pip packages
opencv-python, pyserial, pytesseract, difflib
Electronics

Circuit Diagram & Wiring ⚡

The Arduino hardware receives the score from Python and displays it. Wire everything up carefully — check twice before powering on!

🔌 Complete Wiring Table

ComponentWire / PinArduino PinNotes
Green LED 1 (Pass)Anode +PIN 3220Ω resistor on cathode → GND
Green LED 2 (Pass)Anode +PIN 4220Ω resistor on cathode → GND
Red LED 1 (Fail)Anode +PIN 5220Ω resistor on cathode → GND
Red LED 2 (Fail)Anode +PIN 6220Ω resistor on cathode → GND
Piezo BuzzerPositive +PIN 7Negative − → GND directly
Push Button (Scan)Pin 1PIN 2Other pin → GND. Uses INPUT_PULLUP
16×2 LCD (I2C)SDA / SCLA4 / A5VCC → 5V, GND → GND. I2C: 0x27
Arduino ↔ ComputerUSB SerialUSB PortThis is how Python sends scores to Arduino
ARDUINO UNO 🧠 Brain + Result Display D2 D3 D4 D5 D6 D7 A4(SDA) A5(SCL) 5V GND USB SCAN BUTTON Triggers scan 🔘 → Pin 2 GREEN LEDs ×2 PASS indicator ✅ → Pin 3 & Pin 4 RED LEDs ×2 FAIL indicator ❌ → Pin 5 & Pin 6 BUZZER 🔊 → Pin 7 LCD 16×2 I2C Shows score + grade 📟 A4(SDA) + A5(SCL) 💻 COMPUTER Python AI Script OpenCV + Tesseract OCR NLP Answer Matching → USB Serial to Arduino 📷 WEBCAM USB → Computer KEY: — — — Hardware wires ══ USB serial (Python ↔ Arduino) PASS LEDs FAIL LEDs LCD I2C Python serial
System Design

Software Architecture 🏗️

This project has two parts that talk to each other — the Python AI brain on your computer, and the Arduino display system.

🐍 Python AI Script (computer)

  • Captures image from webcam using OpenCV
  • Pre-processes image (grayscale, threshold, denoise)
  • Extracts text using pytesseract OCR
  • Parses question numbers and answers from text
  • Compares each answer to answer_key.json using difflib
  • Calculates total score and percentage
  • Assigns grade (A/B/C/D/F) and pass/fail
  • Sends result to Arduino via pyserial
  • Saves evaluation report as a text file

⚙️ Arduino Sketch (hardware)

  • Waits for scan button press (Pin 2)
  • Signals Python script via Serial when button pressed
  • Receives score string from Python (e.g., "74:B:PASS")
  • Parses the score, grade, and pass/fail values
  • Lights green LEDs for PASS, red for FAIL
  • Plays melodic tone on buzzer (happy vs sad)
  • Displays score and grade on 16×2 LCD
  • Returns to ready state after 8 seconds
Build Guide

Step-by-Step Instructions 🔧

Follow each step carefully. This project has more software than hardware — take your time with the Python setup!

1

💻 Set Up Python Environment

First, install all the software you need on your computer:

  • Download and install Python 3.10+ from python.org (check "Add to PATH" during install!)
  • Download and install Tesseract OCR from github.com/tesseract-ocr/tesseract
  • Note the Tesseract install path — you'll need it in the Python code
  • Open Command Prompt (Windows) or Terminal (Mac/Linux) and run:
  • pip install opencv-python pytesseract pyserial
  • Also install: pip install pillow numpy
💡 Pro Tip: If pip doesn't work, try "pip3" instead. On Windows, you might need to run Command Prompt as Administrator!
2

⚡ Build the Arduino Circuit

Wire all components to your Arduino using the circuit table above:

  • Set up power and GND rails on your breadboard
  • Connect Push Button to Pin 2 (other pin to GND)
  • Connect 2 Green LEDs with 220Ω resistors to Pins 3 and 4
  • Connect 2 Red LEDs with 220Ω resistors to Pins 5 and 6
  • Connect Buzzer (+) to Pin 7, (–) to GND
  • Connect LCD I2C: SDA → A4, SCL → A5, VCC → 5V, GND → GND
💡 Pro Tip: LEDs have a longer leg (+) and shorter leg (–). Always put the resistor between the Arduino pin and the LED's longer leg!
3

📝 Prepare Your Answer Key File

Create a file called answer_key.json in the same folder as your Python script. This is where you type the correct answers:

answer_key.json
{
  "subject": "General Science",
  "total_marks": 50,
  "pass_percentage": 40,
  "answers": {
    "Q1": "photosynthesis is the process by which plants make food using sunlight",
    "Q2": "mercury venus earth mars jupiter saturn uranus neptune",
    "Q3": "newton first law second law third law motion inertia",
    "Q4": "evaporation condensation precipitation collection",
    "Q5": "nucleus mitochondria cell membrane cytoplasm"
  },
  "marks_per_question": 10
}
ℹ️ Note: Keep your answer key text simple and lowercase. The AI uses keyword matching — more keywords = better accuracy!
4

🎛️ Set Up the Camera Stand

Position your webcam so it can clearly see the entire answer sheet:

  • Mount the webcam about 30–40cm above a flat white surface
  • A cardboard box with the webcam taped to the top works great!
  • Make sure the lighting is even — no shadows on the paper
  • Use a ruler to mark the paper placement area so every sheet goes in the same spot
  • Avoid shiny paper — it causes glare that confuses OCR
  • Test with cv2.imshow() first to check camera image quality
💡 Pro Tip: Print your exam papers in a clear font (Arial or Times New Roman, size 12+). OCR works much better on printed text than messy handwriting!
5

📤 Upload the Arduino Code

Open Arduino IDE, install required libraries, then upload the Arduino sketch below:

  • Install LiquidCrystal_I2C library: Sketch → Include Library → Manage Libraries → search "LiquidCrystal I2C"
  • Copy the Arduino code from the section below into a new sketch
  • Select: Tools → Board → Arduino Uno
  • Select: Tools → Port → your Arduino's COM port
  • Note the COM port number — you'll need it in the Python code!
  • Click Upload (right arrow button)
💡 Pro Tip: Write down your COM port (e.g., COM3 on Windows or /dev/ttyUSB0 on Linux). You'll enter this exact value in the Python script!
6

🐍 Run the Python AI Script

Now run the main Python evaluator script:

  • Open your Python file in VS Code or IDLE
  • Update the SERIAL_PORT variable to match your Arduino's COM port
  • Update TESSERACT_PATH to where you installed Tesseract
  • Run: python exam_evaluator.py
  • A camera preview window will open — you should see live video
  • If the camera preview looks good, you're ready to scan!
ℹ️ Make sure Arduino IDE's Serial Monitor is CLOSED before running Python — both can't use the serial port at the same time!
7

📄 Prepare the Exam Answer Sheet

Format your answer sheet so OCR can read it properly:

  • Print or write answers clearly with question labels (Q1:, Q2:, Q3: etc.)
  • Each answer should start on a new line
  • Use black pen on white paper for best OCR accuracy
  • Example format:
    Q1: Plants make food using sunlight
    Q2: Mercury Venus Earth Mars Jupiter
    Q3: Objects in motion stay in motion
💡 Pro Tip: Test OCR accuracy by scanning a printed sheet first. If OCR accuracy is below 80%, improve your lighting or increase the image contrast in the Python code!
8

🎉 Test the Full System!

Everything is connected — let's test your AI evaluator!

  • Python script should be running and showing camera preview
  • LCD on Arduino should show "Exam Evaluator — Ready to Scan"
  • Place a completed answer sheet under the camera
  • Press the scan button on your Arduino circuit
  • Watch the terminal — OCR extracts text, AI compares answers
  • Score appears on LCD within 5–10 seconds!
  • Green LEDs + happy tune = PASS, Red LEDs + sad tune = FAIL
💡 If the score is too low: Check the camera preview for blur, improve lighting, and make sure question labels (Q1:, Q2:) are clearly visible in the image.
Python AI Code

Python Evaluator Script 🐍

Save this as exam_evaluator.py in the same folder as your answer_key.json file.

exam_evaluator.py — Python 3 AI Script
# ============================================================
#   🤖 AI-BASED EXAM PAPER EVALUATOR — Python Script
#   Uses OpenCV + Tesseract OCR + NLP similarity matching
#   Communicates results to Arduino via Serial (USB)
# ============================================================

import cv2                    # OpenCV — camera and image processing
import pytesseract            # Tesseract OCR wrapper for Python
import serial                 # PySerial — talk to Arduino via USB
import json                   # Read the answer key JSON file
import time                   # For delays
import re                     # Regular expressions for text parsing
from difflib import SequenceMatcher   # NLP-style text similarity
from datetime import datetime  # For timestamps in reports

# ── CONFIGURATION — Change these to match YOUR setup ──
TESSERACT_PATH = r"C:\Program Files\Tesseract-OCR\tesseract.exe"  # Windows
# TESSERACT_PATH = "/usr/bin/tesseract"  # Linux / Mac

SERIAL_PORT   = "COM3"      # Change to your Arduino's port (COM3, COM5, /dev/ttyUSB0)
BAUD_RATE     = 9600        # Must match Arduino Serial.begin() baud rate
CAMERA_INDEX  = 0           # 0 = default webcam, 1 = second webcam
ANSWER_KEY_FILE = "answer_key.json"
MIN_SIMILARITY  = 0.35      # 35% match minimum to award any marks

# Set Tesseract path
pytesseract.pytesseract.tesseract_cmd = TESSERACT_PATH

# ── Load the Answer Key from JSON ──────────────────────
def load_answer_key():
    with open(ANSWER_KEY_FILE, "r") as f:
        data = json.load(f)
    print(f"✅ Loaded answer key: {data['subject']}")
    return data

# ── Capture Image from Webcam ──────────────────────────
def capture_image(cam):
    print("📸 Capturing image...")
    ret, frame = cam.read()
    if not ret:
        print("❌ Camera capture failed!")
        return None
    # Save the raw capture for debugging
    cv2.imwrite("last_capture.jpg", frame)
    return frame

# ── Pre-process Image for Better OCR ──────────────────
def preprocess_image(img):
    print("🔧 Pre-processing image for OCR...")
    # Step 1: Convert to grayscale
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # Step 2: Resize to 2× size (improves OCR on small text)
    scaled = cv2.resize(gray, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
    # Step 3: Apply Gaussian blur to remove noise
    blurred = cv2.GaussianBlur(scaled, (3, 3), 0)
    # Step 4: Threshold — make black text, white background
    _, thresh = cv2.threshold(blurred, 0, 255,
                               cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # Step 5: Deskew if needed (optional — helpful for tilted papers)
    cv2.imwrite("processed.jpg", thresh)
    return thresh

# ── Run OCR to Extract Text ────────────────────────────
def extract_text(processed_img):
    print("🔤 Running OCR on image...")
    # Custom config for better accuracy
    config = "--oem 3 --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789:. "
    raw_text = pytesseract.image_to_string(processed_img, config=config)
    print(f"📄 Extracted text:\n{raw_text[:300]}...")  # Show first 300 chars
    return raw_text

# ── Parse Answers from Extracted Text ─────────────────
def parse_answers(text):
    print("🔍 Parsing question answers from text...")
    answers = {}
    # Match patterns like "Q1: answer text" or "Q1. answer text"
    pattern = re.findall(r"Q(\d+)[:\.\s]+([^\n]+)", text, re.IGNORECASE)
    for q_num, answer in pattern:
        key = f"Q{q_num}"
        answers[key] = answer.strip().lower()
        print(f"  Found {key}: {answers[key][:50]}")
    return answers

# ── NLP Similarity: Compare Student Answer to Key ─────
def similarity_score(student_ans, correct_ans):
    # Method 1: difflib SequenceMatcher (fuzzy string match)
    seq_ratio = SequenceMatcher(None,
                    student_ans.lower(),
                    correct_ans.lower()).ratio()

    # Method 2: keyword matching (count how many key words appear)
    key_words   = set(correct_ans.lower().split())
    stud_words  = set(student_ans.lower().split())
    common      = key_words & stud_words
    kw_ratio    = len(common) / max(len(key_words), 1)

    # Combined score: 60% keyword + 40% sequence similarity
    combined = (kw_ratio * 0.6) + (seq_ratio * 0.4)
    return round(combined, 3)

# ── Evaluate All Answers Against the Key ──────────────
def evaluate_paper(student_answers, answer_key):
    print("\n🧠 Evaluating answers with AI...")
    results       = {}
    total_earned  = 0
    mpq           = answer_key["marks_per_question"]

    for q, correct in answer_key["answers"].items():
        student = student_answers.get(q, "")
        if not student:
            results[q] = {"marks": 0, "similarity": 0, "status": "not answered"}
            print(f"  {q}: ❌ Not answered — 0/{mpq}")
            continue

        sim   = similarity_score(student, correct)
        marks = round(sim * mpq)

        if sim < MIN_SIMILARITY:
            marks = 0
        marks = max(0, min(marks, mpq))   # Clamp 0 to max
        total_earned += marks

        status = "correct" if sim >= 0.7 else ("partial" if sim >= MIN_SIMILARITY else "wrong")
        results[q] = {"marks": marks, "similarity": sim, "status": status}
        print(f"  {q}: {marks}/{mpq} ({status}, sim={sim:.2f})")

    total_marks   = answer_key["total_marks"]
    percentage    = round((total_earned / total_marks) * 100)
    pass_threshold = answer_key["pass_percentage"]
    passed        = percentage >= pass_threshold

    # Assign letter grade
    if   percentage >= 90: grade = "A+"
    elif percentage >= 80: grade = "A"
    elif percentage >= 70: grade = "B"
    elif percentage >= 60: grade = "C"
    elif percentage >= 40: grade = "D"
    else:                   grade = "F"

    print(f"\n📊 RESULT: {total_earned}/{total_marks} = {percentage}% | Grade: {grade} | {'✅ PASS' if passed else '❌ FAIL'}")
    return total_earned, percentage, grade, passed, results

# ── Send Result to Arduino via Serial ─────────────────
def send_to_arduino(arduino, percentage, grade, passed):
    if arduino is None:
        print("⚠️ Arduino not connected — skipping serial send")
        return
    # Format: "SCORE:74:B:PASS\n"
    result_str = f"SCORE:{percentage}:{grade}:{'PASS' if passed else 'FAIL'}\n"
    arduino.write(result_str.encode("utf-8"))
    print(f"📡 Sent to Arduino: {result_str.strip()}")

# ── Save Evaluation Report ─────────────────────────────
def save_report(percentage, grade, passed, results, subject):
    fname = f"report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.txt"
    with open(fname, "w") as f:
        f.write(f"AI EXAM EVALUATION REPORT\n{'='*40}\n")
        f.write(f"Subject  : {subject}\n")
        f.write(f"Date/Time: {datetime.now().strftime('%Y-%m-%d %H:%M')}\n")
        f.write(f"Score    : {percentage}%  Grade: {grade}  Result: {'PASS' if passed else 'FAIL'}\n\n")
        f.write("QUESTION BREAKDOWN:\n")
        for q, r in results.items():
            f.write(f"  {q}: {r['marks']} marks | {r['status']} | similarity {r['similarity']:.0%}\n")
    print(f"📁 Report saved: {fname}")

# ── MAIN PROGRAM ──────────────────────────────────────
def main():
    print("🚀 AI Exam Evaluator starting...")
    answer_key = load_answer_key()

    # Connect to Arduino (optional — system works without it)
    arduino = None
    try:
        arduino = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=2)
        time.sleep(2)   # Arduino resets on serial connect — wait for it
        print(f"✅ Arduino connected on {SERIAL_PORT}")
    except:
        print(f"⚠️ Arduino not found on {SERIAL_PORT} — hardware display disabled")

    # Open webcam
    cam = cv2.VideoCapture(CAMERA_INDEX)
    if not cam.isOpened():
        print("❌ Webcam not found! Check CAMERA_INDEX.")
        return
    print("📷 Camera ready. Press SPACEBAR in preview window to scan!")
    print("   (Or press the hardware button on your Arduino circuit)")

    while True:
        ret, frame = cam.read()
        if not ret: break

        # Show live camera preview with instructions
        display = frame.copy()
        cv2.putText(display, "Place paper under camera",
                    (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,255,100), 2)
        cv2.putText(display, "SPACE = Scan | Q = Quit",
                    (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (100,200,255), 2)
        cv2.imshow("AI Exam Evaluator — Press SPACE to scan", display)

        # Check for Arduino button signal via serial
        scan_triggered = False
        if arduino and arduino.in_waiting > 0:
            msg = arduino.readline().decode("utf-8").strip()
            if msg == "SCAN":
                scan_triggered = True
                print("🔘 Hardware button pressed!")

        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'): break
        if key == 32 or scan_triggered:   # Spacebar = 32
            img        = capture_image(cam)
            processed  = preprocess_image(img)
            raw_text   = extract_text(processed)
            stu_ans    = parse_answers(raw_text)
            earned, pct, grade, passed, results = evaluate_paper(stu_ans, answer_key)
            send_to_arduino(arduino, pct, grade, passed)
            save_report(pct, grade, passed, results, answer_key["subject"])

    cam.release()
    cv2.destroyAllWindows()
    if arduino: arduino.close()
    print("👋 Evaluator closed. Goodbye!")

if __name__ == "__main__":
    main()
Arduino Code

Arduino Evaluator Sketch ⚙️

Upload this to your Arduino Uno. It listens for the result from Python and displays it with LEDs, buzzer, and LCD.

exam_evaluator.ino — Arduino Sketch
// ==================================================
//   🤖 AI EXAM EVALUATOR — Arduino Display Module
//   Receives score from Python via Serial USB
//   Displays result: LEDs + Buzzer + 16x2 LCD
// ==================================================

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

// LCD: I2C address 0x27, 16 columns, 2 rows
LiquidCrystal_I2C lcd(0x27, 16, 2);

// --- Pin Definitions ---
const int BTN_PIN     = 2;   // Scan trigger button (INPUT_PULLUP)
const int GREEN_LED1  = 3;   // PASS indicator LED 1
const int GREEN_LED2  = 4;   // PASS indicator LED 2
const int RED_LED1    = 5;   // FAIL indicator LED 1
const int RED_LED2    = 6;   // FAIL indicator LED 2
const int BUZZER_PIN  = 7;   // Piezo buzzer

// --- State ---
bool   waitingForResult = false;
String serialBuffer    = "";

// ==================================================
//  SETUP
// ==================================================
void setup() {
  Serial.begin(9600);

  // Set pin modes
  pinMode(BTN_PIN,    INPUT_PULLUP);   // Button uses internal pull-up resistor
  pinMode(GREEN_LED1, OUTPUT);
  pinMode(GREEN_LED2, OUTPUT);
  pinMode(RED_LED1,   OUTPUT);
  pinMode(RED_LED2,   OUTPUT);
  pinMode(BUZZER_PIN, OUTPUT);

  // All LEDs off at start
  allLedsOff();

  // Start LCD
  lcd.init();
  lcd.backlight();
  showReadyScreen();

  // Startup blink
  for (int i = 0; i < 2; i++) {
    allLedsOn();  delay(200);
    allLedsOff(); delay(200);
  }
  Serial.println("READY");   // Tell Python we're ready
}

// ==================================================
//  LOOP — Check button + receive serial data
// ==================================================
void loop() {
  // --- Check scan button press ---
  if (digitalRead(BTN_PIN) == LOW && !waitingForResult) {
    delay(50);   // Debounce
    if (digitalRead(BTN_PIN) == LOW) {
      waitingForResult = true;
      Serial.println("SCAN");   // Tell Python to start scanning
      showScanningScreen();
      playBeep(800, 100);   // Short beep = button acknowledged
    }
  }

  // --- Listen for result from Python via Serial ---
  while (Serial.available() > 0) {
    char c = (char)Serial.read();
    if (c == '\n') {
      serialBuffer.trim();
      if (serialBuffer.startsWith("SCORE:")) {
        processResult(serialBuffer);
        serialBuffer = "";
        waitingForResult = false;
      }
      serialBuffer = "";
    } else {
      serialBuffer += c;
    }
  }
}

// ==================================================
//  PROCESS RESULT: parse "SCORE:74:B:PASS"
// ==================================================
void processResult(String data) {
  // Split by ':' → [SCORE, 74, B, PASS]
  int p1 = data.indexOf(':');
  int p2 = data.indexOf(':', p1+1);
  int p3 = data.indexOf(':', p2+1);

  String scoreStr = data.substring(p1+1, p2);
  String grade    = data.substring(p2+1, p3);
  String result   = data.substring(p3+1);
  int    score    = scoreStr.toInt();

  bool passed = (result == "PASS");

  // Show result on LCD
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Score: ");
  lcd.print(score);
  lcd.print("% Gr:");
  lcd.print(grade);
  lcd.setCursor(0, 1);

  if (passed) {
    lcd.print("** PASS - Well Done");
    showPassAnimation();
    playHappyTune();
  } else {
    lcd.print("** FAIL - Study More");
    showFailAnimation();
    playSadTune();
  }

  delay(8000);   // Show result for 8 seconds
  allLedsOff();
  showReadyScreen();
}

// ── LED Helpers ──────────────────────────────
void allLedsOff() {
  digitalWrite(GREEN_LED1, LOW);  digitalWrite(GREEN_LED2, LOW);
  digitalWrite(RED_LED1,   LOW);  digitalWrite(RED_LED2,   LOW);
}
void allLedsOn() {
  digitalWrite(GREEN_LED1, HIGH); digitalWrite(GREEN_LED2, HIGH);
  digitalWrite(RED_LED1,   HIGH); digitalWrite(RED_LED2,   HIGH);
}
void showPassAnimation() {
  for (int i = 0; i < 4; i++) {
    digitalWrite(GREEN_LED1, HIGH); delay(120);
    digitalWrite(GREEN_LED2, HIGH); delay(120);
    allLedsOff();                    delay(120);
  }
  digitalWrite(GREEN_LED1, HIGH);   // Keep green on
  digitalWrite(GREEN_LED2, HIGH);
}
void showFailAnimation() {
  for (int i = 0; i < 5; i++) {
    digitalWrite(RED_LED1, HIGH); digitalWrite(RED_LED2, HIGH);
    delay(200);
    allLedsOff();                  delay(200);
  }
  digitalWrite(RED_LED1, HIGH);     // Keep red on
  digitalWrite(RED_LED2, HIGH);
}

// ── Buzzer Tunes ─────────────────────────────
void playBeep(int freq, int dur) { tone(BUZZER_PIN, freq, dur); delay(dur+20); }
void playHappyTune() {
  // Three rising notes — success sound!
  playBeep(523, 150);   // C5
  playBeep(659, 150);   // E5
  playBeep(784, 300);   // G5
  playBeep(1047, 400);  // C6 — high finish!
}
void playSadTune() {
  // Three falling notes — try again sound
  playBeep(440, 200);   // A4
  playBeep(349, 200);   // F4
  playBeep(294, 400);   // D4 — low end
}

// ── LCD Screens ──────────────────────────────
void showReadyScreen() {
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print(" Exam Evaluator ");
  lcd.setCursor(0, 1); lcd.print(" Ready to Scan! ");
}
void showScanningScreen() {
  lcd.clear();
  lcd.setCursor(0, 0); lcd.print("  Scanning... ");
  lcd.setCursor(0, 1); lcd.print("  AI thinking...");
}
Important Rules

Safety & Ethics 🛡️

This project teaches responsible use of AI — just as important as the coding skills!

👩‍👦

Adult Supervision

Have a parent or teacher help with software installation and wiring verification

⚖️

AI is Not Perfect

This evaluator makes mistakes! It should assist teachers, not replace human judgment completely

🔌

No Power While Wiring

Always disconnect the Arduino before changing any circuit connections

🔒

Protect Answer Keys

Keep your answer_key.json file private — don't share it with students being evaluated!

📷

Camera Privacy

Only use the webcam for scanning exam papers. Turn it off when not in use

🌊

Keep Electronics Dry

No drinks near your circuit — liquids and electronics are dangerous together

Troubleshooting

Frequently Asked Questions ❓

Something not working? These are the most common issues young engineers run into!

Pytesseract says "TesseractNotFoundError" — what do I do?

Tesseract OCR needs to be installed separately from pytesseract. Download Tesseract from github.com/tesseract-ocr and install it. Then update the TESSERACT_PATH in your Python code to the exact folder where you installed it (e.g., C:\Program Files\Tesseract-OCR\tesseract.exe on Windows).

OCR reads garbage text — letters and symbols look wrong!

This usually means poor lighting or a blurry image. Try: (1) move to a brighter room, (2) add a desk lamp pointing at the paper, (3) hold the camera steady or use a tripod, (4) print the exam paper instead of handwriting it, (5) increase the resize scale in preprocess_image() from 2 to 3.

Python can't find the Arduino serial port!

Open Arduino IDE → Tools → Port to see which port your Arduino is on (e.g., COM3 on Windows, /dev/ttyUSB0 on Linux). Make sure the Arduino IDE's Serial Monitor is CLOSED — only one program can use the serial port at a time. Update SERIAL_PORT in the Python script.

The score is always 0% even though answers look correct!

Check that your question labels in the answer sheet match exactly (Q1:, Q2: etc.) including the colon. Also check that MIN_SIMILARITY = 0.35 isn't too high for your answer key. Try printing to the terminal to see what text OCR is extracting and what the parsed answers look like.

Can this AI evaluator grade handwritten answers?

Handwriting recognition (HTR) is much harder than printed text OCR! The current version works best with printed/typed answers. For handwriting, you'd need a neural network model like TrOCR from Microsoft (pip install transformers) — a great upgrade challenge for advanced students!

How accurate is the NLP answer matching?

For keyword-based questions with factual answers, accuracy is around 70–85%. It works best when answers contain specific keywords (planet names, science terms, dates). It's less accurate for opinion questions or complex explanations. This is why the project is a learning tool — not a replacement for human teachers!

Go Further

Level Up Challenges 🚀

Mastered the basic evaluator? These upgrades will take your project to a whole new level!

✍️

Handwriting OCR

Integrate TrOCR neural network to read actual handwritten answers

🌐

Web Dashboard

Build a Flask web app to view all evaluation reports with charts and history

📱

Mobile App

Use Kivy or Flutter to build a phone app that scans papers with your phone camera

🗣️

Voice Feedback

Add pyttsx3 to make the AI speak the score and grade out loud

🎓 You Just Built a Real AI System!

OCR, NLP, serial communication, computer vision — these are the exact skills that data scientists and AI engineers use every single day. You've taken your first real steps into the world of artificial intelligence. Keep building!

AI Exam Evaluator Arduino Python Project OCR Kids Project NLP Beginners OpenCV Tutorial STEM Science Fair Serial Communication Tesseract OCR Computer Vision Kids Machine Learning Basics

© 2026 Kids Robotics Lab · Always build responsibly · AI is a tool, not a replacement for great teachers 💙

Comments

Product Cards
Buddy Bot eBook
⭐ New 2026 Release
Build Your
Own Robot!
3D design, wiring &
Arduino coding.
Young inventors love it!
🖨️
3D Print
All parts
Wire it
Circuit guide
💻
Code it
Arduino IDE
🤖
Watch it
Walk & react
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Website Offer
₹499 300
🌍 International: $5 USD
One-time · Instant digital delivery
🔒 Secured by Razorpay · Your data is safe
📄 Download Free Sample Copy
🔒 Secured by Razorpay · Your data is safe
🍓
Raspberry Pi Pico Mastery
21 Projects
⚡ Launch Price — 80% OFF
Learn Pico
Build 21 Projects!
MicroPython · Wokwi
IoT · Certificate
Perfect for beginners!
🖥️
Wokwi
No hardware
🐍
MicroPy
From zero
🔨
21 Projects
IoT + sensors
📄
Certificate
Verified cert
📋 Your Details
Enter your name
Valid 10-digit no.
Enter a valid email
Special Launch Offer
₹999 200 80% OFF
🌍 International: $5 USD
One-time · Lifetime access · No subscription
🔒 Secured by Razorpay · UPI · Cards · NetBanking
🎉

You're in!

Payment successful! Your Buddy Bot eBook is ready. Time to build!

📖 Access Your eBook Now
🎉

Enrolled!

Payment successful! Lifetime access to all 21 Pico Projects is yours!

🍓 Go to My Course