Two sensors HC-SR04 with different behaviors

I have a robot car which uses an HC-SR04 sensor in two functions. Now, the first sensor works fine in both functions. When I replace the sensor with the other one, it works in one function but not in the other?

It is on a Arduino Nano and I do not use a library for the sensors but wrote my own function. Both earlier mentioned functions use the same function for measuring the distance.

the red wire of the second sensor is loose (may be)

joke aside, show us the circuit, the code, what you tested etc...

2 Likes

Define "works" and "not" in all cases.

1 Like

Post a schematic showing what you have and how it is wired. Be sure to include all hardware items.

As others have suggested, you didn't post enough information for the forum to be helpful.

I will say, these devices HC-SR04 are not high cost precision devices. Variations in the sensors, either in construction or direction on the board could cause variations. I would take a good look at the two sensors side by side to see if there are any visible differences.

You have two HC-SR04, one in the front and one in the back. You do not have one HC-SR04 in two functions. Removing one HC-SR04 does not make the other HC-SR04 do the sensing of the second sensor..

The code is listed below. More information about the project is on Codewerkplaats Les 6 (LED-strip en lijnvolger) – CodeKids.
The project uses one ultrasonic sensor. The sensors we tested are from different batches. In the function functieModeUltrasoon() both sensors work. In the function functieModeLijnvolger() only one of the sensors work. When I disable the linesensors the 'bad' sensor still does not work (so there seems not to be any interference between the sensors)

Thanks for everyones help!

// Versie 2024-04-09_1600
// Dit is de code die we gaan gebruiken bij de Codewerkplaats op 12-4-2024
// Geschreven door Chris Dorna, met dank aan Paul van Deelen die me hielp
// bij het oplossen van het probleem dat de rechter motor niet meer bestuurd
// kon worden als de bibliotheek IRremote werd gebruikt.

#include <L298N.h>  // We gebruiken de library L298N voor de motordriver
// Dit programma is getest met versie 2.0.3 van deze bibliotheek

#include <IRremote.hpp>  // We gebruiken de library IRremote voor de afstandsbediening
// Dit programma is getest met versie 4.3.0 van deze bibliotheek
unsigned long ontvangenCode;  // Variabele om code uit afstandsbediening in op te slaan
int gemetenAfstand = 0;       // Wordt gebruikt om de afstand in op te slaan

#include <Adafruit_NeoPixel.h>  // Bibliotheek voor aansturen LED-strip
// Dit programma is getest met versie 1.12.0 van deze bibliotheek
Adafruit_NeoPixel ledstrip = Adafruit_NeoPixel(8, 12);  // 8 pixels op pin 12
unsigned long huidigeMillis = 0;                        // Om huidige tijd op te slaan
unsigned long vorigeMillis = 0;                         // Om laatste tijd op te slaan dat de LED werd bijgewerkt
int currentPixel = 0;                                   // Houdt bij welke pixel momenteel is bijgewerkt
int ledstripPatroon = 1;

#define pinLampRechts 6    // Nummer van de pin waarop de koplamp rechts is aangesloten
#define pinLampLinks 7     // Nummer van de pin waarop de koplamp links is aangesloten
#define pinZoemer 8        // Nummer van de pin waarop de zoemer is aangesloten
#define pinSensorLinks 14  // Pinnen van de lijnvolgers
#define pinSensorRechts 15

// Maak L298N-object voor de rechter motor
L298N motorRechts(5, 4, 3);  // ENA, IN1, IN2
// Draad van pin 3 naar IN2 is bruin
// Draad van pin 4 naar IN1 is rood
// Draad van pin 5 naar ENA is bruin

// Maak L298N-object voor de linker motor
L298N motorLinks(9, 10, 11);  // ENB, IN3, IN4
// Draad van pin  9 naar ENB is bruin
// Draad van pin 10 naar IN4 is rood
// Draad van pin 11 naar IN3 is oranje

boolean modeUltrasoon = false;   // Variabele om aan te geven of robotkarretje
                                 // in de mode 'Ultrasoon' moet werken
boolean modeLijnvolger = false;  // Variabele om aan te geven of robotkarretje
                                 //in de mode 'Lijnvolger moet werken

int basissnelheidLinks;   // omdat de motoren niet allemaal even snel draaien
int basissnelheidRechts;  // slaan we de basissnelheid op in deze variabelen
int snelheidLinks;        // Variabelen om actuele snelheid van de motoren in
int snelheidRechts;       // op te slaan


void setup() {
  pinMode(13, OUTPUT);  // LED op de Arduino
  digitalWrite(13, HIGH);
  delay(1000);
  digitalWrite(13, LOW);
  pinMode(pinLampRechts, OUTPUT);
  pinMode(pinLampLinks, OUTPUT);
  Serial.begin(9600);  // Hiermee kunnen we informatie van de Arduino naar de laptop sturen.
                       // Dit is handig om fouten in het programma op te sporen
  Serial.println("Communicatie tussen Arduino en Serial Monitor van IDE gestart");

  IrReceiver.begin(2);                // Start IR-ontvanger (aangesloten op pin 2)
  digitalWrite(pinLampRechts, HIGH);  // Koplamp Rechts AAN
  digitalWrite(pinLampLinks, HIGH);   // Koplamp Links AAN

  basissnelheidLinks = 125;   // pas één van deze twee aan als een motor sneller
  basissnelheidRechts = 125;  // draait als de andere
  snelheidLinks = basissnelheidLinks;
  snelheidRechts = basissnelheidRechts;
  motorLinks.setSpeed(snelheidLinks);  // Instellen snelheid (kan van 0 tot 255)
  motorRechts.setSpeed(snelheidRechts);

  ledstrip.begin();
}

