2023 Industrial Training Competition-Smart Logistics-Open Source

2023 Industrial Training Competition-Smart Logistics-Open Source Southwest Petroleum University (Chengdu)-SWPU Flying Team

Foreword:

Let’s talk about the results first. We placed 4th in the provincial finals and 6th in the national competition (we missed the national competition), but many teams in front of us used the kit emmm… It’s hard to comment. After all, we have been working on it for more than half a year. , I will make a record and summary here, and by the way, I will sort out the information and open source it to interested partners (I hope that future competitions will have fewer kit car models and be more fair and happy). As a blogger, my level is limited, and I must have many shortcomings. Everyone Just have fun watching it

Article directory

  • material
  • plan
    • circuit
    • Electronic control
      • basic skills:
        • button, led, buzzer
        • Motor speed closed loop
        • Direction closed loop (gyro angle acquisition + closed loop control)
        • (x,y) coordinate movement control
        • Servo control
        • Stepper motor control (trapezoidal acceleration and deceleration)
        • Robotic arm control
        • openmv communication
        • visual position correction
        • visual heading correction
      • Extra features:
        • Serial terminal
        • lvgl-gui human-computer interaction
        • fatfs file management system + cjson
    • Vision
    • mechanical
  • Thoughts

Information

gitee warehouse portal

Folder description:

lvgl_squareline_pro //lvgl’s squareline ide project

stm32_code_pro //stm32 project, based on cubemx ide

sd_files //Insert the files in the sd card of the stm32 core board (storage control parameters)

Demo video portal

I forgot to record the competition video. The actual speed of the robot in the competition is much faster than the school competition video at Station B.

Plan

Here are some cool photos first


Overall solution: In terms of hardware configuration, stm32 is used as the main control, openmv is used as the vision, the chassis is an ordinary DC encoder motor + Mecanum wheel, and the robotic arm is a classic palletizing robotic arm. Positioning relies on the encoder for integration, and then reuse OpenMV visually corrects the deviation, and is also equipped with a gyroscope for heading angle feedback, but there are also errors that require visual correction.

Circuit

Homemade power module, 12V input, PMOS as power switch, 12 shunt to power the motor, 6V output to power the servo, 3.3V/5V output to power the sensor module

Core board expansion board, lead out the pins used, onboard buttons, buzzer, LED

Specially designed interface PCB centralizes all sockets for easy wiring and easy disassembly and assembly

Electronic control

The robot control function relies on stm32. I am using stm32F07ZGT6. For the purpose of learning, in addition to the basic functions of real competition tasks, I also implemented some other functions to expand skill points. If you are reading this article, you just To start playing games, you only need to be able to implement basic functions, and there is no need to worry about expanding functions. This project uses freertos, lvgl, fatfs32 file management system, cjson and other third-party function packages around stm32. The following is a description of each function and its corresponding Let’s give a brief introduction to the project files, and the specific source code is stored in the previous open source warehouse.

Basic functions:

Achieving basic skills is enough to complete the competition tasks well

Button, led, buzzer
stm32_code_pro/User/my_lib/button.c
stm32_code_pro/User/my_lib/led.c
stm32_code_pro/User/my_lib/beep.c

The most basic ones are buttons, LEDs, and buzzers, which are used for human-computer interaction. Tips and LED flashing are still necessary. You can observe whether the system crashes at the first time, which is convenient for debugging.

Motor speed closed loop
stm32_code_pro/User/my_lib/motor.c

The first thing to control the chassis is to control the motor speed. I use the incremental pid (PI) speed closed loop. There are a lot of online tutorials on pid control, which I won’t introduce here. The core implementation is only a few lines of code. It is still relatively simple. Because we need to control four motors, we define a motor control structure and set an array in advance to store four motor control blocks.

