🔍

ANFASS – tactile interfacing with AI

When we interact with machines, the visual aspect is often the most prominent and often the only interface to human physicality. However, it should not be neglected that our sensory system has the ability to perceive surface properties, vibration or shape transformation. The ANFASS prototype therefore deals with the question: Is it possible to express a non-verbal, mainly tactile dialogue with a machine instance? What form of tactile vocabulary can we use? Where is the potential and limits of this interface?

With the growing integration of complex AI systems in our immediate everyday life and work, the question arises: Which non-invasive, alternative interfaces can we develop to make the dialogue between man and machine – more physical or more sensual?
With the growing influence of AI and automation in our lives, it becomes an urgent need to remind ourselves what purpose technological advances should serve: to be more in touch with our world and ourselves.

first basic component prototype

The first prototype combines vibration, touch sensitivity and simple motor motion with a soft textile form.

#include <Arduino.h>
#include <Servo.h>
#include <touchy.h>

static const int servoPin = 26;

Servo servo1;

int steps = 10;

int tpos = 0;
int cpos = 0;

bool servo_running = false;


void new_target(){

  if(servo_running){return;} // do no double triggers!

  servo_running = true;
  tpos =  int(random(180));
  servo1.attach(servoPin);
  
}


void moveServo(){

  if(tpos>cpos){
    cpos++;
  }

  if(tpos<cpos){
    cpos--;
  }

  servo1.write(cpos);
   delay(10);

   if(tpos==cpos ){

      servo_running = false;
      servo1.detach();
      

   }

}


// ---------------------------------
// ---------------------------------
// ---------------------------------

aTouch touch1(12); 
aTouch touch2(14);
aTouch touch3(27);

#define LED_PIN 1

void setup() {
   // Serial.begin(115200);
   // servo1.attach(servoPin);
   pinMode(LED_PIN,OUTPUT);
    new_target();
}

void loop() {
 
  touch1.readAndProcessInput();
  touch2.readAndProcessInput();
  touch3.readAndProcessInput();

  
   
  if(touch1.on_pressed){
      
      new_target();
  }

   if(touch2.on_pressed){
     
      new_target();
  }

   if(touch3.on_pressed){
      //digitalWrite(LED_PIN,HIGH);
      
     // digitalWrite(LED_PIN,LOW);
    new_target();
  }

  
   moveServo();

    return;
   

      

}


// ----------------------------------
// ------- 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 = 3;
    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);
     }
 
};