void loop() {

  if (IrReceiver.decode()) {  // Kijken of we een IR-signaal hebben ontvangen
    ontvangenCode = IrReceiver.decodedIRData.decodedRawData;
    Serial.println("--------------------");  // Stuur informatie naar de laptop,
    Serial.print("DEC: ");                   // dit werkt alleen als de USB-kabel is aangesloten
    Serial.println(ontvangenCode);           //
    if (ontvangenCode != 0) {                // != betekent NIET gelijk
      switch (ontvangenCode) {
        case 3125149440:  // Knop CH- [ULTRASOON]
          Serial.println("*** Knop CH- ***");
          modeUltrasoon = true;  // Hiermee zet je de robot in de stand 'Ultrasoon'
          modeLijnvolger = false;
          break;
        case 3108437760:  // Knop CH [LIJNVOLGER]
          Serial.println("*** Knop CH ***");
          modeLijnvolger = true;  // Hiermee zet je de robot in de stand 'Lijnvolger'
          modeUltrasoon = false;
          break;
        case 3091726080:  // Knop CH+ [Geluid afspelen]
          Serial.println("*** Knop CH+ ***");
          functieSpeelToon(pinZoemer, 500, 100);   // 500 Hz 500 ms
          functieSpeelToon(pinZoemer, 750, 100);   // 750 Hz 500 ms
          functieSpeelToon(pinZoemer, 1000, 100);  // 500 Hz 500 ms
          functieSpeelToon(pinZoemer, 1250, 100);  // 750 Hz 500 ms
          break;
        case 4077715200:  // Knop 1
          Serial.println("*** Knop 1 ***");
          break;
        case 3877175040:  // Knop 2 [RECHTDOOR]
          Serial.println("*** Knop 2 [RECHTDOOR)] ***");
          modeUltrasoon = false;
          modeLijnvolger = false;
          motorLinks.forward();   // vooruit
          motorRechts.forward();  // vooruit
          break;
        case 2707357440:  // Knop 3
          Serial.println("*** Knop 3 ***");
          break;
        case 4144561920:  // Knop 4 [LINKS]
          Serial.println("*** Knop 4 [LINKS] ***");
          modeUltrasoon = false;
          modeLijnvolger = false;
          motorLinks.stop();
          motorRechts.forward();  // vooruit
          break;
        case 3810328320:  // Knop 5 [STOP en RESET]
          Serial.println("*** Knop 5 [STOP en RESET] ***");
          modeUltrasoon = false;
          modeLijnvolger = false;
          motorLinks.stop();                   // stop
          motorRechts.stop();                  // stop
          snelheidLinks = basissnelheidLinks;  // terug naar de basissnelheid
          snelheidRechts = basissnelheidRechts;
          break;
        case 2774204160:  // Knop 6 [RECHTS]
          Serial.println("*** Knop 6 [RECHTS] ***");
          modeUltrasoon = false;
          modeLijnvolger = false;
          motorLinks.forward();  // vooruit
          motorRechts.stop();
          break;
        case 3175284480:  //Knop 7
          Serial.println("*** Knop 7 ***");
          break;
        case 2907897600:  //Knop 8 [ACHTERUIT]
          Serial.println("*** Knop 8 [ACHTERUIT] ***");
          modeUltrasoon = false;
          modeLijnvolger = false;
          motorLinks.backward();   // achteruit
          motorRechts.backward();  // achteruit
          break;
        case 3041591040:  //Knop 9
          Serial.println("*** Knop 9 ***");
          break;
        case 3910598400:  //knop 0
          Serial.println("*** Knop 0 ***");
          break;
        case 4127850240:  // Knop EQ [LAMPEN AAN/UIT]
          Serial.println("*** Knop EQ ***");
          // Als de koplampen AAN zijn, gaan ze UIT en andersom
          // Eerder hebben we tegen de Arduino gezegd dat de pinnen 6
          // (pinLampLinks) en 7 (pinLampRechts) worden gebruikt als OUTPUT.
          // met de digitalRead() hieronder kijken we of de lamp AAN of
          // UIT is. Met het uitroepteken geef je aan dat de waarde moet
          // worden omgekeerd.
          // Deze 'omkeertruc'is getest op een Arduino Nano
          digitalWrite(pinLampRechts, !digitalRead(pinLampRechts));  // Koplamp Rechts
          digitalWrite(pinLampLinks, !digitalRead(pinLampLinks));    // Koplamp Links
          break;
        case 4161273600:  // knop MIN [GA LANGZAMER]
          Serial.println("*** Knop MIN ***");
          Serial.print("Snelheid Links: ");
          Serial.println(snelheidLinks);
          Serial.print("Snelheid Rechts: ");
          Serial.println(snelheidRechts);
          if (snelheidLinks > 25) {
            snelheidLinks = snelheidLinks - 25;
            motorLinks.setSpeed(snelheidLinks);  // Instellen snelheid
            motorRechts.setSpeed(snelheidRechts);
            motorLinks.forward();   // De nieuwe snelheid wordt pas gebruikt
            motorRechts.forward();  // als je opnieuw een opdracht geeft
          }
          break;
        case 3927310080:  // knop PLUS [GA SNELLER]
          Serial.println("*** Knop PLUS ***");
          Serial.print("Snelheid Links: ");
          Serial.println(snelheidLinks);
          Serial.print("Snelheid Rechts: ");
          Serial.println(snelheidRechts);
          if (snelheidLinks < 225) {
            snelheidLinks = snelheidLinks + 25;
            snelheidRechts = snelheidRechts + 25;
            motorLinks.setSpeed(snelheidLinks);  // Instellen snelheid
            motorRechts.setSpeed(snelheidRechts);
            motorLinks.forward();   // De nieuwe snelheid wordt pas gebruikt
            motorRechts.forward();  // als je opnieuw een opdracht geeft
          }
          break;
        case 3158572800:  // knop >|| [LEDSTRIP]
          Serial.println("*** knop >|| ***");
          ledstripPatroon = ledstripPatroon + 1;
          if (ledstripPatroon > 3) {
            ledstripPatroon = 0;
          }
          Serial.print("Patroon: ");
          Serial.println(ledstripPatroon);
          break;
      }
    }
    IrReceiver.resume();  // IrReceiver weer starten
                          //(deze stopt nadat deze een code heeft ontvangen)
  }

  functieLedstrip(ledstripPatroon);  // Laat gekozen patroon zien

  if (modeUltrasoon == true) {
    functieUltrasoon();  // Naar de mode 'Ultrasoon'
  }
  if (modeLijnvolger == true) {
    functieLijnvolger(); // Naar de mode 'Lijnvolger'
  }
}

