Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting data rate doesn't work on ESP32 #30

Closed
krishnak opened this issue Sep 27, 2022 · 26 comments
Closed

Setting data rate doesn't work on ESP32 #30

krishnak opened this issue Sep 27, 2022 · 26 comments

Comments

@krishnak
Copy link

#print(w0.config('rate'))
w0.config(rate=41) 

gives


Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "esp_sender.py", line 37, in <module>
ValueError: unknown config param
@krishnak
Copy link
Author

There is no implementation in esp_espnow.c

#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
    // Return the value of the requested parameter
    uintptr_t name = (uintptr_t)args[ARG_get].u_obj;
    if (name == QS(MP_QSTR_buffer)) {
        return mp_obj_new_int(self->recv_buffer_size);
    } else if (name == QS(MP_QSTR_timeout)) {
        return mp_obj_new_int(self->recv_timeout_ms);
    } else {
        mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
    }
#undef QS

@krishnak
Copy link
Author

krishnak commented Sep 27, 2022

From the ESP-IDF example I found here, it appears that the build project needs to be set with some configuration, I am not sure how this is handled in this micropython setup.

On a separate note, I tested the long range mode as described in the ESP-IDF example, I would say that it is pretty disappointing, a device just operating on micropython without long range mode and the ESP-IDF with long range mode - more or less have the same coverage. i.e with brick walls and concrete floors, just with the on board antenna i covers approximately 15 ft with the micropython code, the ESP NOW long range example is no different in range - unless there is something terribly iwrong with the code or the board.

@glenn20
Copy link
Owner

glenn20 commented Sep 28, 2022

#print(w0.config('rate'))
w0.config(rate=41) 

gives


Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "esp_sender.py", line 37, in <module>
ValueError: unknown config param

The 'rate' config option is available in the PR for IDF versions above 4.3.0 (see esp_now.c). The necessary functionality is only available for IDF > 4.3.0. However, generic ESP32 images are still built with idf 4.2.2 by default due to some memory fragmentation issues (the esp32[cs][0-9] images are built with idf 4.4 as they need the newer IDF versions.) Soooo, my pre-compiled images for generic ESP32 lack 'rate' support.

You can compile your own image using IDF 4.3+ and it'll probably be absolutely fine (eg. I do all my dev on 4.4), but there are known to be issues which may affect some people. I'll think about making some 4.4 images available when I do my next build (probably after 1.20 comes out).

@glenn20
Copy link
Owner

glenn20 commented Sep 28, 2022

There is no implementation in esp_espnow.c

#define QS(x) (uintptr_t)MP_OBJ_NEW_QSTR(x)
    // Return the value of the requested parameter
    uintptr_t name = (uintptr_t)args[ARG_get].u_obj;
    if (name == QS(MP_QSTR_buffer)) {
        return mp_obj_new_int(self->recv_buffer_size);
    } else if (name == QS(MP_QSTR_timeout)) {
        return mp_obj_new_int(self->recv_timeout_ms);
    } else {
        mp_raise_ValueError(MP_ERROR_TEXT("unknown config param"));
    }
#undef QS

There is - look a few lines above this for the setting code. The ESP IDF provides no support for querying the current rate (only setting it), so I don't support ESPNow.config('rate') to return the current rate.

@glenn20
Copy link
Owner

glenn20 commented Sep 28, 2022

On a separate note, I tested the long range mode as described in the ESP-IDF example, I would say that it is pretty disappointing, a device just operating on micropython without long range mode and the ESP-IDF with long range mode - more or less have the same coverage. i.e with brick walls and concrete floors, just with the on board antenna i covers approximately 15 ft with the micropython code, the ESP NOW long range example is no different in range - unless there is something terribly iwrong with the code or the board.

You can see some prior discussion on LR_MODE in another issue at: #20.

That includes a link to a video showing some people's experiments using LR_MODE. I haven't seen any reports of increased range for LR_MODE on micropython.

@krishnak
Copy link
Author

krishnak commented Sep 28, 2022

Hello Glenn

Thank you for engaging and helpful. I am using ESP-IDF 4.4.2 to build your code and I am not using your pre-built binaries. May be I am missing some configuration parameters to let micropython use 4.4.2 features. Do you know where should I look in to

