Ros proto
protobuf
Protobuf的数据结构定义的语法,以及如何编译proto文件,以及相关的主要读写proto文件结构中的API
说明:
读bin文件API 是bin文件二进制形式,
Prototxt文件 是prototxt形式.ProtoBuf数据保存的一种形式,主要是以txt形式.最主要的功能是可视化,
步骤
Define message formats in a .proto file.
Use the protocol buffer compiler.
Use the C++ protocol buffer API to write and read messages.
语法
syntax = "proto3" 表示使用proto3版本,默认使用proto2版本。
optional 表示当前字段可选,非必填。
string name = 1 每个字段需要有一个唯一的号码,必须大于0。
enum 表示枚举类型。
repeated 表示可重复,
message 可以嵌套
protobuf 的一大特点就是通过 “代码生成” 数据结构类的方式来序列化、反序列化二进制数据
protobuf 使用方式
01.手动调用 protoc 来编译文件,然后引入自己的项目。
02.使用 CMake 提供的 find_package 脚本找到 protobuf,得到一些变量。
03.使用 CMake 下载指定版本 protobuf,源码编译 protobuf,然后用编译生成的 protoc 来编译。
C++
代码示例
#include <vector>
#include <iostream>
#include <ros/types.h>
#include <std_msgs/String.h>
#include <rosbag/view.h>
#include <rosbag/bag.h>
#include "test.pb.h"
#define foreach BOOST_FOREACH
#include <boost/foreach.hpp>
using namespace std;
int main(){
rosbag::Bag bag;
bag.open("/data/test/test.bag", rosbag::bagmode::Read);
std::vector<std::string> topics; //设置需要遍历的topic
topics.push_back(std::string("/test/sensor/test_person"));
rosbag::View view(bag, rosbag::TopicQuery(topics));;
//rosbag::View view_all(view); //读取全部topic如果全读,第二个参数不写,如下
PersonObstacle Person;
foreach(rosbag::MessageInstance const m, view)
{
//此处为消息头文件中的ConstPtr
std_msgs::String::ConstPtr s = m.instantiate<std_msgs::String>();
if (s != NULL){
std::cout << "the null message"<<std::endl;
std::cout << Person.ParseFromString(s->data) <<std::endl;
std::cout << Person.id() <<std::endl;
std::cout << Person.mstatus()<<std::endl;
std::cout << Person.mstatus_Name<<std::endl;
}
else{
std::cout << "the message"<<std::endl;
}
}
bag.close();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)
project(parseBag)
find_package(catkin REQUIRED COMPONENTS
rosbag
roscpp
rospy
std_msgs
)
set(CMAKE_CXX_FLAGS "-std=c++17 -pthread")
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
#Find required protobuf package
find_package(Protobuf REQUIRED)
if(PROTOBUF_FOUND)
message(STATUS "protobuf library found")
else()
message(FATAL_ERROR "protobuf library is needed but cant be found")
endif()
include_directories(
${Protobuf_INCLUDE_DIRS}
${CMAKE_CURRENT_BINARY_DIR}/..
)
message(STATUS "protobuf library includ: ${Protobuf_INCLUDE_DIRS}")
#Find required opncv package
set(OpenCV2_DIR /usr/share/OpenCV)
find_package(OpenCV REQUIRED)
include_directories(
${OpenCV_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}/opencv2
)
link_libraries( ${OpenCV_LIBS})
###########
## Build ##
###########
include_directories(
./include
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
add_executable(${PROJECT_NAME}_node ./src/bagParse.cpp ./include/test.pb.cc ./include/test2.pb.cc )
target_link_libraries(${PROJECT_NAME}_node
${catkin_LIBRARIES} ${PROTOBUF_LIBRARIES}
)
C++调试
未声明的引用是头文件引入错误,
未定义的引用是函数的实现没有引入。
python3
1.安装和使用:
1.安装protobuf ,安装完成后 protoc --version,如果将输出版本号
2.2.python安装protobuf,直接通过pip安装 pip3 install protobuf
3.根据协议生成python文件 protocol -I= --python_out
--python_out --python3_out
4.引入脚本,使用api
2.报错原因:
01.(unicode error) 'utf-8' codec can't d --Python版本问题
02.locale问题
3.说明
python2
SerializeToString(): serializes the message and returns it as a string. Note that the bytes are binary, not text; we only use the str type as a convenient container.
ParseFromString(data)
python3
序列化的时候,pyhont3 使用 protobuf3 的接口变了。
encode_to_bytes 替换了 SerializeToString
parse_from_bytes 替换了 ParseFromString
说明
ParseFromString是一种方法-它不返回任何内容,而是填充self已解析的内容
python 安装proto
details on the protoc and google.protobuf versions.
[root@fedora ]# protoc --version
libprotoc 25.0
[root@fedora ]# python3
>>> import google.protobuf
>>> print(google.protobuf.__version__)
4.25.0
下载地址
https://github.com/protocolbuffers/protobuf/releases
下载文件:
protoc-25.1-linux-x86_64.zip -- 选择了对应平台的包
protobuf-25.1.zip
1. protoc-25.1-linux-x86_64.zip压后打开该目录的bin目录,复制路径到环境变量中
2.解压protobuf-23.1.zip文件,找到python目录,并在protobuf中的python目录打开cmd将下面三条命令敲入
(pip的protobuf和下载的protobuf版本最好一致)–要在当前目录下的cmd噢
pip install protobuf
python setup.py build
python setup.py install
### 安装命令会将当前的 Python 应用安装到当前 Python 环境的 site-packages 目录下,这样其他程序就可以像导入标准库一样导入该应用的代码了。
概览
protocol buffers是一个灵活的、高效的、自动化的用于对结构化数据进行序列化的协议,
与json、xml相比,protocol buffers序列化后的码流更小、速度更快、操作更简单。
tcp协议,用的比较多的是protobuffer
使用步骤
1.Define message formats in a .proto file.
2.Use the protocol buffer compiler.
3.Use the C++ protocol buffer API to write and read messages.
1.需要将要被序列化的数据结构定义一次(使用.proto文件定义)
eg: //xxx.proto
通过在.proto文件中定义protocol buffer的message类型来指定你想要序列化的数据结构
2.使用特别生成的源代码(使用protobuf提供的生成工具protoc) 轻松的使用不同的数据流完成对这些结构数据的读写操作,
使用protocol buffer提供的编译工具protoc来编译.proto文件生成数据访问类
protoc -I=$SRC_DIR --cpp_out=$DST_DIR $SRC_DIR/addressbook.proto
protoc --proto_path=. --cpp_out=. ./format/error_code.proto
# # 查看版本
protoc --version
–proto_path=PATH。它表示要在哪个路径下搜索.proto文件,这个参数既可以用-I指定,也可以使用–proto_path=指定。-I参数没有等于号
即–cpp_out=,–python_out=等。如果protoc已经内置语言对应的编译插件,则无需再安装。如果没有内置语言,就需要单独安装插件,比如–go_out=,对应的就是protoc-gen-g
addressbook.pb.h, the header which declares your generated classes.
addressbook.pb.cc, which contains the implementation of your classes
eg://xxx.pb.h
python
生成的*_pb2.py文件
生成的*_pb2.py文件
3.使用
提供了简单的访问器(比如name()和set_name()),
同时还提供了 将整个结构化数据序列化为原始字节数据 以及 从原始字节数据反序列化为结构化数据的方法
C++使用
#include "common/proto/sensor.pb.h"
对于 C++,编译器从每个 .proto 生成一个 .h 和 .cc 文件,其中包含文件中描述的每种 message 类型对应的类
你在使用 enum 的 .proto 上运行 protocol buffer 编译器时,生成的代码将具有相应的用于 Java 或 C++ 的 enum
方法和属性
the setter methods begin with set_.
There are also has_ methods for each singular (required or optional)
clear_ method that un-sets the field back to its empty state.
the numeric id field
序列化和反序列化方法 Parsing and Serialization
bool SerializeToString(string* output) const 以及 bool ParseFromString(const string& data);
bool SerializeToOstream(ostream* output) const以及 bool ParseFromIstream(istream* input);
proto文件具体详情
1..proto文件 最开始建议说明使用proto2还是proto3语法的声明:syntax = "proto2";,如果不声明默认使用proto2的语法
2..proto文件 必须以package xxxx;声明开头,作为协议唯一的标识,避免不同项目的命名冲突
3.引用其他proto文件 import
message 类型已在另一个 .proto 文件中定义,该怎么办?可以通过导入来使用其他 .proto 文件中的定义
4. message数据格式
一个 message 相当于一个指定类型的集合,一个message可以直接嵌套另一个message使用 组合messages
包含了一系列的 name-value 对
字段声明是required||repeated||optional 缺省默认就设置为 optional)
required: 格式良好的 message 必须包含该字段一次。 在 proto3 中已经为兼容性彻底抛弃 required
optional: 格式良好的 message 可以包含该字段零次或一次(不超过一次)
repeated: 该字段可以在格式良好的消息中重复任意多次(包括零) 或者在最后使用 [packed = true]
标量类型
复合类型,包括 枚举 和其它的 message 类型
构成
字段声明 名称 类型 唯一编号
唯一编号 identify the unique field number that field uses in the binary encoding
可以将默认值指定为 message 描述的一部分。optional int32 result_per_page = 3 [default = 10];
使用
pyhont3 使用 protobuf3 的接口变化了。
encode_to_bytes 替换了原来的 SerializeToString
parse_from_bytes 替换了原来的 ParseFromString
C++
Cmake
Cmake有官方的modules,可以通过简单的几个命令protobuf_generate_cpp来生成对应的.pb.cc和.pb.h。
PROTOBUF_INCLUDE_DIRS - protobuf的头文件
PROTOBUF_LIBRARIES - protobuf库
参考
https://protobuf.dev/reference/cpp/
在 CMake 项目中使用 protobuf
rosbag遍历数据出错:(unicode error) 'utf-8' codec can't d https://www.apude.com/blog/15289.html
https://developers.google.com/protocol-buffers/docs/pythontutorial
【ROS】读写rosbag(c++)
ROS(melodic)创建工作空间,功能包(Ubuntu18.04)