00001 #include "evarobot_odometry/evarobot_odometry.h"
00002
00003 #include <dynamic_reconfigure/server.h>
00004 #include <evarobot_odometry/ParamsConfig.h>
00005
00006 bool b_is_received_params = false;
00007
00008 bool b_reset_odom = false;
00009 double d_wheel_separation;
00010 double d_height;
00011 int i_gear_ratio;
00012 int i_cpr;
00013 double d_wheel_diameter;
00014
00015 int i_error_code = 0;
00016
00017 void CallbackReconfigure(evarobot_odometry::ParamsConfig &config, uint32_t level)
00018 {
00019 b_is_received_params = true;
00020
00021 d_wheel_separation = config.wheelSeparation;
00022 d_height = config.height;
00023 i_gear_ratio = config.gearRatio;
00024 i_cpr = config.CPR;
00025 d_wheel_diameter = config.wheelDiameter;
00026 }
00027
00028 bool CallbackResetOdom(std_srvs::Empty::Request& request, std_srvs::Empty::Response& response)
00029 {
00030 ROS_DEBUG("EvarobotOdometry: Reset Odometry");
00031 b_reset_odom = true;
00032 return true;
00033 }
00034
00035
00036
00037 void ProduceDiagnostics(diagnostic_updater::DiagnosticStatusWrapper &stat)
00038 {
00039 if(i_error_code<0)
00040 {
00041 stat.summaryf(diagnostic_msgs::DiagnosticStatus::ERROR, "%s", GetErrorDescription(i_error_code).c_str());
00042 i_error_code = 0;
00043 }
00044 else
00045 {
00046 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "EvarobotOdometry: No problem.");
00047 }
00048 }
00049
00050 int main(int argc, char **argv)
00051 {
00052 int i_fd;
00053 double d_frequency;
00054 double d_min_freq, d_max_freq;
00055 stringstream ss;
00056
00057 string str_device_path;
00058
00059 ros::init(argc, argv, "/evarobot_odometry");
00060 ros::NodeHandle n;
00061
00062 n.param<string>("evarobot_odometry/devicePath", str_device_path, "/dev/evarobotEncoder");
00063 n.param("evarobot_odometry/minFreq", d_min_freq, 0.2);
00064 n.param("evarobot_odometry/maxFreq", d_max_freq, 10.0);
00065
00066 if(!n.getParam("evarobot_odometry/wheelSeparation", d_wheel_separation))
00067 {
00068 ROS_INFO(GetErrorDescription(-108).c_str());
00069 i_error_code = -108;
00070 }
00071
00072 if(!n.getParam("evarobot_odometry/height", d_height))
00073 {
00074 ROS_INFO(GetErrorDescription(-109).c_str());
00075 i_error_code = -109;
00076 }
00077
00078 if(!n.getParam("evarobot_odometry/frequency", d_frequency))
00079 {
00080 ROS_INFO(GetErrorDescription(-110).c_str());
00081 i_error_code = -110;
00082 }
00083
00084 if(!n.getParam("evarobot_odometry/gearRatio", i_gear_ratio))
00085 {
00086 ROS_INFO(GetErrorDescription(-111).c_str());
00087 i_error_code = -111;
00088 }
00089
00090 if(!n.getParam("evarobot_odometry/CPR", i_cpr))
00091 {
00092 ROS_INFO(GetErrorDescription(-112).c_str());
00093 i_error_code = -112;
00094 }
00095
00096 if(!n.getParam("evarobot_odometry/wheelDiameter", d_wheel_diameter))
00097 {
00098 ROS_INFO(GetErrorDescription(-113).c_str());
00099 i_error_code = -113;
00100 }
00101
00102
00103 realtime_tools::RealtimePublisher<nav_msgs::Odometry> * pose_pub = new realtime_tools::RealtimePublisher<nav_msgs::Odometry>(n, "odom", 10);
00104 realtime_tools::RealtimePublisher<im_msgs::WheelVel> * vel_pub = new realtime_tools::RealtimePublisher<im_msgs::WheelVel>(n, "wheel_vel", 10);
00105
00106
00107
00108 ros::ServiceServer service = n.advertiseService("evarobot_odometry/reset_odom", CallbackResetOdom);
00109
00110 ros::Rate loop_rate(d_frequency);
00111
00112 ros::Time read_time = ros::Time::now();
00113 ros::Duration dur_time;
00114
00115
00116 dynamic_reconfigure::Server<evarobot_odometry::ParamsConfig> srv;
00117 dynamic_reconfigure::Server<evarobot_odometry::ParamsConfig>::CallbackType f;
00118 f = boost::bind(&CallbackReconfigure, _1, _2);
00119 srv.setCallback(f);
00121
00122
00123 diagnostic_updater::Updater updater;
00124 updater.setHardwareID("none");
00125 updater.add("evarobot_odometry", &ProduceDiagnostics);
00126
00127 diagnostic_updater::HeaderlessTopicDiagnostic pub_freq("odom", updater,
00128 diagnostic_updater::FrequencyStatusParam(&d_min_freq, &d_max_freq, 0.1, 10));
00129
00130 char c_read_buf[31], c_write_buf[100];
00131
00132
00133 geometry_msgs::Pose2D odom_pose;
00134 geometry_msgs::Pose2D delta_odom_pose;
00135
00136 string str_data;
00137
00138 float f_left_read = 0.0, f_right_read = 0.0;
00139 float f_left_read_last = 0.0, f_right_read_last = 0.0;
00140
00141
00142 float covariance[36] = {1, 0, 0, 0, 0, 0,
00143 0, 1, 0, 0, 0, 0,
00144 0, 0, 1, 0, 0, 0,
00145 0, 0, 0, 1, 0, 0,
00146 0, 0, 0, 0, 1, 0,
00147 0, 0, 0, 0, 0, 1};
00148 for(int i = 0; i < 36; i++)
00149 {
00150 pose_pub->msg_.pose.covariance[i] = covariance[i];
00151 }
00152
00153
00154 i_fd = open(str_device_path.c_str(), O_RDWR);
00155
00156
00157
00158 write(i_fd, "clean", 5);
00159
00160
00161 if(i_fd < 0)
00162 {
00163 ROS_INFO(GetErrorDescription(-114).c_str());
00164 i_error_code = -114;
00165 exit(-1);
00166 }
00167
00168 while (ros::ok())
00169 {
00170 if(b_is_received_params)
00171 {
00172 ROS_DEBUG("EvarobotOdometry: Updating Odometry Params...");
00173 b_is_received_params = false;
00174 }
00175
00176 if(b_reset_odom)
00177 {
00178 ROS_DEBUG("EvarobotOdometry: Resetting Odometry");
00179
00180 write(i_fd, "clean", 5);
00181
00182 f_left_read = 0.0;
00183 f_right_read = 0.0;
00184 f_left_read_last = 0.0;
00185 f_right_read_last = 0.0;
00186
00187 odom_pose.x = 0.0;
00188 odom_pose.y = 0.0;
00189 odom_pose.theta = 0.0;
00190
00191 delta_odom_pose.x = 0.0;
00192 delta_odom_pose.y = 0.0;
00193 delta_odom_pose.theta = 0.0;
00194
00195 b_reset_odom = false;
00196 }
00197
00198
00199 read(i_fd, c_read_buf, sizeof(c_read_buf));
00200 str_data = c_read_buf;
00201
00202 dur_time = ros::Time::now() - read_time;
00203
00204 read_time = ros::Time::now();
00205
00206
00207 std::size_t found = str_data.find("_");
00208 if (found != std::string::npos)
00209 {
00210 f_left_read = atof(str_data.substr(0, found).c_str());
00211 f_right_read = atof(str_data.substr(found+1).c_str());
00212 str_data = "";
00213 }
00214
00215 float f_delta_sr = 0.0, f_delta_sl = 0.0, f_delta_s = 0.0;
00216
00217
00218 f_delta_sr = PI * d_wheel_diameter * (f_right_read - f_right_read_last) / (i_gear_ratio * i_cpr);
00219 f_delta_sl = PI * d_wheel_diameter * (f_left_read - f_left_read_last) / (i_gear_ratio * i_cpr);
00220
00221
00222 delta_odom_pose.theta = (f_delta_sr - f_delta_sl) / d_wheel_separation;
00223 f_delta_s = (f_delta_sr + f_delta_sl) / 2;
00224
00225
00226 delta_odom_pose.x = f_delta_s * cos(odom_pose.theta + delta_odom_pose.theta * 0.5);
00227 delta_odom_pose.y = f_delta_s * sin(odom_pose.theta + delta_odom_pose.theta * 0.5);
00228
00229
00230 odom_pose.x += delta_odom_pose.x;
00231 odom_pose.y += delta_odom_pose.y;
00232 odom_pose.theta += delta_odom_pose.theta;
00233
00234
00235 f_right_read_last = f_right_read;
00236 f_left_read_last = f_left_read;
00237
00238
00239
00240 pose_pub->msg_.pose.pose.position.x = odom_pose.x;
00241 pose_pub->msg_.pose.pose.position.y = odom_pose.y;
00242 pose_pub->msg_.pose.pose.position.z = (float)d_height;
00243
00244 pose_pub->msg_.pose.pose.orientation.x = 0.0;
00245 pose_pub->msg_.pose.pose.orientation.y = 0.0;
00246 pose_pub->msg_.pose.pose.orientation.z = sin(0.5 * odom_pose.theta);
00247 pose_pub->msg_.pose.pose.orientation.w = cos(0.5 * odom_pose.theta);
00248
00249 float f_lin_vel = 0, f_ang_vel = 0;
00250 float f_lin_vel_right = 0, f_lin_vel_left = 0;
00251
00252 ROS_DEBUG_STREAM("EvarobotOdometry: dur_time: " << dur_time.toSec());
00253
00254 if(dur_time.toSec() > 0)
00255 {
00256 f_lin_vel_right = f_delta_sr / dur_time.toSec();
00257 f_lin_vel_left = f_delta_sl / dur_time.toSec();
00258
00259 ROS_DEBUG_STREAM("EvarobotOdometry: VEl_LEFT: " << f_lin_vel_left << " Vel_right: " << f_lin_vel_right << " dur: " << dur_time.toSec());
00260
00261
00262 f_lin_vel = (f_lin_vel_right + f_lin_vel_left) / 2.0;
00263 f_ang_vel = (f_lin_vel_right - f_lin_vel_left) / d_wheel_separation;
00264 }
00265 else
00266 {
00267 ROS_INFO(GetErrorDescription(-115).c_str());
00268 i_error_code = -115;
00269 }
00270
00271 ss.str("");
00272 ss << n.resolveName(n.getNamespace(), true) << "/wheel_link";
00273
00274 vel_pub->msg_.header.frame_id = ss.str();
00275 vel_pub->msg_.header.stamp = ros::Time::now();
00276 vel_pub->msg_.left_vel = f_lin_vel_left;
00277 vel_pub->msg_.right_vel = f_lin_vel_right;
00278
00279 if (vel_pub->trylock())
00280 {
00281 vel_pub->unlockAndPublish();
00282 }
00283
00284
00285 pose_pub->msg_.twist.twist.linear.x = f_lin_vel;
00286 pose_pub->msg_.twist.twist.linear.y = 0.0;
00287 pose_pub->msg_.twist.twist.linear.z = 0.0;
00288
00289 pose_pub->msg_.twist.twist.angular.x = 0.0;
00290 pose_pub->msg_.twist.twist.angular.y = 0.0;
00291 pose_pub->msg_.twist.twist.angular.z = f_ang_vel;
00292
00293
00294
00295
00296 pose_pub->msg_.header.stamp = ros::Time::now();
00297
00298
00299 ss.str("");
00300 ss << n.resolveName(n.getNamespace(), true) << "/odom";
00301 pose_pub->msg_.header.frame_id = ss.str();
00302
00303 ss.str("");
00304 ss << n.resolveName(n.getNamespace(), true) << "/base_link";
00305 pose_pub->msg_.child_frame_id = ss.str();
00306
00307
00308 if (pose_pub->trylock())
00309 {
00310 pose_pub->unlockAndPublish();
00311 }
00312 pub_freq.tick();
00313
00314 ros::spinOnce();
00315 updater.update();
00316
00317 loop_rate.sleep();
00318 }
00319
00320
00321 close(i_fd);
00322
00323 return 0;
00324 }