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

Pybricksdev changes for Remote Control based on Pybrickdev-Demo #34

Open
johnscary-ev3 opened this issue Jun 21, 2022 · 7 comments
Open

Comments

@johnscary-ev3
Copy link

johnscary-ev3 commented Jun 21, 2022

Hi guys

I am using pybricksdev to do remote control of RI robot.
I developed this from pybricksdev-demo a while back.
It was working fine but then I updated the pybrickdev library and seems like alot of changes happened and does not work anymore.
Mostly related to how we open the hub and check status now.
Looks like PybricksHub does not exist now and hub.program_running also and maybe some other hub methods.
Below is code that was working but now does not.

Can you give me some comments, examples, or other docs that might help me get upgraded to new lib?

from pybricksdev.connections import PybricksHub
from pybricksdev.ble import find_device
from asyncio import gather, sleep, run
import msvcrt

async def main():
    print('main: Start')
    hub = PybricksHub()   
    # You can search for the address like this:
    address = await find_device()
    await hub.connect(address)
    await gather(
    hub.run('robot_Blast.py', print_output=True),
    forwarder(hub)
    )

    # Disconnect from the hub
    await hub.disconnect()
    print('main: Stop')

async def forwarder(hub):    
    print("forwarder: Start")

    # Give the hubs some time to start
    while not hub.program_running :
        #print('forwarder: Waiting for Hub to Run')
        await sleep(2)
    print('forwarder: Hub Running')
 
    # Keyboard command input loop                   
    while hub.program_running :
        # Non blocking keyboard Input
        if msvcrt.kbhit():
            # get char with or without echo
            command = msvcrt.getch()
            
            # clear any extra characters
            while msvcrt.kbhit():
                msvcrt.getch()
        else:  
            command= ''
        # Try to send to the receiving hub
        if len(command) > 0:
            try:
                await hub.write(bytes([ord(command)]))
            except:
                pass          
        # wait some    
        await sleep(.1)

    # Hub has stopped
    print('forwarder: Hub Not Running')

#start it up
run(main())
@johnscary-ev3
Copy link
Author

I found that PybricksHub moved so this import works now but other calls still give errors as below.
Thanks.

from pybricksdev.connections.pybricks import PybricksHub

File "c:/Users/johns/pybricksdev-demo/RemoteControl_Blast.py", line 27, in forwarder
    while not hub.program_running :
AttributeError: 'PybricksHub' object has no attribute 'program_running'

@dlech
Copy link
Member

dlech commented Jun 21, 2022

How about something like this?

import asyncio
import platform
import sys

try:
    import msvcrt
except ModuleNotFoundError:
    pass

try:
    import termios
    import tty
except ModuleNotFoundError:
    pass

from pybricksdev.connections.pybricks import PybricksHub, StatusFlag
from pybricksdev.ble import find_device

def read_key():
    if platform.system() == 'Windows':
        return msvcrt.getch()
    
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)

    try:
        tty.setraw(fd)
        return sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)



async def main():
    print('main: Start')

    hub = PybricksHub()

    device = await find_device()
    await hub.connect(device)
 
    try:
        forwarder_task = asyncio.create_task(forwarder(hub))
        try:
            await hub.run('robot_Blast.py')
        finally:
            forwarder_task.cancel()
    finally:
        # Disconnect from the hub
        await hub.disconnect()
        print('main: Stop')

async def forwarder(hub: PybricksHub):
    print("forwarder: Start")

    queue = asyncio.Queue()

    # wait for user program on the hub to start
    with hub.status_observable.subscribe(lambda s: queue.put_nowait(s)):
        while True:
            status = await queue.get()

            if status & StatusFlag.USER_PROGRAM_RUNNING:
                break

    print('forwarder: Hub Running')

    loop = asyncio.get_running_loop()
 
    # Keyboard command input loop
    while True:
        command = await loop.run_in_executor(None, read_key)

        # Try to send to the receiving hub
        try:
            await hub.write(bytes([ord(command)]))
        except:
            pass

#start it up
asyncio.run(main())

@johnscary-ev3
Copy link
Author

Thanks so much for the help.
I can see from your example and reading the latest pybricksdev code that you have reworked how we get hub status now using the status queue to get status updates. Seems like a reasonable way to get different status codes.

On your example code, I tried to run it.
I don't get any errors, but it seems like it downloads and starts my robot code ok but then immediately drops to the hub.disconnect and stops. The robot side program keeps running fine but with no connection to PC side.
I tried adding a wait to the hub.run call but it made no difference as wait=True is default anyway.

Any ideas on this?

PS C:\Users\johns\pybricksdev-demo> & c:/Users/johns/pybricksdev-demo/.venv/Scripts/python.exe c:/Users/johns/pybricksdev-demo/RemoteControl_example_June_2022
main: Start
forwarder: Start
100%|███████████████████████████████████████████████████████████████| 36.1k/36.1k [00:45<00:00, 790B/s]
main: Stop

@dlech
Copy link
Member

dlech commented Jun 21, 2022

I have tested my code on both Windows and Linux with the the following substitute for robot_Blast.py:

import usys

from pybricks import version

print('hub program started')
print(version)

while True:
    print('received', usys.stdin.read(1))

And it produces the following output when keys are pressed:

main: Start
forwarder: Start
100%|██████████████████████████████████████████████████████████████████████████████████████████| 144/144 [00:00<00:00, 716B/s]
hub program started
forwarder: Hub Running
('technichub', '3.2.0b1', 'v3.2.0b1-28-g8c1d7f77 on 2022-06-14')
received a
received d
received f
received 
received H

dlech added a commit that referenced this issue Jun 21, 2022
Testing to see if this makes a difference in <#34>.

In any case, it doesn't hurt to wait a bit longer.
@dlech
Copy link
Member

dlech commented Jun 21, 2022

It looks like there is a possible problem with the way waiting for a user program running works in pybricksdev. I just published v1.0.0-alpha.27 with an increased timeout that may help if this is the issue.

@johnscary-ev3
Copy link
Author

I tried your short robot side program and it worked fine as you mentioned.

Then saw your post about update v1.0.0-alpha.27 so I updated to that and tried your PC side program with my larger robot side program, and it works fine now. So that timeout must have been the issue.
My robot program can take almost 60 seconds to download and start up. It is about 2600 lines of Python code.
Not sure how that compares to what others may have with respect to download times, but the new timeout seems to cover it.

Thanks again for all the help on this!

@dlech
Copy link
Member

dlech commented Jun 21, 2022

It is about 2600 lines of Python code.

😮

That's pretty big.

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