Hardware Project

PHOTOVORE ROBOT

A custom PCB light-following robot. Dual LDR differential sensing, ATmega328P brain, H-bridge motor control. Designed, built, and coded from scratch.

2
LDR Eyes
328P
MCU Core
L298N
H-Bridge
7.4V
LiPo Power
Explore

How it works

The photovore is a biologically inspired robot that chases light the way a moth chases a flame. Two light-dependent resistors mounted at the front act as "eyes," forming voltage dividers with 10k pulldown resistors. The ATmega328P reads both analog values, computes the brightness differential, and steers by adjusting individual motor speeds through an L298N dual H-bridge.

When more light falls on the left eye, the left motor slows down and the right motor speeds up, causing the robot to arc toward the light source. A configurable dead zone prevents jittery oscillation when both sensors read nearly equal values. Below a darkness threshold, the robot stops and waits.

The entire circuit runs on a custom-designed PCB powered by a 7.4V 2S LiPo, regulated down to 5V for the microcontroller while the motors run on the raw pack voltage for maximum torque.

Differential sensing

Two LDRs in voltage divider configuration feed analog pins A0 and A1. Brightness difference drives proportional steering.

PWM motor control

L298N H-bridge with PWM-capable enable pins allows smooth, variable-speed control for each wheel independently.

Clean power design

AMS1117-5.0 regulator with dual decoupling caps. Separate motor and logic power rails prevent noise coupling.

Tunable behavior

Configurable turn gain, dead zone, speed limits, and dark threshold. Serial debug output for real-time tuning.

PCB circuit design

PWR_RAIL BATT 7.4V 2S SW1 SPST AMS1117 5.0V REG C1+C2 100uF+100nF +5V ATMEGA328P Arduino Nano / Pro Mini A0 A1 D13 D5 D6/D9 D10 D7/D8 VCC SENSORS LDR-L Left eye R1 10k LDR-R Right eye R2 10k MOTOR_CTRL L298N H-Bridge ENA IN1 IN2 ENB IN3 IN4 M1 M2 VMOT 7.4V LED D13 GND
MCU PinNetConnectionFunction
A0SENSE_LLDR-L / R1 dividerLeft light sensor input
A1SENSE_RLDR-R / R2 dividerRight light sensor input
D5 (PWM)ENAL298N Enable ALeft motor speed
D6IN1L298N Input 1Left motor direction A
D9IN2L298N Input 2Left motor direction B
D10 (PWM)ENBL298N Enable BRight motor speed
D7IN3L298N Input 3Right motor direction A
D8IN4L298N Input 4Right motor direction B
D13STATUSLED + R3 220RStatus indicator

Control code

photovore_robot.ino
// Photovore Robot Firmware
// ATmega328P / Arduino Nano / Pro Mini

// Pin definitions
const int LDR_LEFT_PIN  = A0;
const int LDR_RIGHT_PIN = A1;

const int ENA_PIN = 5;    // Left motor speed (PWM)
const int IN1_PIN = 6;    // Left motor dir A
const int IN2_PIN = 9;    // Left motor dir B
const int ENB_PIN = 10;   // Right motor speed (PWM)
const int IN3_PIN = 7;    // Right motor dir A
const int IN4_PIN = 8;    // Right motor dir B
const int LED_PIN = 13;

// Tuning parameters
const int   BASE_SPEED     = 150;
const int   MAX_SPEED      = 255;
const int   MIN_SPEED      = 60;
const int   DEAD_ZONE      = 30;
const int   DARK_THRESHOLD = 100;
const float TURN_GAIN      = 0.8;

void setLeftMotor(int speed) {
  if (speed >= 0) {
    digitalWrite(IN1_PIN, HIGH);
    digitalWrite(IN2_PIN, LOW);
    analogWrite(ENA_PIN, constrain(speed, 0, MAX_SPEED));
  } else {
    digitalWrite(IN1_PIN, LOW);
    digitalWrite(IN2_PIN, HIGH);
    analogWrite(ENA_PIN, constrain(-speed, 0, MAX_SPEED));
  }
}

void setRightMotor(int speed) {
  if (speed >= 0) {
    digitalWrite(IN3_PIN, HIGH);
    digitalWrite(IN4_PIN, LOW);
    analogWrite(ENB_PIN, constrain(speed, 0, MAX_SPEED));
  } else {
    digitalWrite(IN3_PIN, LOW);
    digitalWrite(IN4_PIN, HIGH);
    analogWrite(ENB_PIN, constrain(-speed, 0, MAX_SPEED));
  }
}

void loop() {
  int leftVal  = analogRead(LDR_LEFT_PIN);
  int rightVal = analogRead(LDR_RIGHT_PIN);
  int diff = leftVal - rightVal;
  int avg  = (leftVal + rightVal) / 2;

  if (avg < DARK_THRESHOLD) {
    stopMotors();            // Too dark, stop
  } else if (abs(diff) < DEAD_ZONE) {
    setLeftMotor(BASE_SPEED);  // Go straight
    setRightMotor(BASE_SPEED);
  } else {
    int turn = (int)(abs(diff) * TURN_GAIN);
    int lSpd, rSpd;
    if (diff > 0) {
      lSpd = BASE_SPEED - turn;  // Turn left
      rSpd = BASE_SPEED + turn;
    } else {
      lSpd = BASE_SPEED + turn;  // Turn right
      rSpd = BASE_SPEED - turn;
    }
    setLeftMotor(constrain(lSpd, MIN_SPEED, MAX_SPEED));
    setRightMotor(constrain(rSpd, MIN_SPEED, MAX_SPEED));
  }
  delay(20);
}

Components

01

ATmega328P

Arduino Nano or Pro Mini module

02

AMS1117-5.0

5V LDO voltage regulator, SOT-223

03

L298N module

Dual H-bridge motor driver

04

2x LDR (5mm)

Light dependent resistors, CdS type

05

2x 10k resistors

Voltage divider pulldowns, 1/4W

06

1x 220R resistor

LED current limiter

07

100uF + 100nF caps

Decoupling, electrolytic + ceramic

08

2x DC geared motors

3-12V with wheels attached

09

7.4V 2S LiPo

Battery pack with JST connector

10

Toggle switch

SPST power switch

11

3mm LED

Red, status indicator

12

Screw terminals + headers

Motor connections, programming pins