Smart Soccer Bot

Last updated: 28 October 2026 · r2

Build a small two-wheel robot using an Induino or Arduino Uno and an L298N dual H-bridge motor driver, then add an HC-SR04 ultrasonic sensor and a TCRT5000 IR line sensor module in stages. This guide covers the parts, wiring, firmware, and first checks.

Despite its name, this version is a starting point for a soccer-bot experiment: it drives forward, pivots right when something is close, and if the IR sensor is enabled, also backs away from a detected white boundary. It does not distinguish a ball from another obstacle or track a goal.

Before you start: safety for students

Build and test this robot with your teacher’s guidance. Ask your teacher to check every connection before switching on the power. If you are unsure, stop and ask.

Code: Smart Soccer Bot

Download Smart Soccer Bot — C++ Arduino sketch (.ino)

When you open the downloaded sketch file, the Arduino IDE may prompt you to create a folder and move the sketch into it. Accept the prompt. This is normal: smart-soccer-bot.ino needs to be inside a folder named smart-soccer-bot.

//
//  Created by Rahul Ashokayan on 2026.10.22.
//  Copyright © 2026 Riant Studio. All rights reserved.
//
// ==============================================================
//  Smart Soccer Bot with Ultrasonic & IR Line Boundary Defense
//  Platform: Induino / Arduino Uno
// ==============================================================

// --- Build stages: enable only the sensors you have connected ---
// Stage 1: both false for motor-only forward movement.
// Stage 2: ultrasonic true for ball / obstacle response.
// Stage 3: IR boundary true for white-line defense.
const bool ENABLE_ULTRASONIC = true;
const bool ENABLE_IR_BOUNDARY = false;
// CAUTION: Enable a sensor only after it is wired.
// With IR off, the robot has no edge protection, so test in a contained area,
// away from stairs or raised edges. Alternatively, test with the wheels raised.

// --- Stage 2: Ultrasonic Sensor (HC-SR04) ---
const int trigPin = A0;
const int echoPin = A1;

// --- Stage 3: IR Line Sensor (TCRT5000) ---
const int lineSensorPin = A2; // Digital reading on Analog pin A2

// --- Stage 1: L298N Motor Driver Pins ---
const int enLeft     = 3;  // PWM Left
const int motorL_Fwd = 4;
const int motorL_Rev = 5;

const int enRight    = 9;  // PWM Right
const int motorR_Fwd = 7;
const int motorR_Rev = 8;

const int statusLed  = 13; // Induino onboard LED

// --- Speeds & Distance ---
const int DRIVE_SPEED   = 175;
const int TURN_SPEED    = 160;
const int BALL_ZONE_CM  = 20;

// Set to LOW if your module outputs active LOW on white surface
const int WHITE_DETECTED = LOW;
// CAUTION: If you change this to HIGH, the IR module must be connected.
// With INPUT_PULLUP an unplugged sensor reads HIGH and looks like a
// constant white boundary.

void setup() {
  if (ENABLE_ULTRASONIC) {
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
  }

  if (ENABLE_IR_BOUNDARY) {
    // Pull-up keeps an unconnected pin HIGH (no white line detected).
    pinMode(lineSensorPin, INPUT_PULLUP);
  }

  pinMode(enLeft, OUTPUT);
  pinMode(motorL_Fwd, OUTPUT);
  pinMode(motorL_Rev, OUTPUT);

  pinMode(enRight, OUTPUT);
  pinMode(motorR_Fwd, OUTPUT);
  pinMode(motorR_Rev, OUTPUT);

  pinMode(statusLed, OUTPUT);

  delay(1500); // Power-on stabilizing delay
}

// --- Stage 1: Motor movement ---
void setMotors(int leftDir, int rightDir, int speedL, int speedR) {
  digitalWrite(motorL_Fwd, leftDir == 1 ? HIGH : LOW);
  digitalWrite(motorL_Rev, leftDir == -1 ? HIGH : LOW);

  digitalWrite(motorR_Fwd, rightDir == 1 ? HIGH : LOW);
  digitalWrite(motorR_Rev, rightDir == -1 ? HIGH : LOW);

  analogWrite(enLeft, speedL);
  analogWrite(enRight, speedR);
}

void forward()  { setMotors(1, 1, DRIVE_SPEED, DRIVE_SPEED); }
void reverse()  { setMotors(-1, -1, DRIVE_SPEED, DRIVE_SPEED); }
void spinTurn() { setMotors(1, -1, TURN_SPEED, TURN_SPEED); }
void stopBot()  { setMotors(0, 0, 0, 0); }

// --- Stage 3: Return true after responding to a boundary ---
bool handleBoundary() {
  int lineState = digitalRead(lineSensorPin);

  if (lineState == WHITE_DETECTED) {
    digitalWrite(statusLed, HIGH);
    stopBot();
    delay(100);

    // Pull back into the pitch
    reverse();
    delay(350);

    // Pivot right before checking the line again
    spinTurn();
    delay(400);

    stopBot();
    delay(100);
    return true;
  }

  return false;
}

// --- Stage 2: Distance measurement and obstacle response ---
long readDistanceCM() {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH, 25000);
  if (duration == 0) return 999;
  return (duration * 0.034) / 2;
}

bool handleObstacle() {
  long distance = readDistanceCM();

  if (distance > 0 && distance <= BALL_ZONE_CM) {
    digitalWrite(statusLed, HIGH);
    stopBot();
    delay(100);

    // Quick evasive turn
    spinTurn();
    delay(300);
    return true;
  }

  return false;
}

void loop() {
  // Boundary response takes priority when enabled.
  if (ENABLE_IR_BOUNDARY && handleBoundary()) {
    return;
  }

  // Disabled sensors are not read; otherwise advance when clear.
  if (!ENABLE_ULTRASONIC || !handleObstacle()) {
    digitalWrite(statusLed, LOW);
    forward();
  }

  delay(30);
}

The code above is included directly from the downloadable sketch when the site is built.

First time uploading a program to Arduino? Follow Upload a sketch to your Arduino with your teacher.

Choose your build stage

Two settings near the top of the sketch control the optional sensors: ENABLE_ULTRASONIC and ENABLE_IR_BOUNDARY. Set each to true only when that sensor is connected and ready to use. The download ships at Stage 2 (ENABLE_ULTRASONIC = true, ENABLE_IR_BOUNDARY = false). Enable IR boundary defense once the IR module is wired.

Sensor settings for each build
BuildENABLE_ULTRASONICENABLE_IR_BOUNDARYBehaviour
Stage 1: motors onlyfalsefalseDrive forward without sensing obstacles or boundaries
Stage 2: add ultrasonictruefalseDrive forward and pivot right near an object
Stage 3: add IR boundary defensetruetrueRespond to objects and give white boundaries priority
Alternative: motors and IR onlyfalsetrueDrive forward and back away from white boundaries, without distance sensing

For example, to build with the ultrasonic sensor but no IR module, leave the download’s settings as they are: ENABLE_ULTRASONIC is true and ENABLE_IR_BOUNDARY is false. You can leave all the IR code in place and skip its wiring section. Disabled sensors are neither configured nor read, so an unconnected IR input cannot trigger a boundary response. Upload the sketch again after changing a setting.

The sketch groups motor movement, ultrasonic response, and IR boundary response into labelled sections. handleObstacle() and handleBoundary() each return true after performing their manoeuvre; loop() calls only enabled capabilities and drives forward when neither responds.

Begin stage 1 with the wheels raised: it drives forward continuously after startup. For later stages, follow only the checks for enabled sensors. With IR disabled there is no boundary defense; with ultrasonic disabled there is no obstacle response.

1. Gather the parts

2. Wire the motor driver

Disconnect all power while wiring. With your teacher, remove the ENA and ENB jumpers on the L298N module so that the Arduino can control motor speed through those inputs.

L298N control connections
L298N pinArduino pinPurpose
ENAD3Left motor PWM speed
IN1D4Left motor forward
IN2D5Left motor reverse
IN3D7Right motor forward
IN4D8Right motor reverse
ENBD9Right motor PWM speed
GNDGNDCommon ground

Connect the left motor to OUT1/OUT2 and the right motor to OUT3/OUT4. Connect the motor battery positive to the driver’s motor-supply terminal, often labelled +12V, and its negative to GND. Join the driver and Arduino grounds.

Ask your teacher to check your specific module’s instructions for its logic supply and regulator jumper: the ENA/ENB jumpers are separate from the regulator jumper. Use the controller supply described above, and do not connect the module’s 5V terminal to it without your teacher confirming that terminal’s role for your board. Motors are powered through the driver, never from an Arduino GPIO or its 5V pin.

3. Connect the ultrasonic sensor

Skip this section if ENABLE_ULTRASONIC is false.

Set ENABLE_ULTRASONIC to true only once the HC-SR04 is wired. An unconnected echo pin can float and give false readings, causing unexpected turns. For a motor-only build, change it to false before uploading.

Mount the HC-SR04 at the front of the chassis, pointing forward.

HC-SR04 connections
HC-SR04 pinArduino pinPurpose
VCC5VSensor power
TrigA0Trigger pulse
EchoA1Echo input
GNDGNDGround

The sketch uses A0 and A1 as digital pins. Its motor connections leave D10–D12 free, and D13 is used as the status LED. This arrangement avoids using those pins for the motor driver or ultrasonic sensor.

4. Connect the IR line sensor

Skip this section if ENABLE_IR_BOUNDARY is false.

Mount the IR module near the front underside of the chassis, pointing down at the pitch. Position it so it can detect the boundary before the wheels reach it, with its sensing height set for your module and surface.

TCRT5000 module connections
IR module pinArduino pinPurpose
VCC5VModule power
DO / OUT (digital)A2Boundary input
GNDGNDCommon ground

The sketch uses A2 as a digital input with digitalRead, so connect the module’s digital output, not its analog output (AO). Check the pin labels and power requirements on your particular module with your teacher.

When IR boundary defense is enabled, the sketch enables the Arduino’s internal pull-up on A2, so an unconnected input reads HIGH (no boundary with the default WHITE_DETECTED = LOW) rather than floating. The IR module’s digital output still drives the pin normally.

WHITE_DETECTED is initially LOW: the sketch treats a LOW input as a white boundary. Before running the motors, check the module’s digital output over the white line and darker playing area. Adjust the module’s threshold control, if fitted, until those surfaces give distinct readings. If your module outputs HIGH over white, change WHITE_DETECTED to HIGH before uploading. If you change it to HIGH, make sure the IR module is connected. With the pull-up, an unplugged input reads HIGH and would look like a constant boundary. Surface reflectivity, mounting height, and room lighting can affect detection; visible colour alone is not enough to confirm it works.

5. Assemble and upload

For help with opening the saved file, choosing the board and port, and using Verify and Upload, follow the step-by-step upload guide.

  1. Mount the motors, wheels, and caster on the chassis. Secure the controller and driver using spacers, keeping exposed contacts away from conductive surfaces.
  2. Leave the motor battery disconnected while uploading. Download the sketch above and open it in Arduino IDE. If prompted, allow the IDE to create a matching sketch folder. Set ENABLE_ULTRASONIC and ENABLE_IR_BOUNDARY for your build stage before uploading.
  3. Select Arduino Uno under the board menu for an Uno-compatible board, then select the connected board’s port.
  4. Upload the sketch and confirm completion in the IDE. The sketch does not include an upload-confirmation blink.
  5. Secure the chassis with the wheels off the ground, reconnect motor power, and check direction. After the sketch’s 1.5-second startup delay, both wheels should turn forward. If IR is enabled, hold a sample of the darker playing surface beneath it at its intended sensing distance; if ultrasonic sensing is enabled, keep nearby objects out of its path.
  6. If one wheel turns backward, disconnect power and swap that motor’s two output wires. Repeat the check before putting the robot on the floor.

6. Understand the movement

First priority: IR line boundary defense

When ENABLE_IR_BOUNDARY is true, each loop checks the IR line sensor first. If its reading matches WHITE_DETECTED, the status LED lights and the robot performs this sequence:

  1. Stop for 100 milliseconds.
  2. Reverse for 350 milliseconds.
  3. Pivot right for 400 milliseconds.
  4. Stop for 100 milliseconds.

The loop then returns immediately, skipping the ultrasonic check and the normal end-of-loop delay. The next loop checks the line sensor again. If it still detects the boundary, the sequence repeats.

Second priority: ball or obstacle proximity

When no boundary response occurs and ENABLE_ULTRASONIC is true, the sketch measures distance and compares it with BALL_ZONE_CM, initially 20 cm. For a reading greater than zero and no more than that threshold, it lights the status LED, stops for 100 milliseconds, and pivots right for 300 milliseconds. This branch does not reverse or stop after the pivot; the next loop decides what to do next.

When neither enabled capability responds, the LED is off and the robot drives forward. Every loop without a boundary response has an additional 30-millisecond delay at the end, including motor-only operation.

The ultrasonic read has a 25-millisecond timeout. When no echo is received, the sketch returns 999 and takes the forward-driving branch. A timeout therefore does not stop the robot. Neither sensor is checked during the timed manoeuvres, and a boundary reached during a pivot will only be checked on the next loop. A single front sensor cannot monitor every edge of the robot or guarantee that it stays inside the pitch.

7. Test and tune

Start with the chassis secured and wheels raised, and check forward wheel direction for every build stage. If IR is enabled, move samples of the darker playing surface and white boundary beneath the IR sensor at its intended sensing distance. Check that only the white boundary triggers the stop–reverse–pivot–stop sequence. If both sensors are enabled, place an object in front of the ultrasonic sensor while a boundary is detected and confirm that the boundary sequence still takes priority.

For sensor-enabled builds, then use a clear, contained area at low speed, away from stairs or raised edges. If IR is enabled, approach the white boundary from several angles and check that the robot has enough room to back away. If ultrasonic sensing is enabled, place a ball or another object roughly 15–20 cm in front of it and check that the robot stops briefly and pivots right; keep the IR sensor over the darker playing area if fitted. Try different positions: a curved ball can give different readings from a flat obstacle.

The supplied firmware is a simple baseline for experimenting with motion, distance sensing, and line boundary detection. Ball tracking and goal-directed play would require additional sensing and control logic.

Teacher references: Arduino power-supply guidance and the CPSC warning about loose 18650 lithium-ion cells.

Compiled and curated with AI-assisted drafting and firmware scaffolding.

More Arduino sketches · Lab