Range sensor MIDI instrument

Status
Not open for further replies.

Synchrony

Active member
Hi, coders! I know enough to be dangerous, but not enough to nail my first code project for Teensy 4.0. I probably won't be coding again in the near future, so learning everything from scratch doesn't make sense for me. If I could get some help fixing and finishing this code, I would greatly appreciate it. Here's the project: I'm using 8 Sharp GP2Y0A02YK0F Infrared Proximity Sensors as a MIDI instrument. To start, I just want to program one sensor to send a MIDI note via USB MIDI. If it's fast enough, I'll add the other 7. The idea is, when I put my hand over a sensor, the voltage changes and sends the MIDI note (from there I'll patch the MIDI signal to my software synth for actual sound).

Here is the code I've cobbled together. I'm sure I'm missing some definitions or initializations. The error I'm currently getting is "usbMIDI was not declared within this scope". Please give this a look and tell me what I'm obviously doing wrong. TIA

Code:
int noteIsOn;

void setup() {

}

void loop() {

  if (noteIsOn == false) {
    if (analogRead(0) > 200) {
      usbMIDI.sendNoteOn(60, 100, 1);
      noteIsOn = true;
    }
  } else {
    if (analogRead(0) < 200) {
      usbMIDI.sendNoteOff (60, 0, 1);
      noteIsOn = false;
    }
  }
  while (usbMIDI.read()) {}
  delay(5);

}
 
You need to choose a USB type Midi in Tools so the compiler knows to use it. I don't think T4 supports USB Mid yet.
 
Uh oh! I was wondering why I didn't see it as an option under "port". So, I need a 3.2? Or is there another simple option I should look at? This needs to be performance-ready fast. Any direction would be appreciated.
 
I bought a 3.2 and have it up and running. Everything works well. I've expanded it to 3 sensors and need to go to 8. I'm sure there's a way to loop the code rather than put it in 8 times, but I'm not sure how to do it. Any help appreciated. Here is what I have for 3 sensors:

Code:
int noteIsOn1;
int noteIsOn2;
int noteIsOn3;
int thresh;

void setup() {

thresh = 225;

}

void loop() {

/// Sensor 1
  if (noteIsOn1 == false) {
    if (analogRead(0) > thresh) {
      usbMIDI.sendNoteOn(60, 100, 1);
      noteIsOn1 = true;
    }
  } else {
    if (analogRead(0) < thresh) {
      usbMIDI.sendNoteOff (60, 0, 1);
      noteIsOn1 = false;
    }
  }
/// Sensor 2
  if (noteIsOn2 == false) {
    if (analogRead(1) > thresh) {
      usbMIDI.sendNoteOn(64, 100, 1);
      noteIsOn2 = true;
    }
  } else {
    if (analogRead(1) < thresh) {
      usbMIDI.sendNoteOff (64, 0, 1);
      noteIsOn2 = false;
    }    
  }
/// Sensor 3
  if (noteIsOn3 == false) {
    if (analogRead(2) > thresh) {
      usbMIDI.sendNoteOn(67, 100, 1);
      noteIsOn3 = true;
    }
  } else {
    if (analogRead(2) < thresh) {
      usbMIDI.sendNoteOff (67, 0, 1);
      noteIsOn3 = false;
    }    
  }
  while (usbMIDI.read()) {}
  delay(5);

}
 
Here is a way to loop the code, it compiles but did not test.
Code:
int thresh;

struct Sensor{
  const uint8_t pin;  //analog sensor pin nr
  uint8_t note; //sensor midi note
  bool noteIsOn; //sensor status
};

const uint8_t sensor_nr = 8;

//define sensor pin_nr and midi_note
Sensor sensor[sensor_nr]{
  {0, 60, false},
  {1, 64, false},
  {2, 67, false},
  {3, 70, false},
  {6, 71, false},
  {7, 72, false},
  {8, 73, false},
  {9, 74, false}
};

void setup() {

  thresh = 225;

}

void loop() {

  for(uint8_t s = 0; s < sensor_nr; s++) {
    if (sensor[s].noteIsOn == false) {
      if (analogRead(sensor[s].pin) > thresh) {
        usbMIDI.sendNoteOn(sensor[s].note, 100, 1);
        sensor[s].noteIsOn = true;
      }
    } else {
      if (analogRead(sensor[s].pin) < thresh) {
        usbMIDI.sendNoteOff(sensor[s].note, 0, 1);
        sensor[s].noteIsOn = false;
      }
    }
  }

  while (usbMIDI.read()) {}
  delay(5);

}
 
That's fairly slick...

I haven't been using structures with Teensyduino but seeing how easy it looks I think I might start.



@OP
The delay(5); is likely keeping this code fairly stable in its output. Without it Teensy would run thousands of times faster and likely give some MIDI chatter when you are near threshold values from the sensors.

If you have other code to run and can't afford dead time consider using the ResponsiveAnalogRead() library to stabilise the signal.

Alternately, separate off and on thresholds could also work since you are already tracking a state variable. (Dead-band hysteresis.)
 
That's fairly slick...

I haven't been using structures with Teensyduino but seeing how easy it looks I think I might start.

And in this case it is easy to extend the structure to contain velocity, midi channel and even different threshold values for every sensor.
Code:
struct Sensor{
  const uint8_t pin;  //analog sensor pin nr
  uint8_t note; //sensor midi note
  uint8_t velocity;
  uint8_t midi_channel;
  uint16_t threshold_on;
  uint16_t threshold_off;
  bool noteIsOn; //sensor status
};
 
Great! I was already thinking about this! For velocity, I'm adding in random(95,110) to give the notes a more natural feel. I'm also playing with the idea of adding in MIDI controller 1 data (modulation/expression) as you get closer and further from the sensor, giving you another level of expression.

Question: Can I -- or should I -- use an external 5V power source for the sensors? Or just use what's coming in through USB and pull the power from the Teensy pins?
 
Question: Can I -- or should I -- use an external 5V power source for the sensors? Or just use what's coming in through USB and pull the power from the Teensy pins?

According to the datasheet for the Sharp sensor,
typical supply current is 33mA
max supply current is 50mA

Assuming you only want to power 8 sensors and 1 T3.2 then
total supply current = 8 x 33mA + ~50ma = ~314mA

Worst case scenario
total supply current = 8 x 50mA + ~50ma = ~450mA

This is within the limits of the 500mA of a usb port.

As soon as you add some other peripherals to your project, it would be wise to switch to an external power supply.
You can also choose not to take any risks blowing your usb port because of an accidental short or so and just go with the external power supply.
If so, don't forget to cut the VUSB trace of the teensy.

Another way to protect your possibly expensive computer is to power your project through a powered usb hub.
 
Are those range sensors polite enough to let you power them up, read then power them down in sequence so as to spread out the power drain?

I hope I'm not getting Off-topic here but a hand up from the back of class re neurofun's post:-

Code:
struct Sensor{
  const uint8_t pin;  //analog sensor pin nr
  uint8_t note; //sensor midi note
  bool noteIsOn; //sensor status
};

const uint8_t sensor_nr = 8;

//define sensor pin_nr and midi_note
Sensor sensor[sensor_nr]{
  {0, 60, false},
  {1, 64, false},
  {2, 67, false},
  {3, 70, false},
  {6, 71, false},
  {7, 72, false},
  {8, 73, false},
  {9, 74, false}
};
How would you attach responsiveAnalogRead or bounce objects to each element (if that's the right word) of the struct ?
 
How would you attach responsiveAnalogRead or bounce objects to each element (if that's the right word) of the struct ?

First you have to declare a pointer to the object you want in your struct and then you need to instantiate that object.
Members of the objects inside the struct can then be accessed with ->

Here are 2 versions of an example(tested on a T3.6) that will read an analog input when the corresponding pushbutton is pressed. The only difference is how the objects are instantiated, functionality is the same.
Code:
#include "Bounce.h"
#include "ResponsiveAnalogRead.h"

struct Sensor{
  Bounce* button;
  ResponsiveAnalogRead* analog_input;
};

const uint8_t sensor_nr = 4;

Sensor sensor[sensor_nr]{
  {new Bounce(0, 20), new ResponsiveAnalogRead(0, false)},
  {new Bounce(1, 20), new ResponsiveAnalogRead(1, false)},
  {new Bounce(2, 20), new ResponsiveAnalogRead(2, false)},
  {new Bounce(3, 20), new ResponsiveAnalogRead(3, false)}
};

void setup() {

  Serial.begin(1000000);
  for(uint8_t s = 0; s < sensor_nr; s++) {
    pinMode(s, INPUT_PULLUP);
  }
}

void loop() {

  for(uint8_t s = 0; s < sensor_nr; s++) {
    sensor[s].analog_input->update();
    if (sensor[s].button->update()) {
      if (sensor[s].button->fallingEdge()) {
        int sample = sensor[s].analog_input->getValue();
        Serial.print("sensor ");
        Serial.print(s);
        Serial.print(" value ");
        Serial.println(sample);
      }
    }
  }

}
Code:
#include "Bounce.h"
#include "ResponsiveAnalogRead.h"

struct Sensor{
  Bounce* button;
  ResponsiveAnalogRead* analog_input;
};

const uint8_t sensor_nr = 4;

Sensor sensor[sensor_nr];

void setup() {

  Serial.begin(1000000);
  for(uint8_t s = 0; s < sensor_nr; s++) {
    pinMode(s, INPUT_PULLUP);
    sensor[s].button = new Bounce(s, 20);
    sensor[s].analog_input = new ResponsiveAnalogRead(s, false);
  }
}

void loop() {

  for(uint8_t s = 0; s < sensor_nr; s++) {
    sensor[s].analog_input->update();
    if (sensor[s].button->update()) {
      if (sensor[s].button->fallingEdge()) {
        int sample = sensor[s].analog_input->getValue();
        Serial.print("sensor ");
        Serial.print(s);
        Serial.print(" value ");
        Serial.println(sample);
      }
    }
  }

}
 
I've built the first version and it's working fairly well. Here is a video of me playing it: https://youtu.be/VMS8y9XyK0A

Next: I want to add a potentiometer to adjust the threshold. I've found that the sensors act different depending on the ceiling and other factors. So, I need code for to adjust the "thresh" variable on the fly. Any help appreciated.

Then: I'm going to put the sensors on top of acrylic tubes and add LEDs to the bottom of the tubes. I'd like them to change colors when the sensor is activated. I have absolutely NO IDEA how to this. And I'd like to use this LED: https://www.adafruit.com/product/2524. Can a Teensy 3.2 handle this type of LED?

Problem: Today I tried the instrument in an auditorium with a smoke machine. The smoke freaked out the sensors and I had to increase the threshold significantly. I don't know if there's anything I can do about that...

I'll post everything in an instructable-type thing once everything is done. Thanks for your help!

Video: https://youtu.be/VMS8y9XyK0A
Images: https://imgur.com/5UsVyRW
https://imgur.com/H30AUpI
https://imgur.com/b1ulnFd
 
I've built the first version and it's working fairly well. Here is a video of me playing it: https://youtu.be/VMS8y9XyK0A

...

JUST FYI : Seems "to be performance-ready" ... I was playing the uTube and my wife came from next room telling me what it was ... and singing

For the LED's pick 7 digital pins and when the sensor triggers turn it on - and off on the release. Those can be simple LED's test with. For the high power LED's - you'll need a capable switch for the Teensy pin to trigger and then have it control the current/voltage needed for the higher output LED. I followed the Adafruit links and they don't suggest the proper wiring to power/switch them. Others here or a web search will point to a Mosfet or proper EE thingy to make it work.

<edit> DOCS on this page show hookup that might be good:
LED - 3W Aluminum PCB (5 Pack, Cool White) ... www.sparkfun.com/products/13105
 
Status
Not open for further replies.
Back
Top