단계 | 설명 |
피보나치 수열 (wiki) | |
패키지 생성 | $ cd ~/catkin_ws/src $ catkin_create_pkg actionlib_tutorials actionlib message_generation roscpp rospy std_msgs actionlib_msgs
$ cd actionlib_tutorials |
package.xml | <?xml version="1.0"?> <package format="2"> <name>my_custom_action_msg_pkg</name> <version>0.0.0</version> <description>The my_custom_action_msg_pkg package</description> <maintainer email="user@todo.todo">user</maintainer> <license>TODO</license> <buildtool_depend>catkin</buildtool_depend> <build_depend>actionlib</build_depend> <build_depend>actionlib_msgs</build_depend> <build_depend>roscpp</build_depend> <build_depend>rospy</build_depend> <build_depend>std_msgs</build_depend> <build_export_depend>actionlib</build_export_depend> <build_export_depend>actionlib_msgs</build_export_depend> <build_export_depend>roscpp</build_export_depend> <build_export_depend>rospy</build_export_depend> <build_export_depend>std_msgs</build_export_depend>
<exec_depend>actionlib</exec_depend> <exec_depend>actionlib_msgs</exec_depend> <exec_depend>roscpp</exec_depend> <exec_depend>rospy</exec_depend> <exec_depend>std_msgs</exec_depend> <exec_depend>message_generation</exec_depend>
<export> </export> </package> |
CMakeList.txt 수정 | cmake_minimum_required(VERSION 2.8.3) project(my_custom_action_msg_pkg) ## Find catkin macros and libraries find_package(catkin REQUIRED COMPONENTS actionlib actionlib_msgs message_generation roscpp rospy std_msgs ) ## Generate actions in the 'action' folder add_action_files( DIRECTORY action FILES Fibonacci.action ) ## Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES actionlib_msgs std_msgs ) catkin_package( CATKIN_DEPENDS actionlib actionlib_msgs message_generation roscpp rospy std_msgs ) ## Specify additional locations of header files include_directories( ${catkin_INCLUDE_DIRS} )
add_executable(fibonacci_server src/fibonacci_server.cpp) add_executable(fibonacci_client src/fibonacci_client.cpp)
target_link_libraries( fibonacci_server ${catkin_LIBRARIES} ) target_link_libraries( fibonacci_client ${catkin_LIBRARIES} )
add_dependencies( fibonacci_server fibonacci_client ${actionlib_tutorials_EXPORTED_TARGETS} ) |
Action 메시지 파일
Fibonacci.action | $ mkdir action $ vi action/Fibonacci.action
#goal definition int32 order --- #result definition int32[] sequence --- #feedback int32[] sequence |
액션 서버 | $ vi src/fibonacci_server.cpp
#include <ros/ros.h> #include <actionlib/server/simple_action_server.h> #include <actionlib_tutorials/FibonacciAction.h>
class FibonacciAction { protected:
ros::NodeHandle nh_; actionlib::SimpleActionServer<actionlib_tutorials::FibonacciAction> as_; // NodeHandle instance must be created before this line. Otherwise strange error occurs. std::string action_name_; // create messages that are used to published feedback/result actionlib_tutorials::FibonacciFeedback feedback_; actionlib_tutorials::FibonacciResult result_;
public:
FibonacciAction(std::string name) : as_(nh_, name, boost::bind(&FibonacciAction::executeCB, this, _1), false), action_name_(name) { as_.start(); }
~FibonacciAction(void) { }
void executeCB(const actionlib_tutorials::FibonacciGoalConstPtr &goal) { // helper variables ros::Rate r(1); bool success = true;
// push_back the seeds for the fibonacci sequence feedback_.sequence.clear(); feedback_.sequence.push_back(0); feedback_.sequence.push_back(1);
// publish info to the console for the user 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]);
// start executing the action for(int i=1; i<=goal->order; i++) { // check that preempt has not been requested by the client if (as_.isPreemptRequested() || !ros::ok()) { ROS_INFO("%s: Preempted", action_name_.c_str()); // 액션이 이미 선점되었다. // set the action state to preempted as_.setPreempted(); success = false; break; } feedback_.sequence.push_back(feedback_.sequence[i] + feedback_.sequence[i-1]); // publish the feedback as_.publishFeedback(feedback_); // this sleep is not necessary, the sequence is computed at 1 Hz for demonstration purposes r.sleep(); }
if(success) { result_.sequence = feedback_.sequence; ROS_INFO("%s: Succeeded", action_name_.c_str()); // set the action state to succeeded as_.setSucceeded(result_); } } };
int main(int argc, char** argv) { ros::init(argc, argv, "fibonacci"); FibonacciAction fibonacci("fibonacci"); ros::spin(); return 0; } |
액션 클라이언트 | $ vi src/fibonacci_client.cpp
#include <ros/ros.h> #include <actionlib/client/simple_action_client.h> #include <actionlib_tutorials/FibonacciAction.h>
using namespace actionlib_tutorials; typedef actionlib::SimpleActionClient<FibonacciAction> Client;
class MyNode { public: MyNode() : ac("fibonacci", true) { ROS_INFO("Waiting for action server to start."); ac.waitForServer(); //액션은 비동기라서 기다리는 함수가 필요하다. 이때 다른 작업이 가능하다. ROS_INFO("Action server started, sending goal."); }
void doStuff(int order) { FibonacciGoal goal; goal.order = order;
// Need boost::bind to pass in the 'this' pointer ac.sendGoal(goal, boost::bind(&MyNode::doneCb, this, _1, _2), Client::SimpleActiveCallback(), Client::SimpleFeedbackCallback()); }
void doneCb(const actionlib::SimpleClientGoalState& state, const FibonacciResultConstPtr& result) { ROS_INFO("Finished in state [%s]", state.toString().c_str()); ROS_INFO("Answer: %i", result->sequence.back()); ros::shutdown(); }
private: Client ac; };
int main (int argc, char **argv) { ros::init(argc, argv, "test_fibonacci_class_client"); MyNode my_node; my_node.doStuff(10); ros::spin(); return 0; } |
컴파일 | $ cd ~/catkin_ws $ catkin_make $ source ~/catkin_ws/devel/setup.bash
# 생성된 파일 확인하기
$ ls ~/catkin_ws/devel/share/actionlib_tutorials/msg/
FibonacciActionFeedback.msg FibonacciAction.msg FibonacciFeedback.msg FibonacciResult.msg FibonacciActionGoal.msg FibonacciActionResult.msg FibonacciGoal.msg
$ ls ~/catkin_ws/devel/include/actionlib_tutorials/
FibonacciActionFeedback.h FibonacciAction.h FibonacciFeedback.h FibonacciResult.h FibonacciActionGoal.h FibonacciActionResult.h FibonacciGoal.h |
액션 msg 조회 | $ rosmsg list | grep Fibonacci
actionlib_tutorials/FibonacciAction actionlib_tutorials/FibonacciActionFeedback actionlib_tutorials/FibonacciActionGoal actionlib_tutorials/FibonacciActionResult actionlib_tutorials/FibonacciFeedback actionlib_tutorials/FibonacciGoal actionlib_tutorials/FibonacciResult |
실행 | $ roscore
$ rosrun actionlib_tutorials fibonacci_server
[ INFO] [1708993303.652838775]: fibonacci: Executing, creating fibonacci sequence of order 10 with seeds 0, 1 [ INFO] [1708993313.653343846]: fibonacci: Succeeded
$ rosrun actionlib_tutorials fibonacci_client
[ INFO] [1708993303.429043892]: Waiting for action server to start. [ INFO] [1708993303.651961541]: Action server started, sending goal. [ INFO] [1708993313.656749030]: Finished in state [SUCCEEDED] [ INFO] [1708993313.657268588]: Answer: 89 |
액션 Feedback | $ roscore $ rosrun actionlib_tutorials fibonacci_server $ rosrun actionlib_tutorials fibonacci_client
# 액션이 끝나기 전에 다음을 실행하면, feedback에 대한 정보가 출력된다.
$ rostopic echo /fibonacci/feedback
header: seq: 18 stamp: secs: 1708993537 nsecs: 308300153 frame_id: '' status: goal_id: stamp: secs: 1708993529 nsecs: 306617996 id: "/test_fibonacci_class_client-1-1708993529.306617996" status: 1 text: "This goal has been accepted by the simple action server" feedback: sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] ---
|
액션 Result | $ roscore $ rosrun actionlib_tutorials fibonacci_server $ rosrun actionlib_tutorials fibonacci_client
# 액션이 끝나기 전에 다음을 실행하면, 액션이 끝나면서 result에 대한 정보가 출력된다. $ rostopic echo /fibonacci/result
header: seq: 3 stamp: secs: 1708993724 nsecs: 732221455 frame_id: '' status: goal_id: stamp: secs: 1708993714 nsecs: 730927374 id: "/test_fibonacci_class_client-1-1708993714.730927374" status: 3 text: '' result: sequence: [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89] ---
|
rqt_graph |
|
토픽 조회 | $ rostopic list -v
Published topics: * /rosout_agg [rosgraph_msgs/Log] 1 publisher * /rosout [rosgraph_msgs/Log] 2 publishers * /turtle1/pose [turtlesim/Pose] 1 publisher * /turtle1/color_sensor [turtlesim/Color] 1 publisher * /fibonacci/result [actionlib_tutorials/FibonacciActionResult] 1 publisher * /fibonacci/feedback [actionlib_tutorials/FibonacciActionFeedback] 1 publisher * /fibonacci/status [actionlib_msgs/GoalStatusArray] 1 publisher
Subscribed topics: * /rosout [rosgraph_msgs/Log] 1 subscriber * /turtle1/cmd_vel [geometry_msgs/Twist] 1 subscriber * /fibonacci/goal [actionlib_tutorials/FibonacciActionGoal] 1 subscriber * /fibonacci/cancel [actionlib_msgs/GoalID] 1 subscriber |