ESP, IoT Использование библиотеки ServoSmooth .

smaglyuk

✩✩✩✩✩✩✩
23 Окт 2022
11
1
Прошу помощи .
Решил использовать библиотеку ServoSmooth.
В цикле LOOP библиотека работает нормально. А в функции Naliv, работать отказывается при использовании setTargetDeg. Однако если использовать write, то все работает нормально, но быстро. Основа ESP32-WROOM
Блок LOOP:
void loop() {
   // желаемая позиция задаётся методом setTarget (импульс) или setTargetDeg (угол), далее
  // при вызове tick() производится автоматическое движение сервы
  // с заданным ускорением и ограничением скорости
  myservo.tick();   // здесь происходит движение серво по встроенному таймеру!

  int i = opros_encoder();  // опрос энкодера

switch (i) {
    case 1:
      // выполнить, если значение == 1 Это короткое нажатие на энкодер
      tft.drawString("Это короткое нажатие на энкодер", 0, 0);
      //Serial.println("Нажата кнопка");
      myservo.setTargetDeg(Pos[1]);
      //myservo.write(Pos[1]);
      naliv();

    break;
    case 2:
      // выполнить, если значение == 2 Это длинное нажатие на энкодер
      tft.drawString("Это длинное нажатие на энкодер", 0, 0);
      myservo.setTargetDeg(Pos[2]);
      //myservo.write(Pos[2]);
      //menuEnter(0);  //  Переход в меню
  
    break;
    case 3:
      // выполнить, если значение == 3 Это поворот вправо
      tft.drawString("Это поворот вправо", 0, 0);
      myservo.setTargetDeg(Pos[0]);
      //myservo.write(Pos[0]);
      volum_level_new(1);
    break;
    case 4:
      // выполнить, если значение == 4 Это поворот влево
      tft.drawString("Это поворот влево", 0, 0);
      myservo.setTargetDeg(Pos[5]);
      //myservo.write(Pos[5]);
      volum_level_new(0);
    break;
  }

}

Функция Naliv:
void naliv() {
  tft.fillScreen(TFT_BLACK);  // Заливает экран черным цветом (очищаем)
  tft.setTextSize(2);
  tft.drawString("Наливаем по 50 мл", 50, 100);
  tft.drawString("B  -Ю РЮMKУ    %", 50, 150);
  for (int i = 0; i < NUM_PIXELS; i++) {     // Перебираем все рюмки
  //   if(!digitalRead(SW_pins[i])){
      if (sw_state[i])     // Если рюмку не убирали
      {
        //       lcd.clear();
        //       lcd.setCursor(3, 0);              // Устанавливает курсор в (позицию,Строка)
        //       lcd.print("РЮМКА ");
        //       lcd.print(i+1, DEC);          // Печатаем номер рюмки в которую льем
        //       lcd.setCursor(3, 1);              // Устанавливает курсор в (позицию,Строка)
        //       lcd.print("налита");
        //       delay(1000);
        //       lcd.clear();
        //       lcd.setCursor(2, 0);         // Устанавливает курсор в (Позиция,Строка)
        //       lcd.print("Смените рюмку");
        //       delay(1000);
        //       lcd.clear();
        //       lcd.setCursor(0, 0);              // Устанавливает курсор в (позицию,Строка)
        //       lcd.print("HAЛИBAЮ  по 50MЛ");
        //       lcd.setCursor(0, 1);              // Устанавливает курсор в (позицию,Строка)
        //       lcd.print("B  -Ю РЮMKУ    %");
      }else
      {
        tft.drawNumber( i+1, 70, 150);        // Устанавливает курсор в (Позиция,Строка)  и Печатаем номер рюмки в которую льем
        myservo.write(Pos[i]);                // Предвигаем серву в позицию " i "
       //  myservo.setTargetDeg(Pos[i]);
        delay(servo_time_work);               // Время задержки перед включением помпы
        digitalWrite(PUMP_PIN, HIGH);         // ВКЛЮЧАЕМ помпу
        int pump_time_work_start = millis();  // Время начала налива
        // Пока концевик не отпущен и время налива не закончилось крутим цикл в котором помпа работает
        // И выводим на экран проценты налива
        int t = 0; // Переменная для подсчета времени
        t =  pump_time_work + pump_time_work_start;
        while((millis() < t) && pins_state[i]){
          int p = map(millis(), pump_time_work_start, t, 0, 100); // Переменная для вывода процентов
          tft.drawNumber( p, 190, 150);       // Устанавливает курсор в позицию отображенния процентов налива
          delay(100);
         };
        tft.drawNumber( 100, 190, 150);       // Устанавливает курсор в позицию отображенния процентов налива при окончании налива
        digitalWrite(PUMP_PIN, LOW);          // ВыКЛЮЧАЕМ помпу
        sw_state[i] = true;                   //  обновляем состояние концевика
        delay(1000);
        tft.fillRect(190, 150, 35, 16, TFT_BLACK);
        tft.drawNumber( 0, 190, 150);       // Устанавливает курсор в позицию отображенния процентов налива при окончании налива
      }
    }
  myservo.write(Pos[6]);            //  возвращаем серву в парковочную позицию  
  //  myservo.setTargetDeg(Pos[i]);
}
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
544
160
@smaglyuk,
У вас много намешано, непонятно, как выглядит naliv в варианте с myservo.setTargetDeg
Но чтобы серва работала в Smooth режиме, надо часто вызывать tick()
У вас же в naliv задержки есть, а tick() не вызывается.
Так же не увидел, где вы проверяете окончание движения к точке назначения.
Дополнительно. Я не изучал код, но общая рекомендация - вызывать установку цели только если она изменилась. Или же надо подробно посмотреть код setTargetDeg и убедиться что ее можно часто вызывать с одним и тем же параметром. Например - не сбрасывает ли она в ноль текущую скорость (если используется ускорение) и т.д.
 

smaglyuk

✩✩✩✩✩✩✩
23 Окт 2022
11
1
@Bruzzer, поробую объяснить логику. Есть цикл LOOP в котором крутится опрос энкодера и получаем 4 значения. Вставка в case оператора "myservo.setTargetDeg(Pos);" чисто информативно, потом удалится. И вот здесь отрабатывается хорошо.Серва двигается медленно.
По идее в case 1, обращаемся к функции naliv.
В функции naliv , опрашиваются концевики от 0 до 5 позиции. Вот здесь и должна двигаться серва плавно , так же от 0 до 5 позиции . Однако если использовать "myservo.setTargetDeg(Pos);", то серва не двигается вообще. Если "myservo.write(Pos);" ,то работает, но быстро.
Добавлял в функцию tick() и начале, и в цикле for . Итога нет.
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
544
160
Очевидные причины не работы, я написал в предыдущем сообщении.
Если вы хотите заменить myservo.write(Pos); на myservo.setTargetDeg(Pos); и дождаться окончания движения к позиции, то надо после myservo.setTargetDeg(Pos); вызывать в цикле tick() с выходом из цикла по окончанию движения.
while(myservo.tick() == 0){};

myservo.write(Pos); - приводит к движению серво и без вызова tick()
myservo.setTargetDeg(Pos); - используется только с tick()
 

smaglyuk

✩✩✩✩✩✩✩
23 Окт 2022
11
1
@Bruzzer,
Спасибо.
Вставил цикл while(myservo.tick() == 0){}; ,заработало. Но не понимаю как оно "работает". В документации написано туманно.Можно объяснить на пальцах для начинающих?
 

Bruzzer

★★★✩✩✩✩
23 Май 2020
544
160
@smaglyuk,
Чтобы понимать, как оно работает сначала нужно понять как работает сама серва и "стандартная" библиотека Servo.h например (возможно не лучший)
Там в примерах - есть пример плавного движения без библиотек. Библиотека ServoSmooth это оболочка над Servo.h для удобного использования такого метода.