Как вы справляетесь с дрейфом датчиков?

У меня есть пара потенциометров на Arduino, выход, кажется, смещается на одну или 2 цифры вперед и назад. Я бы предпочел, чтобы они считывались как одно фиксированное значение, без изменений, когда их ручки не поворачиваются. Вы можете видеть на изображении, что первое и второе значения слегка смещаются вперед и назад. Как я должен решить эту проблему?

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

wandering pots

Мой код заключается в том, что значения 2 датчиков являются установочными точками в полилинии SVG. Отклонение означает, что будут нанесены дополнительные баллы, пока устройство ожидает допустимого ввода.

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

Вот мой источник:

/**Fucntion Defs**/
void svgHeader();
void svgFooter();
void polyLineBegin();
void polyLineEnd();

int Reset = 4;     //programmatically reset the arduino
int potX = A0;
int potY = A1;

int sensorValX = 0;
int sensorValY = 0;
int oldX = 0;
int oldY = 0;

int del = 2;       //a button on pin 2 for deleting drawn content
int delbutton = 0;
void setup() {
  Serial.begin(9600);
  pinMode(del, INPUT);
  svgHeader();
  polyLineBegin();
  delay(1000);
}

void loop() {
  // close the svg and start over
  if (digitalRead(del) == LOW ) {
    delbutton = 1;
    polyLineEnd();
    svgFooter();
    delay(5000);
    digitalWrite(Reset, LOW);
    digitalWrite(Reset, HIGH);
    svgHeader();
    polyLineBegin();
  } else {
    delbutton = 0;
    //Serial.println(delbutton);

  }

  //dont draw if its not changing
  sensorValX = analogRead(potX);
  sensorValY = analogRead(potY);
  if (sensorValX == oldX && sensorValY == oldY) {
    ; //dont do shi.
  } else {
    Serial.print(sensorValX);
    Serial.print(",");
    Serial.print(sensorValY);
    Serial.print(",");
    oldX = sensorValX;
    oldY = sensorValY;
    // Serial.println(delbutton);
    delay(1000);
  }
}
/**Functions**/

void polyLineBegin() {
  Serial.println ("<polyline points=\""); //x,y points go here

}

void polyLineEnd() {
  Serial.println ("0, 0\" stroke=\"red\" fill=\"transparent\" stroke-width=\"5\"/>");  //a dirty hack to avoid dealing with 1 last trailing comma.

}

