FSR pedal

Status
Not open for further replies.
I had a 10 k resistor from A0 to gnd. weather it's there or not doesn't seam to make a difference with this sketch. It does with the sketch in #16 in that sketch if I take it out the pedal does nothing. Back to this sketch, when I upload it it immediately played 2 notes alternating rapidly, I had to change the threshold min from 60 to 350 to get that to stop but when I hold the pedal down it does it also. I can't tell weather the notes are changing on the pad. I don't have time now but I'll do more testing later.
Please provide details and especially the serial print output assuming it's working.

The notes that are firing and the peak readings that prompted them will likely give me some hints as to what's going wrong.

Once I've got a clue I may alter what is printed to try to zero in on what's happening with the hardware.
 
Last edited:
The fact that changing the 60 value helped means either I have a massive bug or the problem is with a piezo reading and that would imply you may have a floating input pin generating noise readings.
 
Last edited:
I should mention the code is set up for 10 inputs. If you are running on less in your current testing we need to reduce the pin count.
 
I only have 2 piezos and the pedal connected, (with the 10k resistor). I was wondering why you have 2- 0's in this line (const int note[PINS] = {0,0,36,38,40,41,47,50,49,51}; and 4- 55's in this line (const int HHsplashNote[ZONECOUNT] = {55,55,55,55,44}; No mater what I do the pedal plays constantly when all the way down, it should only play the note once even if I don't let up on the pedal. I would like to try changing the pedal from A0 to A9
Capture 1.PNG
 
Code:
//***************************************** SET PIN ASSIGNMENT CONFIGURATION OPTIONS**************
const int PINS = [COLOR="#FF0000"]3[/COLOR]; // number of signals incoming
const int analogPin[PINS] = {A0,A1,A2[COLOR="#FF0000"]}//[/COLOR],A3,A4,A5,A6,A7,A8,A9}; //array of analog PINs 

...


//***************************************** SET MIDI NOTE VALUE CONFIGURATION OPTIONS**************
...
const int note[PINS] = {0,0,36[COLOR="#FF0000"]}//[/COLOR],38,40,41,47,50,49,51}; // array of MIDI note values for read signals (0 placeholders for HH)...
To test on two piezo on A1 and A2 with FSR (or other voltage divider) on A0 make the changes above to the code in post 72

The brace closes the array and the double slash tell the compiler to ignore the rest of this line. This way you can change it back very quickly when you have 10 (or more) signals connected.

Notes generated by A2 will always have 36 as their note value but A0 and A1 will depend on A0.

The extension for more than 10 piezo should be obvious but it's limited to the number of analog inputs available and on the processing speed of the sketch on your Teensy to pull enough sample values to get representative maximums from the piezo with timing parameters that still feel responsive as note triggers.

For this code the first input pin is assumed to be the voltage-divider (FSR in your case but a pot would work too with slightly different settings). The second is assumed to be the piezo for the hi-hat triggers that is to be modified by the current (last previous) reading of the zone parameter from the first pin.

You don't really need to do this later one (I think) as it's only used internally to build a [PINS]x[ZONECOUNT] array of midi note numbers that the code can pull on in a nested loop.

Please make sure you do have the pull-down on the FSR as it will behave erratically otherwise (pulling up suddenly giving all zone 0 and 4 which you have reported before).
 
Last edited:
I made those changes, now just 1 note rapidly firing. When I bump the min to 350 it stops but continues when pedal is down. Can I switch A0 with A1 ? seams I had some noise on A0 before Capture 2.PNG
 
Messages with 46 as the note number and those peak readings suggest your A1 piezo is sending values six times greater than the amount of noise allowed for in the stock piezo code.

It's either a stray DC voltage or some very severe noise source (unlikely).

If you have a multi-meter check if you have a DC voltage present at the input pin. Check your wiring on that pin generally.

If you swap A1 and A2 in the code the problem should shift to note number 36 and it may respond differently when force is applied to the FSR.

const int analogPin[PINS] = {A0,A2,A1}
 
There may be a problem with A0, when I switched the pedal to A1 its quiet with the resistor, and when I take the resistor out it rapidly fires a note. The pedal only plays one note though.
 
I would like to use A1, A2, A3 instead of A0, A1, A2, is there anything else I need to change? I have it set up that way now, 10k resistors on all 3 pins, the pedal still fires 1 note rapidly when all the way down
 
I can't speak to the piezo's -- I thought you were doing it Paul's method from the note in the original sketch?

You can use any pins you want as long as the one with the FSR/voltage divider is first (index 0) and the one you want to act as HH piezo is second (index 1).

Please stick to one configuration and make it as standard as possible. Please include the printed output on any observation you report -- otherwise don't bother to tell me about it.

You can run test code like your post 62 to see raw values that should help you choose minimum thresholds above the highest quiet values as well as thresholds that represent 'full' output - i.e. thresholds where values equal or higher map to the maximum velocity value 127.

It should also point out if readings are not giving the expected results.
 
Code:
    if (piezo[i] > thresholdMin[i] [COLOR="#FF0000"]&& i>0[/COLOR]) { // except HH??
      msec[i] = 0; // keep resetting timer if above threshold
    } else if (msec[i] > aftershockMillis[!i]) {
      usbMIDI.sendNoteOff(zoneNote[zone][i], 0, channel);
      printMIDI(false, zoneNote[zone][i], 0, zone, peak[i]);
      state[i] = 0; // go back to idle when
    }
  }
