Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <ros/ros.h>
00032 #include <std_msgs/Float32.h>
00033 #include <actionlib/server/simple_action_server.h>
00034 #include <turtlebot_actions/TurtlebotMoveAction.h>
00035 #include <geometry_msgs/Twist.h>
00036 #include <tf/transform_listener.h>
00037 #include <cmath>
00038
00039 class MoveActionServer
00040 {
00041 private:
00042
00043 ros::NodeHandle nh_;
00044 actionlib::SimpleActionServer<turtlebot_actions::TurtlebotMoveAction> as_;
00045 std::string action_name_;
00046
00047 turtlebot_actions::TurtlebotMoveFeedback feedback_;
00048 turtlebot_actions::TurtlebotMoveResult result_;
00049 turtlebot_actions::TurtlebotMoveGoalConstPtr goal_;
00050
00051 ros::Subscriber sub_;
00052 ros::Publisher cmd_vel_pub_;
00053 tf::TransformListener listener_;
00054
00055
00056 std::string base_frame;
00057 std::string odom_frame;
00058 double turn_rate;
00059 double forward_rate;
00060
00061 public:
00062 MoveActionServer(const std::string name) :
00063 nh_("~"), as_(nh_, name, false), action_name_(name)
00064 {
00065
00066 nh_.param<std::string>("base_frame", base_frame, "base_link");
00067 nh_.param<std::string>("odom_frame", odom_frame, "odom");
00068 nh_.param<double>("turn_rate", turn_rate, 0.75);
00069 nh_.param<double>("forward_rate", forward_rate, 0.25);
00070
00071
00072 as_.registerGoalCallback(boost::bind(&MoveActionServer::goalCB, this));
00073 as_.registerPreemptCallback(boost::bind(&MoveActionServer::preemptCB, this));
00074
00075 as_.start();
00076
00077 cmd_vel_pub_ = nh_.advertise<geometry_msgs::Twist>("cmd_vel", 1);
00078 }
00079
00080 void goalCB()
00081 {
00082
00083 feedback_.forward_distance = 0.0;
00084 feedback_.turn_distance = 0.0;
00085
00086 result_.forward_distance = 0.0;
00087 result_.turn_distance = 0.0;
00088
00089 goal_ = as_.acceptNewGoal();
00090
00091 if (!turnOdom(goal_->turn_distance))
00092 {
00093 as_.setAborted(result_);
00094 return;
00095 }
00096
00097 if (driveForwardOdom(goal_->forward_distance))
00098 as_.setSucceeded(result_);
00099 else
00100 as_.setAborted(result_);
00101 }
00102
00103 void preemptCB()
00104 {
00105 ROS_INFO("%s: Preempted", action_name_.c_str());
00106
00107 as_.setPreempted();
00108 }
00109
00110 bool driveForwardOdom(double distance)
00111 {
00112
00113 if (fabs(distance) < 0.01)
00114 return true;
00115
00116
00117 tf::StampedTransform start_transform;
00118 tf::StampedTransform current_transform;
00119
00120 try
00121 {
00122
00123 listener_.waitForTransform(base_frame, odom_frame,
00124 ros::Time::now(), ros::Duration(1.0));
00125
00126
00127 listener_.lookupTransform(base_frame, odom_frame,
00128 ros::Time(0), start_transform);
00129 }
00130 catch (tf::TransformException ex)
00131 {
00132 ROS_ERROR("%s",ex.what());
00133 return false;
00134 }
00135
00136
00137 geometry_msgs::Twist base_cmd;
00138
00139 base_cmd.linear.y = base_cmd.angular.z = 0;
00140 base_cmd.linear.x = forward_rate;
00141
00142 if (distance < 0)
00143 base_cmd.linear.x = -base_cmd.linear.x;
00144
00145 ros::Rate rate(25.0);
00146 bool done = false;
00147 while (!done && nh_.ok() && as_.isActive())
00148 {
00149
00150 cmd_vel_pub_.publish(base_cmd);
00151 rate.sleep();
00152
00153 try
00154 {
00155 listener_.lookupTransform(base_frame, odom_frame,
00156 ros::Time(0), current_transform);
00157 }
00158 catch (tf::TransformException ex)
00159 {
00160 ROS_ERROR("%s",ex.what());
00161 break;
00162 }
00163
00164 tf::Transform relative_transform =
00165 start_transform.inverse() * current_transform;
00166 double dist_moved = relative_transform.getOrigin().length();
00167
00168
00169 feedback_.forward_distance = dist_moved;
00170 result_.forward_distance = dist_moved;
00171 as_.publishFeedback(feedback_);
00172
00173 if(fabs(dist_moved) > fabs(distance))
00174 {
00175 done = true;
00176 }
00177 }
00178 base_cmd.linear.x = 0.0;
00179 base_cmd.angular.z = 0.0;
00180 cmd_vel_pub_.publish(base_cmd);
00181
00182 if (done) return true;
00183 return false;
00184 }
00185
00186 bool turnOdom(double radians)
00187 {
00188
00189 if (fabs(radians) < 0.01)
00190 return true;
00191
00192 while(radians < -M_PI) radians += 2*M_PI;
00193 while(radians > M_PI) radians -= 2*M_PI;
00194
00195
00196 tf::StampedTransform start_transform;
00197 tf::StampedTransform current_transform;
00198
00199 try
00200 {
00201
00202 listener_.waitForTransform(base_frame, odom_frame,
00203 ros::Time::now(), ros::Duration(1.0));
00204
00205
00206 listener_.lookupTransform(base_frame, odom_frame,
00207 ros::Time(0), start_transform);
00208 }
00209 catch (tf::TransformException ex)
00210 {
00211 ROS_ERROR("%s",ex.what());
00212 return false;
00213 }
00214
00215
00216 geometry_msgs::Twist base_cmd;
00217
00218 base_cmd.linear.x = base_cmd.linear.y = 0.0;
00219 base_cmd.angular.z = turn_rate;
00220 if (radians < 0)
00221 base_cmd.angular.z = -turn_rate;
00222
00223
00224 tf::Vector3 desired_turn_axis(0,0,1);
00225
00226 ros::Rate rate(25.0);
00227 bool done = false;
00228 while (!done && nh_.ok() && as_.isActive())
00229 {
00230
00231 cmd_vel_pub_.publish(base_cmd);
00232 rate.sleep();
00233
00234 try
00235 {
00236 listener_.lookupTransform(base_frame, odom_frame,
00237 ros::Time(0), current_transform);
00238 }
00239 catch (tf::TransformException ex)
00240 {
00241 ROS_ERROR("%s",ex.what());
00242 break;
00243 }
00244 tf::Transform relative_transform =
00245 start_transform.inverse() * current_transform;
00246 tf::Vector3 actual_turn_axis =
00247 relative_transform.getRotation().getAxis();
00248 double angle_turned = relative_transform.getRotation().getAngle();
00249
00250
00251 feedback_.turn_distance = angle_turned;
00252 result_.turn_distance = angle_turned;
00253 as_.publishFeedback(feedback_);
00254
00255 if ( fabs(angle_turned) < 1.0e-2) continue;
00256
00257
00258
00259
00260 if (fabs(angle_turned) > fabs(radians)) done = true;
00261 }
00262 if (done) return true;
00263 return false;
00264 }
00265
00266
00267 };
00268
00269 int main(int argc, char** argv)
00270 {
00271 ros::init(argc, argv, "turtlebot_move_action_server");
00272
00273 MoveActionServer server("turtlebot_move");
00274 ros::spin();
00275
00276 return 0;
00277 }
00278