asynycio as_GPS

All ESP32 boards running MicroPython.
Target audience: MicroPython users with an ESP32 board.
User avatar
pythoncoder
Posts: 4173
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: asynycio as_GPS

Post by pythoncoder » Wed Jan 15, 2020 7:17 am

Yes. The main part of the code should read

Code: Select all

    with open(fn, 'w') as f:
        f.write(str_start)
        while True:
            try:
                f.write(gps.longitude_string(as_GPS.KML))
                f.write(',')
                f.write(gps.latitude_string(as_GPS.KML))
                f.write(',')
                f.write(str(gps.altitude))
                f.write('\r\n')
                led(off)
                # for _ in range(interval * 10):
                await asyncio.sleep_ms(100)
            except KeyboardInterrupt:
                break
        f.write(str_end)
I can see no reason why this wouldn't work, but having no Pycom hardware I can't test it.

Using a keyboard interrupt to break does ensure that str_end is written but runs the risk that the last record will be incomplete. My version polls a switch to avoid this risk, with the switch only being checked after the record has been written.
Peter Hinch

User avatar
romeotango
Posts: 27
Joined: Tue Jun 16, 2015 10:52 am
Location: Germany

Re: asynycio as_GPS

Post by romeotango » Thu Jan 16, 2020 11:51 am

The keyboardInterrupt is intended as a temporary solution for evaluation
Write errors on the SD card are over. I formatted the card again in LoPy, obviously there was a discrepancy in access between micropython and ftp. So done. Thank You for your patience.

Overall I like the callback function very much. I think it is the best way to read the stream from the GPS continuously.
But the callback does not work for me.

Code: Select all

import gc
gc.collect()
import as_GPS
gc.collect()
import uasyncio as asyncio
from machine import UART
gc.collect()
gc.threshold(gc.mem_free() // 4 + gc.mem_alloc())

from machine import UART

def callback(gps, *_):  # Runs for each valid fix
    print("cb", gps.latitude(), gps.longitude(), gps.altitude)


async def test():
    print('waiting for GPS data')
    await gps.data_received(position=True, altitude=True)
    print ("Data received")
    print(gps.latitude(), gps.longitude(), gps.altitude)
    await asyncio.sleep(60)  # Run for one minute



uart= UART(1, baudrate=9600, pins=('P20','P21'))
print (uart.readline())
print (uart.readline())
sreader = asyncio.StreamReader(uart)  # Create a StreamReader
gps = as_GPS.AS_GPS(sreader, fix_cb=callback)  # Instantiate GPS
print (gc.mem_free())
print (gc.mem_alloc())
loop = asyncio.get_event_loop()
loop.run_until_complete(test())
>>>
comment
None from print (uart.readline())
None dto
10176 memfree
56832 memallocate
waiting for GPS data
Data received
[52.12479, 'N'] [8.638245, 'E'] 98.9
last debug print shows valid sentence
>
The callback is not executed here.
Maybe the data set from my GPS is not sufficient to fulfill the condition?
Support is still very welcome. :geek:

Code: Select all

Line 224 in as_GPS.py
if isinstance(s_type, int) and (s_type & self.cb_mask):
                # Successfully parsed, data was valid and mask matches sentence type
                self._fix_cb(self, s_type, *self._fix_cb_args)  # Run the callback

User avatar
pythoncoder
Posts: 4173
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: asynycio as_GPS

Post by pythoncoder » Thu Jan 16, 2020 5:04 pm

I'm baffled. Your code works fine here on a Pyboard D. My only adaptations were a) to turn on the 3.3V line and b) to specify the UART - i.e. remove the pin identifiers.
Peter Hinch

User avatar
romeotango
Posts: 27
Joined: Tue Jun 16, 2015 10:52 am
Location: Germany

Re: asynycio as_GPS

Post by romeotango » Thu Jan 16, 2020 6:39 pm

Probably that is because it is your code from the tutorial :P
And your fast_io Version.

Will try the other uasyncio's ...

User avatar
pythoncoder
Posts: 4173
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: asynycio as_GPS

Post by pythoncoder » Fri Jan 17, 2020 7:52 am

romeotango wrote:
Thu Jan 16, 2020 6:39 pm
Probably that is because it is your code from the tutorial :P
And your fast_io Version.

Will try the other uasyncio's ...
Well I recognised the code, that was why I was astonished it wouldn't run. I ran it against official uasyncio V2, not my version.

I suggest you stick with official uasyncio V2 to remove one variable from the setup. Presumably this is what Pycom support? In general V2 works so long as you don't get involved with issues like fast I/O and task cancellation. None of your code samples will challenge that version in any way.

If callbacks aren't taking place in such a simple code sample I'm feeling rather suspicious about Pycom firmware.
Peter Hinch

User avatar
romeotango
Posts: 27
Joined: Tue Jun 16, 2015 10:52 am
Location: Germany

Re: asynycio as_GPS

Post by romeotango » Sun Jan 19, 2020 7:40 pm

Hello,
I can't think of a reason for this, but I think that somehow this if statement

Code: Select all

if isinstance(s_type, int) and (s_type & self.cb_mask):
does not return True and therefore the callback is not called.
I tried again today with another GPS receiver, but the result was without success. Somehow I can't imagine that it is related to the micropython from Pycom, but this is just a feeling ;)

OK, next step.
Thanks to the hints of MostlyHarmless, I have now set up everything to compile frozen bytecode. I use the toolchain from Pycom for this. After having somehow bricked a Linux under virtualbox with all the $PATH changes, I went back to the docker container. And that's how it worked. :)
So it goes on and on...
Thanks for the support and have a nice week
Rainer

User avatar
pythoncoder
Posts: 4173
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: asynycio as_GPS

Post by pythoncoder » Mon Jan 20, 2020 9:17 am

My guess is still that the problem was in firmware. When you recompiled to implement frozen bytecode you doubtless used the latest sources and very likely acquired a bugfix.

Freezing bytecode helps greatly with RAM shortages, but it's not magic. It won't repair broken code ;) So the only thing left is the rebuild.
Peter Hinch

User avatar
romeotango
Posts: 27
Joined: Tue Jun 16, 2015 10:52 am
Location: Germany

Re: asynycio as_GPS

Post by romeotango » Thu Jan 23, 2020 5:45 pm

The mistake is actually ridiculous, but isn't that (always) very common? ;)
Here is my solution:
#1
My GPS modules send sentences which are not included here yet.
I have added them.

Code: Select all

        # Key: currently supported NMEA sentences. Value: parse method.
        self.supported_sentences = {'GPRMC': self._gprmc, 'GLRMC': self._gprmc,
                                    'GPGGA': self._gpgga, 'GLGGA': self._gpgga,
                                    'GPVTG': self._gpvtg, 'GLVTG': self._gpvtg,
                                    'GPGSA': self._gpgsa, 'GLGSA': self._gpgsa, 'GNGSA': self._gpgsa,
                                    'GPGSV': self._gpgsv, 'GLGSV': self._gpgsv,
                                    'GPGLL': self._gpgll, 'GLGLL': self._gpgll, 'GNGLL': self._gpgll,
                                    'GNGGA': self._gpgga, 'GNRMC': self._gprmc,
                                    'GNVTG': self._gpvtg,
                                    }
But that was not all.
#2
The parser is called from this dictionary really very elegantly.
in -gprmc the data set is then evaluated.
There are '' None fields in the record. E.g. for Speed or Course on stationary devices.
The conversion into a float leads to a ValueError and therefore the whole data set is not evaluated anymore.
Hence the callback is omitted.

Code: Select all

s_type = self.supported_sentences[segs[0]](segs)  # Parse
            except ValueError:
                s_type = False
I then convert empty fields to "0". This works well for Course and Speed.

Code: Select all

segs = [i if i != "" else "0" for i in segs] #replace empty with zero for better float conversion

But when Magnetic variation should be evaluated, ValueError, because "0" instead of "WE" in the field.
Well, 2° actually don't play any role, so comment out.
Now the callback works exactly as expected, HURRA!

Would it be less time-consuming to leave the sentence as it was?
And put the float-conversion into a try: section?
Or if-check before the float conversion for None-Entries?

Thank you for good ideas.
RT

User avatar
pythoncoder
Posts: 4173
Joined: Fri Jul 18, 2014 8:01 am
Location: UK
Contact:

Re: asynycio as_GPS

Post by pythoncoder » Thu Jan 23, 2020 7:14 pm

I am puzzled: as_gps.py should ignore unsupported sentences, just incrementing debugging counters. See this line. By default such sentences should be ignored. There is an option to handle them in a subclass by overriding the parse method.

I am also puzzled by your having problems with stationary devices: I haven't seen this.

Perhaps you might explain your ideas more fully as I don't follow them.
Peter Hinch

gersch07
Posts: 2
Joined: Sun Jan 26, 2020 10:00 pm

Re: asynycio as_GPS

Post by gersch07 » Sun Jan 26, 2020 10:11 pm

Dear all,

I've been following this thread as I experience very similar issues with "string index out of range" on an ESP32 with PSRAM (Micropython 1.12).
@romeotango: Could you let me know which specific version of the "uasyncio" library fixed your error and from which link / repository you downloaded it from?
Many thanks in advance!
>>>
waiting for GPS data
Traceback (most recent call last):
File "<stdin>", line 19, in <module>
File "/flash/lib/uasyncio/core.py", line 180, in run_until_complete
File "/flash/lib/uasyncio/core.py", line 154, in run_forever
File "/flash/lib/uasyncio/core.py", line 109, in run_forever
File "/flash/lib/as_GPS.py", line 209, in _update
File "/flash/lib/as_GPS.py", line 89, in _crc_check
IndexError: string index out of range
[/code]

Post Reply