Teensy FSR based MIDI controller

Status
Not open for further replies.

brice

Member
Hello,

I'm a total newbie

I bought a Livid Instruments Brain v2, which seemed to be a perfect fit for my project
but it couldn't read very fast strokes on the FSRs (in the 3ms to 6ms range)
I was told to add ceramic capacitors between the FSRs and the ground to slightly lenghten the hits, but I couldn't get good results.

Looked around and found out about the Teensy

I need to connect 61 FSRs + a sustain pedal
reading through the specs of the teensy 3.2 it says it has 21 analog inputs, right ?
Does that mean it'd be better to buy 3 teensy 3.2 and somehow link them to get up to 63 analog inputs ?
Or should I get multiplexers (I read online that this slows down AnalogRead time)

My controller will fold in half, 21 FSRs in first half, 40 FSRs in the other,
I wouldn't mind buying multiple teensy if that means I can have less wires going between the two halves

- Would the teensy be able to registers those hits properly (fast enough)?
- How hard would it be to program the teensy so that it sends midi notes?
- To be able to control de velocity curves per sensor?
- To be able to send midi CC for aftertouch?

Here you can find some details about the FSR I'm using :
Interlink Electronics FSR 408
http://www.interlinkelectronics.com/FSR408.php
http://www.interlinkelectronics.com/datasheets/Datasheet_FSR.pdf

Best regards
 
Last edited:
First, before you buy anything, I'd recommend installing Arduino+Teensyduino. Then run Arduino and open the examples from File > Examples > Teensy > USB_MIDI.

Teensy is a general purpose board. You program it to become a MIDI device of your own design. These examples are the sort of code you'll be working with. If these look like something you think you can learn, then you're ready to move forward. If the code looks hopelessly complex, Teensy probably isn't the path for you.

Some of your questions are about Teensy and USB MIDI. Those are easy. Yes, you can send note on/off, CC for aftertouch, and any other MIDI messages. Hopefully those examples will give you a rough idea. Detailed documentation is here:

http://www.pjrc.com/teensy/td_midi.html

Questions about reading the sensors are harder. I haven't personally used this sensor, though it looks interesting. A quick search turned up this Adafruit tutorial.

https://learn.adafruit.com/force-sensitive-resistor-fsr/using-an-fsr

Presumably you're connecting it like they show, with the FSR between the analog pin and power, and another resistor between the pin and ground. This seems like the best way.

They also show a digital pin connection. That's not going to work for fast measurement. They're assuming you're applying constant pressure. The measurement takes too much time, which isn't good if you're look fast events.

Adafruit's example code also won't work. It measures the resistance once per second. Even if you speed it up, this won't work. This image from their tutorial should illustrate why:

force___flex_simpletestout.gif

In this screenshot, a single squeeze resulted in 6 lines printing. If you speed it up, you'll get *many* more. Imagine this is really a musical event. You wouldn't want to send 6 MIDI messages. Your challenge will be figuring out code that waits long enough for the initial response to happen. In this case, maybe you'd ignore 124 and 303, but maybe by the time it's at 655 you'd conclude the initial touch has occurred and you want to send a Note On code with velocity. How well you write this code, to turn a flood of incoming data into the decision about the Note On event (and velocity) will be the main thing that determines how great your instrument ends up performing!

Then as time goes on, the touch becomes 901 and 968. Maybe you send aftertouch control messages. There too, you might want to pace yourself. The readings will come in much faster than meaningful human touch, and probably a lot faster than you'd want to flood a MIDI system with messages.

Obviously you'll also need code to send the Note Off message when the reading goes back to zero (or close to zero). That code needs to be designed to know whether the note was on (you'll add a variable to the program to store this info), so you don't needlessly send Note Off messages for every zero reading.

You'd replicate this for each sensor, using loops or by simply copying and paste of the code with minor changes. That will bring up another important issue....

The analogRead() function takes time. It's much faster on Teensy 3.2 than regular Arduino, and there are some functions like analogReadAveraging() which can adjust the speed (slower gives more accurate readings). The normal speed on Teensy 3.2 is 15 microseconds. On regular Arduino, it's about 900.

