Resistives Sensorarray für eine Schuhsohle (Velostat)

Hi! Das hier ist mein erstes Arduino-Projekt, welches ich für die Uni benötige.
Ich habe eine Schuhsohle gebastelt mit je 6 Spalten und 12 Zeilen an Kupferbahnen (Bild ist angehängt). Dazwischen liegt eine Velostat-Schicht. Teste ich das Ganze vorab mit dem Multimeter scheint es auch ganz gut zu funktionieren. So für die Auswertung habe ich mir zwei 16-Channel-Analog Multiplexer von SparkFun besorgt und programmieren möchte ich es mit einem Arduino Pro Mini.

Meine Frage jetzt, weiß jemand wie ich die Kreuzungen der Kupferbahnen, also die einzelnen Sensorelemente, über den seriellen Monitor auslesen kann? (Widerstand? Spannung? Druck?)
Evtl. wäre auch ein Sketch für Arduino und Processing zur visualisierten Darstellung wo auf der Sohle und wie stark der Druck aufgebracht wird, hilfreich.

Ich bedanke mich schon herzlichst im Voraus bei euch allen!!

Und die 6*12 = 72 Widerstand-Werte zu erfassen ist kein Problem?
Toll. (Zeig mal :wink: )

Wie schnell soll das Ganze sein?
Die Auflösung ist vermutlich nicht so hoch. Ein Byte/Wert reicht sicher; wenn das Ergebnis nur als verschiedene Farben dargestellt wird, evtl. sogar nur Werte '0' ...'9'

Die Widerstände hängen über die Velostat-Schicht zusammen, nehme ich an. Oder gehört zu jeder Kreuzung ein isolierter Velostat-Punkt?

Ein Arduino kann nur Spannungen messen, es muß also über einen Multiplexer eine Spannung an eine Sensor-Zeile gelegt werden, mit dem anderen Multiplexer wird die Spalte ausgewählt, und mit einem Analog-Eingang und einem Ableit-Widerstand nach Gnd verbunden werden (Spannungsteiler). Mit 6 Analog-Eingängen kann man den zweiten Mux auch sparen, nur geht dann kein I2C mehr (benutzt A5/A6).

ma1kels:
zwei 16-Channel-Analog Multiplexer von SparkFun

Wenn es die hier sind oder etwas ähnliches, reicht eigentlich einer, der mit 4 Adress-Bits einen von 12 (16) Kanälen lesen kann. 6 Ausgangspins für die Spalten, bleibt Rx / Tx frei für den "SerialMonitor" bzw. das PC - Anzeige/Auswerteprogramm.

Teste ich das Ganze vorab mit dem Multimeter scheint es auch ganz gut zu funktionieren.

Ich nehme mal an, du nimmst einen Widerstandsmessbereich und misst zwischen einer Spalte und eine Zeile? Wenn du dann den Kreuzungspunkt belastest, ändert sich der Messwert ?

Mit dem Arduino kannst du nur Spannungen messen. Brauchst also einen zusätzlichen konstanten Widerstand, der mit deinem Messwiderstand einen Spannungsteiler bildet.

Spalten  1 ... 6  

Zeilen  A0 ... A11  

            |
            |
   S0 ---- MUX  --- SIG --+-- R ---- GND 
   S1 ----                |
   S2 ----                +--------- A0
   S3 ----

Eine der Spalten 1..6 HIGH und die 4 Adress-Bits S0 .. S3 per Arduino OUTPUT einstellen, und an A0 kann der entsprechende Messwert gelesen werden.

Die Auflösung ist am besten, wenn der Widerstand R eine ähnliche Größenordnung hat wie der Widerstand zwischen Zeile und Spalte.

Erstmal je Adresse die 6 Spalten lesen und nacheinander in einer Zeile die Werte auf Serial ausgeben.
Dann das gleiche für die nächste Adresse in der nächsten Zeile.

Zum Spass kannst du den Messwert vor der Ausgabe durch 100 teilen und bekommst so nur einstellige Zahlen, die sich so von selbst in einer Matrix abbilden, die deiner Schuhsohle entspricht. ( Sowas meinte ich mit geringer Auflösung)

okay, den ersten Teil verstehe ich. Aber mit dem "code" verstehe ich nicht ganz was du mir sagen willst?!

Und ab hier..

