Nicht konstante Poti-Werte am Arduino ausgleichen Tutorial

Wenn dein Arduino keine konstanten Werte von den Potis liefert sondern diese leicht schwanken oder zittern, kannst du dies mit einem einfachen Programmier-Trick glätten und die Schwankungen am Poti beseitigen. In diesem kurzen Tutorial zeige ich dir wie’s geht.

So geht’s:

Und so kann man die Zeitverzögerung durch die Glättung umgehen:

int potiWert = 0;
int smoothWert = 0;

int potiWertAlt = 0;
int quickSmooth = 0;
int differenz = 0;
boolean quickAktiv = false;
int x = 0;

void setup() {
 Serial.begin(9600);
}

void loop() {
 
 potiWert = analogRead(A0);
 
 smoothWert = 0.6 * smoothWert + 0.4 * analogRead(A0);
 
 differenz = abs(potiWert - potiWertAlt);
 
 if (differenz <= 5 && quickAktiv == false) {
 quickSmooth = 0.6 * smoothWert + 0.4 * analogRead(A0);
 }
 else if (differenz <= 5 && quickAktiv == true){
 quickSmooth = analogRead(A0);
 x++;
 }
 else {
 quickSmooth = analogRead(A0);
 quickAktiv = true;
 };
 
 if (x >= 10) {
 x = 0;
 quickAktiv = false;
 };
 
 potiWertAlt = potiWert;
 
 Serial.print("\t");
 Serial.print(potiWert);
 Serial.print("\t");
 Serial.print(smoothWert);
 Serial.print("\t");
 Serial.print(differenz);
 Serial.print("\t");
 Serial.print(quickSmooth);
 Serial.print("\t");
 Serial.println(quickAktiv);
}

Beteilige dich an der Unterhaltung

2 Kommentare

  1. Im Gegensatz zu zum Beispiel Desktop-CPUs haben die meisten AVRs, die das Herzstück der Arduinos darstellen, keinen Floating-Point-Support in Hardware. Das heißt, der Compiler muss alles in Software nachbauen, wenn man Fließkommarechnungen verwendet. Das macht die Geschichte natürlich langsam. Daher verwendet man – wo möglich – besser nur Integer-Operationen. Eine sehr gute und ausführliche Betrachtung dazu findet Ihr hier: http://bleaklow.com/2012/06/20/sensor_smoothing_and_optimised_maths_on_the_arduino.html

    Wer keine Lust hat, unter dem Link alles nachzulesen und/oder Assembler scheut, kann diese zwei Zeilen hier verwenden, diese ist ca. 6x schneller als die Floating-Point-Lösung. Wenn es für eure Anwendung egal ist, dass es länger dauert, könnt Ihr bei der Version von Götz bleiben.

    smoothWert = (smoothWert * 10) + (analogRead(A0) * 6);
    smoothWert = (smoothWert + 8) >> 4;

    Kurz zur Erklärung: Statt mit Floating-Point-Arithmetik wird mit Fixed-Point-Arithmetik gearbeitet, hier mit 4 Bit nach dem Komma.
    Möchte man jetzt ganz allgemein a = x * k + y * l berechnen, muss man dafür Folgendes tun:

    a = (x * j) + (y * i);
    a = (a + 8) >> 4;

    Um den Integer-Wert j zu erhalten, muss man k = j / 2^4 für j lösen, also j = k * 2^4. Den Wert i kann man dann so berechnen: i = 2^4 – j.

    Am Beispiel:
    j = 0.6 * 2^4 = 9.6, also rund 10.
    i = 16 – 10 = 6.

    Die zweite Zeile sorgt für die Rundung (via +0.5 und abschneiden der Nachkommastellen) und skaliert das Ergebnis wieder zurück in die „normale“ Skala, denn zuvor haben wir ja mit dem jeweiligen Bruchteil von 2^4 die Zahlen größer gemacht. Die +8 sind die oben genannten +0.5, denn 2^4 / 2 = 8.

    Die Genauigkeit kann erhöht werden, indem man überall statt 2^4 z.B. 2^6 verwendet. Aber Achtung: Gerade 8-Bit-AVRs kommen schnell an die Grenze des Wertebereichs, selbst wenn man uint16_t statt int o.Ä. verwendet. Bei 16 Bit für eine uint16_t-Variable und Poti-Werten von 0 – 255 (8 Bit) sind so maximal 8 Bit nach dem Komma möglich, denn es muss gelten: (255 * 2^8) + (2^8 / 2) <= 2^16 – 1. D.h. hier wäre sogar 2^8 statt 2^4 noch in Ordnung.

  2. Ich habe heute Nachmittag ein paar Stunden mit dem Thema glätten von Potentiometern an Arduinos verbracht und der obige Code ist der einzige, den ich bis jetzt gefunden habe, der nicht asymptotisch wie ein Tiefpass-Filter arbeitet und auch ziemlich schnell reagiert.

    Vielen Dank dafür, genau das habe ich gesucht!

    Es gibt allerdings eine kleine Unschönheit bei dem Code:
    Wenn man sehr langsam am Poti dreht, dann bleibt der „smoothWert“ auf seinem ursprünglichen Wert hängen. In der Praxis hieße das z.B. dass eine langsames Aufdrehen eines Cutoffs nicht stattfinden würde.

    Ich habe ein bisschen herumgespielt und folgende Variante gefunden:
    Wenn die Differenz zw. dem PotiWert und dem smoothWert zu groß ist (z.B. > 3), dann schalte in den „quickAktiv“-Modus.

    d.h.

    definiere eine neue Variable:
    int diff_2 = 0;

    und in der Loop füge folgendes ein
    […]
    differenz = abs(potiWert – potiWertAlt);

    // neuer code
    diff_2 = abs(potiWert-quickSmooth);
    if (diff_2 > 3) quickAktiv = true;

    if (differenz <= 5 && quickAktiv == false) {
    […]

    Das liefert bei mir gute Ergebnisse.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert