LOPY HC-SR04 Adaptation



  • Hi

    I'm trying to adapt the HC-SR04 library to Lopy but for some reason it just get stuck when reading the Echo pin like never seeing the Pulse
    the code is based on micropython lib
    https://github.com/mithru/MicroPython-Examples/tree/master/08.Sensors/HC-SR04

    Class

    import machine
    from machine import Timer
    
    # Pin configuration.
    
    
    class Ultrasonic:
        def __init__(self, tPin, ePin):
            self.triggerPin = tPin
            self.echoPin = ePin
    
            # Init trigger pin (out)
            self.trigger = machine.Pin(self.triggerPin)
            self.trigger.init(machine.Pin.OUT)
            self.trigger.value(False)
    
            # Init echo pin (in)
            self.echo = machine.Pin(self.echoPin)
            self.echo.init(machine.Pin.IN)
    
        def distance_in_inches(self):
            return (self.distance_in_cm() * 0.3937)
    
        def distance_in_cm(self):
            start = 0
            end = 0
    
            # Create a microseconds counter.
            micros = Timer.Chrono()
            micros.reset()
    
            # Send a 10us pulse.
            self.trigger.value(True)
            Timer.sleep_us(10)
            self.trigger.value(False)
    
            # Wait 'till whe pulse starts.
            while self.echo.value() == 0:
                start = micros.read_us()
    
            # Wait 'till the pulse is gone.
            while self.echo.value() == 1:
                end = micros.read_us()
    
            # Deinit the microseconds counter
            micros.stop()
    
            # Calc the duration of the recieved pulse, divide the result by
            # 2 (round-trip) and divide it by 29 (the speed of sound is
            # 340 m/s and that is 29 us/cm).
            dist_in_cm = ((end - start) / 2) / 29
    
            return dist_in_cm
    

    Program

    from machine import Pin
    import time
    import Ultrasonic
    
     sensor1_trigPin = "P20"
     sensor1_echoPin = "P19"
    
    sensor1=Ultrasonic.Ultrasonic(sensor1_trigPin, sensor1_echoPin)
    distance1 = sensor1.distance_in_cm()
    
    


  • @robert-hh Pick it apart :).



  • @papasmurph Yes. I looked into an older data sheet. According to this one, there are variants with embedded flash, internally connected to the SPI controller. So timingwise it behaves like external flash.
    The model with the number ESP32-D2WD has 16 MBit embedded flash. D/K which one is in the pycom devices. Probably the ones w/o internal flash.



  • @robert-hh The datasheet at https://espressif.com/sites/default/files/documentation/esp32_datasheet_en.pdf is not very clear about how Flash is addressed, but there's some Flash.



  • @papasmurph There is no internal flash in the esp32. The external flash is partiallyx memory-mapped, so it looks like internal memory.



  • @robert-hh I thought at least internal Flash was directly addressed. I'm aware external Flash is not. Anyway, I made an implementation using this sensor that works rather well, but not with the precision/stability of the Arduino implementation. I can provide the source if anyone's interested.



  • @papasmurph This is a software problem, but somewhere deep buried into the esp-idf. The largest problem is caching of code in flash. The esp cannot execude code from flash. If a section of code is requested, which is not cached, this has to be tranferred into RAM. That causes a latency of typically 300 µs. And as far as I have been told, there is no mechanism to make some code areas sticky. Even if the python scipts themselves are located in RAM, the runtime engine is in flash, as well as other firmware sections. To some extend you could still determine pulse lengths. Look in the board for the DHT11 driver. That's on the level of this Arduino code.



  • @papasmurph The principle used in the Arduino is quite different. Can the ESP32 (via Python) support the same as pulseIn? I couldn't see any such link between ports and timers.

    Somewhat truncated code:

    // Port configuration
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    
    // Trigger distance sensor (Trig)
    digitalWrite(trigPin, LOW);
    delayMicroseconds(2);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    
    // Read distance pulse (Echo)
    duration = (float)pulseIn(echoPin, HIGH) / Million;
    


  • @robert-hh But at least it looks like a software problem (potentially solvable via a different approach to handling queueing of events?).



  • @papasmurph About hardware interrupt latency with this MP port, look here: https://forum.pycom.io/topic/936/pin-interrupt-latency



  • @slagter Late response, but anyway: A code example I found for Arduino uses a hardware triggered timer to get the time between trig and echo. Can't the ESP32 do the same thing?



  • @gas The other problem is reliable timing, which does not exist on the esp32 or esp8266. At and between every Python statement you may have an extra ~300µs delay due to cache misses.



  • Hi Gas,

    Couple of things that need fixing:

    1. You have to start the Chrono. Insert a "micros.start()" in the Ultrasonic class, just after micros.reset()
    2. Define the pull mode as part of the init of the Pin In and Pin Out: self.trigger.init(machine.Pin.OUT, None)
    3. I would define the pins in the start as: sensor_trigPin = Pin("G16")

    Kind regards,
    Robert


Log in to reply
 

Pycom on Twitter