Хочу сделать автономного дрона, который бы сам мог найти дорогу к цели и обратно, при этом обойти все препятствия ни кого не задев. Решил начать с нейросети и вебки. Так и получился этот проект
Суть проекта — нейросеть, точнее фреймворк imageai написанный на питоне под керас, находит на картинке человека и выдает координаты его бокса. Далее по горизонталь находим центр блока и двигаем туда камеру (естественно оставляя для камеры некоторый гистерезис, что бы она не скакала туда сюда). Далее находим второй центр, но уже по вертикале, прибавляем к нему несколько десятков пикселей, что бы когда человек стоит камера захватывало его лицо. Хотел еще приделать распознавания лиц, но вебка дешевая и поэтому функцию автофокусировки она не имеет.
Для проекта понадобилось
STM32f4discovery — отадочная плата
MT415 пару драйверов движков
2 шаговых двигателя
БП на 24 В 2,5 А
ImageAI
Коротко опишу код на питоне
Инициализация imageai. Выбирается тип нейросеть — yolo и размер картинки — flash. При флеше картинка уменьшается до маленького размера( уже не помню какого) и за счет этого ускоряется работа сети.
detector = ObjectDetection()
detector.setModelTypeAsYOLOv3()
detector.setModelPath("yolo.h5")
detector.loadModel(detection_speed="flash")
Функции для отправки символа на микроконтроллер для совершения одного шаги по оси горизонтале и по вертикали
def step():
i = 1
u = 0
while i:
while u!=1:
u = ser.write( b'v')
u=0
ff=ser.read(1)
print(1111)
if ff==b'B':
i=0
def step_y():
i = 1
u = 0
while i:
while u!=1:
u = ser.write( b'V')
u=0
ff=ser.read(1)
#print(1111)
if ff==b'B':
i=0
Функция которая получает на входе положения левой и правой границы бокса, находит центр и решает в какую сторону нужно крутить, чтобы объект был в середине камеры. Опять же на мк отправляются управляющие символы.
def rotate_x(left, right):
center = (right - left)/2 + left
u = 0
if center < 320:
i=1
while i:
while u!=1:
u = ser.write( b'r')
u=0
ff=ser.read(1)
#print(1111)
if ff==b'B':
i=0
# print("right")
if center > 320:
i=1
while i:
while u!=1:
u = ser.write( b'l')
u=0
ff=ser.read(1)
print(1111)
if ff==b'B':
i=0
#print("left")
global step_right
global step_left
if center > 360:
step_right = step_right + 1
step_left = step_left - 1
if step_left < 0:
step_left = 0
if step_right < 30:
step()
else: step_right = 30
if (center < 250 and center != 0):
step_right = step_right - 1
step_left = step_left + 1
if step_right < 0:
step_right = 0
if step_left < 30:
step()
else: step_left = 30
По вертикале функция управления почти такая же. Отличия описаны выше.
В мэйне мы уже получаем от нейросети сети два объекта. Первый это картинка с разрисованным положением объекта, а второй это массив обнаруженных объектов с их координатами.
detected_copy, detections = detector.detectObjectsFromImage(input_image=frame, input_type ="array", output_type = "array")
for eachObject in detections:
if eachObject["name"] == "person":
str1 = eachObject["box_points"]
str2= str(str1)
n = 1
for i in range(5):
if str2[i] in [","]:
detect1 = int(str2[1:i])
#print(detect1)
print (eachObject["box_points"])
Теперь код для МК
Функция по получению данных через виртуальный ком порт.
static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len)
{
/* USER CODE BEGIN 6 */
//USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]);
strncpy(buffer,(char*)Buf,*Len);
/* if ((buffer[0] == 0x76)&&(h == 0))
{
// h=1;
//i=0;
CDC_Transmit_FS("B", 1);
}*/
if (buffer[0] == 0x76)//v
{
step = 1;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x73)///s
{
step = 0;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x6C)//l
{
dir = 0;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x72)///r
{
dir = 1;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x56)///V
{
step1 = 1;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x53)////S
{
step1 = 0;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x4c)////L
{
dir1 = 0;
CDC_Transmit_FS("B", 1);
}
if (buffer[0] == 0x52)///R
{
dir1 = 1;
CDC_Transmit_FS("B", 1);
}
/* picture[i]=buffer[0];
///CDC_Transmit_FS("Z", 1);
i ++;
if(i == 9599)
{
start = 1;
}*/
/// CDC_Transmit_FS((unsigned char*)str_rx, strlen(str_rx));
USBD_CDC_ReceivePacket(&hUsbDeviceFS);
//CDC_Transmit_FS((unsigned char*)str_rx, strlen(str_rx));
return (USBD_OK);
/* USER CODE END 6 */
}
Управление драйверами шаговиков. Если степ == 1 то тогда делаем один импульс и получаем один шаг. Напрfвление задается в переменной dir
if(step == 1)
{
GPIOC->ODR &= ~(1<<0);
HAL_Delay(1);
GPIOC->ODR |= 1<<0;
HAL_Delay(1);
i++;
if(i == 1)
{
i = 0;
step = 0;
/* if(dir == 0)
{
dir = 1;
}
else
{
dir = 0;
}
////HAL_Delay(1000);*/
}
}
if(dir == 1)
{
GPIOC->ODR |= 1<<1;
}
else
{
GPIOC->ODR &= ~(1<<1);
}
if(step1 == 1)
{
GPIOC->ODR &= ~(1<<2);
HAL_Delay(1);
GPIOC->ODR |= 1<<2;
HAL_Delay(1);
i1++;
if(i1 == 1)
{
i1 = 0;
step1 = 0;
/* if(dir1 == 0)
{
dir1 = 1;
}
else
{
dir1 = 0;
}
////HAL_Delay(1000);*/
}
}
if(dir1 == 1)
{
GPIOC->ODR |= 1<<3;
}
else
{
GPIOC->ODR &= ~(1<<3);
}
Ну вот в принципе и все.
Большое спасибо Артему Лисину за помощь в написание программы на питоне!
Автор: xo4y_B_BostonDynamics