void functieUltrasoon() {
  // We beginnen met het meten we de afstand en zetten deze in
  // de variabele gemetenAfstand.
  gemetenAfstand = functieMeetAfstand(16, 17, 40);
  // pin Trigger = 16
  // pin Echo = 17
  // Maximale afstand = 40
  if (gemetenAfstand > 0 && gemetenAfstand < 10) {
    // De gemeten afstand is kleiner dan 10 cm
    // - De twee is gelijk tekens '==' geven aan dat er twee dingen met
    //   elkaar worden vergeleken.
    // - De twee rechte streepjes '&&', geven EN aan.
    functieSpeelToon(pinZoemer, 1000, 500);  // Laat een toon horen (1000 Hz, 500 ms)
    digitalWrite(13, HIGH);                  // LED op Arduino AAN
    motorLinks.stop();                       // motor eerst stoppen vóór je richting omkeert
    motorRechts.stop();                      // motor eerst stoppen vóór je richting omkeert
    motorLinks.backward();                   // achteruit
    motorRechts.backward();                  // achteruit
    delay(500);
    motorLinks.stop();
    delay(500);
    motorRechts.stop();
  } else {
    // De gemeten afstand is groter dan 10 cm
    digitalWrite(13, LOW);  // LED op Arduino UIT
    motorLinks.forward();   // vooruit
    motorRechts.forward();  // vooruit
  }
}

void functieLijnvolger() {
  if ((digitalRead(pinSensorLinks) == LOW) && (digitalRead(pinSensorRechts) == LOW)) {
    Serial.println("RECHTDOOR");
    // Beide sensors zien zwart (ga rechtdoor)
    gemetenAfstand = functieMeetAfstand(16, 17, 40);  // Maar we kijken wel eerst of er niets
                                                      // in de weg staat. In de functie
                                                      // functieMeetAfstand() staat hoe dit werkt.
    if (gemetenAfstand > 0 && gemetenAfstand < 10) {
      motorLinks.stop();                       // stop
      motorRechts.stop();                      // stop
      functieSpeelToon(pinZoemer, 1000, 200);  // Laat een toon horen (1000 Hz, 200 ms)
    } else {
      motorLinks.forward();   // vooruit
      motorRechts.forward();  // vooruit
    }
  } else if ((digitalRead(pinSensorLinks) == HIGH) && (digitalRead(pinSensorRechts) == HIGH)) {
    Serial.println("ACHTERUIT");
    //Beide sensors zien wit (ga achteruit)
    motorLinks.backward();   // achteruit
    motorRechts.backward();  // achteruit
  } else if (digitalRead(pinSensorLinks) == HIGH) {
    Serial.println("NAAR RECHTS");
    // Links ziet geen zwarte lijn (ga naar rechts)
    motorLinks.forward();  // vooruit
    motorRechts.stop();    // stop
  } else if (digitalRead(pinSensorRechts) == HIGH) {
    Serial.println("NAAR LINKS");
    //Rechts ziet geen zwarte lijn (ga naar links)
    motorLinks.stop();      // stop
    motorRechts.forward();  // vooruit
  }
}

