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

Some examples using DroneKit and Python to fly the DJI drones... #36

Closed
The1only opened this issue Dec 3, 2020 · 85 comments
Closed

Some examples using DroneKit and Python to fly the DJI drones... #36

The1only opened this issue Dec 3, 2020 · 85 comments

Comments

@The1only
Copy link
Collaborator

The1only commented Dec 3, 2020

##Two somewhat complex example that works is this:

At the moment I do not use TimeLining for absolute motion, so the drone will fly somewhat strange, as the PID in RosettaDrone2 is not tuned, this will be fixed, but there are some yaw issues I need, that complicate things.
HOWEVER, all the motion functionality is supposed to work.

The goal is that everything you can do with QGC or DroneKit and a Mavlink based drone, you should be able to do with any DJI-Mobile SDK supported drone.
All the Mavproxy and other Mavlink tools work.

ALWAYS test with Ardupilot SITL first, then with RosettaDrone2...

Send a velocity command with +x being NOTRH of the drone.

def send_global_ned_velocity(self, vx, vy, vz, yaw):
msg = self.vehicle.message_factory.set_position_target_global_int_encode(
0, # time_boot_ms (not used)
0, 0, # target system, target component
mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, # frame
0b0000011111000111, # type_mask (only speeds enabled)
0, 0, 0, # x, y, z positions (not used)
vx, vy, vz, # N, E, D velocity in m/s
0, 0, 0, # x, y, z acceleration (not supported yet, ignored in GCS_Mavlink)
0,float(yaw)) # yaw, yaw_rate (not supported yet, ignored in GCS_Mavlink)
self.vehicle.send_mavlink(msg)

# Send a velocity command with +x being the heading of the drone.
# For the RosettaDrone/DJI we can use yaw_rate... but then we breake Adupilot/PX4 compatibility...   
def send_local_velocity(self, vx, vy, vz,yaw):
    msg = self.vehicle.message_factory.set_position_target_local_ned_encode(
        0,
        0, 0,
        mavutil.mavlink.MAV_FRAME_BODY_OFFSET_NED,
        0b0000011111000111, # Following ( 1 is mask OUT): yaw vel, yaw pos, force not accell, az,ay,ax, vz,vy,vx, pz,py,px 
        0, 0, 0,
        vx, vy, vz, # speed forward, right, down...
        0, 0, 0,
        0,float(yaw))  # yaw rate in radians/s...  
    self.vehicle.send_mavlink(msg)
    self.vehicle.flush()
@The1only
Copy link
Collaborator Author

The1only commented Dec 4, 2020

PS: If you use the GOTO function in QGC you MUST move more than 50cm or it will ignore the command (a DJI thing).

@danammeansbear
Copy link

This might sound trivial but could you make a basic tutorial for this ? once you have rosetta drone working and are able to do a QGC mission, where would i start to use this? my goal is to add a python VoiceBot to automatically handle take off, landing, and assignment of missions.

@The1only
Copy link
Collaborator Author

The1only commented Dec 7, 2020 via email

@robbiedood
Copy link
Contributor

Thanks @The1only ,it's a very useful tutorial on controlling drone using python.
Could you add an even simpler case: change arming status and takeoff the drone ?
We are trying to take off the drone using command line (with mavlink & mavros) but keep getting error, so are considering use python to solve the problem.

Best,
-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Dec 17, 2020

All the information about using the Python DroneKit to control RosettaDrone2 is here:

https://dronekit-python.readthedocs.io/en/latest/

And this very nice class that explains everything in detail:

https://www.udemy.com/course/drone-programming-primer-for-software-development/

It will eventually be 100% Mavlink compatible, so wether you fly DJI or a Mavlink drone it should be the same.
There are some limitations at the moment, but work in progress.

@The1only
Copy link
Collaborator Author

The1only commented Dec 17, 2020

Ahhhh I know you're problem, you MUST unlock the system ( for safety) hitt the small lock button up on the right side, when it is white, THEN you can take off.... Just to prevent accidental takeoffs.

And PS: It is always smart to enter the simulation mode, and tese that everything works before actually flying. Just hit the sim button and take off... :-)

@adpmdrones
Copy link

adpmdrones commented Dec 17, 2020

Hi All,

following a very simple python script that connects to RosettaDrone and print out some vehicle parameters:

Usage:
python rosetta_drone.py --connect=udp:your_gcs_ip_address:14550

your_gcs_ip_address is the address of the computer where the script is running

I'll post also a more complex script with some commands like takeoff , starting a mission and so on

Ciao

/Luca

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from dronekit import connect, VehicleMode
import time
import argparse
import datetime

#Set up option parsing to get connection string                                                                                                                                                                   $parser = argparse.ArgumentParser(description='Print out vehicle state information. Connects to SITL on local PC by default.')
parser.add_argument('--connect',
                   help="vehicle connection target string. If not specified, exit.")
args = parser.parse_args()

connection_string = args.connect
connection_drone_id = args.uavid
sitl = None

#Start SITL if no connection string specified
if not connection_string or not connection_drone_id:
        print("Pls specify the connect parameters (--connect)")
        exit()

# Connect to the Vehicle.
#   Set `wait_ready=True` to ensure default attributes are populated before `connect()` returns.
print("\nConnecting to vehicle on: %s" % connection_string)
vehicle = connect(connection_string, wait_ready=True)

cmds = vehicle.commands
cmds.download()
cmds.wait_ready()

vehicle.wait_ready('autopilot_version')

##########
# Start
##########
while True:
        print vehicle.battery.level
        print vehicle.system_status.state
        print vehicle.armed
        print vehicle.heading
        print vehicle.groundspeed
        print vehicle.gps_0.fix_type
        print vehicle.gps_0.satellites_visible
        print vehicle.location.global_frame.lat
        print vehicle.location.global_frame.lon
        print vehicle.location.global_frame.alt
        print vehicle.heading
        print vehicle.groundspeed
        print vehicle.velocity[2]
        print vehicle.home_location.lat
        print vehicle.home_location.lon
        print vehicle.home_location.alt
        print vehicle.commands.next
        print vehicle.commands.count

@The1only
Copy link
Collaborator Author

Perfekt, I work round the clock to get the mission planning working. The conversion from Mavlink to DJI and back is almost ready.

@danammeansbear
Copy link

danammeansbear commented Dec 17, 2020 via email

@adpmdrones
Copy link

Perfekt, I work round the clock to get the mission planning working. The conversion from Mavlink to DJI and back is almost ready.

Awesome!!!

@robbiedood
Copy link
Contributor

robbiedood commented Dec 18, 2020

We are stuck in change mode from Stabilize to GUIDED. (by using the command vehicle.mode = VehicleMode("GUIDED"))
We've unlocked the safety by clicking the top-right icon, making it white.

To our knowledge, drone can not be armable without going to GUIDED mode.
Is there anyway to set the mode to GUIDED, maybe inside rosettadrone ?

Hope to hear your expertise.

Best,
-- Luke

ps: we are testing DJI mini.

@The1only
Copy link
Collaborator Author

The1only commented Dec 18, 2020 via email

@robbiedood
Copy link
Contributor

robbiedood commented Dec 18, 2020

Thanks for your persistently kind help, @The1only . By ignore mode change and arm check, we are able to takeoff !
To help more newbie folks, we paste the simple takeoff script below:

===

# hello world example: Takeoff your drone to a targetAltitude. 
# Advice: better to remove drone propellers before executing the script

from dronekit import connect
import time

vehicle = connect('udpin:hostip:port', wait_ready=True)
vehicle.wait_ready('autopilot_version')
targetAltitude = 1.5  # in meter
vehicle.simple_takeoff(targetAltitude)

while True:
    print(" Altitude: ", vehicle.location.global_relative_frame.alt)
    if vehicle.location.global_relative_frame.alt>=targetAltitude*0.95:
        print "Reached target altitude"
        break
    time.sleep(1)

We are working on virtual joytick and a simple control feature based on your example.

Best,
-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Dec 19, 2020

PS: remember that if you hit the SIM button on startup you can take off and fly like this without actually taking off. The SIM button enables the built inn DJI HITL module. The drone must be rebooted after using the Simulation mode.

@robbiedood
Copy link
Contributor

robbiedood commented Dec 19, 2020

Nice to know the feature !
BTW, was wondering if you know how to construct a mavlink msg for LANDING ? So far we know it may require:

mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT_INT, mavutil.mavlink.MAV_CMD_NAV_LAND

inside the mavlink packet.

If you know any help manual on mavlink msg construction, please kindly let us know.

Thanks,
-- Luke

@The1only
Copy link
Collaborator Author

