Chapter 5 Bluetooth remote control robot

This section requires an Android or iPhone device with Bluetooth to control the robot.

If you have any concerns, please feel free to contact us via support@freenove.com

Bluetooth Sending and Receiving Data

Bluetooth Module

The Bluetooth module is a serial port transparent transmission module that supports Bluetooth Low Energy (BLE).

It has such advantages as small size, high performance, high-cost performance, low power consumption, and strong platform compatibility. The Bluetooth module we use is as shown below:

../../../_images/Bluetooth00.png

Install Freenove app

There are three ways to install our app.

Method 1

Use Google play to search “Freenove”, download and install.

../../../_images/Bluetooth01.png

Method 2

Visit https://play.google.com/store/apps/details?id=com.freenove.suhayl.Freenove, and click install.

../../../_images/Bluetooth02.png

Method 3

Visit https://github.com/Freenove/Freenove_app_for_Android, download the files in this library, and install freenove.apk to your Android phone manually.

../../../_images/Bluetooth03.png

Instructions for Using the Bluetooth Module

The Bluetooth module communicates with the Raspberry Pi Pico (W) through serial port, and the program is also uploaded to Pico (W) via the serial port. Therefore, when uploading code to pico (W), if it fails, please remove the Bluetooth module and upload again.

When the Bluetooth module is not connected by other device, it can be configured using the AT command. Once connected, the Bluetooth module acts as a data pipe and cannot be configured.

By default, the Bluetooth module has a baud rate of 115200, no parity, 8 data bits, and 1 stop bit. Bluetooth name “BT05”, role mode is slave mode.

Set name of bluetooth

If you have multiple Bluetooth modules with the same name around you, you will be confused when you connect. Which one is the Bluetooth module I want to connect to?

In the next project, we will introduce how to use the AT command to modify the name of the Bluetooth module and the master-slave role in the program.

For AT commands and more information about the Bluetooth module, refer to the documentation in the package for Datasheets/BT05-Instruction.pdf

This project uses the AT command to make some settings for the Bluetooth module, then uses the Bluetooth module to receive data from the app and print the data on the serial monitor.

Introduction to the APP

In this chapter, we use the Freenove Bipedal robot for Raspberry Pi Pico (W) in the app, so let’s learn its interface first, as shown below:

../../../_images/Bluetooth05.png

Sketch

Open “05.1_Bluetooth_Robot” in “ Freenove_Bipedal_Robot_Kit_for_Raspberry_Pi_Pico\Sketches ” and double click “05.1_Bluetooth_Robot.ino”.

Note: if the code fails to upload, please remove the Bluetooth and upload it again.

After the code is successfully uploaded, follow the steps below.

  1. Plug the Bluetooth module to thecar as shown below. Don’t reverse it. The wrong connection may damage your hardware.

../../../_images/Bluetooth06.png
  1. Open Arduino Serial Monitor, and reset the control board.

As shown in the figure below, the Bluetooth name is set to “BT05” and the Bluetooth mode is slave mode (ROLE=0).

../../../_images/Bluetooth07.png

Next, open Freenove APP, tap e Freenove Bipedal Robot for Raspberry Pi Pico.

../../../_images/Bluetooth08.png

Click the following icon.

../../../_images/Bluetooth09.png

Click BT05.

../../../_images/Bluetooth10.png

If the connection successes, you can see “Connected”.

Operate the app, and observe the monitor.

../../../_images/Bluetooth11.png

The monitor will show contents as below:

../../../_images/Bluetooth12.png

Bluetooth data- robot action

The command format for communication between app and robot is A#xxx#xxx#…xxx#, where # is a separator, the first character A represents the action command, it can be other characters, such as B, C, D…The xxx represents the parameters of the action command. And different commands carry different parameters. The command list is as below:

Action command

Description

Command character

Number of parameters

(app send/receive)

Format example

(app send/receive)

MOVE

Under the MOVE mode,

parameter 1 represents the movement mode, and

parameter 2 indicates the moving speed.

A

2

A#100#100#

VOLTAGE

Get the batteries voltage,

parameter is the voltage value, unit mV

P

0/1

P# /P#4100#

LED_RGB

Control RGBLED, parameters respectively are

serial number of LED mode,

red value, green value, blue value.

C

4

C#2#100#150#200#

BUZZER

Control buzzer, and parameter is the frequency.

D

1

D#2000#

Code

 1/**********************************************************************
 2  Filename    : Receive_Bluetooth_Data.ino
 3  Product     : Freenove Robot for Raspberry Pi Pico (W)
 4  Description : Receive data from bluetooth and print it to monitor.
 5  Auther      : www.freenove.com
 6  Modification: 2023/11/07
 7**********************************************************************/
 8#include <Arduino.h>
 9#include <SoftwareSerial.h>  // Reference library