void functieLedstrip(int patroon) {
  huidigeMillis = millis();                   // Hebben we nodig om tijd vast te leggen
  if (huidigeMillis - vorigeMillis >= 100) {  // 100 milliseconde
    vorigeMillis = huidigeMillis;             // Sla de laatste update tijd op

    // Hieronder stel je bij ledstrip.Color met de laatste drie getallen de kleur in
    // (rood, groen, blauw)
    // Deze kan je een waarde geven tussen 0 en 255

    // Er zitten 8 ledstrip op de strip, deze hebben in het programma de nummers
    // 0, 1, 2, 3, 4, 5, 6, 7
    switch (patroon) {
      // Hier worden de verschillende patronen klaargezet, maar nog niet getoond
      case 0:  // Alle LED's uit
        ledstrip.clear();
        break;
      case 1:  // Opbouwende lichtbalk
        ledstrip.setPixelColor(currentPixel, ledstrip.Color(100, 0, 0));
        currentPixel = currentPixel + 1;
        if (currentPixel >= 9) {
          currentPixel = 0;  // Begin opnieuw bij de eerste pixel
          ledstrip.clear();  // Zet alle pixels uit
        }
        break;
      case 2:              // Lopende led
        ledstrip.clear();  // Zet alle pixels uit
        ledstrip.setPixelColor(currentPixel, ledstrip.Color(100, 0, 0));
        currentPixel = currentPixel + 1;
        if (currentPixel >= 9) {
          currentPixel = 0;  // Begin opnieuw bij de eerste pixel
        }
        break;
      case 3:  // Van binnen naar buiten
        if (currentPixel == 1) {
          ledstrip.setPixelColor(3, ledstrip.Color(0, 50, 0));
          ledstrip.setPixelColor(4, ledstrip.Color(0, 50, 0));
        }
        if (currentPixel == 2) {
          ledstrip.setPixelColor(2, ledstrip.Color(0, 50, 0));
          ledstrip.setPixelColor(5, ledstrip.Color(0, 50, 0));
        }
        if (currentPixel == 3) {
          ledstrip.setPixelColor(1, ledstrip.Color(0, 50, 0));
          ledstrip.setPixelColor(6, ledstrip.Color(0, 50, 0));
        }
        if (currentPixel == 4) {
          ledstrip.setPixelColor(0, ledstrip.Color(0, 50, 0));
          ledstrip.setPixelColor(7, ledstrip.Color(0, 50, 0));
        }
        ledstrip.show();
        currentPixel = currentPixel + 1;
        if (currentPixel >= 8) {
          currentPixel = 0;  // Begin opnieuw bij de eerste pixel
          ledstrip.clear();  // Zet alle pixels uit
        }
        break;
    }
    ledstrip.show();  // Laat het patroon zien
  }
}

int functieMeetAfstand(int pinTrigger, int pinEcho, int maxAfstand) {
  // Deze functie bepaalt de afstand tussen de ultrasoonsensor en een
  // obstakel.
  // In de Codewerkplaats gaan we niet uitleggen hoe dit werkt en het advies
  // is om niet te gaan sleutelen aan deze code.

  // Bereken de maximale wachttijd op basis van de maximale afstand
  unsigned long maxDuur = (maxAfstand * 2 * 1000000L) / 34300;  // in microseconden

  // Zorg dat de triggerPin laag is en wacht voor stabiliteit
  pinMode(pinTrigger, OUTPUT);
  digitalWrite(pinTrigger, LOW);
  delayMicroseconds(2);

  // Genereer een korte ultrasone puls
  digitalWrite(pinTrigger, HIGH);
  delayMicroseconds(10);  // Ultrasone puls duurt 10 microseconden
  digitalWrite(pinTrigger, LOW);

  // Zet echoPin als INPUT nadat de puls is verzonden
  pinMode(pinEcho, INPUT);

  // Meet de duur van de teruggekeerde echo pulse met een time-out op basis van de maximale afstand
  long duur = pulseIn(pinEcho, HIGH, maxDuur);

  if (duur == 0) {
    // Als er geen echo is gedetecteerd binnen de time-out, geef -1 terug
    return -1;
  }

  // Bereken de afstand gebaseerd op de duur van de echo
  int afstand = duur * 0.0343 / 2;

  return afstand;  // Geef de gemeten afstand terug
}

