FreqMeasure Library, reading optical rotary encoder for pulse width.

Status
Not open for further replies.

Musicman

Member
I have built a very successful midi musical instrument using a Arduino Uno that plays wav samples on a Sparkfun`s Tsunami wav player. This uses Martin Nawrath's FreqPeriod library for converting a hand cranked optical encoder`s output to map speed of turning to playing volume. The rotary encoder has one phase wired to the Uno`s comparator pin and the other comparator pin tied high. When read by FreqPeriod this gives 'wheelPeriod' range of values such as c. 6000 (4 revs/sec) to 50000 (1/2 rev/sec) .... 1 rev/sec = (1/600) *16us = 26666.66. This all works well.
I would dearly like to use a Teensy to expand the scope of my instrument as I have run out of pins using the Arduino Uno.

So (like on the Uno) I am trying to use the Paul Stoffregen “FreqMeasure” Library to continually measure the elapsed time during each cycle of a 600 pulse per turn optical encoder , (using only one phase attached to pin 3 of an Teensy 3.2).
This will be used to map the pulse size to continually vary midi volume with speed of handle turn.
Unfortunately on the monitor I can only see a measurement perhaps once every twenty-five seconds or so. I need a reading for every pulse for this to work.

My question is ; What am I doing wrong / is this “FreqMeasure” suitable for this , if not how can I achieve the result I am after?

Attached post plays midi notes to the Tsunami board ok and will hopfully give readings of encoder pulse width ( to be incorporated in mapping volume).
 

Attachments

  • working_note_player_USB_sketch_dec01a.ino
    1.5 KB · Views: 70
There are several options for measuring, and freqmeasure should be the right option
https://www.pjrc.com/teensy/td_libs_FreqMeasure.html#compare
for what you are doing.

It is hard to tell since the formatting got messed up in transit but looking at your code there is some oddities with the { and }, suggest going through making sure things are indented in a way that works for you and making sure you are only making routines inside them when you want to. in particular I think your
for (note=10; note <= 127; note++) {
...
delay(200);
...
}
is running every loop, and delaying 200ms one hundred and seventeen times, which would explain the time between serial prints.

There is also something odd with the

Code:
{
  if (FreqMeasure.available()) 
  
wheelPeriod = FreqMeasure.read();
  
    playVolume = map (FreqMeasure.read(),  periodSlow , periodFast, 1, 127);
    playVolume = constrain(playVolume,1, 127);

this will run as

Code:
{
  if (FreqMeasure.available()) wheelPeriod = FreqMeasure.read();
  
 // these lines will run every loop, not just if wheel period changed
    playVolume = map (FreqMeasure.read(),  periodSlow , periodFast, 1, 127);
    playVolume = constrain(playVolume,1, 127);
Going through and only having { where you actually make a conditinal (following and IF or FOR) may also find other things that are not how you intended. To make freqmeasure work you want a tight main loop so it can complete in less time than one encoder count, only firing the midi functions when actually required, and if possible having no delay() at all, instead starting actions and then checking internal/counters timers on following loops to stop them again.
 
Thank you so much for your reply,
The small sketch I post was meant to be a rough proof of concept. I now see that it a dog’s breakfast.
You have given me the confidence that FreqMeasure will work for me, I will today work on a better testing sketch.
Happy New Year

Ps; On the Arduino Uno if turning my 600ppt encoder using "FreqPeriod.h", the serial monitor gives me a reading of period size at 1 rev/sec = (1/600) *16us = 26666.66.
Would this value be the same using FreqMeasure on the teensy ?
 
Freqmeasure works in CPU cycles so direct porting from Uno code may have trouble.

According to the docs

FreqMeasure.countToFrequency(count);

You should get a result in consistent hz, though for your use case it may actually be easier to directly use the raw count value, as long as you track the fact that changes to the clock rate or core later in development will change your 'feel', and possibly need some sort of adjustment constant.
 
If you use FreqMeasure.countToFrequency(), you should get the same result.

If you use the raw count, you can expect a higher number on Teensy 3.2, because it runs so much faster than Arduino Uno. If you run at 96 MHz, the timer runs as 48 MHz, so you can expect exactly 3 times the number you get with Uno at 16 MHz.

And just to qualify the word "exactly", these readings are all in terms of how fast the timer counts. Teensy 3.2 uses a much better crystal than Arduino Uno. But no clock is perfect. There is always some tiny error in the counting speed. Probably not an issue for this application, but in case anyone later finds this thread searching for answers about relative speeds, the ultimate accuracy of these measurements is always relative to the accuracy of the crystal or whatever oscillator creates the timer's clock.
 
I now think I have it worked out

Thank you all so much for your replies; I now think I have it worked out.
I do not need perfectly accurate measurements, but I do need a level of constancy.
I have attached a sketch which is giving me the results I can work for using the settings for period size that I have successfully used on my Uno by simply dividing my FreqMeasure results by 3?
The attached sketch I think is a bit messy, but produces the period measurement needed.
Could someone show me how to clean / simplify it ?

I apologise that there is a big overlap with my other post “FreqMeasure.read() What would the reading be at 600 Hz?”, I had started that as I initially was getting no replies to this post.

Would anyone like to see a video of the musical instrument that I have made using the Arduino Uno but wish to use the Teensy instead. Would it be ok to post it here?
 
Code Attachment for above post

Posting the attached file that has been left out from above post . This works but can it be made better?
 

Attachments

  • FreqMeasure.countToFrequency-2.ino
    561 bytes · Views: 66
It should only have two pairs of {} . Your loop has only one if statement in it but ends with four } rather than two it actually needs.

To make this more useful in your larger code suggest using
https://www.pjrc.com/teensy/td_timing_elaspedMillis.html
to de-sync the changes in period from what your instruments are up to. So each time freqmeasure.availible fires it updates the period, or possibly runs a small floating average.

Separately at some time period either from a timing library or just by watching an ellapsedMillis update your notes.

And on an even slower basis from a different ellapsedMillis ( say every 5 seconds) do your debug serial printing, idea being to avoid where possible having prints called by code that is timing critical.
 
Status
Not open for further replies.
Back
Top