Calm Technology // 19

Since I had scripted the different gestures I wanted to have for Tap in Arduino, I could now combine all the gestures into one script. I then connected the Wemos board that controls Tap to the wifi so that I could trigger each of these gestures wirelessly from my laptop via a simple interface.

To create the interface, I used Max 8 to build a simple patch to send OSC messages to my Wemos board. The patch consists of a few buttons that trigger messages with a value between 0 & 3, which are then sent as an OSC message via UDP to trigger different parts of the Arduino script.

Max patch interface to control tap

I combined all the different gesture scripts into one Arduino script that can receive OSC messages via UDP. These messages set the value for a variable which is then queried in the loop of the script to start the desired gestures. After the gestures have finished, the variable is reset to put Tap back into a suspended state.

#include <AccelStepper.h>
#include <ESP8266WiFi.h>  // The Library for WIFI
#include <WiFiUdp.h>  // Library for UDP
#include <OSCMessage.h>  //Library for OSC

#define motorInterfaceType 1

// Define the stepper motor and the pins that is connected to // (STEP, DIR)
AccelStepper stepper1(motorInterfaceType, D5, D6); 
AccelStepper stepper2(motorInterfaceType, D7, D8);

// Set the target positions for both steppers
int PositionDown = 0;
int PositionUp = 0;

// State variable to keep track of movement sequence
int state1 = 0;
int state2 = 0;

// For triggering movements
int mode = 0;

WiFiUDP Udp;

const char* ssid = "************";           
const char* password = "************";      

const IPAddress dstIp(192,168,1,129); 
const unsigned int dstPort = 7250;  // Destination OSC
const unsigned int localPort = 7300; // Reciving OSC


////////////////////////////////////////////////////////////////////////////////////


void setup() {
  
  Serial.begin(9600);

  // Settings for Motor 1
  stepper1.setMaxSpeed(1000); 
  stepper1.setAcceleration(500);
  stepper1.setCurrentPosition(0);

  // Settings for Motor 2
  stepper2.setMaxSpeed(1000);
  stepper2.setAcceleration(500);
  stepper2.setCurrentPosition(0);

  // Connecting to WIFI
  Serial.print("Connecting WiFi ");
  // Prevent need for powercyle after upload.
  WiFi.disconnect();

  // Use DHCP to connect and obtain IP Address.
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid,password);

  // Wait until we have connected to the WiFi AP.
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("Done!");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  Udp.begin(localPort);

}


////////////////////////////////////////////////////////////////////////////////////


void loop() {

  handleOSC();

  if (mode == 0) {

    state1 = 0;
    state2 = 0;

  }

  if (mode == 1) {

    Wave1();
    Wave2();

  }

  if (mode == 2) {
    
    Knock1();

  }

  if (mode == 3) {
    
    Tap1();
    Tap2();

  }

}


////////////////////////////////////////////////////////////////////////////////////


void Wave1() {

  switch (state1) {

    case 0:
      stepper1.setAcceleration(200);
      PositionDown = 40;
      stepper1.moveTo(PositionDown);
      state1 = 1;
      break;
    
    case 1:
      if (stepper1.distanceToGo() != 0) {
        stepper1.run();
      } else {
        stepper1.stop();
        PositionDown = -40;
        stepper1.moveTo(PositionDown);
        state1 = 2;
      }
      break;
    
    case 2:
      if (stepper1.distanceToGo() != 0) {
        stepper1.run();
      } else {
        stepper1.stop();
        PositionDown = 20;
        stepper1.moveTo(PositionDown);
        state1 = 3;
      }
      break;

    case 3:
      if (stepper1.distanceToGo() != 0) {
        stepper1.run();
      } else {
        stepper1.stop();
        PositionDown = -20;
        stepper1.moveTo(PositionDown);
        state1 = 4;
      }
      break;

    case 4:
      stepper1.setAcceleration(100);
      if (stepper1.distanceToGo() != 0) {
        stepper1.run();
      } else {
        stepper1.stop();
        PositionDown = 0;
        stepper1.moveTo(PositionDown);
        state1 = 5;
      }
      break;
    
    case 5:
      if (stepper1.distanceToGo() != 0) {
        stepper1.run();
      } else {
        stepper1.stop();
      }
      break;
  }
}


void Wave2() {

  if (state1 >= 4){

    switch (state2) {

      case 0:
        stepper2.setAcceleration(275);
        PositionUp = 25;
        stepper2.moveTo(PositionUp);
        state2 = 1;
        break;
      
      case 1:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = -25;
          stepper2.moveTo(PositionUp);
          state2 = 2;
        }
        break;
      
      case 2:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = 15;
          stepper2.moveTo(PositionUp);
          state2 = 3;
        }
        break;

      case 3:
        
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = -15;
          stepper2.moveTo(PositionUp);
          state2 = 4;
        }
        break;

      case 4:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = 15;
          stepper2.moveTo(PositionUp);
          state2 = 5;
        }
        break;

      case 5:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = -15;
          stepper2.moveTo(PositionUp);
          state2 = 6;
        }
        break;

      case 6:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          PositionUp = 0;
          stepper2.moveTo(PositionUp);
          state2 = 7;
        }
        break;  
      
      case 7:
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          mode = 0;          
        }
        break;
    }
  }
}


void Knock1() {

  switch (state1) {

    case 0:
      stepper2.setAcceleration(400);
      PositionUp = -20;
      stepper2.moveTo(PositionUp);
      state1 = 1;
      break;
    
    case 1:
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        PositionUp = 80;
        stepper2.moveTo(PositionUp);
        state1 = 2;
      }
      break;
    
    case 2:
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        PositionUp = 60;
        stepper2.moveTo(PositionUp);
        state1 = 3;
      }
      break;

    case 3:
      stepper2.setAcceleration(800);
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        PositionUp = 80;
        stepper2.moveTo(PositionUp);
        state1 = 4;
      }
      break;

    case 4:
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        PositionUp = 0;
        stepper2.moveTo(PositionUp);
        state1 = 5;
      }
      break;
    
    case 5:
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        mode = 0;
      }
      break;
  }
}


void Tap1() {

  if (state2 >= 2){

    switch (state1) {

      case 0:
        stepper1.setAcceleration(300);
        PositionDown = -20;
        stepper1.moveTo(PositionDown);
        state1 = 1;
        break;
        
      case 1:
        if (stepper1.distanceToGo() != 0) {
          stepper1.run();
        } else {
          stepper1.stop();
          PositionDown = 5;
          stepper1.moveTo(PositionDown);
          state1 = 2;
        }
        break;
        
      case 2:
        stepper1.setAcceleration(600);
        if (stepper1.distanceToGo() != 0) {
          stepper1.run();
        } else {
          stepper1.stop();
          PositionDown = -20;
          stepper1.moveTo(PositionDown);
          state1 = 3;
        }
        break;

      case 3:
        if (stepper1.distanceToGo() != 0) {
          stepper1.run();
        } else {
          stepper1.stop();
          PositionDown = 0;
          stepper1.moveTo(PositionDown);
          state1 = 4;
        }
        break;

      case 4:
        stepper1.setAcceleration(100);
        if (stepper1.distanceToGo() != 0) {
          stepper1.run();
        } else {
          stepper1.stop();
        }
        break;
      
    }
  }
}


void Tap2() {

  switch (state2) {

    case 0:
      stepper2.setAcceleration(400);
      PositionUp = 50;
      stepper2.moveTo(PositionUp);
      state2 = 1;
      break;
    
    case 1:
      if (stepper2.distanceToGo() != 0) {
        stepper2.run();
      } else {
        stepper2.stop();
        PositionUp = 0;
        stepper2.moveTo(PositionUp);
        state2 = 2;       
      }
      break;

    case 2:
      if (state1 >= 4) {
        stepper2.setAcceleration(200);
        if (stepper2.distanceToGo() != 0) {
          stepper2.run();
        } else {
          stepper2.stop();
          mode = 0;
        }
      }
      break;
        
  }
}


////////////////////////////////////////////////////////////////////////////////////


void handleOSC() {
  
  OSCMessage msg("/Mode");
  int size = Udp.parsePacket();
  if (size > 0) {
    while (size--) {
      msg.fill(Udp.read());
    }
    if (!msg.hasError()) {
      msg.dispatch("/Mode", Activating);
    }
  }
}


void Activating(OSCMessage &msg) {
  
  if (msg.isInt(0)) {
    int receivedMode = msg.getInt(0);
    mode = receivedMode;
    Serial.println("Received Mode Command");
    Serial.println(mode);

  }
}

After finishing the interface and the now complete Arduino script, I tested them together. With my laptop set up as a touch interface running Max 8 and the Wemos board running Tap as usual. All went quite smoothly and after some tweaking everything is now running stable. You can see the result below.

Tap controlled via a remote interface

With this, my prototype for this semester’s Design & Research project is almost finished. The last step will be to make the interface a bit cleaner and more intuitive, and then I will make a video explaining my prototype Tap and how it works.

1 comment
  1. This is so sick, can’t wait to see more!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert