Kalibrierung von kapazitiven Sensoren

Hi Leute,

ich versuche gerade, kapazitive Sensoren (jeweils Kupferfolie, verbunden mit Arduino Mega), zu kalibrieren. Bevor ich das mit mehreren versuche, probiere ich es gerade mit einem einzelnen Sensor aus.

Die Idee ist Folgende:

  • Kalibrierungsphase --> LED leuchtet 5 Sekunden lang auf
  • Während dieser Zeit wische ich über den Sensor hin und her, sodass Min- und Max-Werte festgestellt werden
  • Dann ist die Kalibrierungsphase vorbei --> LED geht aus
  • Dann werden die kalibrierten Werte ausgegeben (in meinem Test zwischen 0 und 127)

Leider will das so nicht klappen. Die Werte gehen in meinem Fall auf über 300 hoch, das heißt, die Kalibrierung funktioniert nicht. Hier ist der Code:

#include <CapacitiveSensor.h>
#include <elapsedMillis.h>

float max = 0;
float min = 100000;

void calibrate (float v) {
  if (v > max) max = v;
  if (v < min) min = v;
}
float get (float v) {
  return map(v, min, max, 0, 127);
}

int ledPin = 13;
elapsedMillis timer;
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2);

void setup() {
  pinMode(ledPin, OUTPUT); 
  cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
  Serial.begin(9600);
  digitalWrite(ledPin, HIGH);
  
  while(timer < 5000) {
    calibrate(cs_4_2.capacitiveSensor(30));
  }
  
  digitalWrite(ledPin, LOW);
}

void loop() {
  float sensorValue1 = cs_4_2.capacitiveSensor(30);
  float total1 =  get(sensorValue1);
  Serial.println(total1);
  delay(10);
}

Vermutlich habe ich irgendwo einen Denkfehler drin und die Lösung ist ganz simpel aber anscheinend stehe ich grad gehörig auf dem Schlauch.

Wenn jemand u. U. einen Fehler sieht, wäre ich über jede Hilfe sehr dankbar.

Vielen Dank im voraus und liebe Grüße :slight_smile:

Apollo_M:
Wenn jemand u. U. einen Fehler sieht, wäre ich über jede Hilfe sehr dankbar.

Kannst Du erklären was hier passiert:

  float total1 =  get(sensorValue1);
float get(float v)

{
 return map(v, min, max, 0, 127);
 }

u.a. ist der Rückgabewert für total1 nicht mal ein byte...

Außerdem ist das mitgelieferte map nur für Ganzzahlen. Float ist dort fehl am Platze.

Gruß Tommy

Tommy56:
Außerdem ist das mitgelieferte map nur für Ganzzahlen. Float ist dort fehl am Platze.

Gruß Tommy

Verräter :wink:

Schönen Abend noch - der Tag war sehr unterhaltsam

Dir auch :wink:

Gruß Tommy

Danke euch :slight_smile: Hab jetzt die floats in ints geändert (+ aus dem Grund den min-Wert von 100000 auf 10000 reduziert) mit dem Ergebnis, dass das Programm so, sagen wir mal, 90% funktioniert. Die Kalibrierung funktioniert vom Prinzip her, allerdings habe ich festgestellt, dass ich, obwohl ich nur bis 127 mappe, trotzdem zum Teil Werte um 200 rum bekomme. Wenn ich bis 511 mappe, erhalte ich zum Teil Werte um 600 rum etc.

An was liegt das?

Hier ist der geänderte Code:

#include <CapacitiveSensor.h>
#include <elapsedMillis.h>

int max = 0;
int min = 10000;

void calibrate (int v) {
  if (v > max) max = v;
  if (v < min) min = v;
}
int get (int v) {
  return map(v, min, max, 0, 127);
}

int ledPin = 13;
elapsedMillis timer;
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2);

void setup() {
  pinMode(ledPin, OUTPUT); 
  cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
  Serial.begin(9600);
  digitalWrite(ledPin, HIGH);
  
  while(timer < 5000) {
    calibrate(cs_4_2.capacitiveSensor(30));
  }

  digitalWrite(ledPin, LOW);
}

void loop() {
  int sensorValue1 = cs_4_2.capacitiveSensor(30);
  int total1 =  get(sensorValue1);
  Serial.println(total1);
  delay(10);
}

Habt ein schönes Wochenende!

Apollo_M:
An was liegt das?

Weil Du falsch zuordnest.

int max = 0;      // !!

int min = 10000;  // !!

void calibrate (int v) {
 if (v > max) max = v;
 if (v < min) min = v;
}
int get (int v) {
 return map(v, min, max, 0, 127);
}

Habt ein schönes Wochenende!

Wenn Du rausliest, wie gross die Werte v, min, max, etc. sein dürfen und Du das ausnutzt, ist mein WE gerettet! Danke schonmal dafür - Ich weiss Du machst das :slight_smile:

