Jittery Ultrasonic Sensor Output


#1

Hello everyone. So, as I’m waiting for my robotic starter kit to arrive in the mail, I got my hands on one of the electronics kits. In testing it, I seem to get very jittery/erratic output from the ultrasonic sensor. Instead of a smooth progression of distance readings as I move the sensor towards and object, it will sometimes jump or suddenly read 0. Has anyone else run into this? Is it normal behavior or do I have a bad sensor? If it is normal behavior, does anyone know how to smooth out the output?

Thanks!


Zero readings from line follower and ultrasonic sensors in scratch
#2

This is common with Ultrasonic sensors. I’ve had this will all varietys similar to makeblocks. The idea behind some of the libraries, like https://github.com/PaulStoffregen/NewPing, is to sample several times and take the prominent # as the valid one. This works well and from what I can tell, is not implemented in the MakeBlock version.

Looking at the sensors pinnouts http://www.makeblock.cc/me-ultrasonic-sensor-v3-0/, they are similar to Paralx Ping((( or the RadioShack version. So you may need to adjust the libraries pinnouts if you use it.


#3

Thanks, Shaiss. I’ll give that a look. What do you mean by pinouts? Is that MB’s way of adapting a pin to the RJ25 connection?


#4

@ellfire, not exactly, I’ll explain better below.

Makeblock offers their libraries to interact with their hardware, while this makes it easier, it actually becomes a pain when you want to use another library.

The bottom line is none of the me devices are unique. They’re adapted versions of commonly found parts. The main thing is the pinout is changed from standard headers or pads to an RJ25 connector.

So, if we take the ultrasonic sensor as an example, but we want to use the NewPing library, we have to tell the NewPing library which pins the meSensor is using. Using the pinnout image below, you can sort of figure out which pins that RJ25 connector is connecting to.

In the case of the meSensor, it has 3 pins GND, 5V, and SIG


