Distance Detection

with MaxSonar ultrasonic rangefinder

Library

A library is available at https://github.com/Diaoul/arduino-Maxbotix

It features:

  • Inputs: TX, PW and AN
  • Models: LV, XL and HRLV
  • Filters: NONE, MEDIAN, HIGHEST_MODE, LOWEST_MODE, SIMPLE, BEST

I recommend looking at the examples to get started with it.

Manually

This is a writeup on the MaxSonar ultrasonic range finder. I felt there was a lack of information out there on this product so I thought this might help out people who are learning.

First of All I used the LV-MaxSonar EZ1 but I imagine the fundamentals will be the same and can be applied to all the MaxSonar products.

Please feel free to update the information here if you find different results for different products.


There are 3 ways to interface the the MaxSonar.

  1. Analog. Very simple, but not as accurate as pw in my experience.
  2. PW - Pulse Width. I found there was not much information out there but it is easy to do.
  3. Serial communication. I will not cover this but someone else is free to contribute :).


Analog

//Feel free to use this code.
//Please be respectful by acknowledging the author in the code if you use or modify it.
//Author: Bruce Allen
//Date: 23/07/09

//Analog pin 1 for reading in the analog voltage from the MaxSonar device.
//This variable is a constant because the pin will not change throughout execution of this code.
const int anPin = 1;

//variables needed to store values
long anVolt, inches, cm;
int sum=0;//Create sum variable so it can be averaged
int avgrange=60;//Quantity of values to average (sample size)

void setup() {

  //This opens up a serial connection to shoot the results back to the PC console
  Serial.begin(9600);

}

void loop() {

  //MaxSonar Analog reads are known to be very sensitive. See the Arduino forum for more information.
//A simple fix is to average out a sample of n readings to get a more consistant reading.\\ //Even with averaging I still find it to be less accurate than the pw method.\\ //This loop gets 60 reads and averages them

for(int i = 0; i < avgrange ; i++) {

    //Used to read in the analog voltage output that is being sent by the MaxSonar device.
    //Scale factor is (Vcc/512) per inch. A 5V supply yields ~9.8mV/in
    //Arduino analog pin goes from 0 to 1024, so the value has to be divided by 2 to get the actual inches
    anVolt = analogRead(anPin)/2;
    sum += anVolt;
    delay(10);

  }  

  inches = sum/avgrange;
  cm = inches * 2.54;
  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  //reset sample total
  sum = 0;

  delay(500);

}


PW

I found this to be more accurate than the analog method and just as easy to implement.

//Feel free to use this code.
//Please be respectful by acknowledging the author in the code if you use or modify it.
//Author: Bruce Allen
//Date: 23/07/09

//Digital pin 7 for reading in the pulse width from the MaxSonar device.
//This variable is a constant because the pin will not change throughout execution of this code.
const int pwPin = 7;
//variables needed to store values
long pulse, inches, cm;

void setup() {

  //This opens up a serial connection to shoot the results back to the PC console
  Serial.begin(9600);

}

void loop() {

  pinMode(pwPin, INPUT);

    //Used to read in the pulse that is being sent by the MaxSonar device.
//Pulse Width representation with a scale factor of 147 uS per Inch.

pulse = pulseIn(pwPin, HIGH); //147uS per inch inches = pulse/147; //change inches to centimetres cm = inches * 2.54;

  Serial.print(inches);
  Serial.print("in, ");
  Serial.print(cm);
  Serial.print("cm");
  Serial.println();

  delay(500);

}


PW with mode filter

Based on the above examples and the median filter provided below, I made a mode filter for too be used with the sonar. I used this in conjunction with pulse width, but I'm sure it would work with the analog readings just aswell.

/* This script is designed to take several readings from the maxbotix sonar and generate a mode/median.
Author: Jason Lessels
Date created: 2011/June/06
Lisence: GPL (=>2)
This work has been compileed using many sources mainly posts/wiki posts from;
Allen, Bruce (2009/July/23) and Gentles, Bill (2010/Nov/12)
*/

//Set the pin to recieve the signal.
const int pwPin = 7;
//variables needed to store values
int arraysize = 9; //quantity of values to find the median (sample size). Needs to be an odd number

//declare an array to store the samples. not necessary to zero the array values here, it just makes the code clearer
int rangevalue[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
long pulse;
int modE;
void setup() {

  //Open up a serial connection
Serial.begin(9600); //Wait for the serial connection
delay(500);

}
//Main loop where the action takes place
void loop() {

  pinMode(pwPin, INPUT);

  for(int i = 0; i < arraysize; i++)
  {								    

    pulse = pulseIn(pwPin, HIGH);
    rangevalue[i] = pulse/58;
    delay(10);
  }

  Serial.print("Unsorted: ");
  printArray(rangevalue,arraysize);
  isort(rangevalue,arraysize);
  Serial.print("Sorted: ");
  printArray(rangevalue,arraysize);
  modE = mode(rangevalue,arraysize);
  Serial.print("The mode/median is: ");
  Serial.print(modE);
  Serial.println();
  delay(1000);

}

/*-----------Functions------------*/ //Function to print the arrays.
void printArray(int *a, int n) {

  for (int i = 0; i < n; i++)
  {
    Serial.print(a[i], DEC);
    Serial.print(' ');
  }

  Serial.println();

}

//Sorting function
// sort function (Author: Bill Gentles, Nov. 12, 2010)
void isort(int *a, int n){
// *a is an array pointer function

  for (int i = 1; i < n; ++i)
  {
    int j = a[i];
    int k;
    for (k = i - 1; (k >= 0) && (j < a[k]); k--)
    {
      a[k + 1] = a[k];
    }
    a[k + 1] = j;
  }

}

//Mode function, returning the mode or median.
int mode(int *x,int n){

  int i = 0;
  int count = 0;
  int maxCount = 0;
  int mode = 0;
  int bimodal;
  int prevCount = 0;

  while(i<(n-1)){

    prevCount=count;
    count=0;

    while(x[i]==x[i+1]){

      count++;
      i++;
    }

    if(count>prevCount&count>maxCount){
      mode=x[i];
      maxCount=count;
      bimodal=0;
    }
    if(count==0){
      i++;
    }
    if(count==maxCount){//If the dataset has 2 or more modes.
      bimodal=1;
    }
    if(mode==0||bimodal==1){//Return the median if there is no mode.
      mode=x[(n/2)];
    }
    return mode;
  }

}


Notice

Please check this page before using LV-MaxSonar:

http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1288290319

You can find a very useful post by Scott from MaxBotix Inc.

Take care with:

  • better use median or mode filter, not AVERAGE filter
  • the different resolution between analogRead() (4.8 mv / unit) -> 1024vals and LV-MaxSonar (9.8 mv / inch) -> 512vals
  • every sensor-group from Maxbotix is different:

http://www.maxbotix.com/articles/033.htm

 http://www.maxbotix.com/articles/032.htm

enjoy!

karduino:D

Share