Robot infrared “eyes”

Hello,
First of all, I am new here, so feel free to blame all my mistakes and to ask additional questions.
Recently my friend lent me an atmega8 based driving robot. It has line sensors, motors, some switches, and (most important now) IR diodes and receivers V4836.


It came to me with program to follow hand, and it used this sensors. Sadly though, my friend soldered these robots on some soldering course, so the program was less important. Connection of sensors with atmega looks like that:
Both IR diodes are connected to PB3 (pin 11)
Right ir sensor is connected to PB4 (pin 12)
Left IR sensor is connected to PC5 (pin 19)
The question is: Is there a way to send signal via ir leds and detecting it by receivers?
All answers would be appreciated.
Mikolaj

EDIT

I forgo to mension, that i am using internal clock.

Yes. Have you seen a TV remote?

Please check the introductory messages at the top of the forum. It is suggested that rather than wait for a game of 100 questions about your project, that you provide all the important details in advance, so people don't waste time pulling the information from you.

Yes, I was sending ir codes, but as far as I know, irremote library uses pin 9 on atmega8, but here I have 11. And I need to send and receive in the same time.

You can not do that with the irremote library.

If you know the specs of your IR xmitter/rcvr then share them. Stuff like what's the wave length the LED's operate at. Let's say your LEDS's operate at near IR, you may get away with using another set of IR's that are IR.

Once you figure out the use of two IR's of differing wavelengths, you will now need to tackle the issue of:

You'll need a MCU with multiple cores. That way you can receive, one core, and send, another core, at the same time.

If you choose a ESP32 you'll need to know how to use freeRTOS.

If you do not really need them to run at the same time, you can try using millis() and the doing multiple things at the same time thing; use the search to find it. There you can get time slicing like operations. If you want to take it a bit further you can look up State Machine.

The problem is, that robot came with working code, so spmebody somehow did this. I have compiled hex, but it is useless. And robot is on the custom pcb, so I can’t change anything.

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();
  }
}

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();

}
}

what microcontroller is this written for? For atmega8 i have an error 'attachPinChangeInterrupt' was not declared in this scope

It runs on an Arduino UNO and should run on any AVR processor. You have to install and include the PinChangeInterrupt library.

sady with this library I got lots of errors

 #error PinChangeInterrupt library does not support this MCU.
  ^~~~~
 #error Please enable at least one PCINT port and pin!
  ^~~~~
 #error MCU has no such a register
  ^~~~~

The ATmega8 does not support pin change interrupts. You'll need a later version of the processor for that (ATmega168 or 328). The DIP packages are plug-in compatible.

But this was made using current hardware, and I would like to leave it unchanged.

Then you can't use pin change interrupts. Only INT0 and INT1 are available as external interrupts on the ATmega8.

Instead of this:

attachPinChangeInterrupt(LEFT_RECEIVE_PIN, IRReceiveLeftISR, FALLING);
attachPinChangeInterrupt(RIGHT_RECEIVE_PIN, IRReceiveRightISR, FALLING);

Use attachInterrupt() and make sure the IR sensors are correctly wired to the INT0 and INT1 pins. Other changes to the code and wiring may be necessary.

but the problem is, that this robot is made using custom pcb, so I have no way to change wiring.

Have you looked for the original firmware sources? The maker of the kit might provide the sources online. If you don't know who made the kit and it is not printed anywhere on the circuit board, you might find it still available for sale somewhere on AliExpress.com or Amazon or eBay.

I've tried, but the creators site no longer exists :frowning:

You can always cut PCB traces (e.g. with a razor blade) and solder in wires to make alternative connections. People do that all the time.

Check the Wayback Machine.

I would love to be aware of doing that, because this robot belongs to my friend, and I don't want to modify it in any way.