$search
00001 #!/usr/bin/env python 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 # Dynamic Reconfigure 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 # Parameters 00049 self.width = rospy.get_param('~width',0.5) 00050 self.gyro_scale = rospy.get_param('~gyro_scale_correction',1.0) 00051 00052 # Set up publishers/subscribers 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 # Initialize odometry message 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 # Handler for dynamic_reconfigure 00068 self.gyro_scale = config['gyro_scale_correction'] 00069 return config 00070 00071 def HandleIMU(self,data): 00072 # Correct IMU data 00073 # Right now, gyro scale only 00074 # TODO: Evaluate necessity of adding drift correction 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 # Initialize encoder state 00082 if not self.last_encoder: 00083 self.last_encoder = data 00084 return 00085 # Calculate deltas 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 # Update data 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 # If our wheels aren't moving, we're likely not moving at all. 00107 # Adjust covariance appropriately 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