Как выполнять команды в течение желаемого периода времени

У меня есть программа, которая получает 4 команды по 4 каналам для изменения цвета светодиода с использованием связи mqtt. Давайте просто сосредоточимся на двух каналах, времени и красном.

Я отправляю период времени, за который я хотел бы завершить изменение цвета, и новое значение цвета.

Я провел тестовые прогоны, чтобы рассчитать время, необходимое для обновления одного значения. Я вычисляю это, устанавливая значение intervalRed равным 0,01. с рабочим циклом 1024, при котором светодиод переходит от начального значения к конечному значению полного включения, значение интервала составит 10 240 тиков. когда я отправляю эту команду, беру полученное время выполнения ( 287 мс ) и вычисляю время для обновления одного тика, я получаю значение 0,028027 мс для завершения одного приращения. Когда я устанавливаю жестко заданное значение tickTime в это значение: 0,028027 и я отправляю изменение цвета с выключенного на включенное/наоборот с запрошенным временем завершения 1000 мс, фактическое время выполнения варьируется.

чем больше изменяется запрошенное время выполнения , тем больше разница между фактическим и запрошенным временем.

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

Я рад предоставить вывод терминала для любых попыток показать вывод значений, используемых в моих вычислениях, если это необходимо (но я считаю, что мне нужен разный подход ко всем вместе)

Как лучше всего обеспечить завершение смены цвета за требуемое время? Возможно, какой-то расчет основан на количестве прошедшего времени, а не вычислении жестко заданного значения времени одного тика?

    #include <ESP8266WiFi.h>
#include <PubSubClient.h>


#define CLIENT_NAME "ESP8266_1" // просто имя для идентификации этого клиента
WiFiClient wifiClient;
PubSubClient mqttClient("10.0.0.131", 1883, wifiClient);

// устанавливаем штифты светодиода rgb
int pinGreen = 4;
int pinBlue = 12;
int pinRed = 14;

float currentRed = 1024;
float currentGreen = 1024;
float currentBlue = 1024;

int nextRed = -1;
int nextGreen = -1;
int nextBlue = -1;

float intervalRed = -1;
float intervalGreen = -1;
float intervalBlue = -1;

//время плавания было рассчитано по
//IntervalValue (установлено на 0,01)/изменение значения (1024 при переходе от включения к выключению) = 10 240 тиков
//ExecutionTime (время начала - время окончания) /количество тиков = 0,0347643
// Кажется, у меня разное время выполнения, поэтому я пробовал значения от 0,028 до 0,04
float tickTime = 0.028027;
int executionTime = 1;
int showTime = 1;
int beginningReceivedData;

void setup() 
{
  Serial.begin(9600);
  // устанавливаем контакты светодиода rgb для вывода

  pinMode(pinRed, OUTPUT);
  pinMode(pinGreen, OUTPUT);
  pinMode(pinBlue, OUTPUT);
  digitalWrite(pinRed, HIGH);
  digitalWrite(pinGreen, HIGH);
  digitalWrite(pinBlue, HIGH);

  mqttClient.setCallback(callback);
  WiFi.begin("partyHouse", "whatsthepassword");
  connectToWiFiAndBroker();
}

void connectToWiFiAndBroker() 
{
  Serial.print("\nConnecting to WIFI");
  while (WiFi.status() != WL_CONNECTED) 
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("Connected to WIFI!");

  Serial.println("Connecting to broker");
  while (!mqttClient.connect(CLIENT_NAME)) 
  {
    Serial.print(".");
    delay(500);
  }
  Serial.println("Connected to broker!");

  mqttClient.subscribe("InterestingTopics/#");
}

void loop() 
{
  if (!mqttClient.connected()) {
    connectToWiFiAndBroker();
  }
  mqttClient.loop();

  updateColors();    
}
//------------------------------------------------ -------------------------------------------------- ----------------------
//Обратный вызов для обработки входящих данных
//------------------------------------------------ -------------------------------------------------- ----------------------
//тема это путь на основе подписки
void callback(char* topic, byte* payload, unsigned int length) 
{
  //для отслеживания времени обработки данных, а также времени полного обновления цветов за желаемое время
  beginningReceivedData = millis();
  char commandValue[length+1];
  for (int i = 0; i < length; i++) 
  {
    commandValue[i] = (char)payload[i];
  }
  commandValue[length+1] = '\0';
  if (strcmp(topic, "InterestingTopics/time") == 0) {
    executionTime = atoi(commandValue);
  }
  if (strcmp(topic, "InterestingTopics/red") == 0) {
    showTime = 1;
    nextRed = atoi(commandValue);
    intervalRed = (nextRed - currentRed)/(executionTime/tickTime);
    // ручное значение интервала, используемое для расчета времени тика
    if (nextRed < currentRed) {
      intervalRed = -0.1;
    } else {
      intervalRed = 0.1;
    }

    Serial.print("next: ");
    Serial.print(nextRed);
    Serial.print(" Current: ");
    Serial.print(currentRed);
    Serial.print(" Interval: ");
    Serial.println(intervalRed, 10);

    Serial.print("time to process incoming single value (red): ");
    Serial.println(millis() - beginningReceivedData);
  }
  if (strcmp(topic, "InterestingTopics/green") == 0) {
    nextGreen = atoi(commandValue);
    intervalGreen = (nextGreen - currentGreen)/(executionTime/tickTime);
  }
  if (strcmp(topic, "InterestingTopics/blue") == 0) {
    nextBlue = atoi(commandValue);
    intervalBlue = (nextBlue - currentBlue)/(executionTime/tickTime);
  }
}



void updateColors() {
  //------------------------------------------------ -------------------------------------------------- ----------------------
  //Обновление красного
  //------------------------------------------------ -------------------------------------------------- ----------------------
  if (currentRed != nextRed && nextRed > -1) {
    currentRed = currentRed + intervalRed;
    //если значение уменьшается и оно проходит следующее значение, устанавливаем значения равными, чтобы предотвратить передачу
    if (intervalRed < 0 && currentRed < nextRed) {
      currentRed = nextRed;
    }
    if (intervalRed > 0 && currentRed > nextRed) {
      currentRed = nextRed;
    }
    analogWrite(pinRed, (int)currentRed);
    // это еще существует только для того, чтобы печатать разное время от получения значения до времени, которое потребовалось для обновления
  } else if (currentRed == nextRed && nextRed > -1 && showTime == 1) {
    //showTime устанавливается равным нулю, чтобы печатать время только один раз
    showTime = 0;
    Serial.print("full color change has completed taking this much time: ");
    Serial.println(millis() - beginningReceivedData);
  }
  //------------------------------------------------ -------------------------------------------------- ----------------------
  if (currentGreen != nextGreen && nextGreen > -1) {
    currentGreen = currentGreen + intervalGreen;
    //если значение уменьшается и оно проходит следующее значение, устанавливаем значения равными, чтобы предотвратить передачу
    if (intervalGreen < 0 && currentGreen < nextGreen) {
      currentGreen = nextGreen;
    }
    if (intervalGreen > 0 && currentGreen > nextGreen) {
      currentGreen = nextGreen;
    }
    analogWrite(pinGreen, (int)currentGreen);
  }
  if (currentBlue != nextBlue  && nextBlue > -1) {
    currentBlue = currentBlue + intervalBlue;
    //если значение уменьшается и оно проходит следующее значение, устанавливаем значения равными, чтобы предотвратить передачу
    if (intervalBlue < 0 && currentBlue < nextBlue) {
      currentBlue = nextBlue;
    }
    if (intervalBlue > 0 && currentBlue > nextBlue) {
      currentBlue = nextBlue;
    }
    analogWrite(pinBlue, (int)currentBlue);
  }
}

, 👍0


1 ответ


Лучший ответ:

1

Не думайте, что обновление занимает фиксированное время, и вносите постоянные изменения. Напишите код, который вычисляет изменение/миллисекунду. Затем запишите начальное значение millis(), когда вы начинаете последовательность, и каждый раз в цикле вычисляйте float(millis()-startTime)/sequenceTime. Это даст вам процент изменения цвета, который нужно применить сейчас. Затем используйте этот процент для расчета интерполированного значения цвета.

Это даст вам адаптивную систему, которая установит значение цвета приблизительно на желаемый цвет для текущего этапа анимации, независимо от того, сколько времени занимает каждая итерация цикла. Если цикл по какой-то причине отстает, вы получите более грубые изменения между значениями цвета, но он все равно будет отслеживать желаемый темп.

,

Обратите внимание, что вы получите более отзывчивый код, адаптировав приведенное выше для использования математики с фиксированной запятой, поскольку большинство Arduino не имеют аппаратной поддержки с плавающей запятой, и в результате их операции с плавающей запятой довольно медленные. Однако сопоставление произвольной плавающей запятой с фиксированной точкой немного сложнее. Я бы предложил просто написать его с плавающей запятой для начала, а затем оптимизировать его до математики с фиксированной запятой, если он слишком нервный., @Duncan C

Спасибо за предложение математики с фиксированной точкой, я заметил значительную разницу во времени выполнения, когда я перешел от двойного к плавающему в моей математике. Не уверен, что понимаю, как преобразовать в фиксированную, но пришло время провести больше исследований, @Jordan Klaers

Математика с фиксированной точкой использует фиксированный «двоичный десятичный разряд» и обрабатывает все значения как от 0 до 1 (или от 0 до 2, или от 0 до 4, в зависимости от того, где вы поместите предполагаемый двоичный десятичный разряд. Если вы масштабируете все свои значения до диапазон вашей фиксированной точки, вы можете выполнить целочисленную математику со значениями, а затем интерпретировать результаты как значения с фиксированной точкой и получить гораздо, НАМНОГО более высокую производительность.Однако определение масштабирования и диапазона требует некоторых размышлений., @Duncan C

Обратите внимание, что вы также можете попробовать использовать «короткие» значения с плавающей запятой, а не «плавающие». Это будет еще быстрее и проще в программировании, чем математика с фиксированной точкой. Однако это делает ваши расчеты довольно низкой точностью., @Duncan C