I have w0.config(protocol=network.MODE_LR) - no errors

w0.config(rate=41), - throws unknown param

That thing aside, I have realised why there was NO difference in LR mode and normal mode when I compiled the esp-idf 4.4.2 example of espnow . The Long range mode works only between two devices (its mentioned in one of the espressif blogs) that possibly means it doesn't work in broadcast mode. The example given in esp-idf uses broadcast mode address.

I just changed this now to unicast from the start. The documented sensitivity at LR is only -105dBm at 125Kbps and -97 dBm with standard espnow operating at 1Mbps. -3dB shift in sensitivity means half the power is needed by the transmitter to cover the same range, even though theoretically there is a 8dB shift which should mean that same range should achieved with 1/4th of the power.

I am able to see a difference, now the data is crossing over another brick wall in LR mode, this is with just the on board antenna's in both the devices. If I do a power test then what Espressif claim would be correct, but for practical purpose its just one more brick wall that you may be able to cross without external antennas

@glenn20
Copy link
Owner

glenn20 commented Sep 28, 2022

Thank you for engaging and helpful. I am using ESP-IDF 4.4.2 to build your code and I am not using your pre-built binaries. May be I am missing some configuration parameters to let micropython use 4.4.2 features. Do you know where should I look in to

Mmm - that's puzzling. I just checked on freshly compiled image from espnow-g20 branch and e.config(rate=0x1f) is accepted without complaint. Note: e.config(rate=41) fails with an ESP_FAIL OSError exception (that is 0x29 which is WIFI_PHY_RATE_LORA_250K which seems not to be supported on generic ESP32).

Are you using the espnow-g20 branch? Check the code in espnow_config() includes calls to esp_wifi_config_espnow_rate().

To do a completely clean build I do:

cd ~/projects/micropython/micropython
source ../IDF/v4.4/export.sh
make -C mpy-cross clean
make -C mpy-cross
cd ports/esp32
make BOARD=GENERIC clean
make BOARD=GENERIC submodules
make BOARD=GENERIC

(of course this is all in a complex set of scripts).

@krishnak
Copy link
Author

Regarding your query of espnow_config() yes it does have a check

if (args[ARG_rate].u_int >= 0) {
        #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
        esp_initialise_wifi();  // Call the wifi init code in network_wlan.c
        check_esp_err(esp_wifi_config_espnow_rate(
            ESP_IF_WIFI_STA, args[ARG_rate].u_int));
        check_esp_err(esp_wifi_config_espnow_rate(
            ESP_IF_WIFI_AP, args[ARG_rate].u_int));
        #else
        mp_raise_ValueError(MP_ERROR_TEXT("rate option not supported"));
        #endif
    }

But I get the error
File "esp_sender.py", line 40, in
ValueError: unknown config param

on line 40 I have
w0.config(rate=0x1f)

I just did a clean build and I get this message at the start which says IDF target not set, how is it set?

make deploy
idf.py -D MICROPY_BOARD=GENERIC -B build-GENERIC  -p /dev/ttyUSB0 -b 460800 flash
Executing action: flash
Running cmake in directory /home/krishnak/micropython/ports/esp32/build-GENERIC
Executing "cmake -G 'Unix Makefiles' -DPYTHON_DEPS_CHECKED=1 -DESP_PLATFORM=1 -DMICROPY_BOARD=GENERIC -DCCACHE_ENABLE=0 /home/krishnak/micropython/ports/esp32"...
-- IDF_TARGET not set, using default target: esp32

@krishnak
Copy link
Author

And I have done idf export before calling build (and performed all the other steps you have described)


source ~/esp-idf-4.4.2/export.sh 
Setting IDF_PATH to '/home/krishnak/esp-idf-4.4.2'
Detecting the Python interpreter
Checking "python" ...
Python 3.10.6
"python" has been detected
Adding ESP-IDF tools to PATH...
Using Python interpreter in /home/krishnak/.espressif/python_env/idf4.4_py3.10_env/bin/python
Checking if Python packages are up to date...
Python requirements from /home/krishnak/esp-idf-4.4.2/requirements.txt are satisfied.
Added the following directories to PATH:
  /home/krishnak/esp-idf-4.4.2/components/esptool_py/esptool
  /home/krishnak/esp-idf-4.4.2/components/espcoredump
  /home/krishnak/esp-idf-4.4.2/components/partition_table
  /home/krishnak/esp-idf-4.4.2/components/app_update
  /home/krishnak/.espressif/tools/xtensa-esp32-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32-elf/bin
  /home/krishnak/.espressif/tools/xtensa-esp32s2-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32s2-elf/bin
  /home/krishnak/.espressif/tools/xtensa-esp32s3-elf/esp-2021r2-patch3-8.4.0/xtensa-esp32s3-elf/bin
  /home/krishnak/.espressif/tools/riscv32-esp-elf/esp-2021r2-patch3-8.4.0/riscv32-esp-elf/bin
  /home/krishnak/.espressif/tools/esp32ulp-elf/2.28.51-esp-20191205/esp32ulp-elf-binutils/bin
  /home/krishnak/.espressif/tools/esp32s2ulp-elf/2.28.51-esp-20191205/esp32s2ulp-elf-binutils/bin
  /home/krishnak/.espressif/tools/openocd-esp32/v0.11.0-esp32-20220411/openocd-esp32/bin
  /home/krishnak/.espressif/python_env/idf4.4_py3.10_env/bin
  /home/krishnak/esp-idf-4.4.2/tools
Done! You can now compile ESP-IDF projects.
Go to the project directory and run:

  idf.py build

@krishnak
Copy link
Author

I have done the following test with the esp idf esp now C code

ESP_ERROR_CHECK( esp_wifi_set_protocol(ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR) );
//    ESP_ERROR_CHECK( esp_wifi_config_espnow_rate(ESPNOW_WIFI_IF,WIFI_PHY_RATE_LORA_250K));

With LORA 250K explicitly set, there is NO difference to the sensitivity with the PCB antennas. But there is a definite increase in sensitivity with LR enabled - as per the espressif doc's it is stated as 4dB gain - which is more or less what I am experiencing.

Now I can forget about the datarate bug in micropython and see whether I get the same range with just the LR mode enabled in your code.

I tested it with just w0.config(protocol=network.MODE_LR)
on both the esp32 transmitter and receiver - its not having that extra range.

This is most likely due to the fact that the Long range has to be specifically enabled during compile time - that is what I did using menuconfig on ESP IDF SDK

CONFIG_ESPNOW_ENABLE_LONG_RANGE=y

Checking the micropython build file sdkconfig.base this parameter is not present in my source code - can you check whether you have that parameter enabled in that file or any other file by doing a grep -r "keyword" * under ports/esp32

I added this parameter in sdkconfig.base - micropython compiled and flashed to the device without any error.

When I execute a previous esp_now send/receive program - the device crashes with a GURU meditation error. This is only on ONE hardware. The other hardware has no issues and works.

I look forward to your thoughts

@glenn20
Copy link
Owner

glenn20 commented Sep 29, 2022

on line 40 I have w0.config(rate=0x1f)

Ok - I finally spotted the problem (not the first time I and others have been caught out by this :)).

It should be e0.config(rate=0x1f), not w0.config(rate=0x1f) (assuming w0 = network.WLAN(network.STA_IF) and e0 = espnow.ESPNow().

@krishnak
Copy link
Author

Spot on :) that has got rid of the error - However when I use data rate 0x1f - the range is drastically reduced, i.e it works only with in the same room or line of sight as the data rate is 72Mbps on a 20MHz channel.

Now I tried the Lora 250K and 500K settings, they both throw OSError: [Errno 1] EPERM: ESP_FAIL

Using micropython, "the setting WiFi protocol long range has no sensitivity gain i.e there is NO 4dB gain as it happens with ESP-IDF

The Lora rate settings have no effect in ESP-IDF as well so we have to settle for 1Mbps data rate at ESPNow

@glenn20
Copy link
Owner

glenn20 commented Sep 29, 2022

Spot on :) that has got rid of the error - However when I use data rate 0x1f - the range is drastically reduced, i.e it works only with in the same room or line of sight as the data rate is 72Mbps on a 20MHz channel.

Excellent.

Now I tried the Lora 250K and 500K settings, they both throw OSError: [Errno 1] EPERM: ESP_FAIL

