| 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() |
|---|