map() limitiert sich nicht auf den angegebenen Werte. Die angegebenen Werte sind nur jeweils 2 Punkte auf 2 Geraden. Da die Geraden unendlich lang sind (außer durch den Wertebereich der verwendeten Variablen begrenzt), sind auch Werte außerhalb des Eingabebereichs definiert. Darum kann auch 200 herauskommen.

Grüße Uwe

So, nach längerem Überlegen bin ich auf dieselbe Vermutung gekommen, die sich dann durch uwefed's Beitrag zum Glück bestätigt hat, nämlich, dass die map-Funktion ein Problem macht, wenn NACH der Kalibrierung noch ein höherer "v"-Wert entsteht, als WÄHREND der Kalibrierung. Dann ist v > max, also klappt das mit der map-Funktion dann nicht.

Ich habe das jetzt folgendermaßen gelöst:

int get (int v) {
  if (v > max) max = v; // <-- !!!
  return map(v, min, max, 0, 127);
}

Das heißt, ich setze jetzt v auf den max-Wert, wenn nachträglich (nach der Kalibrierung) noch ein höherer v-Wert entsteht.

Scheint soweit zu klappen.

Als nächstes versuche ich jetzt, das mit mehreren Sensoren zu machen :slight_smile:

Danke euch allen nochmal!

Update: Anbei meine Version für mehrere Sensoren. Bisher klappt es so wie ich es mir vorstelle.

#include <CapacitiveSensor.h>
#include <elapsedMillis.h>

struct Reading {
  int max = 0;
  int min = 10000;

  void calibrate (int v) {
    if (v > max) max = v;
    if (v < min) min = v;
  }
  int get (int v) {
    if (v > max) max = v;
    return map(v, min, max, 0, 127);
  }
};

Reading readings[2];
int ledPin = 13;
elapsedMillis timer;
CapacitiveSensor cs_4_2 = CapacitiveSensor(4,2);
CapacitiveSensor cs_4_6 = CapacitiveSensor(4,6);
//CapacitiveSensor cs_4_8 = CapacitiveSensor(4,8);

void setup() {
  pinMode(ledPin, OUTPUT);
  cs_4_2.set_CS_AutocaL_Millis(0xFFFFFFFF);
  cs_4_6.set_CS_AutocaL_Millis(0xFFFFFFFF);
  //cs_4_8.set_CS_AutocaL_Millis(0xFFFFFFFF);
  Serial.begin(9600);
  digitalWrite(ledPin, HIGH);

  while(timer < 5000) {
    readings[0].calibrate(cs_4_2.capacitiveSensor(30));
    readings[1].calibrate(cs_4_6.capacitiveSensor(30));
    //readings[2].calibrate(cs_4_8.capacitiveSensor(30));
  }
  
  digitalWrite(ledPin, LOW);
}

void loop() {
  int sensorValue1 = cs_4_2.capacitiveSensor(30);
  int sensorValue2 = cs_4_6.capacitiveSensor(30);
  //int sensorValue3 = cs_4_8.capacitiveSensor(30);
  int total1 =  readings[0].get(sensorValue1);
  int total2 =  readings[1].get(sensorValue2);
  //int total3 =  readings[2].get(sensorValue3);
  Serial.print(total1);
  Serial.print("\t");
  Serial.println(total2);
  //Serial.print("\t");
  //Serial.println(total3);
  delay(10);
}

Hoffentlich hab ich nichts übersehen :slight_smile:

Hi

Das 'Nachführen' Deiner Werte nach der Kalibrierung halte ich für gefährlich.
So können Dir zwei Ausreißer den Wertebereich so auseinander drücken, daß die normalen Messwerte 'ziemlich genau in der Mitte' - aber eben Beide nahezu identisch - sind.
Das kann Dir auch erst in drei Wochen passieren - dann ist plötzlich einer der Sensoren 'taub' geworden.

Siehe constrain
Das begrenzt den Variablenwert auf Unter/Obergrenze bzw. gibt den Wert zurück, wenn Er innerhalb der Grenzen liegt.

MfG

Edit
URL-Tag korrigiert ...

Oh, das stimmt, danke dir.

Ich schau mir die constrain-Funktion mal an.

Bei mir sind die Sensoren unter einer Gipsschicht. Um zu verhindern, dass die Werte nach der Kalibrierung höher sind, als während der Kalibrierung, könnte ich natürlich während der Kalibrierung auch einfach ganz fest auf die ganzen Sensoren drücken aber das mit der constraint-Funktion hört sich besser an :slight_smile:

Okay, habe jetzt die "get"-Funktion abgeändert und zwar so:

int get (int v) {
    return constrain(map(v, min, max, 0, 511), 0, 511);
  }

Ich schätze, das sollte passen. Werde ich dann später mal testen und den Post editieren, ob's so geklappt hat.

p.s. Ich hab auch die 127 auf 511 geändert, sodass die Werte ein bisschen weiter auseinander gezogen sind.