Yes - because esp_wifi_config_espnow_rate() returns ESP_FAIL and so check_esp_err() will raise an OSError exception. I assume the "LORA" modes are not supported on generic esp32 platforms.

This is most likely due to the fact that the Long range has to be specifically enabled during compile time - that is what I did using menuconfig on ESP IDF SDK

CONFIG_ESPNOW_ENABLE_LONG_RANGE=y

Checking the micropython build file sdkconfig.base this parameter is not present in my source code - can you check whether you have that parameter enabled in that file or any other file by doing a grep -r "keyword" * under ports/esp32

Excellent - thanks for picking up on this. Can you tell me if setting this in sdkconfig.base fixed the problem (you may need to do a make clean to force a full rebuild).

@krishnak
Copy link
Author

No there is no difference if I set the CONFIG_ESPNOW_ENABLE_LONG_RANGE=y - I have done all make cleans.

Does this entry CONFIG_ESPNOW_ENABLE_LONG_RANGE=y appear in any of the sdkconfig in your build setup?

You can check the rssi of the received packet - it should show a significant increase in its value in long range mode.

@glenn20
Copy link
Owner

glenn20 commented Sep 29, 2022

No there is no difference if I set the CONFIG_ESPNOW_ENABLE_LONG_RANGE=y - I have done all make cleans.

Well, that is disappointing....

Does this entry CONFIG_ESPNOW_ENABLE_LONG_RANGE=y appear in any of the sdkconfig in your build setup?

No - not that I can find.

You can check the rssi of the received packet - it should show a significant increase in its value in long range mode.

Do you have a small IDF example code which works? I could inspect that to see if there are any magic initialisation steps required.

@krishnak
Copy link
Author

krishnak commented Sep 29, 2022

https://github.com/espressif/esp-idf/tree/master/examples/wifi/espnow - I have compiled this example, attached is the binary with and without long range enabled - so you just flash and test. I tried to print RSSI using your code from micropython, it prints the correct RSSI when in broadcast mode but ones they shift to unicast transmission, the code keeps printing -96 as rssi, which either means that the protocol has changed and the rssi is no longer in the header or something else. However your espnow inmicropython keeps printing the correct RSSI which probably means that the long range mode is not enabled

espnow_example_withoutlr.zip
espnow_example_withLR.zip

@glenn20
Copy link
Owner

glenn20 commented Sep 30, 2022

espnow_example_withoutlr.zip espnow_example_withLR.zip

Great - thanks. Also - can you tell me which version of the IDF you are using to build these examples and which esp32 devices these are compiled for? These bins just reboot continuously.

I have built them fresh using your source code and IDF from master and from v4.4 - and I see no significant difference between the reported RSSI when LR mode is enable or not enabled. (However that is for several devices placed fairly close together - maybe the difference is only significant for low RSSI signals).

Oh - BTW, CONFIG_ESPNOW_ENABLE_LONG_RANGE=y is only used in the example code - it is not used when building any other code (ie. it has no effect when building micropython).

@krishnak
Copy link
Author

krishnak commented Sep 30, 2022 via email

@krishnak
Copy link
Author

krishnak commented Sep 30, 2022 via email

@krishnak
Copy link
Author

krishnak commented Sep 30, 2022 via email

@glenn20
Copy link
Owner

glenn20 commented Sep 30, 2022

Here is the output from running the code you sent me (with a few minor additions - like printing out the protocol bitmask).

With LR_MODE on (see the line Protocol=15):

I (721) espnow_longrange: Next line should print Long range enabled, if compiled with correct option
I (721) espnow_longrange: Long range enabled
I (721) wifi:enable tsf
I (731) espnow_longrange: Protocol=15
I (731) ESPNOW: espnow [version: 1.0] init
I (1451) espnow_longrange: RSSI:-18
I (5731) espnow_longrange: Start sending broadcast data
I (5731) espnow_longrange: Receive 2th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (6731) espnow_longrange: send data to ff:ff:ff:ff:ff:ff
I (7691) espnow_longrange: RSSI:-18
I (7711) espnow_longrange: RSSI:-94
I (7731) espnow_longrange: send data to ff:ff:ff:ff:ff:ff
I (7731) espnow_longrange: Receive 0th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (7731) espnow_longrange: Receive 0th unicast data from: cc:50:e3:b5:a2:e8, len: 10
I (8711) espnow_longrange: RSSI:-94
I (8711) espnow_longrange: Receive 1th unicast data from: cc:50:e3:b5:a2:e8, len: 10
I (9711) espnow_longrange: RSSI:-94

