ԀI˥ℲOᙠᴚ∩⊥
🔍

silicone soft touch interface

Working with soft material as a base for digital user interface comes with the challenge to make as many electronic components flexible as possible. Therefore is is very helpful to refer to one of out past experiments with textile and use conductive thread – at least for doing some experiments.

Three biomorph soft samples made from kneading silicone
Besides the obvious topology of the surface, the flexible material offers a very diverse behaviour when pressed or squeezed

inital experiment

Kneading silicone works best for some rapid experiments without pouring and messing up the studio 🙂 – This silicone gets fixed within seconds and comes with two components. It’s even possible to addon material to existing structures. This prototype is for the finger – with two touch inputs realized with conductive thread stiched through the silicone material. This works pretty well even when stiching through longer segments of the material. The thread can be then sealed with more silicone to avoid shortcuts.

inital rough prototype for the finger with kneading silicone
inital rough prototype – the thread is stiched through the material and sealed with the sam silicone afterwards

code and tools

Using the ESP32 with integrated touch pins is the best choice for this experiment. Using the serial interface to send the touch data to Processing makes it possible to even visualize the output properly. I used the TURBOFLIP’S own touch helper for this – just insert it to your project.

#include <Arduino.h>
#include <touch.h>

aTouch touch1(T0);
aTouch touch2(T1);

aTouch touch3(T2);
aTouch touch4(T3);
aTouch touch5(T4);
aTouch touch6(T5);
aTouch touch7(T6);
aTouch touch8(T7);
aTouch touch9(T8);

void setup() {

  Serial.begin(9600);
  Serial.println("0,0"); // initally send null to init

  // put your setup code here, to run once:
}


void loop() {

  touch1.readAndProcessInput();
   touch2.readAndProcessInput();
     touch3.readAndProcessInput();
   touch4.readAndProcessInput();
    touch5.readAndProcessInput();
   touch6.readAndProcessInput();
     touch7.readAndProcessInput();
   touch8.readAndProcessInput();
   touch9.readAndProcessInput();

  // Serial.println(touch1.smoothed_val);

 // if (Serial.available()>0){

    Serial.print(touch1.smoothed_val);
 Serial.print(",");
 Serial.print(touch2.smoothed_val);
 Serial.print(",");
 Serial.print(touch3.smoothed_val);
 Serial.print(",");
 Serial.print(touch4.smoothed_val);
 Serial.print(",");
 Serial.print(touch5.smoothed_val);
 Serial.print(",");
 Serial.print(touch6.smoothed_val);
 Serial.print(",");
 Serial.print(touch7.smoothed_val);
 Serial.print(",");
 Serial.print(touch8.smoothed_val);
 Serial.print(",");
 Serial.println(touch9.smoothed_val);
  //}
   delay(11);

  // put your main code here, to run repeatedly:
}
// ----------------------------------
// ------- TRXYS TOUCH HELPERS ------
// ----------------------------------
// ( put this code PRIOR to your mainloop code or you will get nice errors :) )
  
  // simple lerp helper function
  
float return_lerp(float _s, int _target,int _time){
   
   _s = _s + (( float(_target) - _s)/float(_time));
   return _s;
     
}
  
class aTouch {
  private:
    bool prev_touch_state = false;
    byte pin;
    int smooth_time = 2;
    int trigger_threshold = 15;
    long ts = 0;
  public:
    int current_val = 0;
    int smoothed_val = 0;
    int diff_val = 0;
    bool is_triggered = false;
    bool on_pressed = false;
    bool on_released = false;
     bool is_holded = false;
    aTouch(byte pin) {
     this->pin = pin;
    }
      
  
    void readAndProcessInput() {
  
        // reset interaction states
        on_pressed = false;
        on_released = false;
          
         // directly read out values TWICE = BUGFIX for debouncing 
         current_val = touchRead(pin);
         delayMicroseconds(10);
         current_val = touchRead(pin);
  
        //calculate smoothed input values 
         smoothed_val = return_lerp(smoothed_val,current_val,smooth_time);
  
         // calc current differential sum of button
          diff_val =   smoothed_val - current_val;
  
          // check if there is a noticable difference input values
          if(  diff_val  > trigger_threshold){
  
              if(prev_touch_state == false){
                is_triggered = true;
                prev_touch_state = is_triggered;
                on_pressed = true;
                ts = millis(); // set timestamp for hold routine
             }
               
          }else if( diff_val < trigger_threshold*-.4){
  
              if(prev_touch_state == true){
                is_triggered = false;
                 prev_touch_state = is_triggered;
                 on_released = true;
              }
                  
          }
  
  
          // calculate timed holding function
            
          if( ts + 2500 < millis() && is_triggered){
  
                 
              is_holded = true;
          }else{
  
              is_holded = false;
           }
 
       delayMicroseconds(2);
     }
 
};
Processing App just showing the raw output coming from the ESP
import processing.serial.*;

Serial myPort;

int t1_val = 0;
int t2_val = 0;
int t3_val = 0;
int t4_val = 0;
int t5_val = 0;
int t6_val = 0;
int t7_val = 0;
int t8_val = 0;
int t9_val = 0;
 
void setup () {
  size(300,300);        // window size
  noSmooth();
 ellipseMode(CENTER);
  
  // List all the available serial ports
  //println(Serial.list());
  String portName = Serial.list()[0];
  myPort = new Serial(this,portName, 9600);
  myPort.bufferUntil('\n');
   
}
 

void serialEvent (Serial myPort) {
 
  try {
   operateSerial(myPort);
  }
  catch(RuntimeException e) {
    e.printStackTrace();
  }
 
}

float[] all_touch_vals = {0,0,0,0,0,0,0,0,0};

void operateSerial(Serial myport) {
  String portData = myport.readString();
   
  String[] stringData = split(portData, ',');
   
  int[] values = int(stringData);
   
  t1_val = int(values[0]);
  all_touch_vals[0]=t1_val;
  
   t2_val = int(values[1]); 
  all_touch_vals[1]=t2_val;
  
   t3_val = int(values[2]);
   all_touch_vals[2]=t3_val;
   
  t4_val = int(values[3]);
   all_touch_vals[3]=t4_val;
   
  t5_val = int(values[4]);
   all_touch_vals[4]=t5_val;
  
  t6_val = int(values[5]);
   all_touch_vals[5]=t6_val;
   
  t7_val = int(values[6]);
   all_touch_vals[6]=t7_val;
  
  t8_val = int(values[7]);
   all_touch_vals[7]=t8_val;
  
  t9_val = int(values[8]);
   all_touch_vals[8] = t9_val;
 
}

void draw(){

    background(22);
    fill(255);
    textSize(8);
    for(int i=0;i<9;i++){
      
      fill(222);
      float mappedh = map(all_touch_vals[i],0.,150.,0.,300.); // map the touchpin values around the height of the stage
      rect(i*30,0,20,mappedh);
      
      fill(122);
      text("T:"+i,i*30+4,10);
      
    }

}
 
Related Posts
The unglaubliche ᴏɴᴇʙɪᴛ:ɢᴀʟʟᴇʀʏ – the most minimalistic digital art gallery

what is ᴏɴᴇʙɪᴛ:ɢᴀʟʟᴇʀʏ? As you might already guessed, OBG is all about digital pixel art. The OBG is the most Read more

µFOUR – the minimalist local multiplayer game console – RGB matrix version

development blog of a minimalist 16x16 rgb LED matrix interaction and gaming console