Modular interactive input system

Interactively controlled input

This system can be used with Modular, interactive input devices and allows craftspeople to use tactile input to control brush strokes and ink flow. It uses wireless communication to send the sensor input to the machine. You can connect 7x touch sensors, 2 analog sensors and one digital sensor using rectangular receptacle connectors, like in the image below.

With this additional device, you can tune the sensitivity of the two analog sensors.

Technical visualisation

Code: interactive input sender

#include <esp_now.h>
#include <WiFi.h>


int touchAngle;              // variable to store servo angle in for the touch input to revolution angle
int squeezeSensorPin1 = A9;  // Squeeze sensor pin > up/down
int soundSensorPin2 = A10;   // Sound sensor pin > sweep
int buttonPin = D6;
#define NUM_TOUCH_PINS 7

int touchPins[NUM_TOUCH_PINS] = { T1, T2, T3, T4, T5, T6, T7 };
int touchThresholds[NUM_TOUCH_PINS] = { 110000, 110000, 110000, 110000, 110000, 110000, 110000 };
int mappedValues[13];  // Precompute the 13 values between 0 and 180

int sensorData1 = 0;
int sensorData2 = 0;

// Keeps track of the last pins touched
// so we know when buttons are 'released'
uint16_t lasttouched = 0;
uint16_t currtouched = 0;

// REPLACE WITH YOUR RECEIVER MAC Address: 64:e8:33:00:90:1c
uint8_t broadcastAddress[] = { 0x64, 0xe8, 0x33, 0x00, 0x90, 0x1c };

// Structure example to send data
// Must match the receiver structure
typedef struct struct_message {
  int id;  // must be unique for each sender board
  int revolution;
  int pressure;
  int sweep;
  int ink;
} struct_message;

// Create a struct_message called myData
struct_message myData;

esp_now_peer_info_t peerInfo;

// callback when data is sent
void OnDataSent(const uint8_t *mac_addr, esp_now_send_status_t status) {
  Serial.print("\r\nLast Packet Send Status:\t");
  Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void setup() {
  // Init Serial Monitor
  Serial.begin(115200);
pinMode(buttonPin, INPUT_PULLUP);
  // Set device as a Wi-Fi Station
  WiFi.mode(WIFI_STA);

  // Init ESP-NOW
  if (esp_now_init() != ESP_OK) {
    Serial.println("Error initializing ESP-NOW");
    return;
  }

  // Once ESPNow is successfully Init, we will register for Send CB to
  // get the status of Transmitted packet
  esp_now_register_send_cb(OnDataSent);

  // Register peer
  memcpy(peerInfo.peer_addr, broadcastAddress, 6);
  peerInfo.channel = 0;
  peerInfo.encrypt = false;

  // Add peer
  if (esp_now_add_peer(&peerInfo) != ESP_OK) {
    Serial.println("Failed to add peer");
    return;
  }
}

void loop() {
  touchAngle = getTouchAngle();  // Call the function to update touchAngle
  if (touchAngle != -1) {
    Serial.println(touchAngle);  // Print the touchAngle to Serial Monitor
  }

  sensorData1 = analogRead(squeezeSensorPin1);
  sensorData2 = analogRead(soundSensorPin2);

  // Set values to send
  myData.id = 1;           // board number in case there will be more boards sending later
  myData.revolution = touchAngle;   // 0-180
  myData.pressure = sensorData1;  // 0-4095
  myData.sweep = sensorData2;  // 0-4095
  myData.ink = digitalRead(buttonPin);  // 0-1

  Serial.println(touchAngle);
  Serial.println(sensorData1);
  Serial.println(sensorData2);
  Serial.println(digitalRead(buttonPin));

  // Send message via ESP-NOW
  esp_err_t result = esp_now_send(broadcastAddress, (uint8_t *)&myData, sizeof(myData));

  if (result == ESP_OK) {
    Serial.println("Sent with success");
  } else {
    Serial.println("Error sending the data");
  }
  delay(50);
}

// determine if touch pins are touched and map to servo motor angle 0-180

int getTouchAngle() {
  int activePin = -1;
  int nextPin = -1;

  // Check which pin(s) are touched
  for (int i = 0; i < NUM_TOUCH_PINS; i++) {
    int touchValue = touchRead(touchPins[i]);
    if (touchValue > touchThresholds[i]) {
      if (activePin == -1) {
        activePin = i;
      } else {
        nextPin = i;
        break;  // We found two adjacent touches
      }
    }
  }

  if (activePin != -1) {
    if (nextPin != -1 && nextPin == activePin + 1) {
      // Calculate interpolated value between activePin and nextPin
      int interpolatedValue = map(activePin, 0, NUM_TOUCH_PINS - 1, 0, 180);
      int nextInterpolatedValue = map(nextPin, 0, NUM_TOUCH_PINS - 1, 0, 180);
      return (interpolatedValue + nextInterpolatedValue) / 2;
    } else {
      // Return mapped value for single touch
      return map(activePin, 0, NUM_TOUCH_PINS - 1, 0, 180);
    }
  }

  return -1;  // No touch detected
}