|
2 | 2 | import rospy
|
3 | 3 | import numpy as np
|
4 | 4 | import tf2_ros
|
| 5 | +from geometry_msgs.msg import Quaternion |
| 6 | +from tf.transformations import euler_from_quaternion |
| 7 | +import cv2 |
5 | 8 |
|
6 |
| -field = Field(length = 600, width = 400) |
7 |
| -#listener = tf.transform_listener() |
8 |
| -tfBuffer = tf2_ros.Buffer() |
9 |
| -listener = tf2_ros.TransformListener(tfBuffer) |
10 |
| -rospy.Subscriber("elevation_mapping/occ_grid", OccupancyGrid, field.update_field) |
11 |
| -rospy.spin() |
12 | 9 |
|
13 | 10 |
|
14 | 11 |
|
15 | 12 | class Field:
|
16 | 13 | def __init__(self, length, width):
|
17 |
| - self.map = np.array(size=(600,400)) #length, width |
| 14 | + self.map = np.array(size=(600,400)) |
18 | 15 | self.xpos = 0
|
19 | 16 | self.ypos = 0
|
| 17 | + self.tfBuffer = tf2_ros.Buffer() |
| 18 | + self.listener = tf2_ros.TransformListener(tfBuffer) |
20 | 19 | #self.map_pub = rospy.Publisher
|
21 | 20 |
|
22 | 21 | def update_field(self, new_map_msg):
|
23 | 22 | #convert msg to numpy array
|
24 | 23 | #get pose of robot relative to world
|
25 | 24 | #update corresponding region of self.map
|
26 |
| - local_map = np.reshape(OccupancyGrid.data, (OccupancyGrid.info.height, OccupancyGrid.info.width)) |
| 25 | + |
| 26 | + |
| 27 | + local_map = np.reshape(new_map_msg.data, (new_map_msg.info.height, new_map_msg.info.width)) |
27 | 28 | cur_tf = tfBuffer.lookup_transform("world_pose", "robot_pose", rospy.time(0))
|
| 29 | + q = [cur_tf.transform.rotation.x, |
| 30 | + cur_tf.transform.rotation.y, |
| 31 | + cur_tf.transform.rotation.z, |
| 32 | + cur_tf.transform.rotation.w] #quaternion from tf |
| 33 | + rpy = euler_from_quaternion(Quaternion(q[0], q[1], q[2], q[3])) |
| 34 | + #Rotate the local map based on the difference in angles of the transforms |
| 35 | + (h, w) = local_map.shape[:2] |
| 36 | + (origin_X, origin_Y) = (w/2, h/2) |
| 37 | + |
| 38 | + |
| 39 | + M = cv2.getRotationMatrix2D((cX, cY), rpy[2], 1.0) |
| 40 | + cos = np.abs(M[0, 0]) |
| 41 | + sin = np.abs(M[0, 1]) |
| 42 | + |
| 43 | + new_w = int((h * sin) + (w * cos)) |
| 44 | + new_h = int((h * cos) + (w * sin)) |
| 45 | + |
| 46 | + M[0, 2] += (new_w/2) - origin_X |
| 47 | + M[1, 2] += (new_h/2) - origin_Y |
| 48 | + adj_lmap = cv2.warpAffine(local_map, M, (new_w, new_h)) |
| 49 | + |
| 50 | + #Add values from adjusted local map to world map |
| 51 | + |
| 52 | + (adj_x, adj_y) = adj_lmap.shape[:2] |
| 53 | + |
| 54 | + |
28 | 55 | local_x = cur_tf.getOrigin().x()
|
29 | 56 | local_y = cur_tf.getOrigin().y()
|
30 |
| - for y in local_map: |
31 |
| - local_y = cur_tf.getOrigin().y() |
32 |
| - for x in y: |
33 |
| - self.map[local_y][local_x] = local_map[y][x] |
34 |
| - local_y += 1 |
35 |
| - local_x += 1 |
| 57 | + (field_x, field_y) = Field.shape[:2] |
| 58 | + field_x /= 2 |
| 59 | + field_y /= 2 |
| 60 | + dif_x = np.abs(field_x - local_x) |
| 61 | + dif_y = np.abs(field_y - local_y) |
| 62 | + |
| 63 | + Field[dif_x:(dif_x+adj_x), dif_y:(dif_y+adj_y)] = adj_lmap |
| 64 | + |
36 | 65 |
|
37 |
| - |
| 66 | + |
38 | 67 |
|
39 |
| - |
40 |
| - def msg_callback(new_map.msg): |
| 68 | +if __name__ == "__main__": |
| 69 | + field = Field(length = 600, width = 400) |
| 70 | + #listener = tf.transform_listener() |
| 71 | + rospy.Subscriber("elevation_mapping/occ_grid", OccupancyGrid, field.update_field) |
| 72 | + rospy.spin() |
41 | 73 |
|
42 | 74 |
|
0 commit comments