10
11#include "SerialCommand.h"
12SoftwareSerial BTserial = SoftwareSerial(1, 0);  // RX pin to 0 and TX pin to 1 on the board
13SerialCommand SCmd(BTserial);
14
15String inputString = "";    // a String to hold incoming data
16bool stringComplete = false;// whether the string is complete
17int baudRate[] = {2400, 9600, 19200, 115200};  
18int baudRateCount = sizeof(baudRate) / sizeof(baudRate[0]);  
19
20void receiveStop() {
21  delay(10);
22  Serial.flush();
23}
24
25void setup() {
26  Serial.begin(9600);
27  delay(2000);
28  // Loop through each baud rate and send commands 
29  for(int i = 0; i < baudRateCount; i++){
30    BTserial.begin(baudRate[i]);
31    delay(200);
32    BTserial.println("AT+NAME=BT05");//Set the radio called Robot
33    delay(200);
34    BTserial.println("AT+ROLE=0");
35    delay(200);
36    BTserial.println("AT+UART=2");//1=2400 2=9600 3=19200 4=115200
37    delay(200);
38
39    //SoftwareSerial does not support dynamic adjustment of baud rate, so close the serial
40    BTserial.end();
41  }
42
43  BTserial.begin(9600);
44  delay(2000);
45
46  SCmd.addDefaultHandler(receiveStop);
47  inputString.reserve(200);
48  Serial.println("Set the name of the Bluetooth module to BT05.");
49  Serial.println("Set the Bluetooth baud rate to 9600.");
50  // Serial.println("Set Bluetooth to slave mode.");
51}
52
53void loop() {
54  while (BTserial.available()) {
55    // get the new byte:
56    char inChar = (char)BTserial.read();
57    // add it to the inputString:
58    inputString += inChar;
59    // if the incoming character is a newline, set a flag so the main loop can
60    // do something about it:
61    if (inChar == '\n') {
62      stringComplete = true;
63    }
64    if (stringComplete) {
65      Serial.println(inputString);
66      // clear the string:
67      inputString = "";
68      stringComplete = false;
69    }
70  }
71}

Uplode the code to Raspberry Pi Pico W car and open serial monitor.

../../../_images/Bluetooth13.png

Open Freenove app, and tap the bipedal robot for Raspberry Pi Pico (W).

../../../_images/Bluetooth14.png

Code Explanation

Configure Bluetooth, set the Bluetooth name, baud rate and other parameters.

 1Serial.begin(9600);
 2delay(2000);
 3// Loop through each baud rate and send commands 
 4for(int i = 0; i < baudRateCount; i++){
 5  BTserial.begin(baudRate[i]);
 6  delay(200);
 7  BTserial.println("AT+NAME=BT05");//Set the radio called Robot
 8  delay(200);
 9  BTserial.println("AT+ROLE=0");
10  delay(200);
11  BTserial.println("AT+UART=2");//1=2400 2=9600 3=19200 4=115200
12  delay(200);
13
14  //SoftwareSerial does not support dynamic adjustment of baud rate, so close the serial
15  BTserial.end();
16}
17
18BTserial.begin(9600);

After the Bluetooth module connects successfully, print the data it receives.

 1while (BTserial.available()) {
 2  // get the new byte:
 3  char inChar = (char)BTserial.read();
 4  // add it to the inputString:
 5  inputString += inChar;
 6  // if the incoming character is a newline, set a flag so the main loop can
 7  // do something about it:
 8  if (inChar == '\n') {
 9    stringComplete = true;
10  }
11  if (stringComplete) {
12    Serial.println(inputString);
13    // clear the string:
14    inputString = "";
15    stringComplete = false;
16  }
17}

Bluetooth Remote Robot

In the previous section, we have learned how to receive the data of the app via Bluetooth, and the meanings of the data format. Next, let’s use the data to control the robot to make some basic movements, like moving forward and backward, turning left and right, etc.

Sketch

Open the folder “05.2_Bluetooth_Remote_Robot” in

Freenove_Bipedal_Robot_Kit_for_Raspberry_Pi_Pico\Sketches and double click “05.2_Bluetooth_Remote_Robot.ino”.

../../../_images/Bluetooth18.png

Connect the App to the Bluetooth of the robot, and tap the directional keys to control its movements.

../../../_images/Bluetooth15.png

