Project Description
The motors are controlled via L298N motor driver logic, and speed is controlled using PWM pins. The logic supports:
Forward motion when both IR sensors detect no obstacle and an object is in front.
Turning left/right if one IR sensor detects an obstacle.
Reversing when both IR sensors detect a wall or object.
Stopping if the ultrasonic sensor detects the object is too close (<10cm).
Hardware Used
Arduino Uno
HC-SR04 Ultrasonic Sensor
2 x IR Obstacle Sensors
L298N Motor Driver Module
2 x DC Motors
Battery Pack
Hand-Following Robot code using IR and ultrasonic sensors with DC motors:
🔧 1. Library and Pin Configuration
#include <NewPing.h>
- Includes the NewPing library to handle ultrasonic sensor measurements with better timing and reliability.
#define IR_RIGHT A2
#define IR_LEFT A3
- IR sensor pins:
A2for right andA3for left. These detect black/white surfaces or obstacles.
#define TRIGGER_PIN A1
#define ECHO_PIN A0
#define MAX_DISTANCE 100- Defines HC-SR04 ultrasonic sensor pins and max distance in centimeters for sensing.
#define RIGHT_SPEED_PIN 10
#define LEFT_SPEED_PIN 11- PWM pins connected to motor driver for controlling motor speed.
#define RIGHT_MOTOR_A 4
#define RIGHT_MOTOR_B 5
#define LEFT_MOTOR_A 6
#define LEFT_MOTOR_B 7- Direction control pins for the motor driver. Two pins per motor (H-bridge logic).
2. Constants for Speeds and Distance Thresholds
#define DEFAULT_SPEED 191
#define TURN_SPEED 127
#define MIN_DISTANCE 10
#define MAX_FOLLOW_DISTANCE 30 - Speed values and distance thresholds to decide when to follow or stop.
3. Ultrasonic Object Initialization
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);- Creates a
sonarobject to interact with the ultrasonic sensor.
4. Setup Function
void setup() {
Serial.begin(9600);
pinMode(IR_RIGHT, INPUT);
pinMode(IR_LEFT, INPUT);
pinMode(..., OUTPUT);
motor_stop();
} - Starts serial communication (useful for debugging).
- Sets IR pins as input and motor pins as output.
- Calls
motor_stop()to keep robot still at start.
5. Main Loop
void loop() {
delay(50);
unsigned int distance = sonar.ping_cm();
int rightIR = digitalRead(IR_RIGHT);
int leftIR = digitalRead(IR_LEFT); - Gets the distance to object in front.
- Reads IR sensor values (
0= obstacle,1= clear).
Then the control logic follows:
Move Forward
if (rightIR == 1 && leftIR == 1 && distance >= 10 && distance <= 30)- If no obstacle detected on either side and object is within followable range → move forward.
Turn Right
else if (rightIR == 0 && leftIR == 1) - If obstacle on right → turn right.
Turn Left
else if (rightIR == 1 && leftIR == 0) - If obstacle on left → turn left.
Reverse
else if (rightIR == 0 && leftIR == 0) - If both sides are blocked → reverse to avoid collision.
Stop
else if (distance < 10 || (rightIR == 1 && leftIR == 1)) - If the object is too close or there's nothing to follow → stop.
6. Movement Functions
Each motion control function does:
analogWrite()sets motor speed using PWM.digitalWrite()sets motor direction using H-bridge logic.
For example:
void move_forward(int speed) {
analogWrite(...);
digitalWrite(...); // A = HIGH, B = LOW → forward direction
} Others like reverse(), turn_left(), and turn_right() follow similar structure but flip the direction control.
motor_stop() Function
void motor_stop() {
analogWrite(..., 0); // Cut off speed
digitalWrite(..., LOW); // Stop motor movement
} Summary of Behavior
| Condition | Action |
|---|---|
| IR clear, object in range | Move forward |
| Obstacle right | Turn right |
| Obstacle left | Turn left |
| Obstacle both sides | Reverse |
| Too close or idle | Stop |
Final Code
#include <NewPing.h>
// IR Sensor Pins
#define IR_RIGHT A2
#define IR_LEFT A3
// Ultrasonic Sensor Pins
#define TRIGGER_PIN A1
#define ECHO_PIN A0
#define MAX_DISTANCE 100
// Motor Control Pins
#define RIGHT_SPEED_PIN 10
#define LEFT_SPEED_PIN 11
#define RIGHT_MOTOR_A 4
#define RIGHT_MOTOR_B 5
#define LEFT_MOTOR_A 6
#define LEFT_MOTOR_B 7
// Default speeds
#define DEFAULT_SPEED 191
#define TURN_SPEED 127
#define MIN_DISTANCE 10
#define MAX_FOLLOW_DISTANCE 30
NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE);
void setup() {
Serial.begin(9600);
pinMode(IR_RIGHT, INPUT);
pinMode(IR_LEFT, INPUT);
pinMode(RIGHT_MOTOR_A, OUTPUT);
pinMode(RIGHT_MOTOR_B, OUTPUT);
pinMode(LEFT_MOTOR_A, OUTPUT);
pinMode(LEFT_MOTOR_B, OUTPUT);
motor_stop();
}
void loop() {
delay(50);
unsigned int distance = sonar.ping_cm();
int rightIR = digitalRead(IR_RIGHT);
int leftIR = digitalRead(IR_LEFT);
if (distance > 1 && distance < MIN_DISTANCE) {
motor_stop(); // Too close to object
}
else if (rightIR == 1 && leftIR == 1 && distance >= MIN_DISTANCE && distance <= MAX_FOLLOW_DISTANCE) {
move_forward(DEFAULT_SPEED);
}
else if (rightIR == 0 && leftIR == 1) {
turn_right(TURN_SPEED);
}
else if (rightIR == 1 && leftIR == 0) {
turn_left(TURN_SPEED);
}
else if (rightIR == 0 && leftIR == 0) {
move_reverse(TURN_SPEED);
}
else {
motor_stop(); // Default stop
}
}
// Motion Control Functions
void move_forward(int speed) {
analogWrite(RIGHT_SPEED_PIN, speed);
analogWrite(LEFT_SPEED_PIN, speed);
digitalWrite(RIGHT_MOTOR_A, HIGH);
digitalWrite(RIGHT_MOTOR_B, LOW);
digitalWrite(LEFT_MOTOR_A, HIGH);
digitalWrite(LEFT_MOTOR_B, LOW);
}
void move_reverse(int speed) {
analogWrite(RIGHT_SPEED_PIN, speed);
analogWrite(LEFT_SPEED_PIN, speed);
digitalWrite(RIGHT_MOTOR_A, LOW);
digitalWrite(RIGHT_MOTOR_B, HIGH);
digitalWrite(LEFT_MOTOR_A, LOW);
digitalWrite(LEFT_MOTOR_B, HIGH);
}
void turn_right(int speed) {
analogWrite(RIGHT_SPEED_PIN, 63);
analogWrite(LEFT_SPEED_PIN, speed);
digitalWrite(RIGHT_MOTOR_A, LOW);
digitalWrite(RIGHT_MOTOR_B, HIGH);
digitalWrite(LEFT_MOTOR_A, HIGH);
digitalWrite(LEFT_MOTOR_B, LOW);
}
void turn_left(int speed) {
analogWrite(RIGHT_SPEED_PIN, speed);
analogWrite(LEFT_SPEED_PIN, 63);
digitalWrite(RIGHT_MOTOR_A, HIGH);
digitalWrite(RIGHT_MOTOR_B, LOW);
digitalWrite(LEFT_MOTOR_A, LOW);
digitalWrite(LEFT_MOTOR_B, HIGH);
}
void motor_stop() {
analogWrite(RIGHT_SPEED_PIN, 0);
analogWrite(LEFT_SPEED_PIN, 0);
digitalWrite(RIGHT_MOTOR_A, LOW);
digitalWrite(RIGHT_MOTOR_B, LOW);
digitalWrite(LEFT_MOTOR_A, LOW);
digitalWrite(LEFT_MOTOR_B, LOW);
}