Камера с функцией слежения за объектом

от автора

Хочу сделать автономного дрона, который бы сам мог найти дорогу к цели и обратно, при этом обойти все препятствия ни кого не задев. Решил начать с нейросети и вебки. Так и получился этот проектimage

Суть проекта — нейросеть, точнее фреймворк 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); 		 } 

Ну вот в принципе и все.

Cсылка на исходники

Большое спасибо Артему Лисину за помощь в написание программы на питоне!


ссылка на оригинал статьи https://habr.com/ru/post/483084/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *