1

I am building a robot with multiple sensors, abilities etc. Since I had a bug with a HC-SR04 rotated by a servo, I experimented in a different sketch. If the distance is less than 30cm, the servo turns left and right. Since I need continuous readings of other sensors, I cannot use delays so I used millis in order to keep time. The sensor worked correctly in a different sketch, but something in the full one conflicts with it.

#include <LiquidCrystal.h>
#include <Wire.h>
#include <RTClib.h>
#include <Servo.h>
#include <IRremote.h>

RTC_DS1307 rtc;

/*const int blue2 = 12;
const int blue1 = 11;
const int red1 = 10;
const int red2 = 9;
*/
Servo servo;


byte leds[4] = {8, 7, 6, 9};

const int STBY1=45;
const int ain11=47;
const int ain12=43;
const int aPWM1=2;
const int bin11=41;
const int bin12=40;
const int bPWM1=4;
const int STBY2 = 39;
const int ain21=33;
const int ain22=31;
const int aPWM2=5;
const int bin21=35;
const int bin22=37;
const int bPWM2=3;


const int piezo = 32;

const int flamePin = A7;

int flameState;

const int photoResistor = A1;

int photoState;

const int temp = A2;

float temperature;

int ledAnalog;

const int irGnd = 52;

const int irVcc = 50;

const int irSignal = 48;

decode_results results;

IRrecv irrecv(irSignal);

boolean manualLeds = false;

boolean ledsOn = false;


unsigned long counter;

unsigned long prevMillis = 0;

int piezoInterval = 200;

int drivingMode = 0;

boolean playPiezo=false;

#define trig 22
#define echo 24
long duration;
boolean turned150 = false;
int cm30, cm, cm150;
bool checkLeft = false;
boolean checkRight = false;
boolean mainPing = true;
unsigned long servoTimer = millis();

void setup(){
  Wire.begin();
  rtc.begin();
  pinMode(piezo, OUTPUT);
pinMode(STBY1, OUTPUT);
  pinMode(aPWM1, OUTPUT);
  pinMode(ain11, OUTPUT);
  pinMode(ain12, OUTPUT);
  pinMode(bPWM1, OUTPUT);
  pinMode(bin11, OUTPUT);
  pinMode(bin12, OUTPUT);

  pinMode(STBY2, OUTPUT);
  pinMode(aPWM2, OUTPUT);
  pinMode(ain21, OUTPUT);
  pinMode(ain22, OUTPUT);
  pinMode(bPWM2, OUTPUT);
  pinMode(bin21, OUTPUT);
  pinMode(bin22, OUTPUT);

 servo.attach(12);
 for(int i=0;i<sizeof(leds)/sizeof(leds[0]);i++){
    pinMode(leds[i], OUTPUT);
 }

  pinMode(flamePin, INPUT);
  pinMode(photoResistor, INPUT);
  pinMode(temp, INPUT);
  pinMode(irGnd, OUTPUT);
  digitalWrite(irGnd, LOW);
  pinMode(irVcc, OUTPUT);
  digitalWrite(irVcc, HIGH);
  pinMode(irSignal, INPUT);
 Serial.begin(9600);
  irrecv.enableIRIn();
  digitalWrite(STBY1, LOW);
    digitalWrite(STBY2, LOW);
servo.write(90);
delay(200);
}

void loop(){

 counter=millis();
 //Serial.print("Millis1: ");
 //Serial.println(millis());
 if(irrecv.decode(&results)){
    translateIR();
    irrecv.resume();
  }
 // Serial.print("Millis2: ");
 //Serial.println(millis());
if(drivingMode == 1){
   if(((counter-servoTimer) >= 150) && mainPing){
    ping();
    cm=duration/29.1/2;
    Serial.println(cm);
    counter=millis();
    servoTimer=counter;
  }
  if((cm<30) && mainPing){

    mainPing=false;
    checkRight = true;
    counter=millis();
    servoTimer=millis();
    servo.write(150);
    cm=30;


  }
  if(checkRight && !checkLeft && ((counter-servoTimer) >= 170)){

    ping();
    checkLeft=true;
    cm150 = duration/29.1/2;
    counter=millis();
    servoTimer=millis();
    servo.write(50);
  }
  if(checkRight && checkLeft && ((counter-servoTimer) >= 340)){
  checkRight=false;
  checkLeft=false;
  mainPing=true;
  ping();
  cm30 = duration/29.1/2;
  counter=millis();
  servoTimer=millis();
  servo.write(90);

  }

 }

//getTime();
//existsFire();
/*if(!manualLeds){
readPhoto();
}*/

}



void readPhoto(){

  photoState = analogRead(photoResistor);
  if(photoState>600){
    ledAnalog=0;
  }
  else if(photoState<300){
    ledAnalog=255;
  }
  else{
    ledAnalog = 150 - photoState/4;
  }
  for(int x = 0;x<sizeof(leds)/sizeof(leds[0]);x++){
  analogWrite(leds[x], ledAnalog);
  }


}


void existsFire(){
flameState = analogRead(flamePin);
Serial.println(flameState);
if(flameState <= 50){
  static boolean playingBuzzer = true; 
  if(counter - prevMillis > piezoInterval){

     prevMillis = counter;
     playingBuzzer=!playingBuzzer;

  }
  if(playingBuzzer){

    digitalWrite(piezo, HIGH);

  }
  else{
    digitalWrite(piezo, LOW);
  }

}
else if(!playPiezo){
  digitalWrite(piezo, LOW);
}
else if(playPiezo){
  digitalWrite(piezo, HIGH);
}

}

void checkTemp(){

  temperature = ((analogRead(temp) / 1024.0 * 5.0) - .5) * 100;
  Serial.println(temperature);

}
void ping(){

    digitalWrite(trig, LOW);
    delayMicroseconds(2);
    digitalWrite(trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(trig, LOW);
    duration = pulseIn(echo, HIGH);

}
void getTime(){

  DateTime now = rtc.now();

  Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
}
void forward(){
digitalWrite(STBY1, HIGH);
digitalWrite(ain11, HIGH);
digitalWrite(ain12, LOW);
analogWrite(aPWM1, 255);

digitalWrite(bin11, LOW);
digitalWrite(bin12, HIGH);
analogWrite(bPWM1, 234);


digitalWrite(STBY2, HIGH);
digitalWrite(ain21, LOW);
digitalWrite(ain22, HIGH);
analogWrite(aPWM2, 255);

digitalWrite(bin21, LOW);
digitalWrite(bin22, HIGH);
analogWrite(bPWM2, 234);
}
void backward(){

digitalWrite(STBY1, HIGH);
digitalWrite(ain11, LOW);
digitalWrite(ain12, HIGH);
analogWrite(aPWM1, 255);

digitalWrite(bin11, HIGH);
digitalWrite(bin12, LOW);
analogWrite(bPWM1, 235);


digitalWrite(STBY2, HIGH);
digitalWrite(ain21, HIGH);
digitalWrite(ain22, LOW);
analogWrite(aPWM2, 255);

digitalWrite(bin21, HIGH);
digitalWrite(bin22, LOW);
analogWrite(bPWM2, 235);


}
void left(){

digitalWrite(STBY1, HIGH);
digitalWrite(ain11, HIGH);
digitalWrite(ain12, LOW);
analogWrite(aPWM1, 255);

digitalWrite(bin11, HIGH);
digitalWrite(bin12, LOW);
analogWrite(bPWM1, 255);


digitalWrite(STBY2, HIGH);
digitalWrite(ain21, LOW);
digitalWrite(ain22, HIGH);
analogWrite(aPWM2, 255);

digitalWrite(bin21, HIGH);
digitalWrite(bin22, LOW);
analogWrite(bPWM2, 255);

}
void right(){
digitalWrite(STBY1, HIGH);
digitalWrite(ain11, LOW);
digitalWrite(ain12, HIGH);
analogWrite(aPWM1, 255);

digitalWrite(bin11, LOW);
digitalWrite(bin12, HIGH);
analogWrite(bPWM1, 255);


digitalWrite(STBY2, HIGH);
digitalWrite(ain21, HIGH);
digitalWrite(ain22, LOW);
analogWrite(aPWM2, 255);

digitalWrite(bin21, LOW);
digitalWrite(bin22, HIGH);
analogWrite(bPWM2, 255);


}
void brake(){

digitalWrite(STBY1, LOW);
digitalWrite(ain11, LOW);
digitalWrite(ain12, LOW);
analogWrite(aPWM1, 0);

digitalWrite(bin11, LOW);
digitalWrite(bin12, LOW);
analogWrite(bPWM1, 0);


digitalWrite(STBY2, LOW);
digitalWrite(ain21, LOW);
digitalWrite(ain22, LOW);
analogWrite(aPWM2, 0);

digitalWrite(bin21, LOW);
digitalWrite(bin22, LOW);
analogWrite(bPWM2, 0);

}
void translateIR(){
//Serial.println(results.value, HEX);
switch(results.value){
case 0xFF02FD:
case 0x20DF22DD:
//stop(ok)
if(drivingMode==0){
brake();
//Serial.println("brake");

}
break;
case 0xFF629D:
case 0x20DF02FD:
//forward
if(drivingMode==0){
forward();
//Serial.println("forward");
}
break;
case 0x20DF827D:
case 0xFFA857:
//back
if(drivingMode==0){
backward();
//Serial.println("back");

}
break;
case 0xFF22DD:
case 0x20DFE01F:
//left 
if(drivingMode==0){
left();
//Serial.println("left");
}
break;
case 0x20DF609F:
case 0xFFC23D:
//right
if(drivingMode==0){
right();
//Serial.println("right");

}
break;
case 0xFF6897:
case 0x20DF8877:
if(drivingMode==0){
  brake();
  drivingMode=1;
}
else{
  brake();
  servo.write(90);
  drivingMode=0;
}
//1(switch driving mode)
break;
case 0xFF9867:
case 0x20DF48B7:
//2(switch led mode)
if(!manualLeds){
manualLeds=true;
    for(int x = 0;x<sizeof(leds)/sizeof(leds[0]);x++){
  digitalWrite(leds[x], LOW);
  }
}
else{
manualLeds=false;
}

break;
case 0xFFB04F:
case 0x20DFC837:
if(manualLeds){
  if(!ledsOn){
    for(int x = 0;x<sizeof(leds)/sizeof(leds[0]);x++){
  digitalWrite(leds[x], HIGH);
  }

  ledsOn=true;
  }
  else{
       for(int x = 0;x<sizeof(leds)/sizeof(leds[0]);x++){
  digitalWrite(leds[x], LOW);
  }
  ledsOn=false;   
  }
}
//3(toggle leds if mode is on)
break;
case 0xFF30CF:
case 0x20DF28D7:
//4(play sound)
playPiezo = !playPiezo;

}


}

EDIT 2:

I decided to see what will happen if I start removing code. I removed most of the code that I did not need for this experiment. After the removal, the issue persisted. The sensor is still giving me 0s. This is all the code that was left after I removed stuff:

#include <Servo.h>

//RTC_DS1307 rtc;

/*const int blue2 = 12;
const int blue1 = 11;
const int red1 = 10;
const int red2 = 9;
*/
Servo servo;



unsigned long counter;

unsigned long prevMillis = 0;

int piezoInterval = 200;

int drivingMode = 0;

boolean playPiezo=false;

#define trig 22
#define echo 24
long duration;
boolean turned150 = false;
int cm30, cm, cm150;
bool checkLeft = false;
boolean checkRight = false;
boolean mainPing = true;
unsigned long servoTimer = millis();

void setup(){


 servo.attach(12);
/* for(int i=0;i<sizeof(leds)/sizeof(leds[0]);i++){
    pinMode(leds[i], OUTPUT);
 }
*/
 Serial.begin(9600);

servo.write(90);
delay(200);
}

void loop(){

 counter=millis();
 //Serial.print("Millis1: ");
 //Serial.println(millis());
/* if(irrecv.decode(&results)){
    translateIR();
    irrecv.resume();
  }*/
//  Serial.print("Millis2: ");

if(drivingMode == 0){
   if(((counter-servoTimer) >= 150) && mainPing){
    ping();
    cm=duration/29.1/2;
    Serial.println(cm);
    counter=millis();
    servoTimer=counter;
  }
  if((cm<30) && mainPing){

    mainPing=false;
    checkRight = true;
    counter=millis();
    servoTimer=millis();
    servo.write(150);
    cm=30;


  }
  if(checkRight && !checkLeft && ((counter-servoTimer) >= 170)){

    ping();
    checkLeft=true;
    cm150 = duration/29.1/2;
    counter=millis();
    servoTimer=millis();
    servo.write(50);
  }
  if(checkRight && checkLeft && ((counter-servoTimer) >= 340)){
  checkRight=false;
  checkLeft=false;
  mainPing=true;
  ping();
  cm30 = duration/29.1/2;
  counter=millis();
  servoTimer=millis();
  servo.write(90);

  }

 }

//getTime();
//existsFire();
/*if(!manualLeds){
readPhoto();
}*/

delay(2);
}




//}
void ping(){

    digitalWrite(trig, LOW);
    delayMicroseconds(2);
    digitalWrite(trig, HIGH);
    delayMicroseconds(10);
    digitalWrite(trig, LOW);
    duration = pulseIn(echo, HIGH, 24000L);

}

Maybe this means that the issue is within this remaining code. Of course I will need all of the code that I removed for the final project, but I was just trying to debug.

I made my code a lot more concise since the posted code draft, but the ultrasonic sensor still gives me 0s. I do not understand what can affect its performance as it works fine in my other sketch.

I tried connecting the sensor to an external 5 volt power source and the same thing happened. The reason for the issue is not because if my power source.

I used to have a small delay at the end of my code and I removed that in order to make it run faster. Since pulseIn is blocking for 24ms, the delays do not affect it and it should work normally. But it does not.

Also, the sensor is giving 0s not because the target is too far away. Even if I put my hand close, it still gives 0s. If I make the cm equal 400 if the duration equals 0, the cm are always 400 regardless of the distance from the sensor.

9
  • There seems to be a lot going on in your full program, which can explain why it is slower. If you want to minimize the problem, avoid floating point and – most importantly – blocking calls. delay() is not the only blocking function: pulseIn() is also blocking, and Serial.print() becomes blocking is the output buffer fills up. Commented Aug 21, 2016 at 8:59
  • @EdgarBonet I cannot really avoid using pulseIn() - it is needed for the sensor. Even if I remove Serial.print(), it makes no difference to the servo and sensor.
    – shurup
    Commented Aug 21, 2016 at 12:25
  • I cannot really avoid using pulseIn() - Yes you can, easily. pulseIn is just a blocking way of measuring the time between two events. You could use interrupts and not block.
    – Nick Gammon
    Commented Aug 21, 2016 at 22:19
  • @NickGammon Ok. If this is the source of the issue, I guess I will change it. But I am not sure if it is. After I followed the suggestion below, the servos work, but the sensor still gives me 0s.
    – shurup
    Commented Aug 21, 2016 at 22:24
  • Well it sounds like you have more than one problem then. :)
    – Nick Gammon
    Commented Aug 22, 2016 at 5:30

