Resistives Sensorarray für eine Schuhsohle (Velostat)

michael_x:
Nach dem verlinkten Video sieht das Ganze ja einfach und problemlos aus, Viel Erfolg !

Ich habe es auch bereits mit dem dort verwendeten code versucht umzusetzen. Habe diesen natürlich auf eine 12x6 Matrix angepasst, sowohl im Arduino als auch im Processing. Ändere ich die beiden Sketche nicht, also starte ich es mit 15x15, dann läuft alles bis auf die Darstellung im Processing, die zeigt mir natürlich 225 Kästchen an. Aber sobald ich alle Befehle auf 12x6 anpasse und wieder auf den Arduino spiele, dann zeigt mir die Darstellung zwar 72 Kästchen an, aber es tut sich nicht wirklich was. Woran könnte es liegen?

Woran könnte es liegen?

An deiner Anpassung :wink:

"Sowohl im Arduino als auch im Processing"

michael_x:
Woran könnte es liegen?

An deiner Anpassung :wink:

"Sowohl im Arduino als auch im Processing"

Vielleicht kann ja mal einer noch darüber gucken?
Hier der Processing Code:

import processing.serial.*;
import processing.opengl.*;


int bgcolor;                 // Background color
int fgcolor;                 // Fill color
Serial myPort;                       // The serial port
int[] serialInArray = new int[72];    // Where we'll put what we receive
int[] pastInArray = new int [72];
float[][] colorTarget   = new float[3][255];
float[][] currentColor   = new float[3][255];
PVector[][] vertices = new PVector[6][12];
float[] verticesTZ = new float[12];
float w = 18;
float ease = 0.75; 

int serialCount = 0;                 // A count of how many bytes we receive
int xpos, ypos;                  // Starting position 
boolean firstContact = false;        // Whether we've heard from the microcontroller
int tiempoant;
int render=0;
int dif=0;

void setup() {
  size(960, 600, OPENGL);  // Stage size
  noStroke();      // No border on the next thing draw
  
  
  // Print a list of the serial ports, for debugging purposes:
  println(Serial.list());

  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  
  myPort = new Serial(this, Serial.list()[1], 115200);
  
  for (int j = 0; j < 12; j++) {
        for (int i = 0; i < 6; i++) {
            vertices[i][j] = new PVector( i*w, j*w, 0);
        }
    }
    
  
}

void draw() {

  if (render==1) {
    
    translate(width/4, 100);
    rotateX(0.5);
    //rotateX(PI/10);
    background(0);
    for (int j=0; j<11; j++) {
      beginShape(QUAD_STRIP);
      for (int i=0; i<6; i++) {
          stroke(255);
     
          fill(serialInArray[j*6+i], 0, 0);
          float x = i*width/12;
          float y = j*height/6;
          verticesTZ[i] = serialInArray[j*6+i];
          
          vertices[i][j].z += (verticesTZ[i]-vertices[i][j].z)*ease;
          vertex( vertices[i][j].x, vertices[i][j].y, vertices[i][j].z);
          vertex( vertices[i][j+1].x, vertices[i][j+1].y, vertices[i][j+1].z);
        }
         endShape(CLOSE);
        //        println();
      }
      render=0;
  }
}

void serialEvent(Serial myPort) {
  // read a byte from the serial port:
  int inByte = myPort.read();
  // if this is the first byte received, and it's an A,
  // clear the serial buffer and note that you've
  // h
  //  ad first contact from the microcontroller. 
  // Otherwise, add the incoming byte to the array:
  if (firstContact == false) {
    if (inByte == 'A') { 
      myPort.clear();          // clear the serial port buffer
      firstContact = true;     // you've had first contact from the microcontroller
      myPort.write('A');       // ask for more
    }
  } else {
    // Add the latest byte from the serial port to array:

      serialInArray[serialCount] = inByte;

    serialCount++;

    // If we have 3 bytes:
    if (serialCount > 71 ) {
      println(millis()-tiempoant);
      tiempoant = millis();
      
      render = 1;
    
      // Send a capital A to request new sensor readings:
      myPort.write('A');
      // Reset serialCount:
      serialCount = 0;
    }
  }
}

Und hier das Arduino Pendant:

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

//Mux control pins for Output signal (OUT_pin) default for arduino mini pro
const byte w0 = 9; 
const byte w1 = 8;
const byte w2 = 7;
const byte w3 = 6;

//Mux in "SIG" pin default for arduino mini pro 
const byte SIG_pin = 0; 

//Mux out "SIG" pin default for arduino mini pro
const byte OUT_pin = 5;

//Row and Column pins default for arduino mini pro
const byte STATUS_pin = 3;
const byte COL_pin = 2;

const boolean muxChannel[16][4]={
    {0,0,0,0}, //channel 0
    {1,0,0,0}, //channel 1
    {0,1,0,0}, //channel 2
    {1,1,0,0}, //channel 3
    {0,0,1,0}, //channel 4
    {1,0,1,0}, //channel 5
    {0,1,1,0}, //channel 6
    {1,1,1,0}, //channel 7
    {0,0,0,1}, //channel 8
    {1,0,0,1}, //channel 9
    {0,1,0,1}, //channel 10
    {1,1,0,1}, //channel 11
    {0,0,1,1}, //channel 12
    {1,0,1,1}, //channel 13
    {0,1,1,1}, //channel 14
    {1,1,1,1}  //channel 15
  };


//incoming serial byte
int inByte = 0;

int valor = 0;               //variable for sending bytes to processing
int calibra[12][6];         //Calibration array for the min values of each od the 72 sensors.
int minsensor=254;          //Variable for staring the min array
int multiplier = 254;
int pastmatrix[12][6];

void setup(){
    
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  
  pinMode(w0, OUTPUT); 
  pinMode(w1, OUTPUT); 
  pinMode(w2, OUTPUT); 
  pinMode(w3, OUTPUT); 
  
  pinMode(OUT_pin, OUTPUT); 
  
  pinMode(STATUS_pin, OUTPUT);
  pinMode(COL_pin, OUTPUT);

  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
  digitalWrite(w0, LOW);
  digitalWrite(w1, LOW);
  digitalWrite(w2, LOW);
  digitalWrite(w3, LOW);
  
  digitalWrite(OUT_pin, HIGH);
  digitalWrite(STATUS_pin, HIGH);
  digitalWrite(COL_pin, HIGH);
  
 
  
  Serial.begin(115200);
  
  Serial.println("\n\Calibrating...\n");
  
  // Full of 0's of initial matrix
  for(byte j = 0; j < 12; j ++){ 
    writeMux(j);
    for(byte i = 0; i < 6; i ++)
      calibra[j][i] = 0;
  }
  
  // Calibration
  for(byte k = 0; k < 50; k++){  
    for(byte j = 0; j < 12; j ++){ 
      writeMux(j);
      for(byte i = 0; i < 6; i ++)
        calibra[j][i] = calibra[j][i] + readMux(i);
    }
  }
  
  //Print averages
  for(byte j = 0; j < 12; j ++){ 
    writeMux(j);
    for(byte i = 0; i < 6; i ++){
      calibra[j][i] = calibra[j][i]/50;
      if(calibra[j][i] < minsensor)
        minsensor = calibra[j][i];
      Serial.print(calibra[j][i]);
      Serial.print("\t");
    }
  Serial.println(); 
  }
  
  Serial.println();
  Serial.print("Minimum Value: ");
  Serial.println(minsensor);
  Serial.println();
  
  establishContact();
 
  digitalWrite(COL_pin, LOW);
}


void loop(){
  //Loop through and read all 16 values
  //Reports back Value at channel 6 is: 346
  if (Serial.available() > 0){
    inByte = Serial.read();
    
    if(inByte == 'A'){
    
      for(int j = 12; j >= 0; j--){ 
        writeMux(j);
        
        for(int i = 0; i < 7; i++){
            
          valor = readMux(i);
          
          //Saturation sensors
          int limsup = 450;
          if(valor > limsup)
            valor = limsup;
            
          if(valor < calibra[j][i])
            valor = calibra[j][i];  
          
          valor = map(valor,minsensor, limsup,1,254); 
          
          if(valor < 150)
            valor = 0;
          if(valor > 254)
            valor = 254;
          
          Serial.write(valor);
          digitalWrite(COL_pin,!digitalRead(COL_pin));
        } 
      }
    }
        
  }
}


int readMux(byte channel){
  byte controlPin[] = {s0, s1, s2, s3};

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }

  //read the value at the SIG pin
  int val = analogRead(SIG_pin);

  //return the value
  return val;
}

