Let's Make Robots!

[ALMOST SOLVED] HC-SR04 still giving me grief...

June, 7th 2012

----------------------

- Updated schema.

- Segregated power supplies of arduino + sensor
- Added 0.047uf caps to the motor leads (one per lead) grounded by the casing.

- Motor + servo power supply changed to 4 AA rechargable batteries.

- Arduino + sensor when powered by USB everything seems to work fine, except the sensor is a bit slow to respond but that surely it's the code's fault.

 

- Pending issues:  

Tried to power the arduino + sensor with a 9V 300mAh rechargable battery, but made sensor take even longer to reply to obstable, and once it did the system tipically went haywire (invisble obstacles + short burst wheel motions).

Solution: Find a better alternative portable powering alternative for the arduino + sensor. 

 

June 6th, 2012

Ok, I think it's been widely established that the main culprits are my motors and their suckiness and so they produce too much electric noise that even the typical 0.1uf caps in the motor leads (not depicted, must update picture) won't (are not) help(ing) much/enough.

June, 5th, 2012 -- UPDATED PICTURE

Ok, the HC-SR04 part of my attempt of a first robot is still giving me grief ... 

Whereas:

Power supply:

- USB + Batteries 6 or 8 AA ~6-9V downregulated to 5V and an unregulated line out

- the resistors are 8.8k

