一.解决 无法打开源文件
出错原因:系统没有找到.h文件对应的路径。
在编写完msg、srv、action文件后,要进行编译(catkin_make) .
编译之后,msg、srv、action会生成相应的.h文件。
其对应的.h文件目录在devel/include/功能包下,如下:
解决方法:将.h文件目录加入json文件中即可。
然后保存json文件,之后关闭VScode,然后重新打开,就好了。
二.话题
1.案例一
talker.cpp
#include "ros/ros.h"
#include <sstream>
#include "std_msgs/String.h"
int main(int argc, char** argv){
//ROS结点初始化
ros::init(argc, argv, "talker");
//创建节点句柄
ros::NodeHandle nh;
//创建一个publisher,发布名为chatter的topic,消息类型为std_msgs,队列长度为1000
ros::Publisher chatter_pub=nh.advertise<std_msgs::String>("chatter",1000);
//设置循环频率
ros::Rate loop_Rate(10);
int count=0;
while(ros::ok()){
//初始化std_msgs::String类型的消息
std_msgs::String msg;
std::stringstream ss;
ss<<"hello world:"<<count;
msg.data=ss.str();
//发布消息
ROS_INFO("%s",msg.data.c_str());
chatter_pub.publish(msg);
//回调函数:执行一次回调函数,在这里其实没什么用
ros::spinOnce();
//按照循环频率延时
loop_Rate.sleep();
++count;
}
return 0;
}
listener.cpp
#include "ros/ros.h"
#include "std_msgs/String.h"
//接收到topic后,会进入回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg){
//打印topic信息
ROS_INFO("I heard [%s]",msg->data.c_str());
}
int main(int argc,char **argv){
//初始化ros节点
ros::init(argc,argv,"listener");
//创建节点句柄
ros::NodeHandle nh;
//创建一个subscribler,订阅topic为“chatter”,注册回调函数chatterCallback
ros::Subscriber sub=nh.subscribe("chatter",1000,chatterCallback);
//循环等待执行回调函数
ros::spin();
return 0;
}
CMakeList.txt
add_executable(listener src/listener.cpp)
target_link_libraries(listener ${catkin_LIBRARIES})
add_executable(talker src/talker.cpp)
target_link_libraries(talker ${catkin_LIBRARIES})
2.案例二:自定义msg文件
创建名为msg的文件夹。
定义msg文件,name、sex、age是变量,unknow、male、female是常量:
Person.msg
# 变量
string name
uint8 sex
uint8 age
#常量
uint8 unknow=0
uint8 male=1
uint8 female=2
package.xml 添加功能包依赖:
<!--添加功能包依赖:msg、srv-->
<build_depend>std_msgs</build_depend>
<exec_depend>std_msgs</exec_depend>
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
其中:部分ROS版本中 exec_depend需要改为run_depend
CMakeLists.txt添加编译选项:
find_package(catkin REQUIRED COMPONENTS
message_generation
)
add_message_files(
FILES
Person.msg
)
generate_messages(
DEPENDENCIES
std_msgs
)
catkin_package(
CATKIN_DEPENDS geometry_msgs roscpp std_msgs message_runtime
)
之后catkin_make
查看自己定义的msg:
rosmsg show Person
三.服务
创建名为srv的文件夹。
定义srv文件,a、b是请求数据,sum是服务数据,也就是a、b传给服务器,服务器相加sum传给客户端:
AddTwoInts.srv
#客户端
int64 a
int64 b
---
#服务器
int64 sum
package.xml 添加功能包依赖:
<!--添加功能包依赖:msg、srv-->
<build_depend>std_msgs</build_depend>
<exec_depend>std_msgs</exec_depend>
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
其中:部分ROS版本中 exec_depend需要改为run_depend
CMakeLists.txt添加编译选项:
find_package(catkin REQUIRED COMPONENTS
message_generation
)
add_service_files(
FILES
AddTwoInts.srv
)
catkin_package(
CATKIN_DEPENDS geometry_msgs roscpp std_msgs message_runtime
)
查看自己定义的srv文件:
rossrv show AddTwoInts.srv
client.cpp
#include <cstdlib>
#include "ros/ros.h"
#include "robot_setup_tf/AddTwoInts.h"
int main(int argc,char** argv){
//ROS节点初始化
ros::init(argc,argv,"add_two_ints_client");
//从终端命令行获取两个加数
if(argc!=3){
ROS_INFO("usage: add_two_ints_client X Y");
return 1;
}
//创建节点句柄
ros::NodeHandle nh;
//创建一个client,请求add_two_service
//service消息类型是robot_setup_tf::AddTwoInts
ros::ServiceClient client=nh.serviceClient<robot_setup_tf::AddTwoInts>("add_two_ints");
//创建robot_setup_tf::AddTwoInts类型的消息对象
robot_setup_tf::AddTwoInts srv;
srv.request.a=atoll(argv[1]);
srv.request.b=atoll(argv[2]);
//发布service请求,等待加法运算
if(client.call(srv)){
ROS_INFO("Sum=%ld",(long int)srv.response.sum);
}else{
ROS_INFO("Failed to call service add_two_ints");
return 1;
}
return 0;
}
server.cpp
#include "ros/ros.h"
#include "robot_setup_tf/AddTwoInts.h"
//回调函数,client传进a、b,完成加法后返回给sum
bool add(robot_setup_tf::AddTwoInts::Request &req, robot_setup_tf::AddTwoInts::Response &res)
{
res.sum=req.a+req.b;
ROS_INFO("request: x=%ld, y=%ld",(long int)req.a,(long int)req.b);
ROS_INFO("response: sum=%ld",(long int)res.sum);
return true;
}
int main(int argc,char** argv){
//ROS节点初始化
ros::init(argc,argv,"add_two_ints_server");
//创建节点句柄
ros::NodeHandle nh;
//创建一个名为"add_two_ints"的server,注册回调函数为add()
ros::ServiceServer service=nh.advertiseService("add_two_ints",add);
//循环等待回调函数
ROS_INFO("Ready to add two ints");
ros::spin();
return 0;
}
CMakeList.txt
add_executable(server src/server.cpp)
target_link_libraries(server ${catkin_LIBRARIES})
add_dependencies(server ${PROJECT_NAME}_gencpp)
add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES})
add_dependencies(client ${PROJECT_NAME}_gencpp)
运行:
roscore
rosrun robot_setup_tf server
rosrun robot_setup_tf client 4 5
四.动作
创建名为action文件夹。
创建action文件
DoDishes.action
#goal,定义目标信息,客户端
uint8 dishwasher_id
#Specify which dishwasher we want to use
---
#result,定义结果信息,服务器
uint8 total_dishes_cleaned
---
#feedback,定义周期反馈的消息
float32 percent_complete
package.xml添加功能包依赖
<!--添加功能包依赖:action-->
<build_depend>actionlib</build_depend>
<build_depend>actionlib_msgs</build_depend>
<exec_depend>actionlib</exec_depend>
<exec_depend>actionlib_msgs</exec_depend>
CMakeLists.txt添加编译选项:
find_package(catkin REQUIRED COMPONENTS
actionlib_msgs
actionlib
)
add_action_files(
FILES
DoDishes.action
)
generate_messages(
DEPENDENCIES
actionlib_msgs
)
DoDishes_Client.cpp
#include <actionlib/client/simple_action_client.h>
#include "robot_setup_tf/DoDishesAction.h"
typedef actionlib::SimpleActionClient<robot_setup_tf::DoDishesAction> Client;
//当action完成后会调用该回调函数一次
void doneCb(const actionlib::SimpleClientGoalState& state,const robot_setup_tf::DoDishesResultConstPtr& result){
ROS_INFO("Yay!The dishes are now clean");
ros::shutdown();
}
//当action激活后会调用该回调函数一次
void activeCb(){
ROS_INFO("Goal just went active");
}
//收到feedback后调用该回调函数
void feedbackCb(const robot_setup_tf::DoDishesFeedbackConstPtr& feedback){
ROS_INFO("percent_complete: %f",feedback->percent_complete);
}
int main(int argc,char** argv){
ros::init(argc,argv,"do_dishes_client");
//定义一个客户端
Client client("do_dishes",true);
//等待服务器端
ROS_INFO("Waiting for action server to start.");
client.waitForServer();
ROS_INFO("Action server started,sending goal.");
//创建一个action的goal
robot_setup_tf::DoDishesGoal goal;
goal.dishwasher_id=1;
//发送action的goal给服务器端,并且设置回调函数
client.sendGoal(goal,&doneCb,&activeCb,&feedbackCb);
ros::spin();
return 0;
}
DoDishes_Server.cpp
#include "ros/ros.h"
#include <actionlib/server/simple_action_server.h>
#include "robot_setup_tf/DoDishesAction.h"
typedef actionlib::SimpleActionServer<robot_setup_tf::DoDishesAction> Server;
//收到action的goal后调用该回调函数
void execute(const robot_setup_tf::DoDishesGoalConstPtr& goal,Server* as){
ros::Rate r(1);
robot_setup_tf::DoDishesFeedback feedback;
ROS_INFO("Dishwasher %d is working.",goal->dishwasher_id);
//假设洗盘子的进度,并且按照1hz的频率发布进度feedback
for(int i=1;i<=10;i++){
feedback.percent_complete=i*10;
as->publishFeedback(feedback);
r.sleep();
}
//当action完成后,向客户端返回结果
ROS_INFO("Dishwasher %d finish working.",goal->dishwasher_id);
as->setSucceeded();
}
int main(int argc,char** argv){
ros::init(argc,argv,"do_dishes_server");
ros::NodeHandle n;
//定义一个服务器
Server server(n,"do_dishes",boost::bind(&execute,_1,&server),false);
//服务器开始运行
server.start();
ros::spin();
return 0;
}
CMakeList.txt
add_executable(DoDishes_Client src/DoDishes_Client.cpp)
target_link_libraries( DoDishes_Client ${catkin_LIBRARIES})
add_dependencies(DoDishes_Client ${${PROJECT_NAME}_EXPORTED_TARGETS})
add_executable(DoDishes_Server src/DoDishes_Server.cpp)
target_link_libraries( DoDishes_Server ${catkin_LIBRARIES})
add_dependencies(DoDishes_Server ${${PROJECT_NAME}_EXPORTED_TARGETS})