-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathautopilot.py
282 lines (240 loc) · 10.1 KB
/
autopilot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
from dronekit import connect, VehicleMode
from pymavlink import mavutil
import time
import mock
FLIGHT_MODES = ['STABILIZE', 'LAND', 'OF_LOITER', 'RTL', 'DRIFT',
'FLIP', 'AUTOTUNE', 'BRAKE','GUIDED_NOGPS', 'AVOID_ADSB',
'POSITION', 'SPORT', 'FLOWHOLD', 'POSHOLD','AUTO', 'GUIDED',
'ACRO', 'SMART_RTL', 'ALT_HOLD', 'LOITER', 'CIRCLE', 'THROW']
ACK_RESULT_TYPE = {0:'Command Accepted',
1:'Command Rejected',
2:'Access Denied',
3:'Command Not Supported',
4:'Command Failed'}
MAVLINK_COMMAND_ID = {'ARM/DISARM':400,
'TAKEOFF':22,
'CHANGE_FLIGHT_MODE':11}
is_waiting_for_ack = False
ack_command_id = None
ack_command_result = None
is_connected = False
is_armed = False
feed_back_stack = []
class autopilot:
"""autupilot class has many functions to connect and control the drone.
Attributes:
is_waiting_for_ack (boolean): boolean variable to manage the acknowledgment from the vehicle`.
ack_command_id (int): id of the command to wait for its acknowledgment`.
ack_command_result (int): id of the result type ACK_RESULT_TYPE`.
is_connected (boolean): flag to check if the vehicle is connected or not`.
is_armed (boolean): flag to check if the vehicle is armed or not`.
"""
def __init__(self):
self.autopilot = None
def connect(self,ip,port):
"""Starts a connection with a vehicle.
Args:
ip (str): the ip for the vehicle like `127.0.0.1`.
port (int): the port for the vehicle like 14450
"""
global is_connected
global feed_back_stack
self.autopilot = connect(str(ip)+":"+str(port), wait_ready=True)
if not self.autopilot is None:
is_connected = True
feed_back_stack.insert(0,'connected to vehicle with '+str(ip)+':'+str(port))
'''
Receives COMMAND_ACK mavlink packets
'''
@self.autopilot.on_message('COMMAND_ACK')
def listener_ack(self, name, message):
global is_waiting_for_ack
global ack_command_id
global ack_command_result
if is_waiting_for_ack:
if message.command == ack_command_id:
ack_command_result = message.result
is_waiting_for_ack = False
else:
print 'message: %s' % message,message.command,ack_command_id
'''
Receives HEARTBEAT mavlink packets
'''
@self.autopilot.on_message('HEARTBEAT')
def listener_heartbeat(self, name, message):
global is_armed
if (message.base_mode & 0b10000000)==128:
is_armed = True
else:
is_armed = False
else:
self.is_connected = False
def takeoff(self,altitude):
"""Sends takeoff command to connected vehicle.
Takeooff will fail in any of these situations:
1. There is no connection with a vehicle.
2. The vehicle is disarmed.
3. The vehicle is already above the ground.
Args:
altitude (str): the target altitude.
"""
global is_connected
global is_armed
global is_waiting_for_ack
global ack_command_id
global ack_command_result
global feed_back_stack
if is_connected and is_armed:
tick = 0
is_waiting_for_ack = True
ack_command_id = MAVLINK_COMMAND_ID['TAKEOFF']
self.autopilot.simple_takeoff(altitude)
while is_waiting_for_ack:
tick=1
time.sleep(0.5)
if tick>5:
feed_back_stack.insert(0,'TAKEOFF Time Out ')
print 'TAKEOFF Time Out!'
return
print 'TAKEOFF: ',ACK_RESULT_TYPE[ack_command_result]
if ack_command_result==0:
while True:
feed_back_stack.insert(0," Altitude: "+str(self.autopilot.location.global_relative_frame.alt))
print " Altitude: ", self.autopilot.location.global_relative_frame.alt
#Break and return from function just below target altitude.
if self.autopilot.location.global_relative_frame.alt>=altitude*0.95:
feed_back_stack.insert(0,'Reached target altitude '+str(altitude))
print "Reached target altitude"
break
time.sleep(1)
elif ack_command_result==4 and self.autopilot.location.global_relative_frame.alt>1:
feed_back_stack.insert(0,'The Vehicle is already above the ground!, use MOVE command... ')
print 'The Vehicle is already above the ground!, use MOVE command... '
return
else:
feed_back_stack.insert(0,'Vehicle is NOT armed ')
print 'Vehicle is NOT armed!'
def change_flight_mode(self,flight_mode_name):
"""Changes the flight mode for the connected Vehicle.
change_flight_mode will fail of there is no connection with a vehicle.
Args:
flight_mode_name (str): the name of flight_mode.
"""
global is_connected
global is_armed
global is_waiting_for_ack
global ack_command_id
global ack_command_result
global feed_back_stack
if is_connected:
if flight_mode_name.upper() in FLIGHT_MODES:
tick = 0
is_waiting_for_ack = True
ack_command_id = MAVLINK_COMMAND_ID['CHANGE_FLIGHT_MODE']
self.autopilot.mode = VehicleMode(flight_mode_name.upper())
while is_waiting_for_ack:
tick=1
time.sleep(0.5)
if tick>5:
print 'CHANGE_FLIGHT_MODE Time Out!'
feed_back_stack.insert(0,'CHANGE_FLIGHT_MODE Time Out ')
return
print 'CHANGE_FLIGHT_MODE:',ACK_RESULT_TYPE[ack_command_result]
feed_back_stack.insert(0,'CHANGE_FLIGHT_MODE:'+str(ACK_RESULT_TYPE[ack_command_result]))
else:
feed_back_stack.insert(0,'The available flight modes:'+str(FLIGHT_MODES))
print 'The available flight modes: ',FLIGHT_MODES
else:
feed_back_stack.insert(0,'There is no connection with any vehicle!')
print 'There is no connection with any vehicle!'
def arm(self):
"""arms/turns on the motors.
arm will fail of there is no connection with a vehicle.
"""
global is_connected
global is_armed
global is_waiting_for_ack
global ack_command_id
global ack_command_result
global feed_back_stack
if self.autopilot is None:
print "There is NO connection with any vehicle!"
feed_back_stack.insert(0,'There is NO connection with any vehicle!')
return
if is_armed:
print 'The vehicle is already armed!'
feed_back_stack.insert(0,'The vehicle is already armed!')
else:
tick = 0
is_waiting_for_ack = True
ack_command_id = MAVLINK_COMMAND_ID['ARM/DISARM']
self.autopilot.armed = True
tick=0
while is_waiting_for_ack:
tick=1
time.sleep(0.5)
if tick>5:
print 'Time Out!'
feed_back_stack.insert(0,'Arm Time Out!')
return
if ack_command_result==0:
is_armed = True
print 'ARM: ',ACK_RESULT_TYPE[ack_command_result]
feed_back_stack.insert(0,'ARM: '+str(ACK_RESULT_TYPE[ack_command_result]))
def disarm(self):
"""disarms/turns off the motors.
disarm will fail of there is no connection with a vehicle.
"""
global is_armed
global ack_command_id
if not is_armed:
print 'The vehicle is already disarmed!'
else:
ack_command_id = MAVLINK_COMMAND_ID['ARM/DISARM']
self.autopilot.armed = False
tick=0
while is_waiting_for_ack:
tick=1
time.sleep(0.5)
if tick>5:
print 'DISARM Time Out!'
return
if ack_command_result==0:
is_armed = False
print 'DISARM: ',ACK_RESULT_TYPE[ack_command_result]
#send mavlink packet
def move(self,velocity_x, velocity_y, velocity_z,duration):
"""
Move vehicle in direction based on specified velocity vectors.
"""
msg = self.autopilot.message_factory.set_position_target_local_ned_encode(
0, # time_boot_ms (not used)
0, 0, # target system, target component
mavutil.mavlink.MAV_FRAME_LOCAL_NED, # frame
0b0000111111000111, # type_mask (only speeds enabled)
0, 0, 0, # x, y, z positions (not used)
velocity_x, velocity_y, velocity_z, # x, y, z velocity in m/s
0, 0, 0, # x, y, z acceleration (not supported yet, ignored in GCS_Mavlink)
0, 0) # yaw, yaw_rate (not supported yet, ignored in GCS_Mavlink)
# send command to vehicle on 1 Hz cycle
for x in range(0,duration):
self.autopilot.send_mavlink(msg)
time.sleep(1)
def land(self):
self.change_flight_mode('LAND')
def pop_from_feedback_stack(self):
global feed_back_stack
if len(feed_back_stack)>0:
return feed_back_stack.pop()
else:
return None
if __name__== "__main__":
autopilot_vehicle = autopilot()
autopilot_vehicle.connect('127.0.0.1',14559)
#
print autopilot_vehicle.pop_from_feedback_stack
autopilot_vehicle.change_flight_mode('guided')
#
autopilot_vehicle.arm()
autopilot_vehicle.takeoff(3)
time.sleep(10)