This bit of code is why the first pin (A0 originally) will be more susceptible to refiring notes if the threshold is set too low.

It's there because with the high hat triggered notes you can't count on the signal dropping below the bottom trigger.

However I think it may not be correct and I need to be sure the signal did drop below the close point or it will repeat in error when held closed.
 
I put it back to the original setup with A0 as the FSR, It seams like it wants to work, I can get it to play 2 individual notes sometimes but more often it plays double notes. It still triggers constantly when pedal is down.
 
I put it back to the original setup with A0 as the FSR, It seams like it wants to work, I can get it to play 2 individual notes sometimes but more often it plays double notes. It still triggers constantly when pedal is down. Is there something I can try to adjust in the code in #87?
 
... Is there something I can try to adjust in the code in #87?
You can delete the red text and it should 'fix' the problem but make firing chicks harder. I'll need to think about a proper fix.

That code, btw, says "...AND the index is more than zero." which stopped it from resetting the aftershock timer to keep the current note active and prevent new notes.
 
Even when I put the min threshold at 460 the pedal triggers constantly when down, this wasn't the case with the sketch in #16
Capture 4.PNG
 
Ok... there is a report I can action....

Is that with or without the && i>0?

But you are peaking above levels you said A0 could reach... that's why the velocity readings are stupid high

edit - I see it was only a minute after I posted so I think my change will 'fix' the problem but not really give the desired behavior with the foot-triggered notes.

Even when I put the min threshold at 460...
I have it set to 800 for the close-point on A0

const int thresholdMin[2] = {60,800};


It's the second value that applies to A0 in each of the two-value configuration arrays.

It needs to have a VERY high threshold and it should match the value in the zoneMap array's second-last entry.

const int zoneMap[ZONECOUNT] = {40,150,450,800,1024};
 
Last edited:
that was before this is after, you're right that stopped the constant triggering and now its hard to trigger at all and only 1 note Capture 5.PNG
 
You'll notice that its also sending note offs for the wrong note ID... nearly there on a fix for both issues as they come from the same place.
 
There's a faint hope this sorts the problem but likely it brings new issues...

(If I've introduced a major problem don't try fixing it with random changes... just report the results.)

I've commented back to three inputs (post 80 neglects to say you need a semi-colon after the brace close). Remove the red characters and change PINS back to 10 if you're running with 10 inputs on A0-9.

Can you see if this can output chick notes?

Code:
/* Use a Piezo sensor (percussion / drum) to send USB MIDI note on
messages, where the "velocity" represents how hard the Piezo was
tapped.

This example code is in the public domain.
*multi-pad extension by oddson (under-tested)*
*HH pedal support added for this thread: https://forum.pjrc.com/threads/50114-FSR-pedal
*/

//***************************************** SET PIN ASSIGNMENT CONFIGURATION OPTIONS**************
const int PINS = [COLOR="#0000FF"]3[/COLOR]; // number of signals incoming
const int analogPin[PINS] = {A0,A1,A2[COLOR="#FF0000"]}; //[/COLOR],A3,A4,A5,A6,A7,A8,A9}; //array of analog PINs 

//***************************************** SET HIGH HAT ZONE CONFIGURATION OPTIONS**************
const int ZONECOUNT = 5 ; // number of zones for FSR as modifier for HH
const int zoneMap[ZONECOUNT] = {40,150,450,800,1024};
const int zoneClose = 800;

//***************************************** SET MIDI NOTE VALUE CONFIGURATION OPTIONS**************
//** two value arrays are for normal piezo in index 0 and HH pedal in index 1 (use !i in as index during PINS loops)
const int thresholdMin[2] = {60,800}; // minimum reading, avoid noise and false starts
const int velocityScaleMax[2] = {1023,1023}; // used to scale velocity as effective maximum
const int peakTrackMillis[2] = {12,25};
const int aftershockMillis[2] = {25,45}; // aftershocks & vibration reject


//***************************************** SET MIDI NOTE VALUE CONFIGURATION OPTIONS**************
const int channel = 10; // General MIDI: channel 10 = percussion sounds
const int note[PINS] = {0,0,36[COLOR="#FF0000"]};//[/COLOR],38,40,41,47,50,49,51}; // array of MIDI note values for read signals (0 placeholders for HH)
const int HHstickNote[ZONECOUNT] = {46,2,3,4,42} ; // note values for flavours of HH from open to closed (no general MIDI for intermediaries so used low values as placeholders)
const int HHsplashNote[ZONECOUNT] = {55,55,55,55,44}; // note values for splash/chick 





int zone; // calculated zone
int zoneLag; // zone during last note on event
int state[PINS]; // 0=idle, 1=looking for peak, 2=ignore aftershocks
int peak[PINS]; // remember the highest reading
int piezo[PINS];
elapsedMillis displayLimiter;
elapsedMillis msec[PINS]; // timers to end states 1 and 2
int zoneNote[ZONECOUNT][PINS]; // matrix of note values with zone alterations for HH and it's piezo calc'd during setup

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
  Serial.println("Piezo Peak Capture w/ HH pedal");
  //*****build matrix to hold zone options (different only for HH and it's piezo)
  for (int i=0;i<PINS;i++){
    for (int j=0;j<ZONECOUNT;j++){ 
      if (i==0){
        zoneNote[j][i] = HHsplashNote[j];  // HH pedal notes 
      }else if(i==1){ 
        zoneNote[j][i] = HHstickNote[j];   // HH piezo notes
      }else{
        zoneNote[j][i] = note[i] ;         // other piezo - same for all j
      }
    } 
  }
}

void loop() {
  for (int i=0;i<PINS;i++){
    piezo[i] = analogRead(analogPin[i]);
    if (i==0){ // calc zone if pin index = 0
      int j = 0;
      while ( piezo[0]>zoneMap[j] ) {
        j++;
      }
      zone = j;
    }
    peakDetect(i);
  }
  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-...ses-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }
}


void peakDetect(int i) {
  switch (state[i]) {
    // IDLE state: wait for any reading is above threshold. Do not set threshold too low. 
  case 0:      
    if (i==0 && zoneLag==ZONECOUNT-1){
      if (piezo[0] < thresholdMin[1]) {
        peak[0] = piezo[0];
        msec[0] = 0;
        state[0] = 1;
      }
    }else{
      if (piezo[i] > thresholdMin[!i]) {
        peak[i] = piezo[i];
        msec[i] = 0;
        state[i] = 1;
      }
    }

    return;
    
    // Peak Tracking state: capture largest reading
  case 1:
    if (piezo[i] > peak[i]) {
      peak[i] = piezo[i]; 
    }
    if (msec[i] >= peakTrackMillis[!i]) {
      int velocity = map(peak[i], thresholdMin[!i], velocityScaleMax[!i], 1, 127);
      usbMIDI.sendNoteOn(zoneNote[zone][i], velocity, channel);
      zoneLag = zone;
      printMIDI(true, zoneNote[zone][i], velocity, zone, peak[i]);
      msec[i] = 0;
      state[i] = 2;
    }
    return;
    
    // Ignore Aftershock state: wait for things to be quiet again.
  default:
    if (piezo[i] > thresholdMin[i]) {
      if (i==0 && zoneLag==ZONECOUNT-1){
        // do nothing?
      }else{
        msec[i] = 0; // keep resetting timer if above threshold
      }
    } else if (msec[i] > aftershockMillis[!i]) {
      usbMIDI.sendNoteOff(zoneNote[zoneLag][i], 0, channel);
      printMIDI(false, zoneNote[zoneLag][i], 0, zone, peak[i]);
      state[i] = 0; // go back to idle when
    }
  }
}