Die Auflösung ist am besten, wenn der Widerstand R eine ähnliche Größenordnung hat wie der Widerstand zwischen Zeile und Spalte.

Erstmal je Adresse die 6 Spalten lesen und nacheinander in einer Zeile die Werte auf Serial ausgeben.
Dann das gleiche für die nächste Adresse in der nächsten Zeile.

Zum Spass kannst du den Messwert vor der Ausgabe durch 100 teilen und bekommst so nur einstellige Zahlen, die sich so von selbst in einer Matrix abbilden, die deiner Schuhsohle entspricht. ( Sowas meinte ich mit geringer Auflösung)

.. hört es bei mir ganz auf :frowning: Also ich verstehe es was du meinst, aber ich hab keine Ahnung wie man das im Arduino Sketch umsetzt.

Hier ist mal der Steckbrett-Aufbau (Auf dem Bild wird ein Array von 15x15 verwendet, bei mir bleibt es 6x12): https://cdn.instructables.com/FDC/6B90/IB3HOF9S/FDC6B90IB3HOF9S.LARGE.jpg und im Anhang ist ein Bild des Sohlen-Aufbaus zu sehen.

Auf jeden Fall vielen Dank für die bereits geleistete Hilfe.

ma1kels:
.. hört es bei mir ganz auf :frowning: Also ich verstehe es was du meinst, aber ich hab keine Ahnung wie man das im Arduino Sketch umsetzt.

Michael spricht vom Messen (Spannungen mit dem Multimeter). Da musst Du im Sketch überhaupt nichts tun.

Gruß

Gregor

Bei dir ändert sich der Widerstand der Schicht zwischen den Kontakten. Du misst quasi immer den Widerstand zwischen den beiden Bahnen eines Kreuzungspunktes deiner Sohle. Mit dem Multimeter gar kein Problem, dummerweise kann ein MCU keinen Widerstand direkt messen. Allerdings können sie meist recht gut Spannung messen. Also wandelst du den Widerstandswert in eine Spannung um mittels eines Spannungsteilers. Ein solcher besteht in der Regel aus 2 Widerständen in Reihe, wobei die Spannung in der Mitte der beiden Widerstände gemessen wird. Du hast bis jetzt nur einen Widerstand (genauer 72x einen Einzelwiderstand, welcher seinen Wert ändert). Um einen Spannungsteiler daraus zu machen brauchst du einen festen Referenzwiderstand. Dieser sollte ungefähr in der Größenordnung liegen, in der sich auch der Widerstandswert deiner Schickt befindet. Ansonsten geht die Änderung durch das Draufdrücken auf die Schicht komplett unter.

Wenn es jetzt ans Programmieren geht einfach über den Mux einen der Kreuzungspunkte wählen und über "analogRead(Pin)" den Spannungswert auslesen. Anschließend kannst du diesen in den eigentlichen Wiederstandwert oder auch in einen Druck umrechnen.

Um zu schauen ob es geht einfach alle 72 Werte als lange Zeile oder in einer Art kleinen Tabelle ausgeben (Im Setup: Serial.begin(), im Loop: Serial.println("text")). Sieht nicht hübsch aus, aber du solltest sehen, dass sich die Werte ändern. Später kann man das ganze dann als Pixel darstellen.

Bei dir ändert sich der Widerstand der Schicht zwischen den Kontakten. Du misst quasi immer den Widerstand zwischen den beiden Bahnen eines Kreuzungspunktes deiner Sohle. Mit dem Multimeter gar kein Problem, dummerweise kann ein MCU keinen Widerstand direkt messen. Allerdings können sie meist recht gut Spannung messen. Also wandelst du den Widerstandswert in eine Spannung um mittels eines Spannungsteilers. Ein solcher besteht in der Regel aus 2 Widerständen in Reihe, wobei die Spannung in der Mitte der beiden Widerstände gemessen wird. Du hast bis jetzt nur einen Widerstand (genauer 72x einen Einzelwiderstand, welcher seinen Wert ändert). Um einen Spannungsteiler daraus zu machen brauchst du einen festen Referenzwiderstand. Dieser sollte ungefähr in der Größenordnung liegen, in der sich auch der Widerstandswert deiner Schickt befindet. Ansonsten geht die Änderung durch das Draufdrücken auf die Schicht komplett unter.

