Cirkit Designer LogoCirkit DesignerYour all-in-one circuit design IDE Launch Cirkit Designer App

Arduino Mega 2560 Obstacle-Avoiding Robot with Sound Detection and Servo Control

View and Edit Project In Cirkit DesignerImage of Arduino Mega 2560 Obstacle-Avoiding Robot with Sound Detection and Servo Control

Circuit Documentation

Summary

This circuit is designed to control multiple servos using an Arduino Mega 2560 and an Adafruit PCA9685 PWM Servo Breakout. It also includes an ultrasonic sensor (HC-SR05) for distance measurement and a sound sensor (KY 038) for detecting claps. The system performs rhythmic movements with the servos based on sound detection and distance measurement.

Component List

  1. Arduino Mega 2560

    • Description: A microcontroller board based on the ATmega2560.
    • Pins: IOREF, RESET, 3V3, 5V, GND, VIN, A0-A15, D0-D53, AREF, SDA, SCL
  2. HC-SR05

    • Description: An ultrasonic sensor used for distance measurement.
    • Pins: VCC, TRIG, GND, ECHO, OUT
  3. Micro servo 9G

    • Description: A small servo motor used for precise control of angular position.
    • Pins: GND, +5V, PWM
  4. KY 038

    • Description: A sound sensor module used for detecting sound levels.
    • Pins: +, G, A0, D0
  5. Adafruit PCA9685 PWM Servo Breakout

    • Description: A 16-channel PWM driver used to control servos.
    • Pins: 5.0V, GND, PWRIN, PWM0-PWM15, VCC, SDA, SCL, OE
  6. 5V Battery

    • Description: A power source providing 5V.
    • Pins: +, -

Wiring Details

Arduino Mega 2560

HC-SR05

Micro servo 9G

KY 038

Adafruit PCA9685 PWM Servo Breakout

5V Battery

Code Documentation

#include <Wire.h>
#include <Adafruit_PWMServoDriver.h>

// Create the PCA9685 object
Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver();

// PCA9685 configuration constants
#define SERVO_MIN 150  // Minimum pulse length count (adjust as per servo specifications)
#define SERVO_MAX 600  // Maximum pulse length count (adjust as per servo specifications)

// Servo channel assignments
const int servo1XChannel = 0; // PCA9685 channel for Servo 1X
const int servo1YChannel = 1; // PCA9685 channel for Servo 1Y
const int servo2XChannel = 2; // PCA9685 channel for Servo 2X
const int servo2YChannel = 3; // PCA9685 channel for Servo 2Y

// Pin Definitions for Ultrasonic Sensor
const int trigPin = 3; // Trig pin for ultrasonic sensor
const int echoPin = 2; // Echo pin for ultrasonic sensor

// Sound Sensor Pin and Threshold
const int soundSensorPin = A0; // Analog pin for sound sensor
const int clapThreshold = 500; // Threshold for sound detection

// Debounce Variables for Sound Detection
const unsigned long soundDebounceTime = 1000; // Debounce period in ms
unsigned long lastSoundTime = 0;             // Timestamp of the last detected sound

// Distance Threshold
const int distanceThreshold = 30; // Distance in cm to detect obstacle

// Rhythm State Variables
bool obstacleDetected = false;    // Flag to indicate obstacle detection
bool rhythmActive = false;        // Flag to indicate rhythm execution
unsigned long rhythmStartTime = 0; // Start time for rhythm execution
const unsigned long rhythmDuration = 10000; // Duration for rhythm (10 seconds)
int rhythmCounter = 0;            // Counter to track which rhythm to perform

void setup() {
  // Start I2C communication
  Wire.begin();

  // Initialize PCA9685
  pwm.begin();
  pwm.setPWMFreq(60); // Set frequency to 60Hz for servos
  
  // Initialize Ultrasonic Sensor
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);

  Serial.begin(9600); // Start serial communication
}

void loop() {
  if (!rhythmActive) {
    long distance = measureDistance(trigPin, echoPin); // Measure distance
    int soundValue = analogRead(soundSensorPin);       // Read sound sensor value

    // Check for valid sound detection and debounce
    if (soundValue > clapThreshold && millis() - lastSoundTime > soundDebounceTime) {
      lastSoundTime = millis(); // Update sound detection time
      Serial.println("Sound detected!");

      if (distance < distanceThreshold && !obstacleDetected) {
        obstacleDetected = true;  // Mark obstacle as detected
        rhythmActive = true;      // Activate rhythm mode
        rhythmStartTime = millis(); // Store rhythm start time
        rhythmCounter = (rhythmCounter + 1) % 5; // Cycle through rhythms
        Serial.print("Obstacle Detected. Starting Rhythm ");
        Serial.println(rhythmCounter + 1);
      }
    }
  } else {
    performRhythm(rhythmCounter); // Perform the current rhythm

    // Deactivate rhythm after its duration
    if (millis() - rhythmStartTime > rhythmDuration) {
      rhythmActive = false;
      obstacleDetected = false;
      Serial.println("Rhythm complete. Waiting for next activation...");
    }
  }

  delay(100);
}

// Function to measure distance using the ultrasonic sensor
long measureDistance(int trigPin, int echoPin) {
  digitalWrite(trigPin, LOW);
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH);
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);

  long duration = pulseIn(echoPin, HIGH);
  long distance = duration * 0.034 / 2; // Convert to cm
  return distance;
}

// Function to execute rhythmic servo movement
void performRhythm(int rhythm) {
  switch (rhythm) {
    case 0: // Simple Alternating
      setServoPositions(45, 135, 135, 45);
      delay(500);
      setServoPositions(135, 45, 45, 135);
      break;
    case 1: // Simultaneous Sweep
      for (int angle = 0; angle <= 180; angle += 15) {
        setServoPositions(angle, 180 - angle, angle, 180 - angle);