00001
00002 import roslib; roslib.load_manifest('husky_bringup')
00003 import roslib.rosenv
00004 import rospy
00005 import PyKDL
00006 import copy
00007
00008 from math import sin,cos
00009 from geometry_msgs.msg import Quaternion
00010 from sensor_msgs.msg import Imu
00011 from nav_msgs.msg import Odometry
00012 from clearpath_base.msg import Encoders
00013
00014
00015 import dynamic_reconfigure.server
00016 from husky_bringup.cfg import HuskyConfig
00017
00018 ODOM_POSE_COVAR_MOTION = [1e-3, 0, 0, 0, 0, 0,
00019 0, 1e-3, 0, 0, 0, 0,
00020 0, 0, 1e6, 0, 0, 0,
00021 0, 0, 0, 1e6, 0, 0,
00022 0, 0, 0, 0, 1e6, 0,
00023 0, 0, 0, 0, 0, 1e6]
00024 ODOM_POSE_COVAR_NOMOVE = [1e-9, 0, 0, 0, 0, 0,
00025 0, 1e-3, 1e-9, 0, 0, 0,
00026 0, 0, 1e6, 0, 0, 0,
00027 0, 0, 0, 1e6, 0, 0,
00028 0, 0, 0, 0, 1e6, 0,
00029 0, 0, 0, 0, 0, 1e-9]
00030
00031 ODOM_TWIST_COVAR_MOTION = [1e-3, 0, 0, 0, 0, 0,
00032 0, 1e-3, 0, 0, 0, 0,
00033 0, 0, 1e6, 0, 0, 0,
00034 0, 0, 0, 1e6, 0, 0,
00035 0, 0, 0, 0, 1e6, 0,
00036 0, 0, 0, 0, 0, 1e6]
00037 ODOM_TWIST_COVAR_NOMOVE = [1e-9, 0, 0, 0, 0, 0,
00038 0, 1e-3, 1e-9, 0, 0, 0,
00039 0, 0, 1e6, 0, 0, 0,
00040 0, 0, 0, 1e6, 0, 0,
00041 0, 0, 0, 0, 1e6, 0,
00042 0, 0, 0, 0, 0, 1e-9]
00043
00044
00045 class DeadReckoning(object):
00046 def __init__(self):
00047 rospy.init_node('dead_reckoning')
00048
00049 self.width = rospy.get_param('~width',0.5)
00050 self.gyro_scale = rospy.get_param('~gyro_scale_correction',1.0)
00051
00052
00053 self.pub_imu = rospy.Publisher('imu_data',Imu)
00054 self.pub_enc_odom = rospy.Publisher('encoder',Odometry);
00055 rospy.Subscriber('imu/data', Imu, self.HandleIMU)
00056 rospy.Subscriber('husky/data/encoders', Encoders, self.HandleEncoder)
00057
00058
00059 self.odom = Odometry()
00060 self.odom.header.frame_id = "odom_combined"
00061 self.odom.child_frame_id = "base_footprint"
00062 self.last_encoder = []
00063
00064 dynamic_reconfigure.server.Server(HuskyConfig, self.Reconfigure)
00065
00066 def Reconfigure(self, config, level):
00067
00068 self.gyro_scale = config['gyro_scale_correction']
00069 return config
00070
00071 def HandleIMU(self,data):
00072
00073
00074
00075 imu_corr = copy.deepcopy(data)
00076 imu_corr.header.frame_id = "base_link"
00077 imu_corr.angular_velocity.z = data.angular_velocity.z * self.gyro_scale
00078 self.pub_imu.publish(imu_corr)
00079
00080 def HandleEncoder(self,data):
00081
00082 if not self.last_encoder:
00083 self.last_encoder = data
00084 return
00085
00086 dr = ((data.encoders[0].travel - self.last_encoder.encoders[0].travel) +
00087 (data.encoders[1].travel - self.last_encoder.encoders[1].travel)) / 2;
00088 da = ((data.encoders[1].travel - self.last_encoder.encoders[1].travel) -
00089 (data.encoders[0].travel - self.last_encoder.encoders[0].travel)) / self.width;
00090 ddr = (data.encoders[0].speed + data.encoders[1].speed)/2;
00091 dda = (data.encoders[1].speed - data.encoders[0].speed)/self.width;
00092 self.last_encoder = data
00093
00094
00095 o = self.odom.pose.pose.orientation
00096 cur_heading = PyKDL.Rotation.Quaternion(o.x,o.y,o.z,o.w).GetEulerZYX()
00097 self.odom.pose.pose.position.x += dr * cos(cur_heading[0])
00098 self.odom.pose.pose.position.y += dr * sin(cur_heading[0])
00099 quat = PyKDL.Rotation.RotZ(cur_heading[0] + da).GetQuaternion()
00100 self.odom.pose.pose.orientation = Quaternion(quat[0],quat[1],quat[2],quat[3])
00101 self.odom.twist.twist.linear.x = ddr
00102 self.odom.twist.twist.angular.z = dda
00103
00104 self.odom.header.stamp = rospy.Time.now()
00105
00106
00107
00108 if data.encoders[0].speed == 0 and data.encoders[1].speed == 0:
00109 self.odom.pose.covariance = ODOM_POSE_COVAR_NOMOVE
00110 self.odom.twist.covariance = ODOM_TWIST_COVAR_NOMOVE
00111 else:
00112 self.odom.pose.covariance = ODOM_POSE_COVAR_MOTION
00113 self.odom.twist.covariance = ODOM_TWIST_COVAR_MOTION
00114
00115 self.pub_enc_odom.publish(self.odom)
00116
00117 if __name__ == "__main__":
00118 obj = DeadReckoning()
00119 try:
00120 rospy.spin()
00121 except rospy.ROSInterruptException:
00122 pass