With LR_MODE off (see the line Protocol=7)

I (723) espnow_longrange: Next line should print Long range enabled, if compiled with correct option
I (723) espnow_longrange: Protocol=7
I (723) ESPNOW: espnow [version: 1.0] init
I (3923) espnow_longrange: RSSI:-18
I (4923) espnow_longrange: RSSI:-18
I (5733) espnow_longrange: Start sending broadcast data
I (5733) espnow_longrange: Receive 0th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (5733) espnow_longrange: Receive 1th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (5923) espnow_longrange: RSSI:-19
I (6743) espnow_longrange: send data to ff:ff:ff:ff:ff:ff
I (6743) espnow_longrange: Receive 2th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (6923) espnow_longrange: RSSI:-19
I (6933) espnow_longrange: RSSI:-94
I (7743) espnow_longrange: send data to ff:ff:ff:ff:ff:ff
I (7743) espnow_longrange: Receive 3th broadcast data from: cc:50:e3:b5:a2:e8, len: 10
I (7743) espnow_longrange: Receive 0th unicast data from: cc:50:e3:b5:a2:e8, len: 10
I (7933) espnow_longrange: RSSI:-94

@glenn20
Copy link
Owner

glenn20 commented Sep 30, 2022

I confess that I don't understand LR_MODE sufficiently to know what effect we should be seeing in the RSSI values.

I also don't understand why the RSSI values drop to -94 (-92 on another device) when receiving unicast messages. I don't see that behaviour in micropython.

These teste were with IDF 4.4, but I get the same results with idf from master.

@krishnak
Copy link
Author

krishnak commented Sep 30, 2022 via email

@krishnak
Copy link
Author

krishnak commented Sep 30, 2022 via email

@glenn20
Copy link
Owner

glenn20 commented Oct 1, 2022

@krishnak - thanks for investigating this issue. Unfortunately, I think it is sufficiently unclear what, if any, effect we will see on the measured rssi values of engaging LR_MODE.

I am thinking that the ony definitive method for checking if LR_MODE is successfully engaged (and what benefit it provides) will
be from doing packet loss testing with real devices at range, like (from #20):

I have not tested LR_MODE to see if it provides improved range. I have only tested that connections work. A user pointed me
at the following video 6:05 on video which suggests success. To replicate the
conditions they used in that test (and using my wifi.py module from https://github.com/glenn20/micropython-espnow-utils):

I will close this issue since we have resolved the initial issue about setting the rate and I'm not sure that continuing the discussion about the meaning of the RSSI values will be producitive without the kind of range testing described above (although I am still puzzled about why the unicast rssi values in the example codes jump down to less than -90) - but that is not happening with my micropython images).

Feel free to respond or continue the discussion here and I will keep following it, but this will be marked as a closed Issue.

@glenn20 glenn20 closed this as completed Oct 1, 2022
@krishnak
Copy link
Author

krishnak commented Oct 2, 2022

I looked at the video, and also the code - the broadcast code is writtenin C and the receiver in Arduino. Nothing fancier than what we have tried, he has used an older SDK - his code doesn't compile with SDK 4.4.2.

Coming to the video and their claims, they all are "Youtube videos".

A lightwave can have have as much range as possible if it has sufficient signal strength, the criteria is that it works in line of sight.

The boards have a receiver sensitivity of around -90dB - no signal is received if the signal strength is below this value in long range or regular mode. I was hoping that there will be an increased signal sensitivity by enabling long range. It may be the case that it can be measured only if it is in line of sight for microwave tower builders and not for indoor use.

Ti's CC1120 sub GHz module has a sensitivity of around -125dB, ofcourse it is not possible to achieve that sensitivity with 2.4Ghz frequencies. With that module, if the Tx is inside a room with brickwalls and a small window, you can receive data with 0 packet loss up to 300m - they claim to have a range of over 100Km - I have those development boards :)

https://www.youtube.com/watch?v=wgqtEu5PfAw

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants