# 7. AI Vision Games Lesson
## 7.1 Introduction to ESP32-S3 Vision Module
### 7.1.1 Product Introduction
The **ESP32-S3 vision module** is a compact camera system capable of functioning as a minimal standalone device. It captures images with its built-in camera, processes the data using an **ESP32 microcontroller**, and wirelessly transmits the data via its **Wi-Fi module**. Supporting various communication protocols and offering low power consumption, it is widely used in various **IoT applications**.
* **Port Layout**
| **Port Name** | **Function Description** |
| :-------------: | :----------------------------------------------------------: |
| USB serial port | Used for serial communication and firmware flashing |
| Custom button | Customize the button event in the code |
| I2C port | It is the port for performing secondary development and connecting with the main controller |
* **Image Coordinate System**
We'll briefly introduce some important points about the image coordinate system of the module that users should pay attention to:
The origin is not at the center of the screen, but at the **top-left corner**.
The direction of the **Y-axis** is opposite to that of a typical Cartesian coordinate system.
(1) Image Transmission Mode
:::{Note}
The image transmission mode uses a resolution of **320×240** to match the requirements of our mobile app's image data interface.
:::
(2) Face Recognition Mode
:::{Note}
The image transmission mode uses a resolution of **240×240** to match the requirements of our mobile app's image data interface.
:::
(3) Vision line following/ Color recognition mode
:::{Note}
The vision line following/ color recognition mode uses a resolution of **160×140** to match the requirements of our mobile app's image data interface.
:::
* **Specification**
| **Parameter** | **Specification** |
| :-------------------: | :-------------------------------------: |
| Size | 59\*43\*17.5 |
| Power Supply Range | 4.75~5.25V |
| SPI Flash | Supports up to 16MB |
| RAM | 512 KB internal + 16 MB external PSRAM |
| Bluetooth | Supports Bluetooth 5 and Bluetooth Mesh |
| WiFi | 802.11 b/g/n |
| Supported Interfaces | UART、I2C |
| Serial Port Baud Rate | Default: 115200 |
| Image Output Format | JPEG (OV2640 only), BMP, Grayscale |
| Frequency Range | 2412~2484MHz |
| Antenna Type | Onboard PCB antenna |
:::{Note}
The product specifications are theoretical values provided for reference purposes only. Please refer to the actual product for confirmation.
:::
### 7.1.2 Notice
Please ensure that the module's input power is at least **5V 2A**. Insufficient power may cause image watermarks to appear.
The module comes with pre-installed firmware that supports camera feedback functionality. If vision recognition features are required, you will need to flash the corresponding firmware.
## 7.2 ESP32-S3 Library File Introduction
This section provides an analysis of the drive library for the **ESP32-S3 module**. This library is used to retrieve data on recognized faces or colors from the **ESP32-S3**. It consists of two files: hw_esp32S3cam_ctl.h and hw_esp32S3cam_ctl.cpp.
### 7.2.1 Library File Instruction
* **Member Function (HW_ESP32S3CAM::Init)**
{lineno-start=55}
```
void HW_ESP32S3CAM::Init()
{
Wire.setClock(100000);
Wire.begin();
}
```
The function initializes the **I2C bus configuration**, enabling commands to be sent and data to be received from the vision module in subsequent steps.
* **Underlying Function (Wire_Write_Data_Array)**
{lineno-start=3}
```
static bool Wire_Write_Data_Array(uint8_t addr,
uint8_t reg,
uint8_t *val,
uint16_t len)
{
uint16_t i;
Wire.beginTransmission(addr);
Wire.write(reg);
for(i = 0; i < len; i++)
{
Wire.write(val[i]);
}
if( Wire.endTransmission() != 0 )
{
return false;
}
return true;
}
```
| Wire_Write_Data_Array() | |||
| Function Description | Send data to the ESP32-S3 vision module register through the I2C bus. | ||
| Parameter List | Addr, reg, val, and len | Return Value | False:write failed; True:write succeeded. |
| Instructions for Use | Call "HW_ESP32S3CAM::Init" before using this function. This function is not used in the subsequent development. You can just know it. |
||
| Wire_Write_Byte() | |||
| Function Description | Before reading data from the ESP32-S3 vision module, confirm the address of the data register to be read. | ||
| Parameter List | val | Return Value | False:transmission failed; True:transmission succeeded. |
| Instructions for Use | Call "HW_ESP32S3CAM::Init" before using this function. When transferring or writing data, it is necessary to confirm the address of the data register to be written to the slave. The same implementation statement of this function can be found in "Wire_Write_Data_Array". |
||
| Wire_Read_Data_Array() | |||
| Function Description | Read multi-byte data from the esp32-S3 vision module through the I2C bus. | ||
| Parameter List | Reg, val, and len | Return Value | -1 : read failed; Other: the length of the data successfully read. |
| Instructions for Use | Call "HW_ESP32S3CAM::Init" before using this function. Call "Wire_Write_Byte" to confirm the address of the register to be read before using this function. |
||
| HW_ESP32S3CAM::Facedetection_Data_Receive() | |||
| Function Description | Read face recognition result from the ESP32-S3 vision module. | ||
| Parameter List | Reg, buf, and buf_len | Return Value | None |
| Instructions for Use | Essentially, it encapsulates the direct calling of the "Wire_Read_Data_Array". Its specific parameters' physical meanings are the same as the "Wire_Read_Data_Array". | ||
:::{Note}
If the device is not listed under ports, your computer may be missing the required driver. You can find the driver installation package in the folder:
"[**Apppendix->CH34x Driver (Windows Environment**)](https://docs.hiwonder.com/projects/miniAuto/en/latest/docs/resources_download.html)".
:::
(2) The camera will generate a hotspot named **"HW_ESP32S3CAM"**. Click to connect.
This connection method uses **AP (Access Point) direct mode**.
The vision module also supports **STA (Station) mode** for connecting through a local area network.
For more information, please refer to **"4. Expanded Tutorial."**
### 7.3.2 Start Image Transmission
Open a browser and enter **"192.168.5.1"** in the address bar. This works on both mobile and PC browsers.
For example, on a PC, after the page loads, click
to begin image transmission.
### 7.3.3 Live Camera Feed Firmware Flashing (Optional)
(1) Connect the ESP32-S3 to the computer.
(2) Double click and open **flash_download_tool_3.9.7** file in the "[**Appendix->Firmware Flashing Tools**](https://docs.hiwonder.com/projects/miniAuto/en/latest/docs/resources_download.html)".
(3) Then, select **"ESP32-S3"** in the opening interface.
(4) In the flashing interface, click
to select the firmware ("[**Firmware & Tool/image_transmit.bin**](https://docs.hiwonder.com/projects/miniAuto/en/latest/docs/resources_download.html)").
(5) Next, configure the settings as shown below.**Select an available port number**—this should match the actual port detected on your computer.
:::{Note}
Avoid selecting **COM1**, as it may cause the flashing process to fail.
:::
(6) Click **"ERASE"** to wipe the existing firmware—**this step must be done first**.
Once the erase process is complete, click **"START"** to begin flashing the new firmware.
(7) After a while, the **"FINISH"** prompt will come out. Then disconnect Type-C cable.
:::{Note}
After flashing is completed, the module needs to be restarted.
:::
## 7.4 Color Recognition
In this section, **miniAuto** will utilize the **ESP32-S3 vision module** to recognize **red** and **blue** blocks. The corresponding color will then be displayed on the **RGB LED** on the expansion board.
### 7.4.1 Program Flowchart
### 7.4.2 ESP32-S3 Vision Module
This is a development board integrated with the **ESP32 chip** and a camera module. After inserting the module into the carrier board, it uses the **I2C communication interface** to read color and face data via I2C.
The **ESP32-S3 vision module** is equipped with a **GC2145 camera**. It transmits the captured image data to the **ESP32 chip** via a serial interface. The chip processes the image and then transfers the data to other devices via I2C communication.
### 7.4.3 Program Download
[color_discrimination](../_static/source_code/color_discrimination.zip)
* **ESP32-S3 Vision Module Program Download**
(1) Connect the ESP32S3 vision module to the computer using the ESP32S3 cable.
(2) Open the program file [ESP32S3 Color Recognition Program/ColorDetection/ColorDetection.ino](../_static/source_code/ColorDetection.zip) .
(3) Select the **"ESP32S3 Dev Module"** as the development board.
(4) In the menu bar, click on **"Tools"**, and select the appropriate **ESP32S3 board configuration** as shown in the image below.
(5) Finally, click
to upload the code to the **ESP32S3** and wait for the flashing process to complete.
* **Arduino UNO Program Download**
:::{Note}
- Before downloading the program, please remove the Bluetooth module to prevent serial port conflicts that could cause the download to fail.
- When connecting the Type-B download cable, ensure the battery box switch is set to the "**OFF**" position. This helps avoid accidental contact with the expansion board's power pins, which could result in a short circuit.
:::
(1) Locate and open the [color_discrimination.ino](../_static/source_code/color_discrimination.zip) file.
(2) Connect the Arduino to your computer using the UNO Type-B data cable.
(3) Select the **"Board"** option. The software will automatically detect the connected Arduino's serial port. Click to establish the connection.
(4) Click
to download the program to the Arduino. Wait for the download to complete.
### 7.4.4 Program Outcome
(1) When the robot detects the color red, the RGB LED on the expansion board lights up red, the buzzer sounds once, and the robot rocks back and forth.
(2) When the robot detects the color blue, the RGB LED on the expansion board lights up blue, the buzzer sounds twice, and the robot rocks left and right.
(3) When neither the red nor blue color is detected, the RGB LED on the expansion board lights up white.
### 7.4.5 Program Analysis
[color_discrimination](../_static/source_code/color_discrimination.zip)
* **Import Library File**
Import the RGB control library and ESP32S3 communication library file required for this program.
{lineno-start=1}
```
#include
(2) Click to select the image you want to import (ensure the image is stored in the 'img' folder).
(3) Use the slider to perform HSV threshold segmentation on the image. Adjust the HSV threshold values to a suitable range. You can refer to the color range table below for guidance on making adjustments.
(4) Once the threshold values are set, save them. Then, open the '[ESP32S3 Color Recognition Program\ColorDetection\color_detection.cpp](../_static/source_code/ColorDetection.zip)' file from the same directory. Modify the color data by replacing it with the saved HSV array. Finally, follow the steps in '[7.4.3 Program Download](#anchor_7_4_3)' to flash the updated program to the ESP32-S3.
:::{Note}
Pay attention to the array element format and proper comma separation.
:::
(5) Once the flashing is complete, the ESP32 camera will be able to recognize objects of different colors.
### 7.4.7 FAQ
Q1: The colors detected by the camera are inaccurate or incorrectly identified.
Answer: To improve accuracy, try to reduce background clutter. A solid-color or simple background environment is recommended.
Q2: The vision module fails to recognize correctly after flashing the firmware.
Answer: Ensure that the correct flashing address was selected during the flashing process. Double-check the settings to confirm proper configuration.
## 7.5 Color Tracking
In this section, the car, equipped with the ESP32-S3 vision module, is programmed to track a red ball. As the ball moves, the car will rotate in place to follow its direction.
### 7.5.1 Program Flowchart
### 7.5.2 ESP32-S3 Vision Module
This development board integrates an ESP32 chip and a camera module. When inserted into the baseboard, it communicates via the I²C interface, enabling the reading of color and facial data.
The ESP32-S3 vision module features an onboard camera that captures image data and transmits it to the ESP32 chip through a serial interface. The chip processes the image and communicates the results to other devices via the I²C protocol.
### 7.5.3 Program Download
[ESP32-S3 Color Tracking Program](../_static/source_code/ColorDetection.zip)
[UNO Color Tracking](../_static/source_code/color_tracking.zip)
* **ESP32-S3 Vision Module Program Download**
(1) Connect the ESP32S3 module to the computer using the Type-C cable.
(2) Open the file "[ESP32S3 Color Detection Program/ColorDetection/ColorDetection.ino](../_static/source_code/ColorDetection.zip)" located in the same directory as this document.
(3) Select the **"ESP32S3 Dev Module"** as the development board.
(4) In the menu bar, click on **"Tools"**, and select the appropriate **ESP32S3 board configuration** as shown in the image below.
(5) Finally, click
to upload the code to the **ESP32S3** and wait for the flashing process to complete.
* **Arduino UNO Program Download**
:::{Note}
- Before downloading the program, please remove the Bluetooth module to prevent serial port conflicts that could cause the download to fail.
- When connecting the Type-B download cable, ensure the battery box switch is set to the "OFF" position. This helps avoid accidental contact with the expansion board's power pins, which could result in a short circuit.
:::
(1) Locate and open "[UNO Color Tracking/color_tracking.ino](../_static/source_code/color_tracking.zip)" program file in the same dictionary as this section.
(2) Connect the Arduino to your computer using the Type-B data cable.
(3) Select the **"Board"** option. The software will automatically detect the connected Arduino's serial port. Click to establish the connection.
(4) Click
to download the program to the Arduino. Wait for the download to complete.
### 7.5.4 Program Outcome
Once the robot is powered on, the buzzer beeps once and the RGB light on the expansion board turns white. When a red ball is placed in front of the ESP32-S3 vision module and moved, the robot will rotate in place to follow the ball's direction.
### 7.5.5 Program Analysis
[color_tracking](../_static/source_code/color_tracking.zip)
* **Import Library File**
Import the required header files for the timer, tracking actions, motor control, and ESP32-S3 vision module communication to support the game functionality.
{lineno-start=1}
```
#include "MultiTimer.h"
#include "Motor.h"
#include "hw_esp32s3cam_ctl.h"
#include "track_processing.h"
```
* **Define Pin and Create Objects**
Define two timers (currently only Timer1 is in use), an object for the vision module, and two variables to control the robot's speed and steering angle. Additionally, create an array to store the register values used for the vision module's line-tracking function.
{lineno-start=5}
```
Timers timer1;
Timers timer2;
HW_ESP32S3CAM hw_cam;
#define IMAGE_WIDTH 240
#define IMAGE_LENGTH 240
uint8_t set_speed;
uint16_t set_angle;
static uint8_t buffer[DATA_ARRAY_COUNT];
```
* **Initial Settings**
(1) In the `setup()` function, initialize the necessary hardware components. Start with the serial interface, setting the communication baud rate to 115200.
{lineno-start=33}
```
void setup() {
Serial.begin(115200);
```
(2) Initialize each module in sequence:
`ticksFuncSet(ticksGetFunc)`: Binds the system's default time-fetching function ticksGetFunc to platFormTicksFunction, which will be called to retrieve the current system time.
`Motors_Initialize()`: Initializes the motor hardware.
`hw_cam.Init()`: Initializes the ESP32-S3 vision module.
`Controller_Init()`: Initializes the motion control unit for the robot.
`timerStart(&timer1, 20, timerPIDCalculateCallBack, "20ms cycle PID calculate")`: Starts Timer1 with a 20ms interval. After 20ms, it triggers the timerPIDCalculateCallBack callback function, passing the string "20ms cycle PID calculate" as a descriptive parameter.
{lineno-start=35}
```
ticksFuncSet(ticksGetFunc);
Motors_Initialize();
hw_cam.begin();
Controller_Init();
timerStart(&timer1, 20, timerPIDCalculateCallBack, "20ms cycle PID calculate");
}
```
* **Loop Sub-function Execution**
(1) After initialization is complete, the program enters the `loop()` function. Within this loop, the `timersTaskRunning()` function is repeatedly called. This function iterates through the list of timers and executes the interrupt callbacks for any timers that have reached their trigger time.
(2) Next, the `Velocity_Controller(set_angle, set_speed, 0, SIMULATE_PWM_CONTROL)` function is called to control the robot's movement speed and direction based on the given parameters.
{lineno-start=42}
```
void loop() {
timersTaskRunning();
Velocity_Controller(set_angle, set_speed, 0, SIMULATE_PWM_CONTROL);
}
```
* **Timer Callback Function "timerPIDCalculateCallBack"**
(1) The function is used to determine if the robot has detected the target color position. This is achieved by reading the vision module's line following function register data via the `Linepatrol_Data_Receive` function. Then, control the robot's movement accordingly.
(2) If the target color is detected, the robot adjusts its movement angle, based on the deviation between the color center position and the set target tracking point position. This allows the target center position falls on the set target tracking point position.
(3) The timer starts counting for the next cycle. It works only once by default. Call `timerStart` again can set the timer to loop work.
{lineno-start=25}
```
void timerPIDCalculateCallBack(Timers *ptimer, const void *userdata)
{
hw_cam.Red_Block_Detection(buffer, sizeof(buffer)); /* red */
// printf("[%08ld] Timer:%p callback-> %s.\r\n", platformTicksGetFunc(), ptimer, (char*)userdata);
Position_Controller( buffer[0], buffer[1], IMAGE_WIDTH_SIZE / 2, IMAGE_WIDTH_SIZE / 2, &set_angle, &set_speed);
timerStart(ptimer, 20000, timerPIDCalculateCallBack, userdata);
}
```
* **Timer Monitoring Function "timersTaskRunning"**
(1) The timer list is implemented as a linked list by default. You can traverse and modify the list by using two pointers: pTimerList and entry. These pointers allow you to add or remove timer members.
(2) When a timer reaches its trigger time, it is considered invalid by the timer list and is automatically removed. To make a timer operate repeatedly, you need to call the timerStart function again, either within the callback function or multiple times, depending on the desired behavior.
{lineno-start=99}
```
int timersTaskRunning(void)
{
//将定时器列表pTimerList(注:定时器列表内各个定时器按下一次触发时间的早晚顺序排布)的地址赋给entry
Timers *entry = pTimerList;
//遍历访问定时器列表的每一个定时器
for (; entry; entry = entry->next)
{
/*如果当前定时器的下一次触发时间晚于当前系统时间(排在后面的定时器
自然也还没到下一次被触发的时间),则退出函数,结束遍历*/
if (platFormTicksFunction() < entry->deadline)
{
return (int)(entry->deadline - platFormTicksFunction());
}
//如果当前定时器到点被触发,则先将该定时器从定时器列表中移除,再执行当前定时器的触发回调函数
pTimerList = entry->next;
if(entry->timersCallBack)
{
entry->timersCallBack(entry, entry->userdata);
}
}
return 1;
}
```
* **Motor Initialization Function**
This function is used to initialize the motor pins. It calls the pinMode function within a for loop to set the motor I/O ports to output mode. After that, the Velocity_Controller function is called to stop the robot.
{lineno-start=115}
```
void Motors_Initialize(void)
{
for(uint8_t i = 0; i < 4; i++)
{
pinMode(motordirectionPin[i], OUTPUT);
pinMode(motorpwmPin[i], OUTPUT);
}
Velocity_Controller( 0, 0, 0, SIMULATE_PWM_CONTROL);
}
```
* **Robot Velocity Control Function**
This function sets the speed of each wheel on the robot. By analyzing the kinematics of the robot's Mecanum wheels, the speed of each wheel is calculated. These calculated speed values are then used as input parameters for the Motors_Set function, which adjusts the motor speed and controls the overall movement of the robot. For a detailed explanation of kinematic analysis, please refer to the relevant tutorials.
{lineno-start=84}
```
void Velocity_Controller(uint16_t angle, uint8_t velocity,int8_t rot, uint8_t mode)
{
int16_t velocity_0, velocity_1, velocity_2, velocity_3;
/* 速度因子 */
float speed = 1;
/* 设定初始方向 */
angle += 90;
float rad = angle * PI / 180;
if (rot == 0) speed = 1;
else speed = 0.5;
velocity *= invSqrt(2);
velocity_0 = (velocity * sin(rad) - velocity * cos(rad)) * speed + rot * speed;
velocity_1 = (velocity * sin(rad) + velocity * cos(rad)) * speed - rot * speed;
velocity_2 = (velocity * sin(rad) - velocity * cos(rad)) * speed - rot * speed;
velocity_3 = (velocity * sin(rad) + velocity * cos(rad)) * speed + rot * speed;
switch (mode)
{
case PWM_CONTROL:
Motors_Set(velocity_0, velocity_1, velocity_2, velocity_3);
break;
case SIMULATE_PWM_CONTROL:
_Motors_Set(velocity_0, velocity_1, velocity_2, velocity_3);
break;
default:
break;
}
}
```
* **Motor Setting Function**
This function adjusts the speed and direction of each wheel of the robot based on the input parameter values. Inside the for loop, the robot's steering is adjusted according to the calculated results. The map function is used to scale the calculated values from the range "0 to 100" to the range "pwm_min to 255." Then, the digitalWrite and analogWrite functions are called to set the motor direction and speed, respectively.
{lineno-start=66}
```
static void _Motors_Set(int16_t Motor_0, int16_t Motor_1, int16_t Motor_2, int16_t Motor_3)
{
int8_t pwm_set[4];
int8_t motors[4] = { Motor_0, Motor_1, Motor_2, Motor_3};
bool direction[4] = { 1, 0, 0, 1};///< 前进 左1 右0
for(uint8_t i; i < 4; ++i) {
if(motors[i] < 0) direction[i] = !direction[i];
else direction[i] = direction[i];
if(motors[i] == 0) pwm_set[i] = 0;
else pwm_set[i] = abs(motors[i]);
digitalWrite(motordirectionPin[i], direction[i]);
PWM_Out(motorpwmPin[i], pwm_set[i]);
}
}
```
### 7.5.6 Function Extension
(1) To switch to a different color, modify the code to detect blue. Locate the function in the code that retrieves data from the vision module and replace `hw_cam.Red_Block_Detection()` with `hw_cam.Blue_Block_Detection()` to capture blue data.
(2) After making the necessary changes, refer to "[**7.5.3 Program Download -> Arduino UNO Program Download**](#anchor_7_5_3_2)" to re-upload the program. This will enable the robot to track blue objects.
### 7.5.7 FAQ
**Question 1:** The color detected by the camera is inaccurate or misidentified.
**Answer:** To improve accuracy, minimize background distractions by using a solid-colored or simple background.
## 7.6 Vision Line Following
In this section, the robot, equipped with the ESP32-S3 vision module, is programmed to dete·ct a red wide line and move along it.
### 7.6.1 Program Flowchart
### 7.6.2 ESP32-S3 Vision Module
This development board integrates the ESP32 chip with a camera module. Once the module is inserted into the carrier board, it utilizes an I2C communication interface to read color and facial data.
The ESP32-S3 vision module features a built-in camera that captures image data and transmits it to the ESP32 chip via a serial interface. The chip processes the images and then sends the data to other devices via I2C communication.
### 7.6.3 Program Download
[line_tracking](../_static/source_code/line_tracking.zip)
* **ESP32-S3 Vision Module Program Download**
(1) Connect the ESP32S3 module to the computer using the Type-C cable.
(2) Open the file [ESP32S3 Vision Line Following Program \LineTracking\LineTracking.ino](../_static/source_code/LineTracking.zip) located in the same directory as this document.
(3) Select the **"ESP32S3 Dev Module"** as the development board.
(4) In the menu bar, click on **"Tools"**, and select the appropriate **ESP32S3 board configuration** as shown in the image below.
(5) Finally, click
to upload the code to the **ESP32S3** and wait for the flashing process to complete.
* **Arduino UNO Program Download**
:::{Note}
- Before downloading the program, please remove the Bluetooth module to prevent serial port conflicts that could cause the download to fail.
- When connecting the Type-B download cable, ensure the battery box switch is set to the "OFF" position. This helps avoid accidental contact with the expansion board's power pins, which could result in a short circuit.
:::
(1) Locate and open [Program File/UNO Line Following/line_tracking](../_static/source_code/line_tracking.zip) program file in the same dictionary as this section.
(2) Connect the Arduino to the computer with the Type-B cable.
(3) Click Library Manager on the left and import the PID library. If already installed, this step can be skipped.
(4) Select the "**Select** **Board**" option. The software will automatically detect the connected Arduino's serial port. Click to establish the connection.
(5) Click
to download the program to the Arduino. Wait for the download to complete.
### 7.6.4 Program Outcome
Once the car is powered on, it will begin to follow the red line and move along its path.
### 7.6.5 Program Analysis
[line_tracking](../_static/source_code/line_tracking.zip)
* **Import Library File**
(1) Import the required header files for the timer, tracking actions, motor control, and ESP-S3 vision module communication necessary for the game.
(2) Please note that the tracking action library used in this section differs from the one used in the previous section, "Color Tracking." Although the library files share the same name, their function implementations are different. Therefore, do not mix them.
{lineno-start=1}
```
#include "MultiTimer.h"
#include "Motor.h"
#include "hw_esp32s3cam_ctl.h"
#include "track_processing.h"
```
* **Define Pin and Create Objects**
(1) First, define the timer object, instances of the servo and vision module objects, and set the color for line following to red. The color to be tracked is a green object. Then, define the variables for the coordinate points, as well as for controlling the robot's linear speed, angular speed, and angular direction.
{lineno-start=14}
```
const static uint8_t target_point = 80;
static uint16_t set_angle = 0;
static int8_t set_rot = 0;
static int8_t set_speed = 0;
static uint8_t time_count = 0;
```
(2) Define a line-loss calibration variable to record the position of the color block, which will be used for decision-making when the line is lost. Additionally, define line-following coordinate variables to store the coordinates of the line.
{lineno-start=22}
```
static uint8_t first_calibration_data;
static uint8_t second_calibration_data;
static uint8_t first_block_data[DATA_ARRAY_COUNT];
static uint8_t second_block_data[DATA_ARRAY_COUNT];
```
* **Initial Settings**
(1) Initialize Hardware Components in the setup() Function
Begin by initializing the serial interface. Set the communication baud rate to **115200** to enable proper data transmission.
{lineno-start=89}
```
void setup() {
Serial.begin(115200);
```
(2) Initialize Each Module and Configure Timer1
Timer1 is configured to operate with a cycle time of **60ms**.
ticksFuncSet(ticksGetFunc): Binds the system's built-in ticksGetFunc—used to retrieve the current system time—to the platform-specific platFormTicksFunction. This function will be called to access the current system time during operation.
`Motors_Initialize()`: Initializes the robot's motors, preparing them for movement control.
`hw_cam.Init()`: Initializes the ESP32-S3 vision module for object recognition and tracking.
`Controller_Init()`: Initializes the control unit that manages the robot's motion control parameters.
`timerStart(&timer1, 60000, timerPIDCalculateCallBack, "60ms cycle PID calculate")`: Starts Timer1 with a 60ms cycle. Once the timer reaches the set interval, it triggers the callback function timerPIDCalculateCallBack, passing the description "60ms cycle PID calculate" as a parameter.
{lineno-start=91}
```
void setup(){
Serial.begin(115200);
ticksFuncSet(ticksGetFunc);
Motors_Initialize();
hw_cam.begin();
Calculation_Init();
timerStart(&timer1, 60000, timerPIDCalculateCallBack, "60ms cycle PID calculate");
}
```
* **Loop Call Sub-function**
After initialization, enter the main loop function, repeatedly calling the timersTaskRunning function to iterate through the timer list, check each timer that has reached its trigger time, and execute its corresponding interrupt callback.
Then, call Velocity_Controller(set_angle, set_speed, set_rot, SIMULATE_PWM_CONTROL) to control the robot’s motion speed..
{lineno-start=98}
```
void loop() {
timersTaskRunning();
Velocity_Controller(set_angle, set_speed, set_rot, SIMULATE_PWM_CONTROL);
}
```
* **Timer Callback Function "timerPIDCalculateCallBack"**
This function is used to determine whether the vehicle has detected the target color position (by reading the vision module’s line-following registers via Region1_Red_Block_Detection() and Region1_Red_Block_Detection()), and then calculate the offset along the X-axis.
{lineno-start=25}
```
/* Position coordinate calculation every 20ms */
void timerPIDCalculateCallBack(Timers *ptimer, const void *userdata)
{
int bias_average;
/* Obtain line-following coordinate parameters */
hw_cam.Region1_Red_Block_Detection(first_block_data, sizeof(first_block_data));
hw_cam.Region2_Red_Block_Detection(second_block_data, sizeof(second_block_data));
bias_average = (first_block_data[0] + second_block_data[0]) / 2;
```
Evaluate the detected color: if only the line is detected, continue line-following and save the line coordinates into variables.
```py
if(first_block_data[0] != 0 && second_block_data[0] != 0)
{
set_speed = 50;
Position_Control(&bias_average, &set_rot, &target_point);
timerStart(ptimer, 60000, timerPIDCalculateCallBack, userdata);
first_calibration_data = first_block_data[0]; /* Record block position for judgment when the line is lost */
second_calibration_data = second_block_data[0];
}
```
If the vehicle is currently in the transporting state, it may deviate from the line. In this case, position correction is required to bring the vehicle back onto the line.
```py
else if(first_block_data[0] == 0 || second_block_data[0] == 0)
{
first_calibration_data = first_block_data[0];
second_calibration_data = second_block_data[0];
set_speed = 0;
set_rot = 0;
timerStop(ptimer);
timerStart(&timer2, 100000, timerPositionCalibrationCallBack, "60ms cycle position calibration");
}
```
* **Timer Monitoring Function "timersTaskRunning"**
(1) The timer list is implemented as a linked list by default. You can traverse, add, or remove timer entries using the two pointers: pTimerList and entry.
(2) Once a timer reaches its trigger time, it is considered expired and automatically removed from the list. If you want a timer to run repeatedly, you need to call the timerStart function again—either manually or within the callback function.
```py
int timersTaskRunning(void)
{
Timers *entry = pTimerList;
for (; entry; entry = entry->next)
{
if (platFormTicksFunction() < entry->deadline)
{
return (int)(entry->deadline - platFormTicksFunction());
}
pTimerList = entry->next;
if(entry->timersCallBack)
{
entry->timersCallBack(entry, entry->userdata);
}
}
return 1;
}
```
* **Line Following Callback Function "timerPositionCalibrationCallBack"**
(1) Obtain the color information detected by the vision module using Region1_Red_Block_Detection() and Region1_Red_Block_Detection().
{lineno-start=62}
```
void timerPositionCalibrationCallBack(Timers *ptimer, const void *userdata)
{
hw_cam.Region1_Red_Block_Detection(first_block_data, sizeof(first_block_data));
hw_cam.Region2_Red_Block_Detection(second_block_data, sizeof(second_block_data));
```
(2) If the red color is detected, timer1 is restarted to continue line following.
{lineno-start=66}
```
if(first_block_data[0] != 0 && second_block_data[0] != 0)
{
timerStop(ptimer);
timerStart(&timer1, 60000, timerPIDCalculateCallBack, userdata);
}
```
(3) Otherwise, execute the line-loss routine: analyze the saved block positions to determine the appropriate linear velocity, angular velocity, and movement angles, then restart the line-loss task and repeat until the line is detected again.
{lineno-start=71}
```
else
{
if(first_calibration_data >= 80 || second_calibration_data >= 80)
{
set_angle = 0;
set_speed = 40;
set_rot = -15;
}
else if(first_calibration_data < 80 || second_calibration_data < 80)
{
set_angle = 0;
set_speed = 40;
set_rot = 15;
}
timerStart(ptimer, 100000, timerPositionCalibrationCallBack, userdata);
}
}
```
* **Motor Initialization Function**
This function initializes the motor control pins. It uses a for loop to call the pinMode function, setting each motor I/O pin to output mode. After that, the Velocity_Controller function is called to stop the robot by setting its velocity to zero.
{lineno-start=115}
```
void Motors_Initialize(void)
{
for(uint8_t i = 0; i < 4; i++)
{
pinMode(motordirectionPin[i], OUTPUT);
pinMode(motorpwmPin[i], OUTPUT);
}
Velocity_Controller( 0, 0, 0, SIMULATE_PWM_CONTROL);
}
```
* **Robot Velocity Control Function**
This function is used to set the speed of each wheel of the vehicle. By performing kinematic analysis of the Mecanum wheels, the speed of each wheel is calculated. The calculated speed values are then passed as input parameters to the Motors_Set function to adjust the motors’ rotation speeds and control the overall vehicle movement. For details on the kinematic analysis, please refer to the relevant documentation.
{lineno-start=84}
```
void Motors_Initialize(void);
/**
* @brief
* @param angle
* @param velocity
* @param rot
* @param mode
*
* @retval None
*/
void Velocity_Controller(uint16_t angle, uint8_t velocity, int8_t rot, uint8_t mode);
#endif
```
* **Motor Setting Function**
This function adjusts the speed and direction of each wheel of the vehicle based on the input parameters. Within the for loop, it first adjusts the vehicle’s steering according to the calculated results. Then, the map function is used to scale the calculated values from the range 0–100 to pwm_min–255. Finally, digitalWrite and analogWrite are used to set the motor direction and speed.
{lineno-start=67}
```
static void _Motors_Set(int16_t Motor_0, int16_t Motor_1, int16_t Motor_2, int16_t Motor_3)
{
int8_t pwm_set[4];
int8_t motors[4] = { Motor_0, Motor_1, Motor_2, Motor_3};
bool direction[4] = { 1, 0, 0, 1};///< 前进 左1 右0
for(uint8_t i; i < 4; ++i) {
if(motors[i] < 0) direction[i] = !direction[i];
else direction[i] = direction[i];
if(motors[i] == 0) pwm_set[i] = 0;
else pwm_set[i] = abs(motors[i]);
digitalWrite(motordirectionPin[i], direction[i]);
PWM_Out(motorpwmPin[i], pwm_set[i]);
}
}
```
### 7.6.6 Function Extension
(1) In this section, we demonstrate how to modify the line color detection. For instance, to change from tracking a red line to a blue line, update the coordinate retrieval functions within the position calculation callback. Replace the original functions with Region1_Blue_Block_Detection() and Region2_Blue_Block_Detection(), which correspond to the blue line detection registers.
(2) Additionally, ensure that the necessary adjustments are made in the line-loss handling function.
(3) Finally, follow the steps outlined in "[**7.5.3 Program Download**](#anchor_7_5_3)" to re-upload the modified program. This will enable the robot to track the blue line instead of the red one.
### 7.6.7 FAQ
**Question 1:** The camera detects inaccurate or misidentified colors.
**Answer:** To enhance detection accuracy, reduce background clutter. A solid-colored or simple background with minimal distractions is recommended for optimal performance.
## 7.7 Face Recognition
In this section, the ESP32-S3 vision module is used to detect faces. When a face is detected, the robot gives a slight shake and lights up a green LED as a greeting gesture.
### 7.7.1 Program Flowchart
### 7.7.2 ESP32-S3 Vision Module
This development board integrates the ESP32 chip and a camera module. Once the module is inserted into the carrier board, it utilizes the IIC communication interface to read color and facial data.
The ESP32-S3 vision module comes with an onboard camera that captures image data and sends it to the ESP32 chip via a serial interface. The chip processes the image and transmits the data to other devices via IIC communication.
### 7.7.3 Program Download
[ESP32-S3 Face Recognition Program](../_static/source_code/FaceDetection.zip)
[UNO esp32_face_recognition](../_static/source_code/esp32_face_recognition.zip)
* **ESP32-S3 Vision Module Program Download**
(1) Connect the ESP32S3 module to the computer using the Type-C cable.
(2) Open the file "[**ESP32S3 Face Recognition Program/FaceDetection/FaceDetection.ino**](../_static/source_code/FaceDetection.zip)" located in the same directory as this document.
(3) Select the **"ESP32S3 Dev Module"** as the development board.
(4) In the menu bar, click on **"Tools"**, and select the appropriate **ESP32S3 board configuration** as shown in the image below.
(5) Click
to upload the code to the **ESP32S3** and wait for the flashing process to complete.
* **Arduino UNO Program Download**
:::{Note}
- Before downloading the program, please remove the Bluetooth module to prevent serial port conflicts that could cause the download to fail.
- When connecting the Type-B download cable, ensure the battery box switch is set to the "OFF" position. This helps avoid accidental contact with the expansion board's power pins, which could result in a short circuit.
:::
(1) Locate and open [esp32_face_recognition.ino](../_static/source_code/esp32_face_recognition.zip) program file.
(2) Connect the Arduino to your computer using the Type-B data cable.
(3) Select the **"Board"** option. The software will automatically detect the connected Arduino's serial port. Click to establish the connection.
(4) Click
to download the program to the Arduino. Wait for the download to complete.
### 7.7.4 Program Outcome
Once the robot is powered on, the RGB light on the expansion board will turn white. Upon detecting a face, the ultrasonic sensor activates, the RGB light changes to green, and the robot shakes its body to greet.
### 7.7.5 Program Analysis
[UNO esp32_face_recognition](../_static/source_code/esp32_face_recognition.zip)
* **Import Library File**
Import the required Arduino, RGB, ultrasonic sensor, and ESP32-S3 vision module communication header files for the game.
{lineno-start=1}
```
#include