ardrone_sdk 0.4.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ardrone_sdk-0.4.0/LICENSE +19 -0
- ardrone_sdk-0.4.0/PKG-INFO +54 -0
- ardrone_sdk-0.4.0/README.md +29 -0
- ardrone_sdk-0.4.0/ardrone/__init__.py +3 -0
- ardrone_sdk-0.4.0/ardrone/at.py +169 -0
- ardrone_sdk-0.4.0/ardrone/client.py +73 -0
- ardrone_sdk-0.4.0/ardrone/constant.py +3 -0
- ardrone_sdk-0.4.0/ardrone/drone.py +134 -0
- ardrone_sdk-0.4.0/ardrone/navdata.py +82 -0
- ardrone_sdk-0.4.0/ardrone/network.py +111 -0
- ardrone_sdk-0.4.0/ardrone/video.c +168 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/PKG-INFO +54 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/SOURCES.txt +18 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/dependency_links.txt +1 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/entry_points.txt +2 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/requires.txt +1 -0
- ardrone_sdk-0.4.0/ardrone_sdk.egg-info/top_level.txt +2 -0
- ardrone_sdk-0.4.0/pyproject.toml +39 -0
- ardrone_sdk-0.4.0/setup.cfg +4 -0
- ardrone_sdk-0.4.0/setup.py +9 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2011 Bastian Venthur
|
|
2
|
+
Copyright (c) 2015-2021, Lily Foster <lily@lily.flowers>
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
5
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
6
|
+
the Software without restriction, including without limitation the rights to
|
|
7
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
8
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
9
|
+
subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
16
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
17
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
18
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
19
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ardrone_sdk
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A Python library for controlling the Parrot AR.Drone 2.0 over a network
|
|
5
|
+
Author-email: Lily Foster <lily@lily.flowers>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/lilyinstarlight/python-ardrone
|
|
8
|
+
Project-URL: Tracker, https://github.com/lilyinstarlight/python-ardrone/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: POSIX
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: C
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: Pillow
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
python-ardrone
|
|
27
|
+
==============
|
|
28
|
+
|
|
29
|
+
_**Note: This library is looking for testers and/or maintainers! I have not had access myself to an AR.Drone 2.0 for a while, but there are several important unreleased changes that need testing on actual hardware as well as [stuff that still needs to be done](TODO.md) to make the library more robust. Open a new issue on this repository if you are interested!**_
|
|
30
|
+
|
|
31
|
+
A Python library for controlling the Parrot AR.Drone 2.0 over a network.
|
|
32
|
+
|
|
33
|
+
Usage
|
|
34
|
+
-----
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import ardrone
|
|
38
|
+
|
|
39
|
+
drone = ardrone.ARDrone()
|
|
40
|
+
|
|
41
|
+
drone.takeoff()
|
|
42
|
+
drone.land()
|
|
43
|
+
|
|
44
|
+
print(drone.navdata['demo']['battery'])
|
|
45
|
+
|
|
46
|
+
drone.image.show()
|
|
47
|
+
|
|
48
|
+
drone.halt()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Thanks
|
|
52
|
+
------
|
|
53
|
+
|
|
54
|
+
Thanks to Bastian Venthur for making the beginnings on which this library was based at https://github.com/venthur/python-ardrone!
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
python-ardrone
|
|
2
|
+
==============
|
|
3
|
+
|
|
4
|
+
_**Note: This library is looking for testers and/or maintainers! I have not had access myself to an AR.Drone 2.0 for a while, but there are several important unreleased changes that need testing on actual hardware as well as [stuff that still needs to be done](TODO.md) to make the library more robust. Open a new issue on this repository if you are interested!**_
|
|
5
|
+
|
|
6
|
+
A Python library for controlling the Parrot AR.Drone 2.0 over a network.
|
|
7
|
+
|
|
8
|
+
Usage
|
|
9
|
+
-----
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
import ardrone
|
|
13
|
+
|
|
14
|
+
drone = ardrone.ARDrone()
|
|
15
|
+
|
|
16
|
+
drone.takeoff()
|
|
17
|
+
drone.land()
|
|
18
|
+
|
|
19
|
+
print(drone.navdata['demo']['battery'])
|
|
20
|
+
|
|
21
|
+
drone.image.show()
|
|
22
|
+
|
|
23
|
+
drone.halt()
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Thanks
|
|
27
|
+
------
|
|
28
|
+
|
|
29
|
+
Thanks to Bastian Venthur for making the beginnings on which this library was based at https://github.com/venthur/python-ardrone!
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import socket
|
|
2
|
+
import struct
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
import ardrone.constant
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def f2i(f):
|
|
9
|
+
"""Interpret IEEE-754 floating-point value as signed integer.
|
|
10
|
+
|
|
11
|
+
Arguments:
|
|
12
|
+
f -- floating point value
|
|
13
|
+
"""
|
|
14
|
+
return struct.unpack('i', struct.pack('f', f))[0]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ATCommand(object):
|
|
18
|
+
def __init__(self, host):
|
|
19
|
+
"""
|
|
20
|
+
Open a new AT command socket
|
|
21
|
+
|
|
22
|
+
Parameters:
|
|
23
|
+
host -- destination address
|
|
24
|
+
"""
|
|
25
|
+
self.host = host
|
|
26
|
+
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
27
|
+
|
|
28
|
+
self.seq = 1
|
|
29
|
+
self.interval = 0.2
|
|
30
|
+
|
|
31
|
+
self.lock = threading.Lock()
|
|
32
|
+
self.comwdg_timer = threading.Timer(self.interval, self.comwdg)
|
|
33
|
+
|
|
34
|
+
def halt(self):
|
|
35
|
+
"""
|
|
36
|
+
Halts communication with the drone
|
|
37
|
+
"""
|
|
38
|
+
with self.lock:
|
|
39
|
+
self.comwdg_timer.cancel()
|
|
40
|
+
|
|
41
|
+
def ref(self, takeoff, emergency=False):
|
|
42
|
+
"""
|
|
43
|
+
Basic behaviour of the drone: take-off/landing, emergency stop/reset)
|
|
44
|
+
|
|
45
|
+
Parameters:
|
|
46
|
+
takeoff -- True: Takeoff / False: Land
|
|
47
|
+
emergency -- True: Turn off the engines
|
|
48
|
+
"""
|
|
49
|
+
p = 0b10001010101000000000000000000
|
|
50
|
+
if takeoff:
|
|
51
|
+
p |= 0b1000000000
|
|
52
|
+
if emergency:
|
|
53
|
+
p |= 0b100000000
|
|
54
|
+
self.at('REF', [p])
|
|
55
|
+
|
|
56
|
+
def pcmd(self, progressive, lr, fb, vv, va):
|
|
57
|
+
"""
|
|
58
|
+
Makes the drone move (translate/rotate).
|
|
59
|
+
|
|
60
|
+
Parameters:
|
|
61
|
+
progressive -- True: enable progressive commands, False: disable (i.e.
|
|
62
|
+
enable hovering mode)
|
|
63
|
+
lr -- left-right tilt: float [-1..1] negative: left, positive: right
|
|
64
|
+
rb -- front-back tilt: float [-1..1] negative: forwards, positive:
|
|
65
|
+
backwards
|
|
66
|
+
vv -- vertical speed: float [-1..1] negative: go down, positive: rise
|
|
67
|
+
va -- angular speed: float [-1..1] negative: spin left, positive: spin
|
|
68
|
+
right
|
|
69
|
+
|
|
70
|
+
The above float values are a percentage of the maximum speed.
|
|
71
|
+
"""
|
|
72
|
+
p = 1 if progressive else 0
|
|
73
|
+
self.at('PCMD', [p, float(lr), float(fb), float(vv), float(va)])
|
|
74
|
+
|
|
75
|
+
def ftrim(self):
|
|
76
|
+
"""
|
|
77
|
+
Tell the drone it's lying horizontally.
|
|
78
|
+
"""
|
|
79
|
+
self.at('FTRIM')
|
|
80
|
+
|
|
81
|
+
def zap(self, stream):
|
|
82
|
+
"""
|
|
83
|
+
Selects which video stream to send on the video UDP port.
|
|
84
|
+
|
|
85
|
+
Parameters:
|
|
86
|
+
stream -- Integer: video stream to broadcast
|
|
87
|
+
"""
|
|
88
|
+
# FIXME: improve parameters to select the modes directly
|
|
89
|
+
self.at('ZAP', [stream])
|
|
90
|
+
|
|
91
|
+
def config(self, option, value):
|
|
92
|
+
"""Set configuration parameters of the drone."""
|
|
93
|
+
self.at('CONFIG', [str(option), str(value)])
|
|
94
|
+
|
|
95
|
+
def comwdg(self):
|
|
96
|
+
"""
|
|
97
|
+
Reset communication watchdog.
|
|
98
|
+
"""
|
|
99
|
+
self.at('COMWDG')
|
|
100
|
+
|
|
101
|
+
def aflight(self, flag):
|
|
102
|
+
"""
|
|
103
|
+
Makes the drone fly autonomously.
|
|
104
|
+
|
|
105
|
+
Parameters:
|
|
106
|
+
flag -- Integer: 1: start flight, 0: stop flight
|
|
107
|
+
"""
|
|
108
|
+
self.at('AFLIGHT', [flag])
|
|
109
|
+
|
|
110
|
+
def pwm(self, m1, m2, m3, m4):
|
|
111
|
+
"""
|
|
112
|
+
Sends control values directly to the engines, overriding control loops.
|
|
113
|
+
|
|
114
|
+
Parameters:
|
|
115
|
+
m1 -- Integer: front left command
|
|
116
|
+
m2 -- Integer: front right command
|
|
117
|
+
m3 -- Integer: back right command
|
|
118
|
+
m4 -- Integer: back left command
|
|
119
|
+
"""
|
|
120
|
+
self.at('PWM', [m1, m2, m3, m4])
|
|
121
|
+
|
|
122
|
+
def led(self, anim, f, d):
|
|
123
|
+
"""
|
|
124
|
+
Control the drones LED.
|
|
125
|
+
|
|
126
|
+
Parameters:
|
|
127
|
+
anim -- Integer: animation to play
|
|
128
|
+
f -- Float: frequency in HZ of the animation
|
|
129
|
+
d -- Integer: total duration in seconds of the animation
|
|
130
|
+
"""
|
|
131
|
+
self.at('LED', [anim, float(f), d])
|
|
132
|
+
|
|
133
|
+
def anim(self, anim, d):
|
|
134
|
+
"""
|
|
135
|
+
Makes the drone execute a predefined movement (animation).
|
|
136
|
+
|
|
137
|
+
Parameters:
|
|
138
|
+
anim -- Integer: animation to play
|
|
139
|
+
d -- Integer: total duration in seconds of the animation
|
|
140
|
+
"""
|
|
141
|
+
self.at('ANIM', [anim, d])
|
|
142
|
+
|
|
143
|
+
def at(self, command, params=[]):
|
|
144
|
+
"""
|
|
145
|
+
Encodes and sends AT command
|
|
146
|
+
|
|
147
|
+
Parameters:
|
|
148
|
+
command -- the command
|
|
149
|
+
params -- a list of elements which can be either int, float or string
|
|
150
|
+
"""
|
|
151
|
+
params_str = []
|
|
152
|
+
for p in params:
|
|
153
|
+
if type(p) == int:
|
|
154
|
+
params_str.append('{:d}'.format(p))
|
|
155
|
+
elif type(p) == float:
|
|
156
|
+
params_str.append('{:d}'.format(f2i(p)))
|
|
157
|
+
elif type(p) == str:
|
|
158
|
+
params_str.append('"{:s}"'.format(p))
|
|
159
|
+
|
|
160
|
+
with self.lock:
|
|
161
|
+
self.comwdg_timer.cancel()
|
|
162
|
+
|
|
163
|
+
msg = 'AT*{:s}={:d}{:s}\r'.format(command, self.seq, ''.join(',' + param for param in params_str))
|
|
164
|
+
self.sock.sendto(msg.encode(), (self.host, ardrone.constant.COMMAND_PORT))
|
|
165
|
+
|
|
166
|
+
self.seq += 1
|
|
167
|
+
|
|
168
|
+
self.comwdg_timer = threading.Timer(self.interval, self.comwdg)
|
|
169
|
+
self.comwdg_timer.start()
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fcntl
|
|
2
|
+
import sys
|
|
3
|
+
import termios
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
import ardrone
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def main():
|
|
10
|
+
if len(sys.argv) != 1 and len(sys.argv) != 2:
|
|
11
|
+
print('usage: ' + sys.argv[0] + ' [host]')
|
|
12
|
+
sys.exit(1)
|
|
13
|
+
|
|
14
|
+
fd = sys.stdin.fileno()
|
|
15
|
+
|
|
16
|
+
oldterm = termios.tcgetattr(fd)
|
|
17
|
+
newattr = termios.tcgetattr(fd)
|
|
18
|
+
newattr[3] = newattr[3] & ~termios.ICANON & ~termios.ECHO
|
|
19
|
+
termios.tcsetattr(fd, termios.TCSANOW, newattr)
|
|
20
|
+
|
|
21
|
+
oldflags = fcntl.fcntl(fd, fcntl.F_GETFL)
|
|
22
|
+
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags | os.O_NONBLOCK)
|
|
23
|
+
|
|
24
|
+
if len(sys.argv) >= 2:
|
|
25
|
+
drone = ardrone.ARDrone(sys.argv[1])
|
|
26
|
+
else:
|
|
27
|
+
drone = ardrone.ARDrone()
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
while 1:
|
|
31
|
+
try:
|
|
32
|
+
c = sys.stdin.read(1).lower()
|
|
33
|
+
|
|
34
|
+
if c == 'p':
|
|
35
|
+
break
|
|
36
|
+
elif c == 'a':
|
|
37
|
+
drone.move_left()
|
|
38
|
+
elif c == 'd':
|
|
39
|
+
drone.move_right()
|
|
40
|
+
elif c == 'w':
|
|
41
|
+
drone.move_forward()
|
|
42
|
+
elif c == 's':
|
|
43
|
+
drone.move_backward()
|
|
44
|
+
elif c == ' ':
|
|
45
|
+
drone.land()
|
|
46
|
+
elif c == '\n':
|
|
47
|
+
drone.takeoff()
|
|
48
|
+
elif c == 'q':
|
|
49
|
+
drone.turn_left()
|
|
50
|
+
elif c == 'e':
|
|
51
|
+
drone.turn_right()
|
|
52
|
+
elif c == '1':
|
|
53
|
+
drone.move_up()
|
|
54
|
+
elif c == '2':
|
|
55
|
+
drone.hover()
|
|
56
|
+
elif c == '3':
|
|
57
|
+
drone.move_down()
|
|
58
|
+
elif c == 't':
|
|
59
|
+
drone.reset()
|
|
60
|
+
elif c == 'x':
|
|
61
|
+
drone.hover()
|
|
62
|
+
elif c == 'y':
|
|
63
|
+
drone.trim()
|
|
64
|
+
except IOError:
|
|
65
|
+
pass
|
|
66
|
+
finally:
|
|
67
|
+
termios.tcsetattr(fd, termios.TCSAFLUSH, oldterm)
|
|
68
|
+
fcntl.fcntl(fd, fcntl.F_SETFL, oldflags)
|
|
69
|
+
drone.halt()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == '__main__':
|
|
73
|
+
main()
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Python library for the AR.Drone.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import time
|
|
6
|
+
import multiprocessing
|
|
7
|
+
|
|
8
|
+
import PIL.Image
|
|
9
|
+
|
|
10
|
+
import ardrone.at
|
|
11
|
+
import ardrone.network
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ARDrone(object):
|
|
15
|
+
"""ARDrone Class.
|
|
16
|
+
|
|
17
|
+
Instantiate this class to control your drone and receive decoded video and
|
|
18
|
+
navdata.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
def __init__(self, host='192.168.1.1'):
|
|
22
|
+
self.host = host
|
|
23
|
+
|
|
24
|
+
self.speed = 0.2
|
|
25
|
+
|
|
26
|
+
self.atcmd = ardrone.at.ATCommand(self.host)
|
|
27
|
+
self.atcmd.config('general:navdata_demo', 'TRUE')
|
|
28
|
+
self.atcmd.config('control:altitude_max', '20000')
|
|
29
|
+
self.video_pipe, video_pipe_other = multiprocessing.Pipe()
|
|
30
|
+
self.nav_pipe, nav_pipe_other = multiprocessing.Pipe()
|
|
31
|
+
self.com_pipe, com_pipe_other = multiprocessing.Pipe()
|
|
32
|
+
self.network_process = ardrone.network.ARDroneNetworkProcess(self.host, nav_pipe_other, video_pipe_other, com_pipe_other)
|
|
33
|
+
self.network_process.start()
|
|
34
|
+
self.ipc_thread = ardrone.network.IPCThread(self)
|
|
35
|
+
self.ipc_thread.start()
|
|
36
|
+
|
|
37
|
+
self.image = PIL.Image.new('RGB', (640, 360))
|
|
38
|
+
self.navdata = dict()
|
|
39
|
+
|
|
40
|
+
self.time = 0
|
|
41
|
+
|
|
42
|
+
def takeoff(self):
|
|
43
|
+
"""Make the drone takeoff."""
|
|
44
|
+
self.atcmd.ref(True)
|
|
45
|
+
|
|
46
|
+
def land(self):
|
|
47
|
+
"""Make the drone land."""
|
|
48
|
+
self.atcmd.ref(False)
|
|
49
|
+
|
|
50
|
+
def hover(self):
|
|
51
|
+
"""Make the drone hover."""
|
|
52
|
+
self.atcmd.pcmd(False, 0, 0, 0, 0)
|
|
53
|
+
|
|
54
|
+
def move_left(self):
|
|
55
|
+
"""Make the drone move left."""
|
|
56
|
+
self.atcmd.pcmd(True, -self.speed, 0, 0, 0)
|
|
57
|
+
|
|
58
|
+
def move_right(self):
|
|
59
|
+
"""Make the drone move right."""
|
|
60
|
+
self.atcmd.pcmd(True, self.speed, 0, 0, 0)
|
|
61
|
+
|
|
62
|
+
def move_up(self):
|
|
63
|
+
"""Make the drone rise upwards."""
|
|
64
|
+
self.atcmd.pcmd(True, 0, 0, self.speed, 0)
|
|
65
|
+
|
|
66
|
+
def move_down(self):
|
|
67
|
+
"""Make the drone decent downwards."""
|
|
68
|
+
self.atcmd.pcmd(True, 0, 0, -self.speed, 0)
|
|
69
|
+
|
|
70
|
+
def move_forward(self):
|
|
71
|
+
"""Make the drone move forward."""
|
|
72
|
+
self.atcmd.pcmd(True, 0, -self.speed, 0, 0)
|
|
73
|
+
|
|
74
|
+
def move_backward(self):
|
|
75
|
+
"""Make the drone move backwards."""
|
|
76
|
+
self.atcmd.pcmd(True, 0, self.speed, 0, 0)
|
|
77
|
+
|
|
78
|
+
def turn_left(self):
|
|
79
|
+
"""Make the drone rotate left."""
|
|
80
|
+
self.atcmd.pcmd(True, 0, 0, 0, -self.speed)
|
|
81
|
+
|
|
82
|
+
def turn_right(self):
|
|
83
|
+
"""Make the drone rotate right."""
|
|
84
|
+
self.atcmd.pcmd(True, 0, 0, 0, self.speed)
|
|
85
|
+
|
|
86
|
+
def reset(self):
|
|
87
|
+
"""Toggle the drone's emergency state."""
|
|
88
|
+
self.atcmd.ref(False, True)
|
|
89
|
+
time.sleep(0.1)
|
|
90
|
+
self.atcmd.ref(False, False)
|
|
91
|
+
|
|
92
|
+
def trim(self):
|
|
93
|
+
"""Flat trim the drone."""
|
|
94
|
+
self.atcmd.ftrim
|
|
95
|
+
|
|
96
|
+
def set_cam(self, cam):
|
|
97
|
+
"""Set active camera.
|
|
98
|
+
|
|
99
|
+
Valid values are 0 for the front camera and 1 for the bottom camera
|
|
100
|
+
"""
|
|
101
|
+
self.atcmd.config('video:video_channel', cam)
|
|
102
|
+
|
|
103
|
+
def set_speed(self, speed):
|
|
104
|
+
"""Set the drone's speed.
|
|
105
|
+
|
|
106
|
+
Valid values are floats from [0..1]
|
|
107
|
+
"""
|
|
108
|
+
self.speed = speed
|
|
109
|
+
|
|
110
|
+
def halt(self):
|
|
111
|
+
"""Shutdown the drone.
|
|
112
|
+
|
|
113
|
+
This method does not land or halt the actual drone, but the
|
|
114
|
+
communication with the drone. You should call it at the end of your
|
|
115
|
+
application to close all sockets, pipes, processes and threads related
|
|
116
|
+
with this object.
|
|
117
|
+
"""
|
|
118
|
+
self.atcmd.halt()
|
|
119
|
+
self.ipc_thread.stop()
|
|
120
|
+
self.ipc_thread.join()
|
|
121
|
+
self.network_process.terminate()
|
|
122
|
+
self.network_process.join()
|
|
123
|
+
|
|
124
|
+
def move(self, lr, fb, vv, va):
|
|
125
|
+
"""Makes the drone move (translate/rotate).
|
|
126
|
+
|
|
127
|
+
Parameters:
|
|
128
|
+
lr -- left-right tilt: float [-1..1] negative: left, positive: right
|
|
129
|
+
fb -- front-back tilt: float [-1..1] negative: forwards, positive:
|
|
130
|
+
backwards
|
|
131
|
+
vv -- vertical speed: float [-1..1] negative: go down, positive: rise
|
|
132
|
+
va -- angular speed: float [-1..1] negative: spin left, positive: spin
|
|
133
|
+
right"""
|
|
134
|
+
self.atcmd.pcmd(True, lr, fb, vv, va)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def decode(packet):
|
|
5
|
+
"""Decode a navdata packet."""
|
|
6
|
+
offset = 0
|
|
7
|
+
|
|
8
|
+
_ = struct.unpack_from('IIII', packet, offset)
|
|
9
|
+
s = _[1]
|
|
10
|
+
state = dict()
|
|
11
|
+
state['fly'] = s & 1 # FLY MASK : (0) ardrone is landed, (1) ardrone is flying
|
|
12
|
+
state['video'] = s >> 1 & 1 # VIDEO MASK : (0) video disable, (1) video enable
|
|
13
|
+
state['vision'] = s >> 2 & 1 # VISION MASK : (0) vision disable, (1) vision enable
|
|
14
|
+
state['control'] = s >> 3 & 1 # CONTROL ALGO (0) euler angles control, (1) angular speed control
|
|
15
|
+
state['altitude'] = s >> 4 & 1 # ALTITUDE CONTROL ALGO : (0) altitude control inactive (1) altitude control active
|
|
16
|
+
state['user_feedback_start'] = s >> 5 & 1 # USER feedback : Start button state
|
|
17
|
+
state['command'] = s >> 6 & 1 # Control command ACK : (0) None, (1) one received
|
|
18
|
+
state['fw_file'] = s >> 7 & 1 # Firmware file is good (1)
|
|
19
|
+
state['fw_ver'] = s >> 8 & 1 # Firmware update is newer (1)
|
|
20
|
+
state['fw_upd'] = s >> 9 & 1 # Firmware update is ongoing (1)
|
|
21
|
+
state['navdata_demo'] = s >> 10 & 1 # Navdata demo : (0) All navdata, (1) only navdata demo
|
|
22
|
+
state['navdata_bootstrap'] = s >> 11 & 1 # Navdata bootstrap : (0) options sent in all or demo mode, (1) no navdata options sent
|
|
23
|
+
state['motors'] = s >> 12 & 1 # Motor status : (0) Ok, (1) Motors problem
|
|
24
|
+
state['com_lost'] = s >> 13 & 1 # Communication lost : (1) com problem, (0) Com is ok
|
|
25
|
+
state['vbat_low'] = s >> 15 & 1 # VBat low : (1) too low, (0) Ok
|
|
26
|
+
state['user_el'] = s >> 16 & 1 # User Emergency Landing : (1) User EL is ON, (0) User EL is OFF
|
|
27
|
+
state['timer_elapsed'] = s >> 17 & 1 # Timer elapsed : (1) elapsed, (0) not elapsed
|
|
28
|
+
state['angles_out_of_range'] = s >> 19 & 1 # Angles : (0) Ok, (1) out of range
|
|
29
|
+
state['ultrasound'] = s >> 21 & 1 # Ultrasonic sensor : (0) Ok, (1) deaf
|
|
30
|
+
state['cutout'] = s >> 22 & 1 # Cutout system detection : (0) Not detected, (1) detected
|
|
31
|
+
state['pic_version'] = s >> 23 & 1 # PIC Version number OK : (0) a bad version number, (1) version number is OK
|
|
32
|
+
state['atcodec_thread_on'] = s >> 24 & 1 # ATCodec thread ON : (0) thread OFF (1) thread ON
|
|
33
|
+
state['navdata_thread_on'] = s >> 25 & 1 # Navdata thread ON : (0) thread OFF (1) thread ON
|
|
34
|
+
state['video_thread_on'] = s >> 26 & 1 # Video thread ON : (0) thread OFF (1) thread ON
|
|
35
|
+
state['acq_thread_on'] = s >> 27 & 1 # Acquisition thread ON : (0) thread OFF (1) thread ON
|
|
36
|
+
state['ctrl_watchdog'] = s >> 28 & 1 # CTRL watchdog : (1) delay in control execution (> 5ms), (0) control is well scheduled
|
|
37
|
+
state['adc_watchdog'] = s >> 29 & 1 # ADC Watchdog : (1) delay in uart2 dsr (> 5ms), (0) uart2 is good
|
|
38
|
+
state['com_watchdog'] = s >> 30 & 1 # Communication Watchdog : (1) com problem, (0) Com is ok
|
|
39
|
+
state['emergency'] = s >> 31 & 1 # Emergency landing : (0) no emergency, (1) emergency
|
|
40
|
+
|
|
41
|
+
data = dict()
|
|
42
|
+
data['state'] = state
|
|
43
|
+
data['header'] = _[0]
|
|
44
|
+
data['sequence'] = _[2]
|
|
45
|
+
data['vision'] = _[3]
|
|
46
|
+
|
|
47
|
+
offset += struct.calcsize('IIII')
|
|
48
|
+
|
|
49
|
+
demo_fields = [
|
|
50
|
+
'ctrl_state',
|
|
51
|
+
'battery',
|
|
52
|
+
'theta',
|
|
53
|
+
'phi',
|
|
54
|
+
'psi',
|
|
55
|
+
'altitude',
|
|
56
|
+
'vx',
|
|
57
|
+
'vy',
|
|
58
|
+
'vz',
|
|
59
|
+
'num_frames'
|
|
60
|
+
]
|
|
61
|
+
angles = ['theta', 'phi', 'psi']
|
|
62
|
+
while True:
|
|
63
|
+
try:
|
|
64
|
+
id_nr, size = struct.unpack_from('HH', packet, offset)
|
|
65
|
+
offset += struct.calcsize('HH')
|
|
66
|
+
except struct.error:
|
|
67
|
+
break
|
|
68
|
+
|
|
69
|
+
values = []
|
|
70
|
+
for i in range(size - struct.calcsize('HH')):
|
|
71
|
+
values.append(struct.unpack_from('c', packet, offset)[0])
|
|
72
|
+
offset += struct.calcsize('c')
|
|
73
|
+
|
|
74
|
+
if id_nr == 0:
|
|
75
|
+
values = struct.unpack_from('IIfffIfffI', b''.join(values))
|
|
76
|
+
demo = dict(zip(demo_fields, values))
|
|
77
|
+
for a in angles:
|
|
78
|
+
demo[a] = int(demo[a] / 1000)
|
|
79
|
+
|
|
80
|
+
data['demo'] = demo
|
|
81
|
+
|
|
82
|
+
return data
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides access to the data provided by the AR.Drone.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import select
|
|
6
|
+
import socket
|
|
7
|
+
import struct
|
|
8
|
+
import threading
|
|
9
|
+
import multiprocessing
|
|
10
|
+
|
|
11
|
+
import PIL.Image
|
|
12
|
+
|
|
13
|
+
import ardrone.constant
|
|
14
|
+
import ardrone.navdata
|
|
15
|
+
import ardrone.video
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ARDroneNetworkProcess(multiprocessing.Process):
|
|
19
|
+
"""ARDrone Network Process.
|
|
20
|
+
|
|
21
|
+
This process collects data from the video and navdata port, converts the
|
|
22
|
+
data and sends it to the IPCThread.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def __init__(self, host, nav_pipe, video_pipe, com_pipe):
|
|
26
|
+
multiprocessing.Process.__init__(self)
|
|
27
|
+
self.nav_pipe = nav_pipe
|
|
28
|
+
self.video_pipe = video_pipe
|
|
29
|
+
self.com_pipe = com_pipe
|
|
30
|
+
self.host = host
|
|
31
|
+
|
|
32
|
+
def run(self):
|
|
33
|
+
video_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
34
|
+
video_socket.connect((self.host, ardrone.constant.VIDEO_PORT))
|
|
35
|
+
|
|
36
|
+
nav_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
37
|
+
nav_socket.setblocking(False)
|
|
38
|
+
nav_socket.sendto(b'\x01\x00\x00\x00', (self.host, ardrone.constant.NAVDATA_PORT))
|
|
39
|
+
|
|
40
|
+
stopping = False
|
|
41
|
+
while not stopping:
|
|
42
|
+
inputready, outputready, exceptready = select.select([nav_socket, video_socket, self.com_pipe], [], [])
|
|
43
|
+
for i in inputready:
|
|
44
|
+
if i == video_socket:
|
|
45
|
+
# get first few bytes of header
|
|
46
|
+
data = video_socket.recv(12, socket.MSG_WAITALL)
|
|
47
|
+
if len(data) != 12:
|
|
48
|
+
continue
|
|
49
|
+
|
|
50
|
+
# decode relevant portions of the header
|
|
51
|
+
sig_p, sig_a, sig_v, sig_e, version, codec, header, payload = struct.unpack('4cBBHI', data)
|
|
52
|
+
|
|
53
|
+
# check signature (and ignore packet otherwise)
|
|
54
|
+
if sig_p != b'P' or sig_a != b'a' or sig_v != b'V' or sig_e != b'E':
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
# get remaining frame
|
|
58
|
+
data += video_socket.recv(header - 12 + payload, socket.MSG_WAITALL)
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
# decode the frame
|
|
62
|
+
image = ardrone.video.decode(data)
|
|
63
|
+
self.video_pipe.send(image)
|
|
64
|
+
except ardrone.video.DecodeError:
|
|
65
|
+
pass
|
|
66
|
+
elif i == nav_socket:
|
|
67
|
+
while 1:
|
|
68
|
+
try:
|
|
69
|
+
data, _ = nav_socket.recvfrom(65535)
|
|
70
|
+
except IOError:
|
|
71
|
+
# we consumed every packet from the socket and
|
|
72
|
+
# continue with the last one
|
|
73
|
+
break
|
|
74
|
+
navdata = ardrone.navdata.decode(data)
|
|
75
|
+
self.nav_pipe.send(navdata)
|
|
76
|
+
elif i == self.com_pipe:
|
|
77
|
+
_ = self.com_pipe.recv()
|
|
78
|
+
stopping = True
|
|
79
|
+
break
|
|
80
|
+
video_socket.close()
|
|
81
|
+
nav_socket.close()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class IPCThread(threading.Thread):
|
|
85
|
+
"""Inter Process Communication Thread.
|
|
86
|
+
|
|
87
|
+
This thread collects the data from the ARDroneNetworkProcess and forwards
|
|
88
|
+
it to the ARDrone.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, drone):
|
|
92
|
+
threading.Thread.__init__(self)
|
|
93
|
+
self.drone = drone
|
|
94
|
+
self.stopping = False
|
|
95
|
+
|
|
96
|
+
def run(self):
|
|
97
|
+
while not self.stopping:
|
|
98
|
+
inputready, outputready, exceptready = select.select([self.drone.video_pipe, self.drone.nav_pipe], [], [], 1)
|
|
99
|
+
for i in inputready:
|
|
100
|
+
if i == self.drone.video_pipe:
|
|
101
|
+
while self.drone.video_pipe.poll():
|
|
102
|
+
width, height, image = self.drone.video_pipe.recv()
|
|
103
|
+
self.drone.image = PIL.Image.frombuffer('RGB', (width, height), image, 'raw', 'RGB', 0, 1)
|
|
104
|
+
elif i == self.drone.nav_pipe:
|
|
105
|
+
while self.drone.nav_pipe.poll():
|
|
106
|
+
navdata = self.drone.nav_pipe.recv()
|
|
107
|
+
self.drone.navdata = navdata
|
|
108
|
+
|
|
109
|
+
def stop(self):
|
|
110
|
+
"""Stop the IPCThread activity."""
|
|
111
|
+
self.stopping = True
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
#include <Python.h>
|
|
2
|
+
|
|
3
|
+
#include <libavcodec/avcodec.h>
|
|
4
|
+
#include <libavformat/avformat.h>
|
|
5
|
+
#include <libavutil/imgutils.h>
|
|
6
|
+
#include <libswscale/swscale.h>
|
|
7
|
+
|
|
8
|
+
struct PaVE {
|
|
9
|
+
uint8_t signature[4]; // "PaVE"
|
|
10
|
+
uint8_t version; // protocol version
|
|
11
|
+
uint8_t video_codec; // codec of frame
|
|
12
|
+
uint16_t header_size; // size of this header
|
|
13
|
+
uint32_t payload_size; // size of payload frame
|
|
14
|
+
uint16_t encoded_stream_width; // encoded width
|
|
15
|
+
uint16_t encoded_stream_height; // encoded height
|
|
16
|
+
uint16_t display_width; // actual width
|
|
17
|
+
uint16_t display_height; // actual height
|
|
18
|
+
|
|
19
|
+
uint32_t frame_number; // current frame
|
|
20
|
+
uint32_t timestamp; // timestamp in milliseconds of frame
|
|
21
|
+
uint8_t total_chunks; // number of packets for frame (unused)
|
|
22
|
+
uint8_t chunck_index; // current packet number for frame (unused)
|
|
23
|
+
uint8_t frame_type; // I-frame or P-frame
|
|
24
|
+
uint8_t control; // control command (e.g. end of stream, advertised frames)
|
|
25
|
+
uint32_t stream_byte_position_lw; // lower word of byte position in stream
|
|
26
|
+
uint32_t stream_byte_position_uw; // upper word of byte position in stream
|
|
27
|
+
uint16_t stream_id; // current stream this frame is associated with
|
|
28
|
+
uint8_t total_slices; // number of slices in frame
|
|
29
|
+
uint8_t slice_index; // position of current slice
|
|
30
|
+
uint8_t header1_size; // size of SPS in frame (h.264 only)
|
|
31
|
+
uint8_t header2_size; // size of PPS in frame (h.264 only)
|
|
32
|
+
uint8_t reserved1[2]; // padding to align to 48 bytes
|
|
33
|
+
uint32_t advertised_size; // size of advertised frame
|
|
34
|
+
uint8_t reserved2[12]; // padding to align to 64 bytes
|
|
35
|
+
} __attribute__ ((packed));
|
|
36
|
+
|
|
37
|
+
static PyObject * VideoDecodeError;
|
|
38
|
+
|
|
39
|
+
static PyObject * video_decode(PyObject * self, PyObject * args);
|
|
40
|
+
|
|
41
|
+
static PyMethodDef VideoMethods[] = {
|
|
42
|
+
{"decode", video_decode, METH_VARARGS, "decode a PaVE video packet into an RGB image buffer"},
|
|
43
|
+
{NULL, NULL, 0, NULL}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
static struct PyModuleDef videomodule = {
|
|
47
|
+
PyModuleDef_HEAD_INIT,
|
|
48
|
+
"video",
|
|
49
|
+
NULL,
|
|
50
|
+
-1,
|
|
51
|
+
VideoMethods
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
const AVCodec * codec;
|
|
55
|
+
AVCodecContext * context;
|
|
56
|
+
AVFrame * frame;
|
|
57
|
+
struct SwsContext * sws_context;
|
|
58
|
+
|
|
59
|
+
PyMODINIT_FUNC PyInit_video(void) {
|
|
60
|
+
PyObject * module;
|
|
61
|
+
|
|
62
|
+
module = PyModule_Create(&videomodule);
|
|
63
|
+
if (module == NULL)
|
|
64
|
+
return NULL;
|
|
65
|
+
|
|
66
|
+
VideoDecodeError = PyErr_NewException("ardrone.video.DecodeError", NULL, NULL);
|
|
67
|
+
Py_INCREF(VideoDecodeError);
|
|
68
|
+
PyModule_AddObject(module, "DecodeError", VideoDecodeError);
|
|
69
|
+
|
|
70
|
+
codec = avcodec_find_decoder(AV_CODEC_ID_H264);
|
|
71
|
+
if (!codec) {
|
|
72
|
+
PyErr_SetString(VideoDecodeError, "could not find h.264 decoder");
|
|
73
|
+
return NULL;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
context = avcodec_alloc_context3(codec);
|
|
77
|
+
if (!context) {
|
|
78
|
+
PyErr_NoMemory();
|
|
79
|
+
return NULL;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (avcodec_open2(context, codec, NULL) < 0) {
|
|
83
|
+
PyErr_SetString(VideoDecodeError, "could not open h.264 codec");
|
|
84
|
+
return NULL;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
frame = av_frame_alloc();
|
|
88
|
+
if (!frame) {
|
|
89
|
+
PyErr_NoMemory();
|
|
90
|
+
return NULL;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return module;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
static PyObject * video_decode(PyObject * self, PyObject * args) {
|
|
97
|
+
unsigned char * data;
|
|
98
|
+
int data_size;
|
|
99
|
+
|
|
100
|
+
struct PaVE header;
|
|
101
|
+
unsigned char * payload;
|
|
102
|
+
|
|
103
|
+
AVPacket * packet;
|
|
104
|
+
|
|
105
|
+
unsigned char * image;
|
|
106
|
+
int image_width;
|
|
107
|
+
int image_height;
|
|
108
|
+
int image_size;
|
|
109
|
+
|
|
110
|
+
unsigned char * image_data[1];
|
|
111
|
+
int image_linesize[1];
|
|
112
|
+
|
|
113
|
+
PyObject * py_image;
|
|
114
|
+
|
|
115
|
+
if (!PyArg_ParseTuple(args, "s#", &data, &data_size))
|
|
116
|
+
return NULL;
|
|
117
|
+
|
|
118
|
+
header = *((struct PaVE *)data);
|
|
119
|
+
payload = data + header.header_size;
|
|
120
|
+
|
|
121
|
+
if (memcmp(header.signature, "PaVE", 4) != 0) {
|
|
122
|
+
PyErr_SetString(VideoDecodeError, "packet did not have correct signature");
|
|
123
|
+
return NULL;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (header.header_size + header.payload_size != (unsigned int)data_size) {
|
|
127
|
+
PyErr_SetString(VideoDecodeError, "packet size did not match expected size from header");
|
|
128
|
+
return NULL;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
packet = av_packet_alloc();
|
|
132
|
+
if (!packet) {
|
|
133
|
+
PyErr_NoMemory();
|
|
134
|
+
return NULL;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
packet->pts = AV_NOPTS_VALUE;
|
|
138
|
+
packet->dts = AV_NOPTS_VALUE;
|
|
139
|
+
packet->data = payload;
|
|
140
|
+
packet->size = header.payload_size;
|
|
141
|
+
|
|
142
|
+
if (avcodec_send_packet(context, packet) != 0 || avcodec_receive_frame(context, frame) != 0) {
|
|
143
|
+
av_packet_free(&packet);
|
|
144
|
+
PyErr_SetString(VideoDecodeError, "could not decode frame");
|
|
145
|
+
return NULL;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
av_packet_free(&packet);
|
|
149
|
+
|
|
150
|
+
image_width = frame->width;
|
|
151
|
+
image_height = frame->height;
|
|
152
|
+
|
|
153
|
+
image_size = av_image_get_buffer_size(AV_PIX_FMT_RGB24, image_width, image_height, 1)*sizeof(uint8_t);
|
|
154
|
+
|
|
155
|
+
image = (unsigned char *)av_malloc(image_size);
|
|
156
|
+
|
|
157
|
+
image_data[0] = image;
|
|
158
|
+
image_linesize[0] = image_size/image_height;
|
|
159
|
+
|
|
160
|
+
sws_context = sws_getCachedContext(sws_context, context->width, context->height, AV_PIX_FMT_YUV420P, context->width, context->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
|
|
161
|
+
sws_scale(sws_context, (const unsigned char * const *)frame->data, frame->linesize, 0, frame->height, image_data, image_linesize);
|
|
162
|
+
|
|
163
|
+
py_image = Py_BuildValue("iiy#", image_width, image_height, image, image_size);
|
|
164
|
+
|
|
165
|
+
av_free(image);
|
|
166
|
+
|
|
167
|
+
return py_image;
|
|
168
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ardrone_sdk
|
|
3
|
+
Version: 0.4.0
|
|
4
|
+
Summary: A Python library for controlling the Parrot AR.Drone 2.0 over a network
|
|
5
|
+
Author-email: Lily Foster <lily@lily.flowers>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Source, https://github.com/lilyinstarlight/python-ardrone
|
|
8
|
+
Project-URL: Tracker, https://github.com/lilyinstarlight/python-ardrone/issues
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Operating System :: POSIX
|
|
12
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
13
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: C
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Classifier: Topic :: System :: Hardware :: Hardware Drivers
|
|
20
|
+
Requires-Python: >=3.8
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: Pillow
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
python-ardrone
|
|
27
|
+
==============
|
|
28
|
+
|
|
29
|
+
_**Note: This library is looking for testers and/or maintainers! I have not had access myself to an AR.Drone 2.0 for a while, but there are several important unreleased changes that need testing on actual hardware as well as [stuff that still needs to be done](TODO.md) to make the library more robust. Open a new issue on this repository if you are interested!**_
|
|
30
|
+
|
|
31
|
+
A Python library for controlling the Parrot AR.Drone 2.0 over a network.
|
|
32
|
+
|
|
33
|
+
Usage
|
|
34
|
+
-----
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import ardrone
|
|
38
|
+
|
|
39
|
+
drone = ardrone.ARDrone()
|
|
40
|
+
|
|
41
|
+
drone.takeoff()
|
|
42
|
+
drone.land()
|
|
43
|
+
|
|
44
|
+
print(drone.navdata['demo']['battery'])
|
|
45
|
+
|
|
46
|
+
drone.image.show()
|
|
47
|
+
|
|
48
|
+
drone.halt()
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Thanks
|
|
52
|
+
------
|
|
53
|
+
|
|
54
|
+
Thanks to Bastian Venthur for making the beginnings on which this library was based at https://github.com/venthur/python-ardrone!
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
LICENSE
|
|
2
|
+
README.md
|
|
3
|
+
pyproject.toml
|
|
4
|
+
setup.py
|
|
5
|
+
ardrone/__init__.py
|
|
6
|
+
ardrone/at.py
|
|
7
|
+
ardrone/client.py
|
|
8
|
+
ardrone/constant.py
|
|
9
|
+
ardrone/drone.py
|
|
10
|
+
ardrone/navdata.py
|
|
11
|
+
ardrone/network.py
|
|
12
|
+
ardrone/video.c
|
|
13
|
+
ardrone_sdk.egg-info/PKG-INFO
|
|
14
|
+
ardrone_sdk.egg-info/SOURCES.txt
|
|
15
|
+
ardrone_sdk.egg-info/dependency_links.txt
|
|
16
|
+
ardrone_sdk.egg-info/entry_points.txt
|
|
17
|
+
ardrone_sdk.egg-info/requires.txt
|
|
18
|
+
ardrone_sdk.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Pillow
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=64"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "ardrone_sdk"
|
|
7
|
+
version = "0.4.0"
|
|
8
|
+
description = "A Python library for controlling the Parrot AR.Drone 2.0 over a network"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.8"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Lily Foster", email = "lily@lily.flowers" },
|
|
14
|
+
]
|
|
15
|
+
dependencies = [
|
|
16
|
+
"Pillow",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Operating System :: POSIX",
|
|
22
|
+
"Operating System :: POSIX :: Linux",
|
|
23
|
+
"Operating System :: MacOS :: MacOS X",
|
|
24
|
+
"Operating System :: Microsoft :: Windows",
|
|
25
|
+
"Programming Language :: Python",
|
|
26
|
+
"Programming Language :: Python :: 3",
|
|
27
|
+
"Programming Language :: C",
|
|
28
|
+
"Topic :: Scientific/Engineering",
|
|
29
|
+
"Topic :: System :: Hardware :: Hardware Drivers",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Source = "https://github.com/lilyinstarlight/python-ardrone"
|
|
34
|
+
Tracker = "https://github.com/lilyinstarlight/python-ardrone/issues"
|
|
35
|
+
|
|
36
|
+
[project.scripts]
|
|
37
|
+
ardrone-client = "ardrone.client:main"
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.packages.find]
|