peterhinch / micropython-async

Application of uasyncio to hardware interfaces. Tutorial and code.
MIT License
739 stars 168 forks source link

as_GPS problem #102

Closed beetlegigg closed 1 year ago

beetlegigg commented 1 year ago

I've just been trying out as_GPS. I have a problem with giving a command to my adafruit ultimate GPS and I'm running the code on a rpi picoW, but I don't think the particular GPS or the board is the problem as the issue is a python error message : TypeError: string argument without an encoding.

This occurs in the following code:

import uasyncio as asyncio
from as_rwGPS import GPS
from machine import UART

uart = UART(0, 9600)
sreader = asyncio.StreamReader(uart)  # Create a StreamReader
swriter = asyncio.StreamWriter(uart, {})
gps = GPS(sreader, swriter)  # Instantiate GPS

async def test():
    print('waiting for GPS data')
    await gps.data_received(position=True, altitude=True)
    await gps.update_interval(2000)  # Reduce message rate
    for _ in range(10):
        print(gps.latitude(), gps.longitude(), gps.altitude)
        await asyncio.sleep(2)

asyncio.run(test())

The problem is in the line ' await gps.update_interval(2000) # Reduce message rate'

and this links to line 78 in as_reGPS.py where the error occurs: sentence = bytearray('$PMTK220,{:d}*00\r\n'.format(ms))

In case it was an older version of mp for the picoW causing the error I installed the latest nightly build, but the error still remains.

Thanks for any help on this.

beetlegigg commented 1 year ago

Further to my previous comment, I'm thinking that perhaps this wont work with a picoW after all. Strange behaviour. I run the code from the doc example with a callback, and it runs for about a minute as expected. I run the example that does not use a callback, and it runs for 10 times as expected. I run the last example again, and this time no data is printed to the screen. I run the callback example again, and this time it runs, but for quite a long time (several minutes) before giving up with Task exception wasn't retrieved future: coro= <generator object '_run' at 20014640> Traceback (most recent call last): File "uasyncio/core.py", line 1, in run_until_complete File "as_GPS.py", line 185, in _run File "uasyncio/stream.py", line 1, in readline TypeError: unsupported types for iadd: 'bytes', 'NoneType'

Something is not playing well. :-(

peterhinch commented 1 year ago

This is puzzling. I have done a lot of testing on the Pico UART and am confident that with recent firmware it works well. I would check for electrical problems, notably drooping supply voltage to the GPS or bad ground connections.

beetlegigg commented 1 year ago

Hello Peter, The connections look to be good. I tried the following to test things out.

  1. connected the Adafruit Ultimate GPS to an ESP8266 and ran arduino C++ code to check the GPS was working OK. (it was)
  2. fished out a pico (not a W) , loaded CircuitPython, and ran its gps_simpletest.py. Left this running OK for about 10 minutes.
  3. fished out another pico (not a W) ,loaded Micropython latest nightly build, and commenced testing with as_GPS.

I used the 2 Basic Usage examples from the GPS.md ( the callback example and the example without using a callback ) both slightly modified for the pico uart and having the as_GPS in the main pico directory.

They both run but subsequent runs are inconsistant. Sometimes they can both throw an exception: Task exception wasn't retrieved future: coro= <generator object '_run' at 2000c1a0> Traceback (most recent call last): File "uasyncio/core.py", line 1, in run_until_complete File "as_GPS.py", line 185, in _run File "uasyncio/stream.py", line 1, in readline TypeError: unsupported types for iadd: 'bytes', 'NoneType'

This exception stops the callback example, but the non-callback continued to run and print the remaining 10 gps positions info.

Subsequent runs can work ok, but sometimes the non-callback program just gets stuck at 'waiting for GPS data'. Stopping the program (Control C) and subsequent attempts to run are not successful. The non-callback program will still run but can decide to run on forever, not stopping after on minute. (it still may abort with the exception above). All very strange.

And one thing that will definitely provoke this strange behaviour to immediately occur is if I first run the program as per my first post, where an update to the GPS is attempted to reduce the message frequency to 2 seconds which immediately gives the the error : Traceback (most recent call last): File "", line 18, in File "uasyncio/core.py", line 1, in run File "uasyncio/core.py", line 1, in run_until_complete File "uasyncio/core.py", line 1, in run_until_complete File "", line 13, in test File "as_rwGPS.py", line 78, in update_interval TypeError: string argument without an encoding

Then subsequent runs of the callback and non-callback snippets work (or fail) as described.

After this testing with as_GPS and micropython on a pico, I swapped the pico back to the CircuitPython pico (leaving the breadboard connections to the Adafruit GPS intact) as a double check that the wiring was still adequately connected and working OK. It was and the GPS reads were solid.

I would rather like to have an async GPS reading on a pico working, so if you have any more thoughts then I will give it another go.

peterhinch commented 1 year ago

I will attempt to replicate this, hopefully later today.

The tracebacks you posted suggest communication problems on the serial interface. This is puzzling, firstly because the way GPS uses the interface is very basic: no flow control, communications usually unidirectional, data newline terminated. It is also puzzling because I and others have tested the Pico serial ports under demanding conditions. These are the reasons why I suspect an electrical issue.

The TypeError: string argument without an encoding is a bug. Evidently something in the MP runtime has changed since I tested this. [EDIT] I have pushed an update to fix this.

I am running the Adafruit GPS with a Pico W and have seen the fault you reported. I now think that the RP2 UART is occasionally timing out. The following has been running for 5 minutes without error. I'll leave it running and report back.

import uasyncio as asyncio
import as_drivers.as_GPS as as_GPS
from machine import UART, Pin
def callback(gps, *_):  # Runs for each valid fix
    print(gps.latitude(), gps.longitude(), gps.altitude)

uart = UART(0, 9600, tx=Pin(0), rx=Pin(1), timeout=5000, timeout_char=5000)
sreader = asyncio.StreamReader(uart)  # Create a StreamReader
gps = as_GPS.AS_GPS(sreader, fix_cb=callback)  # Instantiate GPS

async def test():
    print('waiting for GPS data')
    await gps.data_received(position=True, altitude=True)
    await asyncio.sleep(3600)  # Run for one hour

asyncio.run(test())
peterhinch commented 1 year ago

The above code sample runs indefinitely (> 1 hour). I will update the docs for RP2.