话题中自定义msg
1. 编写msg
在功能包(如plumbing_pub_sub
)下创建msg
目录,然后在msg
目录中创建.msg
文件,例如:Test.msg
,内容:
float32[] data
float32 vel
geometry_msgs/Pose pose
string name
2. 编辑package.xml
package.xml
中添加编译时依赖(message_generation
)与执行时依赖(message_runtime
)
<build_depend>message_generation</build_depend>
<exec_depend>message_runtime</exec_depend>
3. 编辑CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
roscpp
rospy
std_msgs
message_generation
geometry_msgs
)
#上面的msg文件中用到了geometry_msgs/Pose类型,那么必须查找geometry_msgs
# 配置 msg 源文件
add_message_files(
FILES
Test.msg
)
# 生成消息时依赖于 std_msgs和geometry_msgs
# generate_messages必须在catkin_package前面
generate_messages(
DEPENDENCIES
std_msgs
geometry_msgs
)
#执行时依赖
catkin_package(
CATKIN_DEPENDS roscpp rospy std_msgs geometry_msgs message_runtime
)
4. 编译
编译之后,在/devel/include/pkg/
下就会出现对应的Test.h
头文件方便调用。
5. 使用
使用就是正常导入头文件即可。
需要注意的是,如果没有执行步骤4,那么需要在CMakeLists.txt中添加:
#node 是要编译的目标文件, 就是add_executable()中的第一个名字。因此add_dependencies要写在add_executable之后
add_dependencies(node ${PROJECT_NAME}_gencpp)
5. 在其他功能包中调用msg
以下步骤仅在需要调用的包下设置:
5.1 编辑package.xml
维护软件包清单的更新
<build_depend>plumbing_pub_sub</build_depend>
<exec_depend>plumbing_pub_sub</exec_depend>
5.2 编辑CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
plumbing_pub_sub
)
add_dependencies(current_node plumbing_pub_sub_gencpp)
#current_node 是当前要编译的目标二进制文件
#add_dependencies要写在add_executable之后
add_dependencies
是防止编译当前功能包时plumbing_pub_sub
还没有被编译。并不是必须,但是最好加上。
服务中自定义srv
1. 编写srv
在功能包下创建srv
目录,然后在msg
目录中创建.srv
文件,例如:Test.srv
,内容:
int32 num1
int32 num2
---
int32 sum
2. 其他
除了在CMakelist.txt中将add_message_files
的部分改成add_service_files
对应部分:
add_service_files(
FILES
Test.srv
)
其他与写msg都相同。
C++调用头文件
1. 编写头文件
编写头文件 a.h
, 放入pkg/include/head_dict/a.h
。
例如: 在功能包plumbing_head下写了hello/hello.h,那么应该放在 plumbing_head/include/hello/hello.h
。
其中, hello.h
内容如下:
#ifndef _HELLO_H //避免重复定义
#define _HELLO_H
namespace hello_ns{
class MyHello{
public:
void run();
};
}
#endif
2. (可选,为了编程时有代码提示)
在VSCode中的c_cpp_properties.json
文件中添加
"includePath": [,
"自己的路径/plumbing_head/include/**"
]
3. 编写源文件来调用头文件
例如:编写hello.cpp
#include "ros/ros.h"
#include "hello/hello.h"
namespace hello_ns{
void MyHello::run(){
ROS_INFO("running ......");
}
}
int main(int argc, char* argv[]){
ros::init(argc, argv, "hello_head");
hello_ns::MyHello myHello;
myHello.run();
return 0;
}
4. 编写CMakeLists.txt
include
取消注释
include_directories(
include #就是将当前包下的include路径加进去
${catkin_INCLUDE_DIRS}
)
其他正常:
add_executable(hello src/hello.cpp)
# add_dependencies似乎不是必须
add_dependencies(hello ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(hello
${catkin_LIBRARIES}
)
C++调用源文件
1 2(与之前相同)
第一步和第二步与之前相同
3. 编写源文件来对头文件实现
例如:编写hello.cpp
#include "ros/ros.h"
#include "hello/hello.h"
namespace hello_ns{
void MyHello::run(){
ROS_INFO("running ......");
}
}
4. 编写源文件来调用实现
例如:编写test_hello.cpp
#include "ros/ros.h"
#include "hello/hello.h"
int main(int argc, char* argv[]){
ros::init(argc, argv, "hello_head");
hello_ns::MyHello myHello;
myHello.run();
return 0;
}
5. 编写CMakeLists.txt
源文件添加到库中,
include_directories(
include
${catkin_INCLUDE_DIRS}
)
add_library(hello_lib
src/hello.cpp
)
add_executable(test_hello src/test_hello.cpp)
add_dependencies(test_hello ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries
添加所有依赖库
target_link_libraries(test_hello
${catkin_LIBRARIES}
hello_lib
)
C++功能包之间互调库函数(A包调B包的库函数)
对B包编写CMakeLists.txt
继续用上面例子,catkin_package
用于指定该包的一些基本信息,提供头文件和库供其他软件包使用。catkin_package
让其他包在使用 find_package(catkin REQUIRED COMPONENTS ...)
后自动引入你的软件包提供的头文件和库,而不需要显式指定。
catkin_package(
INCLUDE_DIRS include
LIBRARIES hello_lib
)
include_directories(
include
${catkin_INCLUDE_DIRS}
)
add_library(hello_lib
src/hello.cpp
)
INCLUDE_DIRS include
是将自己的INCLUDE_DIRS
指定为的include
的绝对路径,LIBRARIES hello_lib
就是将自己的hello_lib
加入到该包的库中。
这样其他包可以使用找到此头文件和头文件的实现。
对A包编写package.xml
<build_depend>B_PKG_NAME</build_depend>
<exec_depend>B_PKG_NAME</exec_depend>
对A包编写CMakeLists.txt
find_package(catkin REQUIRED COMPONENTS
B_PKG_NAME
)
CMake可以使用message来查看一些信息
message(STATUS "B_PKG_NAMEd_LIBRARIES = ${B_PKG_NAME_INCLUDE_DIRS}")
message(STATUS "B_PKG_NAME_LIBRARIES = ${B_PKG_NAME_INCLUDE_DIRS}")
Python引入(import)其他模块(功能包内部、功能包之间)
1.原理
假设
假设我们的python文件都放在workspace/src/pkg1_name/scripts/
下,例如我们写了如下的内容:
- 一个功能模块:
tools.py
, - 一个运行文件:
run.py
, - 一个带有py文件的目录:
arg/arg_tool.py
。
我们依赖情况是run.py
依赖于tools.py
和arg/arg_tool.py
。
即我们的run.py
中有如下内容:
import tools
import arg.arg_tool
问题
我们知道当我们执行rosrun
的时候,是工作空间的根目录下,所以我们run.py
需要找到tools.py
和arg
的路径才行,为此往上主要有两者方法:
- 第一种是在
run.py
中加入这些模块所在的目录。 - 第二种是根据官网教程写
setup.py
。
这两种方法都是可以的,但是第一种的问题就是过于繁琐,如果我们需要在功能包之间互相引入模块,就需要在run.py
开头加入很多路径。第二种的问题是通过那种cmake
生成的tools.py
在VsCode中写代码时无法提示。
思路
我们可以参考消息message
的引用:
当我们自定义了例如workspace/src/pkg2_name/msg/Test.msg
这样的message
进行编译之后,我们可以在任何py文件中使用from pkg2_name.msg import Test
。
这是因为编译之后,python相关的可调用模块被放在了workspace/devel/lib/python3/dist-packages/pkg2_name/msg
下。
也就是说python会优先在workspace/devel/lib/python3/dist-packages
中查找需要的模块。所以我们将tools.py
和arg/arg_tool.py
也放在这里就好了。
2. 编写CMakeLists.txt
在CMakeLists.txt末尾加入以下内容即可。
set(target_dir ${CATKIN_DEVEL_PREFIX}/lib/python3/dist-packages/${PROJECT_NAME}) # 设置目标目录名称
# 需要的模块python文件
set(files_to_link
tools.py
arg/arg_tool.py
)
file(MAKE_DIRECTORY ${target_dir}) #创建目标目录
#建立软链接
foreach(file ${files_to_link})
get_filename_component(file_dir ${file} DIRECTORY)
file(MAKE_DIRECTORY ${target_dir}/${file_dir})
file(CREATE_LINK ${CMAKE_CURRENT_SOURCE_DIR}/scripts/${file} ${target_dir}/${file} SYMBOLIC)
endforeach()
需要修改的就是在这部分加入自己想要添加的python文件。
这里是建立软链接的方式,而不是直接复制。
这是因为这样占用空间较小(仅保存一个路径),而且源py文件改写后,不需要重新编译就可以直接使用。
set(files_to_link
tools.py
arg/arg_tool.py
)
3. 编译和改写python代码
最后编译一遍,然后就可以在任意功能包引入刚刚导入的文件了。
需要注意的是直接使用以下代码是不行的:
import tools
import arg.arg_tool
这是因为在workspace/devel/lib/python3/dist-packages
下创建的是pkg1_name
目录,因此这部分代码要改为:
from pkg1_name import tools
from pkg1_name.arg import arg_tool
4. 最后
编译之后,在任何功能包下就都可以调用刚刚加入的模块了。
当然,如果想使用:文章来源:https://www.toymoban.com/news/detail-849952.html
import tools
import arg.arg_tool
也是可以的,只是需要在CMakeLists.txt中略微修改即可,具体怎么改,莫非就是将建立软链接的地方修改一下。文章来源地址https://www.toymoban.com/news/detail-849952.html
到了这里,关于ROS中不同情况下配置文件的编写的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!