[Documentation] [TitleIndex] [WordIndex

Describe ScottHassan/TestPage here.

   2 #include <actionlib/server/simple_action_server.h>
   3 #include <actionlib_tutorials/FibonacciAction.h>
   4 
   5 class FibonacciAction

Writing a Simple Server

The Code

First, create your_package/src/fibonacci_action.cpp in your favorite editor, and place the following inside it:

   1 #include <ros/ros.h>
   2 #include <actionlib/server/simple_action_server.h>
   3 #include <actionlib_tutorials/FibonacciAction.h>
   4 
   5 class FibonacciAction
   6 {
   7 public:
   8     
   9   FibonacciAction(std::string name) : 
  10     as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1)),
  11     action_name_(name)
  12   {
  13   }
  14 
  15   ~FibonacciAction(void)
  16   {
  17   }
  18 
  19   void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal)
  20   {
  21     // helper variables
  22     ros::Rate r(1); 
  23     bool success = true;
  24 
  25     // push_back the seeds for the fibonacci sequence
  26     feedback_.sequence.clear();
  27     feedback_.sequence.push_back(0);
  28     feedback_.sequence.push_back(1);
  29 
  30     // publish info to the console for the user
  31     ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i", action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
  32         
  33     // start executing the action
  34     for(int i=1; i<=goal->order; i++)
  35     {        
  36       // check that preempt has not been requested by the client
  37       if (as_.isPreemptRequested())
  38       {
  39         ROS_INFO("%s: Preempted", action_name_.c_str());
  40         // set the action state to preempted
  41         as_.setPreempted();

The Code Explained

Now, let's break down the code piece by piece.

   1 #include <ros/ros.h>
   2 #include <actionlib/server/simple_action_server.h>
   3 

actionlib/server/simple_action_server.h is the action library used from implementing simple actions.

   3 #include <actionlib_tutorials/FibonacciAction.h>
   4 

This includes action message generated from the Fibonacci.action file show above. This is a header generated automatically from the FibonacciAction.msg file. For more information on message definitions, see the msg page.

   5 class FibonacciAction
   6 {
   7 public:
   8     
   9   FibonacciAction(std::string name) : 
  10     as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1)),
  11     action_name_(name)
  12   {
  13   }

In the action constructor, an action server is created. The action server takes arguments of a node handle, name of the action, and optionally an executeCB. In this example the action server is created with the arguments for the executeCB.

  15   ~FibonacciAction(void)
  16   {
  17   }
  18 
  19   void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal)

Now the executeCB function referenced in the constructor is created. The callback function is passed a pointer to the goal message.

  20   {
  21     // helper variables
  22     ros::Rate r(1); 
  23     bool success = true;
  24     
  25     // push_back the seeds for the fibonacci sequence
  26     feedback_.sequence.clear();
  27     feedback_.sequence.push_back(0);
  28     feedback_.sequence.push_back(1);
  29 
  30     // publish some info to the console for the user 
  31     ROS_INFO("%s: Executing, creating fibonacci sequence of order %i with seeds %i, %i",action_name_.c_str(), goal->order, feedback_.sequence[0], feedback_.sequence[1]);
  32         
  33     // start executing the action
  34     for(int i=1; i<=goal->order; i++)
  35     {               

Here the internals of the action are created. In this example ROS_INFO is being published to let the user know that the action is executing.

  36         // check to make sure that preempt has not been requested by the client
  37         if (as_.isPreemptRequested())
  38         {
  39           ROS_INFO("%s: Preempted", action_name_.c_str());
  40           // set the action state to preempted
  41           as_.setPreempted();
  42           success = false;
  43           break;
  44         }

In the process of a running action it is important check that the action client has not requested the current goal to be canceled. If the action has been requested to preempt the action should respond with setting preempted after any necessary clean up is completed.

  45         feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]);
  46       // publish the feedback 
  47       as_.publishFeedback(feedback_);
  48       // this sleep is not necessary
  49       r.sleep(); 
  50     }

Here the Fibonacci sequence is put into the feedback variable and then published on the feedback channel provided by the action server. Then the action continues on looping and publishing feedback.

  52     if(success)
  53     {
  54       result_.sequence = feedback_.sequence;
  55       ROS_INFO("%s: Succeeded", action_name_.c_str());
  56       // set the action state to succeeded
  57       as_.setSucceeded(result_);
  58     }
  59   }

Once the action has finished computing the Fibonacci sequence the action notifies the action client that the action is complete by setting succeeded.

  61 protected:
  62     
  63   ros::NodeHandle nh_;
  64   actionlib::SingleGoalActionServer<actionlib_tutorials::FibonacciAction> as_;
  65   std::string action_name_;
  66   // create messages that are used to published feedback/result
  67   actionlib_tutorials::FibonacciFeedback feedback_;
  68   actionlib_tutorials::FibonacciResult result_;
  69 };

These are the protected variables of the action class. The node handle is constructed and passed into the action server during construction of the action. The action server is constructed in the constructor of the action and has been discussed above. The feedback and result messages are created for publishing in the action.

  72 int main(int argc, char** argv)
  73 {
  74     ros::init(argc, argv, "fibonacci");
  75 
  76     FibonacciAction fibonacci(ros::this_node::getName());
  77     ros::spin();
  78 
  79     return 0;
  80 }

Finally the main function, creates the action and spins the node. This puts the action in a pending state when the action is started.

Compiling and Running the Action

Add the following line to your CMakeLists.txt file:

rospack_add_executable(fibonacci_action fibonacci_action.cpp)

After you have made the executable, start a roscore in a new terminal

$ roscore

And then run the action server:

$ rosrun your_package fibonacci_action

You will see something similar to:

To check that your action is running properly list topics being published:

$ rostopic list -v

You will see something similar to:

Alternatively you can look at the nodes:

$ rxgraph

This shows that your action server is publishing the feedback, status, and result channels as expected and subscribed to the goal and cancel channels as expected. The action server is up and running properly.

Sending a Goal to the Action Server

For the next step in using your action, you need to write a simple action client.



2024-02-24 12:23