### Project Introduction
Topic F of the 2021 National Electronics Competition: Intelligent Medicine Delivery Cart. The image processing part is the H750 core board equipped with OPEMMV, the main controller is the F401 single-chip microcomputer, and the motor drive, power supply module and other parts are already available.
This open source project open-sources the motor drive circuit and PCB, and has open-sourced the image processing and control solutions.
Let's take a look at the basic requirements of the topic:
![wCB6ApoNmQwUzfLSfMdUpMTwQY86HPLl7ChtwSJk.png]

![QQ screenshot 20211217133723.png]

Analysis: To realize the automatic recognition of ward numbers and road information by the intelligent car, the car needs to have an image recognition module. Here we choose the H750 single-chip microcomputer core board equipped with OPENMV (see the following text for a detailed analysis of the image processing part). The results of image processing communicate with the main control microcontroller through serial communication, and control the movement of the intelligent car according to the requirements of the topic.
In addition, each requirement has a specified completion time, and speed is the key to success. Our team chose the "tricycle" structure: two main drive wheels and a passive universal wheel. This structure can make the car move more flexibly and has more advantages in right-angle turns and return to the original position. The drive module that drives the two DC motors is the DRV8701 module. The specific circuit and analysis are as follows.
- - -
### Project Function Introduction
* The power supply part of the car uses a 12V aircraft model battery, which is stepped down to 3.3V through the DCDC step-down module to power the microcontroller and other modules;
* Use the DRV8701 motor drive module (see the project file for details);
* The image processing part uses the H750 core board equipped with OPENMV, and the recognition scheme is template matching;
### Circuit Explanation The driver chip we chose for
the motor drive part
is the DRV8701 of **Texas Instruments**, a brushed DC motor full-bridge gate driver, which has the advantages of wide input voltage, convenient and flexible control, and small package size.
DRV8701 uses an H-bridge circuit composed of 4 QN3109 N-channel MOS tubes and some peripheral circuits to realize single-channel DC motor control. See the figure below for the actual picture.
This schematic is drawn according to the official data sheet of DRV8701, and the motor chopping current is about 3.25A. When powered by a lithium battery (about 12V), it can drive the DC motor of model MG513 well.
![QQ screenshot 20211215164002.png]

In this system, the total power supply comes from a lithium battery (voltage is about 12V), and the peripheral circuits such as the microcontroller and motor drive require a working voltage of about 3.3V, which requires a buck module.
At the same time, due to the need to power two microcontrollers and two motor drive modules, the working current and working stability of the buck module are not small.
After many selections, we chose the SY8303 DCDC buck chip, which has the advantages of wide input voltage, high switching frequency, and small package size. The actual circuit diagram of the SY8303 buck module is shown in the figure below.
![QQ screenshot 20211215164238.png]

- - -
### Software
main control program part:
basic part single-car medicine delivery mode and performance part The main control microcontroller program flow chart under the double-car medicine delivery mode is shown in the figure below.
![QQ screenshot 20211215164635.png]

Although the title puts forward the requirement that the body projection cannot cross the line, in fact, as long as the body can track along the red solid line, the effect of not crossing the line can be achieved. Therefore, the first task of the microcontroller is to be able to track along the line; secondly, the visual part is the eye of the microcontroller. When the sensor is limited, all the information that the vision can provide must be used in a timely and fully effective manner. Therefore, data transmission is also an important task of the microcontroller; in addition, some debugging logs need to be output and debugging data printed during the debugging process, which is also an important task of the microcontroller.
To sum up, these tasks of the microcontroller are mainly divided into two categories: one is the complex foreground line-following task, and the other is the background data transmission task (including data transmission with the visual part and the host computer).
The first is the foreground task: the entire process of completing the task is actually a process of constantly switching between multiple different complex states. Therefore, the overall foreground business program adopts the program architecture of the finite state machine to more conveniently display and realize the relationship between each state and the task content of each stage.
Next is the background task: in addition to data transmission, the background task also updates some important control quantities. In view of the large number of background tasks and strong periodicity, we reused the timing resources of a timer, adopted the program architecture of time slice polling, implemented a simple "castrated version of the operating system", and then put different tasks into their respective tasks, and performed time slice polling of different tasks in the timer.
Image recognition program part:
The image is responsible for tracking, digital recognition, judging the direction of steering, etc. The specific flow chart is shown in the figure below
! [QQ screenshot 20211215165019.png]

1) Automatic tracking
Straight line tracking mainly performs edge detection and Hough line detection on the red straight line in the center of the track (the effect after processing is shown in Figure 6). After the straight line is detected, the offset of the center x coordinate of the straight line relative to the center coordinate of the image is calculated and sent to the single-chip microcomputer. The single-chip microcomputer applies the offset to the speed of the two wheels through PID calculation, and realizes the rotation of the car through the two-wheel differential, and automatically follows the direction of the red solid line to realize automatic path finding.
The second part of the tracking part is the recognition of right-angle intersections. The basic steps are the same as straight line recognition. Finally, the angle between the two straight lines and the intersection of the two straight lines are compared to lay the foundation for digital recognition. The cross recognition effect is shown in the figure below
! [QQ screenshot 20211215165144.png]

2) Digital recognition
The digital recognition in this system uses the template matching function in OpenMV, which can automatically match patterns that are basically the same size and angle as the template image. After confirming the ward number, the corresponding digital image stored in the microcontroller flsah in advance will be used as the template image. When encountering an intersection, the image captured by the camera is matched with the target number for template matching. If the match is successful, the position of the corresponding number is recorded and compared with the X coordinate of the center of the cross to determine the turning direction of the car, and then a turning command is sent to the microcontroller. The digital recognition effect is shown in the figure (taking the recognition of the number 4 as an example).
![QQ screenshot 20211215165235.png]

Image processing partDigital recognition part code:
``` C
def find_single_num(img,num,y_thre): #Find a numberif
(num==3):
for temp in template3:
r3=img.find_template(temp, 0.7, step=1, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if(r3):
if(r3[1]+r3[3]/2>y_thre):
black_num=0
for x in range(r3[0],r3[0]+r3[2]):
if img.get_pixel (x,int(r3[1]+r3[3]/2))<40:
black_num+=1
if(black_num>2):
img.draw_rectangle(r3)
return r3[0]+r3[2]/2
elif (num==4):
for temp in template4:
r4=img.find_template(temp, 0.7, step=1, search=SEARCH_EX)#, roi=(10, 0, 60, 60))
if(r4):
if (r4[1]+r4[3]/2>y_thre):
black_num=0
for x in range(r4[0],r4[0]+r4[2]):
if img.get_pixel(x,int(r4[1]+r4[3]/2))<40:
black_num+=1
if(black_num> 2):
img.draw_rectangle(r4)
return r4[0]+r4[2]/2
elif(num==5):
for temp in template5:
r5=img.find_template(temp, 0.7, step=1, search= SEARCH_EX) #, roi=(10, 0, 60, 60))
if(r5):
if(r5[1]+r5[3]/2>y_thre):
black_num=0
for x in range(r5[0] ,r5[0]+r5[2]):
if img.get_pixel(x,int(r5[1]+r5[3]/2))<40:
black_num+=1
if(black_num>2):
img.draw_rectangle(r5)
return r5[0]+r5[2] /2
elif(num==6):
for temp in template6:
r6=img.find_template(temp, 0.7, step=1, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if(r6 ):
if(r6[1]+r6[3]/2>y_thre):
black_num=0
for x in range(r6[0],r6[0]+r6[2]):
if img.get_pixel(x, int(r6[1]+r6[3]/2))<40:
black_num+=1
if(black_num>2):
img.draw_rectangle(r6)
return r6[0]+r6[2]/2
elif(num==7):
for temp in template7:
r7=img.find_template(temp, 0.7, step=1, search=SEARCH_EX) # , roi=(10, 0, 60, 60))
if(r7):
if(r7[1]+r7[3]/2>y_thre):
black_num=0
for x in range(r7[0],r7[ 0]+r7[2]):
if img.get_pixel(x,int(r7[1]+r7[3]/2))<40:
black_num+=1
if(black_num>2):
img.draw_rectangle(r7)
return r7[0]+r7[2]/2
elif(num==8):
for temp in template8:
r8=img.find_template(temp, 0.7 , step=1, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if(r8):
if(r8[1]+r8[3]/2>y_thre):
black_num=0
for x in range(r8[0],r8[0]+r8[2]):
if img.get_pixel(x,int(r8[1]+r8[3]/2))<40:
black_num+=1
if(black_num >2):
img.draw_rectangle(r8)
return r8[0]+r8[2]/2
return 0
````
- - -
### Image processing part Crossroad recognition part code:
``` C
def check_cross(img): #Crossroad recognition
left_y=0
right_y=0
for blob in img.find_blobs([(100,200)], pixel_threshold=500,merge=True, margin=5,roi=(0,0,60,120)):
img.draw_rectangle(blob.rect())
left_y=blob.cy()
img.draw_cross(blob.cx(), blob.cy())
for blob in img.find_blobs([(100,200)], pixel_threshold=500,merge=True, margin=5,roi=(100,0,60,120)):
img.draw_rectangle(blob.rect())
right_y=blob.cy( )
img.draw_cross(blob.cx(), blob.cy())
if(left_y and right_y):
if(math.fabs(left_y-right_y)<20):
return 1
return 0
find_cross_flag=1
```
- - -
### The image
test site is as follows:
! [QQ screenshot 20211215165345.png]

The overall photo of the car is as follows:
![QQ screenshot 20211215165418.png]

See the attached test video, which was shot in the early stage of the project and has defects.