mavlink / MAVSDK-Python

MAVSDK client for Python.
https://mavsdk.mavlink.io
BSD 3-Clause "New" or "Revised" License
328 stars 221 forks source link

simulation with mavsdk python #622

Open naorwaiss opened 1 year ago

naorwaiss commented 1 year ago

hi, i try to run simulation with mavsdk python

the script is : import asyncio from mavsdk import System from mavsdk.offboard import PositionNedYaw import math

async def arm_and_takeoff(drone, altitude): await drone.action.set_takeoff_altitude(altitude) await drone.offboard.set_position_ned(PositionNedYaw(0.0, 0.0, -altitude, 0.0)) await drone.offboard.start() await asyncio.sleep(1) await drone.action.arm() await asyncio.sleep(1) await drone.action.takeoff() print("Drone is armed and taking off...")

async def move_forward(drone, distance):

Calculate target position based on current position

current_position = await drone.telemetry.position()
x = current_position.longitude_deg
y = current_position.latitude_deg
z = current_position.absolute_altitude_m
target_x = x + distance

await drone.offboard.set_position_ned(PositionNedYaw(0.0, distance, -z, 0.0))
print(f"Moving forward by {distance} meters...")

async def land(drone): await drone.action.land() print("Drone is landing...")

async def main(): altitude = float(input("Enter desired altitude (in meters): "))

drone = System()
await drone.connect(system_address="udp://:14540")

await arm_and_takeoff(drone, altitude)

# Wait for takeoff and print current coordinates
await asyncio.sleep(5)  # Allow time for takeoff
current_position = await drone.telemetry.position()
print(
    f"Current Coordinates: Lat={current_position.latitude_deg}, Lon={current_position.longitude_deg}, Alt={current_position.absolute_altitude_m}")

distance = float(input("Enter distance to move forward (in meters): "))

await move_forward(drone, distance)
await asyncio.sleep(5)  # Allow time for movement

land_confirmation = input("Enter 'land' to initiate landing: ")
if land_confirmation.lower() == 'land':
    await land(drone)
else:
    print("Landing aborted.")

if name == "main": asyncio.run(main())

the drone take off to the attitude command but then the code fall Drone is armed and taking off... Traceback (most recent call last): File "/home/naor/PycharmProjects/drone-camera/fly_coordinate.py", line 57, in asyncio.run(main()) File "/usr/lib/python3.8/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete return future.result() File "/home/naor/PycharmProjects/drone-camera/fly_coordinate.py", line 41, in main current_position = await drone.telemetry.position() TypeError: object async_generator can't be used in 'await' expression

can some one helpm me here ?

JonasVautherin commented 1 year ago

Did you check what line 41 is?

I believe this is wrong:

current_position = await drone.telemetry.position()

drone.telemetry.position() returns an async generator, and you can't "await" for it. It works like this:

async for position in drone.telemetry.position():
    # do something with position
naorwaiss commented 1 year ago

thanks

i change little bit the script /

import asyncio
from mavsdk import System
from mavsdk.offboard import PositionNedYaw
from convert_coordinates import convert_gps_to_cartesian
import time

async def arm_and_takeoff(drone, altitude):
    await drone.action.set_takeoff_altitude(altitude)
    await drone.offboard.set_position_ned(PositionNedYaw(0.0, 0.0, -altitude, 0.0))
    await drone.offboard.start()
    await asyncio.sleep(1)
    await drone.action.arm()
    await asyncio.sleep(1)
    await drone.action.takeoff()
    print("Drone is armed and taking off...")

async def move_forward(drone, distance):
    try:
        current_position = await drone.telemetry.position()
        x, y, z = convert_gps_to_cartesian(
            current_position.latitude_deg,
            current_position.longitude_deg,
            current_position.absolute_altitude_m,
            home_latitude_deg,
            home_longitude_deg,
            home_altitude_m
        )

        target_x = x + distance
        await drone.offboard.set_position_ned(PositionNedYaw(0.0, distance, -z, 0.0))
        print(f"Moving forward by {distance} meters...")
    except Exception as e:
        print(f"Error moving forward: {e}")

async def land(drone):
    try:
        await drone.action.land()
        print("Drone is landing...")
    except Exception as e:
        print(f"Error landing: {e}")

async def telemetry_loop(drone):
    while True:
        try:
            current_position = await drone.telemetry.position()
            x, y, z = convert_gps_to_cartesian(
                current_position.latitude_deg,
                current_position.longitude_deg,
                current_position.absolute_altitude_m,
                home_latitude_deg,
                home_longitude_deg,
                home_altitude_m
            )
            print(f"Current Coordinates: X={x}, Y={y}, Z={z}")
            await asyncio.sleep(1)  # Sleep for 1 second
        except Exception as e:
            print(f"Error in telemetry loop: {e}")

async def main():
    altitude = float(input("Enter desired altitude (in meters): "))

    drone = System()

    try:
        await drone.connect(system_address="udp://:14540")

        await arm_and_takeoff(drone, altitude)

        asyncio.create_task(telemetry_loop(drone))  # Start telemetry loop concurrently

        await asyncio.sleep(5)  # Allow time for takeoff

        distance = float(input("Enter distance to move forward (in meters): "))

        await move_forward(drone, distance)
        await asyncio.sleep(5)  # Allow time for movement

        land_confirmation = input("Enter 'land' to initiate landing: ")
        if land_confirmation.lower() == 'land':
            await land(drone)
        else:
            print("Landing aborted.")
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    # Replace these values with the actual home location of your drone
    home_latitude_deg = 0.0
    home_longitude_deg = 0.0
    home_altitude_m = 0.0

    asyncio.run(main())

this is the problem : Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression Error in telemetry loop: object async_generator can't be used in 'await' expression

it run endlesly...

JonasVautherin commented 1 year ago

It's very hard to read your post with the code copy-pasted like that, but I still see:

current_position = await drone.telemetry.position()

As said above, drone.telemetry.position() (and all the subscriptions) are async generators, and you can't await them. You have to run an async for on them. You may want to read a bit about asyncio, which is part of the Python standard library. I think it should help.

naorwaiss commented 1 year ago

Thank you!

I tried to use the new position generator, but I still couldn't get the drone to move to a given location. There are no exceptions, or errors in the logfile of the drone. When using GroundControl I am able to move it to a given location.

import asyncio
from mavsdk import System
from mavsdk.mission import MissionItem
from mavsdk.offboard import PositionNedYaw, OffboardError
import time

async def arm_and_takeoff(drone, altitude):
    await drone.action.set_takeoff_altitude(altitude)
    await move(drone, 0.0, 0.0, -altitude)
    await drone.action.arm()
    await asyncio.sleep(1)
    await drone.action.takeoff()
    print("Drone is armed and taking off...")

async def move(drone, target_north_m, target_east_m, target_down_m):
    try:
        new_position = PositionNedYaw(target_north_m, target_east_m, target_down_m, 0.0)
        await drone.offboard.set_position_ned(new_position)
        await asyncio.sleep(1)
    except Exception as e:
        print(f"Failed moving {e}")

async def land(drone):
    try:
        await drone.action.land()
        print("Drone is landing...")
    except Exception as e:
        print(f"Error landing: {e}")

async def telemetry_loop(drone):
    async for current_position in drone.telemetry.position_velocity_ned():
        try:
            position = current_position.position
            yield position.north_m, position.east_m, position.down_m
        except Exception as e:
            print(f"Error in telemetry loop: {e}")

async def main():
    # Your main control logic here
    altitude = float(input("Enter desired altitude (in meters): "))

    drone = System()

    try:
        await drone.connect(system_address="udp://:14540")

        await arm_and_takeoff(drone, altitude)
        await asyncio.sleep(10)  # Allow time for takeoff

        print(">> Waiting for GPS")
        async for state in drone.telemetry.health():
            if state.is_global_position_ok:
                break
        print(">> Found GPS")

        async for north_m, east_m, down_m in telemetry_loop(drone):
            distance_calculator = {
                "north": lambda target_distance: (
                    north_m + target_distance, east_m, down_m),
                "east": lambda target_distance: (
                    north_m, east_m + target_distance, down_m),
                "up": lambda target_distance: (
                    north_m, east_m, down_m + target_distance),
            }
            command = input(f"Enter direction to move {list(distance_calculator.keys())} or 'land' to land: ")
            if command == "land":
                await land(drone)
                await asyncio.sleep(5)  # Allow time for movement
                break
            else:
                distance = float(input("Enter distance to move (in meters): "))
                target_north_m, target_east_m, target_down_m = distance_calculator[command](
                    distance)
                print(
                    f"Moving from ({north_m}, {east_m}, {down_m}) -> ({target_north_m}, {target_east_m}, {target_down_m})")
                await move(drone, target_north_m, target_east_m, target_down_m)
                await asyncio.sleep(5)  # Allow time for movement
    except Exception as e:
        print(f"Error: {e}")

if __name__ == "__main__":
    asyncio.run(main())
naorwaiss commented 1 year ago

After more debugging, we found that the drone.telemetry.position_velocity_ned() generator doesn't update, you need to create it each time anew to get the current position