Hey! Im trying to get obstacle avoidance to work on my elegoo smart car. The basic premise of the project is this:
- The car needs to be controlled by the ir remote
- It needs to record a certain path (input from remote) and memorise it
- It needs to execute the memorised path
- If an obstacle is in the way of its memorised path, it needs to go around the obstacle and then go back to its memorised path.
So far im stuck on 4. I can either get it to go the memorised path or avoid the obstacle. Not both.
Many thanks in advance!
#include <IRremote.h>
// Motor driver pin configuration
#define PWMA 5 // Controls power to right motor
#define PWMB 6 // Controls power to left motor
#define AIN 7 // Controls direction of right motor, HIGH = FORWARD, LOW = REVERSE
#define BIN 8 // Controls direction of right motor, HIGH = FORWARD, LOW = REVERSE
#define STBY 3 // Place H-Bridge in standby if LOW, Run if HIGH
#define TRIG 13
#define ECHO 12
unsigned long path[50][2]; // Store path as a 2D array [IR code, timestamp]
unsigned long pathIndex = 0; // Index to keep track of the current step in the path
bool recording = false; // Indicates whether we are recording a path
// IR remote setup
int RECV_PIN = 9; // IR receiver pin
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup() {
// Motor pins setup
pinMode(PWMA, OUTPUT); //set IO pin mode OUTPUT
pinMode(PWMB, OUTPUT);
pinMode(BIN, OUTPUT);
pinMode(AIN, OUTPUT);
pinMode(STBY, OUTPUT);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
digitalWrite(STBY, HIGH); //Enable Motors to run
digitalWrite(PWMA, LOW); // Fully on
// Start the IR receiver
Serial.begin(9600);
irrecv.enableIRIn();
}
unsigned long measureDistance() {
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
unsigned int duration = pulseIn(ECHO, HIGH);
unsigned int distance = duration * 0.034 / 2; // Speed of sound in air is 0.034 cm/μs
return distance;
}
void loop() {
if (irrecv.decode(&results)) {
unsigned long value = results.value;
// Print the received IR code to the serial monitor
Serial.println(results.value, HEX);
// Handle the IR remote buttons
if (value == 0xFF6897) {
if (!recording) {
// Start recording
recording = true;
pathIndex = 0;
Serial.println("Recording started.");
} else {
// Stop recording
recording = false;
Serial.println("Recording stopped.");
}
delay(500); // Debounce the button
}
if (recording && pathIndex < 50) {
// Store the received IR code in the recorded path
path[pathIndex][0] = value;
path[pathIndex][1] = millis();
pathIndex++;
Serial.print("Recorded: ");
Serial.print(value, HEX);
Serial.print(" Time Difference (ms): ");
Serial.println(path[pathIndex - 1][1]);
}
delay(500); // Delay to prevent recording multiple actions in one press
if (value == 0xFF9867) { // Replace with your playback button code
Serial.println("Playback started");
executePath();
delay(500); // Debounce the button
} else {
switch (results.value) {
case 0xFF629D: // Forward
moveForward();
break;
case 0xFFA857: // Backward
moveBackward();
break;
case 0xFF22DD: // Left
turnLeft();
break;
case 0xFFC23D: // Right
turnRight();
break;
case 0xFF02FD: // Stop
stopCar();
break;
case 0xFF4AB5: // Reset Car
resetArduino();
break;
default:
// Unknown code; do nothing
break;
}
irrecv.resume(); // Receive the next value
}
}
}
// Functions to store and recall path
void executePath() {
for (int i = 0; i < pathIndex; i++) {
unsigned long value = path[i][0];
unsigned long timestamp = path[i][1];
unsigned long nextTimestamp = (i < pathIndex - 1) ? path[i + 1][1] : millis();
unsigned long timeDifference = nextTimestamp - timestamp;
bool obstacleDetected = false;
switch (value) {
case 0xFF629D:
if (!checkObstacle()) {
moveForward();
}
break;
case 0xFFA857:
moveBackward();
break;
case 0xFF22DD:
turnLeft();
break;
case 0xFFC23D:
turnRight();
break;
case 0xFF02FD:
stopCar();
break;
case 0xFF4AB5:
resetArduino();
break;
default:
// Handle unknown path steps
break;
}
delay(timeDifference); // Delay between transmissions (adjust as needed)
irrecv.resume(); // Receive the next value
}
}
void avoidObstacle() {
// Stop the motors
analogWrite(PWMA, 0);
analogWrite(PWMB, 0);
// Back up a little
digitalWrite(AIN, LOW);
digitalWrite(BIN, LOW);
analogWrite(PWMA, 120);
analogWrite(PWMB, 120);
delay(500);
// Turn away from the obstacle
digitalWrite(AIN, HIGH);
digitalWrite(BIN, LOW);
analogWrite(PWMA, 60);
analogWrite(PWMB, 0);
delay(1000);
// Go forward a little
digitalWrite(AIN, HIGH);
digitalWrite(BIN, HIGH);
analogWrite(PWMA, 120);
analogWrite(PWMB, 120);
delay(2000);
// Turn back
digitalWrite(AIN, LOW);
digitalWrite(BIN, HIGH);
analogWrite(PWMA, 0);
analogWrite(PWMB, 60);
delay(1000);
// Resume forward motion
moveForward();
}
bool checkObstacle() {
// Check if an obstacle is too close (e.g., within 10 cm)
unsigned long distance = measureDistance();
if (distance <= 10) {
Serial.println(" Obstacle in the way");
Serial.println(distance);
avoidObstacle();
return true;
}
return false;
}
// Functions to control the car's movement
void moveForward() {
digitalWrite(AIN, HIGH); // Forward direction
analogWrite(PWMA, 120); // Full power
digitalWrite(BIN, HIGH); // Forward direction
analogWrite(PWMB, 120); // Full power
}
void moveBackward() {
digitalWrite(AIN, LOW); // Backwards direction
analogWrite(PWMA, 120); // Full power
digitalWrite(BIN, LOW); // Backwards direction
analogWrite(PWMB, 120); // Full power
}
void turnLeft() {
digitalWrite(AIN, HIGH); // Backwards direction
analogWrite(PWMA, 60); // Full power
digitalWrite(PWMB, LOW);
}
void turnRight() {
digitalWrite(PWMA, LOW); // No power on Right
digitalWrite(BIN, HIGH); // Forward direction
analogWrite(PWMB, 60); // Full power
}
void stopCar() {
digitalWrite(PWMA, LOW); // No power on Right
digitalWrite(PWMB, LOW); // No power on Left
}
void resetArduino() {
asm volatile (" jmp 0");
}