Arduino Infrared Radar

In this small project I would like to show you how can you create a simple Radar at Home with Arduino. There are many similar projects on the internet, but they are all using an ultrasonic sensor to measure the distance. In this project I use an infrared sensor for distance measurement.

My goal is to create a very simple and cheap LIDAR system with it and implement a mapping device.

You will need the following materials:

  • Arduino (I used a Maple Mini)
  • Sharp distance sensor (I used Sharp GP2Y0A02YK0F)
  • Micro Servo (9g)
  • Breadboard, wires
  • Optional: 4.7k Resistor, 100nF Capacitor

Ultrasonic VS Infrared Sensor

The main difference between ultrasonic and infrared distance sensors is that the ultrasonic sensor measures distance in wider range. Therefore it is not able to precisely locate the position of an obstacle. It means that it measures the distance of the closest object which is located inside a ~ +-30° angle range.

Of course, it doesn’t mean that the Sharp sensor is better. Sometimes this property can be very useful (e.g. used by drones to measure height from ground). The right choice is totally depending on the requirements of your project.

Schematic

It is very simple to make the connection between parts. Select a PWM Output and an Analog Input on your Arduino board and connect the Servo and Sharp distance sensors to those pins. I used the following pins for this purpose:

  • PA0: Analog input for Sharp distance sensor
  • PA9: PWM Output for Servo

Sometimes the Sharp IR Sensor can have noisy output, therefore you have to put a simple Low Pass Filter on it. I used a 4.7k resistor and a 100nF capacitor to reduce the noise on the analog pin. Besides that I also filtered the measured value in the code by reading it multiple times and calculating the average.

Sensor Characteristic

Unfortunately the used infrared distance sensor has non-linear characteristic. It means that to get the distance, it is not enough to multiply the measured ADC value with a constant value and adding another constant value to it.

Although the datasheet of the sensor provides the characteristic, I prefer to measure it by myself in the specific project (it could depend on the used voltage). For this, I made pairs from the measured ADC Value and distance for every 10 cm. (My sensor was able to measure correct distance from 12 cm).

I used these pairs in the code to get the correct distance with Linear Interpolation.

// Structure to store ADC Value - Distance pairs
typedef struct {
  float distance;
  float adcVal;
} S_DIST_ADC_MAP;

// ADC Value - Distance pairs
// Fill it measured SHARP Sensor characteristic values.
S_DIST_ADC_MAP distAdcMap[] = {
  {12,  3599},
  {20,  3122},
  {30,  2295},
  {40,  1733},
  ...
};

// Function to get distance [cm] from measured ADC Value
float getDistance(float adcVal)
{
  float distance = DISTANCE_MAX;

  // Linear interpolation from measured ADC value and MAP.
  for (int i = 1; i < (sizeof(distAdcMap)/sizeof(S_DIST_ADC_MAP)); i++)
  {
    if (adcVal > distAdcMap[i].adcVal)
    {
      float factor = (adcVal - distAdcMap[i].adcVal)/(distAdcMap[i-1].adcVal - distAdcMap[i].adcVal);
      distance = factor * (distAdcMap[i-1].distance - distAdcMap[i].distance) + distAdcMap[i].distance;
      break;
    }
  }

  return distance;
}

You will find a simple Arduino code at the end of document, to measure ADC Value during characteristic measurement.

Serial Communication

I used serial communication to send the measured angle-distance values to the PC. Since I have to send multiple bytes and different type of messages, I designed a simple communication protocol.

FieldSizeOffsetDescription
Sync20Indicates start of message. 0x55AA.
Checksum12Data validation. Start from 0x55.
CMD13Command identifier
Data0…MAX4Payload

This procotol makes able to define different message types in a generic way. In this project I used 2 message types:

  • Parameters: Used to send parameters to PC Application, defined on Arduino like maximum distance and number of obstacles in a round.
  • Obstacle: Used to send a detected obstacle. It is identified by angle of the servo and measured distance. The x-y position will be calculated by PC application.

Qt Application

To communicate with Arduino and draw the measured points like a radar I made a PC Application in Qt (C++). It receives some parameters (defined on Arduino) and the measured distance points.

Download Application

Download Source

Arduino Source Code

Characteristic Measurement

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  float adcVal;
  
  // Read sharp sensor analog value and use a simple filter on it
  adcVal = 0.0f;
  for (int i = 0; i < 50; i++)
  {
    adcVal += analogRead(PA0);
    delay(10);
  }
  adcVal /= 50.0f;

  // Print ADC Value
  Serial.println(adcVal);
}

Radar

You can customize some paremeters at the top of the document with macros.

Note, that if you change the characteristic of the Sharp distance sensor, you have to modify distAdcMap[] array values!

#include <Servo.h>

// ------------------------------------------------------------
// User parameters
// ------------------------------------------------------------
// Define pin where Sharp sensor is located.
#define SHARP_PIN       PA0
// Define pin where servo is located.
#define SERVO_PIN       PA9
// Define the maximum distance you want to measure in [cm].
#define DISTANCE_MAX    150
// Define the angle value that servo will step between measurements.
#define SERVO_STEP      2
// Define the delay in [ms] between measurements.
#define MEAS_DELAY_MS   30


// ------------------------------------------------------------
// Message handling
// ------------------------------------------------------------
// Sync value in message header
#define MSG_SYNC                (0x55AA)
// Start of checksum calculation in message header
#define MSG_CHECKSUM_START      (0x55)
// Maximum size of a message
#define MSG_MAX_SIZE            (64)