3 Answers 3

1
+50

In the setup() function add a setPin(echo, INPUT) statement.

UPDATE

Have you checked the wiring? A loose connection of either the trig or echo pins would cause this behavior.

I know it might seem obvious, but double checking continuity between the Arduino pins and the HC-SR04 module with a basic multimeter (while your board is not powered) is not going to hurt, right?

3
  • Although it is often considered good practice to explicitly set the mode of every pin you use, here it doesn't make any difference, as all the pins are initialized to INPUT by the hardware. Commented Sep 8, 2016 at 7:22
  • You are right @EdgarBonet, default state for pins is INPUT, but he might have includes or other non displayed code which changes the pin state. Also the pulseIn(...) function should actually change the pinMode implicitly via the call to portInputRegister(...) contained inside it, but that depends on the version of Arduino libraries he is using... Commented Sep 8, 2016 at 9:54
  • Thank you for pointing out to me something so obvious. I indeed forgot to set the pinMode to INPUT for echo AND set it as OUTPUT for trig. The trig pinMode caused the issue I am guessing. I spend so much time trying to find a flaw and it was just one line of code.
    – shurup
    Commented Sep 13, 2016 at 0:49
3

pulseIn() may block up to 1 second (by default), which would happen everytime the HC-SR04 receives no echo, which might be the case if ultrasounds do not get properly reflected on a flat surface or if the nearest echoing surface is over ~4 meters away from it.

In this situation, not only would pulseIn block for one second, but it would also return 0 to indicate the pin never changed level during that time (which can explain the 0cm distance you calculated).

Since the HC-SR04 range is maximum 4 meters, the max ultrasound distance echoed should be then less than 8 meters. Under normal atmospheric conditions, sound propagates at ~340m/s, that means in the worst case, i.e. an obstacle found 4 meters away, the sound roundtrip should take less than 8/340s, i.e. ~24ms rounded up.

This shows it is pointless to have pulseIn wait for 1 second, where 24ms would be enough. To tell pulseIn to use a shorter timeout, just pass it an extra argument:

duration = pulseIn(echo, HIGH, 24000L);

Note that timeout must be expressed in us.

Then, in other parts of your code, before using duration, you should check that it is not 0 (which means no obstacle found less than 4 meters away), for example you might consider in this case the distance is 4 meters (or anything larger).

E.g. you could replace:

cm150 = duration/29.1/2;

with:

cm150 = duration == 0 ? 400 : duration/29.1/2;

Since this calculation is found several times you should probably create a function for it, that would improve code maintainability and maybe code size as well.

7
  • So you are saying that the HC-SR04 is sending me a 0 because of an uneven surface? I just tested it without servo rotation and commented everything extra out and it still gave me 0. When I tried running the same code in a separate sketch, the sensor gives me actual values. So I am still not sure why it is giving me 0s. The surface and distance are not the ones causing the issue. I also changed pulsein to 24000L. I saw no change with servo rotation.
    – shurup
    Commented Aug 21, 2016 at 18:21
  • Never mind, the servos rotate normally now after I added 24000L. The sensor still does not work.
    – shurup
    Commented Aug 22, 2016 at 11:36
  • You may have a voltage drop issue (this happened to me in the past, due to the number of devices you are driving. Did you use decoupling caps for each device?
    – jfpoilpret
    Commented Aug 22, 2016 at 11:39
  • It is possible. When I removed all the code for those devices, it still gave me 0. Those devices were still connected up though. They were also connected up when I uploaded the first sketch and everything worked. I am using capacitors.
    – shurup
    Commented Aug 22, 2016 at 22:25
  • It is hard to tell, without seeing your wiring. If you have an oscillograph, then you can check voltage of HC-SR04 power pins and see if it's stable. If you don't, just add a 10uF cap as near the HC-SR04 as possible.
    – jfpoilpret
    Commented Aug 23, 2016 at 4:36
2

Why does the same block of code act differently in different sketches?

There are different interrupt sources in the sketches that may affect pulseIn(). Try using a more advanced method to measure the pulse width such as Timer Capture.

Cheers!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.