5. Intelligent Games Learning
5.1 Overview of Libraries for Secondary Development
During the development process, several libraries are utilized to simplify function calls within the program. These include both official Arduino libraries such as Servo and SoftwareSerial, as well as custom libraries including LobotServoController.
This section provides an overview of the custom libraries and core functions used in secondary development applications. The LED_Matrix library, which has been fully encapsulated, will not be covered in this section.
| HWSensor::ultrasoundGetDistance() | |||
| Description | Directly retrieves the measured distance from the ultrasonic module | ||
| Parameters | None | Return Value | A uint16_t value representing the distance |
| Usage Explanation |
HWSensor hws; Creates glowy ultrasonic object hws.ultrasoundGetDistance(); Returns the measured distance affected by interference |
||
5.1.2 LobotServoController Library
The LobotServoController library is used to control bus servos. It enables execution of individual servo movements and predefined motion sequences for robots.
The following section introduces several frequently used functions from this library.
Member Function: LobotServoController::moveServo
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | void LobotServoController::moveServo(uint8_t servoID, uint16_t Position, uint16_t Time)
{
uint8_t buf[11];
if (servoID > 31 || !(Time > 0)) { //The servo ID cannot be greater than 31, it can be modified according to the corresponding controller
return;
}
buf[0] = FRAME_HEADER; //Fill frame header
buf[1] = FRAME_HEADER;
buf[2] = 8; //Data length = sevo number*3+5,此处=1*3+5
buf[3] = CMD_SERVO_MOVE; //Fill the servo movement command
buf[4] = 1; //Servo number
buf[5] = GET_LOW_BYTE(Time); //Low eight bits of fill time
buf[6] = GET_HIGH_BYTE(Time); //High eight bits of fill time
buf[7] = servoID; //Servo ID
buf[8] = GET_LOW_BYTE(Position); //Fill the lower eight bits of the target position
buf[9] = GET_HIGH_BYTE(Position); //Fill the higher eight bits of the target position
SerialX->write(buf, 10);
}
|
This member function of the LobotServoController class is used to control the rotation of a single bus servo. It accepts three parameters, including servoID, Position, and Time, which represent the ID of the target servo, the position to rotate to, and the duration of the movement, respectively. Description of the function refers to the table below.
| LobotServoController::moveServo | |||
| Description | Controls the rotation of a single bus servo | ||
| Parameters | servoID、Position、Time | Return Value | None |
| Usage Explanation |
LobotServoController lsc(MySerial); creates bus servo controller object lsc.moveServo(16,670,500); |
||
The function uses write to send data to the servo controller via the serial interface. The command follows the protocol format: header + data length + function code + data.
The servo ID, target position, and duration are packaged according to the protocol and sent to the controller. Upon receiving the command, the controller moves the servo to the specified position.
Member Function: LobotServoController::runActionGroup
The runActionGroup function, a member of the LobotServoController class, is used to execute a predefined action group through the servo controller. It takes two parameters, numOfAction and Times, which specify the action group number to be executed and the number of times it should run. Within the function, both parameters are sent to the servo controller via the serial port, formatted according to the communication protocol. Upon receiving the command, the controller locates the specified action group and initiates its execution accordingly.
144 145 146 147 148 149 150 151 152 153 154 155 156 | void LobotServoController::runActionGroup(uint8_t numOfAction, uint16_t Times) { uint8_t buf[7]; buf[0] = FRAME_HEADER; //fill frame header buf[1] = FRAME_HEADER; buf[2] = 5; //Data length, the number of data bytes in the data frame except the frame header, this command is fixed at 5 buf[3] = CMD_ACTION_GROUP_RUN; //Fill in the running action group command buf[4] = numOfAction; //Fill in the running action group number buf[5] = GET_LOW_BYTE(Times); //Get the low eight bits of the number of runs buf[6] = GET_HIGH_BYTE(Times); //Get the high eight bits of the number of runs isRunning_ = true; SerialX->write(buf, 7); //Send data frame } |
| LobotServoController::runActionGroup() | |||
| Description | Executes action group of controller | ||
| Parameters | numOfAction、Times | Return Value | None |
| Usage Explanation | LobotServoController lsc(MySerial); Creates bus servo controller object lsc.runActionGroup(0,1); |
||
5.2 Dot Matrix Display
5.2.1 Project Introduction
This lesson demonstrates how to use a dot matrix module to scroll and display a string of characters.
5.2.2 Project Process
5.2.3 Module Instruction
The LED dot matrix module is a display unit that features high brightness, no flickering during display, and easy wiring, and it can show numbers, text, and patterns. This module consists of two red 8x8 LED matrices and is controlled by the TM640B driver chip, which enables control of the dot matrix display.
5.2.4 Program Download
(1) Open the program file located in the same directory as this lesson: Dot Matrix Display Program\LED_Matrix\LED_Matrix.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.2.5 Project Outcome
Once uploaded, the LED matrix will scroll and display the text “Hi, I am Spiderbot”.
5.2.6 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 | #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
11 12 13 14 15 16 17 18 19 20 | #define rxPin 9 //Serial communication interface between arduino and servo controller #define txPin 8 #define DIN A0 //Dot matrix interface #define CLK A1 Servo sonarServo; //Examples of ultrasonic servo control SoftwareSerial MySerial(rxPin, txPin); //Software serial port instantiation WMMatrixLed matrixLed(CLK, DIN); //Instantiated dot matrix LobotServoController Controller(MySerial); //Instantiated secondary development |
(3) In the setup() function, hardware initialization is performed. The serial port is set to a baud rate of 115200, while the software serial port is set to 9600. A loop within the setup function scrolls the text “Hi, I am Spiderbot” across the matrix.
Initially, the text is drawn on the far-right side of the display. Its horizontal position is then continuously decreased to create a leftward scrolling effect. Once the text reaches the left edge of the screen, the program pauses briefly before restarting the scroll. After this scroll loop completes, the setup() function ends, and the loop() function begins execution.
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | void setup() { MySerial.begin(9600); //Software serial port for communication with servo, baud rate 9600 Serial.begin(9600); //Hardware serial port used for printing and debugging, the baud rate is 9600 matrixLed.setColorIndex(1); // matrixLed.setBrightness(3); //Set dot matrix brightness matrixLed.clearScreen(); //Clear the screen sonarServo.attach(12); //Set the servo control io port sonarServo.write(90); //Initial position 90 degrees delay(300); //Delay until servo turn to the designated position sonarServo.detach(); //Detach servo when finish Controller.runActionGroup(0, 1); //Run No.0 action group for (int i = 0; i > -str_len*6; i -- ){ //Scrolling display, one character occupies 6 dots, scrolling to the left is all negative values matrixLed.drawStr(i,7, str_data); //Parameter 1 represents the abscissa, parameter 2 represents the ordinate, and parameter 3 represents the character to be displayed. The origin of the coordinate is in the lower left corner, the abscissa is positive to the right, and the ordinate is positive to the bottom if (i == 0) {//Pause at the beginning delay(500); } else { delay(40);//Scroll speed } } } |
(4) Inside the loop() function, another scroll loop is executed continuously. This loop starts from the center of the screen, horizontal coordinate 16, and scrolls text toward the left. A delay is added between scroll steps. This loop continues to execute repeatedly until the program stops. It starts displaying from the beginning of the string.
Since the string length is fixed, once the text scrolls to the left edge of the screen, it restarts from the center and scrolls the beginning of the string again. It’s important to note that the loop condition is i > -str_len * 6, where str_len * 6 represents the pixel width of the string, assuming each character is 6 pixels wide.
If the string length exceeds this value, only the beginning portion will be visible. If the string is shorter, the remaining characters will be displayed on the next loop iteration.
48 49 50 51 52 53 54 | void loop() { //Rolling display for (int i = 16; i > -str_len*6; i-- ){ matrixLed.drawStr(i,7, str_data); delay(40);//Scroll speed } } |
5.2.7 Feature Extensions
Changing the Displayed Text
(1) To change the displayed text, simply modify the content inside the double quotation marks in the program, as shown in the figure:
(2) Only English letters and digits are supported. Chinese punctuation marks should not be used. For example, the text can be changed to “Hi,123”
Adjusting Scroll Speed
(1) To adjust the scrolling speed, modify the delay value in milliseconds inside the loop() function, as shown in the figure.
(2) For additional parameter settings and explanations, refer to the comments within the program code.
5.3 Distance Measurement Display
5.3.1 Project Introduction
This lesson demonstrates how the glowy ultrasonic sensor module to detect the distance of an object, and then display the measured distance using an LED matrix module.
5.3.2 Project Process
5.3.3 Module Instruction
Glowy Ultrasonic Module
This is a distance-measuring ultrasonic sensor module equipped with an RGB light feature. It adopts an IIC communication interface and can read distance measurements from the ultrasonic sensor via IIC.
During distance measurement, the module automatically sends out 8 pulses of 40 kHz square waves and waits for a signal to return. If a signal is returned, the module outputs a high-level signal, and the duration of the high-level signal corresponds to the time it takes for the ultrasound to travel to the object and back.
LED Dot Matrix Module
The LED dot matrix module is a display unit that features high brightness, no flickering during display, and easy wiring, and it can show numbers, text, and patterns. This module consists of two red 8x8 LED matrices and is controlled by the TM640B driver chip, which enables control of the dot matrix display.
5.3.4 Program Download
(1) Open the program file located in the same directory as this lesson: Distance Measurement Display Program\ LED_Matrix_Sonar\ LED_Matrix_Sonar.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.3.5 Project Outcome
When an object such as a small box is placed in front of the ultrasonic sensor, the LED matrix module will display the distance between the sensor and the object in numerical form.
5.3.6 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #define rxPin 9 //Serial communication interface between arduino and servo controller #define txPin 8 #define DIN A0 //Dot matrix interface #define CLK A1 #define I2C_ADDR 0x77 //Rigister #define DISDENCE_L 0//Low 8 bytes of distance, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB mode, 0: user-defined mode 1: breathing light mode default 0 #define RGB1_R 3//R value of No.1 light,0~255,Default is 0 #define RGB1_G 4//Default is 0 #define RGB1_B 5//Default is 255 #define RGB2_R 6//R value of No.2 light,0~255,Default is 0 #define RGB2_G 7//Default is 0 #define RGB2_B 8//Default is 255 #define RGB1_R_BREATHING_CYCLE 9 //In the breathing light mode, the breathing cycle of the R of the No. 1light, the unit is 100ms and the default is 0. //If the period is set to 3000ms, the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//RGB 2 #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 #define RGB_WORK_BREATHING_MODE 1 Servo sonarServo; //Examples of ultrasonic servo control SoftwareSerial MySerial(rxPin, txPin); //Software serial port instantiation WMMatrixLed matrixLed(CLK, DIN); //Instantiated dot matrix LobotServoController Controller(MySerial); //Instantiated secondary development |
(3) In the setup() function, I2C communication, software serial, and hardware serial are first initialized. The matrix display brightness is configured, and the screen is cleared. The servo controller is used to position the ultrasonic sensor. RGB lighting mode and brightness are set via I2C commands. A simple pattern is also rendered on the LED matrix.
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 | void setup() { uint8_t RGB[6]; uint8_t breathing[6]; uint8_t value; Wire.begin(); MySerial.begin(9600); //Software serial port for communication with servo, baud rate 9600 Serial.begin(9600); //Hardware serial port used for printing and debugging, the baud rate is 9600 matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //Set the servo control io port sonarServo.write(90); //Initial position to 90 degrees delay(300); sonarServo.detach(); //Detach servo Controller.runActionGroup(0, 0); //Run No.0 action group value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } matrixLed.clearScreen(); } |
(4) When the loop() function begins, the distance is retrieved using the getDistance() function. If the measured value is invalid or out of range, it is reset to zero. The distance is then converted into centimeters and stored in a variable.
Based on the measured distance, the position of the displayed number on the matrix is adjusted to keep it centered. This is achieved by calling the matrixLed.showNum() function.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 | void loop() { int distance = getDistance(); //The value returned beyond the detection range is inaccurate, and is uniformly set to 0 if (distance == 65522) distance = 0; distance = int(distance/10); //cm //Adjust the display position according to different digits so that the number is always displayed in the center if (distance < 10 && distance >= 0) { matrixLed.showNum(7, float(distance)); } else if (distance < 100) { matrixLed.showNum(5, float(distance)); } else if (distance < 1000) { matrixLed.showNum(3, float(distance)); } else if (distance < 10000) { matrixLed.showNum(1, float(distance)); } } |
(5) The getDistance() function obtains the distance value. Inside this function, three measurements are taken to obtain three individual distance readings. The WireReadDataArray() function is used to retrieve these values from the sensor over I2C.
To improve accuracy, the average of the three readings is calculated, minimizing errors from individual measurements. The resulting average value is returned for use in other parts of the program.
147 148 149 150 151 152 153 154 155 | int getDistance() { //Get distance u16 distance1, distance2, distance3; int distance = 0; WireReadDataArray(0,(uint8_t *)&distance1,2); WireReadDataArray(0,(uint8_t *)&distance2,2); WireReadDataArray(0,(uint8_t *)&distance3,2); distance = (distance1 + distance2 + distance3)/3; return distance; //Return to the detected distance } |
5.4 Distance-Based Alert
5.4.1 Project Introduction
This lesson demonstrates how to use the glowy ultrasonic sensor module to detect object distance and control the LED matrix display accordingly.
5.4.2 Project Process
5.4.3 Module Instruction
Glowy Ultrasonic Module
This is a distance-measuring ultrasonic sensor module equipped with an RGB light feature. It adopts an IIC communication interface and can read distance measurements from the ultrasonic sensor via IIC.
During distance measurement, the module automatically sends out 8 pulses of 40 kHz square waves and waits for a signal to return. If a signal is returned, the module outputs a high-level signal, and the duration of the high-level signal corresponds to the time it takes for the ultrasound to travel to the object and back.
LED Dot Matrix Module
The LED dot matrix module is a display unit that features high brightness, no flickering during display, and easy wiring, and it can show numbers, text, and patterns. This module consists of two red 8x8 LED matrices and is controlled by the TM640B driver chip, which enables control of the dot matrix display.
5.4.4 Program Download
(1) Open the program file located in the same directory as this lesson: Distance-Based Alert Program\Breathing\Breathing.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.4.5 Project Outcome
When an object such as a small box is placed in front of the ultrasonic sensor, the LED matrix lights up as a visual alert, and the RGB light on the sensor begins flashing rapidly.
5.4.6 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
8 9 10 11 12 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | #define rxPin 9 //Serial communication interface between arduino and servo controller #define txPin 8 #define DIN A0 //Dot matrix interface #define CLK A1 #define I2C_ADDR 0x77 //Rigister #define DISDENCE_L 0//Lower 8 bits of distance, unit mm #define DISDENCE_H 1 #define RGB_WORK_MODE 2 #define RGB1_R 3//R value of No.1 light,0~255,Default is 0 #define RGB1_G 4//Default is 0 #define RGB1_B 5//Default is 255 #define RGB2_R 6//R value of No.2 light,0~255,Default is 0 #define RGB2_G 7//Default 0 #define RGB2_B 8//Default 255 #define RGB1_R_BREATHING_CYCLE 9 //In the breathing light mode, the breathing cycle of the R of the No. 1light, the unit is 100ms and the default is 0. //If the period is set to 3000ms, the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//RGB 2 #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 //RGB mode,0: User-defined mode 1: Breathing light mode Default 0 #define RGB_WORK_BREATHING_MODE 1 Servo sonarServo; //Examples of ultrasonic servo control SoftwareSerial MySerial(rxPin, txPin); //Software serial port instantiation WMMatrixLed matrixLed(CLK, DIN); //Instantiated dot matrix LobotServoController Controller(MySerial); //Instantiated secondary development |
(3) In the setup() function, I2C communication, software serial, and hardware serial are first initialized. The matrix display brightness is configured, and the screen is cleared. The servo controller is used to position the ultrasonic sensor. RGB lighting mode and brightness are set via I2C commands. A simple pattern is also rendered on the LED matrix.
(4) In the loop() function, the WireReadDataArray function reads the distance value from the I2C device and stores it in the distance variable. If the distance is between 30 mm and 160 mm, the variable timer is set to 5, corresponding to a 0.5-second blinking interval. The MatrixLedBlink function is then called to control the blinking behavior. In this case, the LED matrix flashes at the defined interval. If the distance falls outside this range, the LED matrix turns off using the predefined drawBuffer array, and timer is set to 20, correspongding to a 2-second interval. In this case, the LED matrix remains off.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 | void loop()
{
uint8_t RGB[6];
uint8_t breathing[6];
uint8_t value;
static uint32_t Time;
static int timer;
u16 distance = 0;
WireReadDataArray(0,(uint8_t *)&distance,2); //Get distance
//Set to blink every 0.5s between 30-180mm
if (distance > 30 && distance < 160) {
timer = 5;
MatrixLedBlink(timer*100);
}
else {//In other intervals, the dot matrix is off, and the blinking interval is adjusted to 2s
uint8_t drawBuffer[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
matrixLed.drawBitmap(0,0,16,drawBuffer);
timer = 20;
}
//Allowed to enter again only after the waiting is over. There is no "delay" here. "Delay" is a blocking delay and cannot always detect the distance.
if (Time > millis())
return;
value = RGB_WORK_BREATHING_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
breathing[0] = 0;breathing[1] = 0;breathing[2] = timer;//RGB1,The parameter represents the cycle of the breathing light, for example 20 is 2s, the three parameters are R, G, B respectively
breathing[3] = 0;breathing[4] = 0;breathing[5] = timer;//RGB2
WireWriteDataArray(RGB1_R_BREATHING_CYCLE,breathing,6);
Time = millis() + timer*100;
}
|
(5) This function is used to control the blinking behavior of the LED matrix module. By changing the value of the static variable ledStatus, the LED display toggles between on and off states. The blinking frequency is controlled by setting a time interval.
Two arrays are used to represent the lit and unlit states of the matrix, and the matrixLed.drawBitmap() function is called to apply the corresponding display pattern.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | void MatrixLedBlink(uint8_t t) {
static uint32_t Time = 0;
static bool ledStatus = false;
if (Time > millis()) {
return;
}
if (!ledStatus) {//turn on light
//The dot matrix is 16x8. Each parameter in the list below represents a column, from left to right.
//Each column is represented by a hexadecimal number. The first one is represented by binary when it is lit from bottom to top, the second is 10, and the third is 100. At the same time, the first is lit, and the second is 11. And so on
//Then convert the binary number to hexadecimal.
uint8_t drawBuffer[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
matrixLed.drawBitmap(0,0,16,drawBuffer);
}
else {//turn off light
uint8_t drawBuffer_[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
matrixLed.drawBitmap(0,0,16,drawBuffer_);
}
ledStatus = !ledStatus;
Time = millis() + t;
}
|
5.4.7 Feature Extensions
Adjusting Detection Range
(1) To modify the distance detection conditions, update the values in the relevant section of the code.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | uint8_t breathing[6];
uint8_t value;
static uint32_t Time;
static int timer;
u16 distance = 0;
WireReadDataArray(0,(uint8_t *)&distance,2); //Get distance
//Set to blink every 0.5s between 30-180mm
if (distance > 30 && distance < 160) {
timer = 5;
MatrixLedBlink(timer*100);
}
else {//In other intervals, the dot matrix is off, and the blinking interval is adjusted to 2s
uint8_t drawBuffer[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
matrixLed.drawBitmap(0,0,16,drawBuffer);
timer = 20;
}
//Allowed to enter again only after the waiting is over. There is no "delay" here. "Delay" is a blocking delay and cannot always detect the distance.
if (Time > millis())
return;
value = RGB_WORK_BREATHING_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
breathing[0] = 0;breathing[1] = 0;breathing[2] = timer;//RGB1,The parameter represents the cycle of the breathing light, for example 20 is 2s, the three parameters are R, G, B respectively
breathing[3] = 0;breathing[4] = 0;breathing[5] = timer;//RGB2
WireWriteDataArray(RGB1_R_BREATHING_CYCLE,breathing,6);
Time = millis() + timer*100;
|
(2) The default condition detects objects between 30 mm and 160 mm. These threshold values can be changed directly based on the specific application.
Adjusting Blinking Speed
(1) To change the RGB light’s blinking speed, adjust the timer values in the appropriate sections of the code.
(2) Default settings:
timer = 5: When the object is within 30–160 mm, the RGB light blinks every 0.5 seconds.
timer = 20: When the object is beyond 160 mm, the RGB light blinks every 2 seconds.
(3) For example, to increase blinking speed:
Set timer = 3 for a 0.3-second interval within 30–160 mm.
Set timer = 10 for a 1-second interval beyond 160 mm.
5.5 Autonomous Following
5.5.1 Project Introduction
This lesson focuses on detecting the distance of nearby object using a glowy ultrasonic module, displaying the data via an LED matrix, and controlling the robot’s movement accordingly.
5.5.2 Project Process
5.5.3 Module Instruction
This is a distance-measuring ultrasonic sensor module equipped with an RGB light feature. It adopts an IIC communication interface and can read distance measurements from the ultrasonic sensor via IIC.
During distance measurement, the module automatically sends out 8 pulses of 40 kHz square waves and waits for a signal to return. If a signal is returned, the module outputs a high-level signal, and the duration of the high-level signal corresponds to the time it takes for the ultrasound to travel to the object and back.
5.5.4 Program Download
(1) Open the file named Autonomous Following Program\Follow\Follow.ino located in the corresponding lesson folder.
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.5.5 Project Outcome
Place a cardboard box in front of the ultrasonic sensor. The sensor will measure the distance to the object. If the object approaches, an upward arrow appears on the LED matrix, the ultrasonic module glows red, and the robot moves backward. If the object moves away, a downward arrow is displayed, the module glows green, and the robot moves forward.
5.5.6 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #define DIN A0 //Dot matrix interface #define CLK A1 #define I2C_ADDR 0x77 //Rigister #define DISDENCE_L 0//Low 8 bytes of distance, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB mode, 0: user-defined mode 1: breathing light mode default 0 #define RGB1_R 3//R value of No.1 light,0~255,Default is 0 #define RGB1_G 4//Default is 0 #define RGB1_B 5//Default is 255 #define RGB2_R 6//R value of No.2 light,0~255,Default is 0 #define RGB2_G 7//Default is 0 #define RGB2_B 8//Default is 255 #define RGB1_R_BREATHING_CYCLE 9 //In the breathing light mode, the breathing cycle of the R of the No. 1light, the unit is 100ms and the default is 0. //If the period is set to 3000ms, the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//RGB 2 #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 #define RGB_WORK_BREATHING_MODE 1 |
(3) In the setup() function, I2C communication, software serial, and hardware serial are first initialized. The matrix display brightness is configured, and the screen is cleared. The servo controller is used to position the ultrasonic sensor. RGB lighting mode and brightness are set via I2C commands. A simple pattern is also rendered on the LED matrix.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 | void setup() { Wire.begin(); Serial.begin(9600); //Initialize serial port 0, baud rate 9600 MySerial.begin(9600); //Initialize software serial port matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //Set the servo control io port sonarServo.write(90); delay(300); sonarServo.detach(); //Detach servo Controller.runActionGroup(0, 1); //Run No.0 action group to command the robot to stand up uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { drawBuffer[i] = 0xff; matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } matrixLed.clearScreen(); } |
(4) In the loop() function, Controller.receiveHandle() processes incoming serial data, ensuring real-time response to inputs or sensor data. The getDistance() function retrieves the measured distance to an object.
The function Distancewalking() processes logic based on the measured distance, triggering actions like hardware movement, data handling or responding to other tasks. The specific logic operations depend on the internal implementation of the Distancewalking() function.
219 220 221 222 223 224 225 226 | void loop() { Controller.receiveHandle(); //Receive and process functions, fetch data from the serial port receive buffer getDistance(); //Measure distance // Serial.print("distance = ");Serial.println(distance); Distancewalking(); //Logic realization } |
(5) Within Distancewalking(), local variables are defined, including RGB value arrays and display patterns. The function Controller.isRunning() checks whether a motion group is currently executing. If no action group is running, and the measured distance is between 30mm and 180mm, a specific pattern is displayed on the matrix, RGB mode is set to simple, and RGB lights are dimmed or turned off. If the distance is between 300mm and 400mm, another pattern is displayed and different RGB light settings are applied.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | void Distancewalking()
{
uint8_t RGB[6];
uint8_t breathing[6];
uint8_t value;
if (!Controller.isRunning()) {
if (Distance > 30 && Distance < 180) {
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x0,0x10,0x30,0x7f,0xff
,0x7f,0x30,0x10,0x0,0x0,0x0,0x0,0x0};
matrixLed.drawBitmap(0,0,16,drawBuffer);
value = RGB_WORK_SIMPLE_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
RGB[0] = RGB_BRIGHTNESS;RGB[1] = 0;RGB[2] = 0;//RGB1
RGB[3] = RGB_BRIGHTNESS;RGB[4] = 0;RGB[5] = 0;//RGB2
WireWriteDataArray(RGB1_R,RGB,6);
Controller.runActionGroup(2, 1);
}
else if (Distance > 300 && Distance < 400) {
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x0,0x8,0xc,0xfe,0xff
,0xfe,0xc,0x8,0x0,0x0,0x0,0x0,0x0};
matrixLed.drawBitmap(0,0,16,drawBuffer);
value = RGB_WORK_SIMPLE_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
RGB[0] = 0;RGB[1] = RGB_BRIGHTNESS;RGB[2] = 0;//RGB1
RGB[3] = 0;RGB[4] = RGB_BRIGHTNESS;RGB[5] = 0;//RGB2
WireWriteDataArray(RGB1_R,RGB,6);
Controller.runActionGroup(1, 1);
}
else {
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x70,0xf8,0xfc,0xfe,0x7f
,0x7f,0xfe,0xfc,0xf8,0x70,0x0,0x0,0x0};
matrixLed.drawBitmap(0,0,16,drawBuffer);
value = RGB_WORK_SIMPLE_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
RGB[0] = 255;RGB[1] = 192;RGB[2] = 203;//RGB1
RGB[3] = 255;RGB[4] = 192;RGB[5] = 203;//RGB2
WireWriteDataArray(RGB1_R,RGB,6);
}
}
}
|
5.5.7 Feature Extensions
Adjusting Distance Thresholds
(1) To change the range at which the robot responds, modify the corresponding section of the code marked in red.
(2) When an object is detected at 30–180mm, the robot moves backward by default. When the distance is 280–400mm, the robot moves forward. These values can be adjusted directly as needed.
Modifying Ultrasonic RGB Colors
(1) To change the color display of the ultrasonic module, adjust the RGB array settings in the highlighted code section.
(2) There are two RGB LED onboard, and each consists of three color components, totaling six LED elements indexed from 0 to 5.
(3) When moving backward, LEDs 0 and 3 (left and right) are set to red by default. When moving forward, LEDs 1 and 4 are set to green.
(4) To activate any individual LED, set its corresponding array element to RGB_BRIGHTINESS.
5.8 Inverted Walking
5.8.1 Project Introduction
This lesson demonstrates how the robot can continue walking even when turned upside down.
5.8.2 Project Process
5.8.3 Module Instruction
This sensor primarily uses the MPU6050 component. It integrates a 3-axis MEMS gyroscope, a 3-axis MEMS accelerometer, and an expandable Digital Motion Processor (DMP). The sensor uses three 16-bit ADCs for both the gyroscope and accelerometer to convert measured analog signals into digital output.
5.8.4 Program Download
(1) Open the file named Inverted Walking Program\ upAndDown\ upAndDown.ino located in the corresponding lesson folder.
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.8.5 Project Outcome
During forward movement, if the robot is turned upside down so that its underside faces upward, it will resume walking in a rolling motion after a brief moment. When flipped back to its original orientation, the robot will continue walking as before in its standard posture.
5.8.6 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 11 12 | #include <Wire.h> #include "Servo.h" #include "I2Cdev.h" #include "MPU6050.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | #define L_STAND 0 //Low stance,stand up #define L_GO_FORWARD 1 //Low stance, go forward #define L_GO_BACK 2 //Low stance,backward #define U_STAND 90 //Flipped stance,stand up #define U_GO_FORWARD 91 //Flipped stance,go forward #define U_GO_BACK 92 //Flipped stance,backward #define weight 0.1 #define I2C_ADDR 0x77 //Rigister #define DISDENCE_L 0//Low 8 bytes of distance, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB mode, 0: user-defined mode 1: breathing light mode default 0 #define RGB1_R 3//R value of No.1 light,0~255,Default is 0 #define RGB1_G 4//Default is 0 #define RGB1_B 5//Default is 255 #define RGB2_R 6//R value of No.2 light,0~255,Default is 0 #define RGB2_G 7//Default is 0 #define RGB2_B 8//Default is 255 #define RGB1_R_BREATHING_CYCLE 9 //In the breathing light mode, the breathing cycle of the R of the No. 1light, the unit is 100ms and the default is 0. //If the period is set to 3000ms, the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//RGB 2 #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 #define RGB_WORK_BREATHING_MODE 1 unsigned long now, lastTime = 0; float dt; //Derivative time int16_t ax, ay, az, gx, gy, gz; //Accelerometer gyroscope raw data float aax=0, aay=0,aaz=0, agx=0, agy=0, agz=0; //Angle variable long axo = 0, ayo = 0, azo = 0; //Accelerometer offset long gxo = 0, gyo = 0, gzo = 0; //Gyro offset float pi = 3.1415926; float AcceRatio = 16384.0; //Accelerometer scale factor float GyroRatio = 131.0; //Gyro scale factor uint8_t n_sample = 8; //Accelerometer filtering algorithm sampling number float aaxs[8] = {0}, aays[8] = {0}, aazs[8] = {0}; //x,y axis sampling queue long aax_sum, aay_sum,aaz_sum; //x,y axis sampling and float a_x[10]={0}, a_y[10]={0},a_z[10]={0} ,g_x[10]={0} ,g_y[10]={0},g_z[10]={0}; //Accelerometer covariance calculation queue float Px=1, Rx, Kx, Sx, Vx, Qx; //x-axis Kalman variable float Py=1, Ry, Ky, Sy, Vy, Qy; //y-axis Kalman variable float Pz=1, Rz, Kz, Sz, Vz, Qz; //z-axis Kalman variable MPU6050 accelgyro; Servo sonarServo; //Examples of ultrasonic servo control SoftwareSerial MySerial(rxPin, txPin); //Software serial port instantiation WMMatrixLed matrixLed(CLK, DIN); //Instantiated dot matrix LobotServoController Controller(MySerial); //Instantiated secondary development |
(3) In the setup() function, I2C communication, software serial, and hardware serial are first initialized. The matrix display brightness is configured, and the screen is cleared. The servo controller is used to position the ultrasonic sensor. RGB lighting mode and brightness are set via I2C commands. A simple pattern is also rendered on the LED matrix.
343 344 345 346 347 348 349 350 351 352 353 354 355 356 | void setup() { // put your setup code here, to run once: uint8_t RGB[6]; uint8_t breathing[6]; uint8_t value; Wire.begin(); MySerial.begin(9600); //Software serial port for communication with the servo, baud rate 9600 Serial.begin(9600); //The hardware serial port used for printing and debugging, the baud rate is 9600 matrixLed.setColorIndex(1); matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //Set the servo control io port sonarServo.write(90); //Initial position to 90 degrees |
(4) The main function is primarily responsible for receiving data, measuring distance, updating the LED display, and executing additional logic. The ultrasonic distance is measured using the getDistance() function, which retrieves the current distance information. An array named drawBuffer is defined to store data for the LED matrix display. This array is initialized with zeros, which means all LEDs are off.
A loop iterates through each element in the drawBuffer array. Based on the value of the variable pos, the binary value of each element is shifted accordingly. If pos is positive, each element is shifted left by ptmp bits, where ptmp is the absolute value of pos. If pos is negative, each element is shifted right by ptmp bits.
382 383 384 385 386 387 388 389 390 391 392 393 | uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { drawBuffer[i] = 0xff; matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } sonarServo.detach(); //Detach servo matrixLed.clearScreen(); } |
(5) In the loop() function, the primary tasks include receiving data, measuring distance, updating the LED display, and executing specific logic operations. It integrates data processing, hardware control, and graphical display. These components work together to achieve specific behavior or functionality.
395 396 397 398 399 400 | void loop() { //Main loop // put your main code here, to run repeatedly: Controller.receiveHandle(); //Receiving processing, used to process the data received from the steering gear control board update_mpu6050(); upDown(); //Logic realization } |
5.8.7 Feature Extensions
Adding Inverted Movement
(1) To modify the robot’s behavior after it has been flipped, adjustments can be made in the specified section of the code.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #include <Wire.h> #include "Servo.h" #include "I2Cdev.h" #include "MPU6050.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" #define rxPin 9 //Serial communication interface between arduino and servo controller #define txPin 8 #define DIN A0 //Dot matrix interface #define CLK A1 //Number of all action groups can be modified. #define L_STAND 0 //Low stance,stand up #define L_GO_FORWARD 1 //Low stance, go forward #define L_GO_BACK 2 //Low stance,backward #define U_STAND 90 //Flipped stance,stand up #define U_GO_FORWARD 91 //Flipped stance,go forward #define U_GO_BACK 92 //Flipped stance,backward #define weight 0.1 |
(2) Several predefined macros define different motion actions based on the robot’s orientation.
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 | void upDown()
{
static uint32_t timer = 0;//Define static variable timer for timing
static uint8_t stept = 0; //Static variables for recording steps
if (timer > millis()) //Return if the set time is greater than the current number of milliseconds, otherwise continue
return;
switch (stept) //Switch according to step
{
case 0:
if (agy < 0) {
Controller.stopActionGroup();
stept = 1;
}
else {
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x0,0x10,0x30,0x7f,0xff
,0x7f,0x30,0x10,0x0,0x0,0x0,0x0,0x0};
matrixLed.drawBitmap(0,0,16,drawBuffer);
Controller.runActionGroup(L_GO_FORWARD, 0);//Go forward
}
break;
case 1:
if (agy < 0) {
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x0,0x10,0x30,0x7f,0xff
,0x7f,0x30,0x10,0x0,0x0,0x0,0x0,0x0};
for (int i = 0; i < 16; i++) {
if (drawBuffer[i] != 0x00) {
drawBuffer[i] = getInvert(drawBuffer[i]);
}
}
matrixLed.drawBitmap(0,0,16,drawBuffer);
Controller.runActionGroup(U_STAND, 1);//Stand in the opposite direction
timer = millis() + 1500;
stept = 2;
}
else
stept = 0;
break;
case 2:
if (!Controller.isRunning()) { //If there is no action group running
stept = 3;
}
break;
case 3:
if (agy > 0) {
timer = millis() + 500;
stept = 4;
}
else
// ;
Controller.runActionGroup(U_GO_FORWARD, 0);//Go forward in the opposite direction
break;
case 4:
if (agy > 0){
uint8_t drawBuffer[16] = {
0x0,0x0,0x0,0x0,0x10,0x30,0x7f,0xff
,0x7f,0x30,0x10,0x0,0x0,0x0,0x0,0x0};
matrixLed.drawBitmap(0,0,16,drawBuffer);
Controller.runActionGroup(L_STAND, 1);//Stand up
timer = millis() + 1500;
stept = 0;
}
break;
}
}
|
(3) When the front side faces upward, the robot moves forward. When the robot is flipped upside down, the program triggers inverted movement.
(4) To modify the robot’s actions during operation, update the action value within the highlighted section of the code to match one of the predefined posture macros. For example, by default, when the robot is flipped with its back side facing upward, the action Controller.runActionGroup(U_GO_FORWARD, 0) is executed, initiating forward movement in the inverted state.
(5) This line can be modified to Controller.runActionGroup(U_GO_BACK, 0) to perform backward movement instead. For example, this can be changed to Controller.runActionGroup(L_GO_FORWARD, 0) to move forward in a crouching posture.
5.9 Color Recognition
5.9.1 Assembly and Wiring
5.9.2 Project Introduction
This lesson demonstrates the use of a color sensor to detect three primary colors—red, green, and blue—and to control the robot’s behavior and the RGB lighting on the ultrasonic module accordingly.
5.9.3 Project Process
5.9.4 Module Instruction
This is a sensor that can detect the color of an object, the ambient light intensity, object proximity, and support non-contact gesture detection. It features integrated RGB color detection which enables identification of various colors, ambient light detection to measure light intensity under different lighting conditions, and a built-in infrared LED to support proximity sensing.
5.9.5 Program Download
(1) Open the file named Color Recognition Program\color_detect\color_detect.ino located in the corresponding lesson folder.
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.9.6 Project Outcome
Place the robot on a flat surface and turn on the power. Present the color cards one by one in front of the color sensor.
(1) When blue is detected, the LED matrix scrolls the text “BLUE,” the ultrasonic module emits blue light, and the pan-tilt servo rotates in a head-shaking motion.
(2) When green is detected, the LED matrix scrolls “GREEN,” the ultrasonic module emits green light, and the pan-tilt servo performs the same head-shaking movement.
(3) When red is detected, the LED matrix scrolls “RED,” the ultrasonic module emits red light, and the pan-tilt servo remains stationary.
5.9.7 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 11 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "Adafruit_APDS9960.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created. Control objects for servos and LED matrix are initialized to manage peripheral modules.
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | #define I2C_ADDR 0x77 //register #define DISDENCE_L 0//distanceis lower 8 bits, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB light modoe,0:User-defined mode 1:Breathing light mode default 0 #define RGB1_R 3//R value of probe 1,0~255,default0 #define RGB1_G 4//default0 #define RGB1_B 5//default255 #define RGB2_R 6//R value of proble,0~255,default0 #define RGB2_G 7//default0 #define RGB2_B 8//default255 #define RGB1_R_BREATHING_CYCLE 9 //when breathing light mode is 1,the breathing period of probe 1,unit 100ms default0, //if set to period is 3000ms,then the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//No.2 proble #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 #define RGB_WORK_BREATHING_MODE 1 Adafruit_APDS9960 apds; Servo sonarServo; //unltrasion stastion servo control examples SoftwareSerial MySerial(rxPin, txPin); //soft serial port examples WMMatrixLed matrixLed(CLK, DIN); //dot matrix examples LobotServoController Controller(MySerial); //instantiated secondary development |
(3) In the setup() function, I2C communication, software serial, and hardware serial interfaces are initialized. Servo IO pins are bound, and the servo is set to its initial position at 90 degrees. The robot’s default posture is configured to Attention. The ultrasonic RGB light is set to breathing mode, and the color detection function of the sensor is enabled.
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 | void setup() {
// put your setup code here, to run once:
uint8_t RGB[6];
uint8_t breathing[6];
uint8_t value;
Wire.begin();
MySerial.begin(9600); //soft serial port for communication with the steering gear, baud rate 9600
Serial.begin(9600); //the hardware serial port used for printing and debugging, the baud rate is 9600
matrixLed.setBrightness(3);
matrixLed.clearScreen();
sonarServo.attach(12); //set the servo control io port
sonarServo.write(90); //initial position 90 degrees
delay(300);
sonarServo.detach();
Controller.runActionGroup(0, 1); //running high profile
value = RGB_WORK_SIMPLE_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1
RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2
WireWriteDataArray(RGB1_R,RGB,6);
if (!apds.begin()) { //initialize the sensor
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//enable color sensign mode
apds.enableColor(true);//make sensor can color detection
uint8_t drawBuffer[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
for (int i = 0; i < 16; i++) {
drawBuffer[i] = 0xff;
matrixLed.drawBitmap(0,0,16,drawBuffer);
delay(20);
}
matrixLed.clearScreen();
|
(4) The main function mainly handles data received from the servo controller and executes logic related to color recognition.
287 288 289 290 291 | void loop() { // put your main code here, to run repeatedly: Controller.receiveHandle(); //process the data received from the steering gear control board color_detect(); } |
(5) Within the color_detect() function, the color_logic() function is called to retrieve the detected color. If red is detected, the RGB light on the ultrasonic module is set to red, and “RED” is displayed on the LED matrix.
196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 | void color_detect() {
uint8_t RGB[6];
uint8_t breathing[6];
uint8_t value;
uint8_t color;
uint8_t status_;
color = color_logic();
if (color == RED && status_ != 1)
{
status_ = 1;
value = RGB_WORK_BREATHING_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
breathing[0] = 5;breathing[1] = 0;breathing[2] = 0;//RGB1,the parameter represents the cycle of the breathing light, for example 20 is 2s, the three parameters are R, G, B respectively
breathing[3] = 5;breathing[4] = 0;breathing[5] = 0;//RGB2
breathing[3] = 5;breathing[4] = 0;breathing[5] = 0;//RGB2
WireWriteDataArray(RGB1_R_BREATHING_CYCLE,breathing,6);
showStr("RED", 60);
}
else if (color == GREEN && status_ != 2) {
status_ = 2;
value = RGB_WORK_SIMPLE_MODE;
WireWriteDataArray(RGB_WORK_MODE,&value,1);
RGB[0] = 0;RGB[1] = RGB_BRIGHTNESS;RGB[2] = 0;//RGB1
RGB[3] = 0;RGB[4] = RGB_BRIGHTNESS;RGB[5] = 0;//RGB2
WireWriteDataArray(RGB1_R,RGB,6);
showStr("GREEN", 60);
|
(6) If green is detected, the RGB light is set to green, and “GREEN” is displayed. If blue is detected, the robot performs a head-shaking motion, and the RGB light is set to blue.
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 | else if (color == GREEN && status_ != 2) { status_ = 2; value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = RGB_BRIGHTNESS;RGB[2] = 0;//RGB1 RGB[3] = 0;RGB[4] = RGB_BRIGHTNESS;RGB[5] = 0;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); showStr("GREEN", 60); shake_Head(); } else if (color == BLUE && status_ != 3) { status_ = 3; value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); showStr("BLUE", 60); shake_Head(); } else if (status_ != 4){ status_ = 4; matrixLed.clearScreen(); value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = 0;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = 0;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); } } |
5.9.8 Feature Extensions
Setting a Different Target Color
(1) By default, the program uses red as the target color. To modify the distance detection conditions, update the values in the relevant section of the code.
(2) In the section marked in red, the color sensor evaluates the read values to determine whether the detected color is red, green, or blue. In the green-marked section, the corresponding RGB light color on the ultrasonic module is set based on the identified color.
(3) By default, red triggers a breathing light effect, while green and blue use a steady light. The yellow-marked section contains the character output displayed on the LED matrix. It reflects the identified color. If the detected color is not the correct one, the 9g servo beneath the ultrasonic module will be triggered to move back and forth as an error response.
Customizing Color Recognition
(1) The color sensor detects RGB values, which identifies colors based on the combination of red, green, and blue components.
(2) In the default configuration, the sensor reads RGB values and allows the robot to perform specific actions based on the dominant color. In the red-marked section, the raw R, G, and B values are converted into the variables r, g, and b, representing the intensity of red, green, and blue respectively, with each ranging from 0 to 255.
(3) In the green-marked section, the program compares the r, g, and b values to determine which color component is dominant and thus classifies the detected color.
(4) To add support for other colors, the target RGB values must first be determined. This can be done using the “Paint” application on a Windows system.
(5) Open an image containing the desired color. Use the Eyedropper Tool to select the color. Taking color “Orange” as an example, click “Edit Colors” to view the exact Red, Green, and Blue values.
(6) These RGB values can then be used in the program to compare with the color sensor’s readings. If the sensor readings closely match the target RGB values, the color can be recognized as a user-defined color.
5.10 Sound Control
5.10.1 Assembly and Wiring
5.10.2 Project Introduction
This lesson demonstrates how to control the robot’s movement using a sound sensor. The number of detected sounds determines the robot’s response.
5.10.3 Project Process
5.10.4 Module Instruction
The sensor features a built-in capacitive electret microphone. Sound waves cause the internal diaphragm to vibrate, resulting in capacitance changes and small voltage fluctuations. This voltage is converted to a 0 to 5V signal and compared with a preset adjustable threshold.
Through the module’s A/D conversion, values in the range of 0 to 1023 are read by the data acquisition system. The stronger the sound, the higher the output value, indicating a direct correlation between sound intensity and analog output.
5.10.5 Program Download
(1) Open the program file located in the same directory as this lesson: Sound Control Program\Sound\Sound.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.10.6 Project Outcome
Sound cues, such as claps, can be used to control the robot. One sound triggers a short forward movement, while two sounds trigger a short backward movement.
5.10.7 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
12 13 14 15 16 17 18 19 20 21 | #define rxPin 9 //arduino and servo controller's serial communication port #define txPin 8 #define DIN A0 //dot matrix port #define CLK A1 #define SOUND_PIN A2 /*IO port where the sound sensor is located*/ #define L_STAND 0 //low posture, attention #define I2C_ADDR 0x77 |
(3) In the setup() function, several arrays and variables are defined. First, I2C communication and serial communication are initialized, and the baud rate for communication with the servo controller is set to 9600. Then, the sound input pin is configured as an input. The LED matrix is initialized, with its color and brightness set, and the display cleared.
185 186 187 188 189 190 191 192 | Wire.begin(); MySerial.begin(9600); //soft serial port for communication with the steering gear, baud rate 9600 Serial.begin(9600); //the hardware serial port used for printing and debugging, the baud rate is 9600 pinMode(SOUND_PIN, INPUT); matrixLed.setColorIndex(1); matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //set the servo control io port |
(4) The servo is then configured by binding it to a specific I/O port, and its initial position is set to 90 degrees. A predefined action group is executed, and a value is written to the RGB working mode via the I2C bus. Next, two RGB values are set and transmitted to the LED matrix’s RGB channels through the I2C interface.
188 189 190 191 192 193 194 195 196 | pinMode(SOUND_PIN, INPUT); matrixLed.setColorIndex(1); matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //set the servo control io port sonarServo.write(90); //initial position 90 degrees delay(300); sonarServo.detach(); //release the servo s after use Controller.runActionGroup(0, 1); //run No.0 action group |
(5) A drawing buffer is then created and filled with zero values. This buffer is displayed on the LED matrix to produce a fully lit effect for a brief moment before the screen is cleared.
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | void setup() { // put your setup code here, to run once: uint8_t RGB[6]; uint8_t breathing[6]; uint8_t value; Wire.begin(); MySerial.begin(9600); //soft serial port for communication with the steering gear, baud rate 9600 Serial.begin(9600); //the hardware serial port used for printing and debugging, the baud rate is 9600 pinMode(SOUND_PIN, INPUT); matrixLed.setColorIndex(1); matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //set the servo control io port sonarServo.write(90); //initial position 90 degrees delay(300); sonarServo.detach(); //release the servo s after use Controller.runActionGroup(0, 1); //run No.0 action group value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { drawBuffer[i] = 0xff; matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } matrixLed.clearScreen(); } |
(6) In the loop() function, the system first calls Controller.receiveHandle() to retrieve and process data from the serial buffer, allowing it to respond to control instructions sent via the serial port. Next, the sound() function is called to enable sound-based control, allowing specific actions to be triggered by detecting sound signals.
214 215 216 217 218 | void loop() { // put your main code here, to run repeatedly: Controller.receiveHandle(); //receive processing function, fetch data from the receive buffer sound(); //sound control implementation } |
(7) The sound control function governs the robot’s behavior using static variables to maintain timing and state. The function first checks whether the required delay period has passed and confirms that the previous action is complete. It then processes different conditions based on the current step:
Step 0: Displays the number 0 and proceeds to the next step after a 400 ms delay.
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 | void sound()
{
static uint32_t timer = 0; //static variable for timing
static uint32_t timer_run = 0; //static variable for stepping
static uint8_t stept = 0; //static variable, used to record the step
if (timer > millis()) //if
return;
if (!Controller.isRunning()) { //because the sound of the robot's own footsteps may cause misjudgment, there will be a short delay after the action is completed and go to the next step
switch (stept) //according step to make switch
{
case 0: //step0
matrixLed.showNum(6,0);
stept = 1; //move to next step step1
timer = millis() + 400; //delay400ms
break; //end switch
case 1:
if (readSound() == 1) //read the state of the pin where the sound sensor is located, if it is 1, there is the sound
{
timer = millis() + 30;//delay30ms
timer_run = timer + 500; //1000msdelay
stept = 2;
}
break; //end switch statement
|
Step 1: Reads the sound sensor input. If sound is detected, a timer is started after 30 ms, and the program proceeds to Step 2 after 1000 ms.
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | case 1: if (readSound() == 1) //read the state of the pin where the sound sensor is located, if it is 1, there is the sound { timer = millis() + 30;//delay30ms timer_run = timer + 500; //1000msdelay stept = 2; } break; //end switch statement case 2: if (readSound() == 1) //read the state of the pin where the sound sensor is located, if it is 1, there is the sound { matrixLed.showNum(6,2); stept = 3; //detected two sounds within 1000ms } if (timer_run < millis()) //determine whether it exceeds 500ms { matrixLed.showNum(6,1); stept = 4; //detected one sound within 1000ms } break; //end switch statement |
Step 2: If two sounds are detected within 1000 ms, the number 2 is displayed, and the program advances to Step 3. If no second sound is detected within 500 ms, the number 1 is displayed, and the program proceeds to Step 4.
166 167 168 169 | case 3: //run the action group that detects two sounds stept = 0; //re-enter sound detection Controller.runActionGroup(2, 3); break; |
Step 3 and Step 4: The robot performs different action groups based on the number of detected sounds, and the step counter is reset to 0 to restart the sound detection process.
166 167 168 169 170 171 172 173 174 175 176 177 | case 3: //run the action group that detects two sounds stept = 0; //re-enter sound detection Controller.runActionGroup(2, 3); break; case 4: //run the action group that detects one sound stept = 0; //re-enter sound detection Controller.runActionGroup(1, 3); break; } } } |
5.10.8 Feature Extensions
Adjusting the Sound Detection Threshold
The sound sensor detects volume levels in the range of 0 to 1023. By default, the program considers any value above 200 as a valid sound signal. To modify the sound detection threshold, locate the relevant section in the program and adjust the value accordingly.
Modifying the Robot’s Response to Sound Detection
(1) By default, the program is configured as follows: If one sound is detected within 1000 ms, the robot moves forward. If two sounds are detected within the same 1000 ms interval, the robot moves backward. To change the response behavior after detecting sound, refer to the corresponding sections in the code:
(2) The red-highlighted section determines whether an action should be triggered after the first sound is detected. The green-highlighted section checks for a second sound within the preset 1000 ms interval. The yellow-highlighted section verifies whether the second sound occurred within 500 ms after the first one. If the second sound exceeds this interval, it is not considered part of a continuous sequence.
(3) When two sounds are confirmed to be continuous, the red-highlighted code section executes the corresponding action group. If only a single sound is detected, the green-highlighted section handles the response.
(4) The function Controller.runActionGroup(uint8_t NumOfAction, uint16_t Times); is used to execute specific action groups uploaded from PC software and duration in seconds.
5.11 Touch Defense
5.11.1 Assembly and Wiring
5.11.2 Project Introduction
This lesson introduces posture switching for the robot, controlled via a touch sensor.
5.11.3 Project Process
5.11.4 Module Instruction
This sensor is based on capacitive sensing technology and is typically used for on/off control in electronic devices. It detects human or metal contact through a gold-plated touch surface. When no contact is made with the metal surface, the sensor outputs a high signal. When touched by a human body or metal, the output switches to a low signal.
The sensor connects to the robot via a 4-pin cable, which should be connected to the 5V, GND, D2, and D3 pins.
5.11.5 Program Download
(1) Open the program file located in the same directory as this lesson: Touch Defense Program\touch\touch.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.11.6 Project Outcome
When the metal surface of the touch sensor is touched, the robot will switch to a retracted posture upon first detection. Upon the next detection, it will enter a defensive shaking posture. If the sound sensor detects ambient sound during either the retracted or defensive state, the robot will return to its default posture.
5.11.7 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
6 7 8 9 10 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | #define rxPin 9 //arduino and servo controller's serial communication port #define txPin 8 #define DIN A0 //dot matrix port #define CLK A1 #define LED 13 #define TOUCH 2 //touch sensor port #define SOUND_PIN A2 /*IO port where the sound sensor is located*/ #define I2C_ADDR 0x77 //register #define DISDENCE_L 0//distanceis lower 8 bits, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB light modoe,0:User-defined mode 1:breathing light mode default 0 #define RGB1_R 3//R value of probe 1,0~255,default0 #define RGB1_G 4//default0 #define RGB1_B 5//default255 #define RGB2_R 6//R value of proble,0~255,default0 #define RGB2_G 7//default0 #define RGB2_B 8//default255 #define RGB1_R_BREATHING_CYCLE 9 //when breathing light mode is 1,the breathing period of probe 1,unit 100ms default0, //if set to period is 3000ms,then the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//No.2 proble #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 #define RGB_WORK_SIMPLE_MODE 0 #define RGB_WORK_BREATHING_MODE 1 Servo sonarServo; //unltrasion stastion servo control examples SoftwareSerial MySerial(rxPin, txPin); //soft serial port examples WMMatrixLed matrixLed(CLK, DIN); //dot matrix examples LobotServoController Controller(MySerial); //instantiated secondary development |
(3) Within the setup() function, I2C communication and two types of serial communication are initialized with appropriate baud rates. Several pin modes are configured, such as setting the LED pin as output and the TOUCH and SOUND_PIN pins as input. Then, the LED matrix is initialized, with its color and brightness set, and the display cleared. The servo is then configured by assigning it to a designated I/O pin and setting its initial position. After a brief delay, the servo is released. A specific action group is executed, and an RGB mode value is written via the I2C bus. Next, two RGB arrays are then configured and written to the LED matrix display.
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 | void setup() { // put your setup code here, to run once: uint8_t RGB[6]; uint8_t breathing[6]; uint8_t value; Wire.begin(); MySerial.begin(9600); //soft serial port for communication with the steering gear, baud rate 9600 Serial.begin(9600); //the hardware serial port used for printing and debugging, the baud rate is 9600 pinMode(LED, OUTPUT); pinMode(TOUCH, INPUT); pinMode(SOUND_PIN, INPUT); digitalWrite(LED, LOW); matrixLed.setColorIndex(1); matrixLed.setBrightness(3); matrixLed.clearScreen(); sonarServo.attach(12); //set the servo control io port sonarServo.write(90); //initial position 90 degrees delay(300); sonarServo.detach(); //release the servo s after use Controller.runActionGroup(0, 1); //run low-postion standing upright movements value = RGB_WORK_SIMPLE_MODE; WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { drawBuffer[i] = 0xff; matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } matrixLed.clearScreen(); } |
(4) In the loop() function, Controller.receiveHandle() is first used to process data received from the servo control board. A digital input named TOUCH is monitored to detect whether the user has triggered a touch point. If a touch state change is consistently detected, different actions will be executed based on the context. On the first touch, the robot executes a predefined action group using Controller.runActionGroup(16, 1). The action_status variable is then set to 1, indicating that the first-touch action is in progress.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | void loop() {
// put your main code here, to run repeatedly:
static uint8_t touch_status = 0;
static uint8_t action_status = 0;
static uint8_t status_ = 0;
static bool blink_status = false;
Controller.receiveHandle(); //process the data received from the steering gear control board
while (!digitalRead(TOUCH)) {
delay(20);
status_ = 1;
}
if (status_ == 1) {
status_ = 0;
touch_status = 1;
}
if (!Controller.isRunning()) {
matrixLed.clearScreen();
blink_status = false;
// Serial.print(touch_status);Serial.println(action_status);
if (touch_status == 1 && action_status == 0) {
touch_status = 0;
action_status = 1;
Controller.runActionGroup(16, 1);
}
else if (touch_status == 1 && action_status == 1){
touch_status = 0;
blink_status = true;
Controller.runActionGroup(17, 1);
}
else if (readSound() == 1) {
action_status = 0;
Controller.runActionGroup(0, 1);
}
}
else {
if (blink_status)
MatrixLedBlink(100);
}
}
|
(5) Upon a second or continuous touch, a different action group is triggered using Controller.runActionGroup(17, 1), and an LED blinking indicator is activated. This enables the use of two successive touches to trigger a specific action or command.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | void loop() {
// put your main code here, to run repeatedly:
static uint8_t touch_status = 0;
static uint8_t action_status = 0;
static uint8_t status_ = 0;
static bool blink_status = false;
Controller.receiveHandle(); //process the data received from the steering gear control board
while (!digitalRead(TOUCH)) {
delay(20);
status_ = 1;
}
if (status_ == 1) {
status_ = 0;
touch_status = 1;
}
if (!Controller.isRunning()) {
matrixLed.clearScreen();
blink_status = false;
// Serial.print(touch_status);Serial.println(action_status);
if (touch_status == 1 && action_status == 0) {
touch_status = 0;
action_status = 1;
Controller.runActionGroup(16, 1);
}
else if (touch_status == 1 && action_status == 1){
touch_status = 0;
blink_status = true;
Controller.runActionGroup(17, 1);
}
else if (readSound() == 1) {
action_status = 0;
Controller.runActionGroup(0, 1);
}
}
else {
if (blink_status)
MatrixLedBlink(100);
}
}
|
(6) Simultaneously, the system monitors for sound input using the readSound() function. If a sound signal is detected, such as a clap, the robot resets its action status and executes the default action group using Controller.runActionGroup(0, 1). The program also checks whether the controller is currently active. If it is not running or has completed all tasks, the LED display is cleared or enters a blinking state for visual feedback.
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 | void loop() {
// put your main code here, to run repeatedly:
static uint8_t touch_status = 0;
static uint8_t action_status = 0;
static uint8_t status_ = 0;
static bool blink_status = false;
Controller.receiveHandle(); //process the data received from the steering gear control board
while (!digitalRead(TOUCH)) {
delay(20);
status_ = 1;
}
if (status_ == 1) {
status_ = 0;
touch_status = 1;
}
if (!Controller.isRunning()) {
matrixLed.clearScreen();
blink_status = false;
// Serial.print(touch_status);Serial.println(action_status);
if (touch_status == 1 && action_status == 0) {
touch_status = 0;
action_status = 1;
Controller.runActionGroup(16, 1);
}
else if (touch_status == 1 && action_status == 1){
touch_status = 0;
blink_status = true;
Controller.runActionGroup(17, 1);
}
else if (readSound() == 1) {
action_status = 0;
Controller.runActionGroup(0, 1);
}
}
else {
if (blink_status)
MatrixLedBlink(100);
}
}
|
(7) The sound detection function reads analog values from the sound sensor to determine if a sound is present. If the read value exceeds the defined threshold, which is set to 150 in this section, the function returns 1, indicating sound is detected. Otherwise, it returns 0. This enables a basic yet effective method for detecting sound input.
117 118 119 120 121 122 123 124 125 126 127 128 129 | uint8_t readSound() { uint16_t temp = 0; temp = analogRead(SOUND_PIN); if (temp > 150) { // Serial.println(temp); return 1; } else return 0; } |
5.11.8 Feature Extensions
Modifying Feedback Actions Triggered by Touch
(1) By default, the program is configured to perform a defensive posture upon detecting the first touch input. If a second touch is detected while the robot is already in the defensive posture, it will trigger a shaking motion. To customize the feedback actions after touch input, adjustments can be made in the following sections of the program.
(2) The red-marked section contains the logic that checks whether the touch sensor has been activated. The green-marked section defines the action to be executed after the first touch, switching to a defensive posture. The yellow-marked section handles the behavior when the robot is already in the defensive posture, if another touch input is detected, in which case a shaking motion is performed.
(3) The function Controller.runActionGroup(uint8_t NumOfAction, uint16_t Times); is used to execute specific action groups uploaded from PC software and duration in seconds.
5.12 Edge Detection
5.12.1 Assembly and Wiring
5.12.2 Project Introduction
This lesson uses infrared obstacle avoidance sensors to detect distance and prevent the robot from falling off an edge by adjusting its movement accordingly.
5.12.3 Project Process
5.12.4 Module Instruction
The infrared obstacle avoidance sensor is used to detect whether there is an obstacle in front of it. The sensor consists of an infrared emitter and a receiver. When an object is present, the emitted infrared light is reflected back and detected by the receiver.
Connect the infrared sensors to the ports of 5V, GND, D4, D5 and 5V, GND, D6, D7 respectively.
5.12.5 Program Download
(1) Open the program file located in the same directory as this lesson: Edge Detection Program\RF\RF.ino
(2) Connect the Arduino UNO to the computer via USB cable.
(3) In the Arduino IDE, click the “Select Board” option. The software will automatically detect the connected Arduino serial port.
(4) Then click the upload button
to upload the program to the Arduino. Wait for the upload to complete.
5.12.6 Project Outcome
Note
This project should be conducted indoors. Avoid strong warm light sources such as incandescent bulbs or direct sunlight. Additionally, avoid using excessively high tables and ensure that table edges are flat and stable.
When any leg of the robot fails to detect the ground below, the robot will immediately stop, perform a backward movement, and then turn before continuing to move forward, allowing it to keep scanning the environment safely.
5.12.7 Program Brief Analysis
(1) Several libraries required for this application should be imported, including servo control, sensor, and software serial communication libraries.
5 6 7 8 9 | #include <Wire.h> #include "Servo.h" #include "WMMatrixLed.h" #include "SoftwareSerial.h" #include "LobotServoController.h" |
(2) The communication pins between the Arduino and the servo controller are first defined. Then, instances of the sensor class, software serial class, and other secondary development communication classes are created.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #define rxPin 9 //arduino and servo controller's serial communication port #define txPin 8 #define DIN A0 //dot matrix port #define CLK A1 #define RFR1 6 /*front right infrared sensor*/ #define RFL1 4 /*front left infrared sensor*/ #define GO_FORWARD 43 /*forward action group number*/ #define GO_BACK 44 /*backward action group number*/ #define TURN_LEFT 45 /*turn left action group number*/ #define TURN_RIGHT 46 /*turn right action group number*/ #define L_STAND 0 //low posture, attention #define I2C_ADDR 0x77 //register #define DISDENCE_L 0//distanceis lower 8 bits, unit mm #define DISDENCE_H 1 #define RGB_BRIGHTNESS 50//0-255 #define RGB_WORK_MODE 2//RGB light modoe,0:User-defined mode 1:breathing light mode default 0 #define RGB1_R 3//R value of probe 1,0~255,default0 #define RGB1_G 4//default0 #define RGB1_B 5//default255 #define RGB2_R 6//R value of proble,0~255,default0 #define RGB2_G 7//default0 #define RGB2_B 8//default255 #define RGB1_R_BREATHING_CYCLE 9 //when breathing light mode is 1,the breathing period of probe 1,unit 100ms default0, //if set to period is 3000ms,then the value is 30 #define RGB1_G_BREATHING_CYCLE 10 #define RGB1_B_BREATHING_CYCLE 11 #define RGB2_R_BREATHING_CYCLE 12//No.2 proble #define RGB2_G_BREATHING_CYCLE 13 #define RGB2_B_BREATHING_CYCLE 14 |
(3) Several arrays and variables are then defined. First, I2C communication and serial communication are initialized, and the baud rate for communication with the servo controller is set to 9600. Then, the sound input pin is configured as an input. The LED matrix is initialized, with its color and brightness set, and the display cleared.
275 276 277 278 | WireWriteDataArray(RGB_WORK_MODE,&value,1); RGB[0] = 0;RGB[1] = 0;RGB[2] = RGB_BRIGHTNESS;//RGB1 RGB[3] = 0;RGB[4] = 0;RGB[5] = RGB_BRIGHTNESS;//RGB2 WireWriteDataArray(RGB1_R,RGB,6); |
(4) The servo is then configured by binding it to a specific I/O port, and its initial position is set to 90 degrees. A predefined action group is executed, and a value is written to the RGB working mode via the I2C bus. Next, two RGB values are set and transmitted to the LED matrix’s RGB channels through the I2C interface.
269 270 271 272 273 | sonarServo.attach(12); //set the servo control io port sonarServo.write(90); //initial position 90 degrees delay(300); sonarServo.detach(); //release the servo s after use Controller.runActionGroup(0, 1); //run No.0 action group |
(5) A drawing buffer is then created and filled with zero values. This buffer is displayed on the LED matrix to produce a fully lit effect for a brief moment before the screen is cleared.
280 281 282 283 284 285 286 287 | uint8_t drawBuffer[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; for (int i = 0; i < 16; i++) { drawBuffer[i] = 0xff; matrixLed.drawBitmap(0,0,16,drawBuffer); delay(20); } |
(6) In the loop() function, the system first calls Controller.receiveHandle() to retrieve and process data from the serial buffer, allowing it to respond to control instructions sent via the serial port. The body() function is then called to manage robot behavior.
292 293 294 295 296 297 | void loop() { //main loop Controller.receiveHandle(); //receive processing function, fetch data from the receive buffer body(); //subject logic // Serial.print(digitalRead(RFR1)); // Serial.println(digitalRead(RFL1)); } |
(7) At the beginning of each cycle, the function checks if any action group is currently running. If not, it reads values from the front-left (RFL1) and front-right (RFR1) infrared sensors to assess the surrounding environment.
Step 1: If both sensors confirm no edge detected, the robot moves forward. The LED matrix is cleared, relevant indicators are displayed, and a timer is set to control action duration.
173 174 175 176 177 178 179 180 181 182 | case 1: //step1
if (!Controller.isRunning()) { //if no action group is running
int RFR1_VALUE = digitalRead(RFR1);
int RFL1_VALUE = digitalRead(RFL1);
if ((!RFR1_VALUE) && (!RFL1_VALUE)) { //if the front left, front right infrared sensors are not suspended
matrixLed.clearScreen();
Controller.runActionGroup(71, 1); //run forward the first step
stept = 0; //step moves to step 1
timer = millis() + 300; //delay 300ms
}
|
Step 2: If only the front-right sensor detects no drop, the robot displays a specific pattern, transitions to a designated action step, and updates its status.
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | else if ((RFR1_VALUE) && (!RFL1_VALUE)){ //if the front right infrared sensor does not detect the desktop
uint8_t drawBuffer[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
matrixLed.drawBitmap(0,0,16,drawBuffer);
laststept = 1; //the last step is assigned value is 0
rf_status= 1;
stept = 3; //step moves to step 3
timer = millis() + 200; //delay 300ms
}
else if ((!RFR1_VALUE) && (RFL1_VALUE)){ //if the front left infrared sensor does not detect the desktop
uint8_t drawBuffer[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
matrixLed.drawBitmap(0,0,16,drawBuffer);
laststept = 1; //the last step is assigned value is 0
rf_status = 2;
stept = 3; //move to step 3
timer = millis() + 200; //delay 300ms
}
else if ((RFR1_VALUE) && (RFL1_VALUE)){ //if the two infrared sensors do not detect the desktop
uint8_t drawBuffer[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
|
Step 3: The current action is stopped in preparation for the next step.
215 216 217 218 219 | case 3: //step3 Controller.stopActionGroup(); //send stop action group command stept = 4; //move to step 4 timer = millis() + 200; //delay 300ms break; |
Step 4: A reverse movement action is selected and the system prepares for the next step.
220 221 222 223 224 225 226 227 228 229 230 | case 4: //step4 matrixLed.clearScreen(); if (laststept == 0) { //if the last step is 0 Controller.runActionGroup(81, 1); //run No. 81 action group, No.81 is forward 1 step or the reverse action of No. 71 action group } if (laststept == 1) { //if the last step is 0 Controller.runActionGroup(61, 1); //run No. 61 action group, No.81 is forward s steps or the reverse action of No. 51 action group } timer = millis() + 300; //delay 300ms stept = 5; //move to step 5 break; //end switch statement |
Step 5: The robot performs a backward movement and prepares to proceed step 6.
231 232 233 234 235 236 237 | case 5:
if (!Controller.isRunning()) { //if no action group is running
Controller.runActionGroup(2, 1); //run the No.2 action group twice, and the No.2 is the backward action
timer = millis() + 300; //delay 300ms
stept = 6; //move to step 6
}
break; //end switch statement
|
Step 6: Based on the current state, the robot determines a turning direction, executes the appropriate turning action, and returns to Step 0 to begin a new cycle.
203 204 205 206 207 208 209 210 211 212 | else if ((RFR1_VALUE) && (RFL1_VALUE)){ //if the two infrared sensors do not detect the desktop uint8_t drawBuffer[16] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff , 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; matrixLed.drawBitmap(0,0,16,drawBuffer); laststept = 1; //the last step is assigned value is 0 rf_status = 3; stept = 3; //move to step 3 timer = millis() + 200; //delay 300ms } |
5.12.8 Feature Extensions
Modifying Actions Triggered by Infrared Obstacle Detection
(1) By default, the program is configured as follows:
When both infrared obstacle-avoidance sensors installed on the robot’s legs detect obstacles, the robot performs a forward movement. If either sensor fails to detect an obstacle, the robot executes a sequence of backward and turning actions.
(2) Specifically, when both sensors detect obstacles, the program sets stept = 1. When either sensor detects no obstacle, the program sets stept = 3.
(3) At stept = 3, the command Controller.stopActionGroup() is called to stop the robot’s current action. Then the program proceeds to stept = 4.
(4) If stept = 1 was not executed before reaching stept = 4, the robot runs action group 81 via Controller.runActionGroup(81, 1).
(5) If stept = 1 was previously executed, the robot instead runs action group 61 with Controller.runActionGroup(61, 1). These action groups correspond to pre-uploaded movement routines from the PC software.
(6) After completing the routine at stept = 4, the robot proceeds to stept = 5, executing a backward movement via Controller.runActionGroup(2, 1).
(7) Once the backward action is complete, the robot enters stept = 6, where it executes a turn. By default, a right turn uses Controller.runActionGroup(4, 7), or a left turn with Controller.runActionGroup(3, 7), which can be modified to any other action group as needed.
(8) By default: After completing the routine at stept = 5, the robot proceeds to stept = 6, executing a right turn via Controller.runActionGroup(4, 7). For instance, to replace the right turn with a contraction movement, the command can be changed to Controller.runActionGroup(16, 7) to trigger action group 16 at step 6.
Adjusting Infrared Sensor Sensitivity
Note
For a visual guide, refer to the video tutorial in directory of 2 Software Tools & Source Code → 5. Debug Instructions.
Each infrared obstacle-avoidance sensor is equipped with an adjustable potentiometer for setting detection sensitivity. If the detection performance is suboptimal during use, the sensitivity can be tuned using a small Phillips-head screwdriver.
Turning the red knob clockwise increases the infrared emission strength and extends the detection range. Turning it counterclockwise reduces the emission strength and shortens the detection distance.
Note
Due to the nature of the sensor, detection accuracy can be negatively affected by warm light sources, such as incandescent bulbs and sunlight, which emit significant infrared radiation. These can interfere with the sensor’s signal, so environmental lighting must be carefully considered, and adjusting the sensitivity alone may not suffice.
Sensitivity adjustment is not linear. Each sensor has a built-in threshold point that functions like a boundary. If adjusted beyond this point, the sensor may reset to its original state.
Therefore, sensitivity should be tuned based on practical requirements, rather than being maximized or minimized arbitrarily.
to upload the program to the Arduino. Wait for the upload to complete.
to upload the program to the Arduino. Wait for the upload to complete.