Chapter 4 Infrared Robot

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/Infrared00.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.

../../../_images/Infrared01.png

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.

../../../_images/Infrared02.png

Install IRremote library

In this project, we use a third-party library named IRremote. Please install it first.

Open Arduino IDE, click Library Manage on the left, and search “IRremote” to install.

It is recommended to use version 4.4.1 of the IRremote library to avoid compatibility issues.

../../../_images/Infrared15.png

The second way, open Arduino IDE, click Sketch -> Include Library -> Add .ZIP Library. In the pop-up window, find the file named “./Libraries/ IRremote_V4.4.1_20241029.Zip” which locates in this directory, and click OPEN.

../../../_images/Infrared16.png

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 “04.1_IR_Receiver”in

Freenove_Robot_Kit_for_Raspberry_Pi_Pico\Ordinary_wheels\Sketches ” and double click

“04.1_IR_Receiver.ino”.

../../../_images/Infrared17.png

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/11/07
 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 and set the baud rate to 115200. Press any keys on the IR remote and their corresponding values 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/Infrared03.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}

4.2 Infrared Robot

On the basis of the previous section, we further controls the robot via the infrared remote controller. Press the black buttons on the remote, the robot will move forward, move backward, turn left and turn right accordingly. Press other buttons will stop the robot.

Sketch

Open the folder “04.2_IR_Receiver_Robot” in the

Freenove_Bipedal_Robot_Kit_for_Raspberry_Pi_Pico\Sketches ” and double click “04.2_IR_Receiver_Robot.ino”.

Code

  1/**********************************************************************
  2  Filename    : IR_Receiver_Car.ino
  3  Product     : Freenove Robot for Raspberry Pi Pico (W)
  4  Auther      : www.freenove.com
  5  Modification: 2023/11/07
  6**********************************************************************/
  7#include <Arduino.h>
  8#include <IRremote.hpp>
  9#include <EEPROM.h>
 10#include "Bipedal_Robot.h"
 11
 12#define LeftLeg 10
 13#define RightLeg 12
 14#define LeftFoot 11
 15#define RightFoot 13
 16
 17#define IR_Pin 3
 18#define ENABLE_LED_FEEDBACK true
 19#define DISABLE_LED_FEEDBACK false
 20
 21// #define USE_NO_SEND_PWM
 22
 23int move_flag = 0;
 24
 25Bipedal_Robot Bipedal_Robot;
 26int calibratePosition[4] = { -17, -10, -15, 12 };
 27
 28void calib_homePos() {
 29  int servoPos[4];
 30  servoPos[0] = 90;
 31  servoPos[1] = 90;
 32  servoPos[2] = 90;
 33  servoPos[3] = 90;
 34  Bipedal_Robot._moveServos(500, servoPos);
 35  Bipedal_Robot.detachServos();
 36}
 37
 38void setup() {
 39  Serial.begin(115200);
 40  EEPROM.begin(512);
 41  Bipedal_Robot.init(LeftLeg, RightLeg, LeftFoot, RightFoot, true);  //Set the servo pins 
 42  //Bipedal_Robot.setTrims(calibratePosition[0], calibratePosition[1], calibratePosition[2], calibratePosition[3]);
 43  calib_homePos();
 44  Bipedal_Robot.saveTrimsOnEEPROM();
 45  EEPROM.commit();
 46  Bipedal_Robot.home();
 47  IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK);  // Start the receiver
 48}
 49
 50void loop() {
 51  if (IrReceiver.decode()) {
 52    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
 53    handleControl(value);        // Handle the commands from remote control
 54    Serial.println(value, HEX);  // Print "old" raw data
 55    Serial.println();
 56    IrReceiver.resume();  // Enable receiving of the next value
 57  }
 58  Move(move_flag);
 59}
 60
 61void handleControl(unsigned long value) {
 62  // Handle the commands
 63  switch (value) {
 64    case 0xBF40FF00:  // Receive the number '+'
 65      move_flag = 1;
 66      break;
 67    case 0xE619FF00:  // Receive the number '-'
 68      move_flag = 2;
 69      break;
 70    case 0xF807FF00:  // Receive the number '|<<'
 71      move_flag = 3;
 72      break;
 73    case 0xF609FF00:  // Receive the number '>>|'
 74      move_flag = 4;
 75      break;
 76    case 0xEA15FF00:  // Receive the number '▶'
 77      move_flag = 0;
 78      break;
 79    default:
 80      move_flag = 0;
 81      break;
 82  }
 83}
 84void Move(int data) {
 85  // Handle the commands
 86  switch (data) {
 87    case 1:  // Receive the number '+'
 88      Bipedal_Robot.walk(2, 1500, 1);
 89      break;
 90    case 2:  // Receive the number '-'
 91      Bipedal_Robot.walk(2, 1500, -1);
 92      break;
 93    case 3:  // Receive the number '|<<'
 94      Bipedal_Robot.turn(2, 1500, 1);
 95      break;
 96    case 4:  // Receive the number '>>|'
 97      Bipedal_Robot.turn(2, 1500, -1);
 98      break;
 99    case 0:  // Receive the number '▶'
100      Bipedal_Robot.home();
101      break;
102    default:
103      move_flag = 0;
104      Bipedal_Robot.home();
105      break;
106  }
107}

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.

Infrared04

Infrared08

Move forward

Infrared05

Infrared09

Turn left

Infrared06

Infrared10

Turn right

Infrared07

Infrared11

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

Multi-Functional Infrared Robot

Now we integrated other functions to the infrared remote, so that most functions of the robot can be controlled via the infrared remote.

Sketch

Open the folder “04.3_Multi_Functional_Robot” in the “Freenove_Bipedal_Robot_Kit_for_Raspberry_Pi_Pico\Sketches” and double click “04.3_Multi_Functional_Robot.ino”.

code

  1/**********************************************************************
  2  Filename    : IR_Receiver_Robot.ino
  3  Product     : Freenove Robot for Raspberry Pi Pico (W)
  4  Auther      : www.freenove.com
  5  Modification: 2023/11/07
  6**********************************************************************/
  7#include <Arduino.h>
  8#include <Adafruit_NeoPixel.h>
  9#include <IRremote.hpp>
 10#include <EEPROM.h>
 11#include "Freenove_Robot_For_Pico_W.h"
 12#include "Freenove_Robot_Emotion.h"
 13#include "Freenove_VK16K33_Lib.h"
 14#include "Freenove_Robot_WS2812.h"
 15#include "Bipedal_Robot.h"
 16
 17#define LeftLeg 10
 18#define RightLeg 12
 19#define LeftFoot 11
 20#define RightFoot 13
 21
 22#define IR_Pin 3  // Infrared receiving pin
 23#define ENABLE_LED_FEEDBACK true
 24#define DISABLE_LED_FEEDBACK false
 25
 26int move_flag = 0;
 27extern int move_flag;
 28
 29Bipedal_Robot Bipedal_Robot;
 30int calibratePosition[4] = { -17, -10, -15, 12 };
 31int emotion_flag = 0;
 32int ws2812_flag = 0;
 33
 34void calib_homePos() {
 35  int servoPos[4];
 36  servoPos[0] = 90;
 37  servoPos[1] = 90;
 38  servoPos[2] = 90;
 39  servoPos[3] = 90;
 40  Bipedal_Robot._moveServos(500, servoPos);
 41  Bipedal_Robot.detachServos();
 42}
 43
 44void setup() {
 45  Serial.begin(115200);  //Turn on the serial port monitor and set the baud rate to 115200
 46  WS2812_Setup();        //WS2812 initialization
 47  Buzzer_Setup();        //Initialize the buzzer
 48  Ultrasonic_Setup();
 49  EEPROM.begin(512);
 50  Bipedal_Robot.init(LeftLeg, RightLeg, LeftFoot, RightFoot, true);  //Set the servo pins
 51  //Bipedal_Robot.setTrims(calibratePosition[0], calibratePosition[1], calibratePosition[2], calibratePosition[3]);
 52  calib_homePos();
 53  Bipedal_Robot.saveTrimsOnEEPROM();
 54  EEPROM.commit();
 55  Bipedal_Robot.home();
 56  IrReceiver.begin(IR_Pin, DISABLE_LED_FEEDBACK);  // Start the receiver
 57  delay(100);
 58}
 59
 60void loop() {
 61  if (IrReceiver.decode()) {
 62    unsigned long value = IrReceiver.decodedIRData.decodedRawData;
 63    handleControl(value);        // Handle the commands from remote control
 64    Serial.println(value, HEX);  // Print "old" raw data
 65    Serial.println();
 66    IrReceiver.resume();  // Enable receiving of the next value
 67  }
 68  Emotion_Detection();
 69  Emotion_Show(emotion_task_mode);  //Led matrix display function
 70  WS2812_Show(ws2812_task_mode);    //Car color lights display function
 71  Move(move_flag);
 72}
 73
 74void handleControl(unsigned long value) {
 75  // Handle the commands
 76  switch (value) {
 77    case 0xBF40FF00:  // Receive the number '+'
 78      move_flag = 1;
 79      break;
 80    case 0xE619FF00:  // Receive the number '-'
 81      move_flag = 2;
 82      break;
 83    case 0xF807FF00:  // Receive the number '|<<'
 84      move_flag = 3;
 85      break;
 86    case 0xF609FF00:  // Receive the number '>>|'
 87      move_flag = 4;
 88      break;
 89    case 0xEA15FF00:  // Receive the number '▶'
 90      move_flag = 0;
 91      break;
 92    case 0xE916FF00:  // Receive the number '0'
 93      break;
 94    case 0xF30CFF00:  // Receive the number '1'
 95      break;
 96    case 0xF708FF00:  // Receive the number '4'
 97      break;
 98    case 0xF20DFF00:  // Receive the number 'C'
 99      break;
100    case 0xA15EFF00:  // Receive the number '3'
101      move_flag = 5;
102      break;
103    case 0xA55AFF00:  // Receive the number '6'
104      move_flag = 6;
105      break;
106    case 0xB54AFF00:  // Receive the number '9'
107      break;
108    case 0xBB44FF00:  // Receive the number 'TEST'
109      Buzzer_Variable(2000, 100, 1);
110      break;
111    case 0xE718FF00:  // Receive the number '2'
112      emotion_flag = emotion_flag + 1;
113      if (emotion_flag > 7) {
114        emotion_flag = 0;
115      }
116      Emotion_SetMode(emotion_flag);  //Display
117      break;
118    case 0xE31CFF00:  // Receive the number '5'
119      emotion_flag = 0;
120      Emotion_SetMode(emotion_flag);
121      break;
122    case 0xBD42FF00:  // Receive the number '7'
123      ws2812_flag = ws2812_flag + 1;
124      if (ws2812_flag >= 6) {
125        ws2812_flag = 0;
126      }
127      WS2812_SetMode(ws2812_flag);
128      break;
129    case 0xAD52FF00:  // Receive the number '8'
130      ws2812_flag = 0;
131      WS2812_SetMode(ws2812_flag);
132      break;
133    case 0xFFFFFFFF:  // Remain unchanged
134      break;
135    default:
136      break;
137  }
138}
139
140void Move(int data) {
141  // Handle the commands
142  switch (data) {
143    case 1:  // Receive the number '+'
144      Bipedal_Robot.walk(2, 1500, 1);
145      move_flag = 0;
146      break;
147    case 2:  // Receive the number '-'
148      Bipedal_Robot.walk(2, 1500, -1);
149      move_flag = 0;
150      break;
151    case 3:  // Receive the number '|<<'
152      Bipedal_Robot.turn(2, 1500, 1);
153      move_flag = 0;
154      break;
155    case 4:  // Receive the number '>>|'
156      Bipedal_Robot.turn(2, 1500, -1);
157      move_flag = 0;
158      break;
159    case 5:  // Receive the number '3'
160      Ultrasonic_Avoid();
161      break;
162    case 6:  // Receive the number '6'
163      dance();
164      move_flag = 0;
165      break;
166    case 0:  // Receive the number '▶'
167      Bipedal_Robot.home();
168      break;
169    default:
170      move_flag = 0;
171      Bipedal_Robot.home();
172      break;
173  }
174}
175
176void dance() {
177  Bipedal_Robot.jitter(1, 1000, 40);
178  Bipedal_Robot.home();
179  Bipedal_Robot.moonwalker(1, 1200, 30, 1);
180  Bipedal_Robot.home();
181  Bipedal_Robot.ascendingTurn(1, 1000, 50);
182  Bipedal_Robot.home();
183  Bipedal_Robot.tiptoeSwing(1, 1000, 30);
184  Bipedal_Robot.home();
185  Bipedal_Robot.flapping(1, 1000, 40, 1);
186  Bipedal_Robot.home();
187  Bipedal_Robot.crusaito(1, 3000, 40, 1);
188  Bipedal_Robot.home();
189  Bipedal_Robot.shakeLeg(1, 1000, 1);
190  Bipedal_Robot.home();
191}

After the code uploads successfully, 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/Infrared12.png ../../../_images/Infrared13.png

Code Explanation:

Add the header file for the robot.

1#include <Arduino.h>
2#include <Adafruit_NeoPixel.h>
3#include <IRremote.hpp>
4#include <EEPROM.h>
5#include "Freenove_Robot_For_Pico_W.h"
6#include "Freenove_Robot_Emotion.h"
7#include "Freenove_VK16K33_Lib.h"
8#include "Freenove_Robot_WS2812.h"
9#include "Bipedal_Robot.h"

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}

Sketch 04.4_Multi_Functional_Robot.ino is almost the same as 04.3_Multi_Functional_Robot.ino, except that it is added with the music play function. You can find the function of each key in the table below.

../../../_images/Infrared14.png