/// @brief Incremental PID speed control
/// @param pMotor
static void SpeedControlOne(Motor_Type* pMotor, uint16_t PassTick_ms)
{
    if(pMotor->PID.PIDCtrl_Flag)
    {
        pMotor->PID.Present = pMotor->Speed;
        pMotor->PID.Bias = pMotor->PID.Target - pMotor->PID.Present;
        //Divide by the sampling time to reduce the impact of changes in sampling time
        pMotor->PID.Output + = (pMotor->PID.Kp*(pMotor->PID.Bias-pMotor->PID.LastBias) + pMotor->PID.Ki*pMotor->PID.Bias)/PassTick_ms;
        pMotor->PID.LastBias = pMotor->PID.Bias;
        //Limiting
        if(pMotor->PID.Output < -pMotor->PID.OutLimit){
            pMotor->PID.Output = -pMotor->PID.OutLimit;
        }else if(pMotor->PID.Output > pMotor->PID.OutLimit){
            pMotor->PID.Output = pMotor->PID.OutLimit;
        }

        MotorSetPwm(pMotor->MotorId, (int8_t)pMotor->PID.Output);
    }else
    {
        MotorSetPwm(pMotor->MotorId, 0);
    }
}
Direction closed loop (gyro angle acquisition + closed loop control)
stm32_code_pro/User/wit_c_sdk/jy901.c
stm32_code_pro/User/my_lib/car_ctrl.c

Even if the speeds of the four motors are exactly the same, it will not be able to walk straight for a long time due to problems with the mechanical structure such as slipping. Moreover, we use DC motors instead of stepper motors. Even if there is a speed closed loop with four wheels turning, it will not be possible. It can’t be exactly the same, so we have to add directional feedback for angle control. We use the angle sensor of Vetter Intelligence, which comes with its own calculation and serial communication to obtain the angle, and then performs closed-loop control based on the feedback angle. The position used here Formula pid(PD). In order to prevent the vehicle from continuously adjusting oscillation due to small angular deviation when the vehicle is stationary, an error allowance is introduced here. When the error is less than this range, the output is forced to 0.

/// @brief positional, direction pid control
/// @param PassTick
static void AnglePID_Ctrl(uint16_t PassTick)
{
    static uint8_t flag =0;
    if(IsIMU_Start() & amp; & amp; !flag) //Use the IMU initialization angle as the initial angle of the car
    {
        flag =1;
        AnglePID.Target = GetYaw();
        // MY_LOGD("car", "angle pid tar->%.1f", GetYaw());
    }
    else if(!IsIMU_Start())
    {
        return;
    }

    AnglePID.Present = GetYaw();
    AnglePID.LastBias + = AnglePID.Bias; //last_bias is used as bias accumulation item
    AnglePID.Bias = AnglePID.Target - AnglePID.Present;
    if(AnglePID.Bias >= 180) AnglePID.Bias -= 360;
    else if(AnglePID.Bias <= -180) AnglePID.Bias + = 360;

    //Avoid in-situ oscillation caused by angle adjustment when the car is static
    if(fabs(AnglePID.Bias)<fabs(AnglePID.BiasAllow) & amp; & amp; fabs(coord_ctrl.DisPID.Bias) < fabs(coord_ctrl.DisPID.BiasAllow)){
        AnglePID.Output = 0;
         AnglePID.LastBias = 0;
         AnglePID.BiasSum = 0;
    }
    else{
        AnglePID.BiasSum + = AnglePID.Bias;
        AnglePID.Output = AnglePID.Kp*AnglePID.Bias + AnglePID.Ki*AnglePID.BiasSum;
    }
    //Limiting
    if(AnglePID.Output > AnglePID.OutLimit) AnglePID.Output = AnglePID.OutLimit;
    else if(AnglePID.Output < -AnglePID.OutLimit) AnglePID.Output = -AnglePID.OutLimit;
}
(x,y) coordinate movement control
stm32_code_pro/User/my_lib/car_ctrl.c

Speed control and direction control have been implemented previously. When performing speed closed-loop control, we can also record the mileage (encoder integral) of each motor. According to the moving characteristics of the wheat wheel car, we can calculate the The speed of each motor can also be used to deduce its travel distance in the x/y directions based on the mileage of each motor. Based on this, the coordinate movement of the car can be controlled. In order to make the displacement smoother, we use acceleration and deceleration. Control. The principle of acceleration and deceleration is also very simple. You should still remember a formula from high school physics “v2 = 2ax”. The maximum speed “v” and acceleration “a” are all defined by ourselves. According to this formula, the acceleration and deceleration distance can be calculated, and then the speed is controlled based on the current traveling distance. The code here is relatively complicated. Please refer to the source code for the specific implementation.

void SetMoveCoord(float x, float y) //Set the target movement position and calculate the control parameters, including acceleration and deceleration distances
static void MotorDistance2Car() //Calculate the moving distance based on the mileage of each motor
static void CoordPID_Ctrl(uint16_t PassTick) //Coordinate displacement control
Servo control
stm32_code_pro/User/my_lib/steer.c

The steering gear control is originally relatively simple. You can control the angle by giving a pwm. However, in order to make the robot arm control more smooth, the angle step change method is used here, that is, the steering gear is controlled to change a certain angle every interval to avoid angle changes. The changes are too drastic.

void SteerTask(void* param)
{
    SteerInit();
    while(1)
    {
        if(!steerEnFlag){ //The servo is not automatically enabled after power-on by default
        __HAL_TIM_SET_COMPARE( & amp;MAIN_STEER_TIM, MAIN_STEER_CHANNEL, 0);
        __HAL_TIM_SET_COMPARE( & amp;SECOND_STEER_TIM, SECOND_STEER_CHANNEL, 0);
        __HAL_TIM_SET_COMPARE( & amp;TONG_STEER_TIM, TONG_STEER_CHANNEL, 0);
        __HAL_TIM_SET_COMPARE( & amp;TURN_STEER_TIM, TURN_STEER_CHANNEL, 0);

        vTaskDelay(10);
        continue;
        }


        if(steers[0].state || steers[1].state || steers[2].state || steers[3].state)
        {
            for(uint16_t i=0; i<STEER_NUM; i + + )
            {
                if(!steers[i].state){ //The working state is not set, exit
                    continue;
                }

                if((GetSysTick()-steers[i].last_tick) >= steers[i].step_tick){
                    steers[i].last_tick = GetSysTick();
                }
                else{
                    continue; //Exit before time is up
                }

                // MY_LOG_Print("\r\\
sta:%d tick:%d", sta, steers[i].step_tick);

                if(steers[i].pre_angle == steers[i].tar_angle){ //The target angle has been reached, exit
                    steers[i].state = 0;
                    continue;
                }
                else if(fabs(steers[i].pre_angle-steers[i].tar_angle) < steers[i].step_angle){
                    steers[i].pre_angle = steers[i].tar_angle;
                    steers[i].state = 0;
                }
                else if(steers[i].tar_angle > steers[i].pre_angle){
                    steers[i].pre_angle + = steers[i].step_angle;
                }
                else
                {
                    steers[i].pre_angle -= steers[i].step_angle;
                }
                SteerAngle2PWM(i, steers[i].pre_angle);
            }
            vTaskDelay(2);
        }
        else{
            vTaskDelay(20);
        }
    }
}
Stepper motor control (trapezoidal acceleration and deceleration)
stm32_code_pro/User/my_lib/step_motor.c
stm32_code_pro/User/my_lib/step_trape.c

We use a closed-loop stepper motor driver (no lost steps) and pulse control. Although we use a closed-loop drive, in order to make the robot arm start and stop more smoothly, we use a trapezoidal deceleration control algorithm. About the algorithm principle As for the specific implementation, you can refer to this blog stepper motor trapezoidal acceleration and deceleration.

Robotic arm control
stm32_code_pro/User/my_lib/arm.c

We use a palletizing robot arm. The robot arm coordinate solution is relatively simple. For specific principles, please refer to the robot arm solution.

void Inverse(arm_t* _arm)
{
float L, LL, LV;
float gama, alpha, beta;
    if (_arm->x == 0 & amp; & amp; _arm->y >0) { //Avoid the dividend being zero
        _arm->J1 = 90;
        L = _arm->y;
    }
    else if (_arm->x == 0 & amp; & amp; _arm->y < 0) {
        _arm->J1 = -90;
        L = -_arm->y;
    }
    else {
        if(_arm->x > 0){
            _arm->J1 = atan(_arm->y / _arm->x);
            L = _arm->x / cos(_arm->J1);
            _arm->J1 = PI2AG(_arm->J1);
        }
        else{
            _arm->J1 = atan(_arm->y / _arm->x);
            L = fabs(_arm->x / cos(_arm->J1));
            _arm->J1 = PI2AG(_arm->J1);
            if(_arm->y > 0){
                _arm->J1 + = 180;
            }
            else{
                _arm->J1 -= 180;
            }
        }

    }

    LL = sqrt((L - _arm->L3) * (L - _arm->L3) + (_arm->z - _arm->L0) * (_arm->z - _arm->L0));
    gama = acos((_arm->L1 * _arm->L1 + _arm->L2 * _arm->L2 - LL * LL) / (2 * _arm->L1 * _arm->L2));
    gama = PI2AG(gama);

    alpha = acos((_arm->L1*_arm->L1 + LL*LL - _arm->L2*_arm->L2) / (2*LL*_arm->L1));
    alpha = PI2AG(alpha);

    LV = sqrt(_arm->z*_arm->z + (L-_arm->L3)*(L-_arm->L3));
    beta = acos((LL*LL + _arm->L0*_arm->L0 - LV*LV) / (2*LL*_arm->L0));
    beta = PI2AG(beta);
    _arm->J2 = 360 - beta - alpha - 90;
    _arm->J3 = _arm->J2 - gama;
}
openmv communication
stm32_code_pro/User/my_lib/communication.c

