问题描述:
动作通信类型的消息类型是什么,动作通信如何定义的,请举例?
问题解答:
在ROS中,动作(Action)通信是一种更复杂的通信机制,用于需要较长时间才能完成的任务。动作通信使用动作消息类型,这些消息类型包含三个部分:目标(Goal)、结果(Result)和反馈(Feedback)。这些消息类型文件以.action
为扩展名,包含三个部分,用三个连字符(---
)分隔。
动作通信的消息类型
动作消息类型定义了动作服务器和动作客户端之间传输的数据结构,包括目标、结果和反馈。
动作通信的定义
动作通信的定义包括以下几个步骤:
-
定义动作消息类型:
- 在
action
目录下创建动作消息类型文件。
- 在
-
动作服务器:
- 编写一个ROS节点提供动作服务。
-
动作客户端:
- 编写一个ROS节点发送目标并处理反馈和结果。
示例
假设我们有一个自定义动作消息类型CountNumbers.action
,内容如下:
#goal define
int32 target_number
int32 target_step
---
#result define
bool finish
---
#feedback define
float32 count_percent
int32 count_current
1. 定义动作消息类型
在包的action
目录下创建CountNumbers.action
文件:
#goal define
int32 target_number
int32 target_step
---
#result define
bool finish
---
#feedback define
float32 count_percent
int32 count_current
在CMakeLists.txt
和package.xml
中添加配置以支持自定义动作消息类型:
CMakeLists.txt:
find_package(catkin REQUIRED COMPONENTS roscpp actionlib actionlib_msgs message_generation)
add_action_files(
FILES
CountNumbers.action
)
generate_messages(
DEPENDENCIES
actionlib_msgs std_msgs
)
catkin_package(
CATKIN_DEPENDS actionlib_msgs message_runtime
)
package.xml:
<build_depend>actionlib_msgs</build_depend>
<build_depend>message_generation</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>
<exec_depend>message_runtime</exec_depend>
然后编译包:
catkin_make
source devel/setup.bash
2. 动作服务器
编写一个动作服务器节点count_numbers_server.cpp
,提供CountNumbers
动作服务:
src/count_numbers_server.cpp:
#include <ros/ros.h>
#include <actionlib/server/simple_action_server.h>
#include <your_package_name/CountNumbersAction.h>
class CountNumbersAction
{
protected:
ros::NodeHandle nh_;
actionlib::SimpleActionServer<your_package_name::CountNumbersAction> as_;
std::string action_name_;
your_package_name::CountNumbersFeedback feedback_;
your_package_name::CountNumbersResult result_;
public:
CountNumbersAction(std::string name) :
as_(nh_, name, boost::bind(&CountNumbersAction::executeCB, this, _1), false),
action_name_(name)
{
as_.start();
}
void executeCB(const your_package_name::CountNumbersGoalConstPtr &goal)
{
ros::Rate r(1);
bool success = true;
int count = 0;
for(int i = 1; i <= goal->target_number; i += goal->target_step)
{
if (as_.isPreemptRequested() || !ros::ok())
{
as_.setPreempted();
success = false;
break;
}
count = i;
feedback_.count_current = count;
feedback_.count_percent = (float)i / goal->target_number * 100;
as_.publishFeedback(feedback_);
r.sleep();
}
if(success)
{
result_.finish = true;
as_.setSucceeded(result_);
}
}
};
int main(int argc, char** argv)
{
ros::init(argc, argv, "count_numbers");
CountNumbersAction count_numbers("count_numbers");
ros::spin();
return 0;
}
在CMakeLists.txt
中添加该节点的编译指令:
CMakeLists.txt(部分内容):
add_executable(count_numbers_server src/count_numbers_server.cpp)
target_link_libraries(count_numbers_server ${catkin_LIBRARIES})
add_dependencies(count_numbers_server ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
3. 动作客户端
编写一个动作客户端节点count_numbers_client.cpp
,发送目标并处理反馈和结果:
src/count_numbers_client.cpp:
#include <ros/ros.h>
#include <actionlib/client/simple_action_client.h>
#include <your_package_name/CountNumbersAction.h>
int main(int argc, char **argv)
{
ros::init(argc, argv, "count_numbers_client");
if (argc != 3)
{
ROS_INFO("Usage: count_numbers_client <target_number> <target_step>");
return 1;
}
actionlib::SimpleActionClient<your_package_name::CountNumbersAction> ac("count_numbers", true);
ROS_INFO("Waiting for action server to start...");
ac.waitForServer();
your_package_name::CountNumbersGoal goal;
goal.target_number = atoi(argv[1]);
goal.target_step = atoi(argv[2]);
ROS_INFO("Sending goal...");
ac.sendGoal(goal,
[](const actionlib::SimpleClientGoalState& state,
const your_package_name::CountNumbersResultConstPtr& result)
{
ROS_INFO("Finished in state [%s]", state.toString().c_str());
ROS_INFO("Result: %s", result->finish ? "True" : "False");
},
actionlib::SimpleActionClient<your_package_name::CountNumbersAction>::SimpleActiveCallback(),
[](const your_package_name::CountNumbersFeedbackConstPtr& feedback)
{
ROS_INFO("Feedback: current_count = %d, percent_complete = %.2f", feedback->count_current, feedback->count_percent);
});
ros::spin();
return 0;
}
在CMakeLists.txt
中添加该节点的编译指令:
CMakeLists.txt(部分内容):
add_executable(count_numbers_client src/count_numbers_client.cpp)
target_link_libraries(count_numbers_client ${catkin_LIBRARIES})
add_dependencies(count_numbers_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
4. 编译并运行
编译你的ROS包:
cd ~/catkin_ws
catkin_make
source devel/setup.bash
然后,在三个不同的终端中分别运行roscore、动作服务器和动作客户端:
roscore
rosrun your_package_name count_numbers_server
rosrun your_package_name count_numbers_client 10 2
动作客户端节点将会发送目标到count_numbers
动作服务器,并处理反馈和结果,输出类似于:
Waiting for action server to start...
Sending goal...
Feedback: current_count = 2, percent_complete = 20.00
Feedback: current_count = 4, percent_complete = 40.00
Feedback: current_count = 6, percent_complete = 60.00
Feedback: current_count = 8, percent_complete = 80.00
Feedback: current_count = 10, percent_complete = 100.00
Finished in state [SUCCEEDED]
Result: True
总结
- 消息类型:在这个示例中,定义了一个自定义动作消息类型
CountNumbers.action
。 - 动作服务器:提供
CountNumbers
动作服务,处理目标并返回结果和反馈。 - 动作客户端:发送目标到
CountNumbers
动作服务器,并处理反馈和结果。
通过以上步骤和示例,你可以定义和使用自定义动作消息类型,实现ROS节点之间的动作通信。