A modern alternative to the robomaster SDK
Project description
Dronemaster
a modern alternative to the Robomaster SDK for controlling DJI Tello EDU drones.
This sdk is a result of my frustration with the official robomaster sdk and how other libraries handle specific things.
It is based on the official tello 3.0 protocol documentation, but is extended with undocumented features that were discovered by experiments.
It harnesses the power of pythons async capabilities and also allows to control multiple drones at once.
Basics
This section describes how the drone works, so you are able to efficiently work with this sdk and avoid common pitfalls.
Firstly the drone can operate in two basic modes which can be selected with the slider on the side of the extension module:
ap-mode: the drone connects to a preexisting wifista-mode: the drone creates its own wifi
When operating in ap-mode and using static dhcp entries, the drone sometimes receives a wrong ip
The protocol is based on udp, so packet-loss due to an unstable connection might lead to timeouts (this sdk tries its best to mitigate this, but it is not always successful).
Sometimes the error is not due to the programmer or the sdk, but simply due to the drone itself.
The drone has been observed as reporting ok to a takeoff-request but then staying firmly on the ground even with enough charge, so also account for such failures.
Specs
The drone is equipped with some sensors that might be interesting.
- gyro: to measure roll, pitch and yaw in degrees
- accelerometer: to measure the acceleration in x, y and z direction relative to the current orientation. Note that you should remove gravity from these by using the current orientation.
- barometer: to estimate the elevation of the drone in meters
- downwards time-of-flight sensor: to accurately measure the height above ground
- forwards time-of-flight sensor: to measure the distance to an object (located on the extension module)
- internal temperature: measures the internal temperature (above ~100°C it no longer takes off and above ~105°C it shuts down)
- front camera: positioned at an angle of ~13° downwards that records 720P or 480P in H264
- downwards camera: black and white camera without an IR-filter
- velocity calculation: the internal chip calculates the velocity in x, y and z direction in global space. It uses the downwards camera, so if there is not enough detail in its picture these speeds are 0
- mission-pad detection: this is currently not usable with this sdk
Installing
To install this sdk, simply use pip
pip install dronemaster
or when using the simulator
pip install dronemaster[simulator]
Simulator
This sdk provides a crude simulator so anybody without a drone is able to test parts of their program.
First run pip install dronemaster[simulator] to install the required dependencies.
Then start the simulator with python3 -m dronemaster [IP] where [IP] is the ip-address to listen on.
You can now connect to your own ip as if it would be a drone.
Api overview
The exact behavior of each function is documented in docstrings. This section should only give a very basic overview.
Logging
The sdk uses the python logging module, so you are able to configure it to your liking.
- DEBUG logs exactly what raw packets are sent and received (even repeated ones)
- INFO only logs successful commands and their response
- WARN logs unexpected data
- ERROR logs invalid answers to commands and timeouts
To access the logger, use dronemaster.command_logger
Connecting
First, create the dronemaster.Drone object with the target-ip.
Then call the drone.initialize() function to connect with it.
You should periodically call the drone.keepalive() function to stop the drone from automatically landing.
Flying
To control the flight, use the flight object received by drone.flight.
To learn more, visit the examples or inspect it in your IDE
Extension module
Access the top-rgb-led via drone.rgb and the matrix via drone.matrix
Configuring the video
To configure the video (like resolution, fps, bitrate and selected camera) use drone.video
Configuring the drone
You can configure the drone by using functions like drone.set_own_wifi(ssid, passwd) or drone.set_connecting_wifi(ssid, passwd)
Receiving state information
The last state object is always available at drone.last_state
Register a callback to be called on a new packet with drone.state_subscribe(async_callback) where async_callback is an async function which receives one parameter with type dronemaster.DroneState
Some useful commands
After establishing the connection, you can use many features like:
drone.state_subscribe(...)to subscribe to the drones state (seedronemaster.DroneState)drone.serial_number()to get the serial numberdrone.battery()to get the current battery chargedrone.tof()to read the current heightdrone.ext_tof()to read the distance forwardsdrone.keepalive()call this to keep the drone in the air without sending other commandsdrone.reboot()reboot the drone and disconnect itdrone.matrix.set_brightness(...)set the brightness of the led matrixdrone.matrix.set_pattern(...)to set the pattern of the led matrixdrone.rgb.set(...)sets the color of the top leddrone.rgb.pulse(..., ...)pulses the top led in the specific colordrone.rgb.flash(..., ..., ...)flashed the top led between the two colorsdrone.video.streamon()to enable the video streamdrone.video.streamoff()to stop the video streamdrone.video.downvision(...)to switch the used cameradrone.video.setfps(...)to set the cameras fpsdrone.video.setbitrate(...)to set the cameras bitrate in Mbpsdrone.video.setresolution(...)to set the front-facing cameras resolutiondrone.flight.takeoff()to takeoffdrone.flight.land()to landdrone.flight.rc(..., ..., ..., ...)to set roll, pitch, yaw and throttledrone.flight.stop()to stop moving and start hoveringdrone.flight.emergency()to stop all motors
and many more...
Examples
These are the two most important ones. See more here
Simple flight
import asyncio
import dronemaster
import logging
logging.basicConfig(format="%(asctime)s [%(name)s] [%(levelname)s] %(message)s") # dronemaster uses the logging module internally
dronemaster.command_logger.setLevel(logging.WARNING) # do not log raw commands
# DEBUG logs exactly what commands are sent and received (even repeated ones)
# INFO only logs successful commands and their response
# WARN logs unexpected data
# ERROR logs invalid answers to commands and timeouts
async def main():
# create the drone, but don't connect
ep_drone = dronemaster.Drone("127.0.0.1")
# mark the drone as active and connect to it
await ep_drone.initialize()
serial = await ep_drone.serial_number()
battery = await ep_drone.battery()
print(f"Connected with drone '{serial}' with {battery}%")
ep_flight = ep_drone.flight
# takeoff and wait for completion (up to 20s)
await ep_flight.takeoff()
# fly forwards 20cm
await ep_flight.forward(20, timeout=7)
# land again
await ep_flight.land()
if __name__ == '__main__':
asyncio.run(main())
Video receiving
import asyncio
import dronemaster
import cv2
import logging
logging.basicConfig(format="%(asctime)s [%(name)s] [%(levelname)s] %(message)s") # dronemaster uses the logging module internally
dronemaster.command_logger.setLevel(logging.WARNING) # do not log raw commands
async def main():
# create the drone, but don't connect
ep_drone = dronemaster.Drone("127.0.0.1")
# mark the drone as active and connect to it
await ep_drone.initialize()
serial = await ep_drone.serial_number()
battery = await ep_drone.battery()
print(f"Connected with drone '{serial}' with {battery}%")
await ep_drone.video.set_video_port(11112) # per default, port 11111 is used
await ep_drone.video.streamon()
# uncomment to use the downwards black and white camera
#await ep_drone.video.downvision(True)
# listen on all ips on port 11112
# the drone sends the video in H264 format with an I-Frame every few seconds
cap = cv2.VideoCapture("udp://0.0.0.0:11112")
while True:
if cap.isOpened():
ret, frame = cap.read()
cv2.imshow('live stream', frame)
await asyncio.sleep(1/60) # important to allow the sdk to read new commands
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
await ep_drone.video.streamoff()
if __name__ == '__main__':
asyncio.run(main())
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dronemaster-1.2.0.tar.gz.
File metadata
- Download URL: dronemaster-1.2.0.tar.gz
- Upload date:
- Size: 29.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b53d5f43fd4955f3b0d6214ef6a6d53c33024b28ffbf7e01b7edf4df3d2f1aee
|
|
| MD5 |
d79d616aea2814f7c482391421121cc4
|
|
| BLAKE2b-256 |
4f7e50632d7e4118c41b86d19f229d2c462455249438b17220a67a0b26dec623
|
File details
Details for the file dronemaster-1.2.0-py3-none-any.whl.
File metadata
- Download URL: dronemaster-1.2.0-py3-none-any.whl
- Upload date:
- Size: 28.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.10.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
27bda34e4a32c997d0c61f0e25c41b70faaf6cc683a97e9cf4660baf9b1ff12d
|
|
| MD5 |
ba39a6738f5d59a980dd1ce02e972266
|
|
| BLAKE2b-256 |
cb3838f7aca20fd883c3147081896f5072617b51ccdcadd3952b87f82d4de6a8
|