robagar / tello-asyncio

A library for controlling and interacting with the Tello EDU drone using modern asynchronous Python.
GNU Lesser General Public License v2.1
29 stars 6 forks source link

go_to_mission_pads.py not working as expected #4

Closed jsolderitsch closed 3 years ago

jsolderitsch commented 3 years ago

I changed the code slightly to try to go from pad 2 to pad 1 and then to pad 3.

Here is what I see:

pi@raspberry:~/tello/tello-asyncio/examples $ python3 go_to_mission_pads.py 
waiting for WiFi...
CONNECT 192.168.10.1
SEND command
RECEIVED ok
SEND takeoff
RECEIVED ok
SEND mon
RECEIVED ok
mission pad: 2, position: Vector(x=-4.0, y=-3.0, z=74.0)
SEND go 0 0 100 25 m2
RECEIVED ok
mission pad: 2, position: Vector(x=-4.0, y=-3.0, z=74.0)
SEND go 0 0 100 25 m1
RECEIVED error No valid marker
[go 0 0 100 25 m1] ERROR error No valid marker
SEND land
RECEIVED ok
DISCONNECT 192.168.10.1
Traceback (most recent call last):
  File "go_to_mission_pads.py", line 31, in <module>
    loop.run_until_complete(main())
  File "/usr/lib/python3.7/asyncio/base_events.py", line 584, in run_until_complete
    return future.result()
  File "go_to_mission_pads.py", line 20, in main
    await drone.go_to(relative_position=Vector(0, 0, 100), speed=25, mission_pad=1)
  File "/home/pi/.local/lib/python3.7/site-packages/tello_asyncio/tello.py", line 369, in go_to
    return await self.send(command, timeout=LONG_RESPONSE_TIMEOUT)
  File "/home/pi/.local/lib/python3.7/site-packages/tello_asyncio/tello.py", line 502, in send
    response_message, result = await asyncio.wait_for(response, timeout=timeout)
  File "/usr/lib/python3.7/asyncio/tasks.py", line 416, in wait_for
    return fut.result()
tello_asyncio.tello.Error: error No valid marker

The pads are close by to each other, maybe 50 cm's apart. They are arranged in a straight line.

Maybe my expectations are wrong about what should happen.

jsolderitsch commented 3 years ago

I tried with both a Tello Edu and my new Tello TT.

Sometimes the second marker is found, but then it times out because the last marker (m3) is not found.

jsolderitsch commented 3 years ago

I just noticed that there is an SDK change from 2.0 to 3.0 regarding mission pad detection. The default for mon is ONLY DOWN being enabled, not BOTH (forward and down). So I suspect that if BOTH is enabled then the next mission pad should be detected if it is a short distance away. I can't check now since my evening room lighting is poor but I will do some experimentation tomorrow in daylight conditions.

Both of my Telle EDUs and both Tello TTs are running with SDK 3.0.

jsolderitsch commented 3 years ago

Here is some code that works SOME of the time but not 100% repeatably:

#!/usr/bin/env python3

import asyncio
from tello_asyncio import Tello, Vector, MissionPadDetection

async def main():
    drone = Tello()

    def output_state():
        print(f'mission pad: {drone.mission_pad}, position: {drone.mission_pad_position}')

    try:
        await drone.wifi_wait_for_network()
        await drone.connect()
        await drone.takeoff()
        await drone.enable_mission_pads()
        await drone.set_mission_pad_detection(MissionPadDetection.BOTH)
        output_state()
        await drone.go_to(relative_position=Vector(50, 0, 100), speed=10, mission_pad=1)
        output_state()
#        await drone.turn_clockwise(360)
        await drone.move_up(50)
#        output_state()
        await drone.move_down(50)
        await drone.go_to(relative_position=Vector(50, 0, 100), speed=10, mission_pad=2)
        output_state()
        await drone.move_up(50)
        await drone.move_down(50)
        await drone.go_to(relative_position=Vector(50, 0, 100), speed=10, mission_pad=3)
        output_state()
        await drone.move_up(50)
        await drone.move_down(50)
        await drone.go_to(relative_position=Vector(50, 0, 100), speed=10, mission_pad=4)
        output_state()
        await drone.move_up(50)
        await drone.move_down(50)
        await drone.go_to(relative_position=Vector(0, 0, 80), speed=10, mission_pad=5)
        output_state()
        await drone.land()
    finally:
        await drone.disconnect()

# Python 3.7+
#asyncio.run(main())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Seems like loitering around the current pad, looking for the next one to fly too, helps but is not guaranteed to work.

jsolderitsch commented 3 years ago

I am trying to use the mission pads as waypoints. I think a better approach is to navigate to 1 pad, send it away from that pad so that it is near a second pad. This should be far enough away that the first pad is no longer in the field of view of the Tello any longer. If the second pad is close enough it should be in the Tello's current view field, and then go to its center point. Then repeat the process in reverse to head back to the first pad. Once again my evening room light is too dim to try this now. First thing tomorrow...

Also, I think I do just want DOWN rather than BOTH for the mission pad detection setting.

jsolderitsch commented 3 years ago

OK, I think I have a working understanding of how the mission pads can work. Here is code that is working reliably:

#!/usr/bin/env python3

import asyncio
from tello_asyncio import Tello, Vector, MissionPadDetection

async def main():
    drone = Tello()

    def output_state():
        print(f'mission pad: {drone.mission_pad}, position: {drone.mission_pad_position}')

    try:
        await drone.wifi_wait_for_network()
        await drone.connect()
        await drone.enable_mission_pads()
        await drone.set_mission_pad_detection(MissionPadDetection.DOWN)
        await drone.takeoff()
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=1)
        output_state()
        await drone.go_to(relative_position=Vector(150, 0, 100), speed=50, mission_pad=1)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=2)
        output_state()
        await drone.go_to(relative_position=Vector(150, 0, 100), speed=50, mission_pad=2)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=3)
        output_state()
        await drone.go_to(relative_position=Vector(150, 0, 100), speed=50, mission_pad=3)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=4)
        output_state()
        await drone.go_to(relative_position=Vector(150, 0, 100), speed=50, mission_pad=4)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=3)
        output_state()
        await drone.go_to(relative_position=Vector(-150, 0, 100), speed=50, mission_pad=3)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=2)
        output_state()
        await drone.go_to(relative_position=Vector(-150, 0, 100), speed=50, mission_pad=2)
        output_state()
        await drone.go_to(relative_position=Vector(0, 0, 100), speed=50, mission_pad=1)
        output_state()
        await drone.land()
    finally:
        await drone.disconnect()

# Python 3.7+
#asyncio.run(main())
loop = asyncio.get_event_loop()
loop.run_until_complete(main())

There are 4 mission pads arranged more or less linearly, about 1.5 meters apart. This code flies out along the mission pad route from pad 1 to pad 4 and then back again to the pad 1 origin. The state messages show that the Tello senses the pads as it goes.

I did need to increase the go-to speed and I am only using the down position.

Perhaps a version of this code could be added to the repo?

robagar commented 3 years ago

Cool, tbh I wasn't sure how the mission pad operations were supposed to work. Can you make a PR?

jsolderitsch commented 3 years ago

Will see if I can remember what it takes to make a PR. I don't do it very much.

jsolderitsch commented 3 years ago

Created pull request successfully, I think.