Project 8 : Ultrasonic Radar using Servo and ESP32
Share
ESP32 Radar Project - Complete Beginner Tutorial
Overview
This project creates a radar system using an ESP32 microcontroller, ultrasonic sensor, servo motor, and a visual display on your computer. The radar sweeps in a 180-degree arc, detecting objects and displaying them on a colorful radar screen - just like in movies!
What You'll Learn
- How to use ultrasonic sensors for distance measurement
 - Servo motor control with ESP32
 - Serial communication between ESP32 and computer
 - Visual programming with Processing IDE
 - Real-time data visualization
 
Components Needed
Hardware:
- ESP32 Development Board - The brain of the project
 - HC-SR04 Ultrasonic Sensor - For distance measurement (like a bat's echolocation!)
 - SG90 Servo Motor - To rotate the sensor
 - Breadboard - For connecting components
 - Jumper Wires - Male-to-male and male-to-female
 - USB Cable - To connect ESP32 to computer
 - Power Supply - 5V (optional, USB can power everything)
 
Software:
- Arduino IDE - To program the ESP32
 - Processing IDE - To create the radar display
 - ESP32 Board Package - For Arduino IDE
 
Part 1: Hardware Setup
Step 1: Wiring Connections
Ultrasonic Sensor (HC-SR04) to ESP32:
HC-SR04    →    ESP32
VCC        →    3.3V
GND        →    GND
TRIGGER    →    GPIO 5
ECHO       →    GPIO 18
Servo Motor to ESP32:
Servo      →    ESP32
Red Wire   →    5V
Brown Wire →    GND
Orange Wire→    GPIO 13
Step 2: Physical Assembly
- Mount the ultrasonic sensor on the servo horn (the plastic piece that comes with servo)
 - Secure with hot glue or double-sided tape
 - Connect all wires according to the wiring diagram above
 - Place on breadboard for stability
 
Wiring Diagram Description:
Part 2: Software Setup
Step 1: Install Arduino IDE
Step 2: Install Processing IDE
- Download from processing.org
 - Install and run it once to set up
 
Step 3: Install Required Libraries
In Arduino IDE:
- Go to Tools → Manage Libraries
 - Search and install: "ESP32Servo"
 
Part 3: Programming the ESP32
Step 1: Understanding the ESP32 Code
The ESP32 code does three main things:
- Controls the servo - Makes it sweep back and forth
 - Reads the ultrasonic sensor - Measures distances
 - Sends data to computer - Via serial communication
 
Step 2: Upload the ESP32 Code
Arduino Ide Code :
-------------------------------------------------------------------------------
#include <ESP32Servo.h>
// Pin definitions
#define TRIGGER_PIN 5  // GPIO pin connected to ultrasonic trigger
#define ECHO_PIN 18    // GPIO pin connected to ultrasonic echo
#define SERVO_PIN 13   // GPIO pin connected to servo signal
// Constants
#define SERVO_DELAY 50      // Delay between servo movements (ms)
#define SCAN_ANGLE_MIN 15   // Minimum sweep angle
#define SCAN_ANGLE_MAX 165  // Maximum sweep angle
#define SCAN_STEP 1         // Degrees to move each step
#define MAX_DISTANCE 200    // Maximum distance to measure (cm)
Servo radarServo;
int currentAngle = SCAN_ANGLE_MIN;
bool scanningForward = true;
unsigned long lastMeasurement = 0;
const unsigned long measurementInterval = 100; // ms between measurements
void setup() {
  // Initialize serial communication
  Serial.begin(115200);
  
  // Configure ultrasonic sensor pins
  pinMode(TRIGGER_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  
  // ESP32 specific - allow allocation of timers
  ESP32PWM::allocateTimer(0);
  ESP32PWM::allocateTimer(1);
  ESP32PWM::allocateTimer(2);
  ESP32PWM::allocateTimer(3);
  
  // Initialize servo with ESP32 servo settings
  radarServo.setPeriodHertz(50);    // Standard 50hz servo
  radarServo.attach(SERVO_PIN, 500, 2400); // Default min/max pulse width values
  radarServo.write(SCAN_ANGLE_MIN);
  
  delay(2000); // Give time for the servo to reach starting position
  
  Serial.println("ESP32 Radar Starting...");
}
void loop() {
  // Move the servo
  radarServo.write(currentAngle);
  delay(SERVO_DELAY);
  
  // Measure distance at appropriate intervals
  unsigned long currentTime = millis();
  if (currentTime - lastMeasurement >= measurementInterval) {
    lastMeasurement = currentTime;
    
    // Measure distance
    int distance = measureDistance();
    
    // Send data to Processing in format: angle,distance
    Serial.print(currentAngle);
    Serial.print(",");
    Serial.println(distance);
  }
  
  // Update angle for next measurement
  if (scanningForward) {
    currentAngle += SCAN_STEP;
    if (currentAngle >= SCAN_ANGLE_MAX) {
      scanningForward = false;
    }
  } else {
    currentAngle -= SCAN_STEP;
    if (currentAngle <= SCAN_ANGLE_MIN) {
      scanningForward = true;
    }
  }
}
int measureDistance() {
  // Clear the trigger pin
  digitalWrite(TRIGGER_PIN, LOW);
  delayMicroseconds(2);
  
  // Set the trigger pin high for 10 microseconds
  digitalWrite(TRIGGER_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGER_PIN, LOW);
  
  // Read the echo pin, return pulse duration in microseconds
  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // Timeout after 30ms
  
  // Calculate the distance
  int distance = duration * 0.034 / 2; // Speed of sound wave divided by 2
  
  // Constrain the distance to maximum range
  if (distance > MAX_DISTANCE || distance <= 0) {
    distance = MAX_DISTANCE;
  }
  
  return distance;
}
----------------------------------------------------------------------------------
Processing Code:
----------------------------------------------------------------------------------
import processing.serial.*;
Serial myPort;        // Serial port object
String serialData;    // Data received from serial port
boolean connected = false;
int dataCount = 0;    // Count received data points for debugging
// Display configuration - made larger for kids
int displaySize = 900;
int radarRadius = 400;  // Bigger radar for better visibility
int centerX, centerY;
// Radar settings - optimized for short range
int maxDistance = 100;  // Reduced to 100cm (1 meter) for short range
float currentAngle = 15;
float previousAngle = currentAngle;
boolean scanningForward = true;
float[] distances = new float[181];
int[] objectAge = new int[181];  // Track how long objects have been detected
// Servo timing simulation
int servoDelay = 50;
int scanStep = 1;
int scanAngleMin = 15;
int scanAngleMax = 165;
long lastMoveTime = 0;
// Enhanced visual settings for kids
color backgroundColor = color(5, 15, 25);
color gridColor = color(0, 80, 120);
color sweepColor = color(100, 255, 100);
color objectColor = color(255, 80, 80);
color textColor = color(200, 255, 200);
color warningColor = color(255, 255, 0);
color dangerColor = color(255, 50, 50);
// Kid-friendly features
boolean showDebug = false;  // Start with debug off for kids
StringList debugLog = new StringList();
int maxLogLines = 5;
boolean forceTestObject = false;
boolean playWarningSound = true;
int warningDistance = 30;  // Objects closer than 30cm show warning
// Distance zones for kids
int[] distanceZones = {20, 40, 60, 80, 100};
String[] zoneLabels = {"VERY CLOSE!", "Close", "Medium", "Far", "Very Far"};
color[] zoneColors = {
  color(255, 0, 0),    // Red - Very close
  color(255, 100, 0),  // Orange - Close
  color(255, 255, 0),  // Yellow - Medium
  color(0, 255, 0),    // Green - Far
  color(0, 150, 255)   // Blue - Very far
};
// IMPORTANT: Change this to match your ESP32's port
String ESP32_PORT = ""; // Leave blank to force manual selection
void setup() {
  size(900, 900);
  centerX = width / 2;
  centerY = height / 2;
  smooth();
  
  // Initialize arrays
  for (int i = 0; i < distances.length; i++) {
    distances[i] = 0;
    objectAge[i] = 0;
  }
  
  // List available serial ports
  println("Available serial ports:");
  String[] portList = Serial.list();
  for (int i = 0; i < portList.length; i++) {
    println(i + ": " + portList[i]);
  }
  
  addDebugMessage("Available ports: " + portList.length);
  
  if (ESP32_PORT.isEmpty()) {
    println("Press 0-9 keys to select a serial port");
    addDebugMessage("Press 0-9 to select a serial port");
  } else {
    connectToPort(ESP32_PORT);
  }
}
void addDebugMessage(String message) {
  println(message);
  debugLog.append(message);
  if (debugLog.size() > maxLogLines) {
    debugLog.remove(0);
  }
}
void connectToPort(String portName) {
  try {
    if (myPort != null) {
      myPort.stop();
    }
    
    println("Connecting to: " + portName);
    addDebugMessage("Connecting to: " + portName);
    
    myPort = new Serial(this, portName, 115200);
    myPort.bufferUntil('\n');
    
    connected = true;
    println("Connected successfully!");
    addDebugMessage("Connected successfully!");
    dataCount = 0;
  } catch (Exception e) {
    println("Failed to connect to: " + portName);
    addDebugMessage("Failed: " + portName);
    connected = false;
  }
}
void draw() {
  background(backgroundColor);
  
  // Age objects (fade old detections)
  for (int i = 0; i < objectAge.length; i++) {
    if (objectAge[i] > 0) {
      objectAge[i]--;
      if (objectAge[i] == 0) {
        distances[i] = 0;  // Clear old detections
      }
    }
  }
  
  // Draw title for kids
  fill(textColor);
  textSize(28);
  textAlign(CENTER);
  text("RADAR DETECTOR", width/2, 40);
  textAlign(LEFT);
  
  // Draw connection status
  if (!connected) {
    fill(dangerColor);
    textSize(20);
    textAlign(CENTER);
    text("NOT CONNECTED - PRESS 0-9 TO SELECT PORT", width/2, 80);
    textAlign(LEFT);
    
    // Simulate movement when not connected
    if (millis() - lastMoveTime >= servoDelay) {
      updateServoPosition();
      lastMoveTime = millis();
    }
    
    // Add test objects for demonstration
    if (forceTestObject) {
      distances[90] = 50;  // Test object at 90 degrees, 50cm
      distances[60] = 25;  // Another test object
      objectAge[90] = 30;
      objectAge[60] = 30;
    }
  } else {
    fill(color(0, 255, 0));
    textSize(18);
    textAlign(CENTER);
    text("CONNECTED ✓ - Objects detected: " + countObjects(), width/2, 80);
    textAlign(LEFT);
  }
  
  // Draw the enhanced radar
  drawRadarGrid();
  drawSweepLine();
  drawDetectedObjects();
  drawInfoPanel();
  
  // Draw warning if objects are too close
  drawWarnings();
  
  // Draw debug panel if enabled
  if (showDebug) {
    drawDebugPanel();
  }
}
void updateServoPosition() {
  if (scanningForward) {
    currentAngle += scanStep;
    if (currentAngle >= scanAngleMax) {
      scanningForward = false;
    }
  } else {
    currentAngle -= scanStep;
    if (currentAngle <= scanAngleMin) {
      scanningForward = true;
    }
  }
}
void drawRadarGrid() {
  // Draw colorful distance zones
  noFill();
  strokeWeight(2);
  
  // Draw zone circles with colors
  for (int i = 0; i < distanceZones.length; i++) {
    float radius = map(distanceZones[i], 0, maxDistance, 0, radarRadius);
    stroke(zoneColors[i], 100);
    arc(centerX, centerY, radius * 2, radius * 2, PI, TWO_PI);
    
    // Draw zone labels
    fill(zoneColors[i]);
    textSize(14);
    text(zoneLabels[i] + " (" + distanceZones[i] + "cm)", 
         centerX + radius + 10, centerY - 5);
  }
  
  // Draw angle lines
  stroke(gridColor);
  strokeWeight(1);
  for (int angle = 0; angle <= 180; angle += 30) {
    float rad = radians(angle);
    float x = centerX + radarRadius * cos(rad);
    float y = centerY - radarRadius * sin(rad);
    line(centerX, centerY, x, y);
    
    // Draw bigger angle labels
    fill(textColor);
    textSize(16);
    float labelX = x + 20 * cos(rad);
    float labelY = y - 20 * sin(rad);
    text(angle + "°", labelX, labelY);
  }
  
  // Draw the radar base (bigger)
  fill(gridColor);
  stroke(gridColor);
  strokeWeight(2);
  arc(centerX, centerY, 80, 80, PI, TWO_PI);
  
  // Add "RADAR" text in the base
  fill(textColor);
  textSize(12);
  textAlign(CENTER);
  text("RADAR", centerX, centerY - 5);
  textAlign(LEFT);
}
void drawSweepLine() {
  // Draw animated sweep line
  stroke(sweepColor);
  strokeWeight(3);
  
  // Convert angle correctly for display
  float displayAngle = currentAngle; // 0 is up, 90 is right, 180 is down
  float rad = radians(displayAngle);
  float x = centerX + radarRadius * cos(rad);
  float y = centerY - radarRadius * sin(rad);
  
  line(centerX, centerY, x, y);
  
  // Draw glowing effect at the end
  noStroke();
  fill(sweepColor, 200);
  ellipse(x, y, 12, 12);
  fill(sweepColor, 100);
  ellipse(x, y, 20, 20);
  
  // Draw trail effect
  for (int i = 1; i <= 10; i++) {
    float trailAngle = scanningForward ? 
                      displayAngle - i * 2 : 
                      displayAngle + i * 2;
    
    if (trailAngle >= 0 && trailAngle <= 180) {
      float trailRad = radians(trailAngle);
      float trailX = centerX + radarRadius * cos(trailRad);
      float trailY = centerY - radarRadius * sin(trailRad);
      
      float alpha = map(i, 1, 10, 100, 10);
      stroke(sweepColor, alpha);
      strokeWeight(2);
      line(centerX, centerY, trailX, trailY);
    }
  }
}
void drawDetectedObjects() {
  noStroke();
  
  for (int angle = 0; angle <= 180; angle++) {
    if (distances[angle] > 0 && distances[angle] <= maxDistance) {
      float distance = distances[angle];
      
      // Calculate screen position
      float displayAngle = angle;
      float rad = radians(displayAngle);
      
      // Improved distance mapping - linear and accurate
      float screenDistance = map(distance, 0, maxDistance, 0, radarRadius);
      float x = centerX + screenDistance * cos(rad);
      float y = centerY - screenDistance * sin(rad);
      
      // Determine object color based on distance
      color objColor = getObjectColor(distance);
      
      // Draw object with size based on age (newer = bigger)
      float objSize = map(objectAge[angle], 0, 30, 8, 20);
      
      // Draw glow effect
      fill(objColor, 50);
      ellipse(x, y, objSize * 2, objSize * 2);
      
      // Draw main object
      fill(objColor);
      ellipse(x, y, objSize, objSize);
      
      // Draw distance label for close objects
      if (distance <= 50) {
        fill(255);
        textSize(10);
        textAlign(CENTER);
        text(int(distance) + "cm", x, y - objSize/2 - 5);
        textAlign(LEFT);
      }
    }
  }
}
color getObjectColor(float distance) {
  // Return color based on distance zones
  for (int i = 0; i < distanceZones.length; i++) {
    if (distance <= distanceZones[i]) {
      return zoneColors[i];
    }
  }
  return zoneColors[zoneColors.length - 1];
}
void drawInfoPanel() {
  // Overlay panel on lower part of radar
  int panelWidth = 400;
  int panelHeight = 100;
  int panelX = centerX - panelWidth / 2;
  int panelY = centerY + radarRadius - panelHeight - 20 - 200;
  // Draw main info panel
  fill(0, 100);
  stroke(gridColor);
  strokeWeight(2);
  rect(panelX, panelY, panelWidth, panelHeight, 15);
  
  // Current angle and direction
  fill(textColor);
  textSize(18);
  text("Scanning: " + int(currentAngle) + "° " + 
       (scanningForward ? "→" : "←"), panelX + 20, panelY + 30);
  
  // Current distance reading
  int angleIndex = int(currentAngle);
  if (angleIndex >= 0 && angleIndex < distances.length && distances[angleIndex] > 0) {
    float currentDistance = distances[angleIndex];
    fill(getObjectColor(currentDistance));
    text("Distance: " + int(currentDistance) + "cm", panelX + 20, panelY + 55);
    
    // Status message
    String status = getDistanceStatus(currentDistance);
    text("Status: " + status, panelX + 20, panelY + 80);
  } else {
    fill(textColor);
    text("Distance: No object detected", panelX + 20, panelY + 55);
    text("Status: Clear", panelX + 20, panelY + 80);
  }
  
  // Object counter
  fill(textColor);
  textSize(16);
  text("Objects in range: " + countObjects(), panelX + 230, panelY + 30);
}
String getDistanceStatus(float distance) {
  if (distance <= 20) return "VERY CLOSE!";
  if (distance <= 40) return "Close";
  if (distance <= 60) return "Medium distance";
  if (distance <= 80) return "Far";
  return "Very far";
}
void drawWarnings() {
  // Check for very close objects
  boolean hasCloseObjects = false;
  for (int i = 0; i < distances.length; i++) {
    if (distances[i] > 0 && distances[i] <= warningDistance) {
      hasCloseObjects = true;
      break;
    }
  }
  
  if (hasCloseObjects) {
    // Flash warning
    int flashRate = millis() / 300;
    if (flashRate % 2 == 0) {
      fill(dangerColor, 150);
      textSize(32);
      textAlign(CENTER);
      text("⚠️ VERY CLOSE OBJECT! ⚠️", width/2, height/2 - 100);
      textAlign(LEFT);
    }
  }
}
int countObjects() {
  int count = 0;
  for (int i = 0; i < distances.length; i++) {
    if (distances[i] > 0 && distances[i] <= maxDistance) {
      count++;
    }
  }
  return count;
}
void drawDebugPanel() {
  // Debug panel for troubleshooting
  fill(0, 150);
  rect(width - 350, 100, 330, 200, 10);
  
  fill(255, 200, 0);
  textSize(14);
  text("DEBUG MODE", width - 340, 125);
  text("Press 'D' to hide", width - 340, 145);
  
  if (serialData != null) {
    text("Data: " + serialData, width - 340, 170);
  }
  
  text("Angle: " + currentAngle + "°", width - 340, 190);
  text("Objects: " + countObjects(), width - 340, 210);
  text("Connected: " + connected, width - 340, 230);
  
  // Show recent debug messages
  for (int i = 0; i < min(debugLog.size(), 3); i++) {
    text(debugLog.get(debugLog.size() - 1 - i), width - 340, 250 + i * 20);
  }
}
void serialEvent(Serial port) {
  serialData = port.readStringUntil('\n');
  
  if (serialData != null) {
    serialData = trim(serialData);
    
    String[] data = split(serialData, ',');
    
    if (data.length == 2) {
      try {
        int angle = int(data[0]);
        float distance = float(data[1]);
        
        // Update scanning direction
        if (angle > currentAngle) {
          scanningForward = true;
        } else if (angle < currentAngle) {
          scanningForward = false;
        }
        
        previousAngle = currentAngle;
        currentAngle = angle;
        
        // Store distance and set object age for persistence
        if (angle >= 0 && angle < distances.length) {
          distances[angle] = distance;
          objectAge[angle] = 30;  // Keep object visible for 30 frames
          dataCount++;
        }
      } catch (Exception e) {
        addDebugMessage("Parse error: " + e.toString());
      }
    }
  }
}
void keyPressed() {
  // Port selection
  if (key >= '0' && key <= '9') {
    int portIndex = key - '0';
    String[] portList = Serial.list();
    if (portIndex < portList.length) {
      connectToPort(portList[portIndex]);
    }
  }
  
  // Toggle debug mode
  if (key == 'd' || key == 'D') {
    showDebug = !showDebug;
  }
  
  // Toggle test objects
  if (key == 't' || key == 'T') {
    forceTestObject = !forceTestObject;
  }
  
  // Clear all objects
  if (key == 'c' || key == 'C') {
    for (int i = 0; i < distances.length; i++) {
      distances[i] = 0;
      objectAge[i] = 0;
    }
    addDebugMessage("Cleared all objects");
  }
}
----------------------------------------------------------------------------------
- Connect your ESP32 to computer via USB
 - Open Arduino IDE
 - Select your board: Tools → Board → ESP32 Arduino → "ESP32 Dev Module"
 - Select the port: Tools → Port → (choose your ESP32 port)
 - Copy and paste the ESP32 code (the one you provided)
 - Click Upload (arrow button)
 
Key Code Explanations:
// This part measures distance
int measureDistance() {
    digitalWrite(TRIGGER_PIN, HIGH);  // Send ultrasonic pulse
    delayMicroseconds(10);
    digitalWrite(TRIGGER_PIN, LOW);
    
    long duration = pulseIn(ECHO_PIN, HIGH);  // Wait for echo
    int distance = duration * 0.034 / 2;     // Convert to centimeters
    return distance;
}
// This part moves the servo
if (scanningForward) {
    currentAngle += SCAN_STEP;  // Move forward
} else {
    currentAngle -= SCAN_STEP;  // Move backward
}
radarServo.write(currentAngle);  // Move servo to new position
Part 4: Setting Up the Processing Radar Display
Step 1: Understanding the Processing Code
The Processing code creates a visual radar display that:
- Receives data from ESP32 via serial port
 - Draws a radar screen with distance rings and angle lines
 - Shows detected objects as colored dots
 - Provides kid-friendly interface with warnings and status
 
Step 2: Run the Processing Code
- Open Processing IDE
 - Copy and paste the Processing code (the one you provided)
 - Click Run (play button)
 
Step 3: Connect to ESP32
When the Processing program runs:
- It will show available serial ports
 - Press the number key (0-9) corresponding to your ESP32 port
 - You should see "CONNECTED ✓" message
 - The radar should start showing objects!
 
Part 5: How It Works
The Radar Process:
- Servo rotates from 15° to 165° and back
 - At each angle, ultrasonic sensor measures distance
 - ESP32 sends angle and distance data: "90,45" (90 degrees, 45cm)
 - Processing receives this data and draws it on screen
 - Objects appear as colored dots based on distance
 
Distance Zones (Kid-Friendly):
- Red: Very Close (0-20cm) - "VERY CLOSE!"
 - Orange: Close (20-40cm) - "Close"
 - Yellow: Medium (40-60cm) - "Medium"
 - Green: Far (60-80cm) - "Far"
 - Blue: Very Far (80-100cm) - "Very Far"
 
Part 6: Testing and Troubleshooting
Testing Your Radar:
- Move your hand in front of the sensor at different distances
 - Place objects at various positions
 - Watch the radar screen - objects should appear as colored dots
 - Test the range - maximum detection is about 100cm (1 meter)
 
Common Issues and Solutions:
"Port not found" or "Connection failed":
- Check USB cable - Make sure it's a data cable, not power-only
 - Check drivers - Install ESP32 drivers if needed
 - Try different port - Use different USB port on computer
 - Restart Arduino IDE and try again
 
"Servo not moving smoothly":
- Check power supply - Servo needs enough power (5V recommended)
 - Check connections - Ensure all wires are secure
 - 
Adjust delay - Increase 
SERVO_DELAYin ESP32 code 
"No objects detected" or "Incorrect distances":
- Check sensor connections - TRIGGER and ECHO pins
 - Sensor orientation - Make sure sensor faces forward
 - Remove obstacles - Clear area in front of sensor
 - Check sensor mounting - Should be stable on servo
 
"Processing display not working":
- Select correct port - Press right number key for ESP32 port
 - Check baud rate - Should be 115200 in both codes
 - Try debug mode - Press 'D' in Processing to see debug info
 
Useful Processing Controls:
- Press 'D' - Toggle debug mode
 - Press 'T' - Add test objects (when not connected)
 - Press 'C' - Clear all detected objects
 - Press 0-9 - Select serial port
 
Part 7: Customization Ideas
For Beginners:
- Change colors - Modify the color variables in Processing code
 - 
Adjust range - Change 
maxDistanceto scan further/closer - 
Speed control - Modify 
SERVO_DELAYfor faster/slower scanning - Add sounds - Use Processing's sound library for beeps
 
For Advanced Users:
- Add LCD display - Show distance on hardware display
 - Multiple sensors - Use multiple ultrasonics for wider coverage
 - Object tracking - Remember object positions over time
 - Save radar data - Log detections to file
 - WiFi connectivity - Send data over network
 
Part 8: Understanding the Science
How Ultrasonic Sensors Work:
- Send sound wave at 40kHz (too high for humans to hear)
 - Wait for echo to return from objects
 - Calculate distance using: Distance = (Time × Speed of Sound) ÷ 2
 - Speed of sound ≈ 343 meters/second in air
 
Why Divide by 2?
Sound travels to the object and back, so total distance is double the actual distance to object.
Servo Motor Basics:
- PWM Control - Uses pulse width to set position
 - 50Hz frequency - Standard for servo motors
 - Pulse width: 1ms = 0°, 1.5ms = 90°, 2ms = 180°
 
Part 9: Safety and Best Practices
Safety Tips:
- Low voltage - This project uses safe 5V/3.3V levels
 - Secure connections - Ensure all wires are properly connected
 - Stable mounting - Prevent servo/sensor from falling
 - Adult supervision - For younger builders
 
Best Practices:
- Comment your code - Add explanations for future reference
 - Test incrementally - Test each component separately first
 - Keep backups - Save working code versions
 - Document changes - Note what modifications you make
 
Conclusion
Congratulations! You've built a working radar system that can detect objects and display them in real-time. This project demonstrates many important concepts:
- Sensor interfacing - Reading real-world data
 - Motor control - Precise positioning
 - Serial communication - Data transfer between devices
 - Data visualization - Converting numbers to graphics
 - Real-time systems - Processing continuous data streams
 
Next Steps:
- Experiment with different objects and distances
 - Modify the code to add new features
 - Share your project with friends and family
 - Learn more about robotics and programming
 
Additional Resources:
- ESP32 Documentation: docs.espressif.com
 - Processing Reference: processing.org/reference
 - Arduino Tutorials: arduino.cc/en/Tutorial
 
Happy building! 🚀