Слежение за лицом ai камерой

Тема в разделе "Arduino & Shields", создана пользователем dennche70, 23 янв 2022.

  1. dennche70

    dennche70 Нуб

    Прошу форумчан пнуть в нужном направлении. Бьюсь уже несколько дней)

    Связка Ардуино Уно и AI камера Huskylens плюс 2 сервы. Стоит задача поиска и слежения за лицом. В части слежения за лицом реализовать удалось. В части поиска лица (поворот сервы в одну сторону и в другую) не совсем.

    Есть код:

    Код (C++):
    #include <Servo.h> // подключаем библиотеку для работы с сервоприводом
    #include "HUSKYLENS.h"
    #include "SoftwareSerial.h"


    Servo servo1;
    Servo servo2;


    HUSKYLENS huskylens;
    SoftwareSerial mySerial(A4, A5); // RX, TX
    //HUSKYLENS green line >> Pin 10; blue line >> Pin 11
    void printResult(HUSKYLENSResult result);

    int angle1 = 80;
    int angle2 = 95;

    void setup() {
    Serial.begin(115200);
    servo1.attach(5);
    servo2.attach(3);
    servo1.write(angle1);
    servo2.write(angle2);


    Wire.begin();
    while (!huskylens.begin(Wire))
    {
    Serial.println(F("Begin failed!"));
    Serial.println(F("1.Please recheck the \"Protocol Type\" in HUSKYLENS (General Settings>>Protocol Type>>I2C)"));
    Serial.println(F("2.Please recheck the connection."));
    delay(100);
        }

    huskylens.writeAlgorithm(ALGORITHM_FACE_RECOGNITION);


    }


    void loop() {
        if (!huskylens.request()) Serial.println(F("Fail to request data from HUSKYLENS, recheck the connection!"));
        else if(!huskylens.isLearned()) Serial.println(F("Nothing learned, press learn button on HUSKYLENS to learn one!"));
        else if(!huskylens.available()) Serial.println(F("No block or arrow appears on the screen!")); // Если лицо не обнаружено, в мониторе выводится это сообщение
     
    else  {
    HUSKYLENSResult result = huskylens.read();
    printResult(result);

    // Код слежения за лицом (работает)
    if (result.xCenter>200) {
      Serial.println(result.xCenter);
       angle1 -= 1;
        servo1.write(abs((constrain(angle1, 10, 170))));
        delay (10);
      }
    else if (result.xCenter>10 && result.xCenter <120 ) {
       angle1 += 1;
        servo1.write(abs((constrain(angle1, 10, 170))));
            delay (10);
      }

    if (result.yCenter>150) {
       angle2 -=1.5;
        servo2.write(abs((constrain(angle2, 75, 140))));
        delay (30);
      }
    else if (result.yCenter>10 && result.yCenter <100 ) {
       angle2 +=1.5;
        servo2.write(abs((constrain(angle2, 75, 140))));
            delay (30);
      }
    }
     
    }


    void printResult(HUSKYLENSResult result){
           if (result.command == COMMAND_RETURN_BLOCK){

            Serial.println(String()+F("Block:xCenter=")+result.xCenter+F(",yCenter=")+result.yCenter+F(",width=")+result.width+F(",height=")+result.height+F(",ID=")+result.ID);
        }
        else if (result.command == COMMAND_RETURN_ARROW){
            Serial.println(String()+F("Arrow:xOrigin=")+result.xOrigin+F(",yOrigin=")+result.yOrigin+F(",xTarget=")+result.xTarget+F(",yTarget=")+result.yTarget+F(",ID=")+result.ID);
        }
        else{
            Serial.println("Object unknown!");
        }
    }


    Как я понял, когда лицо обнаружено, срабатывает условие из 46 строчки, как только лицо теряется, срабатывает из 44 строки.

    Когда лицо не обнаружено, хочу сделать, чтобы серва крутила камеру в поисках лица. Но как только я вставляю код поворота сервы в условие 44 строки, даже при обнаружении лица, условие из 46 строки уже не срабатывает. Серва так и продолжает крутить камеру от 0 до 180 градусов.

    Что я делаю не так?

    И еще вопрос.

    В loop в 42, 43 и 44 строках указаны восклицательные знаки. Насколько я понимаю. знак ! - отрицание. К чему он в этих переменных?

    Код (C++):
    if (!huskylens.request()) Serial.println(F("Fail to request data from HUSKYLENS, recheck the connection!"));
    else if(!huskylens.isLearned()) Serial.println(F("Nothing learned, press learn button on HUSKYLENS to learn one!"));
    else if(!huskylens.available())
    Буду благодарен за комментарии, подсказки, замечания.
     
  2. User248

    User248 Гик

    Функции request(), isLearned() и available() возвращают двоичное (bool) значение. Вот и получается буквально: if(!huskylens.isLearned()) - если не изучил, if(!huskylens.available()) - если не доступен.
     
    Последнее редактирование: 23 янв 2022
  3. User248

    User248 Гик

    Смотря как вы это реализовали. Например, можно поворачивать камеру на +10 градусов и выходить на проверку. Потребуется задержка (delay), чтобы камера успела повернуться, а потом уже начиналось слежение за лицом.
     
    Последнее редактирование: 23 янв 2022
  4. parovoZZ

    parovoZZ Гуру

    так вроде сперва составляют алгоритм работы программы, а уже потом её пишут? Здесь же полное непонимание того, как МК выполняет программу.
     
  5. dennche70

    dennche70 Нуб

    Спасибо, получается, что после if(!huskylens.available()) следующий else, в котором код слежения сервы за лмцом, означает буквально - если доступен huskylens.available().

    По логике в условие если НЕ доступен if(!huskylens.available()) нужно вставить код вращения сервы влево-вправо, и как только камера зафиксирует лицо,
    huskylens.available() должен стать доступен.

    Но у меня этого не происходит, несмотря на то,что камера лицо фиксирует
     
  6. User248

    User248 Гик

    Покажите, как вы делаете код поворота сервы.
     
  7. dennche70

    dennche70 Нуб

    Пробовал так
    Код (C++):
    void loop() {
        if (!huskylens.request()) Serial.println(F("Fail to request data from HUSKYLENS, recheck the connection!"));
        else if(!huskylens.isLearned()) Serial.println(F("Nothing learned, press learn button on HUSKYLENS to learn one!"));
    else if(!huskylens.available()) {Serial.println(F("No block or arrow appears on the screen!")); // Если лицо не обнаружено, в мониторе выводится это сообщение

    // Код сканирования лица для сервы
        for (angle1; angle1 <= 180; angle1 += 1) {
            servo1.write(abs((constrain(angle1, 10, 170))));            
        delay(50);                    
      }
      for (angle1; angle1 >= 0; angle1 -= 1) {
        servo1.write(abs((constrain(angle1, 10, 170))));          
        delay(50);                    
      }
        }
    }


    else  {
    HUSKYLENSResult result = huskylens.read();
    printResult(result);

    // Код слежения за лицом (работает)
    if (result.xCenter>200) {
      Serial.println(result.xCenter);
       angle1 -= 1;
        servo1.write(abs((constrain(angle1, 10, 170))));
        delay (10);
      }
    else if (result.xCenter>10 && result.xCenter <120 ) {
       angle1 += 1;
        servo1.write(abs((constrain(angle1, 10, 170))));
            delay (10);
      }

    if (result.yCenter>150) {
       angle2 -=1.5;
        servo2.write(abs((constrain(angle2, 75, 140))));
        delay (30);
      }
    else if (result.yCenter>10 && result.yCenter <100 ) {
       angle2 +=1.5;
        servo2.write(abs((constrain(angle2, 75, 140))));
            delay (30);
      }
    }
    }
    но условие, когда huskylens.available доступен не срабатывает. Если код сервы сканирования удалить. то срабатывает мгновенно
     
  8. dennche70

    dennche70 Нуб

    Код (C++):
    // Код сканирования лица для сервы
        for (angle1; angle1 <= 180; angle1 += 1) {
            servo1.write(abs((constrain(angle1, 10, 170))));    
        delay(50);            
      }
      for (angle1; angle1 >= 0; angle1 -= 1) {
        servo1.write(abs((constrain(angle1, 10, 170))));  
        delay(50);            
      }
        }
    }
    Я так понял, цикл for влияет на выполнение условия. Потому что без него сообщение в монитор No block or arrow appears on the screen сыпится ежесекундно, а с кодом сервы разового после каждого прохода сервы.

    Пробовал while с условием !huskylens.available(), аналогично.

    P.S убрал вообще for, заработало)

    Сейчас так

    Код (C++):
    else if(!huskylens.available()) {Serial.println(F("No block or arrow appears on the screen!")); // Если лицо не обнаружено, в мониторе выводится это сообщение


    angle1 += 1;
    servo1.write(abs((constrain(angle1, 10, 170))));          
        delay(50);

    }
    Только не понятно. как без цикла заставить серву вращаться в обратную сторону/

    P.S.2 Сам спросил, сам ответил. Еще одним условием

    Код (C++):
    if (angle1 <= 180) {
    angle1 += 1;
    servo1.write(abs((constrain(angle1, 10, 170))));          
        delay(50);

    }

    else if (angle1 >= 0) {
    angle1 += 1;
    servo1.write(abs((constrain(angle1, 10, 170))));          
        delay(50);

    }
    Я так понимаю, все ломалось из-за использования for и while. Но теперь серва делает проход однократно, вместо того, чтобы крутится в другую сторону до момента поиска лица
     
    Последнее редактирование: 23 янв 2022
  9. User248

    User248 Гик

    А если так:
    Код (C++):

    // Код сканирования лица для сервы
    int step = 1;
    // to right
    if (!reverse && angle1 <= 180) angle1 += step;
    else reverse = true;
    // to left
    if (reverse && angle1 >= 0) angle1 -= step;
    else reverse = false;
    // write
    servo1.write(abs((constrain(angle1, 10, 170))));
    delay(step * 50);
     
    Только в начале кода (перед setup) нужно добавить:
    Код (C++):
    bool reverse = false;
     
    Последнее редактирование: 23 янв 2022
  10. dennche70

    dennche70 Нуб

    Отлично, благодарствую, Вы Бог Ардуино!)
     
  11. User248

    User248 Гик

    Ардуино я сам только изучаю, а вот на C++ программирую давно. Подправил код.
     
    Последнее редактирование: 23 янв 2022
  12. dennche70

    dennche70 Нуб

    Благодаря помощи форумчан продвинулся чуть дальше. Решил не делать отдельную тему. Собственно сейчас это представляет из себя связку UNO с камерой Huskylens, 2 сервами и модулем DFPlayer.

    Алгоритм работы такой: при включении камера за счет серв сканирует несколько раз пространство вокруг, если видит кого-то из знакомых, то переходит в режим слежения на лицом и DFPlayer в зависимости от ID лица воспроизводит одно из приветствий.

    Проблема в том, что если добавлять код с условиями проверки ID лиц, то сервы в режиме слежения за лицом работают значительно медленнее. Думал, что не справляется Уно, попробовал на есп32, но результат тот же. Скорее всего виной мой кривой код) Если пнете в нужном направлении, буду благодарен.

    Сам код

    Код (C++):
    #include <Servo.h> // подключаем библиотеку для работы с сервоприводом
    #include "HUSKYLENS.h" // подключаем библиотеку для работы HUSKYLENS
    #include "SoftwareSerial.h"
    #include "DFPlayer_Mini_Mp3.h" // подключаем библиотеку для работы DFPlayer


    Servo servo1;
    Servo servo2;


    HUSKYLENS huskylens;
    SoftwareSerial mySerial(A4, A5); // RX, TX
    //HUSKYLENS green line >> Pin 10; blue line >> Pin 11
    void printResult(HUSKYLENSResult result);

    int angle1 = 90; // положение сервы при включении
    int angle2 = 105; // положение сервы при включении
    bool reverse2 = false;
    bool hallo = true;
    bool hallo2 = true;
    bool hallo3 = true;
    bool trackingSonya = false;
    bool trackingSonya2 = false;
    int stopscan = 0;



    void setup() {
    Serial.begin(115000);
    servo1.attach(5);
    servo2.attach(2);
    servo1.write(angle1);
    servo2.write(angle2);
    mp3_set_serial (Serial);
    mp3_set_volume (30);
    delay (3000);
    Wire.begin();
    while (!huskylens.begin(Wire))
    {
    Serial.println(F("Begin failed!"));
    Serial.println(F("1.Please recheck the \"Protocol Type\" in HUSKYLENS (General Settings>>Protocol Type>>I2C)"));
    Serial.println(F("2.Please recheck the connection."));
    delay(100);
        }




    }


    void loop() {
        if (!huskylens.request()) Serial.println(F("Fail to request data from HUSKYLENS, recheck the connection!"));
        else if(!huskylens.isLearned()) Serial.println(F("Nothing learned, press learn button on HUSKYLENS to learn one!"));
        else if (!huskylens.available()) {Serial.println ("Scan"); // Если лицо не обнаружено, в мониторе выводится это сообщение

    // Код поиска лиц - нижний проход, вверх, вкерхний проход, вниз. По достижении stopscan 100 останиваливается. если ничего не нашел
    if (stopscan < 100) {
    Serial.println (String("stopscan") + String(stopscan));
    int step = 2;
    // to right

    if (!reverse2 && angle1 <= 180)

    {angle1 += step;
    Serial.println ("right");

    }
    else if(angle1 > 180 && angle2 < 120) {
    angle2 += step;
    Serial.println ("top");
    }

    else if (angle2 >= 120 &&  angle1 > 10) {
    angle1 -= step;
    reverse2 = true;

    Serial.println ("left");

    }


    else if (reverse2 && angle1 <= 10 && angle2 > 85){
    angle2 -= step;
    Serial.println ("down");
    stopscan +=1;
    }

    else reverse2 = false ;
    // write
    servo1.write(abs((constrain(angle1, 10, 170))));
    Serial.println (angle1);
    servo2.write(abs((constrain(angle2, 85, 130))));
    Serial.println (angle2);
    delay(step * 40);
        }

    }



    else  {
    HUSKYLENSResult result = huskylens.read();
    printResult(result);

    // Код слежения за лицом

    if (result.xCenter>200) {
    //Serial.println (result.ID);
    //Serial.println (String("x") + (result.xCenter) + ("servox") + (angle1));
    //Serial.println (String("y") + (result.yCenter) + ("servoy") + (angle2));
    angle1 -= 2;
    servo1.write(abs((constrain(angle1, 10, 170))));
    delay (30);
      }
    else if (result.xCenter>10 && result.xCenter <=120 ) {
    //Serial.println (result.ID);
    //Serial.println (String("x") + (result.xCenter) + ("servox") + (angle1));
    //Serial.println (String("y") + (result.yCenter) + ("servoy") + (angle2));
    angle1 += 2;
    servo1.write(abs((constrain(angle1, 10, 170))));
    delay (30);
      }

    if (result.yCenter>150) {
    //Serial.println (result.ID);
    //Serial.println (String("x") + (result.xCenter) + ("servox") + (angle1));
    //Serial.println (String("y") + (result.yCenter) + ("servoy") + (angle2));
       angle2 -=1;
        servo2.write(abs((constrain(angle2, 75, 130))));
        delay (30);
      }
    else if (result.yCenter>10 && result.yCenter <= 90 ) {
    //Serial.println (result.ID);
    //Serial.println (String("x") + (result.xCenter) + ("servox") + (angle1));
    //Serial.println (String("y") + (result.yCenter) + ("servoy") + (angle2));
       angle2 +=1;
        servo2.write(abs((constrain(angle2, 75, 130))));
            delay (30);
      }


    // Однократное привествие лица ID2
    if (hallo && huskylens.writeAlgorithm(ALGORITHM_FACE_RECOGNITION) && result.ID == 2) {
      mp3_play (1);
      delay (2000);
      hallo = false;
    }

    // Однократное привествие лица ID1
    if (hallo2 && huskylens.writeAlgorithm(ALGORITHM_FACE_RECOGNITION) && result.ID ==1) {
       mp3_play (2);
       hallo2 = false;
      trackingSonya = true;

    }

    // Второе привествие для ID1

    if (trackingSonya && !trackingSonya2 && result.ID ==1) {
       mp3_play (3);
       trackingSonya2 = true;
    }




    }
     
    }

     


    void printResult(HUSKYLENSResult result){
           if (result.command == COMMAND_RETURN_BLOCK){

            //Serial.println(String()+F("Block:xCenter=")+result.xCenter+F(",yCenter=")+result.yCenter+F(",width=")+result.width+F(",height=")+result.height+F(",ID=")+result.ID);
        }
        else if (result.command == COMMAND_RETURN_ARROW){
            Serial.println(String()+F("Arrow:xOrigin=")+result.xOrigin+F(",yOrigin=")+result.yOrigin+F(",xTarget=")+result.xTarget+F(",yTarget=")+result.yTarget+F(",ID=")+result.ID);
        }
        else{
            Serial.println("Object unknown!");
        }
    }
     
  13. User248

    User248 Гик

    Наверно, проверка ID занимает много времени. Тут никак не ускорить. Можно попробовать увеличить угол (шаг) поворота камеры, градусов 20-30. Но это не точно.
     
    Последнее редактирование: 6 фев 2022