|
| 1 | + |
| 2 | +# In settings.json first activate computer vision mode: |
| 3 | +# https://github.com/Microsoft/AirSim/blob/master/docs/image_apis.md#computer-vision-mode |
| 4 | + |
| 5 | +import setup_path |
| 6 | +import airsim |
| 7 | + |
| 8 | +import numpy as np |
| 9 | +import time |
| 10 | +import os |
| 11 | +import pprint |
| 12 | +import tempfile |
| 13 | +import math |
| 14 | +from math import * |
| 15 | +from scipy.misc import imsave |
| 16 | + |
| 17 | +from abc import ABC, abstractmethod |
| 18 | + |
| 19 | +#define abstract class to return next vector in the format (x,y,yaw) |
| 20 | +class AbstractClassGetNextVec(ABC): |
| 21 | + |
| 22 | + @abstractmethod |
| 23 | + def get_next_vec(self, depth, obj_sz, goal, pos): |
| 24 | + print("Some implementation!") |
| 25 | + return pos,yaw |
| 26 | + |
| 27 | +class ReactiveController(AbstractClassGetNextVec): |
| 28 | + def get_next_vec(self, depth, obj_sz, goal, pos): |
| 29 | + print("Some implementation!") |
| 30 | + return |
| 31 | + |
| 32 | +class AvoidLeft(AbstractClassGetNextVec): |
| 33 | + |
| 34 | + def __init__(self, hfov=radians(90), coll_thres=5, yaw=0, limit_yaw=5, step=0.1): |
| 35 | + self.hfov = hfov |
| 36 | + self.coll_thres = coll_thres |
| 37 | + self.yaw = yaw |
| 38 | + self.limit_yaw = limit_yaw |
| 39 | + self.step = step |
| 40 | + |
| 41 | + def get_next_vec(self, depth, obj_sz, goal, pos): |
| 42 | + |
| 43 | + [h,w] = np.shape(depth) |
| 44 | + [roi_h,roi_w] = compute_bb((h,w), obj_sz, self.hfov, self.coll_thres) |
| 45 | + |
| 46 | + # compute vector, distance and angle to goal |
| 47 | + t_vec, t_dist, t_angle = get_vec_dist_angle (goal, pos[:-1]) |
| 48 | + |
| 49 | + # compute box of interest |
| 50 | + img2d_box = img2d[int((h-roi_h)/2):int((h+roi_h)/2),int((w-roi_w)/2):int((w+roi_w)/2)] |
| 51 | + |
| 52 | + # scale by weight matrix (optional) |
| 53 | + #img2d_box = np.multiply(img2d_box,w_mtx) |
| 54 | + |
| 55 | + # detect collision |
| 56 | + if (np.min(img2d_box) < coll_thres): |
| 57 | + self.yaw = self.yaw - radians(self.limit_yaw) |
| 58 | + else: |
| 59 | + self.yaw = self.yaw + min (t_angle-self.yaw, radians(self.limit_yaw)) |
| 60 | + |
| 61 | + pos[0] = pos[0] + self.step*cos(self.yaw) |
| 62 | + pos[1] = pos[1] + self.step*sin(self.yaw) |
| 63 | + |
| 64 | + return pos, self.yaw,t_dist |
| 65 | + |
| 66 | +class AvoidLeftIgonreGoal(AbstractClassGetNextVec): |
| 67 | + |
| 68 | + def __init__(self, hfov=radians(90), coll_thres=5, yaw=0, limit_yaw=5, step=0.1): |
| 69 | + self.hfov = hfov |
| 70 | + self.coll_thres = coll_thres |
| 71 | + self.yaw = yaw |
| 72 | + self.limit_yaw = limit_yaw |
| 73 | + self.step = step |
| 74 | + |
| 75 | + def get_next_vec(self, depth, obj_sz, goal, pos): |
| 76 | + |
| 77 | + [h,w] = np.shape(depth) |
| 78 | + [roi_h,roi_w] = compute_bb((h,w), obj_sz, self.hfov, self.coll_thres) |
| 79 | + |
| 80 | + # compute box of interest |
| 81 | + img2d_box = img2d[int((h-roi_h)/2):int((h+roi_h)/2),int((w-roi_w)/2):int((w+roi_w)/2)] |
| 82 | + |
| 83 | + # detect collision |
| 84 | + if (np.min(img2d_box) < coll_thres): |
| 85 | + self.yaw = self.yaw - radians(self.limit_yaw) |
| 86 | + |
| 87 | + pos[0] = pos[0] + self.step*cos(self.yaw) |
| 88 | + pos[1] = pos[1] + self.step*sin(self.yaw) |
| 89 | + |
| 90 | + return pos, self.yaw, 100 |
| 91 | + |
| 92 | +class AvoidLeftRight(AbstractClassGetNextVec): |
| 93 | + def get_next_vec(self, depth, obj_sz, goal, pos): |
| 94 | + print("Some implementation!") |
| 95 | + #Same as above but decide to go left or right based on average or some metric like that |
| 96 | + return |
| 97 | + |
| 98 | + |
| 99 | +#compute resultant normalized vector, distance and angle |
| 100 | +def get_vec_dist_angle (goal, pos): |
| 101 | + vec = np.array(goal - np.array(pos)) |
| 102 | + dist = math.sqrt(vec[0]**2 + vec[1]**2) |
| 103 | + angle = math.atan2(vec[1],vec[0]) |
| 104 | + if angle > math.pi: |
| 105 | + angle -= 2*math.pi |
| 106 | + elif angle < -math.pi: |
| 107 | + angle += 2*math.pi |
| 108 | + return vec/dist, dist, angle |
| 109 | + |
| 110 | +def get_local_goal (v, pos, theta): |
| 111 | + return goal |
| 112 | + |
| 113 | +#compute bounding box size |
| 114 | +def compute_bb(image_sz, obj_sz, hfov, distance): |
| 115 | + vfov = hfov2vfov(hfov,image_sz) |
| 116 | + box_h = ceil(obj_sz[0] * image_sz[0] / (math.tan(hfov/2)*distance*2)) |
| 117 | + box_w = ceil(obj_sz[1] * image_sz[1] / (math.tan(vfov/2)*distance*2)) |
| 118 | + return box_h, box_w |
| 119 | + |
| 120 | +#convert horizonal fov to vertical fov |
| 121 | +def hfov2vfov(hfov, image_sz): |
| 122 | + aspect = image_sz[0]/image_sz[1] |
| 123 | + vfov = 2*math.atan( tan(hfov/2) * aspect) |
| 124 | + return vfov |
| 125 | + |
| 126 | +#matrix with all ones |
| 127 | +def equal_weight_mtx(roi_h,roi_w): |
| 128 | + return np.ones((roi_h,roi_w)) |
| 129 | + |
| 130 | +#matrix with max weight in center and decreasing linearly with distance from center |
| 131 | +def linear_weight_mtx(roi_h,roi_w): |
| 132 | + w_mtx = np.ones((roi_h,roi_w)) |
| 133 | + for j in range(0,roi_w): |
| 134 | + for i in range(j,roi_h-j): |
| 135 | + w_mtx[j:roi_h-j,i:roi_w-i] = (j+1) |
| 136 | + return w_mtx |
| 137 | + |
| 138 | +#matrix with max weight in center and decreasing quadratically with distance from center |
| 139 | +def square_weight_mtx(roi_h,roi_w): |
| 140 | + w_mtx = np.ones((roi_h,roi_w)) |
| 141 | + for j in range(0,roi_w): |
| 142 | + for i in range(j,roi_h-j): |
| 143 | + w_mtx[j:roi_h-j,i:roi_w-i] = (j+1)*(j+1) |
| 144 | + return w_mtx |
| 145 | + |
| 146 | +def print_stats(img): |
| 147 | + print ('Avg: ',np.average(img)) |
| 148 | + print ('Min: ',np.min(img)) |
| 149 | + print ('Max: ',np.max(img)) |
| 150 | + print('Img Sz: ',np.size(img)) |
| 151 | + |
| 152 | +def generate_depth_viz(img,thres=0): |
| 153 | + if thres > 0: |
| 154 | + img[img > thres] = thres |
| 155 | + else: |
| 156 | + img = np.reciprocal(img) |
| 157 | + return img |
| 158 | + |
| 159 | +def moveUAV(client,pos,yaw): |
| 160 | + client.simSetVehiclePose(airsim.Pose(airsim.Vector3r(pos[0], pos[1], pos[2]), airsim.to_quaternion(0, 0, yaw)), True) |
| 161 | + |
| 162 | + |
| 163 | +pp = pprint.PrettyPrinter(indent=4) |
| 164 | + |
| 165 | +client = airsim.VehicleClient() |
| 166 | +client.confirmConnection() |
| 167 | + |
| 168 | +tmp_dir = os.path.join(tempfile.gettempdir(), "airsim_drone") |
| 169 | +#print ("Saving images to %s" % tmp_dir) |
| 170 | +#airsim.wait_key('Press any key to start') |
| 171 | + |
| 172 | +#Define start position, goal and size of UAV |
| 173 | +pos = [0,5,-1] #start position x,y,z |
| 174 | +goal = [120,0] #x,y |
| 175 | +uav_size = [0.29*3,0.98*2] #height:0.29 x width:0.98 - allow some tolerance |
| 176 | + |
| 177 | +#Define parameters and thresholds |
| 178 | +hfov = radians(90) |
| 179 | +coll_thres = 5 |
| 180 | +yaw = 0 |
| 181 | +limit_yaw = 5 |
| 182 | +step = 0.1 |
| 183 | + |
| 184 | +responses = client.simGetImages([ |
| 185 | + airsim.ImageRequest("1", airsim.ImageType.DepthPlanner, True)]) |
| 186 | +response = responses[0] |
| 187 | + |
| 188 | +#initial position |
| 189 | +moveUAV(client,pos,yaw) |
| 190 | + |
| 191 | +#predictControl = AvoidLeftIgonreGoal(hfov, coll_thres, yaw, limit_yaw, step) |
| 192 | +predictControl = AvoidLeft(hfov, coll_thres, yaw, limit_yaw, step) |
| 193 | + |
| 194 | +for z in range(10000): # do few times |
| 195 | + |
| 196 | + #time.sleep(1) |
| 197 | + |
| 198 | + # get response |
| 199 | + responses = client.simGetImages([ |
| 200 | + airsim.ImageRequest("1", airsim.ImageType.DepthPlanner, True)]) |
| 201 | + response = responses[0] |
| 202 | + |
| 203 | + # get numpy array |
| 204 | + img1d = response.image_data_float |
| 205 | + |
| 206 | + # reshape array to 2D array H X W |
| 207 | + img2d = np.reshape(img1d,(response.height, response.width)) |
| 208 | + |
| 209 | + [pos,yaw,target_dist] = predictControl.get_next_vec(img2d, uav_size, goal, pos) |
| 210 | + moveUAV(client,pos,yaw) |
| 211 | + |
| 212 | + if (target_dist < 1): |
| 213 | + print('Target reached.') |
| 214 | + airsim.wait_key('Press any key to continue') |
| 215 | + break |
| 216 | + |
| 217 | + # write to png |
| 218 | + #imsave(os.path.normpath(os.path.join(tmp_dir, "depth_" + str(z) + '.png')), generate_depth_viz(img2d,5)) |
| 219 | + |
| 220 | + #pose = client.simGetPose() |
| 221 | + #pp.pprint(pose) |
| 222 | + #time.sleep(5) |
| 223 | + |
| 224 | +# currently reset() doesn't work in CV mode. Below is the workaround |
| 225 | +client.simSetVehiclePose(airsim.Pose(airsim.Vector3r(0, 0, 0), airsim.to_quaternion(0, 0, 0)), True) |
| 226 | + |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
| 233 | + |
| 234 | + |
| 235 | + |
| 236 | + |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | +#################### OLD CODE |
| 241 | +# timer = 0 |
| 242 | +# time_obs = 50 |
| 243 | +# bObstacle = False |
| 244 | + |
| 245 | +# if (bObstacle): |
| 246 | +# timer = timer + 1 |
| 247 | +# if timer > time_obs: |
| 248 | +# bObstacle = False |
| 249 | +# timer = 0 |
| 250 | +# else: |
| 251 | +# yaw = target_angle |
| 252 | + |
| 253 | +# print (target_angle,target_vec,target_dist,x,y,goal[0],goal[1]) |
| 254 | + |
| 255 | + |
| 256 | +# if (np.average(img2d_box) < coll_thres): |
| 257 | +# img2d_box_l = img2d_box = img2d[int((h-roi_h)/2):int((h+roi_h)/2),int((w-roi_w)/2)-50:int((w+roi_w)/2)-50] |
| 258 | +# img2d_box_r = img2d_box = img2d[int((h-roi_h)/2):int((h+roi_h)/2),int((w-roi_w)/2)+50:int((w+roi_w)/2)+50] |
| 259 | +# img2d_box_l_avg = np.average(np.multiply(img2d_box_l,w_mtx)) |
| 260 | +# img2d_box_r_avg = np.average(np.multiply(img2d_box_r,w_mtx)) |
| 261 | +# print('left: ', img2d_box_l_avg) |
| 262 | +# print('right: ', img2d_box_r_avg) |
| 263 | +# if img2d_box_l_avg > img2d_box_r_avg: |
| 264 | +# ##Go LEFT |
| 265 | +# #y_offset = y_offset-1 |
| 266 | +# yaw = yaw - radians(10) |
| 267 | +# bObstacle = True |
| 268 | +# else: |
| 269 | +# ##Go RIGHT |
| 270 | +# #y_offset = y_offset+1 |
| 271 | +# yaw = yaw + radians(10) |
| 272 | +# bObstacle = true |
| 273 | +# print('yaw: ', yaw) |
0 commit comments