1 | #!/usr/bin/python |
---|
2 | |
---|
3 | """ |
---|
4 | This program reads the RAW GPS readings from a file every INTERVAL seconds, converts them to GPS coordinates and directs the uav to traverse to those. After all the waypoints are traversed, it sets the UAV to RTL mode. |
---|
5 | """ |
---|
6 | import re |
---|
7 | import sys, os |
---|
8 | import socket |
---|
9 | import select |
---|
10 | import time |
---|
11 | |
---|
12 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.realpath(__file__)), '../lib')) |
---|
13 | |
---|
14 | import mavlink_apm, FTL_util |
---|
15 | |
---|
16 | INTERVAL = 5 |
---|
17 | MAX_SIZE = 1024 |
---|
18 | |
---|
19 | # Following are used for converting RAW GPS data into GPS coordinates |
---|
20 | raw_int_to_float_lat_lon = 10**7 |
---|
21 | raw_int_to_float_alt = 10**3 |
---|
22 | |
---|
23 | # Object used for accessing utility functions |
---|
24 | FTL_util_obj = FTL_util.FTL_util() |
---|
25 | |
---|
26 | """ This function sets the next waypoint the UAV has to traverse to""" |
---|
27 | def send_wp (mav_obj, mavproxy_sock, latitude, longitude,altitude, |
---|
28 | address_of_mavproxy): |
---|
29 | global MAX_SIZE, INTERVAL |
---|
30 | # A simpler way of assigning would be a,b,c,d = p1,p2,p3,p4. But for |
---|
31 | # readability sake, we stick with the usual assignment |
---|
32 | target_system = target_component = 1 |
---|
33 | seq = 0 |
---|
34 | #frame = mavlink_apm.MAV_FRAME_GLOBAL_RELATIVE_ALT |
---|
35 | frame = mavlink_apm.MAV_FRAME_GLOBAL |
---|
36 | command = mavlink_apm.MAV_CMD_NAV_WAYPOINT |
---|
37 | # signifies whether this is the current waypoint to proceed to, |
---|
38 | # any positive value is true |
---|
39 | current = 2 |
---|
40 | autocontinue = 1 # continue to next waypoint |
---|
41 | param1 = param2 = param3 = param4 = PARAM_IGNORE = 0 |
---|
42 | |
---|
43 | # Send the waypoint message and wait till the ACK is received for 2 seconds |
---|
44 | list_read_sockets = [mavproxy_sock] |
---|
45 | list_write_sockets = list_error_sockets = [] |
---|
46 | while 1: |
---|
47 | msg = mav_obj.mission_item_encode(target_system, target_component,seq,frame,command,current,autocontinue,param1,param2,param3,param4,latitude,longitude,altitude-584.0) |
---|
48 | try: |
---|
49 | mavproxy_sock.sendto(msg.get_msgbuf(),(address_of_mavproxy)) |
---|
50 | except socket.error as v: |
---|
51 | print "Exception when setting WP:" |
---|
52 | print os.strerror(v.errno) |
---|
53 | time.sleep(1) |
---|
54 | continue |
---|
55 | readable, writable, error = select.select(list_read_sockets, |
---|
56 | list_write_sockets, |
---|
57 | list_error_sockets,INTERVAL) |
---|
58 | if readable: |
---|
59 | data_from_mavproxy,address_of_mavproxy = mavproxy_sock.recvfrom (MAX_SIZE) |
---|
60 | decoded_message = mav_obj.decode(data_from_mavproxy) |
---|
61 | msg_id = decoded_message.get_msgId() |
---|
62 | |
---|
63 | # Check if this is a waypoint request message |
---|
64 | if msg_id == mavlink_apm.MAVLINK_MSG_ID_MISSION_ACK: |
---|
65 | print 'ACK for this way-point received received...' |
---|
66 | break |
---|
67 | else: |
---|
68 | #print "Expected message ID 47, received %d" % msg_id |
---|
69 | continue |
---|
70 | else: |
---|
71 | # Send the message again |
---|
72 | print "Timeout on receiving waypoint ACK message" |
---|
73 | continue |
---|
74 | |
---|
75 | return |
---|
76 | |
---|
77 | """ This function parses the RAW GPS data and returns latitude, longitude |
---|
78 | and altitude""" |
---|
79 | def parse_gps_info(gps_info): |
---|
80 | latitude = longitude = altitude = 0 |
---|
81 | # Get Latitude |
---|
82 | match_for_latitude = re.search(r'lat : (.+?),',gps_info) |
---|
83 | if not match_for_latitude: |
---|
84 | print "Error - no latitude information found, return!" |
---|
85 | return 0,0,0 |
---|
86 | else: |
---|
87 | latitude = match_for_latitude.group(1) |
---|
88 | |
---|
89 | # Get longitude |
---|
90 | match_for_longitude = re.search(r'lon : (.+?),',gps_info) |
---|
91 | if not match_for_longitude: |
---|
92 | print "Error - no longitude information found, return!" |
---|
93 | return 0,0,0 |
---|
94 | else: |
---|
95 | longitude = match_for_longitude.group(1) |
---|
96 | |
---|
97 | # Get altitude |
---|
98 | match_for_altitude = re.search(r'alt : (.+?),',gps_info) |
---|
99 | if not match_for_altitude: |
---|
100 | print "Error - no altitude information found, return!" |
---|
101 | return 0,0,0 |
---|
102 | else: |
---|
103 | altitude = match_for_altitude.group(1) |
---|
104 | |
---|
105 | return latitude, longitude, altitude |
---|
106 | |
---|
107 | """ This function is invoked to obtain the address of MAVProxy""" |
---|
108 | def get_mavproxy_address (mav_obj,mavproxy_sock): |
---|
109 | MAX_SIZE = 1024 |
---|
110 | heartbeat_received = 'False' |
---|
111 | mavproxy_sock.setblocking(1) |
---|
112 | print "Waiting for heartbeat message..." |
---|
113 | while not heartbeat_received.lower() == 'TRUE'.lower(): |
---|
114 | # Wait for heartbeat message to get the remote address |
---|
115 | # used by MAVProxy |
---|
116 | try: |
---|
117 | data_from_mavproxy,address_of_mavproxy = mavproxy_sock.recvfrom (MAX_SIZE) |
---|
118 | except socket.error as v: |
---|
119 | print "Exception when trying to obtain address of MAVProxy" |
---|
120 | print os.strerror(v.errno) |
---|
121 | decoded_message = mav_obj.decode(data_from_mavproxy) |
---|
122 | msg_id = decoded_message.get_msgId() |
---|
123 | if msg_id == mavlink_apm.MAVLINK_MSG_ID_HEARTBEAT: |
---|
124 | # Undo the change made |
---|
125 | heartbeat_received = 'True' |
---|
126 | print 'Got the address of MAV, proceeding..' |
---|
127 | print address_of_mavproxy |
---|
128 | mavproxy_sock.setblocking(0) |
---|
129 | return address_of_mavproxy |
---|
130 | |
---|
131 | """ The main function """ |
---|
132 | def main(): |
---|
133 | global MAX_SIZE, raw_int_to_float_lat_lon, raw_int_to_float_alt |
---|
134 | file_handle = "" |
---|
135 | |
---|
136 | if len(sys.argv) != 3: |
---|
137 | print "Usage: ./uav_guided_mode.py <MAVProxy port> <path to file with GPS info>" |
---|
138 | sys.exit(1) |
---|
139 | mavproxy_port = int(sys.argv[1]) |
---|
140 | file_name_with_gps_info = sys.argv[2] |
---|
141 | # Check if the file exists |
---|
142 | if not os.path.exists(file_name_with_gps_info): |
---|
143 | print "File name %s does not exist" % file_name_with_gps_info |
---|
144 | sys.exit(1) |
---|
145 | |
---|
146 | # Check if the file is not empty |
---|
147 | if not (os.path.getsize(file_name_with_gps_info) > 0): |
---|
148 | print "File %s is empty" % file_name_with_gps_info |
---|
149 | sys.exit(1) |
---|
150 | |
---|
151 | try: |
---|
152 | HOST = '' # Listen on all interfaces |
---|
153 | # Create a server socket for MAVProxy |
---|
154 | mavproxy_sock = socket.socket (socket.AF_INET,socket.SOCK_DGRAM) |
---|
155 | mavproxy_sock.setblocking(0) |
---|
156 | print 'created UDP socket for MAVProxy' |
---|
157 | mavproxy_sock.bind((HOST,mavproxy_port)) |
---|
158 | print 'Binding socket for MAVProxy connection' |
---|
159 | # Create the mavproxy object |
---|
160 | mav_obj = mavlink_apm.MAVLink (mavproxy_sock) |
---|
161 | |
---|
162 | # Get the address used by MAVProxy |
---|
163 | address_of_mavproxy = get_mavproxy_address (mav_obj, mavproxy_sock) |
---|
164 | |
---|
165 | # ARM the UAV |
---|
166 | component_id = mavlink_apm.MAV_COMP_ID_SYSTEM_CONTROL |
---|
167 | # Same command for arming or disarming, arm_flag controls whether the UAV |
---|
168 | # armed or disarmed. arm_flag=1->arm, arm_flag=0->disarm |
---|
169 | command = mavlink_apm.MAV_CMD_COMPONENT_ARM_DISARM |
---|
170 | arm_flag = 1 |
---|
171 | # Number of confirmations needed for this command. 0 means immediately |
---|
172 | confirmation = 0 |
---|
173 | # Other parameters are ignored by this command and are to be set to zero. |
---|
174 | PARAM_IGNORE = 0 |
---|
175 | msg = mav_obj.command_long_encode (1,component_id,command,confirmation, |
---|
176 | arm_flag,PARAM_IGNORE,PARAM_IGNORE, |
---|
177 | PARAM_IGNORE,PARAM_IGNORE,PARAM_IGNORE, |
---|
178 | PARAM_IGNORE) |
---|
179 | try: |
---|
180 | mavproxy_sock.sendto(msg.get_msgbuf(),(address_of_mavproxy)) |
---|
181 | except socket.error as v: |
---|
182 | print "Exception when trying to ARM the copter:" |
---|
183 | print os.strerror(v.errno) |
---|
184 | print "ARMED" |
---|
185 | file_handle = open(file_name_with_gps_info, 'r') |
---|
186 | |
---|
187 | # For each line which represents raw GPS data, generate and set a waypoint |
---|
188 | for line in file_handle: |
---|
189 | # Skip empty lines |
---|
190 | if line not in ['\n','\r\n']: |
---|
191 | latitude, longitude, altitude = parse_gps_info(line) |
---|
192 | # Filter unexpected values |
---|
193 | if not longitude or not latitude or not altitude: |
---|
194 | print "Erroneous values, skip.." |
---|
195 | continue |
---|
196 | latitude = float(latitude)/raw_int_to_float_lat_lon |
---|
197 | longitude = float(longitude)/raw_int_to_float_lat_lon |
---|
198 | altitude = float(altitude)/raw_int_to_float_alt |
---|
199 | send_wp (mav_obj, mavproxy_sock, latitude,longitude, |
---|
200 | altitude,address_of_mavproxy) |
---|
201 | # Sleep for INTERVAL seconds |
---|
202 | time.sleep(float(INTERVAL)) |
---|
203 | |
---|
204 | return_status = FTL_util_obj.set_mav_mode(FTL_util_obj.rtl_mode,mav_obj, |
---|
205 | mavproxy_sock, address_of_mavproxy) |
---|
206 | if return_status < 0: |
---|
207 | print "Error while setting mode, please check the parameters passed..." |
---|
208 | sys.exit(1) |
---|
209 | |
---|
210 | except Exception as ex: |
---|
211 | template = "An exception of type {0} occured. Arguments:\n{1!r}" |
---|
212 | message = template.format(type(ex).__name__, ex.args) |
---|
213 | print message |
---|
214 | sys.exit(1) |
---|
215 | |
---|
216 | if file_handle: |
---|
217 | file_handle.close() |
---|
218 | |
---|
219 | if __name__ == '__main__': |
---|
220 | main() |
---|