ROS基础目录
工作空间
src 代码空间
build 编译空间
devel 开发空间
install 安装控件
创建工作空间
创建工作空间是在src目录下进行catkin_init_workspace
mkdir -p ~/catkin_ws/src // 创建目录 -p 一次行创建多级目录
cd ~/catkin_ws/src // 切换到 ~/catkin_ws/src 目录下
catkin_init_workspace // 初始化工作空间
编译工作空间
编译工作空间要在根目录下
cd ~/catkin_ws/ // 切换到工作空间根目录
catkin_make // 编译
设置环境变量
仅在当前terminal中有效的设置方法
source devdl/setup.bash // 这一步是在根目录下执行
确定当前环境变量是否设置成功
echo $ROS_PACKAGE_PATH
输出
/home/luo/ws/catkin_ws/src:/opt/ros/melodic/share
环境变量通过 : 进行分割 如果自己的目录在环境变量中,既是设置成功,可以发现后加入的环境变量在前面。
永久有效的方法
前面的方法在新开的terminal中,刚刚设置的环境变量还是不存在的。如果想在新打开的terminal中依然存在刚设置的环境变量,需要修改~目录下的.bashrc。方法如下
nano ~/.bashrc
在.bashrc 最后加入
source ~/ws/catkin_ws/devel/setup.bash
source ~/.bashrc // 更新环境变量
验证 环境变量 是否成功设置,新开一个terminal,
echo $ROS_PACKAGE_PATH
查看输出的路径中是否有刚刚自己添加的路径。
在环境变量中 筛选有用信息
env |grep ROS_PACKAGE_PATH
查看环境变量中和ROS_PACKAGE_PATH相关的信息
创建功能包
创建功能包要在src下面
catkin_create_pkg learning_communication std_msgs rospy roscpp
其中catkin_create_pkg是指令
learning_communication是功能包的名字
std_msgs rospy roscpp 是依赖环境 正常都要带上
编译功能包
返回到根目录
cd ..
编译
catkin_make
注意事项:同一个工作空间下,不可以存在相同的功能包
不同的工作空间下,可以存在相同的功能包
查找功能包
rospack find roscpp_tutorials
返回的是功能包的路径
ROS通信机制
1、话题编程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjiF89gD-1640778615234)(D:\笔记文件夹\ROS基础(2).assets\image-20211229105628607-16407466072741.png)]
-
创建发布者
-
创建订阅者
-
添加编译选项
-
运行可执行程序
创建发布者
/**
* 该例程将发布chatter话题,消息类型String
*/
#include <sstream>
#include "ros/ros.h"
#include "std_msgs/String.h"
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc, argv, "talker");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Publisher,发布名为chatter的topic,消息类型为std_msgs::String
ros::Publisher chatter_pub = n.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;
}
CMakeLists.txt 中文件修改
生产可执行文件 talker 生成到 devel/lib/node名称下/talker,之后通过rosrun 对其进行执行
add_executable(talker src/talker.cpp)
如果cpp中用到第三方插件,需要在这里进行target_link 链接到第三方库文件,现在链接的库是catkin的基础库
target_link_libraries(talker ${catkin_LIBRARIES} )
创建接收者
自己写的程序
#include "ros/ros.h"
#include "std_msgs/String.h"
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
ROS_INFO("I heard : %s",msg->data.c_str());
}
int main(int argc, char **argv)
{
ros::init(argc,argv,"lensener");
ros::NodeHandle n;
ros::Subscriber sub = n.subscribe("chatter1",1000,chatterCallback);
ros::spin();
return 0;
}
程序历程
/**
* 该例程将订阅chatter话题,消息类型String
*/
#include "ros/ros.h"
#include "std_msgs/String.h"
// 接收到订阅的消息后,会进入消息回调函数
void chatterCallback(const std_msgs::String::ConstPtr& msg)
{
// 将接收到的消息打印出来
ROS_INFO("I heard: [%s]", msg->data.c_str());
}
int main(int argc, char **argv)
{
// 初始化ROS节点
ros::init(argc, argv, "listener");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个Subscriber,订阅名为chatter的topic,注册回调函数chatterCallback
ros::Subscriber sub = n.subscribe("chatter", 1000, chatterCallback);
// 循环等待回调函数
ros::spin();
return 0;
}
CMakeLists.txt 中文件修改
生产可执行文件 talker 生成到 devel/lib/node名称下/talker,之后通过rosrun 对其进行执行
add_executable(lensener src/lensener.cpp)
如果cpp中用到第三方插件,需要在这里进行target_link 链接到第三方库文件,现在链接的库是catkin的基础库
target_link_libraries(lensener ${catkin_LIBRARIES} )
此处出现的问题:
当先开启 subscribe,再启动Publisher 时, 发布的前两包信息会被丢弃 这个是什么原因?
- 定义msg文件
- 再package.xml中添加功能包依赖
- 再CMakeList.txt中添加编译
自定义消息结构
-
在功能包下新建 msg文件夹
新建文件Person.msg
string name uint8 sex uint8 age uint8 unknown = 0 uint8 male =1 uint8 female =2
-
在package.xml 中加入
<build_depend> message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
-
CMakeList中加入
-
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation )
-
## Generate messages in the 'msg' folder add_message_files( FILES Person.msg # Message2.msg )
-
## Generate added messages and services with any dependencies listed here generate_messages( DEPENDENCIES std_msgs )
-
catkin_package( # INCLUDE_DIRS include # LIBRARIES learning_communication CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # DEPENDS system_lib )
在创建完成后,编译 可以通过
rosmsg show Person 来验证创建的是否正确
-
2、服务编程
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0t52qGJO-1640778615236)(D:\笔记文件夹\ROS基础 (2).assets\image-20211229153801254-16407634850601.png)]
- 创建服务器
- 创建客户端
- 添加编译选项
- 运行可执行程序
定义srv文件
-
定义srv文件
-
在package.xml中添加功能包依赖
<build_depend> message_generation</build_depend> <exec_depend>message_runtime</exec_depend>
-
在CMakeList.txt中修改 和自定义添加编译依赖 1、2 相同 3 是特有的
-
find_package(catkin REQUIRED COMPONENTS roscpp rospy std_msgs message_generation )
-
catkin_package( # INCLUDE_DIRS include # LIBRARIES learning_communication CATKIN_DEPENDS roscpp rospy std_msgs message_runtime # DEPENDS system_lib )
-
## Generate services in the 'srv' folder add_service_files( FILES AddTwo.srv # Service2.srv )
-
生成可支持 文件
add_executable(server src/server.cpp)
-
测试生成文件是否可用
启动 roscore rosrun
注意
在vscode中编程为了在编程过程中能够讲新建的srv文件引入,需要在 src/.vscode/c_cpp_properties.json 文件下 includePath 下面加入
"includePath": [
"/opt/ros/melodic/include/**",
"/home/luo/ws/catkin_ws/src/learning_communication/include/**",
"/usr/include/**",
"/home/luo/ws/catkin_ws/devel/include/learning_communication**" // 这行是新加入的,包含的新生成的srv文件
],
创建一个服务器
- 初始化ROS节点
- 创建Server实例
- 循环等到服务请求,进入回调函数
- 在回调函数中完成服务功能的处理,并反馈应答数据
#include "ros/ros.h"
#include "learning_communication/AddTwo.h"
// service回调函数,输入参数req,输出参数res
bool add(learning_communication::AddTwo::Request &req,
learning_communication::AddTwo::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("sending back response: [%ld]", (long int)res.sum);
return true;
}
int main(int argc, char **argv)
{
// ROS节点初始化
ros::init(argc,argv,"add_two_inis_server");
// 创建节点句柄
ros::NodeHandle n;
// 创建一个名为add_two_ints的server,注册回调函数add()
ros::ServiceServer service = n.advertiseService("add_two_inis",add);
// 循环等待回调函数
ROS_INFO("Ready to add two ints.");
ros::spin();
return 0;
}
客户端程序
#include "learning_communication/AddTwo.h"
#include "ros/ros.h"
#include <cstdlib>
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 n;
// 创建一个client,请求add_two_int service,service消息类型是learning_communication::AddTwoInts
ros::ServiceClient client = n.serviceClient<learning_communication::AddTwo>("add_two_inis_server");
// 创建learning_communication::AddTwoInts类型的service消息
learning_communication::AddTwo 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;
}
编译代码
add_executable(server src/server.cpp) // 编译代码生成可执行文件
target_link_libraries(server ${catkin_LIBRARIES} ) // 设置链接库
add_dependencies(server ${PROJECT_NAME}_gencpp) // server 需要多加的一句 设置依赖
add_executable(client src/client.cpp)
target_link_libraries(client ${catkin_LIBRARIES} )
add_dependencies(client ${PROJECT_NAME}_gencpp)