// Header of message structure
typedef struct
{
    uint16_t sync;
    uint8_t checkSum;
    uint8_t cmd;
} S_MSG_HEADER;

// Message: Parameters
typedef struct
{
    uint16_t distanceMax;
    uint16_t sampleNum;
} S_MESSAGE_PARAMETERS;

// Message: Obstacle
typedef struct
{
    uint16_t angle;
    uint16_t distance;
} S_MESSAGE_OBSTACLE;

// Message identifiers
typedef enum
{
    eMESSAGE_PARAMETERS,
    eMESSAGE_OBSTACLE,
} E_MESSAGE_CMD;

// Function to send a message to PC Application
void sendMessage(uint8_t cmd, void* data)
{
  // Structure for message to send
  static struct
  {
    S_MSG_HEADER header;
    uint8_t data[MSG_MAX_SIZE];
  } sendData;
  uint8_t msgSize;

  // Get size of data based on command
  switch (cmd)
  {
    case eMESSAGE_PARAMETERS:
      msgSize = sizeof(S_MESSAGE_PARAMETERS);
      break;
    case eMESSAGE_OBSTACLE:
      msgSize = sizeof(S_MESSAGE_OBSTACLE);
      break;
  }

  // Fill header of message
  sendData.header.cmd = cmd;
  sendData.header.sync = MSG_SYNC;
  sendData.header.checkSum = MSG_CHECKSUM_START;
  
  // Fill data bytes
  for (uint8_t i = 0; i < msgSize; i++)
  {
    sendData.data[i] = ((uint8_t*)(data))[i];
    sendData.header.checkSum += sendData.data[i];
  }
  
  // Send composed message to PC
  Serial.write((uint8_t*)&sendData, sizeof(S_MSG_HEADER) + msgSize);
}

// ------------------------------------------------------------
// Distance calculation
// ------------------------------------------------------------
// Structure to store ADC Value - Distance pairs
typedef struct {
  float distance;
  float adcVal;
} S_DIST_ADC_MAP;

// TODO
// ADC Value - Distance pairs
// Fill it measured SHARP Sensor characteristic values.
S_DIST_ADC_MAP distAdcMap[] = {
  {12,  3599},
  {20,  3122},
  {30,  2295},
  {40,  1733},
  {50,  1381},
  {60,  1191},
  {70,  1000},
  {80,  855},
  {90,  751},
  {100, 662},
  {110, 606},
  {120, 559},
  {130, 517},
  {140, 465},
  {150, 418},
};

// Function to get distance [cm] from measured ADC Value
float getDistance(float adcVal)
{
  float distance = DISTANCE_MAX;

  // Linear interpolation from measured ADC value and MAP.
  for (int i = 1; i < (sizeof(distAdcMap)/sizeof(S_DIST_ADC_MAP)); i++)
  {
    if (adcVal > distAdcMap[i].adcVal)
    {
      float factor = (adcVal - distAdcMap[i].adcVal)/(distAdcMap[i-1].adcVal - distAdcMap[i].adcVal);
      distance = factor * (distAdcMap[i-1].distance - distAdcMap[i].distance) + distAdcMap[i].distance;
      break;
    }
  }

  return distance;
}

// ------------------------------------------------------------
// Application
// ------------------------------------------------------------
// Global variables
Servo myServo;
int servoVal = 0;
int servoDir = SERVO_STEP;
S_MESSAGE_OBSTACLE msgObstacle;
S_MESSAGE_PARAMETERS msgParameters;

void setup()
{
  Serial.begin(115200);
  myServo.attach(SERVO_PIN);
  myServo.write(servoVal);

  msgParameters.distanceMax = DISTANCE_MAX;
  msgParameters.sampleNum = (180/SERVO_STEP);
}

void loop()
{
  float adcVal;
  float distance;

  // Send parameters at start
  if (servoVal == 0)
    sendMessage(eMESSAGE_PARAMETERS, &msgParameters);

  // Read sharp sensor analog value and use a simple filter on it.
  adcVal = 0.0f;
  for (int i = 0; i < 10; i++)
    adcVal += analogRead(SHARP_PIN);
  adcVal /= 10.0f;
  distance = getDistance(adcVal);

  // Compose send data structure from measured values
  msgObstacle.angle    = servoVal;
  msgObstacle.distance = (uint16_t)distance;
  sendMessage(eMESSAGE_OBSTACLE, &msgObstacle);

  // Set servo to next position
  if (servoVal >= 180)
    servoDir = -SERVO_STEP;
  else if (servoVal <= 0)
    servoDir = +SERVO_STEP;
    
  servoVal += servoDir;
  myServo.write(servoVal);

  // Wait until new measurement
  delay(MEAS_DELAY_MS);
}

Vélemény, hozzászólás?

Adatok megadása vagy bejelentkezés valamelyik ikonnal:

WordPress.com Logo

Hozzászólhat a WordPress.com felhasználói fiók használatával. Kilépés /  Módosítás )

Google kép

Hozzászólhat a Google felhasználói fiók használatával. Kilépés /  Módosítás )

Twitter kép

Hozzászólhat a Twitter felhasználói fiók használatával. Kilépés /  Módosítás )

Facebook kép

Hozzászólhat a Facebook felhasználói fiók használatával. Kilépés /  Módosítás )

Kapcsolódás: %s

Üzemelteti a WordPress.com. , Anders Noren fejlesztésében.

Fel ↑

Create your website at WordPress.com
Kezdjük el
%d blogger ezt szereti: