Touch Board

From Interaction Station Wiki
Jump to navigation Jump to search

What is the Touch Board?

The Touch Board is a microcontroller (like Arduino for instance), with already build in capacitive sensors (also known as touch sensors) as well as an audio socket. This set up makes the board really convenient for projects having interaction through touch (or proximity) and a sound output.
Touchboard.png
In detail, the Touch Board has:

  • 12 CAPACITIVE ELECTRODES

The Touch Board has 12 capacitive electrodes that respond to a touch. These electrodes can be extended with conductive materials, like Electric Paint,

  • MP3 PLAYER AND MIDI SYNTHESIZER

The Touch Board has on-board MP3 playback and a MIDI synthesizer. This means you can either play MP3 files or simulate a MIDI instrument by touching the electrodes.

  • 3.5MM AUDIO SOCKET

In order to hear the sounds coming from the Touch Board simply connect either headphones or speakers to the 3.5mm audio socket.

  • MICROSD CARD READER

Upload MP3 files onto the supplied microSD card and change it without having to reprogram the Touch Board.

  • USB SERIAL, MIDI INTERFACE AND MOUSE AND KEYBOARD

When plugged into a computer, the Touch Board can act as a USB serial device, USB MIDI interface or as a USB mouse or keyboard. Use the data from the electrodes as an input for software that utilises either serial, MIDI or keyboard strokes.
You can also have a look at the Technical Data Sheet [here].

Some links about it

Use the Touch Board to play sounds

The Touch Board has a practical SD card reader, enabling us to upload sounds in MP3 format.
You can follow Changing the sounds of the board this instructions to change the sounds on the board.
You can use your own sounds, or look for free to use sound material online.
Here you can find a list of websites where you can find copyright free and ready to use sounds:

NB. Files can be converted by VLC or online, in case they are not in mp3 format.

Setting up your Touch Board with the Arduino Installer

The touch board can be programmed on the Arduino IDE software. In order to do so it is first required to install some dependencies that make you able to work with the Touch Board. You can find the instructions here.
Once you completed the instructions you can check whether the library has been installed correctly by opening your Arduino IDE and go to:
File --> Sketchbook --> Touch Board Examples
Touch install.png
You should be able to find already a bunch of example code you can use and modify to make it your own. To play MP3 files from the SD card when touching the sensors you can use Touch_MP3. You can also use the touch board as a keyboard with the HID_keyboard sketch.

Making Distance Sensors: Trigger the Touch Board with proximity

Maybe you might want to use the touch board sensor in a different way, maybe without actual touching happening but only by proximity to the sensor. The board allows you to modify the sensitivity of the sensor to be able to detect presence without any touching. to do so you can follow the instructions here.

Other options (not in the example folder)

Hold electrode to play sound or Play only when touched

Here you can find an already made example code that allows you to play a track only while the sensor is touched. The sound will stop when releasing the sensor.
Hold To Play Code
Download this library

Play new track only when last one is over

This code is a variant on the Touch_MP3 example but instead of starting a the corresponding track when another sensor gets triggered it forces the board to finish to play the previous file. If you press another sensor while the last track it still playing it will ignore the touch. You will be able to trigger another file only when the previous one is over.

 
//#include "Compiler_Errors.h"
#include <MPR121.h>
#include <Wire.h>
#include <SPI.h>
#include <SdFat.h>
#include <FreeStack.h>
#include <SFEMP3Shield.h>

const uint32_t BAUD_RATE = 115200;
const uint8_t MPR121_ADDR = 0x5C;
const uint8_t MPR121_INT = 4;
const bool WAIT_FOR_SERIAL = false;

uint8_t result;
uint8_t lastPlayed = 0;
bool isTrackPlaying = false;  // Flag to track if a track is currently playing

SFEMP3Shield MP3player;

SdFat sd;

// Set your desired touch and release thresholds
const uint8_t TOUCH_THRESHOLD = 40;
const uint8_t RELEASE_THRESHOLD = 20;

void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(LED_BUILTIN, OUTPUT);

  if (WAIT_FOR_SERIAL) {
    while (!Serial);
  }

  if (!sd.begin(SD_SEL, SPI_HALF_SPEED)) {
    sd.initErrorHalt();
  }

  if (!MPR121.begin(MPR121_ADDR)) {
    Serial.println("error setting up MPR121");
    switch (MPR121.getError()) {
      // Handle error cases as before...
    }
    while (1);
  }

  MPR121.setInterruptPin(MPR121_INT);

  // Set touch and release thresholds
  MPR121.setTouchThreshold(TOUCH_THRESHOLD);
  MPR121.setReleaseThreshold(RELEASE_THRESHOLD);

  // Set other MPR121 configuration parameters as needed...

  result = MP3player.begin();
  MP3player.setVolume(10, 10);

  if (result != 0) {
    Serial.print("Error code: ");
    Serial.print(result);
    Serial.println(" when trying to start MP3 player");
  }
}
void loop() {
  MPR121.updateAll();

  // Only make an action if we have one or fewer pins touched
  // Ignore multiple touches
  if (MPR121.getNumTouches() <= 1) {
    for (int i = 0; i < 12; i++) {
      if (MPR121.isNewTouch(i)) {
        if (i >= 0 && i <= 11) {
          if (!isTrackPlaying) {
            // If no track is currently playing, start playing the requested track
            MP3player.playTrack(i);
            lastPlayed = i;
            isTrackPlaying = true;
            Serial.print("Playing track ");
            Serial.println(i);
          }
        }
      } else {
        if (MPR121.isNewRelease(i)) {
          // Handle release logic (if needed)
        }
      }
    }
  }

  // Check if the current track has finished playing
  if (isTrackPlaying && !MP3player.isPlaying()) {
    isTrackPlaying = false;  // Reset the flag
    Serial.println("Track finished playing.");
    // Blink the LED at the end of the track
    digitalWrite(LED_BUILTIN, HIGH);
    delay(500);  // Adjust the delay as needed
    digitalWrite(LED_BUILTIN, LOW);
  }
}

When using this code check the Serial Monitor to see when the track is playing/over.

Playing more sounds simultaneously: Polyphonic Playback

As you might have noticed, the Touch Board is not able to play multiple sounds at the same time - or to do what is called Polyphonic playback. You can still achieve this by using your touch board as a keyboard and play sounds with the help of a software. You can find here a guide on how to set up your Touch Board with Soundplant. Soundplant.png When using this code check the Serial Monitor to see when the track is playing/over.

Use additional Pins on the TouchBoard

TouchboardPins.png
Most of the Pins of the TouchBoard are used for the capacitive sensors and the MP3 functions. There are though some unallocated pins that you can program in case you need to add a new functionality (a light, another sensor or similar).
For this purpose you can use:

  • Digital Pins 0,1,10,11,12,13
  • Digital Pins 5,6,7,8,9 (only if you are not using the MP3 function)

Adding an extra capacitive sensor

Sometimes you want to use the same TouchBoard functionalities but add a couple of sensors. To do so you can add and program external capacitive sensors.
You can follow this guide to add extra capacitive sensors.

Read sensors and link it to a key press

 
#include <CapacitiveSensor.h>
#include <Keyboard.h>

// Define the capacitive sensors
CapacitiveSensor cs_10_11 = CapacitiveSensor(10, 11); // sensor1
CapacitiveSensor cs_12_13 = CapacitiveSensor(12, 13); // sensor2

void setup() {
  // Initialize the Keyboard library
  Keyboard.begin();
}

void loop() {
  long sensorValue1 = cs_10_11.capacitiveSensor(30);
  long sensorValue2 = cs_12_13.capacitiveSensor(30);

  // Check if the existing sensor is touched
  if (sensorValue1 > 1000) {
    Keyboard.press('Y'); // Example key for existing sensor
  } else {
    Keyboard.release('Y');
  }

  // Check if the new sensor 1 is touched
  if (sensorValue2 > 1000) {
    Keyboard.press('Z');
  } else {
    Keyboard.release('Z');
  }

  delay(10); // Small delay to avoid bouncing
}

Add the new keys to the other 12

Let's add our new keys to the HID_KEYBOARD sketch:

 
//CAPACITIVE SENSORS using 10-11 and 12-13 pins 
//check wiring here https://www.bareconductive.com/blogs/resources/make-a-basic-capacitive-sensor-with-electric-paint-and-arduino?srsltid=AfmBOoonCrtXdl4H0WSuAYeuSYUIlz1rfkKDb2qsZFdfGwGpJY0BfPTZ
//****************************
#include <CapacitiveSensor.h>
CapacitiveSensor cs_10_11 = CapacitiveSensor(10, 11); // sensor1
CapacitiveSensor cs_12_13 = CapacitiveSensor(12, 13); // sensor2
//****************************

// compiler error handling
//#include "Compiler_Errors.h"

// touch includes
#include <MPR121.h>
#include <MPR121_Datastream.h>
#include <Wire.h>

// keyboard includes
#include <Keyboard.h>

// keyboard variables
char key;

// keyboard behaviour constants
const bool HOLD_KEY = true;  // set this to false if you want to have a single quick keystroke, true means the key is pressed and released when you press and release the electrode respectively
//const char KEY_MAP[12] = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L'};
const char KEY_MAP[12] = {'M', 'R', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X'};
// const char KEY_MAP[12] = {KEY_LEFT_ARROW, KEY_RIGHT_ARROW, KEY_UP_ARROW, KEY_DOWN_ARROW, ' ', KEY_ESC, KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_PAGE_UP, KEY_PAGE_DOWN};  // more keys at http://arduino.cc/en/Reference/KeyboardModifiers
//const char KEY_MAP[12] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'h', 'j'};  // for memory game
//9
// touch constants
const uint32_t BAUD_RATE = 115200;
const uint8_t MPR121_ADDR = 0x5C;
const uint8_t MPR121_INT = 4;

// MPR121 datastream behaviour constants
const bool MPR121_DATASTREAM_ENABLE = false;

void setup() {
  Serial.begin(BAUD_RATE);
  pinMode(LED_BUILTIN, OUTPUT);

  if (!MPR121.begin(MPR121_ADDR)) {
    Serial.println("error setting up MPR121");
    switch (MPR121.getError()) {
      case NO_ERROR:
        Serial.println("no error");
        break;
      case ADDRESS_UNKNOWN:
        Serial.println("incorrect address");
        break;
      case READBACK_FAIL:
        Serial.println("readback failure");
        break;
      case OVERCURRENT_FLAG:
        Serial.println("overcurrent on REXT pin");
        break;
      case OUT_OF_RANGE:
        Serial.println("electrode out of range");
        break;
      case NOT_INITED:
        Serial.println("not initialised");
        break;
      default:
        Serial.println("unknown error");
        break;
    }
    while (1);
  }

  MPR121.setInterruptPin(MPR121_INT);

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121.restoreSavedThresholds();
    MPR121_Datastream.begin(&Serial);
  } else {
    MPR121.setTouchThreshold(40);
    MPR121.setReleaseThreshold(20);
  }

  MPR121.setFFI(FFI_10);
  MPR121.setSFI(SFI_10);
  MPR121.setGlobalCDT(CDT_4US);  // reasonable for larger capacitances
  
  digitalWrite(LED_BUILTIN, HIGH);  // switch on user LED while auto calibrating electrodes
  delay(1000);
  MPR121.autoSetElectrodes();  // autoset all electrode settings
  digitalWrite(LED_BUILTIN, LOW);
  
  Keyboard.begin();
}

void loop() {
  MPR121.updateAll();

  for (int i=0; i < 12; i++) {  // check which electrodes were pressed
    key = KEY_MAP[i];
    
    if (MPR121.isNewTouch(i)) {
      digitalWrite(LED_BUILTIN, HIGH);
      Keyboard.press(key);  // press the appropriate key on the "keyboard" output

      if (!HOLD_KEY) {
        Keyboard.release(key);  // if we don't want to hold the key, immediately release it
      }
    } else {
      if (MPR121.isNewRelease(i)) {
        digitalWrite(LED_BUILTIN, LOW);

        if (HOLD_KEY) {
          Keyboard.release(key);  // if we have a new release and we were holding a key, release it
        }
      }
    }
  }

//add the extra sensors with the extra keys
//****************************
  long sensorValue1 = cs_10_11.capacitiveSensor(30);
  long sensorValue2 = cs_12_13.capacitiveSensor(30);

  // Check if the existing sensor is touched
  if (sensorValue1 > 1000) {
    Keyboard.press('Y'); // Example key for existing sensor
    delay(10);
  } else {
    Keyboard.release('Y');
  }

  // Check if the new sensor 1 is touched
  if (sensorValue2 > 1000) {
    Keyboard.press('Z');
    delay(10);
  } else {
    Keyboard.release('Z');
  }
  
//****************************

  if (MPR121_DATASTREAM_ENABLE) {
    MPR121_Datastream.update();
  }
}