Go Down

Topic: optical tachometer to MIDI help (Read 643 times) previous topic - next topic

kazimier

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: [Select]
/*
* 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

ai4ai

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


kazimier

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: [Select]
/*
* 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);
 

 

 }




M Lundin

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

Go Up