Radar4code

By Paul , 15 September 2025
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <Servo.h>

// TFT Display pins - using easy-to-find digital pins
#define TFT_CS     10  // Chip Select
#define TFT_RST    9   // Reset
#define TFT_DC     8   // Data/Command
#define TFT_MOSI   11  // SDI on your display
#define TFT_CLK    13  // SCK on your display  
#define TFT_MISO   12  // SDO on your display

// Sensor and servo pins
#define TRIG_PIN   4   // Ultrasonic TRIG
#define ECHO_PIN   5   // Ultrasonic ECHO
#define SERVO_PIN  6   // Servo signal

// Display dimensions
#define SCREEN_WIDTH  240
#define SCREEN_HEIGHT 320

// Radar parameters
#define RADAR_CENTER_X 120
#define RADAR_CENTER_Y 280
#define RADAR_RADIUS   100
#define MAX_DISTANCE   200
#define ANGLE_STEP     3

// Colors (16-bit RGB565 format)
#define COLOR_BACKGROUND 0x0020  // Dark green
#define COLOR_GRID      0x0400   // Medium green
#define COLOR_SWEEP     0x07E0   // Bright green
#define COLOR_OBJECT    0xF800   // Red
#define COLOR_TEXT      0x07E0   // Bright green
#define COLOR_TRAIL     0x0200   // Dim green

// Create display using software SPI (easier wiring)
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO);
Servo radarServo;

// Radar variables
int currentAngle = 0;
int direction = 1;
int lastSweepAngle = -1;
unsigned long lastScanTime = 0;
const int scanDelay = 120;  // Milliseconds between scans

// Object storage
struct RadarObject {
  int angle;
  int distance;
  unsigned long timestamp;
  bool active;
};

const int MAX_OBJECTS = 15;
RadarObject objects[MAX_OBJECTS];
int objectCount = 0;

void setup() {
  Serial.begin(9600);
  Serial.println("Starting TFT Radar System...");
  
  // Initialize TFT display
  tft.begin();
  tft.setRotation(0); // Portrait mode
  tft.fillScreen(COLOR_BACKGROUND);
  
  // Initialize sensor pins
  pinMode(TRIG_PIN, OUTPUT);
  pinMode(ECHO_PIN, INPUT);
  
  // Initialize servo
  radarServo.attach(SERVO_PIN);
  radarServo.write(0);
  delay(1000);
  
  // Draw initial radar screen
  drawRadarBase();
  drawTitle();
  
  Serial.println("TFT Radar System Ready!");
}

void loop() {
  unsigned long currentTime = millis();
  
  if (currentTime - lastScanTime >= scanDelay) {
    // Move servo to current angle
    radarServo.write(currentAngle);
    delay(60); // Wait for servo to reach position
    
    // Measure distance
    int distance = measureDistance();
    
    // Clear old sweep line
    if (lastSweepAngle >= 0) {
      drawSweepLine(lastSweepAngle, COLOR_BACKGROUND);
    }
    
    // Add object if detected within range
    if (distance > 5 && distance < MAX_DISTANCE) {
      addObject(currentAngle, distance);
      Serial.print("Object detected at ");
      Serial.print(currentAngle);
      Serial.print("° - ");
      Serial.print(distance);
      Serial.println("cm");
    }
    
    // Redraw radar components
    drawObjects();
    drawSweepLine(currentAngle, COLOR_SWEEP);
    drawSweepTrail(currentAngle);
    updateInfoDisplay(currentAngle, distance);
    
    lastSweepAngle = currentAngle;
    
    // Update angle for next scan
    currentAngle += direction * ANGLE_STEP;
    if (currentAngle >= 180) {
      direction = -1;
      currentAngle = 180;
    } else if (currentAngle <= 0) {
      direction = 1;
      currentAngle = 0;
    }
    
    lastScanTime = currentTime;
  }
  
  // Clean old objects periodically
  cleanOldObjects();
}