void svgHeader() {
  Serial.println("<svg width=\"1023\" height=\"1023\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">");
};

void svgFooter() {
  Serial.println ("</svg>");
};

, 👍10

Обсуждение

Это шум квантования, и это нормально. Вы не можете избавиться от этого, только смириться с этим. Вы могли бы взять среднее значение, или вы могли бы отказаться от некоторого разрешения, или вы могли бы написать свой код для работы в диапазоне значений, а не в одном единственном значении., @Majenko

Это не дрейф, просто электрический шум на аналоговом входе. Вы действительно не можете избежать этого. Но поскольку ваш код не критичен по времени, почему бы не измерить несколько раз, стереть значения, а затем использовать результат. Это значительно уменьшило бы шум в используемых значениях, @chrisl

так что мне придется написать какой - нибудь код, чтобы справиться с этим. В настоящее время я рассматриваю расчет дисперсии, стандартного отклонения, нормализации и некоторых других математических терминов, с которыми я точно не знаком. Я думаю, что могу сделать простое заявление, чтобы игнорировать значения +/-1 из прочитанных значений, но я не уверен, что делать, если разница больше, чем это., @j0h

Перед тем, как выполнить аналоговую обработку(potX) ... выполните "калибровку" источника питания Vcc (через внутреннюю ссылку), если он используется в качестве "эталонного" напряжения с некоторым "средним"значением. Это может помочь., @Antonio51


4 ответа


10

хорошо, как только у меня появилась идея, что мне нужно будет сделать это в коде, решить ее стало проще. При изучении терминов квантования появился термин "удержание порога", и я понял, как решить эту проблему.

Я создал пороговое значение и сравнил разницу между старыми и новыми переменными.

int threshold =3;
int xVariance = abs(sensorValX-oldX);
int yVariance = abs(sensorValY-oldY);
if (xVariance >=threshold && yVariance >= threshold ||xVariance >=threshold || yVariance >=threshold){
  Serial.print(sensorValX);
  Serial.print(",");
  Serial.print(sensorValY);
  Serial.print(",");
 oldX=sensorValX;
 oldY=sensorValY; 
  
}else{
; //dont do shi.
 // Serial.println(delbutton);
delay(1000);
    } 

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

,

Обратите внимание, что вы можете опустить часть " xVariance >=порог && yVariance >>= порог в своем заявлении if. Это излишне. Оператор OR ||` также примет значение true, если будут выполнены оба условия., @chrisl

Этот подход вводит [гистерезис](https://en.wikipedia.org/wiki/Hysteresis), что действительно является распространенным и эффективным подходом к решению такого рода проблем., @Edgar Bonet

@chrisl, это лишнее? в случае, если один или оба потенциометра имеют пороговое значение+/ -? одно значение может измениться, в то время как другое остается постоянным, или могут измениться оба., @j0h

Да, это излишне. Оператор OR || также принимает значение true, если оба операнта являются истинными. Вы можете обратиться к таблице истинности этого оператора. То, о чем вы думали, называется эксклюзивным ИЛИ, или коротко XOR., @chrisl


6

Удалите аналоговый компонент с вашего устройства.

Используйте поворотный энкодер.

Он будет воспринимать вращение ручки в цифровом виде.

Одним из огромных преимуществ является то, что вы можете легко выбрать чувствительность входного сигнала. Один клик может продвинуть счетчик на 0,001 так же легко, как и на 1000.

https://duckduckgo.com/?q=rotary+кодировщик и iar=изображения и iax=изображения и ia=изображения

,

вы не ошибаетесь, как только я сделаю этот проект функционально работоспособным, он отправится в детский музей, и у вас не может быть ручек с ограничениями, они ломаются, когда вы получаете 1000 детей в неделю, запихивая их в одну или другую сторону. но мне все еще нужно кое-что сделать, и у меня еще нет кодеров., @j0h

@j0h тогда это может вас заинтересовать ... использует шаговый двигатель в качестве кодера ... это создает трудный кодировщик ... https://create.arduino.cc/projecthub/andrewf1/using-stepper-motor-as-rotary-encoder-3f5de4, @jsotola

Прямо сейчас! @jsotola Я видел некоторые подобные вещи, работая на бумажной фабрике, но совсем забыл об этом. Я определенно собираюсь разобраться в этом подробнее, так как более крутые двигатели сложнее сломать, чем крошечные ручки., @j0h


2

Я думаю, что вы должны обрабатывать конечную запятую в Arduino, используя вместо этого начальные запятые, но опустите первую начальную запятую, используя флаг для указания первой координаты:

bool firstCoordinate;

void loop()
{
    . . .
    if (xVariance >= threshold || yVariance >= threshold)
    {
        if (!firstCoordinate)
        {
            Serial.print(",");
            firstCoordinate = false;
        }
        Serial.print(sensorValX);
        Serial.print(",");
        Serial.print(sensorValY);
        oldX = sensorValX;
        oldY = sensorValY;
    }
    . . .
}

void polyLineBegin()
{
    Serial.println("<polyline points=\""); //x,y points go here
    firstCoordinate = true;
}


void polyLineEnd()
{
    // Clean line ending.
    Serial.println("\" stroke=\"red\" fill=\"transparent\" stroke-width=\"5\"/>");
}

В качестве альтернативы, первая координата может быть добавлена к строке, когда она начинается, тогда нет необходимости в флаге:

void polyLineBegin()
{
    Serial.println("<polyline points=\""); //x,y points go here
    Serial.println(sensorValX);
    Serial.println(",");
    Serial.println(sensorValY);
}

void loop()
{
    . . .
    if (xVariance >= threshold || yVariance >= threshold)
    {
        Serial.print(",");
        Serial.print(sensorValX);
        Serial.print(",");
        Serial.print(sensorValY);
        oldX = sensorValX;
        oldY = sensorValY;
    }
    . . .
}

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

,

спасибо @tim, это обоснованная, конструктивная критика, связанная с кодом. Это может не отвечать на вопрос, но оно представляет собой значимую обратную связь., @j0h


5

Некоторые методы "борьбы" с шумом:

  1. Возьмите несколько образцов. Рассчитайте среднее значение ("среднее"). Отбросьте десятичную дробь. Это "передискретизация" наряду с уменьшением разрешения (но уменьшением теперь увеличенного разрешения передискретизации).
  2. Возьмите несколько образцов. Найдите наиболее распространенное значение ("режим").
  3. Разделите значение на 2 (или 4, если необходимо). Это уменьшает диапазон значений и дискретизированное разрешение, но устраняет часть шума.

Проблема, от которой вы страдаете, - это "шум квантования". Это связано с тем, что аналоговый сигнал и цифровой сигнал не полностью совместимы. АЦП преобразует аналоговый сигнал в цифровое значение путем последовательного пошагового сравнения его с все меньшими и меньшими напряжениями ("квантами"). Существует ограничение на то, насколько малыми могут быть шаги (разрешение), но аналоговое напряжение не соответствует этим шагам, оно всегда будет где-то между последними двумя шагами. Иногда это будет обнаружено как нижняя ступень, иногда как верхняя ступень. Взяв несколько выборок и усреднив их, вы оцениваете, насколько близко к тому или иному шагу находится значение, и "уточняете" результат. Это "передискретизация" и используется для увеличения разрешения АЦП за счет скорости дискретизации.

С этими дополнительными образцами вы можете либо сказать "Это намного ближе к верхней ступени" (возьмите "среднее"), либо сказать "Скорее всего, это будет ближе к верхней ступени" (выберите "режим"), чтобы попытаться "зафиксировать" значение на одном из шагов.

,

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