00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044 import rospy
00045 import tf
00046 import PyKDL
00047
00048
00049 from applanix_msgs.msg import NavigationSolution, GNSSStatus, IMUData
00050 import geodesy.utm
00051
00052
00053 from sensor_msgs.msg import Imu, NavSatFix, NavSatStatus
00054 from nav_msgs.msg import Odometry
00055 from geometry_msgs.msg import Quaternion, Point, Pose
00056
00057
00058 from math import radians as RAD
00059
00060
00061
00062 IMU_ORIENT_COVAR = [1e-3, 0, 0,
00063 0, 1e-3, 0,
00064 0, 0, 1e-3]
00065
00066 IMU_VEL_COVAR = [1e-3, 0, 0,
00067 0, 1e-3, 0,
00068 0, 0, 1e-3]
00069
00070 IMU_ACCEL_COVAR = [1e-3, 0, 0,
00071 0, 1e-3, 0,
00072 0, 0, 1e-3]
00073
00074 NAVSAT_COVAR = [1, 0, 0,
00075 0, 1, 0,
00076 0, 0, 1]
00077
00078 POSE_COVAR = [1, 0, 0, 0, 0, 0,
00079 0, 1, 0, 0, 0, 0,
00080 0, 0, 1, 0, 0, 0,
00081 0, 0, 0, 0.1, 0, 0,
00082 0, 0, 0, 0, 0.1, 0,
00083 0, 0, 0, 0, 0, 0.1]
00084
00085 TWIST_COVAR = [1, 0, 0, 0, 0, 0,
00086 0, 1, 0, 0, 0, 0,
00087 0, 0, 1, 0, 0, 0,
00088 0, 0, 0, 0.1, 0, 0,
00089 0, 0, 0, 0, 0.1, 0,
00090 0, 0, 0, 0, 0, 0.1]
00091
00092 class ApplanixPublisher(object):
00093
00094 def __init__(self):
00095 rospy.init_node('applanix_publisher')
00096
00097 self.publish_tf = rospy.get_param('~publish_tf', False)
00098 self.odom_frame = rospy.get_param('~odom_frame', 'odom_combined')
00099 self.base_frame = rospy.get_param('~base_frame', 'base_footprint')
00100 self.zero_start = rospy.get_param('~zero_start', False)
00101
00102 origin_param = rospy.get_param('/gps_origin', None)
00103 self.origin = Point()
00104 if origin_param is not None and origin_param != "None":
00105 self.zero_start = False
00106 self.origin.x = origin_param["east"]
00107 self.origin.y = origin_param["north"]
00108 self.origin.z = origin_param["alt"]
00109 elif not self.zero_start:
00110 origin_param = {
00111 "east" : self.origin.x,
00112 "north" : self.origin.y,
00113 "alt" : self.origin.z,
00114 }
00115 rospy.set_param('/gps_origin', origin_param)
00116
00117
00118 self.pub_imu = rospy.Publisher('imu_data', Imu, queue_size=5)
00119 self.pub_odom = rospy.Publisher('gps_odom', Odometry, queue_size=5)
00120 self.pub_origin = rospy.Publisher('origin', Pose, queue_size=5)
00121 self.pub_navsatfix = rospy.Publisher('gps_fix', NavSatFix, queue_size=5)
00122 self.pub_navsatstatus = rospy.Publisher('gps_status', NavSatStatus, queue_size=5)
00123 if self.publish_tf:
00124 self.tf_broadcast = tf.TransformBroadcaster()
00125
00126
00127 self.nav_status = NavSatStatus()
00128 self.nav_status.status = NavSatStatus.STATUS_NO_FIX
00129 self.nav_status.service = NavSatStatus.SERVICE_GPS
00130
00131 self.init = False
00132
00133
00134 rospy.Subscriber('nav', NavigationSolution, self.navigation_handler)
00135 rospy.Subscriber('status/gnss/primary', GNSSStatus, self.status_handler)
00136
00137 def navigation_handler(self, data):
00138 """ Rebroadcasts navigation data in the following formats:
00139 1) /odom => /base footprint transform (if enabled, as per REP 105)
00140 2) Odometry message, with parent/child IDs as in #1
00141 3) NavSatFix message, for systems which are knowledgeable about GPS stuff
00142 4) IMU messages
00143 """
00144 rospy.logdebug("Navigation received")
00145
00146 if self.nav_status.status == NavSatStatus.STATUS_NO_FIX:
00147 return
00148
00149
00150
00151
00152
00153
00154 orient = PyKDL.Rotation.RPY(RAD(data.roll), RAD(-data.pitch), RAD(90-data.heading)).GetQuaternion()
00155
00156
00157 utm_pos = geodesy.utm.fromLatLong(data.latitude, data.longitude)
00158
00159 if not self.init and self.zero_start:
00160 self.origin.x = utm_pos.easting
00161 self.origin.y = utm_pos.northing
00162 self.origin.z = data.altitude
00163 self.init = True
00164 origin_param = {
00165 "east" : self.origin.x,
00166 "north" : self.origin.y,
00167 "alt" : self.origin.z,
00168 }
00169 rospy.set_param('/gps_origin', origin_param)
00170
00171
00172 p = Pose()
00173 p.position.x = self.origin.x
00174 p.position.y = self.origin.y
00175 p.position.z = self.origin.z
00176 self.pub_origin.publish(p)
00177
00178
00179
00180
00181
00182 odom = Odometry()
00183 odom.header.stamp = rospy.Time.now()
00184 odom.header.frame_id = self.odom_frame
00185 odom.child_frame_id = self.base_frame
00186 odom.pose.pose.position.x = utm_pos.easting - self.origin.x
00187 odom.pose.pose.position.y = utm_pos.northing - self.origin.y
00188 odom.pose.pose.position.z = data.altitude - self.origin.z
00189 odom.pose.pose.orientation = Quaternion(*orient)
00190 odom.pose.covariance = POSE_COVAR
00191
00192
00193
00194 odom.twist.twist.linear.x = data.east_vel
00195 odom.twist.twist.linear.y = data.north_vel
00196 odom.twist.twist.linear.z = -data.down_vel
00197 odom.twist.twist.angular.x = RAD(data.ang_rate_long)
00198 odom.twist.twist.angular.y = RAD(-data.ang_rate_trans)
00199 odom.twist.twist.angular.z = RAD(-data.ang_rate_down)
00200 odom.twist.covariance = TWIST_COVAR
00201
00202 self.pub_odom.publish(odom)
00203
00204 t_tf = odom.pose.pose.position.x, odom.pose.pose.position.y, odom.pose.pose.position.z
00205 q_tf = Quaternion(*orient).x, Quaternion(*orient).y, Quaternion(*orient).z, Quaternion(*orient).w
00206
00207
00208
00209 if self.publish_tf:
00210 self.tf_broadcast.sendTransform(t_tf,q_tf,
00211 odom.header.stamp,odom.child_frame_id, odom.header.frame_id)
00212
00213
00214
00215
00216
00217 navsat = NavSatFix()
00218 navsat.header.stamp = rospy.Time.now()
00219 navsat.header.frame_id = self.odom_frame
00220 navsat.status = self.nav_status
00221
00222 navsat.latitude = data.latitude
00223 navsat.longitude = data.longitude
00224 navsat.altitude = data.altitude
00225
00226 navsat.position_covariance = NAVSAT_COVAR
00227 navsat.position_covariance_type = NavSatFix.COVARIANCE_TYPE_UNKNOWN
00228
00229 self.pub_navsatfix.publish(navsat)
00230
00231
00232
00233
00234
00235 imu = Imu()
00236 imu.header.stamp == rospy.Time.now()
00237 imu.header.frame_id = self.base_frame
00238
00239
00240 imu.orientation = Quaternion(*orient)
00241 imu.orientation_covariance = IMU_ORIENT_COVAR
00242
00243
00244 imu.angular_velocity.x = RAD(data.ang_rate_long)
00245 imu.angular_velocity.y = RAD(-data.ang_rate_trans)
00246 imu.angular_velocity.z = RAD(-data.ang_rate_down)
00247 imu.angular_velocity_covariance = IMU_VEL_COVAR
00248
00249
00250 imu.linear_acceleration.x = data.long_accel
00251 imu.linear_acceleration.y = data.trans_accel
00252 imu.linear_acceleration.z = data.down_accel
00253 imu.linear_acceleration_covariance = IMU_ACCEL_COVAR
00254
00255 self.pub_imu.publish(imu)
00256
00257
00258 pass
00259
00260 def status_handler(self, data):
00261 """ Rebroadcasts GNSS status as a standard NavSatStatus message """
00262
00263 solution_map = {
00264 GNSSStatus.SOLUTION_UNKNOWN: NavSatStatus.STATUS_NO_FIX,
00265 GNSSStatus.SOLUTION_NO_DATA: NavSatStatus.STATUS_NO_FIX,
00266 GNSSStatus.SOLUTION_HORIZONTAL_CA: NavSatStatus.STATUS_FIX,
00267 GNSSStatus.SOLUTION_3D_CA: NavSatStatus.STATUS_FIX,
00268 GNSSStatus.SOLUTION_HORIZONTAL_DGPS: NavSatStatus.STATUS_SBAS_FIX,
00269 GNSSStatus.SOLUTION_3D_DGPS: NavSatStatus.STATUS_SBAS_FIX,
00270 GNSSStatus.SOLUTION_FLOAT_RTK: NavSatStatus.STATUS_GBAS_FIX,
00271 GNSSStatus.SOLUTION_WIDE_LANE_RTK: NavSatStatus.STATUS_GBAS_FIX,
00272 GNSSStatus.SOLUTION_NARROW_LANE_RTK: NavSatStatus.STATUS_GBAS_FIX,
00273 GNSSStatus.SOLUTION_P_CODE: NavSatStatus.STATUS_FIX,
00274 GNSSStatus.SOLUTION_OMNISTAR_HP: NavSatStatus.STATUS_SBAS_FIX,
00275 GNSSStatus.SOLUTION_OMNISTAR_XP: NavSatStatus.STATUS_SBAS_FIX,
00276 GNSSStatus.SOLUTION_OMNISTAR_VBS: NavSatStatus.STATUS_SBAS_FIX,
00277 }
00278 self.nav_status.status = solution_map.get(data.solution_status,NavSatStatus.STATUS_NO_FIX)
00279
00280
00281 self.nav_status.service = NavSatStatus.SERVICE_GPS
00282
00283 self.pub_navsatstatus.publish(self.nav_status)
00284
00285
00286 def main():
00287 node = ApplanixPublisher()
00288 rospy.spin()