void functieSpeelToon(uint8_t pin, unsigned long frequentie, unsigned int duur) {
  // Deze functie is gebaseerd op de bibliotheek TimerFreeTone van Tim Eckel
  // (https://bitbucket.org/teckel12/arduino-timer-free-tone/wiki/Home)
  // Samen met ChatGPT is de code aangepast voor de Codewerkplaats
  // In de Codewerkplaats gaan we niet uitleggen hoe dit werkt en het advies
  // is om niet te gaan sleutelen aan deze code

  frequentie = 500000 / frequentie;  // Bereken de helft van de periode van de vierkante golf (in microseconden).

  // Zet pin in uitgangsmodus.
  uint8_t pinBit = digitalPinToBitMask(pin);
  volatile uint8_t *pinOutput = (uint8_t *)portOutputRegister(digitalPinToPort(pin));
  *(uint8_t *)portModeRegister(digitalPinToPort(pin)) |= pinBit;

  uint32_t startTime = millis();         // Begintijd van de noot.
  while (millis() - startTime < duur) {  // Lus voor de duur.
    *pinOutput |= pinBit;                // Zet pin hoog.
    delayMicroseconds(frequentie);       // Duur van vierkante golf (hoe lang de pin hoog blijven).
    *pinOutput &= ~pinBit;               // Zet pin laag.
    delayMicroseconds(frequentie);       // Duur van vierkante golf (hoe lang de pin laag blijven).
  }
}

can you check the sensors individually outside your code and your current circuit, for example with a straightforward connection and example code from the NewPing library?
are they behaving exactly the same way, providing distances that are coherent?

PS: some functions would need better attention to types
for example this would be better written

long functieMeetAfstand(const byte pinTrigger, const byte  pinEcho, unsigned long maxAfstand) {
  // Deze functie bepaalt de afstand tussen de ultrasoonsensor en een
  // obstakel.
  // In de Codewerkplaats gaan we niet uitleggen hoe dit werkt en het advies
  // is om niet te gaan sleutelen aan deze code.

  // Bereken de maximale wachttijd op basis van de maximale afstand
  unsigned long maxDuur = (maxAfstand * 2UL * 1000000UL) / 34300UL; // in microseconden

  // Zorg dat de triggerPin laag is en wacht voor stabiliteit
  pinMode(pinTrigger, OUTPUT);
  digitalWrite(pinTrigger, LOW);
  delayMicroseconds(2);

  // Genereer een korte ultrasone puls
  digitalWrite(pinTrigger, HIGH);
  delayMicroseconds(10);  // Ultrasone puls duurt 10 microseconden
  digitalWrite(pinTrigger, LOW);

  // Zet echoPin als INPUT nadat de puls is verzonden
  pinMode(pinEcho, INPUT);

  // Meet de duur van de teruggekeerde echo pulse met een time-out op basis van de maximale afstand
  unsigned long duur = pulseIn(pinEcho, HIGH, maxDuur);

  if (duur == 0) return -1; // Als er geen echo is gedetecteerd binnen de time-out, geef -1 terug
    
  // Bereken de afstand gebaseerd op de duur van de echo
  return duur * 0.0343 / 2;  // Geef de gemeten afstand terug
}

Thanks for your suggestions. Since this is an 'ongoing' project we will check the declarations.

I used a microscope to check the resistor values (capacitors are unmarked) on the two sensors, and I found significant differences.

On Sensor Wiki: KY-050 / HC-SR04 Ultrasonic Sensor - The Geek Pub I found this diagram:


Most of the values of the resistors on the working module correspond with values in the diagram. On the not-working module some values are significantly different:

Can the different behavior in the two functions functieModeUltrasoon() and functieModeLijnvolger() be explained by the differences in the values of the resistors (and probably different electronic behavior?

case 3125149440

This line is not the cause of any errors, but reflects the state of the sketch. The comments are voluminous to the point of hiding the code, but the sketch randomly uses uncommented hardcoding and variables.

Make the comments visually separate from the code, and use descriptive words for discrete values. This will go a long way to learning why your project is not operating as desired.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.