ESP32 Bench
Boards: ESP32, S2, S3, C3, C6
Flash and monitor: Web Serial
← All projects

IR sonar sweep

A servo swings a Sharp IR distance sensor back and forth like a radar dish. The bench charts every reading and each sweep ends with a little map of what it saw.

Intermediate30 min115200 baud
Board
Fig. 1. Pins this project uses on the ESP32-DevKitC V4, 38 pin. USB connector at the bottom.

Wiring

FromTo boardNote
Sharp VCC (red)5VThe sensor needs 5 V. Its output stays below about 3.1 V, so it is safe for the ESP32
Sharp GND (black)GNDPut the 100 µF capacitor across VCC and GND, right at the sensor
Sharp Vo (yellow or white)GPIO 34An ADC1 pin, so it keeps working if you add Wi-Fi later
Servo red5VOne micro servo is fine from USB
Servo brownGND
Servo orangeGPIO 18

Tested on this board

Not run on this board yet. Treat the wiring and code as a first draft.

Firmware, Arduino sketch for ESP32 Dev Module

// IR sonar sweep: a servo swings a Sharp IR distance sensor from side to side
// and maps what it sees. Open the bench: angle and cm chart live, and each sweep
// ends with a little top-down map.
#include <ESP32Servo.h>

const int SERVO_PIN = 18;
const int IR_PIN = 34;               // an ADC1 pin: the sensor's analog output
const int STEP_DEG = 10;               // degrees per step
const int SETTLE_MS = 60;              // let the servo arrive and the sensor update (it refreshes every ~40 ms)
const int SAMPLES = 8;                 // readings averaged per step: the sensor is noisy
const float MIN_CM = 10, MAX_CM = 80;  // the GP2Y0A21's useful range

Servo servo;
float distances[180 / STEP_DEG + 1];

// The GP2Y0A21YK's output falls as distance rises, roughly as a power curve.
// cm = 27.86 * V^-1.15 is a common fit to the datasheet's typical curve from
// 10 to 80 cm. Measure a few known distances and adjust it for real accuracy.
float readCm() {
  uint32_t mv = 0;
  for (int i = 0; i < SAMPLES; i++) {
    mv += analogReadMilliVolts(IR_PIN);
    delay(2);
  }
  const float volts = mv / (float)SAMPLES / 1000.0f;
  if (volts < 0.35f) return MAX_CM + 1;  // nothing in range
  const float cm = 27.86f * powf(volts, -1.15f);
  return constrain(cm, MIN_CM - 1, MAX_CM + 1);
}

// A top-down map of one sweep: the sensor at the bottom middle, '*' where it saw
// something. It contains no digits, so the bench's plotter ignores it.
void drawMap() {
  const int W = 41, H = 11;
  char grid[H][W + 1];
  for (int y = 0; y < H; y++) {
    memset(grid[y], ' ', W);
    grid[y][W] = 0;
  }
  for (int i = 0; i * STEP_DEG <= 180; i++) {
    const float cm = distances[i];
    if (cm > MAX_CM) continue;
    const float a = radians(i * STEP_DEG);
    const int x = W / 2 + (int)roundf(cosf(a) * cm / MAX_CM * (W / 2));
    const int y = H - 1 - (int)roundf(sinf(a) * cm / MAX_CM * (H - 1));
    if (x >= 0 && x < W && y >= 0 && y < H) grid[y][x] = '*';
  }
  grid[H - 1][W / 2] = 'S';
  Serial.println("+-----------------------------------------+");
  for (int y = 0; y < H; y++) Serial.printf("|%s|\n", grid[y]);
  Serial.println("+-----------------------------------------+");
}

void setup() {
  Serial.begin(115200);
  analogSetPinAttenuation(IR_PIN, ADC_11db);  // the full 0 to 3.1 V range
  servo.setPeriodHertz(50);
  servo.attach(SERVO_PIN, 500, 2400);  // pulse range for SG90-class servos
  servo.write(0);
  delay(500);
  Serial.println("IR sweep ready");
}

int sweep = 0;

void loop() {
  sweep++;
  const bool forward = sweep % 2 == 1;  // sweep back and forth, so the servo never jumps
  float nearest = MAX_CM + 1;
  int nearestAt = -1;
  for (int i = 0; i * STEP_DEG <= 180; i++) {
    const int angle = forward ? i * STEP_DEG : 180 - i * STEP_DEG;
    servo.write(angle);
    delay(SETTLE_MS);
    const float cm = readCm();
    distances[angle / STEP_DEG] = cm;
    Serial.printf("angle = %d, cm = %.1f\n", angle, cm);
    if (cm < nearest) {
      nearest = cm;
      nearestAt = angle;
    }
  }
  drawMap();
  if (nearestAt >= 0 && nearest <= MAX_CM) {
    Serial.printf("sweep = %d, nearest_cm = %.1f, nearest_angle = %d\n", sweep, nearest, nearestAt);
  }
}

Parts

QuantityPartWhere to buy
1×ESP32 dev boardBuy at Amazon
1×Sharp GP2Y0A21YK0F IR distance sensor, 10 to 80 cmBuy at Adafruit
1×Micro servo, SG90 or similarBuy at Adafruit
1×100 µF electrolytic capacitor
6×Jumper wires

Amazon buy links may include an Associates tag, and this site may earn a commission from qualifying Amazon purchases at no extra cost to you. Adafruit links are direct.

Libraries

ESP32Servo

Load it

  1. In the Arduino IDE, install the esp32 board package and pick the board named above the sketch.
  2. Install the libraries listed above from the Library Manager.
  3. Paste the sketch, choose the board's port and upload. Hold BOOT if the upload stalls at Connecting.
  4. Close the IDE's serial monitor, then open the bench here to watch the output.

Field notes

  • Stick the IR sensor on the servo horn with tape or a dab of hot glue so it points the way the horn turns.
  • The Sharp sensor draws its current in short bursts, which makes its output jumpy. The 100 µF capacitor across its power pins smooths that; the sketch also averages eight readings per step.
  • It only measures from about 10 to 80 cm. Closer than 10 cm the reading folds back and looks farther away, so keep the first 10 cm in front of it clear.
  • The cm figure comes from a typical curve for the GP2Y0A21. Check it with a ruler at two or three distances and adjust the 27.86 and -1.15 in readCm() if yours reads high or low.
  • Dark, shiny or very angled surfaces send back less infrared light and may read farther than they are. A sheet of paper makes a good test target.
  • Open the bench at 115200 baud: angle and cm chart live, and each sweep prints a top-down map with the sensor at the bottom.

Not tested yet

  • Not tested on hardware yet. Compiles for every board listed with Arduino-ESP32 core 3.3.12.

Community builds

Loading build reports from people who made this.

Built it? Send a build report with your board and what the serial port printed. Working reports become the "Tested on this board" entries above.