RobTillaart / SRF05

Arduino library for SRF05 distance sensor
MIT License
7 stars 1 forks source link

Limited range on ATTiny85 #6

Closed MyVanitar closed 2 years ago

MyVanitar commented 2 years ago

Hello,

I used this library on ATTiny85 MCU. I use ATTinyCore board manager. The best performance is up to 70cm, and with many fluctuations up to 100cm. I think it is the timing issue. Could you please investigate? The clock is 8MHz, internal.

MyVanitar commented 2 years ago

Please follow the picture (Tiny85-No bootloader, 8MHz Internal) and you can simply program the chip using the Arduino generated HEX file.

2022-03-21_16-52-02

RobTillaart commented 2 years ago

The code uses pulseIn() to determine the distance. This is an Arduino library function which is limited in accuracy. As the clock of your board 8Mhz, the accuracy is I think 8 us at best (If there are no other interrupts etc)

and with many fluctuations up to 100cm

For that reason I added different reading modes which takes the median or average of multiple samples. That improves the accuracy. Which mode to use depends on the amount of noise in your system.

In most cases the average mode with 4 or 8 samples will work, otherwise you might increase the number of samples used of use the median mode. This latter mode just selects the middle sample when you sort them in size. The advantage is that outliers are ignored, drawback is that is takes more CPU cycles. The number of samples for median is ideally an odd number (5,7,9 ..) .

MyVanitar commented 2 years ago

My main problem is not the fluctuations, however the range is very limited. The fluctuation happens near the maximum range, however in my case the range does not go higher than 100cm.

if you think the 8MHz clock is the cause of the problem, I can increase it to 20MHz external to see what happens, however the problem is that the pins are limited and used by the SRF05 module itself.

RobTillaart commented 2 years ago

I need to install ATTINY boards to investigate how the pulsein() function looks like.

MyVanitar commented 2 years ago

I need to install ATTINY boards to investigate how the pulsein() function looks like.

You just need to have one ATTiny85 chip and an AVR programmer (such as USBasp) to check this. By the way, I have also tested this using the NewPing library, and the problem happened there also. The detection range was limited.

RobTillaart commented 2 years ago

I don't have a tiny85 around.

RobTillaart commented 2 years ago
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout)
{
    // cache the port and bit of the pin in order to speed up the
    // pulse width measuring loop and achieve finer resolution.  calling
    // digitalRead() instead yields much coarser resolution.
    uint8_t bit = digitalPinToBitMask(pin);
    uint8_t port = digitalPinToPort(pin);
    uint8_t stateMask = (state ? bit : 0);

    // convert the timeout from microseconds to a number of times through
    // the initial loop; it takes approximately 16 clock cycles per iteration
    unsigned long maxloops = microsecondsToClockCycles(timeout)/16;

    unsigned long width = countPulseASM(portInputRegister(port), bit, stateMask, maxloops);

    // prevent clockCyclesToMicroseconds to return bogus values if countPulseASM timed out
    if (width)
        return clockCyclesToMicroseconds(width * 16 + 16);
    else
        return 0;
}

The pulseIn() calls an assembly routine countPulseASM() which is register optimized for AVR

From the library the "C code equivalent"

unsigned long pulseInSimpl(volatile uint8_t *port, uint8_t bit, uint8_t stateMask, unsigned long maxloops)
{
     unsigned long width = 0;
     // wait for any previous pulse to end
     while ((*port & bit) == stateMask)
         if (--maxloops == 0)
             return 0;

     // wait for the pulse to start
     while ((*port & bit) != stateMask)
         if (--maxloops == 0)
             return 0;

     // wait for the pulse to stop
     while ((*port & bit) == stateMask) {
         if (++width == maxloops)
             return 0;
     }
     return width;
 }

Code wise it will be very hard or impossible to optimize this code. The good news is that it could measure with a higher accuracy than I expected, probably 2 us .

As the speed of sound is ~340.000 mm per second 0.34 mm per microsecond. So the ultimate accuracy could in theory be around 1 mm. In practice this is not feasible.


Inaccuracy for longer times can come from interrupts that occur during the pulseIn()

So is your code using interrupts?

MyVanitar commented 2 years ago

So is your code using interrupts?

Well, No, I just have one SSD1306 I2C LED module connected. I'm not sure if that causes this. I try to port it with a different library. What I use now is Tiny4kOLED

RobTillaart commented 2 years ago

I assume you do not write to the display in the background so that should not cause interrupts.

RobTillaart commented 2 years ago

By the way, I have also tested this using the NewPing library, and the problem happened there also. The detection range was limited.

What does the datasheet of the SRF tell about range etc?

MyVanitar commented 2 years ago

I assume you do not write to the display in the background so that should not cause interrupts.

The code is very simple. This is the loop, apart from this is just initialization.

void loop() {  
  oled.setCursor(0, 2);
  oled.print(SRF.getCentimeter(), 1);
  oled.setCursor(0, 4);
  oled.print(SRF.getInch());
  delay(100);
}

What does the datasheet of the SRF tell about range etc?

it is the SRF05 module Sensor. it says up to 450cm. The module might be bad? I'm not sure really!

RobTillaart commented 2 years ago

The module might be bad?

That is an option, you can do some simple testing e.g 10 20 30 40 50 cm and how accurate it measures them and where it stops measuring.

MyVanitar commented 2 years ago

The module might be bad?

That is an option, you can do some simple testing e.g 10 20 30 40 50 cm and how accurate it measures them and where it stops measuring.

it is good up to 70cm and accurate, after that it sucks.

RobTillaart commented 2 years ago

70 cm is definitely not 450 cm..

Can you try the sensor with an UNO or ESP32?
If these give a similar (too) short range it would point towards the sensor.

RobTillaart commented 2 years ago

A SRF has a PIC microprocessor on it. 5 pins on the board are to program it (not disclosed how). An option is that the code of the PIC is corrupted.

RobTillaart commented 2 years ago

The library has this line uint32_t duration = pulseIn(_echo, HIGH, 300000); so it measures at most 300.000 us = 0.3 seconds that is equivalent to ~100 meters...

So library is not limiting on distance.

MyVanitar commented 2 years ago

I tested the SRF05 module with Arduino-UNO board and it works as expected.

RobTillaart commented 2 years ago

If the UNO with SRF works ok, it is the tiny85 (compiler?)

some thoughts:

MyVanitar commented 2 years ago

I got tired of this since this is either the compiler problem or the unknown chip limitations. Arduino is not a stable platform to count on it for all scenarios. the freeRam() shows 369 as return. I can not use an external crystal on the pins since they are already equipped.

RobTillaart commented 2 years ago

Ok, RAM seems to be no limitation.

You might ask the question on the Arduino forum. There are definitely people with more tiny specific experience than I have. If you do and get some good cause analysis ir even a solution please let me know as it might help to improve the library in the future.