从上周搞定ROS工程下使用Protbuf的问题后,陆续对原有工程进行了更改,在这一过程中,探索了下Protobuf与ROS工程结合的不同方式,暂时总结了一份模板,并在此记录下心得。

1. 使用 Proto 的 ROS 节点

在这贴下个人使用的范例:

1
2
3
4
5
6
7
8
9
10
11
.
├── CMakeLists.txt
├── include
│ └── map
│ ├── map.cpp
│ └── map.h
├── package.xml
├── proto
│ └── map.proto
└── src
└── map_node.cpp

个人在尝试不同的组织结构的过程中,也试过把proto文件单独设置一个节点,后续节点只需要添加即可,不需要都更改CmakeLists.txt文件。但对比Apollo工程发现,这样做会使工程目录不够清晰,不能直观地看到工程中是否引用了proto文件。再三考虑后还是决定每个节点单独设置proto文件夹来存在proto文件,这样更清晰直观。


2. CmakeLists.txt模板

目前最终效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
cmake_minimum_required(VERSION 2.8.3)

project(map)

find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)

## System dependencies are found with CMake's conventions
list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
include(FindProtobuf)
find_package(Protobuf REQUIRED)

set(proto_dir ${PROJECT_SOURCE_DIR}/proto)
file(GLOB proto_files "${proto_dir}/*.proto")

# Set up destination directories
catkin_destinations()
set(proto_gen_dir ${CATKIN_DEVEL_PREFIX}/${CATKIN_GLOBAL_INCLUDE_DESTINATION}/${PROJECT_NAME})
set(proto_gen_cpp_dir ${proto_gen_dir})
file(MAKE_DIRECTORY ${proto_gen_dir})
file(MAKE_DIRECTORY ${proto_gen_cpp_dir})
set(protogen_include_dirs ${proto_gen_cpp_dir}/../ ${proto_gen_python_dir})

# Create lists of files to be generated
set(proto_gen_cpp_files "")
foreach(proto_file ${proto_files})
get_filename_component(proto_name ${proto_file} NAME_WE)
list(APPEND proto_gen_cpp_files
${proto_gen_cpp_dir}/${proto_name}.pb.h
${proto_gen_cpp_dir}/${proto_name}.pb.cc
)
endforeach(proto_file ${proto_files})

# Run protoc and generate language-specific headers.
add_custom_command(
OUTPUT ${proto_gen_cpp_files}
COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${proto_dir} --cpp_out=${proto_gen_cpp_dir} ${proto_files}
DEPENDS ${PROTOBUF_PROTOC_EXECUTABLE} ${proto_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)

set_source_files_properties(${proto_gen_cpp_files} PROPERTIES GENERATED TRUE)

add_custom_target(${PROJECT_NAME}_generate_headers
DEPENDS ${proto_gen_cpp_files}
)

# Create proto library for lining.
include_directories(${PROTOBUF_INCLUDE_DIR} ${PROTOBUF_INCLUDE_DIR}/../../)
add_library(${PROJECT_NAME}_proto ${proto_gen_cpp_files})
target_link_libraries(${PROJECT_NAME}_proto ${PROTOBUF_LIBRARY})
add_dependencies(${PROJECT_NAME}_proto ${PROJECT_NAME}_generate_headers)

catkin_package(
INCLUDE_DIRS ${protogen_include_dirs}
LIBRARIES ${PROJECT_NAME}_proto
)

install(TARGETS ${PROJECT_NAME}_proto
ARCHIVE DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
LIBRARY DESTINATION ${CATKIN_PACKAGE_LIB_DESTINATION}
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION}
)

install(DIRECTORY ${proto_gen_cpp_dir}/
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h"
)

catkin_package(
INCLUDE_DIRS include
)

include_directories(
${catkin_INCLUDE_DIRS}
${PROTOBUF_INCLUDE_DIR}
${CATKIN_DEVEL_PREFIX}
include
)

add_library(${PROJECT_NAME}
include/${PROJECT_NAME}/map.cpp
)

add_executable(map_node
src/map_node.cpp
include/${PROJECT_NAME}/map.cpp
)

target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES}
${PROTOBUF_LIBRARIES}
${Boost_FILESYSTEM_LIBRARY}
${Boost_SYSTEM_LIBRARY}
)

在使用中,有以下几点需要注意:

  1. 使用时必须保证节点根目录下存在proto文件夹,并放置好proto文件,否则会提示无目标文件错误;
  2. 使用时需对应修改下与节点名称相关的变量
  3. 注意:生成的proto文件存在于devel目录inlude文件夹下,对应生成节点名称的文件夹,下面存在生成的变量。
  4. include_directories目录中包含${CATKIN_DEVEL_PREFIX}宏,之后才可以引用devel文件目录中的proto生成文件;