Code

  1/**********************************************************************
  2  Product     : Freenove Robot for Raspberry Pi Pico (W)
  3  Description : Control the robot movement.
  4  Auther      : www.freenove.com
  5  Modification: 2023/11/07
  6**********************************************************************/
  7//Check that the servos are properly connected to the corresponding interface before uploading the code
  8/************************************
  9           ---     ---
 10         --------------- 
 11        |     O   O     |
 12        |---------------|
 13YR 12==>|               | <== YL 10
 14         --------------- 
 15            ||     ||
 16            ||     ||
 17RR 13==>  -----   ------  <== RL 11
 18         |-----   ------|
 19************************************/
 20#include <Arduino.h>
 21#include <SoftwareSerial.h>  
 22#include <EEPROM.h>
 23#include "Freenove_Robot_For_Pico_W.h"
 24
 25#include "SerialCommand.h"
 26SoftwareSerial BTserial = SoftwareSerial(1, 0);  // RX pin to 1 and TX pin to 0 on the board
 27SerialCommand SCmd(BTserial);
 28#include "Bipedal_Robot.h"
 29Bipedal_Robot Bipedal_Robot;
 30
 31#define LeftLeg 10
 32#define RightLeg 12
 33#define LeftFoot 11
 34#define RightFoot 13
 35
 36int YL;
 37int YR;
 38int RL;
 39int RR;
 40
 41int T = 1000;
 42int moveId = 0;
 43bool isServoResting = true;
 44
 45extern int moveId;
 46extern bool isServoResting;
 47
 48int moveSize = 15;
 49
 50String inputString = "";    // a String to hold incoming data
 51bool stringComplete = false;// whether the string is complete
 52int baudRate[] = {2400, 9600, 19200, 115200};  
 53int baudRateCount = sizeof(baudRate) / sizeof(baudRate[0]); 
 54
 55void receiveStop() {
 56  sendAck();
 57  sendFinalAck();
 58}
 59
 60void recieveBuzzer() {
 61  sendAck();
 62  bool error = false;
 63  int frec;
 64  int duration;
 65  char *arg;
 66  arg = SCmd.next();
 67  if (arg != NULL) frec = atoi(arg);
 68  else error = true;
 69  Serial.println("\nfrec is:");
 70  Serial.println(frec);
 71  tone(2, frec);
 72  sendFinalAck();
 73}
 74
 75void receiveMovement() {
 76  sendAck();
 77  Serial.print("move loop...");
 78  if (Bipedal_Robot.getRestState() == true) Bipedal_Robot.setRestState(false);
 79  isServoResting = Bipedal_Robot.getRestState();
 80  char *arg;
 81  arg = SCmd.next();
 82  if (arg != NULL) {
 83    moveId = atoi(arg);
 84    Serial.print("moveId:");
 85    Serial.print(moveId);
 86  } else {
 87    moveId = 0;
 88  }
 89  arg = SCmd.next();
 90  if (arg != NULL) {
 91    T = atoi(arg);
 92    if (T == 0) {
 93      T = 1000;
 94    } else if (T == 1) {
 95      T = 1500;
 96    } else if (T == 2) {
 97      T = 2000;
 98    }
 99  } else T = 2000;
100  Serial.print("T is:");
101  Serial.print(T);
102  arg = SCmd.next();
103  if (arg != NULL) moveSize = atoi(arg);
104  else moveSize = 15;
105}
106void move(int moveId) {
107  // bool manualMode = false;
108  switch (moveId) {
109    case 0:
110      Bipedal_Robot.home();
111      // Serial.print("moveId 0 home");
112      break;
113    case 1:
114      Bipedal_Robot.walk(1, T, 1);
115      break;
116    case 2:
117      Bipedal_Robot.walk(1, T, -1);
118      break;
119    case 3:
120      Bipedal_Robot.turn(1, T, 1);
121      break;
122    case 4:
123      Bipedal_Robot.turn(1, T, -1);
124      break;
125    default:
126      break;
127  }
128}
129
130void sendAck() {
131  delay(10);
132  Serial.flush();
133}
134void sendFinalAck() {
135  delay(10);
136  Serial.flush();
137}
138
139void setup() {
140  Serial.begin(9600);
141  delay(2000);
142  // Loop through each baud rate and send commands 
143  for(int i = 0; i < baudRateCount; i++){
144    BTserial.begin(baudRate[i]);
145    delay(200);
146    BTserial.println("AT+NAME=BT05");//Set the radio called Robot
147    delay(200);
148    BTserial.println("AT+ROLE=0");
149    delay(200);
150    BTserial.println("AT+UART=2");//1=2400 2=9600 3=19200 4=115200
151    delay(200);
152
153    //SoftwareSerial does not support dynamic adjustment of baud rate, so close the serial
154    BTserial.end();
155  }
156
157  BTserial.begin(9600);
158  delay(1500);
159  Buzzer_Setup();  //Initialize the buzzer
160  EEPROM.begin(512);
161  Bipedal_Robot.init(LeftLeg, RightLeg, LeftFoot, RightFoot, true);  //Set the servo pins and Buzzer pin
162
163  YL = EEPROM.read(0);
164  if (YL > 128) YL -= 256;
165  YR = EEPROM.read(1);
166  if (YR > 128) YR -= 256;
167  RL = EEPROM.read(2);
168  if (RL > 128) RL -= 256;
169  RR = EEPROM.read(3);
170  if (RR > 128) RR -= 256;
171  Bipedal_Robot.setTrims(YL, YR, RL, RR);
172  calib_homePos();
173  Bipedal_Robot.saveTrimsOnEEPROM();
174  Bipedal_Robot.home();
175  delay(100);
176  EEPROM.commit();
177  SCmd.addCommand("S", receiveStop);
178  SCmd.addCommand("D", recieveBuzzer);
179  SCmd.addCommand("A", receiveMovement);
180
181  inputString.reserve(200);
182  SCmd.addDefaultHandler(receiveStop);
183  Serial.println("Set the name of the Bluetooth module to BT05.");
184  Serial.println("Set the Bluetooth baud rate to 9600.");
185  Bipedal_Robot.home();
186}
187
188void loop() {
189  SCmd.readSerial();
190  move(moveId);
191}
192
193void calib_homePos() {
194  int servoPos[4];
195  servoPos[0] = 90;
196  servoPos[1] = 90;
197  servoPos[2] = 90;
198  servoPos[3] = 90;
199  Bipedal_Robot._moveServos(500, servoPos);
200  Bipedal_Robot.detachServos();
201}

Code Explanation

Add the header files to drive the robot.

1#include <Arduino.h>
2#include <SoftwareSerial.h>  
3#include <EEPROM.h>
4#include "Freenove_Robot_For_Pico_W.h"
5
6#include "SerialCommand.h"

Upon receiving movement commands, the robot makes corresponfing actions.

 1  Serial.print(T);
 2  arg = SCmd.next();
 3  if (arg != NULL) moveSize = atoi(arg);
 4  else moveSize = 15;
 5}
 6void move(int moveId) {
 7  // bool manualMode = false;
 8  switch (moveId) {
 9    case 0:
10      Bipedal_Robot.home();
11      // Serial.print("moveId 0 home");
12      break;
13    case 1:
14      Bipedal_Robot.walk(1, T, 1);
15      break;
16    case 2:
17      Bipedal_Robot.walk(1, T, -1);
18      break;
19    case 3:
20      Bipedal_Robot.turn(1, T, 1);
21      break;
22    case 4:
23      Bipedal_Robot.turn(1, T, -1);

Multifunctional Bluetooth Remote Robot

In this section, we add more functions to the robot based on the previous section, making the robot more interested. The main functions include automatic obstacle avoidance, audio playing, LED displaying, and expressions on LED dot matrix.

Upload Code and Running

Connect the robot to your computer with the USB cable.

As this section involves the audio playing function, please upload the audio data to the Raspberry Pi Pico (W) before uploading sketch. You can find the detailed steps here.

After uploading the audio file, you can upload sketch 05.3_Multi_Functional_Robot to the robot.

If the code fails to upload, please remove the Bluetooth module and upload again. Reconnect the Bluetooth module after the code uploads successfully.

../../../_images/Bluetooth16.png

After the code is successfully uploaded, unplug the USB cable and plug the Bluetooth module to the robot. Turn on the robot power switch.

../../../_images/Bluetooth17.png

Connect the APP with the robot through Bluetooth. Tap or swipe the operation panels on the app to control the robot’s movements. The color palette of the lower right corner can be clicked to control the display mode and color of the LED. Among them,

Mode 0 is a flowing rainbow,

Mode 1 is a flowing water LED with color changing.

Mode 2 is a color-adjustable Blink.

Mode 3 displays the selected color of the current color picker for all LEDs.

Code

On the basis of the previous sketch, this one is added with more interesting functions.

Multi_Functional_Robot

  1/**********************************************************************
  2  Product     : Freenove Robot for Raspberry Pi Pico (W)
  3  Description : Multi Functional Robot.
  4  Auther      : www.freenove.com
  5  Modification: 2023/11/07
  6**********************************************************************/
  7//Check that the servos are properly connected to the corresponding interface before uploading the code
  8/************************************
  9           ---     ---
 10         --------------- 
 11        |     O   O     |
 12        |---------------|
 13YR 12==>|               | <== YL 10
 14         --------------- 
 15            ||     ||
 16            ||     ||
 17RR 13==>  -----   ------  <== RL 11
 18         |-----   ------|
 19************************************/
 20#include <Arduino.h>
 21#include <EEPROM.h>
 22#include "Bipedal_Robot.h"
 23#include "AudioFileSourceLittleFS.h"
 24#include "AudioGeneratorMP3.h"
 25#include "AudioOutputI2SNoDAC.h"
 26#include "AudioFileSourceID3.h"
 27#include "AudioOutputI2S.h"
 28#include <SoftwareSerial.h>
 29#include "SerialCommand.h"
 30#include "Freenove_Robot_For_Pico_W.h"
 31#include "Freenove_Robot_Emotion.h"
 32#include "Freenove_Robot_WS2812.h"
 33#include "Freenove_VK16K33_Lib.h"
 34
 35SoftwareSerial BTserial = SoftwareSerial(1, 0);  // RX pin to 0 and TX pin to 1 on the board
 36SerialCommand SCmd(BTserial);
 37
 38Bipedal_Robot Bipedal_Robot;
 39AudioGeneratorMP3 *mp3;
 40AudioFileSourceLittleFS *file;
 41AudioOutputI2SNoDAC *out;
 42AudioFileSourceID3 *id3;
 43
 44#define LeftLegPin 10
 45#define RightLegPin 12
 46#define LeftFootPin 11
 47#define RightFootPin 13
 48#define BuzzerPin 20
 49
 50int motionFlag = 0;
 51int ultrasonicavoidMode = 0;
 52int playstartingmusic = 0;
 53int musicmode = 0;
 54int playsong = 0;
 55extern int playsong;  //Set the proportional coefficient
 56int T = 1000;
 57int moveId = 0;
 58int dance_steps = 0;
 59int Ultrasonic_Avoid_steps = 0;
 60bool isServoResting = true;
 61extern int moveId;
 62extern bool isServoResting;
 63int moveSize = 15;
 64
 65String inputString = "";    // a String to hold incoming data
 66bool stringComplete = false;// whether the string is complete
 67int baudRate[] = {2400, 9600, 19200, 115200};  
 68int baudRateCount = sizeof(baudRate) / sizeof(baudRate[0]); 
 69
 70#define ACTION_GET_VOLTAGE 'P'
 71#define ACTION_GET_DISTANCE 'E'
 72#define INTERVAL_CHAR '#'
 73unsigned long lastUploadVoltageTime;
 74unsigned long lastUploadDistanceTime;
 75#define UPLOAD_VOL_TIME 2000
 76
 77int Resting = 0;
 78float Distance = 0;
 79
 80// int calibratePosition[4] = { -17, -10, -15, 12 };
 81// int YL;
 82// int YR;
 83// int RL;
 84// int RR;
 85
 86void upLoadVoltageToApp() {
 87  float voltage = 0;
 88  voltage = Get_Battery_Voltage();
 89  BTserial.print("P#");
 90  BTserial.println(int(voltage * 1000));
 91}
 92
 93void upLoadDistanceToApp() {
 94  Distance = Get_Sonar();
 95  BTserial.print("E#");
 96  BTserial.println(Distance);
 97}
 98
 99void receiveStop() {
100  sendAck();
101  sendFinalAck();
102}
103
104void recieveBuzzer() {
105  sendAck();
106  moveId = 0;
107  playsong = 0;
108  bool error = false;
109  int frec;
110  char *arg;
111  arg = SCmd.next();
112  if (arg != NULL) frec = atoi(arg);
113  else error = true;
114  tone(2, frec);
115  sendFinalAck();
116}
117
118void receiveAvoid() {
119  sendAck();
120  ws2812_task_mode = 0;
121  emotion_task_mode = 0;
122  if (Bipedal_Robot.getRestState() == true) Bipedal_Robot.setRestState(false);
123  isServoResting = Bipedal_Robot.getRestState();
124  char *arg;
125  arg = SCmd.next();
126  if (arg != NULL) {
127    ultrasonicavoidMode = atoi(arg);
128    playsong = 0;
129    if (ultrasonicavoidMode == 1) {
130      moveId = 21;
131      Ultrasonic_Avoid_steps = 0;
132      playsong = 0;
133    }
134    if (ultrasonicavoidMode == 2) {
135      dance_steps = 0;
136      moveId = 22;
137      playsong = 4;
138    }
139    if (ultrasonicavoidMode == 0) {
140      moveId = 0;
141      Resting = 1;
142      playsong = 0;
143    }
144  }
145  sendFinalAck();
146}
147
148void receiveEmotion() {
149  sendAck();
150  Emotion_Setup();
151  moveId = 0;
152  playsong = 0;
153  char *arg;
154  char *endstr;
155  arg = SCmd.next();
156  if (arg != NULL) {
157    String stringOne = String(arg);  // converting a constant char into a String
158    emotion_task_mode = stringOne.toInt();
159    Emotion_SetMode(emotion_task_mode);  //显示静态表情
160  } else {
161  }
162  sendFinalAck();
163}
164
165void receiveLED() {
166  sendAck();
167  moveId = 0;
168  playsong = 0;
169  char *arg;
170  unsigned char paramters[3];
171  char *endstr;
172  arg = SCmd.next();
173  if (arg != NULL) {
174    String stringOne = String(arg);  // converting a constant char into a String
175    ws2812_task_mode = stringOne.toInt();
176  } else {
177  }
178  arg = SCmd.next();
179  String stringOne1 = String(arg);
180  paramters[0] = stringOne1.toInt();
181
182  arg = SCmd.next();
183  String stringOne2 = String(arg);
184  paramters[1] = stringOne2.toInt();
185
186  arg = SCmd.next();
187  String stringOne3 = String(arg);
188  paramters[2] = stringOne3.toInt();
189
190  WS2812_Set_Color_1(15, paramters[0], paramters[1], paramters[2]);
191  sendFinalAck();
192}
193
194void songmusic() {
195  if (playsong > 0) {
196    playmusic(1, playsong);
197    if (playsong != 4) {
198      playsong = 0;
199    }
200  } else {
201    pinMode(6, OUTPUT);
202    digitalWrite(6, LOW);
203  }
204}
205void receiveMusic() {
206  int music_song;
207  sendAck();
208  ws2812_task_mode = 0;
209  emotion_task_mode = 0;
210  if (Bipedal_Robot.getRestState() == true) Bipedal_Robot.setRestState(false);
211  isServoResting = Bipedal_Robot.getRestState();
212  char *arg;
213  arg = SCmd.next();
214  if (arg != NULL) {
215    music_song = atoi(arg);
216    playsong = music_song;
217    playstartingmusic = music_song;
218    clearEmtions();
219    if (playsong == 1) {
220      moveId = 18;  //play music  Hello.mp3
221    } else if (playsong == 2) {
222      moveId = 19;  //play music  Nicetomeetyou.mp3
223    } else if (playsong == 3) {
224      moveId = 20;  //play music  goodbye.mp3
225      Serial.print("yundong");
226    } else if (playsong == 0) {
227      moveId = 0;
228    }
229    Serial.print("moveId:");
230    Serial.print(moveId);
231  } else {
232    moveId = 0;
233    Resting = 1;
234  }
235}
236
237void playmusic(int playtimes, int song) {
238  if (playtimes--) {
239    if (song == 1) {
240      file = new AudioFileSourceLittleFS("Hello.mp3");
241    } else if (song == 2) {
242      file = new AudioFileSourceLittleFS("Nicetomeetyou.mp3");
243    } else if (song == 3) {
244      file = new AudioFileSourceLittleFS("goodbye.mp3");
245    } else if (song == 4) {
246      file = new AudioFileSourceLittleFS("1.mp3");
247    } else if (song == 5) {
248      file = new AudioFileSourceLittleFS("onfoot.mp3");
249    } else if (song == 6) {
250      file = new AudioFileSourceLittleFS("hello_cn.mp3");
251    } else if (song == 0) {
252      file = new AudioFileSourceLittleFS("split.mp3");
253    }
254    out = new AudioOutputI2SNoDAC(6);
255    out->SetGain(4.0);  //Volume Setup (0-4.0)
256    mp3 = new AudioGeneratorMP3();
257    mp3->begin(file, out);
258    if (mp3->isRunning() && song > 0) {
259      if (!mp3->loop() && song > 0) {
260        delete file;
261        delete mp3;
262        out->flush();
263        out->stop();
264      }
265    } else {
266      delete file;
267      delete mp3;
268      out->flush();
269      out->stop();
270      pinMode(6, OUTPUT);
271      digitalWrite(6, LOW);
272    }
273  }
274}
275
276//Ultrasonic robot
277void Ultrasonic_Avoid() {
278  if (Distance <= 15) {
279    Bipedal_Robot.walk(2, 1000, -1);  // BACKWARD x2
280    Bipedal_Robot.turn(3, 1000, -1);  // LEFT x3
281  }
282  Bipedal_Robot.walk(1, 1500, 1);  // FORWARD x1
283}
284
285void dance() {
286  dance_steps = dance_steps + 1;
287  staticEmtions(21);
288  if (moveId > 0) {
289    switch (dance_steps) {
290      case 0:
291        dance_steps = 0;
292        break;
293      case 1:
294        Bipedal_Robot.jitter(1, 750, 20);
295        break;
296      case 2:
297        Bipedal_Robot.jitter(1, 750, 20);
298        break;
299      case 3:
300        Bipedal_Robot.crusaito(1, 800, 30, 1);
301        break;
302      case 4:
303        Bipedal_Robot.crusaito(1, 800, 30, -1);
304        break;
305      case 5:
306        Bipedal_Robot.crusaito(1, 800, 30, 1);
307        Bipedal_Robot.home();
308        delay(300);
309        break;
310      case 6:
311        Bipedal_Robot.walk(1, 1500, -1);
312        break;
313      case 7:
314        Bipedal_Robot.walk(1, 1000, 1);
315        break;
316      case 8:
317        Bipedal_Robot.walk(1, 1000, 1);
318        Bipedal_Robot.home();
319        break;
320      case 9:
321        Bipedal_Robot.moonwalker(1, 600, 30, 1);
322        break;
323      case 10:
324        Bipedal_Robot.moonwalker(1, 600, 30, -1);
325        break;
326      case 11:
327        Bipedal_Robot.moonwalker(1, 600, 30, 1);
328        break;
329      case 12:
330        Bipedal_Robot.moonwalker(1, 600, 30, -1);
331        Bipedal_Robot.home();
332        delay(100);
333        break;
334      case 13:
335        Bipedal_Robot.walk(1, 1500, -1);
336        Bipedal_Robot.home();
337        delay(100);
338        break;
339    }
340    if (dance_steps > 14) {
341      dance_steps = 0;
342    }
343  } else {
344    Resting = 1;
345    moveId = 0;
346    dance_steps = 0;
347  }
348}
349
350void receiveMovement() {
351  sendAck();
352  ws2812_task_mode = 0;
353  emotion_task_mode = 0;
354  if (Bipedal_Robot.getRestState() == true) Bipedal_Robot.setRestState(false);
355  isServoResting = Bipedal_Robot.getRestState();
356  char *arg;
357  arg = SCmd.next();
358  if (arg != NULL) {
359    moveId = atoi(arg);
360    if (moveId == 0) {
361      Resting = 1;
362    }
363  } else {
364    moveId = 0;
365  }
366  arg = SCmd.next();
367  if (arg != NULL) {
368    T = atoi(arg);
369    if (T == 0) {
370      T = 1000;
371    } else if (T == 1) {
372      T = 1500;
373    } else if (T == 2) {
374      T = 2000;
375    }
376  } else T = 2000;
377  Serial.print("T is:");
378  Serial.print(T);
379  arg = SCmd.next();
380  if (arg != NULL) moveSize = atoi(arg);
381  else moveSize = 15;
382}
383
384void move(int movemode) {
385  // bool manualMode = false;
386  switch (movemode) {
387    case 0:
388      Bipedal_Robot.home();
389      if (Resting == 1) {
390        Bipedal_Robot.setRestState(false);
391        Bipedal_Robot.home();
392        Resting = 0;
393      }
394      break;
395    case 1:
396      staticEmtions(21);
397      Bipedal_Robot.walk(1, T, 1);
398      break;
399    case 2:
400      staticEmtions(21);
401      Bipedal_Robot.walk(1, T, -1);
402      break;
403    case 3:
404      staticEmtions(21);
405      Bipedal_Robot.turn(1, T, 1);
406      break;
407    case 4:
408      staticEmtions(21);
409      Bipedal_Robot.turn(1, T, -1);
410      break;
411    case 5:
412      Bipedal_Robot.updown(1, 2000, 30);
413      break;
414    case 6: Bipedal_Robot.moonwalker(1, T, moveSize, 1); break;
415    case 7: Bipedal_Robot.moonwalker(1, T, moveSize, -1); break;
416    case 8: Bipedal_Robot.swing(1, T, moveSize); break;
417    case 9: Bipedal_Robot.crusaito(1, T, moveSize, 1); break;
418    case 10: Bipedal_Robot.crusaito(1, T, moveSize, -1); break;
419    case 11: Bipedal_Robot.jump(1, T); break;
420    case 12: Bipedal_Robot.flapping(1, T, moveSize, 1); break;
421    case 13: Bipedal_Robot.flapping(1, T, moveSize, -1); break;
422    case 14: Bipedal_Robot.tiptoeSwing(1, T, moveSize); break;
423    case 15: Bipedal_Robot.bend(1, T, 1); break;
424    case 16: Bipedal_Robot.bend(1, T, -1); break;
425    case 17: Bipedal_Robot.shakeLeg(1, T, 1); break;
426    case 18:
427      staticEmtions(21);
428      Bipedal_Robot.swing(1, 1100, 50); 
429      Bipedal_Robot.home();
430      Resting = 1;
431      moveId = 0;
432      clearEmtions();
433      break;
434    case 19:
435      staticEmtions(22);
436      Bipedal_Robot.moonwalker(1, 1550, 50, 1);  //1541
437      Bipedal_Robot.home();
438      Resting = 1;
439      moveId = 0;
440      clearEmtions();
441      break;
442    case 20:
443      staticEmtions(23);
444      Bipedal_Robot.ascendingTurn(2, 700, 12);  //1332
445      clearEmtions();
446      delay(100);
447      Bipedal_Robot.home();
448      Resting = 1;
449      moveId = 0;
450      break;
451    case 21:
452      Ultrasonic_Avoid();
453      break;
454    case 22:
455      dance();
456      break;
457    default:
458      break;
459  }
460}
461
462void sendAck() {
463  delay(5);
464  Serial.flush();
465}
466void sendFinalAck() {
467  delay(5);
468  Serial.flush();
469}
470
471void calib_homePos() {
472  int servoPos[4];
473  servoPos[0] = 90;
474  servoPos[1] = 90;
475  servoPos[2] = 90;
476  servoPos[3] = 90;
477  Bipedal_Robot._moveServos(500, servoPos);
478  Bipedal_Robot.detachServos();
479}
480
481void setup() {
482  Serial.begin(9600);
483  delay(2000);
484  // Loop through each baud rate and send commands 
485  for(int i = 0; i < baudRateCount; i++){
486    BTserial.begin(baudRate[i]);
487    delay(200);
488    BTserial.println("AT+NAME=BT05");//Set the radio called Robot
489    delay(200);
490    BTserial.println("AT+ROLE=0");
491    delay(200);
492    BTserial.println("AT+UART=2");//1=2400 2=9600 3=19200 4=115200
493    delay(200);
494
495    //SoftwareSerial does not support dynamic adjustment of baud rate, so close the serial
496    BTserial.end();
497  }
498
499  BTserial.begin(9600);
500  delay(1500);
501  EEPROM.begin(512);                                                             //Initialize the ultrasonic module
502  Bipedal_Robot.init(LeftLegPin, RightLegPin, LeftFootPin, RightFootPin, true);  //Set the servo pins
503  Bipedal_Robot.Buzzer_init(BuzzerPin);
504
505  Bipedal_Robot.saveTrimsOnEEPROM();
506  Bipedal_Robot.home();
507  delay(50);
508  Buzzer_Setup();  //Initialize the buzzer
509  WS2812_Setup();  //WS2812 initialization
510  Emotion_Setup();
511  Ultrasonic_Setup();
512
513  SCmd.addCommand("S", receiveStop);
514  SCmd.addCommand("C", receiveLED);
515  SCmd.addCommand("D", recieveBuzzer);
516  SCmd.addCommand("A", receiveMovement);
517  SCmd.addCommand("B", receiveEmotion);
518  SCmd.addCommand("H", receiveAvoid);
519  SCmd.addCommand("M", receiveMusic);
520
521  inputString.reserve(200);
522  SCmd.addDefaultHandler(receiveStop);
523  Serial.println("Set the name of the Bluetooth module to BT05.");
524  Serial.println("Set the Bluetooth baud rate to 9600.");
525}
526
527void loop() {
528  SCmd.readSerial();
529  Emotion_Detection();
530  WS2812_Show(ws2812_task_mode);  //Car color lights display function
531  if (millis() - lastUploadVoltageTime > UPLOAD_VOL_TIME) {
532    upLoadVoltageToApp();
533    lastUploadVoltageTime = millis();
534  }
535  if (millis() - lastUploadDistanceTime > 200) {
536    if (ultrasonicavoidMode == 1) {
537      upLoadDistanceToApp();
538    }
539    lastUploadDistanceTime = millis();
540  }
541  if (Check_Module_value == MATRIX_IS_EXIST) {
542    Emotion_Show(emotion_task_mode);  //Led matrix display function
543  }
544  move(moveId);
545}
546
547void setup1() {
548  delay(2000);
549  playmusic(1, 2);
550  pinMode(6, OUTPUT);
551  digitalWrite(6, LOW);
552}
553void loop1() {
554  songmusic();
555}

Same as in the previous project, when the corresponding command is received by Bluetooth, the corresponding function is executed.

 1delay(1500);
 2EEPROM.begin(512);                                                             //Initialize the ultrasonic module
 3Bipedal_Robot.init(LeftLegPin, RightLegPin, LeftFootPin, RightFootPin, true);  //Set the servo pins
 4Bipedal_Robot.Buzzer_init(BuzzerPin);
 5
 6Bipedal_Robot.saveTrimsOnEEPROM();
 7Bipedal_Robot.home();
 8delay(50);
 9Buzzer_Setup();  //Initialize the buzzer
10WS2812_Setup();  //WS2812 initialization
11Emotion_Setup();
12Ultrasonic_Setup();
13
14SCmd.addCommand("S", receiveStop);
15SCmd.addCommand("C", receiveLED);
16SCmd.addCommand("D", recieveBuzzer);
17SCmd.addCommand("A", receiveMovement);
18SCmd.addCommand("B", receiveEmotion);
19SCmd.addCommand("H", receiveAvoid);

The decription of the commands and their functions are as shwon in the table below:

Commands

Description

A#parm1#parm2

Controls the robot’s movements.

B#parm1

Expressions control command

C#parm1#parm2#parm3#parm4

RGB LEDs control command

D#parm1

Buzzer control command

Send battery data every 25s

Send the battery level to the APP.

Format: P#Battery voltage

M#parm1

Audio playing command

H#parm1

Ultrasonic obstacle avoidanve mode

or dance mode

Send distance data under the obstacle avoidance mode

Send the ultrasonic data to the APP.

Format: E# ultrasonic data