Foot Gesture Control – iFoot

Foot Gesture Control.

Code/Circuit completed and verified: September 20, 2016

Last Update: April 10th 2017

Means or method by which a foot control device (sensor, potentiometer, etc) controls a peripheral device such as a circuit, micro-controller, or effect pedal.  Features can be controlled, adjusted, switched, etc by monitoring foot gestures or rapid foot movements without the need for mechanical switches.

Possible uses for FGC

Foot Gesture Control (FGC) is not limited to music industry devices.  Foot Gesture Control or Rapid Foot Movement could be enabled or devised to operate any other device in a hands free environment.  Foot gesture control has obvious uses in the automotive world were analysis of the foot pedals could provide auxiliary control of other devices or features in the car or to an accessory.

Military tank operators can have increased access to utilities, defenses or armament for enhanced battlefield readiness.

Obvious benefits to the medical world including surgery, imaging, etc.  Gaming world, enhanced playability, etc.

ATMEGA CODE – Arduino Sketch

Here is the code for a micro-controller.  This code allows user to input a heel down – toe down – heel down rapid foot gesture control to activate or turn off the reverb effect in this guitar effect pedal.  iFoot and fancy free.

/*
Tremoverb pedal by Keeley Electronics, inc.
iPhoot
Started 9/20/2016
modified last 3/24/2017
by Robert Keeley

*/
#include <EEPROM.h>

const int analogInPin = A0; // Analog input pin that the treadle potentiometer is attached to
const int maxRatePin = A1; // Analog input pin that read Max Rate Pot
const int maxDepthPin = A2; // Analog input pin that read Max Depth Pot
const int programSelectPin = A3; //Analog input pin that reads Program Select Potentiometer
const int reverbPin = A4; // Analog input pin that read Max Depth Pot
const int analogOutPin = 11; // Analog output pin that the rate control
const int depthAnalogOutPin = 10; //analog output pin for depth control
const int reverbAnalogOutPin = 9; //analog output pin for reverb control

const int rateSwitch = 2; // the number of the pushbutton pin
const int rateLED = 13; // the number of the LED pin
const int progSelect0 = 7;
const int progSelect1 = 6;
const int progSelect2 = 5;

const int depthSwitch = 4; // the number of the pushbutton pin for Depth
const int depthLED = 12; // the number of the LED pin for Depth

int treadlePot = 0; // value read from the pot
int ratePot = 0; // value read from Rate Pot
int depthPot = 0; // value read from Depth Pot
int rateOutputValue = 0; // value output to the PWM (analog out)
int depthOutputValue = 0; // value output to the Depth PWM
float rateMaxRatio = 0.0; //create percentage for use in limiting range of rate control PWM
int ratePotNew = 127;
int programSelectPotValue; //value read from program select pot
int programSelection; //value 0-4 for Spin FV-1 program select
int pedalMode = 0; //mode of pedal operation, 0-3, 4 modes of operation
int reverbPot = 0; //value on Reverb Pot
int reverbPotNew = 0; //updated reverb pot value
int reverbOutputValue = 0; //output PWM value to reverb on FV-1
int FGC = 0; // Foot Gesture Control OFF
int FGCint;
int address = 0; //address in the internal EEPROM for FGC
int addressInitial = 1; //address in the internal EEPROM for FGC set one time only
float depthMaxRatio = 1.0; //create percentage for use in limiting range of rate control PWM
int depthPotNew = 255;

// Variables will change: Switch for LED
int ledState = LOW; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input pin

int ledStateD = LOW; // the current state of the output pin, Depth
int buttonStateD; // the current reading from the input pin, Depth
int lastButtonStateD = LOW; // the previous reading from the input pin, Depth

int reverbBypass = HIGH; //reverb bypass initialized for On

float scaleFactor = .5; //FACTORY DEFAULT FOR RATE Pick a value between 0 and 1 to scal rate pot

//reverb on off detection
int counterR = 0;
long timerR = 0;
long timerDelay = 0;

// the following variables are long’s because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 50; // the debounce time; increase if the output flickers

long lastDebounceTimeD = 0; // the last time the output pin was toggled, Depth
long debounceDelayD = 50; // the debounce time; increase if the output flickers, Depth

void setup() {

Serial.begin(9600);

pinMode(rateSwitch, INPUT);
pinMode(rateLED, OUTPUT);

pinMode(depthSwitch, INPUT);
pinMode(depthLED, OUTPUT);

pinMode(progSelect0, OUTPUT);
pinMode(progSelect1, OUTPUT);
pinMode(progSelect2, OUTPUT);

FGCint = EEPROM.read(addressInitial);
if (FGCint == 1) {
// FGC has already been initialized from factory once
}

else
{

FGCint = 1;
EEPROM.write(addressInitial, FGCint); //sets FGC to off on very first power up only.

FGC = 0;
EEPROM.write(address, FGC);
}

//read FGC from Internal EEPROM
FGC = EEPROM.read(address);

if (digitalRead(rateSwitch) == HIGH && digitalRead(depthSwitch) == HIGH) {
FGC = !FGC; //Foot Gesture Control Toggle
EEPROM.write(address, FGC);
}
}

void loop() {
// set initial LED state
digitalWrite(rateLED, ledState);
digitalWrite(depthLED, ledStateD);

ratePot = analogRead(maxRatePin); //Read Rate Pot, user preset max value
depthPot = analogRead(maxDepthPin); //Read Depth Pot, user preset max value

programSelectPotValue = analogRead(programSelectPin); //Read Waveform Selector, 5 waves possible ramp up, down, square, sine, Harmonic Tremolo
programSelection = map(programSelectPotValue, 0, 1023, 1, 6); // map the pot to one of 5 different programs

switch (programSelection) {
case 1: //do RAMP UP TREMOLO when var equals 1
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, LOW);
break;
case 2: //do RAMP DOWN TREMOLO when var equals 2
digitalWrite(progSelect0, HIGH);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, LOW);
break;
case 3: //do SINE WAVE when var equals 3
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, HIGH);
digitalWrite(progSelect2, LOW);
break;
case 4: //do SQUARE WAVE when var equals 4
digitalWrite(progSelect0, HIGH);
digitalWrite(progSelect1, HIGH);
digitalWrite(progSelect2, LOW);
break;
case 5: //do HARMONIC TREMOLO when var equals 5
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, HIGH);
break;

// break;
}

//FOOT GESTURE CONTROL copyright 2016 Keeley Electronics
//Detection of distinctive foot gestures to control effect pedal.
//Monitors for Toe Up/Down/Up to toggle Reverb Effect on/off
//Monitors for Toe Down/Up/down to cycle thru tremolo modes sine/ramp/square/harmonic/rotary

if (FGC == 1) {

treadlePot = analogRead(analogInPin);

//read pot discounting max and min values that fluctuate.
if (treadlePot < 25) {
timerR = millis();
}
//check for min to max deflection gesture within 1/4 second
if ((millis() – timerR) < 150) {
treadlePot = analogRead(analogInPin);

if (treadlePot > 980 && (counterR == 0)) {
counterR = 1;
}
}
if ((millis() – timerR) > 300) {
counterR = 0;
}
//read pot again to see if it goes to min quickly in order to shut on/off Reverb
treadlePot = analogRead(analogInPin);
if (treadlePot < 25) {
if (((millis() – timerR) < 300) && (counterR == 1)) {
reverbBypass = !reverbBypass;
counterR = 0;
}
}

if (reverbBypass == HIGH){

//read the Reverb Pot in value:

reverbPot = analogRead(reverbPin);

// map it to the range of the analog out:
reverbOutputValue = map(reverbPot, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(reverbAnalogOutPin, reverbOutputValue);
}
else
{
reverbOutputValue = 0; //mute/bypass Reverb
analogWrite(reverbAnalogOutPin, reverbOutputValue);
}

// END FOOT GESTURE CONTROL
}

else{
//no foot gesture control
//reverb control read and set level
reverbPot = analogRead(reverbPin);

// map it to the range of the analog out:
reverbOutputValue = map(reverbPot, 0, 1023, 0, 255);
// change the analog out value:
analogWrite(reverbAnalogOutPin, reverbOutputValue);
}

// read the state of the switch into a local variable:
int reading = digitalRead(rateSwitch);
int readingD = digitalRead(depthSwitch);

// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you’ve waited
// long enough since the last press to ignore any noise:
// wait 2 milliseconds before the next loop
// for the analog-to-digital converter to settle
// after the last reading:
delay(2);

// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}

if (readingD != lastButtonStateD) {
// reset the debouncing timer
lastDebounceTimeD = millis();
}

if ((millis() – lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it’s been there for longer
// than the debounce delay, so take it as the actual current state:

// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;

if (buttonState == HIGH) {
ledState = !ledState;
// ledStateD = !ledStateD; //test mode LED

}

}
}

if ((millis() – lastDebounceTimeD) > debounceDelayD) {
// whatever the reading is at, it’s been there for longer
// than the debounce delay, so take it as the actual current state:

// if the button state has changed:
if (readingD != buttonStateD) {
buttonStateD = readingD;

if (buttonStateD == HIGH) {
ledStateD = !ledStateD;
}

}
}

// set the LED:
digitalWrite(rateLED, ledState);
digitalWrite(depthLED, ledStateD);

// read program select pot
programSelectPotValue = analogRead(programSelectPin);
programSelection = map(programSelectPotValue, 0, 1023, 1, 6); // map the pot to one of 5 different programs

switch (programSelection) {
case 1:
//do something when var equals 1
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, LOW);
break;
case 2:
//do something when var equals 2
digitalWrite(progSelect0, HIGH);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, LOW);
break;
case 3:
//do something when var equals 3
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, HIGH);
digitalWrite(progSelect2, LOW);
break;
case 4:
//do something when var equals 4
digitalWrite(progSelect0, HIGH);
digitalWrite(progSelect1, HIGH);
digitalWrite(progSelect2, LOW);
break;
case 5:
//do something when var equals 5
digitalWrite(progSelect0, LOW);
digitalWrite(progSelect1, LOW);
digitalWrite(progSelect2, HIGH);
break;

// break;
}
//Determine pedal mode
if (ledState == LOW && ledStateD == LOW) {
// Rate LED OFF – Depth LED OFF – Treadle Controls both Rate and Depth
pedalMode = 1;
}

if (ledState == HIGH && ledStateD == LOW) {
// Rate LED ON – Depth LED OFF – Rate knob sets max rate
pedalMode = 2;
}

if (ledState == LOW && ledStateD == HIGH) {
// Rate LED OFF – Depth LED ON – Depth knob sets max depth
pedalMode = 3;
}

if (ledState == HIGH && ledStateD == HIGH) {
// Rate LED ON – Depth LED ON – Treadle goes to set Max Rate/Depth
pedalMode = 4;
}
switch (pedalMode) {
case 1:
//Rate and Depth set by knobs, LEDs both off
//read the Rate Pot in value:
//read the Rate Pot in value:

treadlePot = analogRead(analogInPin);

// map it to the range of the analog out:
rateOutputValue = map(treadlePot, 0, 1023, 0, (255*scaleFactor));
// change the analog out value:
analogWrite(analogOutPin, rateOutputValue);

//set Depth to Max:
depthOutputValue = 255;
// change the depth out value:
analogWrite(depthAnalogOutPin, depthOutputValue);

break;
case 2:
//do Dynamic Rate / Fixed Depth equals 2

//read Depth Pot value:
depthPot = analogRead(maxDepthPin);
depthOutputValue = map(depthPot, 0, 1023, 0, 255);
// change the depth out value:
analogWrite(depthAnalogOutPin, depthOutputValue);

//read the Rate Pot in value:
ratePot = analogRead(maxRatePin);
rateMaxRatio = (255*scaleFactor) * (ratePot / 1023.0);
ratePotNew = (int)rateMaxRatio;
// read the analog in value:
treadlePot = analogRead(analogInPin);
// map it to the range of the analog out:
rateOutputValue = map(treadlePot, 0, 1023, 0, ratePotNew);
// change the analog out value:
analogWrite(analogOutPin, rateOutputValue);

break;
case 3:
//do Dynamic Depth / Fixed Rate equals 3

//read the Rate Pot in value:
ratePot = analogRead(maxRatePin);
rateMaxRatio = (255*scaleFactor) * (ratePot / 1023.0);
ratePotNew = (int)rateMaxRatio;

// change the analog out value:
analogWrite(analogOutPin, ratePotNew);

//read the Depth Pot in value:
depthPot = analogRead(maxDepthPin);
depthMaxRatio = 255 * (depthPot / 1023.0);
depthPotNew = (int)depthMaxRatio;
// read the analog in value:
treadlePot = analogRead(analogInPin);
// map it to the range of the analog out:
depthOutputValue = map(treadlePot, 0, 1023, 0, depthPotNew);
// change the analog out value:
analogWrite(depthAnalogOutPin, depthOutputValue);

break;
case 4:
//do Limited Rate and Depth equals 4

//read the Rate Pot in value:
ratePot = analogRead(maxRatePin);
rateMaxRatio = (255*scaleFactor) * (ratePot / 1023.0);
ratePotNew = (int)rateMaxRatio;

// read the analog in value:
treadlePot = analogRead(analogInPin);

// map it to the range of the analog out:
rateOutputValue = map(treadlePot, 0, 1023, 0, ratePotNew);
// change the analog out value:
analogWrite(analogOutPin, rateOutputValue);

//read the Depth Pot in value:
depthPot = analogRead(maxDepthPin);
depthMaxRatio = 255 * (depthPot / 1023.0);
depthPotNew = (int)depthMaxRatio;
// read the analog in value:
treadlePot = analogRead(analogInPin);
// map it to the range of the analog out:
depthOutputValue = map(treadlePot, 0, 1023, 0, depthPotNew);
// change the analog out value:
analogWrite(depthAnalogOutPin, depthOutputValue);

break;
break;
}

// save the reading. Next time through the loop,
// it’ll be the lastButtonState:
lastButtonState = reading;
lastButtonStateD = readingD;

}

 

Patent Applied For

Robert Keeley
iPhoot (TM)
iFoot (TM)