dead_reckoning.py
Go to the documentation of this file.
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


husky_bringup
Author(s): Mike Purvis, Ryan Gariepy
autogenerated on Sun Oct 5 2014 22:53:15