In addition to identifying the color of objects, openmv also needs to complete the function of position and heading correction, which involves different types of data transmission. Therefore, the communication between stm32 and openmv cannot rely on a single character for communication, so we have separately specified a Communication protocol “frame header + data length + data id + data 1 + data 2 + … + data n + check code”, the verification uses the common CRC verification method. In this way, openmv can send freely with stm32 The content of the data only needs to be interpreted in a predetermined way.

Visual position correction
stm32_code_pro/User/my_lib/car_ctrl.c
stm32_code_pro/User/my_lib/route.c

The coordinate displacement control implemented previously can only move to an approximate position, and there will inevitably be errors. Therefore, openmv recognizes special elements on the track (such as rings, right angles) to adjust the position according to the x/y offset of the camera center distance from the special point. The displacement is used to control the movement of the vehicle in the x/y direction.

/// @brief position correction pid control
/// @param PassTick
static void PosAdjustPID_Ctrl(uint16_t PassTick)
{
    if(gDistenceCtrl){ //When performing position correction, distance pid control should be stopped
        MY_LOGE("car", "distance pid is run when pos adjust");
        return;
    }
    Pos_PID.Bias =sqrt(pos_adjust.x_bias*pos_adjust.x_bias + pos_adjust.y_bias*pos_adjust.y_bias); //Calculate the deviation distance from the coordinates
    if(fabs(Pos_PID.Bias) <= fabs(Pos_PID.BiasAllow)){ //Avoid oscillation in place
        Pos_PID.Output = 0;
    }
    else{
        Pos_PID.Output = Pos_PID.Kp*Pos_PID.Bias;
    }
    Pos_PID.LastBias = Pos_PID.Bias;
    //Output limiting
    if(Pos_PID.Output > Pos_PID.OutLimit)
    {
        Pos_PID.Output = Pos_PID.OutLimit;
    }else if(Pos_PID.Output < -Pos_PID.OutLimit)
    {
        Pos_PID.Output = -Pos_PID.OutLimit;
    }

    double rad;
    if(pos_adjust.x_bias == 0){
        if (pos_adjust.y_bias > 0) rad = PI/2;
        else rad = -PI/2;
    }
    else{
        rad = atan(pos_adjust.y_bias/pos_adjust.x_bias);
        if(pos_adjust.x_bias<0 & amp; & amp; pos_adjust.y_bias>=0)
            rad + = PI;
        else if(pos_adjust.x_bias<0 & amp; & amp; pos_adjust.y_bias<0)
            rad -= PI;
    }
    float x_speed, y_speed;
    x_speed = Pos_PID.Output*cos(rad);
    y_speed = Pos_PID.Output*sin(rad);
    //Set the speed (the angle loop control still exists, using parallel output)
    CarMotorSpeed[0] + = (-x_speed + y_speed);
    CarMotorSpeed[1] + = (-x_speed-y_speed);
    CarMotorSpeed[2] + = (-x_speed + y_speed);
    CarMotorSpeed[3] + = (-x_speed-y_speed);
}
Visual heading correction
stm32_code_pro/User/my_lib/route.c

The other part is heading correction. Since the gyroscope will drift in heading angle after working for a long time, in order to control the heading angle error range, it is necessary to rely on openmv to identify the straight line elements on the track and compare the angle deviation to adjust the heading.

