DIY Mini Radar Kit: 1.8″ SPI TFT Display & Ultrasonic Scanning with Arduino Uno R3

Construct a standalone desktop radar scanner that shows nearby obstacles in real time on a colorful 1.8-inch TFT screen! This project uses an Arduino Uno R3 and a Sensor Shield v5.0 to track things up to 100 cm away by putting an HC-SR04 ultrasonic sensor onto a revolving SG90 servo motor.

Watch the full video

For written instructions, continue reading this page, or watch the video guide.

Components Used

  • Microcontroller: Arduino Uno R3 Development Board
  • Expansion Shield: Sensor Shield Version 5.0
  • Sensor: HC-SR04 Ultrasonic Distance Sensor
  • Actuator: SG90 Micro Servo Motor
  • Display: 1.8-inch SPI TFT Display Screen (128×160 resolution, ST7735)
  • Frame & Hardware:

Find the assembly kit in TEMU

Ultrasonic Module Distance Measurement Scanning Detector Kit

Frame & Hardware

  • Laser-cut Acrylic Base, Side, Display, and Sensor Mounting Plates
  • 4x M3 x 40mm Copper Standoffs
  • 8x M3 x 10mm Copper Standoffs
  • 6x M3 x 10mm Screws & 6x M3 Nuts
  • 1x M2 x 12mm Screw & 1x M2 Nut
  • 1x M1.6 x 12mm Screw & 1x M1.6 Nut
  • Servo mounting screws and horn package

Mechanical Assembly Steps

Prepare & Assemble Ultrasonic Sensor Horn

Every acrylic plate should have its protective coating removed. Using the M1.6 nut and M1.6 x 12mm screw, attach the HC-SR04 ultrasonic sensor to the appropriate acrylic plate.

Next, use the screws included in the servo motor package to fasten the servo horn to the rear of this sensor plate assembly.

Mount Servo Motor & Base Standoffs

Use the M2 x 12mm screw and M2 nut to fasten the SG90 servo motor to its acrylic plate.

Thread four M3 x 40mm copper standoffs into the acrylic base plate

Mount the acrylic plate containing the servo motor onto four M3 x 40mm copper standoffs that have been threaded into the acrylic base plate.

Using its central mounting screw, fasten the servo horn—which has the sensor assembly attached—to the servo motor shaft.

Mount Arduino Uno R3 & Sensor Shield

Four M3 x 10mm copper standoffs should be fastened to the base plate.

Place the Arduino Uno R3 board on top of these standoffs and fasten it with four more M3 x 10mm standoffs.

Firmly align all of the pins on the Arduino Uno R3 by pressing the Sensor Shield Version 5.0 onto it.

Enclose Acrylic Frame & TFT Screen

Next to the microcontroller, fasten the left and right acrylic plates with two M3 nuts and two M3 x 10mm screws.

Secure the 1.8-inch SPI TFT display to its mounting plate using four M3 x 10mm screws and four M3 nuts.

Place this assembled screen unit between the two side plates after fastening the 1.8-inch SPI TFT display to its mounting plate with four M3 x 10mm screws and four M3 nuts.

Circuit Wiring & Schematic Description

Using the Sensor Shield v5.0, connect the peripherals to the dedicated headers:

Sensor Shield Version 5.0SG90 Servo Motor1.8″ SPI TFT DisplayHC-SR04 Ultrasonic Sensor
Pin 3Signal Pin
VCCPin (+5V)
GroundGNDGNDGND
Pin 10CS (Chip Select)
Pin 8RESET
Pin 9A0 (Data/Command)
Pin 11SDA (MOSI)
Pin 13SCK (Clock)
LED (Backlight)Connect to one of the Bluetooth line header VCC/3.3V pin
Pin 5Echo
Pin 6Trig
V Pin (+5V)VCC

Ucglib library

High-performance graphics driver for color TFT displays (ST7735 hardware SPI support)

Servo library

Built-in hardware timer control for the SG90 servo motor

SPI library

Built-in communication library for driving the TFT display

Arduino Code

/* mini radar kit */
#include <Servo.h> 
#include <SPI.h>
#include "Ucglib.h"           

#define trigPin   6          // Ultrasonic Module Trig -> D6
#define echoPin   5          // Ultrasonic Module Echo -> D5
#define ServoPin  3          // Servo Signal -> D3

int Ymax = 128;              // Vertical pixels of the screen
int Xmax = 160;              // Horizontal pixels of the screen
int Xcent = Xmax / 2;         // Horizontal screen center position
int base = 118;              // Baseline position
int scanline = 105;          // Radar scan line length

Servo baseServo; 
Ucglib_ST7735_18x128x160_HWSPI ucg(/*cd=*/ 9, /*cs=*/ 10, /*reset=*/ 8);

