Project Overview & Difficulty Rating

The Processing Arduino radar is a classic embedded systems project that bridges hardware sensor polling with desktop graphical rendering. The system uses an HC-SR04 ultrasonic sensor mounted on an SG90 micro servo to sweep a 180-degree field of view. The Arduino polls the sensor at each degree increment, calculates the distance using the speed of sound, and streams the angle/distance pairs over a 9600 baud USB serial connection. A desktop application written in the Processing IDE reads this serial stream and renders a real-time polar coordinate sweep, mimicking a sonar or radar screen.

Target Board Variant: This code and wiring guide specifically targets the Arduino Uno R3 (ATmega328P). While compatible with the Nano v3, the Uno R3's dedicated 5V logic and robust USB-to-serial bridge (ATmega16U2) make it the most stable platform for continuous Processing serial handshakes without brownout resets.
ParameterSpecification
Difficulty RatingIntermediate (Requires dual-IDE serial sync)
Estimated Build Time2 hours (Hardware: 45m, Software: 1h 15m)
Estimated Cost$16 - $22 USD
Core ProtocolUART Serial via USB (9600 Baud)

Hardware BOM & Pin Mapping

Sourcing the exact module variants matters here. Do not substitute the HC-SR04 with a 3.3V US-015 if you are using a 5V Arduino, and avoid cheap clone servos that lack internal potentiometer feedback, as they will jitter and ruin your radar sweep geometry.

  • Microcontroller: Arduino Uno R3 (Official or reputable clone like Elegoo)
  • Sensor: HC-SR04 Ultrasonic Distance Sensor (5V logic, 2cm-400cm range)
  • Actuator: SG90 9g Micro Servo (180-degree analog)
  • Power/Wiring: 1x Half-size breadboard, 12x M-M jumper wires, 1x USB-B to USB-A cable

Pin Mapping Table

ComponentComponent PinArduino Uno R3 PinNotes
HC-SR04VCC5VDo not use 3.3V; sensor will fail to trigger
HC-SR04GNDGNDShared ground with servo
HC-SR04TrigDigital 9Output pin
HC-SR04EchoDigital 10Input pin (5V tolerant on Uno R3)
SG90 ServoRed (Power)5VDraws ~200mA on stall; monitor for USB brownouts
SG90 ServoBrown (GND)GNDMust share ground with HC-SR04
SG90 ServoOrange (Signal)Digital 6PWM capable pin

Arduino Firmware: The Sweep & Ping Logic

The Arduino sketch handles the physical sweeping and ultrasonic timing. We use the pulseIn() function with a strict timeout to prevent the radar from hanging when the sound wave scatters into open space. According to the official Arduino pulseIn reference, a 30,000 microsecond timeout limits the maximum readable distance to roughly 5 meters, which is perfect for a desktop radar.

// Processing Arduino Radar - Firmware
// Target: Arduino Uno R3 (ATmega328P)
#include <Servo.h>

#define TRIG_PIN 9
#define ECHO_PIN 10
#define SERVO_PIN 6
#define MAX_DISTANCE 400 // cm

Servo myServo;

void setup() {
  Serial.begin(9600);
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  myServo.attach(SERVO_PIN);
  myServo.write(15); // Start at 15 degrees to avoid mechanical binding at 0
  delay(1000);
}

void loop() {
  // Sweep forward
  for (int angle = 15; angle <= 165; angle++) {
    myServo.write(angle);
    delay(30); // Wait for servo to settle and sensor to ping
    int distance = measureDistance();
    sendSerialData(angle, distance);
  }
  
  // Sweep backward
  for (int angle = 165; angle >= 15; angle--) {
    myServo.write(angle);
    delay(30);
    int distance = measureDistance();
    sendSerialData(angle, distance);
  }
}

int measureDistance() {
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  // Timeout set to 30000us (~5 meters max)
  long duration = pulseIn(ECHO_PIN, HIGH, 30000);
  
  // Speed of sound = 343 m/s -> 0.0343 cm/us. Divide by 2 for round trip.
  int distance = duration * 0.0343 / 2;
  
  // Error handling: if timeout triggers, duration is 0
  if (distance == 0 || distance > MAX_DISTANCE) {
    distance = MAX_DISTANCE; // Cap at max range for GUI rendering
  }
  return distance;
}

void sendSerialData(int angle, int distance) {
  Serial.print(angle);
  Serial.print(",");
  Serial.println(distance);
}

Processing GUI: Rendering the Radar Sweep

The Processing IDE uses Java under the hood. The GUI listens to the serial port, parses the comma-separated angle and distance strings, and draws lines using polar-to-Cartesian trigonometry. For detailed serial library implementation, refer to the Processing Serial Documentation.

Callout Tip: You must install the Processing IDE (version 4.x recommended) from processing.org. Do not attempt to compile this Java code inside the Arduino IDE.
// Processing Arduino Radar - GUI
// Target: Processing IDE 4.x
import processing.serial.*;

Serial myPort; 
int[] distances = new int[181]; // Array to store distances for each degree
int maxDistance = 400;

void setup() {
  size(800, 600); 
  smooth();
  
  // Initialize array with max distance
  for (int i = 0; i < distances.length; i++) {
    distances[i] = maxDistance;
  }
  
  try {
    // Automatically selects the first available serial port (usually the Arduino)
    String portName = Serial.list()[0];
    myPort = new Serial(this, portName, 9600);
    myPort.bufferUntil('\n');
  } catch (Exception e) {
    println("Error: Arduino not found or port busy. Check connections.");
  }
}

void draw() {
  background(10, 20, 30); // Dark radar background
  stroke(0, 255, 0); // Green radar lines
  noFill();
  
  pushMatrix();
  translate(width/2, height - 50); // Move origin to bottom center
  
  // Draw radar grid circles
  for (int i = 100; i <= maxDistance; i += 100) {
    ellipse(0, 0, i*2, i*2);
  }
  
  // Draw the detected objects
  strokeWeight(2);
  for (int i = 15; i <= 165; i++) {
    float rad = radians(i);
    float x1 = cos(rad) * distances[i];
    float y1 = -sin(rad) * distances[i];
    line(0, 0, x1, y1);
  }
  
  popMatrix();
}

void serialEvent(Serial myPort) {
  String data = myPort.readStringUntil('\n');
  if (data != null) {
    data = trim(data);
    String[] items = split(data, ',');
    if (items.length == 2) {
      int angle = int(items[0]);
      int distance = int(items[1]);
      if (angle >= 0 && angle <= 180) {
        distances[angle] = distance;
      }
    }
  }
}

Debugging: Serial Sync & "Port Not Found" Errors

When bridging hardware and desktop software, serial handshake failures are the most common point of failure. If your Processing screen stays black or throws red text in the console, follow these diagnostic steps.

The First Three Things to Check When It Fails

  1. Port Index Mismatch: Processing defaults to Serial.list()[0]. If you have a Bluetooth adapter or virtual COM port installed, your Arduino might actually be on index 1 or 2. Print Serial.list() in Processing's setup() to verify the exact array index of your Uno R3.
  2. Baud Rate Asymmetry: Ensure the Arduino Serial.begin(9600) exactly matches the Processing new Serial(this, portName, 9600). A mismatch (e.g., 115200 on one side) will result in garbage characters and array parsing failures.
  3. USB Cable Charge-Only Wiring: A surprisingly common bench mistake. If the Arduino powers on but doesn't show up in the Arduino IDE port list or Processing, swap the USB-B cable. Charge-only cables lack the D+ and D- data lines required for the ATmega16U2 serial bridge.

Exact Error Strings & Ranked Causes

Error String: Serial port 'COM3' not found or ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

  • Cause 1: The Arduino is unplugged or the USB cable is data-defective.
  • Cause 2: The Arduino IDE Serial Monitor is currently open. The monitor locks the COM port, preventing Processing from accessing it. Close the Serial Monitor.

Error String: NumberFormatException: For input string: "" or disconnected

  • Cause 1: Serial buffer fragmentation. The Arduino sent a partial string before Processing read it. Fix this by ensuring myPort.bufferUntil('\n') is present in Processing and Serial.println() is used in Arduino.
  • Cause 2: The HC-SR04 Echo pin is floating or disconnected, causing the Arduino to crash or reboot due to electrical noise, dropping the USB connection.

Extending and Simplifying the Build

Depending on your project goals, you may want to scale this build up for a robotics application or down for a basic microcontroller introduction.

How to Simplify: Strip away the SG90 servo and the Processing GUI. Hardcode the Arduino to take a single continuous distance reading and output it to the built-in Serial Plotter (Tools > Serial Plotter in the Arduino IDE). This reduces the project to a basic 10-minute ultrasonic logger, perfect for teaching pulseIn() timing without the overhead of Java GUI rendering.

How to Extend: Upgrade the sensor array for a dual-beam radar. Add a second HC-SR04 mounted at a 45-degree offset. Modify the Arduino payload to send angle,distance1,distance2. In Processing, map the second dataset to a different color (e.g., red) to create a stereoscopic depth map. For a modern IoT twist, swap the Arduino Uno R3 for an ESP32 DevKit v1, replace the Processing serial link with WebSockets, and render the radar sweep in a browser using HTML5 Canvas and JavaScript.

Frequently Asked Questions

Can I use an ESP32 instead of an Arduino for the Processing radar?

Yes, but you must account for logic level differences. The ESP32 operates at 3.3V logic. The standard HC-SR04 requires a 5V trigger and outputs a 5V echo signal, which will fry the ESP32's GPIO pins over time. You must either use a 3.3V-compatible ultrasonic sensor (like the US-015 or RCWL-1601) or use a bidirectional logic level converter on the Echo pin. Additionally, the ESP32's servo PWM library differs from the standard Arduino Servo.h library; you will need to use ESP32Servo.h.

Why does my Processing radar lag or stutter during the sweep?

Stuttering is almost always caused by the delay() function in the Arduino firmware blocking the serial buffer, or the servo drawing too much current and causing minor USB brownouts. First, ensure your delay(30) isn't set too high; 15ms is usually sufficient for the SG90 to settle. Second, if the servo stalls at the mechanical limits (0 or 180 degrees), it can draw up to 700mA, exceeding the Arduino Uno's onboard 5V regulator limits and resetting the ATmega16U2 USB bridge. This is why the code limits the sweep to 15-165 degrees.

How do I change the radar sweep from 180 degrees to 360 degrees?

The standard SG90 micro servo is mechanically limited to 180 degrees. To achieve a full 360-degree sweep, you must replace the SG90 with a continuous rotation servo modified for positional feedback, or a dedicated 360-degree digital servo (like the DS3218). However, the HC-SR04's wiring will twist and snap after a few rotations. For a true 360-degree radar, mount the sensor on a slip ring to pass the wires through the rotating axis, or move to a non-contact time-of-flight (ToF) LiDAR module like the TFMini-S, which handles 360-degree rotation via a dedicated slip-ring assembly.