void writeMux(byte channel){
  byte controlPin[] = {w0, w1, w2, w3};

  //loop through the 4 sig
  for(byte i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
}

void establishContact() {
  while (Serial.available() <= 0) {
    Serial.print('A');   // send a capital A
    delay(300);
  }
}

Im Anhang ist ein Foto der Darstellung die ich von Processing bekomme. Nur dass das Ganze sich ständig bewegt.

Processing Display.png

Mir kommen die Konstruktoren mit "new int[]..." verdächtig vor. Falls hier die Arrays zur Laufzeit erzeugt werden, kann das zu Problemen mit dem dynamischen Speicher führen.

@DrDiettrich: Die Überschriften "Arduino Code" / "Processing Code" sind vertauscht.

import processing.serial.*; ist natürlich Java.

Ah ja, ich habe mich schon über setup() und loop() im Processing Code gewundert :wink:

michael_x:
@DrDiettrich: Die Überschriften "Arduino Code" / "Processing Code" sind vertauscht.

import processing.serial.*; ist natürlich Java.

Stimmt, auch eben erst gemerkt. Sorry dafür :slight_smile:

Kann mir nochmal jemand sagen wie ich den Widerstand für den Spannungsteiler wähle? Wenn ich mein Multimeter anschließe zeigt mir dieses einen sich dauernd abnehmenden Wert beginnend bei 50kOhm bis ca 20kOhm... beim Aufbringen von Druck ändert sich dieser auf etwa 2 - 1,5kOhm.

Vielleicht kriecht das Material beim Auflegen der Meßspitzen. Der Meßwiderstand sollte etwa in der Mitte des Widerstandsbereichs liegen, wobei die Obergrenze schon durch die normale Belastung (Körpergewicht) begrenzt ist.

Hi,

die Messung des Widerstandes ist am genauesten, wenn Du oben wie unten den gleichen Spannungswert hast (rawADC 1024 / 2), zu den Rändern hin wird der Wert immer ungenauer. Die Messfehlerkurve ergibt eine Badewanne zwischen den Werten 0 bis 1023, in der Mitte flach (genau) und knapp vor dem Rand jeweils steil ansteigend. Da Du Werte zwischen 1,5k und ca. 20k nennst, würde ich ca. 5,4k Ohm nehmen, dann hast Du in Richtung 1,5k Faktor 3,6x wie auch in Richtung 20k, liegst also in der Mitte Deiner genannten Daten.

Gruß André

michael_x:
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)

Hallo Michael,

ich komme nochmal zurück auf deinen Tipp hier.

Ich habe nun Meinen Arduino Code soweit fertig, nur wenn ich mir den Seriellen Monitor öffne, werden mir zwar die Werte in Form einer Matrix (12x6) angezeigt, dass aber nur ein einziges mal. Die Werte ändern sich also nicht mehr bei Belastung. Mein Ziel ist, dass der serielle Monitor bei jedem neuen Kontakt mit der Sohle eine neue Matrix mit neuen Werten ausgibt.

Hier der aktuelle Sketch:

void setup(){
    
  pinMode(s0, OUTPUT); 
  pinMode(s1, OUTPUT); 
  pinMode(s2, OUTPUT); 
  pinMode(s3, OUTPUT); 
  
  pinMode(w0, OUTPUT); 
  pinMode(w1, OUTPUT); 
  pinMode(w2, OUTPUT); 
  pinMode(w3, OUTPUT); 
  
  pinMode(OUT_pin, OUTPUT); 
  
  pinMode(STATUS_pin, OUTPUT);
  pinMode(COL_pin, OUTPUT);

  
  digitalWrite(s0, LOW);
  digitalWrite(s1, LOW);
  digitalWrite(s2, LOW);
  digitalWrite(s3, LOW);
  
  digitalWrite(w0, LOW);
  digitalWrite(w1, LOW);
  digitalWrite(w2, LOW);
  digitalWrite(w3, LOW);
  
  digitalWrite(OUT_pin, HIGH);
  digitalWrite(STATUS_pin, HIGH);
  digitalWrite(COL_pin, HIGH);
  
 
  
  Serial.begin(115200);
  
  
  // Full of 0's of initial matrix
  for(byte j = 0; j < 13; j ++){ 
    writeMux(j);
    for(byte i = 0; i < 7; i ++)
      calibra[j][i] = 0;
  }
  
  // Calibration
  for(byte k = 0; k < 50; k++){  
    for(byte j = 0; j < 13; j ++){ 
      writeMux(j);
      for(byte i = 0; i < 7; i ++)
        calibra[j][i] = calibra[j][i] + readMux(i);
    }
  }
  
  //Print averages
  for(byte j = 0; j < 12; j ++){ 
    writeMux(j);
    for(byte i = 0; i < 6; i ++){
      calibra[j][i] = calibra[j][i]/50;
      if(calibra[j][i] < minsensor)
        minsensor = calibra[j][i];
      Serial.print(calibra[j][i]);
      Serial.print("\t");
    }
  Serial.println(); 
  }
  
  Serial.println();
  Serial.print("Minimum Value: ");
  Serial.println(minsensor);
  Serial.println();
  
  establishContact();
 
  digitalWrite(COL_pin, LOW);
}


void loop(){
 
  if (Serial.available() > 0){
    inByte = Serial.read();
    
    if(inByte == 'A'){
    
      for(int j = 12; j >= 0; j--){ 
        writeMux(j);
        
        for(int i = 0; i < 7; i++){
            
          valor = readMux(i);
          
          //Saturation sensors
          int limsup = 450;
          if(valor > limsup)
            valor = limsup;
            
          if(valor < calibra[j][i])
            valor = calibra[j][i];  
          
          valor = map(valor,minsensor, limsup,1,254); 
          
          if(valor < 150)
            valor = 0;
          if(valor > 254)
            valor = 254;
          
          Serial.write(valor);
          digitalWrite(COL_pin,!digitalRead(COL_pin));
        } 
      }
    }
        
  }
}


int readMux(byte channel){
  byte controlPin[] = {s0, s1, s2, s3};

  //loop through the 4 sig
  for(int i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }

  //read the value at the SIG pin
  int val = analogRead(SIG_pin);

  //return the value
  return val;
}

void writeMux(byte channel){
  byte controlPin[] = {w0, w1, w2, w3};

  //loop through the 4 sig
  for(byte i = 0; i < 4; i ++){
    digitalWrite(controlPin[i], muxChannel[channel][i]);
  }
}

void establishContact() {
  while (Serial.available() <= 0) {
    Serial.print('A');   // send a capital A
    delay(300);
  }
}

Du hast das so gebaut, dass erst bei Eingabe eines 'A' eine neue Messung getriggert wird. Tust Du das?

Gruß Tommy

Tommy56:
Du hast das so gebaut, dass erst bei Eingabe eines 'A' eine neue Messung getriggert wird. Tust Du das?

Gruß Tommy

Du meinst wenn ich ein 'A' sende? Also bei mir kommt halt am Anfang die gewünschte Matrix mit den Werten (je nachdem wie stark ich Anfangs die Sohle belaste) und ab dann tut sich nichts mehr, außer dass ich eben ein nach rechts fortlaufendes 'A' unterhalb der Matrix bekomme (establishContact).

Ich beziehe mich auf den Code in #43

void loop(){
 
  if (Serial.available() > 0){
    inByte = Serial.read();
    
    if(inByte == 'A'){

....

Gruß Tommy

Tommy56:
Ich beziehe mich auf den Code in #43

void loop(){

if (Serial.available() > 0){
    inByte = Serial.read();
   
    if(inByte == 'A'){

....



Gruß Tommy

Okay, aber was meinst du damit? Wie müsste der code den da abgeändert werden?

Das ist der Nachteil, wenn man Code verwendet, den man nicht verstanden hat.
Du musst im Seriellen Monitor ein A eingeben und Senden drücken, damit das ausgeführt wird, was bei den .... steht.

Warum Du in establishContact() ein A zurück sendest erschließt sich mir nicht. Soll das evtl. der Hineis sein, ein A einzugeben?

Gruß Tommy

Tommy56:
Das ist der Nachteil, wenn man Code verwendet, den man nicht verstanden hat.
Du musst im Seriellen Monitor ein A eingeben und Senden drücken, damit das ausgeführt wird, was bei den .... steht.

Warum Du in establishContact() ein A zurück sendest erschließt sich mir nicht. Soll das evtl. der Hineis sein, ein A einzugeben?

Gruß Tommy

Das habe ich schon verstanden. Problem ist aber, sende ich nun ein A, dann tut sich eben nichts mehr. Der serielle Monitor sieht aus als hätte er sich aufgehängt. Kann doch nicht so schwer sein bei jedem neuen Kontakt mit der Sohle, ein neues Array mit Werten auszuspucken oder?

Warum Du in establishContact() ein A zurück sendest erschließt sich mir nicht. Soll das evtl. der Hineis sein, ein A einzugeben?

Richtig.

Woran willst Du denn den neuen Kontakt mit der Sohle erkennen?

Die Funktion establishContact() sollte nach meiner Meinung nur eine Ausgabe machen und keine Schleife beinhalten.

Gruß Tommy

Tommy56:
Woran willst Du denn den neuen Kontakt mit der Sohle erkennen?

Ja ich drücke doch mit der Hand oder dem Fuß darauf!? Und dann ändert sich mein Spannungswert je nachdem wie stark ich belaste. Und genau hier soll immer ein neues Array ausgegeben werden.

Dann musst Du mit 2 Arrays arbeiten und alle Werte des alten Arrays mit den Werten der neuen Messung vergleichen. Sobald Du feststellst, dass ein Wert anders ist (oder um mehr als x anders ist) musst Du ein neues Messwertset schreiben und das neue Array zum alten Array machen.

Ich vermute, dass genau das der Grund war, den Start der Messung per seriellem Monitor zu triggern.

Gruß Tommy