An autonomous tracking system can easily collide with static roadblocks. To mitigate this risk, we add an Ultrasonic Distance Module (HC-SR04). This sensor proactively measures the distance to upcoming obstacles by calculating the time-of-flight of high-frequency audio pings.To prevent software lag, we supply a 30,000 microsecond hardware limit to the pulseIn() function. This prevents the script from freezing if the sensor misses an echo pulse. If the calculated clearance falls beneath 30 cm, the robot suspends line tracking and maneuvers away.
Here, the vehicle gains a contact-free defensive boundary. While navigating autonomously, if the ultrasonic sonar module captures a barrier closing within 30 cm, the robot overrides line following to execute a sharp evasive turn away from danger.
#include <Arduino.h>
#include <IRremote.hpp>
const int motorPinA_1A = 5;
const int motorPinA_1B = 6;
const int motorPinB_1A = 9;
const int motorPinB_1B = 10;
const int IR_RECEIVE_PIN = 2;
const int TrackingPin_L = A2;
const int TrackingPin_R = A3;
// Ultrasonic Sonar (Echo pin moved to interrupt pin 3)
const int trigPin = 4;
const int echoPin = 3;
enum RobotMode { MODE_MANUAL, MODE_AUTONOMOUS };
RobotMode currentMode = MODE_MANUAL;
const int motorSpeed = 200;
int trackSpeed = 200;
unsigned long lastCommandTime = 0;
const unsigned long commandTimeout = 250;
void motor(int A1, int A2, int B1, int B2) {
analogWrite(motorPinA_1A, A1);
analogWrite(motorPinA_1B, A2);
analogWrite(motorPinB_1A, B1);
analogWrite(motorPinB_1B, B2);
}
float getDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH, 30000); // 30ms hardware timeout constraint
float d = duration * 0.0343 / 2;
if (d == 0) return 999.0; // Return out-of-bounds constant on reading error
return d;
}
void exec_cmd(byte key_val) {
switch (key_val) {
case 0x1C:
if (currentMode == MODE_MANUAL) { currentMode = MODE_AUTONOMOUS; }
else { currentMode = MODE_MANUAL; motor(0, 0, 0, 0); }
break;
case 0x18: if (currentMode == MODE_MANUAL) motor(0, motorSpeed, 0, motorSpeed); break;
case 0x08: if (currentMode == MODE_MANUAL) motor(motorSpeed, 0, 0, motorSpeed); break;
case 0x5A: if (currentMode == MODE_MANUAL) motor(0, motorSpeed, motorSpeed, 0); break;
case 0x52: if (currentMode == MODE_MANUAL) motor(motorSpeed, 0, motorSpeed, 0); break;
default: if (currentMode == MODE_MANUAL) motor(0, 0, 0, 0); break;
}
}
void setup() {
Serial.begin(9600);
// pinMode(motorPinA_1A, OUTPUT);
// pinMode(motorPinA_1B, OUTPUT);
// pinMode(motorPinB_1A, OUTPUT);
// pinMode(motorPinB_1B, OUTPUT);
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
pinMode(TrackingPin_L, INPUT_PULLUP);
pinMode(TrackingPin_R, INPUT_PULLUP);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
if (IrReceiver.decode()) {
byte command = IrReceiver.decodedIRData.command;
exec_cmd(command);
if (currentMode == MODE_MANUAL) lastCommandTime = millis();
IrReceiver.resume();
}
if (currentMode == MODE_MANUAL) {
if (millis() - lastCommandTime > commandTimeout) {
motor(0, 0, 0, 0);
}
}
else if (currentMode == MODE_AUTONOMOUS) {
float distance = getDistance();
if (distance < 30) {
motor(motorSpeed, 0, 0, motorSpeed); // Evasion vector: Quick turn left
delay(300);
}
else {
int trackL = digitalRead(TrackingPin_L);
int trackR = digitalRead(TrackingPin_R);
int Track = trackL * 2 + trackR;
if (Track == 0) motor(0, 0, 0, 0);
else if (Track == 1) motor(0, trackSpeed, trackSpeed, 0);
else if (Track == 2) motor(trackSpeed, 0, 0, trackSpeed);
else if (Track == 3) motor(0, trackSpeed, 0, trackSpeed);
delay(10);
}
}
}