- and the "strange" labeled hc-sr5 is what the HR-SR04 should be (but Fritzing was lacking a pretty picture of it) is the TROUBLESOME module... :,(

So in the presented setup (I've tried several variations whereas this was the one presenting the "best results") the robot on perch (thus unable to go anywhere) presents me distance measurings as such:

 

 

Distance in centimers: 294

Distance in centimers: 47

Distance in centimers: 102

Distance in centimers: 183

Distance in centimers: 182

Distance in centimers: 136

Distance in centimers: 97

Distance in centimers: 0

Left: 500

Right: 179

Distance in centimers: -69

Left: 500

Right: 177

Distance in centimers: 0

Left: 500

Right: 178

Distance in centimers: -67

Left: 500

Right: 178

Distance in centimers: -66

Left: 500

Right: 178

Distance in centimers: -66

Left: 500

Right: 178

Distance in centimers: -65

Left: 500

Right: 0

Distance in centimers: 0

Left: 0

Right: 0

Distance in centimers: 0

Left: 3

Right: 178

Distance in centimers: 176

Distance in centimers: 44

Distance in centimers: 57

Distance in centimers: 102

Distance in centimers: 96

Distance in centimers: 27

Distance in centimers: 145

Distance in centimers: 0

Left: 500

Right: 178

Distance in centimers: 265

Distance in centimers: -285

 

 

So basically, just the fact that the motors are running the sensor (pointed forward) shows me wild variation of distance:

Distance in centimers: 47

Distance in centimers: 102

Distance in centimers: 183

Distance in centimers: 182

Distance in centimers: 136

Distance in centimers: 97

then once it "seemingly" randomly stumbles upon a value less than 6 (my conditional), the servo activates:

Distance in centimers: 0 

 

 

Left: 500

Right: 179

Distance in centimers: -69

....
when it's scanning the motors are off, and the returned values seem accurate enough... but then... servo goes back to center... and it's silly value time again... at that point the loop is restarting again... but if check the forward distance still within the sweeping function I get an ok value....
So the only things I heavily suspect is:
- (wheel) motors working => interference with sonic ranging
- the start of my loop() section should be "smoother" somehow?

My testing code below for appreciation:

#include <DistanceSRF04.h>
#include <Servo.h>
DistanceSRF04 dist;         // Define the "batvision" object
Servo neckServo;            // Define the Servo object
const int stopDist = 6;            // STOPPING distance (TWEEK THIS)
int distance;               // current distance to obstacle
int distArray[2];            // array of distances measured during a sonar sweep
int enableRight = 5;        // Enable/disable RIGHT motor
int enableLeft = 10;         // Enable/disable LEFT motor
int directionRight = 6;     // Direction of RIGHT motor
int directionLeft = 11;      // Direction of LEFT motor
void setup()
  // initialize serial communication:
  Serial.begin(9600);
  dist.begin(2,3);                    // pins for batvision's Echo AND Trigger (respectively)
  neckServo.attach(9);               // attach the servo on pin 9 to the servo object 
  pinMode(enableRight, OUTPUT); 
  pinMode(enableLeft, OUTPUT);
  pinMode(directionRight, OUTPUT);
  pinMode(directionLeft, OUTPUT);
}
void loop()
{
  delay(500);
  howFar();
  Serial.print("\nDistance in centimers: ");
  Serial.print(distance);  
  delay(500); //make it readable
  if(distance > stopDist){
    forward();
  }
  else{
    stopBot();
    lookAround();
    if(distArray[0] <= distArray[1] && distArray[1] > stopDist){ 
      forwardRight();
      delay(500);
    }
    else if(distArray[0] > distArray[1] && distArray[0] > stopDist){    //hmm - 2
      forwardLeft();
      delay(500);
    }
    else if(distArray[0] <= distArray[1] && distArray[1] <= stopDist){   // hmmmm
      reverseLeft();
      delay(500);
    }
    else if(distArray[0] > distArray[1] && distArray[1] <= stopDist){ 
      reverseRight();
      delay(500);
    }
  }
}  // close loop()
void howFar()
{
  delay(25);
  distance = dist.getDistanceCentimeter();
  delay(25);
}
void lookAround() 
{
  int pos;     
  for(pos = 30; pos <= 150; pos += 1)    // goes from 30 degrees to 150 degrees in steps of 1 degree
  {                                      
    neckServo.write(pos);               // tell servo to go to position in variable 'pos' 
    delay(15);
    if(pos == 45){
      delay(1000);
      distArray[0] = dist.getDistanceCentimeter();
      if(distArray[0] < 0){distArray[0] = 500;}
    }
    if(pos == 135){
      delay(1000);
      distArray[1] = dist.getDistanceCentimeter();
      if(distArray[1] < 0){distArray[1] = 500;}
    }
  }
  
  neckServo.write(90);                  // returns to looking forward
  // testing -- distance read here seems accurate enough
  delay(250);
  howFar();
  delay(50);
  Serial.print("\nLeft: ");  
  Serial.print(distArray[0]);
  Serial.print("\nRight: ");  
  Serial.print(distArray[1]);  
  delay(500); //make it readable  
}
// Robot directional controls
void forward()
{
  digitalWrite(enableRight, HIGH);
  digitalWrite(enableLeft, HIGH);
  digitalWrite(directionRight, HIGH);     // HIGH (currently) means FORWARD
  digitalWrite(directionLeft, HIGH);
}
void forwardRight()                  // ANTI-CLOCKWISE MOVE
{
  digitalWrite(enableRight, LOW);
  
  digitalWrite(enableLeft, HIGH);
  digitalWrite(directionLeft, HIGH);
}
void forwardLeft()                  // CLOCKWISE MOVE
{
  digitalWrite(enableRight, HIGH);
  digitalWrite(directionRight, HIGH);
  
  digitalWrite(enableLeft, LOW);
}
void reverse()
{
  digitalWrite(enableRight, HIGH);
  digitalWrite(enableLeft, HIGH);
  digitalWrite(directionRight, LOW);
  digitalWrite(directionLeft, LOW);
}
void reverseRight()
{
  digitalWrite(enableRight, LOW);
  
  digitalWrite(enableLeft, HIGH);
  digitalWrite(directionLeft, LOW);
}
void reverseLeft()
{
  digitalWrite(enableRight, HIGH);
  digitalWrite(directionRight, LOW);
  
  digitalWrite(enableLeft, LOW);
}
void stopBot()
{
  digitalWrite(enableRight, LOW);
  digitalWrite(enableLeft, LOW);
}
 

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

are you using any library for this program.

Yes, "#include <DistanceSRF04.h>"

As of the moment and after some soldering the dry docks tests seem to show its working more or less ok. As it seems it gets wonkier when the sensor is tilted down, but as I only intend to do horizontal scans (1dof) it should cause no problem. I also altered the code so that it could handle ridiculous distances such as negative ones.

 

why the resistors and transistors?

they form an inverter or NOT gate. If that is the case, they are there to let him save pins on connecting to his h-bridge. This way a HIGH will drive one direction, a LOW will drive the other, and the only way to get true motion is to put some kind of signal on the Enable line, either a digital HIGH/LOW, or a PWM signal to get speed control.

 

duh, i didnt recognize the "mickey mouse logic" thanks for clearing that up

http://letsmakerobots.com/node/32881

i tried with this code 

it works well

#include <Servo.h>
#include "pitches.h"
Servo myservo;
const int numOfReadings = 10;                   // number of readings to take/ items in the array
int readings[numOfReadings];                    // stores the distance readings in an array
int arrayIndex = 0;                             // arrayIndex of the current item in the array
int total = 0;                                  // stores the cumlative total
int averageDistance = 0;                        // stores the average value
int led = 13;
// setup pins and variables for SRF05 sonar device

int echoPin = 8;                               // SRF05 echo pin (digital 2)
int initPin = 7;                               // SRF05 trigger pin (digital 3)
unsigned long pulseTime = 0;                    // stores the pulse in Micro Seconds
unsigned long distance = 0;                     // variable for storing the distance (cm)

int motor1Pin1 = 3;                             // pin 2 on L293D
int motor1Pin2 = 4;                             // pin 7 on L293D                            // pin 1 on L293D
int motor2Pin1 = 5;                             // pin 10 on L293D
int motor2Pin2 = 6;                             // pin  15 on L293D                            // pin 9 on L293D
int speaker = 10;


void setup() {
  // set the motor pins as outputs:
  pinMode(motor1Pin1, OUTPUT);
  pinMode(motor1Pin2, OUTPUT);
 
  pinMode(motor2Pin1, OUTPUT);
  pinMode(motor2Pin2, OUTPUT);
  pinMode(speaker,OUTPUT);
  pinMode(0,INPUT);
  pinMode(1,INPUT);
 
  // set enablePins high so that motor can turn on:
 

  myservo.attach(9);
  myservo.write(90);
  delay(100);

  pinMode(initPin, OUTPUT);                     // set init pin 3 as output
  pinMode(echoPin, INPUT);                      // set echo pin 2 as input
 
  int melody[] = {NOTE_C4,NOTE_G3,NOTE_G3,NOTE_A3,NOTE_G3,0,NOTE_B3,NOTE_C4};
  int noteDurations[] = {4,8,8,4,4,4,4,4};
  for (byte Note = 0; Note < 8; Note++)
  {
    int noteDuration = 1000/noteDurations[Note];
    tone(speaker,melody[Note],noteDuration);
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
  }

  // create array loop to iterate over every item in the array

  for (int thisReading = 0; thisReading < numOfReadings; thisReading++) {
    readings[thisReading] = 0;
  }
}

void loop() {
  digitalWrite(initPin, HIGH);                  // send 10 microsecond pulse
  delayMicroseconds(10);                                // wait 10 microseconds before turning off
  digitalWrite(initPin, LOW);                   // stop sending the pulse
  pulseTime = pulseIn(echoPin, HIGH);           // Look for a return pulse, it should be high as the pulse goes low-high-low
  distance = pulseTime/58;                      // Distance = pulse time / 58 to convert to cm.
  total= total - readings[arrayIndex];          // subtract the last distance
  readings[arrayIndex] = distance;              // add distance reading to array
  total= total + readings[arrayIndex];          // add the reading to the total
  arrayIndex = arrayIndex + 1;                  // go to the next item in the array  

  // At the end of the array (10 items) then start again
  if (arrayIndex >= numOfReadings)  {
    arrayIndex = 0;
  }

  averageDistance = total / numOfReadings;      // calculate the average distance
  delay(10);
  byte noise;
  noise++;
  if(noise>24)
  {
    tone(speaker,distance*5+100,5);
    noise=0;
  }

  // check the average distance and move accordingly

  if (averageDistance <= 10){
    // go backwards
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
    myservo.write(10);
    delay(100);   

  }

  if (averageDistance <= 25 && averageDistance >= 10) {
    // turn
    digitalWrite(motor1Pin1, HIGH);
    digitalWrite(motor1Pin2, LOW);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH);
    myservo.write(150);
    delay(100);  
  }
  if (averageDistance >= 25 && averageDistance <= 10) {
    // turn
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, HIGH);
    digitalWrite(motor2Pin2, LOW);
    myservo.write(120);
    delay(100);  
  }

  
   if (averageDistance > 25)   {
    // go forward
    digitalWrite(motor1Pin1, LOW);
    digitalWrite(motor1Pin2, HIGH);
    digitalWrite(motor2Pin1, LOW);
    digitalWrite(motor2Pin2, HIGH); 
    myservo.write(90);
    delay(100);  

  }
 
}
 
 
 
 
 
 

Thanks,

I'll try your pinging strategy later at home, albeit I have been having wonky results with other codes/libraries.
Thus at this moment I'm leaning more torwards my sensor being somehow particularly prickly than it should be. *shakes fist*

I've ordered another one that should be arriving any day now.

OK it's working properly I think. :)

So basically I think that JAX's RC trick (caps from leads to motor casing) solved the servo jitter. 

And Max indeed segregating the arduino and sensor's power supply from the servo and motors fixed the faulty readings. Anyhow I made some other slight changes, I have dinner in the making now but I'll post and updated schema after I'm done.

:) *long exhale* 

#include<high5.h>

First, the schematic still has the Arduino Vcc/Gnd going into the same rails.  If the motors really are introducing electronic noise into the system, isolate the Voltages from eachother  and it should disappear.  

However, I'm not certain that this is the issue, especially if the physical setup is the same as the one Bird/JAX showed me the other night.  If you're only experiencing problems with the sonar when the motors are running my first guess at the problem is that the construction materials aren't doing enough to stabilize the physical vibrations caused by the motors out of the system and that the HC-SR04 as a result is probably sweeping up and down as much as it is left and right, which will make a small bot like this see spots on the floor in front of it as obstacles.  Corrugated cardboard and sticky tape are great lightweight maker materials but they aren't what you want when it comes to rigidity.

An idea to test this: unplug the motors from the circuit, run the test sketch and push the bot along the desktop at roughly the speed you get out of the motors.  If you still get the jitter, it's likely not electronic noise.