multiple maxbotix LVEZ on one UNO?

FWIW, I rewrote your sketch, since I plan to try it on my own robot, which has both
EZ1 and EZ4 - tomorrow, as I'm beat tonight. I need to change the I/O pins, etc.
It compiles ok.

The only thing I'm not too sure about is your holding the txpin high for the entire
duration of ALL sonar pings. The usual method is to pulse it low after triggering,
but I imagine the code will get around the loop ok, as it is, before the next
pulse comes out.

Also, thanks for the sort code, I needed that :-).

/* Two LV Maxsonar EZ1 sensors with mode filter by Dan Shields 
   Adapted from Jason Lessels, Bruce Allen, and Bill Gentles.
*/
int button = 7;              
int PIRleft = A3;                                              
int LEDleft = 12;	                                          
int PIRright = A4;                                              
int LEDright = 8;
int motorL = 9;     //forward left
int motorR = 10;    //forward right
int SonarR = 5;
int TriggerR = 2;
int SonarL = 3;
int TriggerL = 4;
int val;                        // variable for reading the pin status
int val2;                       // variable for reading the delayed status
int buttonState = 0;                // variable to hold the button state
int robotMode = 0; 

int arraysizeR = 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 rangevalueR[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
//long pulseR;
int modER;
//long valueR = 0;

int arraysizeL = 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 rangevalueL[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0};
//long pulseL;
int modEL;
//long valueL = 0;


void setup() 
{
  pinMode(button, INPUT);
  pinMode(LEDright, OUTPUT);
  pinMode(LEDleft, OUTPUT);
  pinMode(TriggerL, OUTPUT);
  pinMode(TriggerR, OUTPUT);
  pinMode(motorR, OUTPUT);
  pinMode(motorL, OUTPUT);
  Serial.begin(9600);
}

void loop()  
{
  distCalcL();
  distCalcR();
  if (modEL >= 14 && modEL <= 36) {
    digitalWrite(LEDleft, HIGH);
  }
  else if (modEL < 14 || modEL > 36) {
    digitalWrite(LEDleft, LOW);
  }
  if (modER >= 14 && modER <= 36) {
    digitalWrite(LEDright, HIGH);
  }
  else if (modER < 14 || modER > 36) {
    digitalWrite(LEDright, LOW);
  }
}

int distCalcL()
{    
  read_sonar( TriggerL, SonarL, rangevalueL, arraysizeL);
  isort( rangevalueL, arraysizeL);
  
  modEL = mode( rangevalueL, arraysizeL);
  display_output("The mode/medianL is: ", modEL);
  delay(100);
}

int distCalcR()
{    
  read_sonar( TriggerR, SonarR, rangevalueR, arraysizeR);
  isort( rangevalueR, arraysizeR);
  
  modER = mode( rangevalueR, arraysizeR);
  display_output("The mode/medianR is: ", modER);
  delay(100);
}

/*******************************************/
void display_output( char* msg, int mode) 
{
  Serial.print(msg);
  Serial.print(mode);
  Serial.println();
}

/**********************************************************/
void read_sonar(int txpin, int rxpin, int* ary, int asiz)
{
  pinMode(rxpin, INPUT);

  for(int i = 0; i < arraysizeL; i++) {								    
    digitalWrite(txpin, HIGH);
    ary[i] = pulseIn(rxpin, HIGH) / 147;
    delay(10);
  }
  digitalWrite(txpin, LOW);
}

/*-----------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();
//}

// sort function (Author: Bill Gentles, Nov. 12, 2010)
void isort(int *a, int n)
{
  int i, j, k;
  
  // *a is an array pointer function
  for( i=1; i < n; ++i) {
    j = a[i];
    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, countL=0;
  int prevCountL=0, maxCountL=0;
  int modeL=0;
  int bimodalL;

  while( i < (n-1) ) {
    prevCountL=countL;
    countL=0;

    while( x[i] == x[i+1]) {
      countL++;
      i++;
    }
    if( (countL > prevCountL) & (countL > maxCountL) ) {
      modeL=x[i];
      maxCountL=countL;
      bimodalL=0;
    }
    if(countL==0) { i++; }
    
    if(countL==maxCountL) { //If the dataset has 2 or more modes.
      bimodalL=1;
    }
    if( (modeL==0) || (bimodalL==1) ) { //Return the median if there is no mode.
      modeL=x[(n/2)];
    }
    return modeL;
  }
}

oops, need to change arraysizeL to asiz inside function

void read_sonar(int txpin, int rxpin, int* ary, int asiz)

Yea, I wondered about where exactly and low long to hold the TX pins high. I'm gonna play with it a little more tonight when I get home from work. Also about the mode filter, you're right that it doesn't improve the accuracy of the sensors at all, but it does do a pretty good job of getting rid of the random readings that I get that are way off. I'm also adding more code to this for my robot. For me, I add one sensor at a time. It's easier to debug. I'm adding a couple PIR sensors and a push button to turn the robot on and to turn it in standby mode.

Ok, I learned a lot about Maxsonars today, via courtesy of your code. :slight_smile:

I have both EZ1 and EZ4. The target is a cardboard box located exactly 24" from the front of
the sonars. It's a small robot, so the sonars are only 7" above the floor. I did change the ping
routine so the trigger pin is only held high for 20-usec. First the data.

Using 10-msec delay between samples (original)
-----------------------------------
EZ1 mode/medianL is: 21
0 0 0 0 21 21 21 21 21 
EZ4 mode/medianR is: 20
0 0 0 0 20 23 23 23 23 

Using 100-msec delay between samples
------------------------------------
sonars head-on to 8"x8" box:
EZ1 mode/medianL is: 21
21 21 21 21 21 21 21 21 21 
EZ4 mode/medianR is: 23
20 23 23 23 23 23 23 23 23 

sonars aimed up approx 20-degrees:
EZ1 mode/medianL is: 24
24 24 24 24 24 24 24 24 24 
EZ4 mode/medianR is: 25
22 25 25 25 25 25 25 25 25

First, using your original 10-msec delay between samples gives 0 for the first 4 readings, then
the other readings are "close". I assume what happens is the sonar doesn't have time to self-
calibrate properly, and you have to wait longer before resampling. Also, the spec sheet indicates
the total processing time = 50-msec or so. Apparently, after 4 samples it finally gets the
self-calibration done. ????

Second, changing to 100-msec sampling delay works much better, but still is not perfect. The
EZ1 always reads low, and the 1st EZ4 reading is always < the others. I think this must be a
self-calibration issue again - so looks like:

ALWAYS have to sample the EZ4 at least twice, and throw away the frst sample. Doh!

Thirdly, if I aim the sonars upwards, instead of perfectly horizontally, then the readings get better.
Apparently, due to the wide beams, especially of the EZ1, they pick up ground clutter because
the robot is small and the sonars are too close to the ground. Pointing the sonars away from the
ground fixes the problem, except now the narrow-beam EZ4 is apparently pointing too high to give
a correct reading. LOL, it's always something.

All in all, a lot of issues involved with using these sonars.

Ok, it occurred to me I screwed up last time, forgot that the sort re-orders the samples
in the original data array. So now I am displaying data both before and after sorting.
Things make a little more sense, as the ranges jump between 0 and /almost/ correct
with the 10-msec sampling delay, but don't have this problem for 100-msec delay.
Apparently, the sample = 0 is due to not enough time to calibrate. Or whatever.

The EZ4 still ranges low the first time, in either case.

10-msec sampling delay:
----------------------
EZ1
22 0 22 0 22 0 22 0 22 
EZ1 mode/medianL is: 22
0 0 0 0 22 22 22 22 22 

EZ4
20 0 23 0 23 0 23 0 23 
EZ4 mode/medianR is: 20
0 0 0 0 20 23 23 23 23 

100-msec sampling delay:
-----------------------
EZ1
22 22 22 22 22 22 22 22 22 
EZ1 mode/medianL is: 22
22 22 22 22 22 22 22 22 22 

EZ4
20 23 23 23 23 23 23 23 23 
EZ4 mode/medianR is: 23
20 23 23 23 23 23 23 23 23

I was under the assumption that the sensor only had to calibrate once. Does it calibrate every time the trigger pin is held high? For my robot, + or - 2" is fine, but it would be nice to get an accurate reading. You don't seem to get the same spikes that I get. Are you using this noise filter pictured in the attachment? That came from here: http://www.maxbotix.com/tutorials.htm#New_Flash_UAV_and_Mobile_Robotic_Users Also I saw where an engineer from Maxbotix suggested even using a 100 OHM resistor on the negative pin as well. It seems that they monitor forums for questions and try to help. http://arduino.cc/forum/index.php/topic,14301.0.html
The reply from a Maxbotix engineer is posted on the second page I think. I wonder if the XL line of sensors would be more accurate and stable, but they cost twice as much. And I hate to just throw money at the problem without understanding what is causing it. My spikes in readings occur even when the motors aren't on and with the noise filter in place. My sensors are also close to the ground but still occur when I raise the robot off the ground and use different objects to detect.

maxbotix.PNG

oric_dan,
How do you have the sensors wired? Are they in the daisy chain? Is that why you have TX and RX?

void read_sonar(int txpin, int rxpin, int* ary, int asiz)
{
pinMode(rxpin, INPUT);

Why is rx an input?

if(countL>prevCountL&countL>maxCountL){

s/b:

if( countL > prevCountL && countL > maxCountL ) {

or as I prefer:

if( (countL > prevCountL) && (countL > maxCountL) ) {

Did you change this in your code that you're using now?
Could you post the code that you're using now? Thanks

Thinking more on this, the alternating 0 with non-0 readings were probably due to having the
trigger pulses so close together that the units hadn't finished the previous "full" cycle before
the next trigger came along. So increasing delay from 10 to 100-msec fixed that.

As far as noise goes, there isn't much noise in the good sets of readings, the only anomaly is
the first EZ4 reading is much lower than the others. I don't know why, but probably should take
more than 1 reading and throw the first away every time. ????

I don't know what spikes you are seeing. I don't have the 100-100 filter you show, but do actually
have a 100-uF cap on the Vdd buss in the area that feeds the sonars.

Also, as noted last time, I think the short readings are largely due to ground clutter pickup.
I have one more test to try.

How do you have the sensors wired? Are they in the daisy chain? Is that why you have TX and RX?

Quote
void read_sonar(int txpin, int rxpin, int* ary, int asiz)
{
pinMode(rxpin, INPUT);

Why is rx an input?

No daisy-chain, I am simply using your code, and separate sonars. If you check your original code
with my editing, you'll see tx,rx are just your same pins:

int SonarR = 5;
int TriggerR = 2;
int SonarL = 3;
int TriggerL = 4;

Could you post the code that you're using now? Thanks

See post #20.

Well, I did some more testing, and now I am stumped. Tried to figure out why the EZ4 was reading
low on the first measurement.

First, I changed to the order of reading EZ1 and EZ4, and lo and behold, then the EZ1 was the
one reading low. See first data set below. So, it's not the sonar device that's the problem, it's
the manner of reading. I've tried various things so far, but can't figure it out.

First, I typically use 57600 bps, so the Serial.print() displays come out very fast. By playing around,
I found I could get the 2nd sonar to read ok by either using 9600 bps [which takes about 50-msec
to send the data lines], or inserting a minimum 10-msec delay between sonar readings, see code.

I've also tried other things like zeroing the data arrays before reading, and also changing the
trigger pulsewidths, etc, but so far none of that works, so I'm stumped as to why adding a little
10-msec delay fixes the problem.

Especially given that there is already a 100-msec delay at the end of the measurement loop in
the read_sonar() routine, shown earlier. Duh? Scratches his head.

57600 bps, no delay [bad]
-------------------
23 23 23 23 23 23 23 23 23 
EZ4 mode/medianR is: 23
20 23 23 23 23 23 23 23 23 
EZ1 mode/medianL is: 23


9600 bps, or 57600 bps & delay(10) [good]
----------------------------------
23 23 23 23 23 23 23 23 23 
EZ4 mode/medianR is: 23
23 23 23 23 23 23 23 23 23 
EZ1 mode/medianL is: 23

void loop()  
{
  Serial.println(" ");
  distCalcR();
  delay(10);
  distCalcL();
  .....
}

No daisy-chain, I am simply using your code, and separate sonars. If you check your original code
with my editing, you'll see tx,rx are just your same pins:

int SonarR = 5;
int TriggerR = 2;
int SonarL = 3;
int TriggerL = 4;

How are your sensors wired? I have only four wires coming from each sensor. For example the right sonic has +, -, RX to pin 2, and PWM to pin 5. Is that how your sensors are connected?

pinMode(rxpin, INPUT);

Why is rx pin an input? Shouldn't it be an output just to trigger the sensor into reading?

if(countL>prevCountL&countL>maxCountL){

s/b:

if( countL > prevCountL && countL > maxCountL ) {

or as I prefer:

if( (countL > prevCountL) && (countL > maxCountL) ) {

Were you going to change this in your code? It seems to work both ways, but it shouldn't since the single "&" is for binary.

Also I'm not getting the nine values in the array that get converted into mode even when I un-comment the "void printArray" part of the code. I am only getting the mode for each of the sensors.
if you could copy and paste the code as you are using it with your modifications it would be a big help. Thanks.

If you check my code in post #20 you'll see:

  read_sonar( TriggerR, SonarR, rangevalueR, arraysizeR);
..........

/**********************************************************/
void read_sonar(int txpin, int rxpin, int* ary, int asiz)
{

Also, must be "&&" in the other, I forgot to fix it in post #20 code. It doesn't matter in regards
the 2nd sonar, 1st sample problem.

Why do you have TX and RX in your code? Do you have TX wired up to something? And Why is RX an input instead of output? I'm missing something.

Local [temporary] variables are visible only inside the function, call them whatever you like.
I modified this to reflect the other changes I mentioned.

/**********************************************************/
void read_sonar(int trigpin, int pulsepin, int* ary, int asiz)
{
  pinMode(pulsepin, INPUT);

  for(int i = 0; i < arraysizeL; i++) {							    
    digitalWrite(trigpin, HIGH);
    delay(20);
    digitalWrite(trigpin, LOW);
    ary[i] = pulseIn(pulsepin, HIGH) / 147;
    delay(100);
  }
}

That makes more sense to me now. Thanks. But unfortunately the code only works good for a stationary robot ranging a stationary target (21" x 21" box. There's a 4-5 second lag to change the led's to reflect the change in range if I move the robot closer or farther away. I changed some of your delays to delayMicroseconds and still get ok results. Still some spikes, though. I think the main problem is with the inherent limitations of the sensor. It's fairly accurate but the accuracy isn't very repeatable (precise).

void read_sonar(int trigpin, int pulsepin, int* ary, int asiz)
{
pinMode(pulsepin, INPUT);

for(int i = 0; i < arraysizeL; i++) {
digitalWrite(trigpin, HIGH);
delayMicroseconds(20);
digitalWrite(trigpin, LOW);
ary = pulseIn(pulsepin, HIGH) / 147;

  • //delay(100);*
  • }*
    }[/quote]
    *I also tried it with the baud rate set to 57600 got the same results. The data sheet for the Maxsonar says 9600 baud, but it works ok anyway. *
    The parallax ping sensor seems to be more accurate and precise, but it's footprint is so narrow that it's worthless for my robot. I might have to rethink my whole approach to my project.

I think the 4-5 sec delay on Leds you mention is simply because your range check covers 14 - 36".

I wouldn't remove the delay, but you might shorten it to 50-msec - per the EZ datasheet.

Also, the Maxsonar 9600 bps is only if you use the RS232 mode output, which you're not using.

I think the 4-5 sec delay on Leds you mention is simply because your range check covers 14 - 36".

Can you elaborate on this?

The following code cuts the delay to about 2 seconds from the longer delay. I don't care about the LED's but at the moment they are simulating motors.

  for(int i = 0; i < arraysizeR; i++)
  {								    
    digitalWrite(TriggerR, HIGH);
    delayMicroseconds(200);
    digitalWrite(TriggerR, LOW);
    pulseR = pulseIn(SonarR, HIGH);
    rangevalueR[i] = pulseR/147;
    delay(50);

Do you agree with these delays?

Delays look good.

But unfortunately the code only works good for a stationary robot ranging a stationary target (21" x 21" box. There's a 4-5 second lag to change the led's to reflect the change in range if I move the robot closer or farther away.

I guess I didn't understand what this meant.

Hello!

Hello! I am working on a project on human presence detection. I have ordered 2 maxbotix ez3 an arduino uno and a buzzer. I want my sensors to detect presence one at a time so that I can detect when the person is inside a room. I can't find the tutorial where I connect the to sensors to the Arduino Uno. Please, can you help me?