99import rospy
1010import ros_numpy
1111from tf .transformations import quaternion_matrix
12- from sensor_msgs .msg import PointCloud2
1312import tf2_ros
1413import rospkg
1514
15+ from sensor_msgs .msg import PointCloud2
16+ from grid_map_msgs .msg import GridMap
17+ from std_msgs .msg import Float32MultiArray
18+ from std_msgs .msg import MultiArrayLayout as MAL
19+ from std_msgs .msg import MultiArrayDimension as MAD
20+
1621class ElevationMapWrapper ():
1722 def __init__ (self ):
1823 rospack = rospkg .RosPack ()
1924 self .root = rospack .get_path ("elevation_mapping_cupy" )
2025 self .initalize_elevation_mapping ()
21-
26+ self . node_name = "elevation_mapping"
2227 # ROS
2328 self .initalize_ros ()
2429 self .register_subscribers ()
@@ -29,12 +34,15 @@ def initalize_elevation_mapping(self):
2934 weight_file = os .path .join (self .root , "config/weights.dat" )
3035 plugin_config_file = os .path .join (self .root , "config/plugin_config.yaml" )
3136 param = Parameter ( use_chainer = False , weight_file = weight_file , plugin_config_file = plugin_config_file )
37+ param .update ()
3238 self ._pointcloud_process_counter = 0
3339 self ._map = ElevationMap (param )
3440 self ._map_data = np .zeros ((self ._map .cell_n - 2 , self ._map .cell_n - 2 ), dtype = np .float32 )
41+ self ._map_q = None
42+ self ._map_t = None
3543
3644 def initalize_ros (self ):
37- rospy .init_node ("elevation_mapping" , anonymous = False )
45+ rospy .init_node (self . node_name , anonymous = False )
3846 self ._tf_buffer = tf2_ros .Buffer ()
3947 self ._listener = tf2_ros .TransformListener (self ._tf_buffer )
4048 self .get_ros_params ()
@@ -47,37 +55,79 @@ def register_subscribers(self):
4755
4856 def register_publishers (self ):
4957 # TODO publishers
50- print (self .publishers )
58+ self ._publishers = {}
59+ self ._publishers_timers = []
60+ for k , v in self .publishers .items ():
61+ print (f"Register Publisher: { k } " )
62+ self ._publishers [k ] = rospy .Publisher (f"/{ self .node_name } /{ k } " , GridMap , queue_size = 10 )
63+ self ._publishers_timers .append ( rospy .Timer (rospy .Duration (1 / v ["fps" ]), lambda x : self .publish_map (x , k )))
64+
65+ def publish_map (self , t , k ):
66+ print (k )
67+ if self ._map_q is None :
68+ return
5169
70+ gm = GridMap ()
71+ gm .info .header .frame_id = self .map_frame
72+ gm .info .header .stamp = rospy .Time .now ()
73+ gm .info .header .seq = 0
74+ gm .info .resolution = self ._map .resolution
75+ gm .info .length_x = self ._map .map_length
76+ gm .info .length_y = self ._map .map_length
77+ gm .info .pose .position .x = self ._map_t .x
78+ gm .info .pose .position .y = self ._map_t .y
79+ gm .info .pose .position .z = self ._map_t .z
80+ gm .info .pose .orientation .w = 1 # self._map_q.w
81+ gm .info .pose .orientation .x = 0 # self._map_q.x
82+ gm .info .pose .orientation .y = 0 # self._map_q.y
83+ gm .info .pose .orientation .z = 0 # self._map_q.z
84+ gm .layers = self .publishers [k ]["layers" ]
85+ gm .basic_layers = self .publishers [k ]["basic_layers" ]
86+
87+ # arr.layout.dim = [int(gm.info.length_x/gm.info.resolution), int(gm.info.length_y/gm.info.resolution)]
88+
89+ for i , layer in enumerate (gm .layers ):
90+ self ._map .get_map_with_name_ref (layer , self ._map_data )
91+ self ._map_data = np .nan_to_num (self ._map_data , False , 0 )
92+ data = self ._map_data .copy ()
93+ arr = Float32MultiArray ()
94+ arr .layout = MAL ()
95+ N = self ._map_data .shape [0 ]
96+ arr .layout .dim .append ( MAD (label = "column_index" ,size = N ,stride = int (N * N )))
97+ arr .layout .dim .append ( MAD (label = "row_index" ,size = N ,stride = N ))
98+ arr .data = tuple (np .ascontiguousarray (data ).reshape (- 1 ))
99+ gm .data .append ( arr )
100+
101+ self ._publishers [k ].publish ( gm )
102+
52103 def register_timers (self ):
53104 self .timer_variance = rospy .Timer (rospy .Duration (1 / self .update_variance_fps ), self .update_variance )
54105 self .timer_pose = rospy .Timer (rospy .Duration (1 / self .update_pose_fps ), self .update_pose )
55106 self .timer_time = rospy .Timer (rospy .Duration (self .time_interval ), self .update_time )
56107
57- def pointcloud_callback (self , data , config ):
108+ def pointcloud_callback (self , msg , config ):
58109 # convert pcd into numpy array
59- points = ros_numpy .numpify (data )
60- out = np .copy ( np .frombuffer (points .tobytes (), np .dtype (np .float32 ) ))
61- out = out .reshape (out .shape [0 ],- 1 )[:,:3 ]
62- points = points .astype (np .float32 )
110+ channels = config [0 ]
111+ fusion = config [1 ]
112+ points = ros_numpy .point_cloud2 .pointcloud2_to_xyz_array (msg )
63113
64114 # get pose of pointcloud
65- t = rospy .Time (secs = data .header .stamp .secs , nsecs = data .header .stamp .nsecs )
115+ t = rospy .Time (secs = msg .header .stamp .secs , nsecs = msg .header .stamp .nsecs )
66116 try :
67- transform = self ._tf_buffer .lookup_transform (self .map_frame , data .header .frame_id , t , rospy .Duration (1.0 ))
117+ transform = self ._tf_buffer .lookup_transform (self .map_frame , msg .header .frame_id , t , rospy .Duration (1.0 ))
68118 except (tf2_ros .LookupException , tf2_ros .ConnectivityException , tf2_ros .ExtrapolationException ) as e :
69119 print (e )
70120 return
71121
72122 t = transform .transform .translation
73123 t = np .array ( [t .x , t .y , t .z ] )
74124 q = transform .transform .rotation
75- R = quaternion_matrix ([q .w , q .x , q .y , q .z ])
125+ R = quaternion_matrix ([q .w , q .x , q .y , q .z ])[: 3 ,: 3 ]
76126
77127 # process pointcloud
78- self ._map .input (points , 0 , R , t , 0 , 0 )
79- self ._map .update_normal (self ._map .elevation_map [0 ])
128+ self ._map .input (points , ['x' ,'y' ,'z' ]+ channels , R , t , 0 , 0 )
80129 self ._pointcloud_process_counter += 1
130+ print (self ._pointcloud_process_counter )
81131
82132 def update_pose (self , t ):
83133 # get pose of base
@@ -90,9 +140,12 @@ def update_pose(self, t):
90140 t = transform .transform .translation
91141 trans = np .array ( [t .x , t .y , t .z ] )
92142 q = transform .transform .rotation
93- rot = quaternion_matrix ([q .w , q .x , q .y , q .z ])
143+ rot = quaternion_matrix ([q .w , q .x , q .y , q .z ])[: 3 ,: 3 ]
94144 self ._map .move_to (trans , rot )
95145
146+ self ._map_t = t
147+ self ._map_q = q
148+
96149 def update_variance (self , t ):
97150 self ._map .update_variance ()
98151
@@ -104,9 +157,9 @@ def get_ros_params(self):
104157 # This is currently {p} elevation_mapping")
105158 para = os .path .join (self .root , "config/parameters.yaml" )
106159 sens = os .path .join (self .root , "config/sensor_parameter.yaml" )
160+ os .system (f"rosparam delete /{ self .node_name } " )
107161 os .system (f"rosparam load { para } elevation_mapping" )
108162 os .system (f"rosparam load { sens } elevation_mapping" )
109-
110163 self .subscribers = rospy .get_param ("~subscribers" )
111164 self .publishers = rospy .get_param ("~publishers" )
112165 self .initialize_frame_id = rospy .get_param ("~initialize_frame_id" , "base" )
0 commit comments