Project tutorial
USB Footswitch from Boss FS-5U, 6U and Similar

USB Footswitch from Boss FS-5U, 6U and Similar © GPL3+

Build a small and robust device with minimal effort, turning any jack plug footswitch into a USB footswitch.

  • 649 views
  • 1 comment
  • 3 respects

Components and supplies

About this project

If you play an instrument you will sooner or later want to play along some tracks, some kind of drum machine or metronome, flip pages of your score and finally start a recording. (I'm using Transcribe!, Audacity and Hydrogen.) Starting, stopping, looping the song, switching the software or change BPM by tapping a key is usually done by keyboard commands. With your hands holding your instrument you need one or more foot switches, emulating certain keyboard commands.

There are a lot more situations where you could use a foot switch.

To my surprise there are almost no cheap, robust and programmable usb-foot switches avilable. But most musicians (at least e-guitar and e-bass players) will know or even own a jack plug foot switch for their amps or effects. Probably the most common is the BOSS FS-5U or FS-6U (double switch). Of course any other open/close push-button will do. Using instrument cables between your footswitch and this device can help to cover long distances which might be difficult with usb cables. Plus you don't have to modify the original switch.

So I wanted to make a small device that can be connected to these switches by a jack plug (mono or stero), could handle one or two switches, could handle "tap" and "hold" commands and could send keyboard commands through USB to my computer. And I wanted a real world product, not some fragile concept study. Anyone should be able to build it in less that an hour for less than 15€, and to get all required components easily.

Let's assume you know how a switch works (a push-button to be more precise because the contact opens when you remove your foot). We are dealing with two different type of cables, mono (two wires, ground and tip) and stereo (three wires, ground, ring and tip)

When you are planning to use just one switch a mono cable is ok and you can use any jack (socket?) for our little project. If you want to use two switches you can either use a Y-cable (2 mono plugs, one for each switch and one stereo plug on the other end), or a double switch (e.g. FS 6U) with a stereo jack output.

On the Micro board the three contact are are wired like this:

  • Ground contact of jack -> PIN ground
  • Tip contact of jack -> PIN 7 (I used PIN 5 at first, but switched to PIN 7 because this an interrupt pin). Decide for yourself and adopt the value of Pin_Tip in the script)
  • Ring contact of jack -> PIN 2

Make sure that you don't connect the pins during soldering. Just skip Pin 2 if you don't need stereo cables. The other ends of these three wires are conncted to the jack. As there are a variety of types this picture ist only an example.

Make sure to select the correct contacts as described above. And yes, I am a world class solderer.

That's all.

Now drill the two holes in the two caps...:

... and we are ready for finay assembly. Be careful not to break the connection of the usb-socket. I lost one board during assembly.

I have used a small cable strap as a tension relief and a piece of foam to fix everything inside the tube. By the way, here in Germany theses tubes are called HT-Rohre (High Temperature Tubes). They are used for waste water, the smallest size is 32mm in diameter (I have used 40mm). They are available at any construction market. Price for a double socket and two end caps is 2€.

Done. Connect the device to your computer, start the Arduino IDE, load the script listed in the software section of this project.

When using the device make sure that you first connect the switch(es) and then the usb plug. This is because the device performs a testing routine at startup whether stereo or mono cables are used. When the device is connected to your switches and the computer before the computer is powered up (the standard situation), everything works fine.

In the software you can define the keyboard commands for each footswitch. Actually there are two commands for each switch. One for a short tap, and another one for a long step on the button. The second one is applied when you release the button after a time longer than LongPressTime (0.7sec).

I use "Space" (Play/Stop, Flip page) and "Left Alt+Tab" (Switch to previous App) on one switch, and "," (Tap BPM, Pause) on the other switch (don't need a hold command here).

As there are more pins available on the board, you could connect multiple jacks and serve more than two switches with one devices.

One last thing: The script assumes that your hardware switch closes the contact between tip/ground or ring/ground when operated. There are other switches which open the contact when activated. The FS-5U allows to toggle the mode by a so called polarity switch at the rear. So make sure to choose the correct setting.

I will add bluetooth in the near future.

Have fun.

Code

USB Foot switchC/C++
#include <Keyboard.h>
//######################################################################################

//######################################################################################
//User Settings:
//Character(s) sent to USB when the "Tip" Button is pressed shortly
char Char_Tip[] ={' '};//start/stop command for many Apps. Hydrogen, Audacity, Transcibe!, YouTube, etc.
//Character(s) sent to USB when the "Tip" Button is pressed for at least LongPressTime ms 
char Char_Tip_Long[] = {KEY_LEFT_ALT, KEY_TAB};//Switching to previous App

//Character(s) sent to USB when the "Ring" Button is pressed shortly
const char Char_Ring[] ={','};//tapping the BPM for Hydrogen
//Character(s) sent to USB when the "Ring" Button is pressed for at least LongPressTime ms 
const char Char_Ring_Long[] ={KEY_LEFT_ALT, KEY_TAB};//Switching to previous App

int LongPressTime=700; //milliseconds 
int delayafterrelease=200;//milliseconds
int CMode=0; //Cable mode, Mono- or Stereo cable
//######################################################################################
//Cablemode 0: Autodetect
//    For Mono or Stereo cable Ring contact is always "connected" to ground (Boss FS-5U)
//    If AutoDetectStereo is 1: At Powerup for three seconds the signal of Ring_Tip
//    is evaluated. If it is LOW all the time (contact closed) a mono setup is assumed.
//    This is not hot-plugable. If cables are changed please reset by reconnecting usb.
//Cablemode 1: Mono or Stereo Cable, One Button, Tip contact only
//Cablemode 2: 2x mono to stereo, Two Buttons or Boss FS-6

//Button Commandes: KEY_RETURN, KEY_ESC, KEY_F1.., KEY_BACKSPACE, KEY_LEFT_CTRL...
//https://www.arduino.cc/en/Reference/KeyboardModifiers
//https://www.electronicsweekly.com/blogs/engineer-in-wonderland/arduino-micro-direct-access-board-leds-2017-08/
//----------------------------------------------------------------------------------------------------------
const int RXLED = 17; // The RX LED has a defined Arduino Micro pin
const int TXLED = 30; // The TX LED has a defined Arduino Micro pin
const int Pin_Ring = 2;
const int Pin_Tip = 7    ;
int Stat_Ring=0;
int Stat_Tip=0;
int RingPressedTime=0;
int TipPressedTime=0;
unsigned long int presstime;
int  lenRingCmd,lenRingLongCmd;
int  lenTipCmd,lenTipLongCmd;
//----------------------------------------------------------------------------------------------------------
void setup() {
  //turn off all LED
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(RXLED, OUTPUT); // Set RX LED as an output
  pinMode(TXLED, OUTPUT); // Set TX LED as an output
  digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW
  digitalWrite(RXLED, HIGH); // set the LED off
  digitalWrite(TXLED, HIGH); // set the LED off
  // put your setup code here, to run once:
  pinMode(Pin_Ring, INPUT_PULLUP);
  pinMode(Pin_Tip, INPUT_PULLUP);
  digitalWrite(Pin_Ring, HIGH);
  digitalWrite(Pin_Tip, HIGH);

  lenRingCmd     =sizeof(Char_Ring)/sizeof(Char_Ring[0]); //number of keystrokes to be transmitted
  lenRingLongCmd =sizeof(Char_Ring_Long)/sizeof(Char_Ring_Long[0]);
  lenTipCmd      =sizeof(Char_Tip)/sizeof(Char_Tip[0]);
  lenTipLongCmd  =sizeof(Char_Tip_Long)/sizeof(Char_Tip_Long[0]);

  int locount=0; // number of events with Pin_Ring==low (contact closed)
  int hicount=1;// number of events with Pin_Ring==high (contact open), starts with 1 to avoid zero division
  if (CMode==0){
    for (int i=0; i<300; i++){ // testing for 3 seconds, counting open and close events
      if (LOW==digitalRead(Pin_Ring))
        locount+=1;
      else
        hicount+=1;
      delay(10);
    }
    if (locount/hicount < 0.01)//if highcount (open) is much higher than locount (closed) the Ring/Ground contact
                               //is not permamently closed. A stereo cable is used. Seems to be more stable than testing
                               //for a single open event.
      CMode=2;//stereo cable
    else 
      CMode=1;//mono cable
  }
  Keyboard.releaseAll();//you never know ;-)
}
//----------------------------------------------------------------------------------------------------------
void loop() {
  // put your main code here, to run repeatedly:
  int pressed=0;
  Stat_Ring=0;
  Stat_Tip=0;

//might be a good idea to use interrupts some day
  for (int i=0; i < 5; i++){
    delay(10);
    if (LOW==digitalRead(Pin_Ring)){
        Stat_Ring=1;  // This one is always 1 with a mono cable. With stereo cable 1 means button is pressed
    }
    if (LOW==digitalRead(Pin_Tip)){
        Stat_Tip=1;// 1 means button pressed with any cable
    }
  }

//Selecting and sending the keyboard commands:
  if (CMode==2){ //Ring contact is used. 2xmono->stereo or stereo->stereo configuration
    if (Stat_Ring==1){
      presstime=millis();//remember time of pressing event (ring contact)      
      while (LOW==digitalRead(Pin_Ring))
        delay(10); // wait for button being released. delay could be removed
      if (millis()-presstime > LongPressTime)//if button has been pressed longer than LongPressTime use long command
        for (int r=0; r<lenRingLongCmd; r++)//send all keyboard commands in the list
          Keyboard.press(Char_Ring_Long[r]);
      else
        for (int r=0;r<lenRingCmd;r++) //otherwise use short command
          Keyboard.press(Char_Ring[r]);
      pressed=1;//button has been pressed
    }
  }  
  
  if (Stat_Tip==1){//same as Ring Contact, for any CMode
    presstime=millis();
    while (LOW==digitalRead(Pin_Tip))
      delay(10); 
    if (millis()-presstime > LongPressTime)
      for (int t=0; t<lenTipLongCmd; t++)
        Keyboard.press(Char_Tip_Long[t]);
    else
     for (int t=0; t<lenTipCmd; t++)
        Keyboard.press(Char_Tip[t]);
    pressed=1;
    }
  
  if (pressed==1){
    Keyboard.releaseAll();
    delay(delayafterrelease);//make sure that no button press event is detectd during button release
    pressed=0;
  digitalWrite(LED_BUILTIN, HIGH); // turn the LED off by making the voltage LOW
//One could use these two LEDs for indicating CableMode
  digitalWrite(RXLED, HIGH); // set the LED off
  digitalWrite(TXLED, HIGH); // set the LED off
  }
  }
//----------------------------------------------------------------------------------------------------------
//----------------------------------------------------------------------------------------------------------  

 

Comments

Similar projects you might like

Arduino Controlled USB Trackpad

Project tutorial by Dante Roumega

  • 8,055 views
  • 6 comments
  • 13 respects

USB Wizard - Keyboard/Mouse Control

Project in progress by Scott Clandinin

  • 4,731 views
  • 4 comments
  • 9 respects

Press to Talk: A One-Button USB Joystick

Project in progress by Gambatte

  • 1,020 views
  • 1 comment
  • 0 respects

Multi-Source Controlled USB Lamp

Project tutorial by Amal Mathew

  • 3,462 views
  • 2 comments
  • 19 respects

SNES classic controller usb HID

Project showcase by Chris Wootton

  • 780 views
  • 0 comments
  • 3 respects
Add projectSign up / Login