void setup(void)
{
  ucg.begin(UCG_FONT_MODE_SOLID); // Initialize screen
  ucg.setRotate90();               // Set to horizontal orientation

  pinMode(trigPin, OUTPUT);        // Set Trig Pin mode
  pinMode(echoPin, INPUT);         // Set Echo Pin mode
  Serial.begin(115200);            // Serial communication speed
  baseServo.attach(ServoPin);      // Initialize servo

  // Screen startup interface
  ucg.setFontMode(UCG_FONT_MODE_TRANSPARENT);
  ucg.setColor(0, 0, 100, 0);
  ucg.setColor(1, 0, 100, 0);
  ucg.setColor(2, 20, 20, 20);
  ucg.setColor(3, 20, 20, 20);
  ucg.drawGradientBox(0, 0, 160, 128);
  ucg.setPrintDir(0);
  ucg.setColor(0, 5, 0);
  ucg.setPrintPos(27, 42);
  ucg.setFont(ucg_font_logisoso18_tf);  
  ucg.print("Mini Radar");
  ucg.setColor(0, 255, 0);
  ucg.setPrintPos(25, 40);
  ucg.print("Mini Radar");
  ucg.setFont(ucg_font_helvB08_tf);
  ucg.setColor(0, 255, 0);
  ucg.setPrintPos(40, 100);
  ucg.print("Testing...");
  baseServo.write(90);

  // Test servo movement across 180 degrees
  for(int x = 0; x < 180; x += 5) { 
    baseServo.write(x);
    delay(50);
  }
  ucg.print("OK!");
  delay(500);

  cls(); // Clear screen
  ucg.setFont(ucg_font_orgv01_hr);
  ucg.setFontMode(UCG_FONT_MODE_SOLID);
}

void cls() {
  ucg.setColor(0, 0, 0, 0);
  for(int s = 0; s < 128; s += 8) {
    for(int t = 0; t < 160; t += 16) {
      ucg.drawBox(t, s, 16, 8);
    }
  }
}

int calculateDistance() { 
  long duration;
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  duration = pulseIn(echoPin, HIGH);
  return duration * 0.034 / 2;
}

void fix_font() {
  ucg.setColor(0, 180, 0);
  ucg.setPrintPos(70, 128 - 120 + 7);
  ucg.print("100cm");
  ucg.setPrintPos(70, 128 - 85 - 11);
  ucg.print("75cm");
  ucg.setPrintPos(70, 128 - 60 - 8);
  ucg.print("50cm");
  ucg.setPrintPos(70, 128 - 35 - 4);
  ucg.print("25cm");
}

void fix() {
  ucg.setColor(0, 40, 0);
  ucg.drawDisc(Xcent, base + 1, 3, UCG_DRAW_ALL); 
  ucg.drawCircle(Xcent, base + 1, 115, UCG_DRAW_UPPER_LEFT);
  ucg.drawCircle(Xcent, base + 1, 115, UCG_DRAW_UPPER_RIGHT);
  ucg.drawCircle(Xcent, base + 1, 86, UCG_DRAW_UPPER_LEFT);
  ucg.drawCircle(Xcent, base + 1, 86, UCG_DRAW_UPPER_RIGHT);
  ucg.drawCircle(Xcent, base + 1, 58, UCG_DRAW_UPPER_LEFT);
  ucg.drawCircle(Xcent, base + 1, 58, UCG_DRAW_UPPER_RIGHT);
  ucg.drawCircle(Xcent, base + 1, 29, UCG_DRAW_UPPER_LEFT);
  ucg.drawCircle(Xcent, base + 1, 29, UCG_DRAW_UPPER_RIGHT);
  ucg.drawLine(0, base + 1, Xmax, base + 1);
 
  ucg.setColor(0, 120, 0);
  for(int i = 40; i < 140; i += 2) {
    if (i % 10 == 0) 
      ucg.drawLine(105 * cos(radians(i)) + Xcent, base - 105 * sin(radians(i)), 113 * cos(radians(i)) + Xcent, base - 113 * sin(radians(i)));
    else
      ucg.drawLine(110 * cos(radians(i)) + Xcent, base - 110 * sin(radians(i)), 113 * cos(radians(i)) + Xcent, base - 113 * sin(radians(i)));
  }
    
  ucg.setColor(0, 200, 0);
  ucg.drawLine(0, 0, 0, 18);
  for(int i = 0; i < 5; i++) {
    ucg.setColor(random(255), random(255), random(255));
    ucg.drawBox(2, i * 4, random(14) + 2, 3);
  }

  ucg.setColor(0, 0, 180);
  ucg.drawFrame(146, 0, 14, 14);
  ucg.setColor(0, 0, 60);
  ucg.drawHLine(148, 0, 10);
  ucg.drawVLine(146, 2, 10);
  ucg.drawHLine(148, 13, 10);
  ucg.drawVLine(159, 2, 10);
  
  ucg.setColor(random(255), random(255), random(255));
  ucg.drawBox(148, 2, 4, 4);
  ucg.setColor(0, 220, 0);
  ucg.drawBox(148, 8, 4, 4);
  ucg.setColor(random(255), random(255), random(255));
  ucg.drawBox(154, 8, 4, 4);
  ucg.setColor(random(255), random(255), random(255));
  ucg.drawBox(154, 2, 4, 4);

  ucg.setColor(0, 0, 90);
  ucg.drawTetragon(62, 123, 58, 127, 98, 127, 102, 123);
  ucg.setColor(0, 0, 160);
  ucg.drawTetragon(67, 123, 63, 127, 93, 127, 97, 123);
  ucg.setColor(0, 255, 0);
  ucg.drawTetragon(72, 123, 68, 127, 88, 127, 92, 123);
}

void loop(void) {
  int distance;
  
  fix(); 
  fix_font();

  // Sweep backward (180 -> 4 degrees)
  for (int x = 180; x > 4; x -= 2) {
    baseServo.write(x);
    
    int f = x - 4; 
    ucg.setColor(0, 255, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    f += 2;
    ucg.setColor(0, 128, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    f += 2;
    ucg.setColor(0, 0, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    
    distance = calculateDistance();
   
    if (distance < 100) {
      ucg.setColor(255, 0, 0);
      ucg.drawDisc(1.15 * distance * cos(radians(x)) + Xcent, -(1.15 * distance * sin(radians(x))) + base, 1, UCG_DRAW_ALL);
    } else {
      ucg.setColor(255, 255, 0);
      ucg.drawDisc(116 * cos(radians(x)) + Xcent, -116 * sin(radians(x)) + base, 1, UCG_DRAW_ALL);
    }
          
    Serial.print("Degree:  ");
    Serial.print(x); 
    Serial.print("    ,Distance:   ");
    Serial.println(distance); 

    if (x > 70 && x < 110) fix_font(); 

    ucg.setColor(0, 0, 155, 0);
    ucg.setPrintPos(0, 126);
    ucg.print("DEG: "); 
    ucg.setPrintPos(24, 126);
    ucg.print(x);
    ucg.print("  ");
    ucg.setPrintPos(125, 126);
    ucg.print("  ");
    ucg.print(distance);
    ucg.print("cm  "); 
  }

  delay(50);
  cls();
  fix(); 
  fix_font();

  // Sweep forward (1 -> 176 degrees)
  for (int x = 1; x < 176; x += 2) {
    baseServo.write(x);
    
    int f = x + 4;
    ucg.setColor(0, 255, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    f -= 2;
    ucg.setColor(0, 128, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    f -= 2;
    ucg.setColor(0, 0, 0);
    ucg.drawLine(Xcent, base, scanline * cos(radians(f)) + Xcent, base - scanline * sin(radians(f)));
    
    distance = calculateDistance();

    if (distance < 100) {
      ucg.setColor(255, 0, 0);
      ucg.drawDisc(1.15 * distance * cos(radians(x)) + Xcent, -(1.15 * distance * sin(radians(x))) + base, 1, UCG_DRAW_ALL);
    } else {
      ucg.setColor(255, 255, 0);
      ucg.drawDisc(116 * cos(radians(x)) + Xcent, -116 * sin(radians(x)) + base, 1, UCG_DRAW_ALL);
    }
          
    Serial.print("Degree:  ");
    Serial.print(x); 
    Serial.print("    ,Distance:   ");
    Serial.println(distance); 
   
    if (x > 70 && x < 110) fix_font(); 
    
    ucg.setColor(0, 0, 155, 0);
    ucg.setPrintPos(0, 126);
    ucg.print("DEG: "); 
    ucg.setPrintPos(24, 126);
    ucg.print(x);
    ucg.print("   ");
    ucg.setPrintPos(125, 126);
    ucg.print("   ");
    ucg.print(distance);
    ucg.print("cm   "); 
  }

  delay(50);
  cls();
}

How It Works

The SG90 servo motor is continuously swept back and forth across a 180-degree field of vision by the Arduino Uno R3. At each angle step, the HC-SR04 ultrasonic sensor releases high-frequency sound pulses and counts the reflection time to calculate the exact distance of neighboring obstructions.

The Ucglib graphics driver processes these real-time angle and distance values to plot sweeping green scan lines onto the TFT display. Any object detected within a 100cm range appears as a distinct red dot on the radar grid, while the screen dynamically updates the current angle degree and distance reading along the bottom edge.

Leave a Reply