Chapter 6 Infrared Car

6.1 Introduction of infrared reception function

Infrared Remote

An infrared(IR) remote control is a device with a certain number of buttons. Pressing down different buttons will make the infrared emission tube, which is located in the front of the remote control, send infrared ray with

different command. Infrared remote control technology is widely used in electronic products such as TV, air conditioning, etc. Thus making it possible for you to switch TV programs and adjust the temperature of the air conditioning when away from them. The remote control we use is shown below:

../../../_images/Chapter06_00.png

Infrared receiver

An infrared(IR) receiver is a component which can receive the infrared light, so we can use it to detect the signal emitted by the infrared remote control. DATA pin here outputs the received infrared signal.

When you use the infrared remote control, the infrared remote control sends a key value to the receiving circuit according to the pressed keys. We can program the Raspberry Pi Pico W to do things like lighting, when a key value is received.

The following is the key value that the receiving circuit will receive when each key of the infrared remote control is pressed.

ICON

KEY Value

ICON

KEY Value

Chapter06_01

BA45FF00

Chapter06_11

F20DFF00

Chapter06_02

B847FF00

Chapter06_12

F30CFF00

Chapter06_03

BB44FF00

Chapter06_13

E718FF00

Chapter06_04

BF40FF00

Chapter06_14

A15EFF00

Chapter06_05

BC43FF00

Chapter06_15

F708FF00

Chapter06_06

F807FF00

Chapter06_16

E31CFF00

Chapter06_07

EA15FF00

Chapter06_17

A55AFF00

Chapter06_08

F609FF00

Chapter06_18

BD42FF00

Chapter06_09

E916FF00

Chapter06_19

AD52FF00

Chapter06_10

E619FF00

Chapter06_20

B54AFF00

This sketch uses the infrared receiving tube to receive the value sent form the infrared remote control, and print it out via the serial port.

Sketch

Each time when you press the infrared remote control, the car will print the received infrared coding value through serial port.

Open the folder “05.1_IR_Receiver”in

“Freenove_4WD_Car_Kit_for_Raspberry_Pi_Pico\Ordinary_wheels\Sketches” and double click

“05.1_IR_Receiver.ino”.

Code

 1/**********************************************************************
 2  Filename    : Infrared Remote Control
 3  Description : Decode the infrared remote control and print it out through the serial port.
 4  Auther      : www.freenove.com
 5  Modification: 2023/04/13
 6**********************************************************************/
 7#include <IRremote.hpp>
 8#define IR_Pin 3  // Infrared receiving pin
 9#define ENABLE_LED_FEEDBACK true
10#define DISABLE_LED_FEEDBACK false
11void setup() {
12  Serial.begin(115200);                           // Initialize the serial port and set the baud rate to 115200
13  IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK);  // Start the receiver
14  Serial.print("IRrecvDemo is now running and waiting for IR message on Pin ");
15  Serial.println(IR_Pin);  //print the infrared receiving pin
16}
17
18void loop() {
19  if (IrReceiver.decode()) {
20    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
21    Serial.println(value, HEX);  // Print "old" raw data
22    IrReceiver.resume();    // Enable receiving of the next value
23  }
24}

Download the code to Raspberry Pi Pico (W), open the serial port monitor, set the baud rate to 115200, press the IR remote control, the pressed keys value will be printed out through the serial port. As shown in the following figure: (Note that if the remote control button is long pressed, the infrared receiving circuit receives a “0”.)

../../../_images/Chapter06_21.png

First, include header file. Each time you use the infrared sensor, you need to include the header file at the beginning of the program.

1#include <IRremote.hpp>

Second, define an infrared receive pin and the infrared sensor is initialized.

1#define IR_Pin 3                      // Infrared receiving pin
2...
3IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK);  // Start the receiver

Finally, IrReceiver.decode() is used to determine whether an infrared signal has been received, returning true/1 if an infrared signal has been received, or false/0 if no infrared signal has been received; If an infrared signal is received, the received infrared coded value is printed through the serial port.

Please note that IrReceiver.resume() must be applied to release the infrared receiver function each time data are received. Otherwise, the infrared receiver function can only be used once and data cannot be received next time.

1if (IrReceiver.decode()) {
2    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
3    Serial.println(value, HEX);  // Print "old" raw data
4    IrReceiver.resume();    // Enable receiving of the next value
5}

6.2 Infrared Car

Based on the previous section, we use the infrared remote control to control the car. Press the black button on the infrared remote control to control the car to move forward, backward, turn left, and turn right. Press other buttons and the cart stops moving.

Sketch

Open the folder “05.2_IR_Receiver_Car” in the “Freenove_4WD_Car_Kit_for_Raspberry_Pi_Pico\Ordinary_wheels\Sketches” and double click “05.2_IR_Receiver_Car.ino”.

Code

 1/**********************************************************************
 2  Filename    : IR_Receiver_Car.ino
 3  Product     : Freenove 4WD Car for Raspberry Pi Pico (W)
 4  Auther      : www.freenove.com
 5  Modification: 2023/04/13
 6**********************************************************************/
 7#include <Arduino.h>
 8#include <IRremote.hpp>
 9#include "Freenove_4WD_Car_For_Pico_W.h"
10#define IR_Pin 3
11#define ENABLE_LED_FEEDBACK true
12#define DISABLE_LED_FEEDBACK false
13int motor_speed = 50;
14int emotionMode = 4;
15int motor_flag = 0;
16
17void setup() {
18  Serial.begin(115200);
19  Motor_Setup();                                  //Motor initialization
20  Emotion_Setup();                                //Initializes Emotion module
21  IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK);  // Start the receiver
22}
23
24void loop() {
25  if (IrReceiver.decode()) {
26    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
27    handleControl(value);        // Handle the commands from remote control
28    Serial.println(value, HEX);  // Print "old" raw data
29    Serial.println();
30    IrReceiver.resume();  // Enable receiving of the next value
31  }
32  showEmotion(emotionMode);
33}
34
35void handleControl(unsigned long value) {
36  // Handle the commands
37  switch (value) {
38    case 0xBF40FF00:  // Receive the number '+'
39      motor_flag = 1;
40      Motor_Move(motor_speed , motor_speed);  // Go forward
41      delay(200);
42      Motor_Move(0 , 0);
43      break;
44
45    case 0xE619FF00:  // Receive the number '-'
46      motor_flag = 2;
47      Motor_Move(-motor_speed , -motor_speed);  // Back up
48      delay(200);
49      Motor_Move(0 , 0);
50      break;
51
52    case 0xF807FF00:  // Receive the number '|<<'
53      motor_flag = 3;
54      Motor_Move(-motor_speed , motor_speed);  // Turn left
55      delay(200);
56      Motor_Move(0 , 0);
57      break;
58
59    case 0xF609FF00:  // Receive the number '>>|'
60      motor_flag = 4;
61      Motor_Move(motor_speed , -motor_speed);  // Turn right
62      delay(200);
63      Motor_Move(0 , 0);
64      break;
65
66    case 0xE916FF00:  // Receive the number '0'
67      emotionMode = millis() % 10;
68      break;
69
70    default:
71      motor_flag = 0;
72      Motor_Move(0 , 0);  //stop
73      break;
74  }
75}

Compile and upload the code to Raspberry Pi Pico (W). When pressing “0” of the infrared remote control, the expression module will randomly display the content dynamically.

Chapter06_22

Chapter06_26

Move forward

Chapter06_23

Chapter06_27

Turn left

Chapter06_24

Chapter06_28

Turn right

Chapter06_25

Chapter06_29

Move back

Code Explanation

Variable IrReceiver.DecodedIRData.DecodedRawData holds the infrared remote control encoding information, call handleccontrol function performs different code value corresponding action. After each execution of the program, call the IrReceiver.resume() function to release the infrared pin. If you do not call this function, you cannot use the infrared receiving and decoding functions again.

 1void loop() {
 2  if (IrReceiver.decode()) {
 3    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
 4    handleControl(value);        // Handle the commands from remote control
 5    Serial.println(value, HEX);  // Print "old" raw data
 6    Serial.println();
 7    IrReceiver.resume();  // Enable receiving of the next value
 8  }
 9  showEmotion(emotionMode);
10}