/// @brief cooperates with openmv to complete heading angle correction
/// @param
static void YawAdjust(void)
{
    MY_LOGI("OV", "start yaw adjust");

    IsEnableDistenceCtrl(0); //Turn off distance correction
    
    ResetInfo();
    CommunicationTrans(YAW_ADJUST, NULL, 0); //Continuous communication correction
    while(1)
    {
        while(xSemaphoreTake(com_receive_sem, 1000) != pdTRUE)
        {
            MY_LOGW("com", "No information was obtained");
            MY_LOG_Print("crc-> [%0x]-[%0x]\r\\
", com_infor.crc, CRC16_Check(com_infor.infor_buf, com_infor.infor_len));
            MY_LOGI("OV", "send YAW_ADJUST id");
            CommunicationTrans(YAW_ADJUST, NULL, 0);
        }

        if(com_infor.id == OV_STOP){ //openmv actively stops communication
            MY_LOGI("ov", "yaw adjust finish");
            ResetInfo();
            IsEnableDistenceCtrl(1); //Restore distance correction
            return;
        }
        else if(com_infor.id != YAW_ADJUST){
            MY_LOGW("ov", "id[%d] is wrong", com_infor.id);
            IsEnableDistenceCtrl(1); //Restore distance correction
            return;
        }
        
        // x_bias = com_infor.infor_buf[0]? (-com_infor.infor_buf[1]):com_infor.infor_buf[1];
        // y_bias = com_infor.infor_buf[2]? (-com_infor.infor_buf[3]):com_infor.infor_buf[3];
        float adjustAngle = (float)com_infor.infor_buf[1] + (float)com_infor.infor_buf[2]/10.0f;
        adjustAngle = com_infor.infor_buf[0]? (-adjustAngle):adjustAngle;

        SetCarTurnAngle(adjustAngle); //Turn
        vTaskDelay(20); //Release control
        MY_LOG_Print("\r\\
adjust angle: %.1f", adjustAngle);
        if(fabs(adjustAngle) <= AnglePID.BiasAllow){
            MY_LOGW("route","adjust angle[%.1f] < bias[%.1f]", adjustAngle, AnglePID.BiasAllow);
        }
        while(!IsCarReady()){
            vTaskDelay(20);
        }
    }
}

Extra features:

As an electronics DIY enthusiast, of course I cannot just limit myself to completing competition tasks. For the purpose of learning techniques and designing perfect works, I have also added some additional non-essential functions.

Serial terminal
stm32_code_pro/User/my_lib/m_shell.c

In order to facilitate debugging, a simple serial port terminal that imitates a shell console is implemented. Command parameters can be sent through the serial port tool (I use putty) for robot control. Of course, the function I wrote is relatively simple, and there are more functions online You can check out the powerful open source serial port terminal library.

lvgl-gui human-computer interaction
intelligent-logistics-chassis/stm32_code_pro/User/GUI //stm32 code
intelligent-logistics-chassis/lvgl_squareline_pro //lvgl-squareline ide project

The stm32 core board I bought comes with a touch screen. It would be a waste not to use it. On the one hand, in order to learn something new, and on the other hand, in order to make the work more advanced, I used lvgl to make a touch screen interactive interface, which can be used to control the robotic arm. , do some parameter debugging, etc.


fatfs file management system + cjson
intelligent-logistics-chassis/ sd_files //SD card stores files
intelligent-logistics-chassis/stm32_code_pro/User/cJson //cjson library
stm32_code_pro/User/my_lib/file_info.c //Implement file reading and writing functions

Several controllers were mentioned earlier, and there are many fixed parameters that need to be frequently debugged and modified. In addition, parameters such as the robot arm action group and the vehicle movement distance need to be frequently modified. On the one hand, in order to avoid frequent parameter modifications that lead to frequent downloads Program, on the one hand, in order to make the functions of the work more powerful and complete, a file management system was added, using the cjson format for file storage and analysis. Every time I modify these data, I only need to modify the files in the SD card. This is my most important Value functions, when the final proposition changes, it will be extremely convenient to reorganize the functions.

This is a path file. When STM is powered on, it is read and stored in the form of a linked list. After starting the competition mode, it will be executed in the order of the linked list. “coord” represents the movement distance, “angle” represents the rotation angle after the movement distance is completed. “event” represents the event number (not as good as arriving at the QR code, disk grabbing, etc.)

This is the robot arm action group file, “1/2/3/4…” is the action number defined in advance, and the stored content is the x/y/z coordinates of the front end of the robot arm, as well as the opening and closing status of the hand, etc.

Visual

pending upgrade

Mechanical

pending upgrade

Thoughts

This paragraph records the game experience

At the end of the first semester of my sophomore year, that is, at the beginning of 2023, my teammates invited me to form a team to participate in the 2023 Industrial Training Competition-Smart Logistics Project. I originally thought that I would only need to be responsible for a small part of the tasks, but I immediately agreed for the purpose of mixed prizes. (Later on, he became the main force and couldn’t mess around. O(∩_∩)O haha~). The formal preparations began in the middle of the second semester of my sophomore year (around April 2023). After determining the general plan, I began to use existing materials to build it. Feasibility of vehicle model chassis verification scheme.

We soon encountered the first problem. The Mecanum wheel chassis we built could not maintain linear motion when moving sideways (laterally) and always shifted to one side. This problem puzzled me for about a week. During this period, I always thought it was a problem with the mechanical structure. Finally, after various tests failed, with the mentality of giving it a try, I changed the original figure-eight-shaped installation of the wheat wheel to an X-shaped installation, and the problem of lateral movement suddenly disappeared. Solved, this is my first time using a McLun car model. The blog posts I read before only mentioned that there are two ways to install the McLun car model, but they did not mention the disadvantages of this figure-eight installation method. What are the specific solutions? The matter is still unclear, anyway, just use the X-shaped installation… Then the most embarrassing situation I encountered was that four or five pieces of the stm32 core board (70 to 80 yuan) were burned out, mainly due to the structure of the car model. Aluminum alloy is easy to conduct electricity but the insulation treatment is not in place…

The provincial competition was held on the 28th and 29th of October 2023. The final result was 4th in the provincial finals and 6th in the national selections. The selections were actually the same as the rules of the finals, but there were mistakes in the selections. Finally, I missed the national competition (the top four in the selection can go to the national competition). The two days and two nights of the provincial competition were also extremely exciting. On the night of the report on the 27th, I found that the visual stability was not good after changing the venue, so I paved the track in the hotel and modified it overnight. strategy to reduce visual dependence. I didn’t finish work until 5 a.m. and only slept for two hours. During the preliminary competition the next day (28th), there was a problem with the scanning code (it was finally found out that the scanning module was not fixed properly and the position was wrong. (no code), I was frustrated. I took the score sheet and was about to sign to confirm the end of the competition. Suddenly the car scanned the QR code and started moving. After that, it ran normally and entered the finals. Two words – “exciting”, but This wasn’t over yet. During our team’s game, the sun suddenly shone brightly, and strong light shone into our track map, directly interfering with our visual recognition. Fortunately, the referee allowed volunteers to help us block the light, otherwise we would have to Sent. I was given a few hours of debugging time on the night of the 28th. The debugging was originally fine, but a bug appeared before the debugging time was almost over. I have encountered it before, but the probability of it happening is extremely low because it cannot be reproduced. I didn’t go to troubleshoot the problem. This time it happened twice in a row. I panicked and my heart was beating fast. But the venue was crowded and I couldn’t go to test and troubleshoot anymore. Before the finals the next day, my heart was in doubt. Fortunately, I was lucky and there were no problems in the finals. Everything was normal. Unfortunately, there was a problem with the color recognition in the trials. In addition, the order of grabbing the QR code colors was not good, and too much time was wasted on the disk. , did not complete the task within 5 minutes.

The Sichuan Provincial Competition is actually quite unreliable. The size of the QR code did not follow the rules, which led to many teams in the previous batch of competitions failing to successfully scan the code. It was quite funny. Apart from the time limit, there was not much difference between the finals and the preliminary round. I don’t know what the significance is. , the national competition selection competition was another final competition, with a mysterious operation. There were many identical car models at the competition, some were from the same school, and some were slightly modified kit car models, and the host committee did not care. The key was that they were among the top teams. Kit car model used by several teams…not good review

Although it has stopped at the provincial competition, the robot our team built from scratch has gone through two generations of optimization, and the final effect is still good, but there is still a gap in stability and accuracy compared with the kit car model. From start to finish , which lasted for more than half a year, I gained a lot. I not only learned and strengthened my skills, but also added a lot of fun to the boring university study life. We are able to do this thanks to the strong support of our instructors, who gave us The mechanical design of the robot provided a lot of guidance, and it also provided strong financial support. Of course, the contributions of my other two teammates are also indispensable (one is engaged in openmv vision, one is engaged in mechanical mechanism, and I am responsible for robot control + overall strategy + circuit design)