Robot infrared “eyes”

The self-balancing robot I bought has the same arrangement. They use millis() to send a burst of 38 kHz periodically and use Pin Change Interrupts to detect the received reflections. They count received reflections and look for a majority of sent pulses being received as reflections.

bool left_flag[10] = {false};
unsigned char left_count_flag = 0;
unsigned char left_index = 0;

bool right_flag[10] = {false};
unsigned char right_count_flag = 0;
unsigned char right_index = 0;

unsigned long ir_send_time = 0;
unsigned long left_receive_time = 0;
unsigned char left_receive_flag = 0;
unsigned int left_count = 0;
unsigned long left_count_time = 0;
unsigned long left_test_time = 0;
bool left_test_flag = false;
bool left_is_obstacle = false;

unsigned long right_receive_time = 0;
unsigned char right_receive_flag = 0;
unsigned int right_count = 0;
unsigned long right_count_time = 0;
unsigned long right_test_time = 0;
bool right_test_flag = false;
bool right_is_obstacle = false;

// right_count_flag = number of detected
// reflections in the last 10 samples
void rightFilter(bool value)
{
  if (right_flag[right_index])
    right_count_flag--;
  if (value)
    right_count_flag++;
  right_flag[right_index] = value;
  right_index++;
  if (right_index >= 10)
    right_index = 0;
}

// left_count_flag = number of detected
// reflections in the last 10 samples
void leftFilter(bool value)
{
  if (left_flag[left_index])
    left_count_flag--;
  if (value)
    left_count_flag++;
  left_flag[left_index] = value;
  left_index++;
  if (left_index >= 10)
    left_index = 0;
}

/**
   @brief 发送40个38KHz的脉冲

   @param pin 产生脉冲的引脚
*/
void send38K(int pin)
{
  for (int i = 0; i < 39; i++)
  {
    digitalWrite(pin, LOW);
    delayMicroseconds(9);
    digitalWrite(pin, HIGH);
    delayMicroseconds(9);
  }
}

/**
   @brief 接收引脚中断服务函数

*/
// Detect LOW pulses
void IRReceiveLeftISR()
{
  if (left_receive_flag == 0)
  {
    left_receive_time = micros();
    left_receive_flag = 1;
    attachPinChangeInterrupt(LEFT_RECEIVE_PIN, IRReceiveLeftISR, RISING);
  }
  else if (left_receive_flag == 1)
  {
    left_test_time = micros() - left_receive_time;
    left_count++;
    left_receive_flag = 0;
    attachPinChangeInterrupt(LEFT_RECEIVE_PIN, IRReceiveLeftISR, FALLING);
  }
}

// Detect LOW pulses
void IRReceiveRightISR()
{
  if (right_receive_flag == 0)
  {
    right_receive_time = micros();
    right_receive_flag = 1;
    attachPinChangeInterrupt(RIGHT_RECEIVE_PIN, IRReceiveRightISR, RISING);
  }
  else if (right_receive_flag == 1)
  {
    right_test_time = micros() - right_receive_time;
    right_count++;
    right_receive_flag = 0;
    attachPinChangeInterrupt(RIGHT_RECEIVE_PIN, IRReceiveRightISR, FALLING);
  }
}

void IRInit()
{
  pinMode(IR_SEND_PIN, OUTPUT);
  pinMode(LEFT_RECEIVE_PIN, INPUT_PULLUP);
  pinMode(RIGHT_RECEIVE_PIN, INPUT_PULLUP);
  attachPinChangeInterrupt(LEFT_RECEIVE_PIN, IRReceiveLeftISR, FALLING);
  attachPinChangeInterrupt(RIGHT_RECEIVE_PIN, IRReceiveRightISR, FALLING);
}

// Call frequently
void checkObstacle()
{
  // Every 15 milliseconds, send a pulse of modulated IR
  if (millis() - ir_send_time > 15)
  {
    send38K(IR_SEND_PIN);
    ir_send_time = millis();
  }

  // Every 50 milliseconds, check the detected Left reflections.
  if (millis() - left_count_time > 50)
  {
    // Record the last 10 samples
    leftFilter(left_count >= 3);

    // If 50% or more of the last 10 intervals received reflections

    left_is_obstacle = left_count_flag >= 5;

    // Serial.println();
    left_count = 0;
    left_count_time = millis();
  }

  // Every 50 milliseconds, check the detected Right reflections.
  if (millis() - right_count_time > 50)
  {
    // Record the last 10 samples
    rightFilter(right_count >= 3);

    // If 50% or more of the last 10 intervals received reflections

    right_is_obstacle = left_count_flag >= 5;

    // Serial.println();
    right_count = 0;
    right_count_time = millis();
  }
}