So, if you have 20 sensors connected, and if your code doesn't spend time do other stuff, you'll be able to read all of them in about 300 microseconds. That seems like it ought to be able to catch an event which is 3 to 6 milliseconds. Maybe? Without seeing an oscilloscope capture of the actual voltage vs time for those light touches, it's very hard to know if this is fast enough.

There are techniques to connect more than 1 sensor to an analog pin. The simplest (and usually best) way involves 74HC4051 or similar analog switch chips. You can find a section near the end of that MIDI page about how this is done. It's a very common question for people building MIDI controllers.

However, the downside to analog switch chips is you need a brief delay after changing the switch. Just a few microseconds is usually enough. But if you're trying to rapidly track lots of sensors with very brief events, those extra microseconds and the larger number of analogRead() times really add up. There are a few (very advanced/difficult) things which can be done in software to speed things up a little, but ultimately you're still stuck with the reality of measuring many things one at a time.

For a project like this which needs very rapid response, you're probably going to need to limit the number of sensors per Teensy. Even 20 might be pushing things, depending on how fast that signal really changes. If measuring it every 0.3 ms is fast enough to really detect well the point where the finger has really engaged the material (where you'd send the Note On), 20 should be possible. If you need faster sampling, like 0.15 ms, you'd want to limit to only 10 sensors per Teensy.
 
Last edited:
PaulStoffregen : thank you for your time and the detailed answer
I've downloaded and looked at the examples, some of it is indeed over my head, but I'll dive in.

monkeybiscuits : domo arigato, I will give it a look and give feedback
 
I think it is very good advice to get up to speed with C programming for the teensy ...will save you a lot of frustration.

Edit : monkeybiscuit's code (under MIDInote.cpp + header) looks really good! kind of what i was thinking, so ignore the following ramblings. I am leaving the ramblings here, even though Mr Biscuits code looks the deal, just so it looks like I took time to think about stuff instead of jumping on in.

i wonder if one way to do this is to grab an analog value every once in a while, and check it gainst a threshold, flag 'on' and then use the value as velocity. Obviously, its not going to be super-accurate, but given the potential amount of data you have, its a quick way to do it, otherwise you will be flooded with analog data. Fsrs retain their values a bit due to decompression, so it might not be that inaccurate.

I tried a way whereby once over a threshold, values were tracked to a mximum, and the max is used for velocity... it didn't work that great. And with the amount of fsrs you are looking at, might not be practical.

If you have an 'on' event you could then wait a bit and then grab another reading or two or three for aftertouch .... Maybe for aftertouch you might want a separate channel sensor (there are two varieties of aftertouch, poly and channel) ...

aftertouch is tricky, but it is so wonderfully expressive. If I recollect correctly ...synths use microswitches for velocity and 'on' flags (using time between two digital switches to measure velocity) with aftertouch done via separate sensors (usually a channel 'strip', rather than poly aftertouch ... poly aftertouch is not that common ...) .... something to think about
 
Last edited:
...once over a threshold, values were tracked to a maximum, and the max is used for velocity... it didn't work that great. And with the amount of fsrs you are looking at, might not be practical.
That's pretty much how it works. A note is triggered any time an analog reading breaks the threshold but higher velocities are only triggered when there is a SUDDEN change in the analog reading. It sounds like the "reading dual microswitch" approach would be way more efficient and cost effective (FSRs are like $7 a pop) but a DIY keyboard with such precision would be a VERY impressive feat.

For aftertouch, the FSR just reads the analog signal and sends corresponding MIDI messages as long as the analog remains above the threshold. When it drops, a note off is sent. Currently the 'aftertouch' acts as poly because messages are sent for each note that's on. This is fine for 8 or so sensors but for 61...I'll have to work on how to achieve true 'channel pressure' type aftertouch.
 
channel pressure aftertouch takes the highest value for all of the notes ....I guess it is actually implemented using a strip fsr for say 16 keys, and compared with the next sixteen keys. A while ago I futzed around with fsrs and midi ...in the end I got a very nice useable instrument, but I went down a few blind alleys on the way .. I'll have to look for the code to see where I ended up. I still havea song I made using the fsr 'aftertouch device' really cool and expressive way to make midi ...bash an fsr ..smear your finger along it. I remember it being very satisfying for rythm ,,, a bit vague on the code details now though .... I am wondering about the OPs 61 fsr complement ....I still have a few lying around and I might have a go at putting 12 or so together on a teensy. I wonder if a multiplexer is the way to go ... if you think about 4 to 6 milliseconds as being 'below the human threshold" the likelihood of a keystroke lasting that long must be minimal, and even at 240 bpm, in 16ths, your note duration is 15 miliseconds ... man 240 bpm in sixteens is realllllly fast musically. polyphony of 12 .... i reckon its a go.
 
aftertouch is not going to be anygood for hitting it with a stick ...tbh it might be a step too far ....

anyway fsrs are quite successfully used in drum pads, as are piezos and probably other sensors.

the thing about fsrs is the (usual) need for an actuator, or overlay. This overlay will have its own characteristics .... In the paper you link to there is the characteristics of a stick on a drumhead ...FSRs have different electrical characteristics and mechanical characteristics from the electro mechanical system in the paper... for instance, fsrs take a bit longer to 'spring back', and have a slower 'rise time' ...add in the deformability of the actuator and I would say that you could double the time analysis in figure 4.2 (with an accompanying lower and longer force profile). Unless you are attaching fsrs to something with the same charaxcteristics as a snare drum membrane, the paper is really only a starting point ....

My point was really that you can't hit a drum or anything more than 240 / 60 / 16ths etc etc times in a minute, and you can look at one 'sample' of a fairly long window to get a velocity reading .... I reckon 5 to six ms easy ...this is not a snare head.

So if you have a lot of analog reads, which will obviously put a space between same pin reads, and you have a hit over the threshold, you could just assume that such hit is also the velocity of the hit

you only need to be looking at less than 5-6 ms intervals

its worth noting that a lot of 'velocity sensitive' drum pads are really rather insensitive and inaccurate, and I am talking commercial here .... some of that is to do with the actuator overlay, some may be down to inaccurate software ... i don't really know ... just more stuff to think about.
 
The Brainv2 (from Livid Instruments) samples each analog every 15 milliseconds, it wasn't fast enough to register the stick hitting the FSR.
That's why I'm looking for a faster alternative, indeed I think that if I can get the teensy to can scan at around 5 to 6ms intervals it'd be perfect
The FSRs will be laid flat on a metal enclosure (they have double sided tape underneath), I've tried various materials on top of the FSR.

The FSR 408 rise time is < 3 microseconds, so that's not gonna help lenghthen the time for analysis, or am I wrong?

Thank you all for your help, I guess I'll have to dive in and buy a teensy and see how far I can get.
Any plan for a teensy++ v3 with solder pads for all the I/O?
 
I think you will find that FSRs hold their values as they decompress a bit, so it is on the fall side that you pick up some time (plus the actuator material) ... the teensy is going to do quite a few analog reads in 3 or 4 miliseconds!!!

here is some code I just wrote on my word processor ... its untested ... hopefully it will compile, if you put it into the right format for arduino setup loop etc.

if you do get a teensy, and you don't want it, I'll buy it off you (as long as you haven't wrecked it).

i'm a bit worried about the price of 61 FSRs... you might want to look at the videos / posts etc on chopping big ones up into little ones as a cost saving measure.... anyway.... hopefully you will have as much fun as I have had ...

Code:
//Neoprene rubber over a fsr is quite common.  Felt might work too.

//GLOBAL
bool Hit = false;
int THRESH = 70;
int FSRpin = A6;
int FSRRead;
int velocity;

//SETUP
{Serial.begin (32500);}

//LOOP ....
{

delay(2); 
/*
I reckon this will be alright .... Serial.println (below) takes up time as well ...obviously remove the serial prints if you have like 10 FSRs
*/

FSRRead = analogRead(FSRpin); 

if (FSRRead > THRESH) 
     {
      if (!Hit) {
                    velocity = map (FSRRead, THRESH, 1023, 60, 127);  
                    Serial.println (velocity);
                 // usbMidi.sendNoteOn (63, velocity, 1);                        
                    Hit = true;
                   }                                 
         }
else                           
        {
          if (Hit) {
           Serial.println ("OFF");
        //usbMidi.sendNoteOff (63, 0, 1);
           Hit =false;}
          }  

/*map function .... if the hit is just over the threshold you still want a decent whack, given that you could be on the shoulder of the “pressure” (but on the other hand if you set the THRESH right, you could be in the money! ...) ... some pads are notoriously insensitive because of this range scaling, I assume...*/


/* a lot of drum software doesn’t send / receive noteoffs, if I remember correctly!! So maybe the noteoff in the ‘else’ isn’t necessary for your application?? */

}
 
Last edited:
@Adrian. That code would send several note ons per hit and a note off for every cycle that the analog reading is below the threshold. That's a lot of MIDI even if you're only reading one FSR. Have a look at the code in post #3. It ain't pretty but it only sends what's needed.
 
MR biscuits ...you are right ... I left a line out of the code ...really sorry about that .... I've fixed it now. Should have been at home and tested it first ...I think it is right now and I will test it...

edit: tested and works ...one note on when going over threshold, and one note off when dropping back through the threshold. I think I'll do a test with a couple of FSRs, to see how the delay and threshold work out .... im going to make me a drum machine.
 
Last edited:
Got them in the mail yesterday, the boards are so cute and tiny !
I can't wait to get to work (and ask more questions around here)
 
GO! fun ahoy. I'm waiting for some more teensys at the moment (I've mounted my first oneinto a midi controller I made!!). I've got some cute little fsrs made yp and I'm going to hook them up as soon as I get the teensys. I've been looking at capacitive touch as an alternative to fsrs.... it looks cheaper and might even be better in some respects... And you can make the sensors yourself.
 
@adrian Is there a way to get accurate velocity with capacitive sensors? That would be awesome! Cap sens is great for on/off input without any of the mechanical noise most buttons have and I know they can be used for variable input too. The only thing you need to get them working is a couple of resistors so yeah, they'd be way cheaper than FSRs.....IF you can get the same results from them. Please post anything you learn about velocity sensitive cap sens!
 
there are some pretty hi tech capacative touch implementations out there and some of them look like they have the potential to give force-type data ... swept frequency capacative touch looks 'interesting' and there are several implementations usijng dielectric sandwiches that give force type readings .... there is even one that uses sine carrier waves and ffts to measure the distance between two sets of copper plates (separated by a dielectric neoprene pad...) So it looks 'interesting'...

I've used the teensy capacative touchRead function for on off, but maybe it could give force data .... Its certainly something to look at, that's for sure.

Capacative response would appear to have a distance component in it .... (I am soooo ignorant) so we should be able to capture that info
 
Getting any sort of velocity sensing from capacitive touch would be tricky at best.

Teensy LC and 3.x have hardware capacitive sensing which is much better than what you can get with the 2-pin approach. Perhaps try touchRead() in a loop and see if you can sense anything different when the sensor is struck faster. If you can read fast enough, maybe you'll be able to sense the touch as the finger approaches or just at the beginning, before much of the skin is in contact. Maybe keeping a short history of rapid readings will let you look back after you've detected the touch, to see if the readings increased suddenly, or if there was a gradual increase.

Inside hardware/teensy/avr/cores/teensy3/touch.c are some tunable settings. Maybe if you increase the speed (which decreases resolution) you might get extra info that could help?

It'd be pretty awesome to get even very simple velocity sensing from touch. I hope you'll share whatever you learn, if you try this?
 
First of all, I think it's pretty amazing that I can yank a stainless steel business card case out of my desk, stick it to a single pin on the LC and nothing more is needed for a touch sensitive input. It works great for on/off and I get good variable readings when my finger gets about 6 inches from the contact.

Unfortunately, as long as I'm striking it with my finger (hard or soft), touchRead() always yields a similar spike (within about 2 readings). So I don't think it's quite fast enough for velocity. Different NSCALE and PRESCALE gave me different values but not enough of a speed boost to interpret a variation in velocity.

Anyway, I think it would be very interesting to try and implement some kind of 'pretouch' but as far as the OP's project goes, I don't think it will work being hit with a stick and with 61 inputs...is touchRead() muxable?
 
Last edited:
Thanks for trying that monkeybiscuits! Bit of a bummer that there was no velocity info ..

.I'd like to know if it is muxable to, but I would suppose so, since its just an analog signal, isn't it?

With a couple of analog muxes you could probably have 20 capacitive touch sensors (with no velocity ....) easy ... and with hundreds of reads per second, per sensor I am guessing. Perhaps even thousands of reads per second per touch sensor.

If you didn't need velocity, then touchRead would be a good solution.

I think there are are some very sophisticated bits of sensor kit out there that give a velocity reading via capacitance ... worth looking further maybe

Be careful of denting your card case .... unless it sounds like a Jamacian steel drum ... :D
 
Last edited:
...its just an analog signal, isn't it?

No, it's not analog. The way I understood the 2-pin approach is (I'm sure the 1-pin approach is similar), a send pin sends a pulse and the time it takes for the pulse to reach the receive pin is measured. Any capacitive object (like a finger) slows that time down and that's what gives you a reading. So it's very time sensitive. That's why my hunch is that the time it takes to cycle through the 8 or 16 inputs of a mux will throw a monkey wrench into the time-sensitive works of touchRead().

UPDATE: I seem to have a knack for figuring things out only after I post the question. I'm sure it IS muxable. You just set the mux pin you want to read and touchRead() will take the time it needs to get a value before letting the loop continue on to the next pin. So a mux8 on 8 of the Teensy's touch pins will give you 64 inputs. But although it IS muxable, the longer it takes to mux through all the inputs, the farther we get from velocity. =(
 
Last edited:
Ah ..you may well be right, but maybe mux delay would only makes it more inaccurate, rather than non-operational ... ?

i understand the switching time for a mux is in the microsecond realm, and I suppose the measurement of voltage over time for capacitance is maybe of a similar order, , perhaps it suggests error rather than ;non-function'''>?

I will look on google ...

edit; i found this i2c peripheral for 10 bucks. Looks like you could use four on a i2c bus, for a total of 40 something sensors ... the teensy lc has a fair few touch pins as well, so you could use them, and communicate the results to a master. ...

will keep searching about muxing ...

final edit: I found a page here that explains how capacitive touch works for an avr, and I am pretty sure it is the same for teensy .... the way it works looks like you could switch a mux chip, touchRead, rinse and repeat
 
Last edited:
Hello!!

I made an fsr project, with poly aftertouch.... the best thing about it is cutting up one of these 24 inch fsrs into about 24 bits and making baby fsrs out of them cheap ... $1 a pop.

Here are some pictures ...

WP_20151220_20_58_42_Pro.jpgWP_20151220_20_59_02_Pro.jpg

Basically you cut out the zigzag interlocking electrode part to create two electrode 'rails' (the grey plastic in the photos) ...You peel the backing off your new electrodes and manually shove a flattened out heavy duty staple (or other small bit of metal) through the grey part, crimp using pliers, and apply a bit of conductive glue (probably unnecessary) .... you can't solder directly to the fsr, but I guess you can solder to the staple, so long as you are quick (or solder before you shove them in!!) ...I used female breadboard wires myself...

I used 15kohm resistors because thats what I had ...10k may be better, in the sense that it will give a different velocity curve, I think ... I didn't use any actuator pads or mount the fsrs properly (that would help with repeatability / stability) ...I just wanted to see how it would work ...

The circuit diagram (such as it is) is from adafruit. Here is a picture on the breadboard for 2 fsrs, and of the teensy LC I used ... (I used 3.3V btw, not 5V!)

force___flex_fsrpulldownsch.gifWP_20151220_21_01_16_Pro.jpgWP_20151220_21_00_09_Pro.jpg

Anyway, here is code for two FSRs (following PaulStoffregen's suggestions above) ...
Code:
int FSRpin[] = {A9, A1};      //number of FSRs, and the relevant analog pins ...
const int FSRs = 2;           //making the sensors is pretty cheap and easy ... see the photos ...
int Note [] = {63, 64};       //MIDI note numbers ... listed in order of FSRpin
int counter [FSRs];
int VELMASK = 0;
int ATMASK = 0;
int AFTERTHRESH = 50;          //analog sensor value above which aftertouch messages are sent

int THRESH = 45;               //analog sensor value above which note / velocity is recognised

int VELTIME = 500;              /*counter value at which point velocity is sampled ...
                                counter is zero when first touched, velocity is sampled X ticks later
                                500 ticks sounds like a lot, but the teensy LC is clocked at 48Mhz       */

int AFTERTIME = 2500;           /*counter value at which point aftertouch is sampled ...
                                every X ticks of a touch, until released ...
                                you don't want too many aftertouch messages per touch, and 2500 gives a surprising number */

int MIDIMIN = 20;             //bottom MIDI value for the MIDI velocity AND aftertouch messages
void NoteOnSend (int);
void PolyTouchSend (int);

void setup()

{
  Serial.begin (32500);
}

void loop ()

{
  for (int i = 0; i < FSRs; i++)
  {
    int FSRRead = analogRead(FSRpin[i]);
    if (FSRRead > THRESH)
    {
      counter[i] ++;
      if (!(VELMASK & (1 << i)) && (counter[i] == VELTIME)) {
        VELMASK |= (1 << i);
        counter [i] = 0;
        NoteOnSend (i);
      }
      if (counter [i] == AFTERTIME) {
        counter [i] = 0;
        PolyTouchSend(i);
      }
    }
    else {
      if (VELMASK & (1 << i)) {
        usbMIDI.sendNoteOff (Note[i], 0, 1);
        VELMASK &= ~ (1 << i);
        counter [i] = 0;
      }
    }
  }
}

void NoteOnSend (int j)
{
  int FSRRead = analogRead(FSRpin [j]);
  int velocity = map (FSRRead, 0, 800, MIDIMIN, 127);
  usbMIDI.sendNoteOn (Note[j], velocity, 1);
}

void PolyTouchSend (int j)
{
  int FSRRead = analogRead(FSRpin [j]);
  if (FSRRead > AFTERTHRESH) {
    int aftertouch = map (FSRRead, 0, 800, MIDIMIN, 127);
    usbMIDI.sendPolyPressure (Note[j], aftertouch, 1);
  }
}

The way it works is by setting up an array of counters (to create delays) and if an adc goes over the threshold there is a quick count/delay and then the velocity is sampled, and sent as a 'noteon' event. Obviously this creates a bit of latency between physically hitting the FSR and noteon, but its not noticable, and you can tweak around with it .... after the noteon, there are aftertouch readings (using the counters) at regular intervals .... once the note is released, you get a note off and start again. The sensitivity thresholds can all be tweaked, and the mapping from the analog voltage to midi can be adjusted too ...I set it for 3.3V with my 15kOhm resistors by a bit of trial and error (about 1 trial and one error).

Here is a picture of midiox recording midi events .. I chose notes E and Eflat .... yay. I'm out of the studio at the moment otherwise I would have inflicted sound on y'all. When you compiled for teensy, use the MIDI dropdown option ...

WP_20151220_20_59_38_Pro.jpg

Cheers.

PS, a big question is how things would respond with many more fsrs .... given that there is plenty of fat in the delay counter I used, I'm guessing that many fsrs are possible even on a teensy LC.
 
Last edited:
Excellent, I've been way too busy lately to make progress, but I'll get back to it after christmas.
Thank you adrian for the detailed post.
 
Last edited:
Status
Not open for further replies.
Back
Top