Skip to content

Commit bd2a52d

Browse files
committed
updated transition documentation and added migrated examples
1 parent 44181e2 commit bd2a52d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

63 files changed

+7212
-49
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Introduction
2+
This folder is intended to house the client scripts for Project AirSim that behave identically or similarly to the scripts housed in the PythonClient folder that work for AirSim OSS.
3+
4+
# Conventions
5+
Mirror scripts: We will call the relationship between two scripts that do the same thing, one for Project AirSim and the other for AirSim OSS, as mirrors.
6+
7+
# Rules
8+
To maintain a correspondence between scripts, the script inside this folder must have the same relative location as its mirror script in the PythonClient folder. The name of two mirror scripts must be the same
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import pprint
2+
import tempfile
3+
import os
4+
import time
5+
import cv2
6+
7+
from projectairsim import ProjectAirSimClient, Drone, World
8+
from projectairsim.utils import projectairsim_log, rpy_to_quaternion, unpack_image
9+
from projectairsim.types import Pose, Quaternion, Vector3, ImageType
10+
11+
def to_quaternion(pitch, roll, yaw):
12+
quat = rpy_to_quaternion(pitch, roll, yaw)
13+
return Quaternion({"w": quat[0], "x": quat[1], "y": quat[2], "z": quat[3]})
14+
15+
pp = pprint.PrettyPrinter(indent=4)
16+
17+
def camera_callback(camera_info, camera_name):
18+
projectairsim_log().info("CameraInfo %s: %s" % (camera_name, pp.pprint(camera_info)))
19+
client.unsubscribe(drone.sensors["front_center"]["scene_camera_info"])
20+
21+
client = ProjectAirSimClient()
22+
client.connect()
23+
24+
try:
25+
world = World(client, "scene_computer_vision.jsonc", delay_after_load_sec=2)
26+
drone = Drone(client, world, "Drone1")
27+
28+
projectairsim_log().info('Press enter to get camera parameters')
29+
input()
30+
cam_list = ["front_center","front_right", "front_left"]
31+
for cam_name in cam_list:
32+
client.subscribe(
33+
drone.sensors[cam_name]["scene_camera_info"],
34+
lambda _, camera_info, camera_name=cam_name: camera_callback(camera_info, camera_name),
35+
)
36+
37+
#wait for cameras to log
38+
time.sleep(1)
39+
40+
projectairsim_log().info('Press enter to get images')
41+
input()
42+
tmp_dir = os.path.join(tempfile.gettempdir(), "airsim_drone")
43+
projectairsim_log().info ("Saving images to %s" % tmp_dir)
44+
try:
45+
for n in range(3):
46+
os.makedirs(os.path.join(tmp_dir, str(n)))
47+
except OSError:
48+
if not os.path.isdir(tmp_dir):
49+
raise
50+
51+
for x in range(50): # do few times
52+
drone.set_pose(Pose({"translation":Vector3({"x":x, "y":0, "z":-2}), "rotation":to_quaternion(0, 0, 0)}), True)
53+
time.sleep(0.1)
54+
55+
responses = drone.get_images(camera_id="front_center", image_type_ids=[ImageType.SCENE])
56+
responses.update(drone.get_images(camera_id="front_right", image_type_ids=[ImageType.SCENE]))
57+
responses.update(drone.get_images(camera_id="front_left", image_type_ids=[ImageType.SCENE]))
58+
59+
for i, response in enumerate(responses.values()):
60+
if response["encoding"] == "16UC1":
61+
projectairsim_log().info("Type %s, size %d, pos %s" % (response["encoding"], len(response["data"]), pprint.pformat([response["pos_x"],response["pos_y"],response["pos_z"]])))
62+
filename = os.path.normpath(os.path.join(tmp_dir, str(x) + "_" + str(i) + '.pfm'))
63+
else:
64+
projectairsim_log().info("Type %s, size %d, pos %s" % (response["encoding"], len(response["data"]), pprint.pformat([response["pos_x"],response["pos_y"],response["pos_z"]])))
65+
filename = os.path.normpath(os.path.join(tmp_dir, str(i), str(x) + "_" + str(i) + '.png'))
66+
img = unpack_image(response)
67+
cv2.imwrite(filename, img)
68+
69+
pose = drone.get_ground_truth_pose()
70+
pp.pprint(pose)
71+
72+
time.sleep(3)
73+
74+
# return the camera to the original position
75+
drone.set_pose(Pose({"translation":Vector3({"x":0, "y":0, "z":0}), "rotation":to_quaternion(0, 0, 0)}), True)
76+
finally:
77+
client.disconnect()
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import pprint
2+
import os
3+
import time
4+
import math
5+
import tempfile
6+
import cv2
7+
8+
from projectairsim import ProjectAirSimClient, Drone, World
9+
from projectairsim.utils import projectairsim_log, rpy_to_quaternion, unpack_image
10+
from projectairsim.types import Pose, Quaternion, Vector3, ImageType
11+
12+
def camera_callback(camera_info, camera_name):
13+
projectairsim_log().info("CameraInfo %s: %s" % (camera_name, pp.pprint(camera_info)))
14+
client.unsubscribe(drone.sensors["front_center"]["scene_camera_info"])
15+
16+
def to_quaternion(pitch, roll, yaw):
17+
quat = rpy_to_quaternion(pitch, roll, yaw)
18+
return Quaternion({"w": quat[0], "x": quat[1], "y": quat[2], "z": quat[3]})
19+
20+
pp = pprint.PrettyPrinter(indent=4)
21+
22+
client = ProjectAirSimClient()
23+
client.connect()
24+
25+
try:
26+
world = World(client, "scene_computer_vision.jsonc", delay_after_load_sec=2)
27+
drone = Drone(client, world, "Drone1")
28+
projectairsim_log().info('Press enter to set front_center gimbal to 15-degree pitch')
29+
input()
30+
camera_pose = Pose({"translation":Vector3({"x":0, "y":0, "z":0}), "rotation":to_quaternion(math.radians(15), 0, 0)}) #radians
31+
drone.set_camera_pose("front_center", camera_pose)
32+
33+
#camera info is unimplemented
34+
projectairsim_log().info('Press enter to get camera parameters')
35+
input()
36+
cam_list = ["front_center","front_right","front_left","bottom_center","back_center"]
37+
for cam_name in cam_list:
38+
client.subscribe(
39+
drone.sensors[cam_name]["scene_camera_info"],
40+
lambda _, camera_info, camera_name=cam_name: camera_callback(camera_info, camera_name),
41+
)
42+
43+
#wait for cameras to log
44+
time.sleep(1)
45+
46+
tmp_dir = os.path.join(tempfile.gettempdir(), "airsim_cv_mode")
47+
projectairsim_log().info ("Saving images to %s" % tmp_dir)
48+
try:
49+
os.makedirs(tmp_dir)
50+
except OSError:
51+
if not os.path.isdir(tmp_dir):
52+
raise
53+
54+
projectairsim_log().info('Press enter to get images')
55+
input()
56+
for x in range(3): # do few times
57+
z = x * -20 - 5 # some random number
58+
drone.set_pose(Pose({"translation":Vector3({"x":z, "y":z, "z":z}), "rotation":to_quaternion(x / 3.0, 0, x / 3.0)}))
59+
60+
# DepthVis isn't implemented, so we substitute DepthPlanar
61+
responses = drone.get_images("front_center", [ImageType.DEPTH_PLANAR])
62+
responses.update(drone.get_images("front_right", [ImageType.DEPTH_PERSPECTIVE]))
63+
responses.update(drone.get_images("front_left", [ImageType.SEGMENTATION]))
64+
responses.update(drone.get_images("bottom_center", [ImageType.SCENE]))
65+
# uncomment this once these image types have been implemented
66+
#responses.update(drone.GetImages("back_center", [ImageType.DISPARITY_NORMALIZED, ImageType.SURFACE_NORMALS]))
67+
68+
for idx, response in enumerate(responses.values()):
69+
if response["encoding"] == "16UC1":
70+
filename = os.path.join(tmp_dir, str(x) + "_" + str(idx) + ".pfm")
71+
else:
72+
filename = os.path.join(tmp_dir, str(x) + "_" + str(idx) + ".png")
73+
img = unpack_image(response)
74+
cv2.imwrite(filename, img)
75+
76+
pose = drone.get_ground_truth_pose()
77+
pp.pprint(pose)
78+
79+
time.sleep(3)
80+
finally:
81+
client.disconnect()
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
import numpy as np
2+
import time
3+
import os
4+
import pprint
5+
import tempfile
6+
import math
7+
from math import *
8+
9+
from projectairsim import ProjectAirSimClient, Drone, World
10+
from projectairsim.utils import projectairsim_log, rpy_to_quaternion, unpack_image
11+
from projectairsim.types import ImageType, Vector3, Quaternion, Pose
12+
13+
from abc import ABC, abstractmethod
14+
15+
def to_quaternion(pitch, roll, yaw):
16+
quat = rpy_to_quaternion(pitch, roll, yaw)
17+
return Quaternion({"w": quat[0], "x": quat[1], "y": quat[2], "z": quat[3]})
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+
#compute resultant normalized vector, distance and angle
93+
def get_vec_dist_angle (goal, pos):
94+
vec = np.array(goal) - np.array(pos)
95+
dist = math.sqrt(vec[0]**2 + vec[1]**2)
96+
angle = math.atan2(vec[1],vec[0])
97+
if angle > math.pi:
98+
angle -= 2*math.pi
99+
elif angle < -math.pi:
100+
angle += 2*math.pi
101+
return vec/dist, dist, angle
102+
103+
def get_local_goal (v, pos, theta):
104+
return goal
105+
106+
#compute bounding box size
107+
def compute_bb(image_sz, obj_sz, hfov, distance):
108+
vfov = hfov2vfov(hfov,image_sz)
109+
box_h = ceil(obj_sz[0] * image_sz[0] / (math.tan(hfov/2)*distance*2))
110+
box_w = ceil(obj_sz[1] * image_sz[1] / (math.tan(vfov/2)*distance*2))
111+
return box_h, box_w
112+
113+
#convert horizonal fov to vertical fov
114+
def hfov2vfov(hfov, image_sz):
115+
aspect = image_sz[0]/image_sz[1]
116+
vfov = 2*math.atan( tan(hfov/2) * aspect)
117+
return vfov
118+
119+
#matrix with all ones
120+
def equal_weight_mtx(roi_h,roi_w):
121+
return np.ones((roi_h,roi_w))
122+
123+
#matrix with max weight in center and decreasing linearly with distance from center
124+
def linear_weight_mtx(roi_h,roi_w):
125+
w_mtx = np.ones((roi_h,roi_w))
126+
for j in range(0,roi_w):
127+
for i in range(j,roi_h-j):
128+
w_mtx[j:roi_h-j,i:roi_w-i] = (j+1)
129+
return w_mtx
130+
131+
#matrix with max weight in center and decreasing quadratically with distance from center
132+
def square_weight_mtx(roi_h,roi_w):
133+
w_mtx = np.ones((roi_h,roi_w))
134+
for j in range(0,roi_w):
135+
for i in range(j,roi_h-j):
136+
w_mtx[j:roi_h-j,i:roi_w-i] = (j+1)*(j+1)
137+
return w_mtx
138+
139+
def print_stats(img):
140+
projectairsim_log().info ('Avg: ',np.average(img))
141+
projectairsim_log().info ('Min: ',np.min(img))
142+
projectairsim_log().info ('Max: ',np.max(img))
143+
projectairsim_log().info('Img Sz: ',np.size(img))
144+
145+
def generate_depth_viz(img,thres=0):
146+
if thres > 0:
147+
img[img > thres] = thres
148+
else:
149+
img = np.reciprocal(img)
150+
return img
151+
152+
def moveUAV(client,pos,yaw):
153+
drone.set_pose(Pose({"translation":Vector3({"x":pos[0], "y":pos[1], "z":pos[2]}), "rotation":to_quaternion(0, 0, yaw)}), True)
154+
155+
156+
pp = pprint.PrettyPrinter(indent=4)
157+
158+
client = ProjectAirSimClient()
159+
client.connect()
160+
161+
try:
162+
world = World(client, "scene_computer_vision.jsonc", delay_after_load_sec=2)
163+
drone = Drone(client, world, "Drone1")
164+
165+
#Define start position, goal and size of UAV
166+
pos = [0,5,-3] #start position x,y,z
167+
goal = [160,0] #x,y
168+
uav_size = [0.29*3,0.98*2] #height:0.29 x width:0.98 - allow some tolerance
169+
170+
#Define parameters and thresholds
171+
hfov = radians(90)
172+
coll_thres = 5000
173+
yaw = 0
174+
limit_yaw = 5
175+
step = 0.1
176+
177+
responses = drone.get_images("front_right", [ImageType.DEPTH_PLANAR])
178+
response = responses[ImageType.DEPTH_PLANAR]
179+
180+
#initial position
181+
moveUAV(client,pos,yaw)
182+
183+
predictControl = AvoidLeft(hfov, coll_thres, yaw, limit_yaw, step)
184+
185+
for z in range(10000): # do few times
186+
187+
# get response
188+
responses = drone.get_images("front_right", [ImageType.DEPTH_PLANAR])
189+
response = responses[ImageType.DEPTH_PLANAR]
190+
191+
# get numpy array
192+
img2d = unpack_image(response)
193+
194+
[pos,yaw,target_dist] = predictControl.get_next_vec(img2d, uav_size, goal, pos)
195+
moveUAV(client,pos,yaw)
196+
197+
if (target_dist < 1):
198+
projectairsim_log().info('Target reached.')
199+
projectairsim_log().info('Press enter to continue')
200+
input()
201+
break
202+
203+
drone.set_pose(Pose({"translation":Vector3({"x":0, "y":0, "z":0}), "rotation":to_quaternion(0, 0, 0)}), True)
204+
finally:
205+
client.disconnect()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
from projectairsim import ProjectAirSimClient, Drone, World
2+
from projectairsim.utils import projectairsim_log, quaternion_to_rpy
3+
4+
client = ProjectAirSimClient()
5+
client.connect()
6+
7+
try:
8+
world = World(client, "scene_computer_vision.jsonc", delay_after_load_sec=2)
9+
drone = Drone(client, world, "Drone1")
10+
pose = drone.get_ground_truth_pose()
11+
projectairsim_log().info("x={}, y={}, z={}".format(pose["translation"]["x"], pose["translation"]["y"], pose["translation"]["z"]))
12+
13+
angles = quaternion_to_rpy(pose["rotation"]["w"],pose["rotation"]["x"],pose["rotation"]["y"],pose["rotation"]["z"])
14+
projectairsim_log().info("pitch={}, roll={}, yaw={}".format(angles[0], angles[1], angles[2]))
15+
16+
pose["translation"]["x"] = pose["translation"]["x"] + 1
17+
drone.set_pose(pose, True)
18+
19+
finally:
20+
client.disconnect()

0 commit comments

Comments
 (0)