Infrared key code value processing function, receives instructions sent by the infrared remote control, and execute the corresponding program.

 1void handleControl(unsigned long value) {
 2    // Handle the commands
 3    switch (value) {
 4        case 0xBF40FF00:  // Receive the number '+'
 5        ...
 6        case 0xE619FF00:  // Receive the number '-'
 7        ...
 8        case 0xF807FF00:  // Receive the number '|<<'
 9        ...
10        case 0xF609FF00:  // Receive the number '>>|'
11        ...
12        case 0xE916FF00:  // Receive the number '0'
13        ...
14        default:        // Control the car to stop moving
15        ...
16    }
17}

6.3 Multi-Functional Infrared Car

Following the previous section, we now integrate other functions into the infrared car, and most of the car’s functions can be controlled by the infrared remote.

Sketch

Open the folder “05.3_Multi_Functional_Car” in the “Freenove_4WD_Car_Kit_for_Raspberry_Pi_Pico\Ordinary_wheels\Sketches” and double click “05.3_Multi_Functional_Car.ino”.

Code

  1/**********************************************************************
  2  Filename    : IR_Receiver_Car.ino
  3  Product     : Freenove 4WD Car for Raspberry Pi Pico (W)
  4  Auther      : www.freenove.com
  5  Modification: 2023/04/13
  6**********************************************************************/
  7#include <Arduino.h>
  8#include <Adafruit_NeoPixel.h>
  9#include <IRremote.hpp>
 10#include "Freenove_4WD_Car_For_Pico_W.h"
 11#include "Freenove_4WD_Car_Emotion.h"
 12#include "Freenove_VK16K33_Lib.h"
 13#include "Freenove_4WD_Car_WS2812.h"
 14
 15#define IR_Pin 3  // Infrared receiving pin
 16#define ENABLE_LED_FEEDBACK          true
 17#define DISABLE_LED_FEEDBACK         false
 18
 19static int servo_1_angle = 90;
 20int emotion_flag = 0;
 21int ws2812_flag = 0;
 22
 23int CAR_MODE_VOL = 0;
 24int LASt_CAR_MODE_VOL = 0;
 25
 26void setup() {
 27  Serial.begin(115200);  //Turn on the serial port monitor and set the baud rate to 115200
 28  Motor_Setup();         //Initialize motor
 29  Servo_Setup();         //Initialize servo
 30  Buzzer_Setup();        //Initialize the buzzer  
 31  WS2812_Setup();        //WS2812 initialization
 32  Emotion_and_Ultrasonic_Setup();
 33  IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK); // Start the receiver
 34  Servo_1_Angle(servo_1_angle);
 35  delay(100);
 36}
 37
 38void loop() {
 39  if (IrReceiver.decode()) {
 40      unsigned long value=IrReceiver.decodedIRData.decodedRawData;
 41      handleControl(value);  // Handle the commands from remote control
 42      Serial.println(value, HEX); // Print "old" raw data
 43      Serial.println();
 44      IrReceiver.resume();  // Enable receiving of the next value
 45  }
 46  Emotion_and_Ultrasonic_Setup();
 47  oa_CalculateVoltageCompensation();
 48  if (Check_Module_value == MATRIX_IS_EXIST) {
 49    Emotion_Show(emotion_task_mode); //Led matrix display function
 50  } else if (Check_Module_value == SONAR_IS_ESIST) {
 51  }
 52  Car_Select(carFlag);
 53  WS2812_Show(ws2812_task_mode);    //Car color lights display function
 54}
 55
 56void handleControl(unsigned long value) {
 57  // Handle the commands
 58  switch (value) {
 59    case 0xBF40FF00:  // Receive the number '+'
 60      Motor_Move(50, 50);
 61      delay(300);
 62      Motor_Move(0, 0);
 63      break;
 64    case 0xE619FF00:  // Receive the number '-'
 65      Motor_Move(-50, -50);
 66      delay(300);
 67      Motor_Move(0, 0);
 68      break;
 69    case 0xF807FF00:  // Receive the number '|<<'
 70      Motor_Move(-50, 50);
 71      delay(300);
 72      Motor_Move(0, 0);
 73      break;
 74    case 0xF609FF00:  // Receive the number '>>|'
 75      Motor_Move(50, -50);
 76      delay(300);
 77      Motor_Move(0, 0);
 78      break;
 79    case 0xEA15FF00:  // Receive the number '▶'
 80      Motor_Move(0, 0);
 81      break;
 82    case 0xE916FF00:  // Receive the number '0'
 83      servo_1_angle = servo_1_angle + 10;
 84      Servo_1_Angle(servo_1_angle);
 85      break;
 86    case 0xF30CFF00:  // Receive the number '1'
 87      servo_1_angle = servo_1_angle - 10;      
 88      Servo_1_Angle(servo_1_angle);
 89      break;
 90    case 0xF708FF00:  // Receive the number '4'
 91      servo_1_angle = 90;
 92      Servo_1_Angle(servo_1_angle);
 93      break;
 94    case 0xF20DFF00:  // Receive the number 'C'
 95      isLightModeFirstStarting = true; 
 96      Servo_1_Angle(90);
 97      Car_SetMode(1);
 98      break;
 99    case 0xA15EFF00:  // Receive the number '3'
100      Servo_1_Angle(90);
101      Car_SetMode(2);
102      break;
103    case 0xA55AFF00:  // Receive the number '6'
104      Servo_1_Angle(90);
105      if (Check_Module_value == SONAR_IS_ESIST) {
106        LASt_CAR_MODE_VOL = 1;
107        Car_SetMode(3);
108      }
109      if (Check_Module_value != SONAR_IS_ESIST) {
110        Buzzer_Variable(2000, 50, 2);
111        Car_SetMode(0);
112        Motor_Move(0, 0);
113      }
114      break;
115    case 0xB54AFF00:  // Receive the number '9'
116      emotion_flag = 0;
117      Emotion_SetMode(emotion_flag);    
118      Servo_1_Angle(90);
119      Car_SetMode(0);
120      Motor_Move(0, 0);
121      break;
122    case 0xBB44FF00:  // Receive the number 'TEST'
123      Buzzer_Variable(2000, 100, 1);
124      break;
125    case 0xE718FF00:  // Receive the number '2'
126      if (Check_Module_value == MATRIX_IS_EXIST) {
127        emotion_flag = emotion_flag + 1;
128        if (emotion_flag > 7) {
129          emotion_flag = 0;
130        }
131        Emotion_SetMode(emotion_flag);  //Display
132        Serial.print(" \n matrix is exist !!! \n");
133      }
134      if (Check_Module_value != MATRIX_IS_EXIST) {
135        Buzzer_Variable(2000, 50, 2);
136        Serial.print(" \n sonar is exist !!! \n");
137      }
138      break;
139    case 0xE31CFF00:  // Receive the number '5'
140      emotion_flag = 0;
141      Emotion_SetMode(emotion_flag);
142      break;
143    case 0xBD42FF00:  // Receive the number '7'
144      ws2812_flag = ws2812_flag + 1;
145      if (ws2812_flag >= 6) {
146        ws2812_flag = 0;
147      }
148      WS2812_SetMode(ws2812_flag);
149      break;
150    case 0xAD52FF00:  // Receive the number '8'
151      ws2812_flag = 0;
152      WS2812_SetMode(ws2812_flag);
153      break;
154    case 0xFFFFFFFF:  // Remain unchanged
155      break;
156    default:
157      break;
158  }
159}

After the code is successfully uploaded, turn on the power of the car and use the infrared remote to control the car and other functions. The corresponding keys and their functions are shown in the following table:

../../../_images/Chapter06_00.png

ICON

KEY Value

Function

ICON

KEY Value

Function

Chapter06_04

BF40FF00

Move forward

Chapter06_13

E718FF00

Change the expression display mode

Chapter06_06

F807FF00

Turn left

Chapter06_16

E31CFF00

Turn off emoticons

Chapter06_08

F609FF00

Turn light

Chapter06_18

BD42FF00

Change the display mode of the WS2812

Chapter06_10

E619FF00

Move back

Chapter06_19

AD52FF00

Turn off WS2812 display

Chapter06_07

EA15FF00

Stop the car

Chapter06_11

F20DFF00

Light tracing car mode

Chapter06_09

E916FF00

Control servo turn left

Chapter06_14

A15EFF00

Line tracking car mode

Chapter06_12

F30CFF00

Control servo turn right

Chapter06_17

A55AFF00

Ultrasonic obstacle avoidance car mode

Chapter06_15

F708FF00

Control servo turn to 90°

Chapter06_20

B54AFF00

Manual control mode

Chapter06_03

BB44FF00

Control the buzzer

Since the ultrasonic module shares the interface with the LED Matrix, only one of them can be used at the same time. When the function of the sent button conflicts with the current head module, the buzzer will sound twice continuously. The situations can be as follows:

