limit maxbotix LV EZ1's range to two or three feet

What’s up everyone?

I am attempting to replace the LDR I have been using for my midi theremin with a maxbotix ultrasonic rangefinder. As with the LDR, I want to use this device to sense where my hand is and select the appropriate midi note.

With the LDR, I was able to map out the notes from 0-1023, and it worked great except I am having trouble getting it to work consistently in environments with different light levels. I’ve tried adapting the calibration example codes on this site but have had no luck.

My problem with the maxbotix device is that its range is about 21 feet. Obviously if I map out my notes across its range of 0-512 I will have to grow much longer arms to access it all. I have managed to limit it to more manageable ranges but when I do so I either end up having it skip many notes and stop detecting where I want it to, or it detects the notes correctly up to where I want it to stop but keeps detecting past that point and detects notes that are no longer in the musical scale that I have programmed.

Any ideas? Hell, if someone can suggest a better way of using the LDRs I’ll go with that, too! Thanks.

You could constrain the output of the sensor to the range of values that represent what you can reach. http://arduino.cc/en/Reference/Constrain

Then, use that range in the map function to create a mapping between what you can reach and the note to play.

Hi PaulS, thanks for the response and suggestion.

Unfortunately, I wasn't clear enough in my first post ... I have tried using constrain and map without success. Example:

   sonar_value = analogRead(sonar_pin);        
                                 
     sonar_value = constrain(sonar_value, 0, 52);
  
    int mapped_sonar_value = map(sonar_value, 0, 52, 0, number_of_notes);

^ this stops the range to about where I want it to stop, but mysteriously causes my device to start 'skipping' values. For example, say the first detected note (my hand closest to the sensor) is C. The next note detected might be F, then A, etc.

If I map it out like so:

   int mapped_sonar_value = map(sonar_value, 0, 512, 0, number_of_notes);

... the notes advance in the correct order but either get cut off at the spot that I've constrained or, if I don't use the constrain function, are mapped out across 21 feet.

I am really confused that this happens ... it seems like what you suggested should have the correct effect but it doesn't seem to work.

I have also tried adding an 'if (sonar_value >= 52) {' type of attack but get similar results. Anytime I map less than 512 values notes start disappearing.

Perhaps the problem is later in my code, as I do acknowledge that it is pretty long and inelegant ... but then it does work with the LDR so I don't understand why it would be so clumsy with another analog sensor.

Any ideas? :-/

If you don’t constrain the reading, the values should be in the range 0 to 1023, not 0 to 512. Perhaps the thing to do is to map the distance reading using the from range 0 to 52, and the to range 0 to number_of_notes. Any value output by the map function that is greater than number_of_notes then would simply be ignored. Since you can’t reach that far, there should never be readings greater than 52 (or whatever value is determined experimentally to be the upper limit you can reach), there should not be values returned that are greater than number_of_notes, but, it is best to program for the possibility, by simply ignoring them.

int sonar_value = analogRead(sonar_pin);
int mapped_sonar_value = map(sonar_value, 0, 52, 0, number_of_notes);
if(mapped_sonar_value <= number_of_notes)
{
   // do something
}

Here’s a quick update in case anyone in the future has a similar problem … I was unable to get the maxbotix to behave consistently the way that I needed it to for this project. Based on the variety of attacks I have made I am left to conclude that it is the sensor itself that caused my problems.

However, I was able to get the parallax ping)) to do my bidding as a pw input. The maxsonar can do pw too but behaved as strangely as it did when I tried using it as an analog input.

This was a nice learning experience though … originally I couldn’t figure out how to use the pw values that the ping)) gave me and that was why I got the maxsonar in the first place … so that I could utilize its analog input. I think the maxsonar is a good product but the scaling values it gives seem pretty inaccurate and as far as I can see it is not good for a project like mine. If you want something with a longer range it might be what you want though.

My code was derived from the ping example code on the main arduino site and the relevant part is posted below for future n00b use:

void loop() {
   
   long duration, cm;
   
   pinMode(sonar_pin, OUTPUT);
   digitalWrite(sonar_pin, LOW);
   delayMicroseconds(2);
   digitalWrite(sonar_pin, HIGH);
  delayMicroseconds(2);
  digitalWrite(sonar_pin, LOW);
 
 pinMode(sonar_pin, INPUT);
duration = pulseIn(sonar_pin, HIGH); 
cm = microseconds_to_centimeters(duration); 
sonar_value = cm;  //sonar value is equal to detected distance in centimeters  
    
    if (sonar_value > 72){
sonar_value = 72;
    }
    if (sonar_value < 5) {
      sonar_value = 5;
    }
    if (sonar_value <= 72) {
      int mapped_sonar_value = map(sonar_value, 72, 5, 0, number_of_notes);
   mapped_sonar_value = constrain(mapped_sonar_value, 0, number_of_notes);

//and then lots and lots of inelegant code goes here
}
 long microseconds_to_centimeters(long microseconds) {
   return microseconds / 29 / 2;
 }

ps thanks again to PaulS for the help