void printMIDI(boolean on, int noteID, int vel, int zone, int peak){
  Serial.print("NoteOn: ");
  Serial.print(on);
  Serial.print(" NoteID: ");
  Serial.print(noteID);
  Serial.print(" Velocity: ");
  Serial.print(vel);
  Serial.print(" Zone: ");
  Serial.print(zone);
  Serial.print(" Peak: ");
  Serial.println(peak);
}
 
Yes it triggers the chick but when I lift the pedal up it triggers the other note. At least the the pedal works, just have to make only one note trigger at a time but the pedal works good other than that. I'm still thinking if the FSR peak zone lasts for X milliseconds play chick note else if < X milliseconds play splash note would give the best response if it's doable.
 
Last edited:
Please post the serial.print output for any observation about performance... it's much easier to figure out when I can see the values explicitly.

That version, however, is definitely not a step in the right direction...
 
Last edited:
Here's the code from 72 but with 3 pins and fixed so it sends the correct note-off message.

I need to see the output again to make sure I understand the bug.

Copy and paste the serial print output after one chick attempt (down and hold, release at 1 second).

Then attempt a splash (down and quick release) and paste the serial print results here too... (I don't think you need a screen capture. You should be able to copy text from the serial monitor with Ctrl-A and Ctrl-C.)


Code:
//***************************************** SET MIDI NOTE VALUE CONFIGURATION OPTIONS**************
//** two value arrays are for normal piezo in index 0 and HH pedal in index 1 (use !i in as index during PINS loops)
const int thresholdMin[2] = {60,800}; // minimum reading, avoid noise and false starts
const int velocityScaleMax[2] = {1023,1023}; // used to scale velocity as effective maximum
const int peakTrackMillis[2] = {12,25};
const int aftershockMillis[2] = {25,45}; // aftershocks & vibration reject


//***************************************** SET MIDI NOTE VALUE CONFIGURATION OPTIONS**************
const int channel = 10; // General MIDI: channel 10 = percussion sounds
const int note[PINS] = {0,0,36,38,40,41,47,50,49,51}; // array of MIDI note values for read signals (0 placeholders for HH)
const int HHstickNote[ZONECOUNT] = {46,2,3,4,42} ; // note values for flavours of HH from open to closed (no general MIDI for intermediaries so used low values as placeholders)
const int HHsplashNote[ZONECOUNT] = {55,55,55,55,44}; // note values for splash/chick 





int zone; // calculated zone
int zoneLag; // zone during last note on event
int state[PINS]; // 0=idle, 1=looking for peak, 2=ignore aftershocks
int peak[PINS]; // remember the highest reading
int piezo[PINS];
elapsedMillis displayLimiter;
elapsedMillis msec[PINS]; // timers to end states 1 and 2
int zoneNote[ZONECOUNT][PINS]; // matrix of note values with zone alterations for HH and it's piezo calc'd during setup

void setup() {
  Serial.begin(115200);
  while (!Serial && millis() < 2500) /* wait for serial monitor */ ;
  Serial.println("Piezo Peak Capture w/ HH pedal");
  //*****build matrix to hold zone options (different only for HH and it's piezo)
  for (int i=0;i<PINS;i++){
    for (int j=0;j<ZONECOUNT;j++){ 
      if (i==0){
        zoneNote[j][i] = HHsplashNote[j];  // HH pedal notes 
      }else if(i==1){ 
        zoneNote[j][i] = HHstickNote[j];   // HH piezo notes
      }else{
        zoneNote[j][i] = note[i] ;         // other piezo - same for all j
      }
    } 
  }
}

void loop() {
  for (int i=0;i<PINS;i++){
    piezo[i] = analogRead(analogPin[i]);
    if (i==0){ // calc zone if pin index = 0
      int j = 0;
      while ( piezo[0]>zoneMap[j] ) {
        j++;
      }
      zone = j;
    }
    peakDetect(i);
  }
  // MIDI Controllers should discard incoming MIDI messages.
  // http://forum.pjrc.com/threads/24179-...ses-midi-crash
  while (usbMIDI.read()) {
    // ignore incoming messages
  }
}


void peakDetect(int i) {
  switch (state[i]) {
    // IDLE state: wait for any reading is above threshold. Do not set threshold too low. 
  case 0:      
    if (piezo[i] > thresholdMin[!i]) {
      peak[i] = piezo[i];
      msec[i] = 0;
      state[i] = 1;
    }

    return;
    
    // Peak Tracking state: capture largest reading
  case 1:
    if (piezo[i] > peak[i]) {
      peak[i] = piezo[i]; 
    }
    if (msec[i] >= peakTrackMillis[!i]) {
      int velocity = map(peak[i], thresholdMin[!i], velocityScaleMax[!i], 1, 127);
      usbMIDI.sendNoteOn(zoneNote[zone][i], velocity, channel);
      zoneLag = zone;
      printMIDI(true, zoneNote[zone][i], velocity, zone, peak[i]);
      msec[i] = 0;
      state[i] = 2;
    }
    return;
    
    // Ignore Aftershock state: wait for things to be quiet again.
  default:
    if (piezo[i] > thresholdMin[i]) {
      msec[i] = 0; // keep resetting timer if above threshold
    } else if (msec[i] > aftershockMillis[!i]) {
      usbMIDI.sendNoteOff(zoneNote[zoneLag][i], 0, channel);
      printMIDI(false, zoneNote[zoneLag][i], 0, zone, peak[i]);
      state[i] = 0; // go back to idle when
    }
  }
}



void printMIDI(boolean on, int noteID, int vel, int zone, int peak){
  Serial.print("NoteOn: ");
  Serial.print(on);
  Serial.print(" NoteID: ");
  Serial.print(noteID);
  Serial.print(" Velocity: ");
  Serial.print(vel);
  Serial.print(" Zone: ");
  Serial.print(zone);
  Serial.print(" Peak: ");
  Serial.println(peak);
}
 
Last edited:
I get an error... PINS' was not declared in this scope
HTML:
[/Arduino: 1.8.5 (Windows 7), TD: 1.41, Board: "Teensy 3.6, Serial + MIDI, 180 MHz, Faster, US English"

NEWHH:11: error: 'PINS' was not declared in this scope
 const int note[PINS] = {0,0,36,38,40,41,47,50,49,51}; // array of MIDI note values for read signals (0 placeholders for HH)

                ^

NEWHH:12: error: 'ZONECOUNT' was not declared in this scope
 const int HHstickNote[ZONECOUNT] = {46,2,3,4,42} ; // note values for flavours of HH from open to closed (no general MIDI for intermediaries so used low values as placeholders)

                       ^

NEWHH:13: error: 'ZONECOUNT' was not declared in this scope
 const int HHsplashNote[ZONECOUNT] = {55,55,55,55,44}; // note values for splash/chick 

                        ^

NEWHH:21: error: 'PINS' was not declared in this scope
 int state[PINS]; // 0=idle, 1=looking for peak, 2=ignore aftershocks

           ^

NEWHH:22: error: 'PINS' was not declared in this scope
 int peak[PINS]; // remember the highest reading

          ^

NEWHH:23: error: 'PINS' was not declared in this scope
 int piezo[PINS];

           ^

NEWHH:25: error: 'PINS' was not declared in this scope
 elapsedMillis msec[PINS]; // timers to end states 1 and 2

                    ^

NEWHH:26: error: 'ZONECOUNT' was not declared in this scope
 int zoneNote[ZONECOUNT][PINS]; // matrix of note values with zone alterations for HH and it's piezo calc'd during setup

              ^

NEWHH:26: error: 'PINS' was not declared in this scope
 int zoneNote[ZONECOUNT][PINS]; // matrix of note values with zone alterations for HH and it's piezo calc'd during setup

                         ^

NEWHH: In function 'void setup()':
NEWHH:33: error: 'PINS' was not declared in this scope
   for (int i=0;i<PINS;i++){

                  ^

NEWHH:34: error: 'ZONECOUNT' was not declared in this scope
     for (int j=0;j<ZONECOUNT;j++){ 

                    ^

NEWHH:36: error: 'zoneNote' was not declared in this scope
         zoneNote[j][i] = HHsplashNote[j];  // HH pedal notes 

         ^

NEWHH:36: error: 'HHsplashNote' was not declared in this scope
         zoneNote[j][i] = HHsplashNote[j];  // HH pedal notes 

                          ^

NEWHH:38: error: 'zoneNote' was not declared in this scope
         zoneNote[j][i] = HHstickNote[j];   // HH piezo notes

         ^

NEWHH:38: error: 'HHstickNote' was not declared in this scope
         zoneNote[j][i] = HHstickNote[j];   // HH piezo notes

                          ^

NEWHH:40: error: 'zoneNote' was not declared in this scope
         zoneNote[j][i] = note[i] ;         // other piezo - same for all j

         ^

NEWHH:40: error: 'note' was not declared in this scope
         zoneNote[j][i] = note[i] ;         // other piezo - same for all j

                          ^

NEWHH: In function 'void loop()':
NEWHH:47: error: 'PINS' was not declared in this scope
   for (int i=0;i<PINS;i++){

                  ^

NEWHH:48: error: 'piezo' was not declared in this scope
     piezo[i] = analogRead(analogPin[i]);

     ^

NEWHH:48: error: 'analogPin' was not declared in this scope
     piezo[i] = analogRead(analogPin[i]);

                           ^

NEWHH:51: error: 'zoneMap' was not declared in this scope
       while ( piezo[0]>zoneMap[j] ) {

                        ^

NEWHH: In function 'void peakDetect(int)':
NEWHH:67: error: 'state' was not declared in this scope
   switch (state[i]) {

           ^

NEWHH:70: error: 'piezo' was not declared in this scope
     if (piezo[i] > thresholdMin[!i]) {

         ^

NEWHH:71: error: 'peak' was not declared in this scope
       peak[i] = piezo[i];

       ^

NEWHH:72: error: 'msec' was not declared in this scope
       msec[i] = 0;

       ^

NEWHH:80: error: 'piezo' was not declared in this scope
     if (piezo[i] > peak[i]) {

         ^

NEWHH:80: error: 'peak' was not declared in this scope
     if (piezo[i] > peak[i]) {

                    ^

NEWHH:83: error: 'msec' was not declared in this scope
     if (msec[i] >= peakTrackMillis[!i]) {

         ^

NEWHH:84: error: 'peak' was not declared in this scope
       int velocity = map(peak[i], thresholdMin[!i], velocityScaleMax[!i], 1, 127);

                          ^

NEWHH:85: error: 'zoneNote' was not declared in this scope
       usbMIDI.sendNoteOn(zoneNote[zone][i], velocity, channel);

                          ^

NEWHH:95: error: 'piezo' was not declared in this scope
     if (piezo[i] > thresholdMin[i]) {

         ^

NEWHH:96: error: 'msec' was not declared in this scope
       msec[i] = 0; // keep resetting timer if above threshold

       ^

NEWHH:97: error: 'msec' was not declared in this scope
     } else if (msec[i] > aftershockMillis[!i]) {

                ^

NEWHH:98: error: 'zoneNote' was not declared in this scope
       usbMIDI.sendNoteOff(zoneNote[zoneLag][i], 0, channel);

                           ^

NEWHH:99: error: 'peak' was not declared in this scope
       printMIDI(false, zoneNote[zoneLag][i], 0, zone, peak[i]);

                                                       ^HTML]
 
Status
Not open for further replies.
Back
Top