Pages: [1]   Go Down
Author Topic: optical tachometer to MIDI help  (Read 497 times)
0 Members and 1 Guest are viewing this topic.
UK
Offline Offline
Full Member
***
Karma: 0
Posts: 116
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

hi

I am working on a device that will be able to measure the speed of a rotating object (in this case a bicycle wheel) and control the pitch of an audio file (in ableton) I have go the optical tachometer working accuratly enough (although the incrementations by which it goes up and down need a bit of tweaking), I have managed to also get it to control the brightness of an LED according to the RPM. The next hurdle is to get the arduino to output the RPM as a midi cc message.
I have wired into the arduino a MIDI out port and have attempted to hack together some code I had from previous projects but so far with so success.
The arduino is outputting midi values but its jibbirish. I just want the RPM to be a cc value so that when it is at its fastest speed it is reading the highest midi value of 127 and when it is still it reads a midi value of 0.
below is the code I have so far - does anyone have any suggestions how to improve it?

Code:
/*
 * Optical Tachometer
 *
 * Uses an IR LED and IR phototransistor to implement an optical tachometer.
 * The IR LED is connected to pin 13 and ran continually. A status LED is connected
 * to pin 12. Pin 2 (interrupt 0) is connected across the IR detector.
 *
 *
 */
 
int ledPin = 13;                // IR LED connected to digital pin 13
int statusPin = 12;
int lightPin = 11;// LED connected to digital pin 12
int brightness = 0;
int delay_time = 40; // delay for this amount each write cycle.
byte MIDI_channel = 1;
byte cc_number = 127;
byte printing_byte = 0;
int baud_rate = 32500;
int Value = 0;

volatile byte rpmcount;
volatile int status;

unsigned int rpm;

unsigned long timeold;

 void rpm_fun()
 {
   //Each rotation, this interrupt function is run twice, so take that into consideration for
   //calculating RPM
   //Update count
      rpmcount++;
      
   //Toggle status LED  
   if (status == LOW) {
     status = HIGH;
   } else {
     status = LOW;
   }
   digitalWrite(statusPin, status);
 }

void setup()
 {
   Serial.begin(baud_rate);
   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, rpm_fun, FALLING);
  
   //Turn on IR LED
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH);
  
   //Use statusPin to flash along with interrupts
   pinMode(statusPin, OUTPUT);
   pinMode(lightPin, OUTPUT);
   rpmcount = 0;
   rpm = 0;
   timeold = 0;
   status = LOW;
   MIDI_channel = MIDI_channel - 1;
 }

 void loop()
 {
   //Update RPM every second
   delay(500);
   //Don't process interrupts during calculations
   detachInterrupt(0);
   //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
   //happened once per revolution instead of twice. Other multiples could be used
   //for multi-bladed propellers or fans
   rpm = 3*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;
  
  brightness = (4 * rpm);
  analogWrite(lightPin, brightness);
  printing_byte = rpmcount;

  
  Serial.print(B10110000 + MIDI_channel,BYTE);
  Serial.print(cc_number,BYTE);
  Serial.print(127-printing_byte,BYTE);
   //Write it out to serial port
   Serial.println(rpm,DEC);
  
   //Restart the interrupt processing
   attachInterrupt(0, rpm_fun, FALLING);

  }




any help would be greatly appreciated
Logged

Tallahassee, FL
Offline Offline
Newbie
*
Karma: 0
Posts: 25
Rocket Scientist
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you might benefit (and, I should say, your code would also) from a peek at the map() function.

map(inLow,inHigh,outLow,outHigh);

[this is from memory, so no slings and arrows, please!!]

for instance:   map(0,4095,1,127)  will map input values of 0-4095 into output values of 1-127

also, you probably don't want to swamp the MIDI bus with THOUSANDS of CC messages per second, so you'll want to determine a way to scale that back a bit (perhaps only output an averaged value every so often, for example

Logged

UK
Offline Offline
Full Member
***
Karma: 0
Posts: 116
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

hey

thanks for your reply - the map function is next on my list.
For now, I have managed to get the MIDI working pretty well - just need to tidy up the maths regarding the rpm readout as it jumps around a bit.
here is the code I have used:

Code:
/*
 * Optical Tachometer
 *
 * Uses an IR LED and IR phototransistor to implement an optical tachometer.
 * The IR LED is connected to pin 13 and ran continually. A status LED is connected
 * to pin 12. Pin 2 (interrupt 0) is connected across the IR detector.
 *
 *
 */
//#define DEBUG      
 
int ledPin = 13;                // IR LED connected to digital pin 13
int statusPin = 12;
int lightPin = 11;// LED connected to digital pin 12
int brightness = 0;
int delay_time = 40; // delay for this amount each write cycle.
byte MIDI_channel = 0;
byte cc_number = 0;
byte printing_byte = 0;
int Value = 0;
int midi_pitch = 0;
#ifdef DEBUG
const int DEBUG_RATE = 9600;        // Serial debugging communicates at 9600 baud
const int SERIAL_PORT_RATE = DEBUG_RATE;
#else
const int MIDI_BAUD_RATE = 31250;   // MIDI communicates at 31250 baud
const int SERIAL_PORT_RATE = MIDI_BAUD_RATE;
#endif



volatile byte rpmcount;
volatile int status;

unsigned int rpm;

unsigned long timeold;

 void rpm_fun()
 {
   //Each rotation, this interrupt function is run twice, so take that into consideration for
   //calculating RPM
   //Update count
      rpmcount++;
      
   //Toggle status LED  
   if (status == LOW) {
     status = HIGH;
   } else {
     status = LOW;
   }
   digitalWrite(statusPin, status);
 }

void setup()
 {
   Serial.begin(SERIAL_PORT_RATE);
   //Interrupt 0 is digital pin 2, so that is where the IR detector is connected
   //Triggers on FALLING (change from HIGH to LOW)
   attachInterrupt(0, rpm_fun, FALLING);
  
   //Turn on IR LED
   pinMode(ledPin, OUTPUT);
   digitalWrite(ledPin, HIGH);
  
   //Use statusPin to flash along with interrupts
   pinMode(statusPin, OUTPUT);

   rpmcount = 0;
   rpm = 0;
   timeold = 0;
   status = LOW;

 }

 void loop()
 {
   //Update RPM every second
   delay(500);
   //Don't process interrupts during calculations
   detachInterrupt(0);
   //Note that this would be 60*1000/(millis() - timeold)*rpmcount if the interrupt
   //happened once per revolution instead of twice. Other multiples could be used
   //for multi-bladed propellers or fans
   rpm = 3*1000/(millis() - timeold)*rpmcount;
   timeold = millis();
   rpmcount = 0;
  brightness = (4 * rpm);
  analogWrite(lightPin, brightness);
 
   if(rpm > 127) {
    printing_byte = 127;
  
   }
  

else {
  
  printing_byte = rpm ;
  }
  #ifdef DEBUG
    Serial.println(rpm, DEC);
  #else
  Serial.print(B10110000 + MIDI_channel,BYTE);
  Serial.print(cc_number,BYTE);
  Serial.print(printing_byte,BYTE);
  #endif

  
    
   //Write it out to serial port
 
  
   //Restart the interrupt processing
   attachInterrupt(0, rpm_fun, FALLING);
  
 
  

  }



Logged

Gothenburg, Sweden
Offline Offline
Jr. Member
**
Karma: 0
Posts: 87
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

You are are measuring the time while you write the MIDI output and the pulse counting is inactive.
Maybe you should move the
Code:
  timeold = millis();
to just before you reenable the interrupts and restart the counting.
Logged

Pages: [1]   Go Up
Jump to: