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
00017 std::string tf_prefix;
00018
00019
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;
00029 double right_steps=-5;
00030 bool dir_left = true;
00031 bool dir_right = true;
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
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
00049 tf::TransformListener listener;
00050 tf::StampedTransform transform;
00051
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
00077 return (2* M_PI - (old_steps - new_steps)) / dt;
00078 }else if (!dir && old_steps < 0 && new_steps > 0){
00079
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
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
00110 x_speed = (WHEEL_RADIUS *
00111 (left_angular + right_angular)) / 2;
00112 yaw = getYaw(right_angular, left_angular);
00113
00114
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
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
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
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
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
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
00188 publisher = n.advertise<nav_msgs::Odometry>(odom_publish_topic, 1000);
00189
00190 ROS_INFO("DPL: OdomProvider initialized");
00191
00192
00193 ros::spin();
00194
00195 return 0;
00196 }