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 if (done) return true;
00179 return false;
00180 }
00181
00182 bool turnOdom(double radians)
00183 {
00184
00185 if (fabs(radians) < 0.01)
00186 return true;
00187
00188 while(radians < -M_PI) radians += 2*M_PI;
00189 while(radians > M_PI) radians -= 2*M_PI;
00190
00191
00192 tf::StampedTransform start_transform;
00193 tf::StampedTransform current_transform;
00194
00195 try
00196 {
00197
00198 listener_.waitForTransform(base_frame, odom_frame,
00199 ros::Time::now(), ros::Duration(1.0));
00200
00201
00202 listener_.lookupTransform(base_frame, odom_frame,
00203 ros::Time(0), start_transform);
00204 }
00205 catch (tf::TransformException ex)
00206 {
00207 ROS_ERROR("%s",ex.what());
00208 return false;
00209 }
00210
00211
00212 geometry_msgs::Twist base_cmd;
00213
00214 base_cmd.linear.x = base_cmd.linear.y = 0.0;
00215 base_cmd.angular.z = turn_rate;
00216 if (radians < 0)
00217 base_cmd.angular.z = -turn_rate;
00218
00219
00220 tf::Vector3 desired_turn_axis(0,0,1);
00221
00222 ros::Rate rate(25.0);
00223 bool done = false;
00224 while (!done && nh_.ok() && as_.isActive())
00225 {
00226
00227 cmd_vel_pub_.publish(base_cmd);
00228 rate.sleep();
00229
00230 try
00231 {
00232 listener_.lookupTransform(base_frame, odom_frame,
00233 ros::Time(0), current_transform);
00234 }
00235 catch (tf::TransformException ex)
00236 {
00237 ROS_ERROR("%s",ex.what());
00238 break;
00239 }
00240 tf::Transform relative_transform =
00241 start_transform.inverse() * current_transform;
00242 tf::Vector3 actual_turn_axis =
00243 relative_transform.getRotation().getAxis();
00244 double angle_turned = relative_transform.getRotation().getAngle();
00245
00246
00247 feedback_.turn_distance = angle_turned;
00248 result_.turn_distance = angle_turned;
00249 as_.publishFeedback(feedback_);
00250
00251 if ( fabs(angle_turned) < 1.0e-2) continue;
00252
00253
00254
00255
00256 if (fabs(angle_turned) > fabs(radians)) done = true;
00257 }
00258 if (done) return true;
00259 return false;
00260 }
00261
00262
00263 };
00264
00265 int main(int argc, char** argv)
00266 {
00267 ros::init(argc, argv, "turtlebot_move_action_server");
00268
00269 MoveActionServer server("turtlebot_move");
00270 ros::spin();
00271
00272 return 0;
00273 }
00274