When “6” is pressed, if the LED Matrix is connected to the head, the buzzer will sound twice.

When “2” is pressed, if the head is connected to an ultrasonic module, the buzzer will sound twice.

When you hear the buzzer beep twice, please replace the module on the head to continue the experiment.

Code Explanation

Add the header file for the car.

1#include <Arduino.h>
2#include <Adafruit_NeoPixel.h>
3#include <IRremote.hpp>
4#include "Freenove_4WD_Car_For_Pico_W.h"
5#include "Freenove_4WD_Car_Emotion.h"
6#include "Freenove_VK16K33_Lib.h"
7#include "Freenove_4WD_Car_WS2812.h"

Initialize each function of the car.

1Serial.begin(115200);  //Turn on the serial port monitor and set the baud rate to 115200
2Motor_Setup();         //Initialize motor
3Servo_Setup();         //Initialize servo
4Buzzer_Setup();        //Initialize the buzzer  
5WS2812_Setup();        //WS2812 initialization
6Emotion_and_Ultrasonic_Setup();
7IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK); // Start the receiver
8Servo_1_Angle(servo_1_angle);
9delay(100);

Infrared key code value processing function receives instructions sent by the infrared remote control and execute the corresponding program.

 1void handleControl(unsigned long value) {
 2    // Handle the commands
 3    switch (value) {
 4        case 0xBF40FF00:  // Receive the number '+'
 5        ...
 6        case 0xE619FF00:  // Receive the number '-'
 7        ...
 8        case 0xF807FF00:  // Receive the number '|<<'
 9        ...
10        case 0xF609FF00:  // Receive the number '>>|'
11        ...
12        case 0xEA15FF00:  // Receive the number '▶'
13        ...
14        case 0xE916FF00:  // Receive the number '0'
15        ...
16        case 0xF30CFF00:  // Receive the number '1'
17        ...
18        case 0xF708FF00:  // Receive the number '4'
19        ...
20        case 0xF20DFF00:  // Receive the number 'C'
21        ...
22        case 0xA15EFF00:  // Receive the number '3'
23        ...
24        case 0xA55AFF00:  // Receive the number '6'
25        ...
26        case 0xB54AFF00:  // Receive the number '9'
27        ...
28        case 0xBB44FF00:  // Receive the number 'TEST'
29        ...
30        case 0xE718FF00:  // Receive the number '2'
31        ...
32        case 0xE31CFF00:  // Receive the number '5'
33        ...
34        case 0xBD42FF00:  // Receive the number '7'
35        ...
36        case 0xAD52FF00:  // Receive the number '8'
37        ...
38        case 0xFFFFFFFF:  // Remain unchanged
39        break;
40        default:
41        break;
42    }
43}