void drawRadarBase() {
  // Clear radar area
  tft.fillCircle(RADAR_CENTER_X, RADAR_CENTER_Y, RADAR_RADIUS + 5, COLOR_BACKGROUND);
  
  // Draw concentric circles (distance rings)
  for (int i = 1; i <= 4; i++) {
    int radius = (RADAR_RADIUS * i) / 4;
    drawArc(RADAR_CENTER_X, RADAR_CENTER_Y, radius, 0, 180, COLOR_GRID);
  }
  
  // Draw angle lines every 30 degrees
  for (int angle = 0; angle <= 180; angle += 30) {
    float radian = angle * PI / 180.0;
    int x = RADAR_CENTER_X + cos(radian) * RADAR_RADIUS;
    int y = RADAR_CENTER_Y - sin(radian) * RADAR_RADIUS;
    tft.drawLine(RADAR_CENTER_X, RADAR_CENTER_Y, x, y, COLOR_GRID);
  }
  
  // Draw distance labels
  tft.setTextColor(COLOR_TEXT);
  tft.setTextSize(1);
  
  for (int i = 1; i <= 4; i++) {
    int distance = (MAX_DISTANCE * i) / 4;
    int radius = (RADAR_RADIUS * i) / 4;
    
    tft.setCursor(RADAR_CENTER_X - 15, RADAR_CENTER_Y - radius - 8);
    tft.print(distance);
    tft.print("cm");
  }
  
  // Draw angle labels
  tft.setCursor(RADAR_CENTER_X + RADAR_RADIUS - 15, RADAR_CENTER_Y + 8);
  tft.print("0°");
  
  tft.setCursor(RADAR_CENTER_X - 8, RADAR_CENTER_Y - RADAR_RADIUS + 8);
  tft.print("90°");
  
  tft.setCursor(RADAR_CENTER_X - RADAR_RADIUS + 5, RADAR_CENTER_Y + 8);
  tft.print("180°");
}

void drawArc(int centerX, int centerY, int radius, int startAngle, int endAngle, uint16_t color) {
  // Draw arc by plotting points
  for (int angle = startAngle; angle <= endAngle; angle += 1) {
    float radian = angle * PI / 180.0;
    int x = centerX + cos(radian) * radius;
    int y = centerY - sin(radian) * radius;
    tft.drawPixel(x, y, color);
  }
}

void drawSweepLine(int angle, uint16_t color) {
  float radian = angle * PI / 180.0;
  int x = RADAR_CENTER_X + cos(radian) * RADAR_RADIUS;
  int y = RADAR_CENTER_Y - sin(radian) * RADAR_RADIUS;
  tft.drawLine(RADAR_CENTER_X, RADAR_CENTER_Y, x, y, color);
}

void drawSweepTrail(int currentAngle) {
  // Draw fading trail behind sweep line
  for (int i = 1; i <= 8; i++) {
    int trailAngle = currentAngle - (direction * i * ANGLE_STEP);
    if (trailAngle >= 0 && trailAngle <= 180) {
      uint16_t trailColor;
      if (i <= 4) {
        trailColor = COLOR_TRAIL; // Dim green trail
      } else {
        trailColor = COLOR_BACKGROUND; // Fade to background
      }
      drawSweepLine(trailAngle, trailColor);
    }
  }
}

int measureDistance() {
  // Send ultrasonic pulse
  digitalWrite(TRIG_PIN, LOW);
  delayMicroseconds(2);
  digitalWrite(TRIG_PIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIG_PIN, LOW);
  
  // Read echo pulse duration
  long duration = pulseIn(ECHO_PIN, HIGH, 30000); // 30ms timeout
  
  if (duration == 0) {
    return MAX_DISTANCE; // No echo received
  }
  
  // Calculate distance in centimeters
  int distance = duration * 0.034 / 2;
  
  // Limit to maximum range
  if (distance > MAX_DISTANCE) {
    return MAX_DISTANCE;
  }
  
  return distance;
}

void addObject(int angle, int distance) {
  // Find empty slot or replace oldest object
  int targetIndex = -1;
  unsigned long oldestTime = millis();
  
  for (int i = 0; i < MAX_OBJECTS; i++) {
    if (!objects[i].active) {
      targetIndex = i;
      break;
    }
    if (objects[i].timestamp < oldestTime) {
      oldestTime = objects[i].timestamp;
      targetIndex = i;
    }
  }
  
  if (targetIndex >= 0) {
    objects[targetIndex].angle = angle;
    objects[targetIndex].distance = distance;
    objects[targetIndex].timestamp = millis();
    objects[targetIndex].active = true;
    
    if (objectCount < MAX_OBJECTS) objectCount++;
  }
}

void drawObjects() {
  unsigned long currentTime = millis();
  
  for (int i = 0; i < MAX_OBJECTS; i++) {
    if (objects[i].active) {
      // Calculate object age for fading effect
      unsigned long age = currentTime - objects[i].timestamp;
      
      if (age < 4000) { // Show objects for 4 seconds
        float radian = objects[i].angle * PI / 180.0;
        int scaledDistance = (objects[i].distance * RADAR_RADIUS) / MAX_DISTANCE;
        
        int x = RADAR_CENTER_X + cos(radian) * scaledDistance;
        int y = RADAR_CENTER_Y - sin(radian) * scaledDistance;
        
        // Choose color based on age
        uint16_t color = COLOR_OBJECT;
        if (age > 2500) {
          color = 0x8000; // Dimmer red for older objects
        }
        
        // Draw object as filled circle
        tft.fillCircle(x, y, 2, color);
        
        // Draw small ring around recent objects
        if (age < 1000) {
          tft.drawCircle(x, y, 4, color);
        }
      }
    }
  }
}

void cleanOldObjects() {
  unsigned long currentTime = millis();
  
  for (int i = 0; i < MAX_OBJECTS; i++) {
    if (objects[i].active && (currentTime - objects[i].timestamp > 4000)) {
      // Clear old object from screen
      float radian = objects[i].angle * PI / 180.0;
      int scaledDistance = (objects[i].distance * RADAR_RADIUS) / MAX_DISTANCE;
      
      int x = RADAR_CENTER_X + cos(radian) * scaledDistance;
      int y = RADAR_CENTER_Y - sin(radian) * scaledDistance;
      
      // Clear the object area
      tft.fillCircle(x, y, 6, COLOR_BACKGROUND);
      
      objects[i].active = false;
      if (objectCount > 0) objectCount--;
    }
  }
}

void drawTitle() {
  tft.setTextColor(COLOR_TEXT);
  tft.setTextSize(2);
  tft.setCursor(35, 10);
  tft.print("RADAR SCAN");
  
  tft.setTextSize(1);
  tft.setCursor(90, 35);
  tft.print("SYSTEM");
}

void updateInfoDisplay(int angle, int distance) {
  // Clear info area
  tft.fillRect(5, 50, 230, 110, COLOR_BACKGROUND);
  
  // Draw info box border
  tft.drawRect(5, 50, 230, 110, COLOR_GRID);
  
  tft.setTextColor(COLOR_TEXT);
  tft.setTextSize(1);
  
  // Current readings - top row
  tft.setCursor(10, 60);
  tft.print("Angle: ");
  tft.print(angle);
  tft.print("°");
  
  tft.setCursor(130, 60);
  tft.print("Distance: ");
  tft.print(distance);
  tft.print("cm");
  
  // Status info - second row
  tft.setCursor(10, 80);
  tft.print("Objects: ");
  tft.print(objectCount);
  
  tft.setCursor(130, 80);
  tft.print("Range: ");
  tft.print(MAX_DISTANCE);
  tft.print("cm");
  
  // Scan direction - third row
  tft.setCursor(10, 100);
  tft.print("Direction: ");
  if (direction == 1) {
    tft.print("→ (0 to 180°)");
  } else {
    tft.print("← (180 to 0°)");
  }
  
  // System status - fourth row
  tft.setCursor(10, 120);
  tft.print("Status: SCANNING");
  
  tft.setCursor(130, 120);
  tft.print("Mode: ACTIVE");
  
  // Progress bar
  int barWidth = 200;
  int barHeight = 6;
  int barX = 20;
  int barY = 140;
  
  // Draw progress bar background
  tft.drawRect(barX - 1, barY - 1, barWidth + 2, barHeight + 2, COLOR_GRID);
  tft.fillRect(barX, barY, barWidth, barHeight, COLOR_BACKGROUND);
  
  // Draw current progress
  int progress = (angle * barWidth) / 180;
  tft.fillRect(barX, barY, progress, barHeight, COLOR_SWEEP);
  
  // Progress percentage
  tft.setCursor(10, 155);
  tft.print("Progress: ");
  tft.print((angle * 100) / 180);
  tft.print("%");
}

Comments1

Paul

3 months ago

Pin Connections for TFT Version

ComponentPinArduino Mega PinNotes
TFT Display  ⚠️ IMPORTANT: Use 3.3V, NOT 5V!
VCC 3.3VPower (NEVER 5V!)
GND GNDGround
CS Pin 10Chip Select
RESET Pin 9Reset
DC Pin 8Data/Command
SDI (MOSI) Pin 11Serial Data Input
SCK Pin 13Serial Clock
LED 3.3VBacklight
SDO (MISO) Pin 12Serial Data Output
Ultrasonic Sensor   
VCC 5VPower
GND GNDGround
TRIG Pin 4Trigger
ECHO Pin 5Echo
Servo Motor   
Red (VCC) 5VPower
Brown (GND) GNDGround
Orange (Signal) Pin 6Control Signal