odometry_provider.cpp
Go to the documentation of this file.
00001 #include <ros/ros.h>
00002 
00003 #include <sensor_msgs/JointState.h>
00004 #include <nav_msgs/Odometry.h>
00005 
00006 #include <message_filters/subscriber.h>
00007 #include <message_filters/synchronizer.h>
00008 #include <message_filters/sync_policies/approximate_time.h>
00009 
00010 #include <tf/transform_listener.h>
00011 
00012 #include <string>
00013 #include <utility>
00014 #include <math.h>
00015 
00016 // robot's index in ROS ecosystem (if multiple instances)
00017 std::string tf_prefix;
00018 
00019 // publisher in IMU for imu message
00020 ros::Publisher publisher;
00021 
00022 double WHEELS_HALF_SPACING = 0.15;
00023 double WHEEL_RADIUS = 0.098;
00024 
00025 double pos_x = 0;
00026 double pos_y = 0;
00027 double pos_th = 0;
00028 double left_steps=-5; // range from -PI to PI
00029 double right_steps=-5;
00030 bool dir_left = true; // direction of rotation of left wheel true== forward
00031 bool dir_right = true; // direction of rotation of right wheel true== forward
00032 ros::Time last_time;
00033 
00034 double left_angular = 0;
00035 double right_angular = 0;
00036 
00037 std::string odom_frame_id="/odom";
00038 std::string odom_publish_topic="odom";
00039 std::string odom_right_wheel="hal/rightMotor/getState";
00040 std::string odom_left_wheel="hal/leftMotor/getState";
00041 
00042 // calculates inverse kinematic value of robot heading with differencial drive
00043 double getYaw(const double velRight, const double velLeft) {
00044   return (WHEEL_RADIUS * (velRight - velLeft)) / (2*WHEELS_HALF_SPACING);
00045 }
00046 
00047 void setWheelSpacing(const std::string & motor_left_frame,const std::string & motor_right_frame) {
00048   // tf listener for calculation of wheel spacing
00049   tf::TransformListener listener;
00050   tf::StampedTransform transform;
00051   // get length in between wheels
00052   try {
00053     listener.waitForTransform(tf_prefix + motor_left_frame,
00054                               tf_prefix + motor_right_frame,
00055                               ros::Time::now(), ros::Duration(10.0));
00056     listener.lookupTransform(tf_prefix + motor_left_frame,
00057                              tf_prefix + motor_right_frame,
00058                              ros::Time(0), transform);
00059     WHEELS_HALF_SPACING = transform.getOrigin().absolute().getY() / 2;
00060     ROS_INFO("DPL: motor_controler WHEELS_HALF_SPACING: %f",
00061              WHEELS_HALF_SPACING);
00062 
00063   } catch (tf::TransformException ex) {
00064     ROS_ERROR("Problem with transformation between wheels: %s", ex.what());
00065   }
00066 }
00074 double getAngularVel(const double old_steps, const double new_steps, const bool dir,const double dt){
00075   if(dir && old_steps > 0 && new_steps < 0){
00076     // overflow from PI --> -PI
00077     return (2* M_PI - (old_steps - new_steps)) / dt;
00078   }else if (!dir && old_steps < 0 && new_steps > 0){
00079     // overflow in negative direction from -PI --> PI
00080     return (-2*M_PI + (new_steps - old_steps)) / dt;
00081   }
00082   return (new_steps-old_steps) / dt;
00083 }
00084 
00085 void odomData_cb(const sensor_msgs::JointState::ConstPtr &left_motor_msg,
00086                  const sensor_msgs::JointState::ConstPtr &right_motor_msg) {
00087   nav_msgs::Odometry odom_msg;
00088   double yaw;
00089   double x_speed;
00090   double dt = (left_motor_msg->header.stamp - last_time).toSec();
00091 
00092   // calculate andular velocities from angular diplacement in both joints
00093   if(left_steps > -4 || right_steps > -4){
00094     if(dt != 0){
00095       left_angular = getAngularVel(left_steps, left_motor_msg->position[0],dir_left,dt);
00096       right_angular = getAngularVel(right_steps, right_motor_msg->position[0],dir_right,dt);
00097     }
00098   }
00099   if(left_angular > 0)
00100     dir_left = true;
00101   else
00102     dir_left = false;
00103   if (right_angular > 0)
00104     dir_right = true;
00105   else
00106     dir_right = false;
00107   right_steps = right_motor_msg->position[0];
00108   left_steps = left_motor_msg->position[0];
00109   // calculate robot's forward speed and yaw
00110   x_speed = (WHEEL_RADIUS *
00111             (left_angular + right_angular)) / 2;
00112   yaw = getYaw(right_angular, left_angular);
00113 
00114   // move old point in 2D space to new predicted position and an angle
00115   if(dt != 0){
00116     pos_x += (x_speed * cos(pos_th)) * dt;
00117     pos_y += (x_speed * sin(pos_th)) * dt;
00118     pos_th += yaw * dt;
00119   }
00120 
00121   geometry_msgs::Quaternion odom_quat = tf::createQuaternionMsgFromYaw(pos_th);
00122 
00123   // create odom msg
00124   odom_msg.header.frame_id = tf_prefix + odom_frame_id;
00125   odom_msg.header.stamp = last_time;
00126   odom_msg.pose.pose.position.x = pos_x;
00127   odom_msg.pose.pose.position.y = pos_y;
00128   odom_msg.pose.pose.orientation = odom_quat;
00129   odom_msg.child_frame_id = tf_prefix + "/base_footprint";
00130   odom_msg.twist.twist.linear.x = x_speed;
00131   odom_msg.twist.twist.angular.z = yaw;
00132   // add covariance
00133   double c =10e-4;
00134   odom_msg.pose.covariance={c,0,0,0,0,0,
00135                             0,c,0,0,0,0,
00136                             0,0,c,0,0,0,
00137                             0,0,0,c,0,0,
00138                             0,0,0,0,c,0,
00139                             0,0,0,0,0,c};
00140   odom_msg.twist.covariance={c,0,0,0,0,0,
00141                              0,c,0,0,0,0,
00142                              0,0,c,0,0,0,
00143                              0,0,0,c,0,0,
00144                              0,0,0,0,c,0,
00145                              0,0,0,0,0,c};
00146   publisher.publish(odom_msg);
00147 
00148   last_time = left_motor_msg->header.stamp;
00149 }
00150 
00151 int main(int argc, char **argv) {
00152   ros::init(argc, argv, "odometryProvider");
00153   ros::NodeHandle n;
00154   std::string frame_id_left_wheel="/base/joint1";
00155   std::string frame_id_right_wheel="/base/joint0";
00156 
00157   // get parameters
00158   std::string tf_prefix_path;
00159   if (n.searchParam("tf_prefix", tf_prefix_path))
00160   {
00161     n.getParam(tf_prefix_path, tf_prefix);
00162   }
00163   ros::param::get("~leftWheelTopic", odom_left_wheel);
00164   ros::param::get("~rightWheelTopic", odom_right_wheel);
00165   ros::param::get("~odomPublTopic", odom_publish_topic);
00166   ros::param::get("~frameIDLeftWheel", frame_id_left_wheel);
00167   ros::param::get("~frameIDRightWheel", frame_id_right_wheel);
00168   ros::param::get("~frameIDodom",  odom_frame_id);
00169 
00170   last_time = ros::Time::now();
00171   setWheelSpacing(frame_id_left_wheel,frame_id_right_wheel);
00172 
00173   // subscribers to motors' states and imu
00174   message_filters::Subscriber<sensor_msgs::JointState> left_motor_sub(
00175       n, odom_left_wheel, 1000);
00176   message_filters::Subscriber<sensor_msgs::JointState> right_motor_sub(
00177       n, odom_right_wheel, 1000);
00178 
00179   // sync messages using approximate alghorithm
00180   constexpr int allowed_delay = 10;
00181   typedef message_filters::sync_policies::ApproximateTime<
00182       sensor_msgs::JointState, sensor_msgs::JointState> OdomSyncPolicy;
00183   message_filters::Synchronizer<OdomSyncPolicy> odom_processor(
00184       OdomSyncPolicy(allowed_delay), left_motor_sub, right_motor_sub);
00185   odom_processor.registerCallback(odomData_cb);
00186 
00187   // publish fused message
00188   publisher = n.advertise<nav_msgs::Odometry>(odom_publish_topic, 1000);
00189 
00190   ROS_INFO("DPL: OdomProvider initialized");
00191 
00192   // runs event loop
00193   ros::spin();
00194 
00195   return 0;
00196 }


p3dx_dpl
Author(s):
autogenerated on Sat Jun 8 2019 20:22:37