Das heißt also ich messe nochmal den Widerstand zwischen den beiden Bahnen eines Kreuzungspunktes und wähle dann einen Referenzwiderstand der dieser Größenordnung entspricht, richtig?! Wie verschalte ich diesen dann auf dem Steckbrett? An den VCC-Pin des Arduino? Sorry für die banalen Fragen, aber für mich ist es nicht ganz so simpel :confused:

Wenn es jetzt ans Programmieren geht einfach über den Mux einen der Kreuzungspunkte wählen und über "analogRead(Pin)" den Spannungswert auslesen

Ich schließe quasi meine Sohle jetzt an die beiden Mux an und über "analogRead(Pin)" wähle ich die entsprechenden Kanäle dann?

Sorry für die Verwirrung. "Code"-Formatierung habe ich nur verwendet, damit die Ascii-Grafik besser rüber kommt.
GND und A0 sind Arduino Pins
S0 ... S3 sind Multiplexer Pins die vom Arduino angesteuert werden
A0 ... A11 sind die Multiplexer Eingänge
SIG der Multiplexer Ausgang
R der Spannungsteiler-Widerstand

--- + | sollen Verbindungen darstellen und das Ganze einen Schaltplan, keinen Code.


Ich schließe quasi meine Sohle jetzt an die beiden Mux an und über "analogRead(Pin)" wähle ich die entsprechenden Kanäle dann?

Wenn du unbedingt zwei Mux verwenden willst, adressierst du über einen eine Spalte und über den anderen eine Zeile. und nutzt aus, dass die Mux bidirektional arbeiten. Der eine SIG bekommt 5V und schaltet diese auf 1 von 6 (16) Ausgängen, der andere SIG hat liefert dann die Spannung hinter dem Messwiderstand.

Um den Analogwert zu lesen brauchst du nur einen einzigen Analog-Eingang und einen Spannungsteiler-Widerstand.

michael_x:
Eine der Spalten 1..6 HIGH und die 4 Adress-Bits S0 .. S3 per Arduino OUTPUT einstellen, und an A0 kann der entsprechende Messwert gelesen werden.

Erstmal je Adresse die 6 Spalten lesen und nacheinander in einer Zeile die Werte auf Serial ausgeben.
Dann das gleiche für die nächste Adresse in der nächsten Zeile.

LD-:
Wenn es jetzt ans Programmieren geht einfach über den Mux einen der Kreuzungspunkte wählen und über "analogRead(Pin)" den Spannungswert auslesen. Anschließend kannst du diesen in den eigentlichen Wiederstandwert oder auch in einen Druck umrechnen.

Um zu schauen ob es geht einfach alle 72 Werte als lange Zeile oder in einer Art kleinen Tabelle ausgeben (Im Setup: Serial.begin(), im Loop: Serial.println("text")). Sieht nicht hübsch aus, aber du solltest sehen, dass sich die Werte ändern. Später kann man das ganze dann als Pixel darstellen.

So ich habe jetzt mal die hier erwähnten Hinweise versucht als code darzustellen ... Kann jemand mal darüber gucken und mir feedback geben ob es den so gemeint ist?

//Mux control pins for output signal (OUT_pin) default for arduino mini pro
const byte s0 = 13;
const byte s1 = 12;
const byte s2 = 11;
const byte s3 = 10;

int columnPin = 9;

int analogPin = A0;

int val = 0; 

void setup() {
 
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 

  digitalWrite(columnPin, HIGH);

  Serial.begin(9600);

  
}

void loop() {
  val = analogRead(analogPin);
  Serial.println(val);

}

Das ist doch schonmal ein Anfang :wink:

Ich sehe jetzt nicht genau, wofür

   int columnPin = 9;

gut ist.

Willst du 1 oder 2 Multiplexer verwenden?
( Im Augenblick verwendest du noch gar keinen, bzw. liest permanent von Kanal 0 )

Erstmal mit nur einem MUX und ohne dynamische Spalten-Anwahl:
Musst du nacheinander die Kanäle 0 .. 11 des MUX adressieren.

z.B. so oder ähnlich:

...
byte kanal = 0; // Wertebereich 0 .. 11
void loop () {
  setzeMUXAdresse(kanal, s0, s1, s2, s3) ; 
  int val =  analogRead(analogPin);
  Serial.print ("Kanal "); Serial print(kanal);
  Serial.print(" : "); Serial.println(val);
  delay(100); // zum Test verlangsamen
  kanal++;
  if (kanal > 11) kanal = 0; 
}

void setzeMUXAdresse(byte kanal, const byte S0, const byte S1, const byte S2, const byte S3) {
  digitalWrite(S0, bitRead(kanal, 0);
  digitalWrite(S1, bitRead(kanal, 1);
  digitalWrite(S2, bitRead(kanal, 2);
  digitalWrite(S3, bitRead(kanal, 3);
}

Mit den vielen Parametern kannst du die Funktion setzeMUXAdresse mehrfach (für zwei MUX) verwenden.

Willst du 1 oder 2 Multiplexer verwenden?
( Im Augenblick verwendest du noch gar keinen, bzw. liest permanent von Kanal 0 )

Na wenn es mit 1 Multiplexer auch geht, dann erstmal einen :wink:

Erstmal mit nur einem MUX und ohne dynamische Spalten-Anwahl:
Musst du nacheinander die Kanäle 0 .. 11 des MUX adressieren.

z.B. so oder ähnlich:

Okay, ich hab den sketch jetzt mal angepasst und deinen part noch eingebunden. Der serielle Monitor gibt mir jetzt Kanal 0: 0 - Kanal 11:0 aus. (Habe die Schaltung noch nicht umgebaut und den Spannungsteiler noch nicht drin.) Wenn das dann richtig aufgebaut ist sollte mir hier die Spannung angezeigt werden, richtig? Also ich drücke quasi auf meiner Sohle auf einen Kreuzungspunkt von Spalte und Reihe und je nachdem welche Reihe (Kanal 0-11) nun belastet wird, so zeigt mir der serielle Monitor den entsprechenden Wert?

Wo schließe ich den aber jetzt mein Kabel mit den 6 Pins an? Also die 12 Pins kommen ja an den Multiplexer an Ch 0-11, soweit ist es mir klar.

Danke!

Hier mein aktueller code:

//Mux control pins for output signal (OUT_pin) default for arduino mini pro
const byte s0 = 13;
const byte s1 = 12;
const byte s2 = 11;
const byte s3 = 10;

int analogPin = A0;

int val = 0; 

byte kanal = 0; // Wertebereich 0 .. 11

void setup() {
 
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 


  Serial.begin(9600);
  
}

void loop() {
  setzeMUXAdresse(kanal, s0, s1, s2, s3) ; 
  int val =  analogRead(analogPin);
  Serial.print("Kanal"); Serial.print(kanal);
  Serial.print(" : "); Serial.println(val);
  delay(500); 
  kanal++;
  if (kanal > 11) kanal = 0; 
}

void setzeMUXAdresse(byte kanal, const byte S0, const byte S1, const byte S2, const byte S3) {
  digitalWrite(S0, bitRead(kanal, 0));
  digitalWrite(S1, bitRead(kanal, 1));
  digitalWrite(S2, bitRead(kanal, 2));
  digitalWrite(S3, bitRead(kanal, 3));
}

Ich würde langsam vorgehen, und mich erstmal über 12 lebende Messwerte freuen, bevor ich auch noch die 6 Spalten schalte.

Dazu brauchst du nur die interessierende Spalte mit 5V zu verbinden und den Widerstand zwischen GND und den Analog-Eingang = MUX - Ausgang. Fertig ist der Spannungsteiler.

Statt 5V kannst du natürlich auch einen von 6 weiteren Ausgängen verwenden, die du an die Spalten anschliesst und so das Spalten-Multiplexen direkt machst.

michael_x:
Ich würde langsam vorgehen, und mich erstmal über 12 lebende Messwerte freuen, bevor ich auch noch die 6 Spalten schalte.

Na ich kriege aber doch keinen Messwert wenn ich nur die 12 Reihen schalte, weil dieser entsteht doch durch den Kontakt von "Spalte - Velostat - Reihe" ?! Oder verstehe ich dich jetzt falsch?

Statt 5V kannst du natürlich auch einen von 6 weiteren Ausgängen verwenden, die du an die Spalten anschliesst und so das Spalten-Multiplexen direkt machst.

Von welchen Ausgängen ist die Rede? Mit 5V direkt verbinden wird nicht gehen da ich die Spalten und Reihen ja über Flachbandkabel mit 6-poligen und 12-poligen Steckverbinder kontaktiert habe.

Mir ist ein Problem aufgefallen:
Wenn alle Kreuzungspunkte mit der Velostat-Widerstandsmatte untereinander verbunden sind, bräuchte man noch zusätzlich in jedem Kreuzungspunkt eine Diode, um das Ganze frei von Rückwirkungen zu halten, oder ?

Aber das müsste auch schon bei deiner direkten Widerstandmessung zwischen einem Spalten- und einem Reihendraht der Fall sein, auch wenn die gerade nicht aktiven Reihen und Spalten nicht auf LOW, sondern offen sind.


Oder habe ich da einen Denkfehler ?

michael_x:
Wenn alle Kreuzungspunkte mit der Velostat-Widerstandsmatte untereinander verbunden sind, bräuchte man noch zusätzlich in jedem Kreuzungspunkt eine Diode, um das Ganze frei von Rückwirkungen zu halten, oder ?

Naja, ein "Kanalübersprechen" hast Du bei so einer Konstruktion schon, aber solange der Widerstand am direkten Druckpunkt um wenigstens eine Größenordnung kleiner ist als der Widerstand zum Nachbarkanal (Spalte) sollte das Signal auswertbar bleiben. Hier hängt viel von der Sohlenkonstruktion ab, wie gut die Druckpunkte voneinander unterscheidbar und damit messbar sind.

Gruß André

Mir ist ein Problem aufgefallen:
Wenn alle Kreuzungspunkte mit der Velostat-Widerstandsmatte untereinander verbunden sind, bräuchte man noch zusätzlich in jedem Kreuzungspunkt eine Diode, um das Ganze frei von Rückwirkungen zu halten, oder ?

Aber das müsste auch schon bei deiner direkten Widerstandmessung zwischen einem Spalten- und einem Reihendraht der Fall sein, auch wenn die gerade nicht aktiven Reihen und Spalten nicht auf LOW, sondern offen sind.

Ne da denkst du falsch glaub ich, also es funktioniert vom Aufbau her alles so wie es sollte. Mir fehlt jetzt eben nur noch der korrekte Anschluss der 6 Spalten.

fehlt jetzt eben nur noch der korrekte Anschluss der 6 Spalten

In meinem Bildchen von heute 02:18 sind das die Linien links (4 in diesem Beispiel-Bild)
Eine von denen sollte OUTPUT HIGH sein, die anderen INPUT (= High Impedance) oder LOW.

solange der Widerstand am direkten Druckpunkt um wenigstens eine Größenordnung kleiner ist als der Widerstand zum Nachbarkanal

Na, im Gegensatz zu einer Tasten-Matrix, werden ja "alle" Kreuzungspunkte mehr oder weniger gleichmässig belastet. Immerhin geht der Einfluss der Nachbar-Kanäle durch zwei Widerstände hintereinander, aber dafür durch alle 5 Nachbarspalten. So ganz bin ich von einer Lösung ohne Dioden noch nicht überzeugt.

michael_x:
Immerhin geht der Einfluss der Nachbar-Kanäle durch zwei Widerstände hintereinander, aber dafür durch alle 5 Nachbarspalten.

Damit hast Du zwar Recht, aber um so weiter weg der 2. /3./ 4. Nachbarkanal ist um so größer und unbedeutender wird der Widerstand der Folie. Die soll nur 0.1 - 0.2mm dick sein. Unter der Annahme, daß der Widerstand der Folie nicht richtungsgebunden ist, hast Du am Druckpunkt 0,1mm Folie, zum Nachbardruckpunkt meinetwegen 5mm, also 1:50 auch den Widerstand. Der übernächste ist dann schon egal ...
Als Denkanstoß: der NANO hat 8 Analogeingänge A0-A7, A4+A5 sind I²C, bleiben 6x, passt!

Gruß André

Mir geht es nicht darum, den Widerstand über mehrere Zentimeter längs der Folie zu messen.

Vielmehr denke ich, dass die Widerstände an den anderen Kreuzungspunkten über die im Moment eigentlich nicht beachteten Spalten- und Reihen-Leitungen mitgemessen werden.

Wenn ein Fuß auf der Sohle steht, sind gut die Hälfte der Kreuzungspunkte mehr oder weniger belastet, und eine Mischung aus vielen parallel und hintereinander geschalteten Widerständen wird bei jeder Zeile-Spalte-Kombi gemessen.
( Wenn nicht jeder Kreuzungspunkt mit einer Diode entkoppelt wird. )