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

в 11:49, , рубрики: DIY, diy или сделай сам, github, open source, opencv, stm32, машинное обучение, нейросеть, программирование микроконтроллеров

Хочу сделать автономного дрона, который бы сам мог найти дорогу к цели и обратно, при этом обойти все препятствия ни кого не задев. Решил начать с нейросети и вебки. Так и получился этот проект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сылка на исходники

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

Автор: xo4y_B_BostonDynamics

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js