def return_home_and_land(self):
    # Send Drone home and land...        
    print("Waiting for drone to enter RTL flight mode")
    self.vehicle.mode = VehicleMode("RTL")
    time.sleep(5)
    while not self.vehicle.mode.name == 'RTL':
        time.sleep(0.5)

    print("Waiting for drone to return to landing")
    while self.vehicle.armed is True:
        print("Current Altitude: %f" % self.vehicle.location.global_relative_frame.alt)
        time.sleep(1.0)
    
    print("Landed...")

def land(self):
    print("Now let's land")
    self.vehicle.mode = VehicleMode("LAND")
    time.sleep(5)

    print("Waiting for landing")
    while self.vehicle.mode == 'LAND' and self.vehicle.armed is True:
        print("Current Altitude: %f" % self.vehicle.location.global_relative_frame.alt)
        time.sleep(1)

    print("Landed...")

@The1only
Copy link
Collaborator Author

In QGC you can also point and click on the location you want the drone to "goto" and it will.

@robbiedood
Copy link
Contributor

robbiedood commented Dec 19, 2020

The problem we met is VehicleMode doesn't take effect. We've tested multiple VehicleMode such as GUIDED, LAND, but none of them is successfully set.

Alternatively, vehicle.send_mavlink(msg) works. Since Rosetta Drone has MAV_CMD dictionary, so maybe we could send command to corresponding mission, s.t. MAV_CMD_NAV_LAND = 21;

Hope to hear your expertise.

Best,
-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Dec 19, 2020

Hmm strange I have been using this code for over one year now without issues. Let me look into it.

No works fine, both RTL and LAND commands are OK.

If you are used to PX4 or Ardupilot, do not get too hooked up in how the mode changes work, DJI does this totally different. The DJI drone itself controls mode changes, so the RosettaDrone convert mode changes to commands, like land or return to launsh. You can not directly SET a mode change.

Also DJI handles RTL strange if you do not fly more than 10 meters or so from takeoff, then they simply land I've noticed,

@robbiedood
Copy link
Contributor

Thanks for your prompt reply.
In the meantime, we will also log the behavior inside doInBackground of MainActivity.java.
Hope to print out msg_cmd.command for the analysis.

@The1only
Copy link
Collaborator Author

It's allready there, just select the LOGCAT windows and enter MAV in the text window and select Verbose...
You will the see all you're commands.

@robbiedood
Copy link
Contributor

robbiedood commented Dec 19, 2020

We found that MAV_CMD_DO_SET_MODE cause the issue, so we logcat it:

sysid:255 compid:0 param1:1.0 param2:9.0 param3:0.0 param4:0.0 param5:0.0 param6:0.0 param7:0.0 command:176 target_system:1 target_component:0 confirmation:0

Then Rosetta Drone executes changeFlightMode((int) msg_cmd.param1);

That's weird, param1 is 1.0 (it's the altitude); But param2 is 9, which seems matches LAND code better.
Once we modify the line to changeFlightMode((int) msg_cmd.param2);, Landing works!

Hope to hear your expertise on the parameter discrepancy. Does it cause by different mavlink protocol used in different DJI model ?

-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Dec 19, 2020

Can you provide a short test case that recreates this problem?
As you know there are two different MAVlink commands for changing the mode, both end up doing the same.
Maybe there is something there. The long command 176 uses parameter 1, the command 11 uses parameter 2. However, in RosettaDrone we use parameter 3 (Custom Mode). This goes all the way back but might need to change.

https://mavlink.io/en/messages/common.html

The only modes that will have any effect are these:
AUTO
BRAKE
RTL
LAND

And at the moment the only ones that are confirmed to work is:
RTL
LAND

As we still work on the waypoint functionality.
All other modes the Drone handles by itself, nothing we can do. So for compatibility, you would still put them in you're script, but ignore the response for RosettaDrone. This way you can fly complex missions on both DJI and a MAVlink drone without changing the code. Works fine for me.

@robbiedood
Copy link
Contributor

The python code of dronekit is below. VehicleMode("LAND") send command 176 to RosettaDrone, and RosettaDrone uses command 176 to do the case MAV_CMD_DO_SET_MODE, and then changeFlightMode((int) msg_cmd.param2) needs to use to set proper mode for RosettaDrone.

The long command is: sysid:255 compid:0 param1:1.0 param2:9.0 param3:0.0 param4:0.0 param5:0.0 param6:0.0 param7:0.0 command:176 target_system:1 target_component:0 confirmation:0

Not sure why LAND parameter (9.0) is not put in param 1. It's put in 2 for Custom Mode.

    def land(self):
        print("Now let's land")
        self.vehicle.mode = VehicleMode("LAND") 
        time.sleep(5)

        print("Waiting for landing")
        while self.vehicle.mode == 'LAND' and self.vehicle.armed is True:
            print("Current Altitude: %f" % self.vehicle.location.global_relative_frame.alt)
            time.sleep(1)

        print("Landed...")

@The1only
Copy link
Collaborator Author

You are on to something, thank you.

On my MAC with all the latest modules, I get the same issue as you, that is, the Mode change command uses parameter 2, as it should. When I change the code to use parameter 2 rather than 1 then all the mode changes work again and I can take off and land.
However on my main Linux system that pulled modules 6 months ago. I need to use parameter 1.
I will check the DroneKit issue list, they may have fixed this.

Greate catch...

@The1only
Copy link
Collaborator Author

I used a setup from a Udemy class years ago...
I will check-in the fix and update all my systems.

@The1only
Copy link
Collaborator Author

The1only commented Dec 19, 2020 via email

@robbiedood
Copy link
Contributor

robbiedood commented Dec 20, 2020

Thanks for your fix, @The1only !

We are working on velocity control, regards to your example "Send a velocity command with +x being the heading of the drone." on the top of the discussion thread:

What is int(x10000000), int(y10000000), float(z) ? Our python can not recognize x10000000 and y10000000.

And the line: speed, speed, 1.0, # x, y, z velocity in m/s, why you give 1.0 m/s for the z direction ?

Best,
-- Luke

@adpmdrones
Copy link

We're experiencing the same issues:

from python script, we're able to takeoff and go to specified lat,lon

We've also an issue with goto command, the altitude will change to 1.2m

We're unable to issue command like RTL or LAND too

@The1only
Copy link
Collaborator Author

The1only commented Dec 21, 2020

Hmm We just fixed RTL did we not???
I installed everything fresh yesterday evening and it was working just fine.
It seems some DroneKit versions uses parameter 1 and some uses the correct parameter 2
Make sure you are on the "Work" branch

Sorry for the bad example, I updated it now.

@adpmdrones
Copy link

Ps: I have also tested the Mavproxy, it also works. Moust interesting is the abillity to split Mavlink streams, and the command line GCS.

I used mavproxy too for splitting mavlink stream to qgcs and my REST API scripts

@adpmdrones
Copy link

adpmdrones commented Dec 25, 2020

In this tread they mention POST also, did you test that?

https://discuss.ardupilot.org/t/mavlink-to-rest-api/51660

I've tested sending RTH change mode (the same I use in my python script) but Rosetta Drone does not respond

{
  "header": {
    "system_id": 1,
    "component_id": 1,
    "sequence": 0
  },
  "message": {
    "type":"COMMAND_LONG",
    "param1":1.0,
    "param2":6.0,"param3":0.0,"param4":0.0,"param5":0.0,"param6":0.0,"param7":0.0,
    "command":{
      "type":"MAV_CMD_DO_SET_MODE"
    },
    "target_system":0,
    "target_component":0,
    "confirmation":0
  }
 }

@The1only
Copy link
Collaborator Author

The1only commented Jan 13, 2021 via email

@The1only
Copy link
Collaborator Author

The1only commented Jan 13, 2021 via email

@The1only
Copy link
Collaborator Author

The1only commented Jan 13, 2021 via email

@robbiedood
Copy link
Contributor

Dear Dronekit friends,

We are trying to use DroneKit's Gimbal function to change the pitch of gimbal, but not very sure if it is compatible with rosettadrone.

I was wondering if someone tried DroneKit to control camera gimbal. Hope to know what kind of DJI model works.

-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Jan 26, 2021 via email

@robbiedood
Copy link
Contributor

robbiedood commented Jan 26, 2021

Great tips @The1only ! We do find below important lines in MAVLinkReceiver which can map to DroneKit Servo control

case MAV_CMD_DO_SET_SERVO:
    mModel.do_set_Gimbal(msg_cmd.param1, msg_cmd.param2);
    break;

As we know, do_set_Gimbal is implemented in DroneModel, showing that channel 9 is for pitch control. (8 is for yaw)

We are working on Mavic. So just curious about why you said in #14 Mavic might have issue on controlling gimbal, is it fundamentally restricted by DJI SDK ?

@robbiedood
Copy link
Contributor

Update @The1only : Good news, we are able to make camera looking down (i.e. bird's view) by changing the servo position between 1500 and 1000.

However, we got issue on making the camera looking up. We changed the servo position up to 2000 but there is no response.

We are testing DJI mavic mini, codes are below:

msg = self.vehicle.message_factory.command_long_encode(
0, 0, # target_system, target_component
mavutil.mavlink.MAV_CMD_DO_SET_SERVO, # command
0, # confirmation
9, # servo number
position, # servo position between 1000 and 2000
0, 0, 0, 0, 0) # param 3 ~ 7 not used

-- Luke

@The1only
Copy link
Collaborator Author

The1only commented Jan 26, 2021 via email

@robbiedood
Copy link
Contributor

robbiedood commented Jan 26, 2021

Thanks for your reply so that we are able to realize a 5.5 value corresponds to 1 degree tilt.

@patrickelectric
Copy link

Hi, I'm the creator of mavlink2rest, I'm a bit lost, is there any integration for it in this project, is there any work in progress for that or is this an acceptable contribution ?

@The1only
Copy link
Collaborator Author

The1only commented Feb 22, 2021 via email

@avncalst
Copy link

avncalst commented May 2, 2021

Just had a successful test flight with my mavic mini controlled by a artificial intelligence python script to avoid obstacles. First results are promising. Congratulations to "The1only" for this excellent Rossetadrone2 work.

@fajrulfx
Copy link

Dear Dronekit friends,

I've successfully connect Rosetta Drone and Dronekit, and use python script to interact with my Drone (Mavic Mini). It works with simple_takeoff command, but the altitude of my drone is stuck at 1 m although I set a higher altitude. Other command like simple_goto also not working, my drone doesn't move anywhere.

Any idea how to solve this issue? Thanks.

@Newguyonthefield
Copy link

This might sound trivial but could you make a basic tutorial for this ? once you have rosetta drone working and are able to do a QGC mission, where would i start to use this? my goal is to add a python VoiceBot to automatically handle take off, landing, and assignment of missions.

Did you find the way? i wanna do something like that with a Mavic Mini

@Newguyonthefield
Copy link

I would love to have a little guide for that. I’m trying to connect my Mavic Mini

@The1only
Copy link
Collaborator Author

The1only commented Dec 28, 2021 via email

@kripper
Copy link
Collaborator

kripper commented Jan 9, 2023

Just had a successful test flight with my mavic mini controlled by a artificial intelligence python script to avoid obstacles. First results are promising. Congratulations to "The1only" for this excellent Rossetadrone2 work.

Hi @avncalst, I saw your video on YouTube.
Which repo are you using? I saw some reports of problems dealing with the video stream. Have they been fixed?

I'm interested in writing AI scripts for the mini SE.

@The1only
Copy link
Collaborator Author

The1only commented Jan 9, 2023 via email

@avncalst
Copy link

avncalst commented Jan 9, 2023

Hi @kripper my code can be found on GitHub https://github.com/avncalst/drone_cnn/tree/master/rosetta. I had no problems video streaming using gstreamer.

@kripper
Copy link
Collaborator

kripper commented Jan 9, 2023

Hi @kripper my code can be found on GitHub https://github.com/avncalst/drone_cnn/tree/master/rosetta. I had no problems video streaming using gstreamer.

Thanks. I will replicate your environment.
Are you using The1only's repo?

I'm asking because there is a fork with additional enhancements for Mini 2 here:
https://github.com/m4xw/rosettadrone_mini2

@avncalst
Copy link

avncalst commented Jan 9, 2023

I compiled with Android Studio "The 1 only's" repo june 2021. So the enhancements for the Mini 2 were not yet available

@paw-krz
Copy link

paw-krz commented Jan 26, 2023

Do you know if it's possible to control attitude (roll, pitch, yaw)? I tried code from dronekit examples (https://github.com/dronekit/dronekit-python/blob/master/examples/set_attitude_target/set_attitude_target.py), but it does't work, nothing changes

@kripper
Copy link
Collaborator

kripper commented Apr 8, 2023

Closing. Discussion continues here: #133

@kripper kripper closed this as completed Apr 8, 2023
@kripper
Copy link
Collaborator

kripper commented Apr 12, 2023

I compiled with Android Studio "The 1 only's" repo june 2021. So the enhancements for the Mini 2 were not yet available

Hi @avncalst, you were probably using a MINI (not MINI SE). Good to know that video streaming works with the MINI.
Could you please test video streaming using latests version of RosettaDrone?

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

10 participants