This identical to the Paralx Ping(( module https://www.parallax.com/product/28015:

And differs from the more common HC-SR04 and SR05 modules that have a Trigger and Echo Pin

In summary, the MeRangeSensor and ParalaxPing(( are nearly identical and both use the SIG pin for trigger and Echo.
If use the NewPing library, you will need to supply the same pin for the trigger and echo depending on which RJ25 port you connect it to on the Orion board.

See lines 7 & 8 in https://github.com/PaulStoffregen/NewPing/blob/master/examples/NewPingExample/NewPingExample.ino.

So if you plugged the RJ25 into port 4, you’d change those lines to pin 2. If that doesn’t work, try pin 8. One of the two will work.

If you used port 3, you’d try pin 13, then 12.

Hope that helps, and feel free to post pictures or your code if you need more help!


#5

Shaiss,

Wow! Thanks for the very detailed and informative post! I’ve seen the board diagram before, but never really got what the different color representations meant in relation to normal arduino pins. This is great! I’ll give the ping library a shot and update how it goes. Thanks again!


#6

Okay, so I tried the new ping library and it does work better as far as the jittery readings. Now, might anyone know how to eliminate readings that come back as 0? I.e. I can be holding at 10-15 then it drops down to 0 randomly.

UPDATE - Code posted below with proper formatting.


#7

Hi,

When you want to show code examples, use the </> button at the top of the editor.

#define someThing 6 // It will let you place code without messing up the text

But you need to copy/paste you code into that area. Once you hit Enter, it will put you back into text-mode.

Unfortunately, with out the #include’s and #define’s it will be hard to test you code.


#8

mddickey - Thanks for the tip. Repasting the properly formatted code below. Right now the lights will pop from green to red at a given point. I’d love to have them fade from green to red based on distance, but still need to find examples of that.

#include <Makeblock.h>
#include <NewPing.h> //Library for improved ultrasonic sensor readings
#include <Arduino.h>
#include <SoftwareSerial.h>
#include <Wire.h>

#define TRIGGER_PIN  13  // Set to pin 13 when using PORT_3 for Ultrasonic Sensor
#define ECHO_PIN     13  // Set to same pin as trigger pin.
#define MAX_DISTANCE 400 // Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.

MeUltrasonicSensor ultraSensor(PORT_3); //Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield.
MeRGBLed led(PORT_8); //Set port location for LED module
Me7SegmentDisplay disp(PORT_4); //Set port location for 7 segment display

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

//Declared Global Variables

int rBrite = 0;
int gBrite = 0;

//End Declared Global Variables

void setup()
{
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
  
}

void loop() // Put your main code here
{
 
  if(sonar.ping_cm() <= 15) {rBrite = 50;} else {rBrite = 0;}; //Sets value of the red LED from 0 to 55 based on distance
  if(sonar.ping_cm() > 15) {gBrite = 50;} else {gBrite = 0;}; //Sets value of the green LED from 0 to 55 based on distance

  int dispDist = sonar.ping_cm(); //Create an integer variable to let 7 segment display show value of sonar.ping
  
  Serial.print("Distance : ");
  Serial.print(sonar.ping_cm());
  Serial.println(" cm");
  delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.

  disp.display(dispDist);

  led.setColorAt(0, rBrite, gBrite, 0); //LED 1 R G B
  led.setColorAt(1, rBrite, gBrite, 0); //LED 2 R G B
  led.setColorAt(2, rBrite, gBrite, 0); //LED 3 R G B
  led.setColorAt(3, rBrite, gBrite, 0); //LED 4 R G B
  led.show();

}

#9

ellfire,

Try something like this. Change your if(sonar.ping_cm() <= 15), and if(sonar.ping_cm() > 15) statement to setting the brightness level based on the ratio of the distance to the max_distance

rBrite = 50 * (sonar.ping_cm() / MAX_DISTANCE);

and to have the colors change smoothly from red to green

gBrite = 50 - (50 *(sonar.ping_cm() / MAX_DISTANCE));

I haven’t tried this, but it might give you some ideas.


OK, I tried it out. need to change the lines a bit.

rBrite = 50 * (MAX_DISTANCE / sonar.ping_cm());

and

gBrite = 50 - (50 *(MAX_DISTANCE / sonar.ping_cm());

Good luck.


#10

Thanks. I gave this a try. While I think the code works well, the ultrasonic sensor is just too jittery. I tried using the median option from NewPing, but the results were still very jittery. Maybe there is a more accurate sensor out there to judge distance? Or a better option to smooth out the readings?

Also, in your example, do you know how I could get the fade but still bracket it. I.e. Fade to red when getting closer to a predefined collision point but stay solid green for most of the time?

Thanks again to all.


#12

ellfire,

Here is a copy of the code so far. I have made some changes to the pin configuration (for use with my current hardware setup). I have also made several changes to the program flow. I have tried to include as many comments as I thought necessary.

I’m not quite clear on how you want to fading/transitioning from green to red. If you could make a graph or attach a photo of how it should work, I’ll see if I can help some more.

Mike

#include <Makeblock.h>
#include <NewPing.h> //Library for improved ultrasonic sensor readings
#include <SoftwareSerial.h>
#include <Wire.h>

//Declared Global Constants

#define TRIGGER_PIN  15  // *** this was changed *** Set to pin 13 when using PORT_3 for Ultrasonic Sensor
#define ECHO_PIN     15  // *** this was changed *** Set to same pin as trigger pin.
#define MAX_DISTANCE 200 // *** this was changed *** Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define MAX_BRITE 50     // *** this was added ***
#define TRANSISITION 15  // *** this was added ***

//End Declared Global Constants

MeUltrasonicSensor ultraSensor(PORT_8); //*** this was changed *** Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield.
MeRGBLed led(PORT_3); //Set port location for LED module
Me7SegmentDisplay disp(PORT_4); //Set port location for 7 segment display

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

//Declared Global Variables

int rBrite = 0;
int gBrite = 0;

//End Declared Global Variables

void setup()
{
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() // Put your main code here
{
  int dispDist;
  int cmPing = sonar.ping_cm();  // each time you ping, you get a new reading
  delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.

  if(cmPing > 0){   // this will drop zero values, which seems to be the cause of most of the jitteriness
    rBrite = 0; // reset
    gBrite = 0;  //reset
    if(cmPing <= TRANSISITION) {   //Sets value of the red LED from 0 to 55 based on distance
      rBrite = map(cmPing, 0, TRANSISITION, MAX_BRITE, 0); // https://www.arduino.cc/en/Reference/Map
    } else {
      gBrite = map(cmPing, TRANSISITION, MAX_DISTANCE, 1, MAX_BRITE);
    }; 

    dispDist = cmPing; //Create an integer variable to let 7 segment display show value of sonar.ping
  
    Serial.print("Distance : ");
    Serial.print(cmPing);
    Serial.print(" cm, ");
    Serial.print("rBrite : ");
    Serial.print(rBrite);
    Serial.print(", gBrite : ");
    Serial.println(gBrite);
  };

  disp.display(dispDist);
  
  for(int i = 0; i <= 3; i++){
    led.setColorAt(i, rBrite, gBrite, 0); //LED i R G B
  }
  // led.setColorAt(1, rBrite, gBrite, 0); //LED 2 R G B
  // led.setColorAt(2, rBrite, gBrite, 0); //LED 3 R G B
  // led.setColorAt(3, rBrite, gBrite, 0); //LED 4 R G B
  led.show();

#13

Cool. I’ll give it try.

What I’m thinking for the fade is this.

0-10cm = Solid Read
10-30 = Transition/Fade from Green to Red (This actually makes yellow.)
30+ = Solid green.

Basically, it’s a visual cue for when the robot gets too close to an object. Does that help?


#14

ellfire,

I made a few changes to the code to match your request, see how it works.

#include <Makeblock.h>
#include <NewPing.h> //Library for improved ultrasonic sensor readings
#include <SoftwareSerial.h>
#include <Wire.h>

//Declared Global Constants

#define TRIGGER_PIN  15  // *** this was changed *** Set to pin 13 when using PORT_3 for Ultrasonic Sensor
#define ECHO_PIN     15  // *** this was changed *** Set to same pin as trigger pin.
#define MAX_DISTANCE 200 // *** this was changed *** Maximum distance we want to ping for (in centimeters). Maximum sensor distance is rated at 400-500cm.
#define MAX_BRITE 50     // *** this was added ***
#define TRANSISITION_NEAR 10  // *** this was added ***
#define TRANSISITION_FAR 30  // *** this was added ***

//End Declared Global Constants

MeUltrasonicSensor ultraSensor(PORT_8); //*** this was changed *** Ultrasonic module can ONLY be connected to port 3, 4, 6, 7, 8 of base shield.
MeRGBLed led(PORT_3); //Set port location for LED module
Me7SegmentDisplay disp(PORT_4); //Set port location for 7 segment display

NewPing sonar(TRIGGER_PIN, ECHO_PIN, MAX_DISTANCE); // NewPing setup of pins and maximum distance.

//Declared Global Variables

int rBrite = 0;
int gBrite = 0;

//End Declared Global Variables

void setup()
{
  Serial.begin(115200); // Open serial monitor at 115200 baud to see ping results.
}

void loop() // Put your main code here
{
  int dispDist;
  int cmPing = sonar.ping_cm();  // each time you ping, you get a new reading
  delay(50); // Wait 50ms between pings (about 20 pings/sec). 29ms should be the shortest delay between pings.

  if(cmPing > 0){   // this will drop zero values, which seems to be the cause of most of the jitteriness
    rBrite = 0;
    gBrite = 0;

    if(cmPing <= TRANSISITION_NEAR) {   //Sets value of the red LED from 0 to 55 based on distance
      rBrite = MAX_BRITE;
    } else {
      if(cmPing > TRANSISITION_FAR) {
        gBrite = MAX_BRITE;
      } else {
        rBrite = map(cmPing, TRANSISITION_NEAR, TRANSISITION_FAR, MAX_BRITE, 0); // https://www.arduino.cc/en/Reference/Map
        gBrite = map(cmPing, TRANSISITION_FAR, TRANSISITION_NEAR, MAX_BRITE, 0);
      }
    }; 

    dispDist = cmPing; //Create an integer variable to let 7 segment display show value of sonar.ping
  
    Serial.print("Distance : ");
    Serial.print(cmPing);
    Serial.print(" cm, ");
    Serial.print("rBrite : ");
    Serial.print(rBrite);
    Serial.print(", gBrite : ");
    Serial.println(gBrite);
  };

  disp.display(dispDist);
  
  for(int i = 0; i <= 3; i++){
    led.setColorAt(i, rBrite, gBrite, 0); //LED i R G B
  }
  led.show();
}

#15

I am using an averaging method that seems to work ok but a more advanced sampling method can be used that eliminates outliers with more complex coding. Basically whatever the hardware is doing you can do in software because at the core of the sensor the readings are always noisy. The only drawback is that the sampling in software will probably be slower but you are in control of the algorithm.

The mBlock program here will sample 1-10 readings .02 sec apart and averages them. It starts at 10 samples. You can change the samples by pushing the mCore on board button. When pushing the button it will display a live reading of the ultrasonic sensor on the left and the sampling rate to be used when the button is released on the right. Since this was written for the mBot you might have to adjust for the potential lack of the on-board button.

distance_slide_picture_multi_sample_button_adjust.sb2 (73.6 KB)

This arduino code was generated by the mBlock routines so the code isn’t really optimized but you can use this as a start.

#include <Arduino.h>
#include <Wire.h>
#include <Servo.h>
#include <SoftwareSerial.h>

#include "mBot.h"
#include "MePort.h"
MeBoard myBoard(mBot);
#include "MeUltrasonic.h"
#include "MeLEDMatrix.h"

double angle_rad = PI/180.0;
double angle_deg = 180.0/PI;
double num_samples;
double prox;
MeUltrasonic ultrasonic_3(3);
MeLEDMatrix ledMtx_1(1);
unsigned char drawBuffer[16];
unsigned char *drawTemp;



void setup(){
    pinMode(A7,INPUT);
    num_samples = 10;
    
}

void loop(){
    
    prox =  0 ;
    for(int i=0;i<num_samples;i++)
    {
        prox = (prox) + (ultrasonic_3.distanceCm());
        delay(1000*0.02);
    }
    prox = (prox) / (num_samples);
    ledMtx_1.clearScreen();
    ledMtx_1.setColorIndex(1);
    ledMtx_1.setBrightness(6);
drawTemp = new unsigned char[16]{0,0,255,193,225,225,205,197,197,205,225,225,193,255,0,0};
    memcpy(drawBuffer,drawTemp,16);
    free(drawTemp);
    ledMtx_1.drawBitmap(0,round((prox) / (15)),16,drawBuffer);
    if((0^(analogRead(A7)>10?0:1))){
        num_samples += 1;
        if((num_samples) > (10)){
            num_samples = 1;
        }
        while(!(!((0^(analogRead(A7)>10?0:1)))))
        {
            ledMtx_1.clearScreen();
            ledMtx_1.setColorIndex(1);
            ledMtx_1.setBrightness(6);
            ledMtx_1.showClock(ultrasonic_3.distanceCm(),num_samples,strcmp(":",":")==0);
            delay(1000*0.1);
        }
    }
    
}

Dan


#16

Thanks everyone! I’ve been swamped lately, but hope to try all these new updates over the weekend.


#17