在ros2中使用共享内存 -- 案例

前面写了一篇文章专门讲述了在ros2中使用fastdds的共享内存中间件实现的一些配置项及参考资料,下面我们来通过一个案例来说明共享内存的配置使用

共享内存配置

根据前面的笔记及文档资料总结,要使用共享内存必须要配置好相关的profile,下面提供的一个案例:
需要注意几个点:

  1. 必须配置default profile,否则会报错;
  2. xml profile的格式,字段不能有问题,否则会报错,是固定的;
  3. 官网文档不详尽,还是得结合源码来推断一些字段的名称,比如,historyMemoryPolicy如果配置成DYNAMIC实际上是对应官方的DYNAMIC_RESERVE_MEMORY_MODE;而官方还有一种DYNAMIC类型是DYNAMIC_REUSABLE_MEMORY_MODE;内存分配策略如果内存资源充足,或对平响有较高要求,推荐PREALLOCATED_MEMORY_MODE,折衷选PREALLOCATED_WITH_REALLOC_MEMORY_MODE,内存资源较少则选DYNAMIC
  4. fastdds官网没有publisher类型的profile attribute说明,但实际是可以用的,publisher/subscriber可以对应多个data_writer或data_reader;
  5. 根据fastdds的官方文档各配置项都可以加,注意好层级关系即可,如在ros2的rtps案例中data_sharing只写了kind,但fastdds介绍了datasharing有domain_ids,shared_dir等属性,这里shared_dir也得从源码看,官网文档也没举例,改目录也没用,可能还得配置环境变量,具体就没再仔细研究了;
<?xml version="1.0" encoding="UTF-8"?>
<dds xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">
    <profiles>
        <!-- Default publisher profile -->
        <publisher profile_name="default publisher profile" is_default_profile="true">
            <qos>
                <publishMode>
                    <kind>SYNCHRONOUS</kind>
                </publishMode>
                <data_sharing>
                    <kind>AUTOMATIC</kind>
                </data_sharing>
            </qos>
            <historyMemoryPolicy>PREALLOCATED_WITH_REALLOC</historyMemoryPolicy>
        </publisher>

        <subscriber profile_name="default subscriber profile" is_default_profile="true">
            <qos>
                <data_sharing>
                    <kind>AUTOMATIC</kind>
                </data_sharing>
            </qos>
            <historyMemoryPolicy>PREALLOCATED_WITH_REALLOC</historyMemoryPolicy>
        </subscriber>
        
        <publisher profile_name="count">
            <qos>
                <publishMode>
                    <kind>SYNCHRONOUS</kind>
                </publishMode>
                <data_sharing>
                    <kind>AUTOMATIC</kind>
                    <domain_ids>
                        <domainId>123</domainId>
                    </domain_ids>
                    <shared_dir>"/home/lzs/docker/robo_volume/desertrescue/output/ros2"</shared_dir>
                </data_sharing>
            </qos>
            <historyMemoryPolicy>PREALLOCATED_WITH_REALLOC</historyMemoryPolicy>
        </publisher>

        <!-- Default subscriber profile -->
        <subscriber profile_name="count">
            <qos>
                <data_sharing>
                    <kind>AUTOMATIC</kind>
                    <domain_ids>
                        <domainId>456</domainId>
                    </domain_ids>
                    <shared_dir>"/home/lzs/docker/robo_volume/desertrescue/output/ros2"</shared_dir>
                </data_sharing>
            </qos>
            <historyMemoryPolicy>PREALLOCATED_WITH_REALLOC</historyMemoryPolicy>
        </subscriber>
    </profiles>
</dds>

配置好共享内存后,编译出可执行文件然后通过指定环境变量就可以使用了,指定环境变量按前面的文章也有两种方式。一般来说多个应用,统一配置在一个xml文件中,统一指定环境变量;

#include "rclcpp/loaned_message.hpp"
#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/int32.hpp"
#include "common_proto_data/msg/pubapp2_subapp.hpp"
#include <chrono>
#include <iostream>

class ZeroCopyPublisher : public rclcpp::Node {
public:
    ZeroCopyPublisher() : Node("ZeroCopyPublisher") {
        //countPub = this->create_publisher<std_msgs::msg::Int32>("count", 10);
        countPub = this->create_publisher<common_proto_data::msg::Pubapp2Subapp>("count", 10);
    }
    void pub_count() {
        auto count_ = countPub->borrow_loaned_message();
        count_.get().count = i;
        std::cout << "publishing count:" << count_.get().count << std::endl;
        countPub->publish(std::move(count_));
        ++i;
    }
private:
    //rclcpp::Publisher<std_msgs::msg::Int32>::SharedPtr countPub;
    rclcpp::Publisher<common_proto_data::msg::Pubapp2Subapp>::SharedPtr countPub;
    int i = 0;
};

int main(int argc, char **argv) {
    rclcpp::init(argc, argv);
    auto node = std::make_shared<ZeroCopyPublisher>();
    rclcpp::Rate rate(std::chrono::seconds(1));
    while(rclcpp::ok()) {
        node->pub_count();
        rate.sleep();
        rclcpp::spin_some(node);
    }
    return 0;
}

cmake如下:

cmake_minimum_required(VERSION 3.8)
project(pub_app)

#set(CMAKE_C_COMPILER /usr/bin/gcc-12)
#set(CMAKE_CXX_COMPILER /usr/bin/g++-12)
set(CMAKE_CXX_STANDARD 17)
add_compile_options(-Wall -Wextra -Wpedantic)

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)
find_package(common_proto_data REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

message("project source:${PROJECT_SOURCE_DIR}")
include_directories(${PROJECT_SOURCE_DIR}/../../../third_party/toml/include)
include_directories(${PROJECT_SOURCE_DIR}/../../../third_party/ullib/include)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()
#target_link_libraries(publisher PUBLIC ${PROJECT_SOURCE_DIR}/third_party/toml/lib/libtoml11.a)
#add_executable(publisher src/pub_example.cpp)
add_executable(publisher src/shared_mem_pub.cpp)
ament_target_dependencies(publisher rclcpp std_msgs common_proto_data)
#target_link_directories(publisher PUBLIC ${PROJECT_SOURCE_DIR}/../../../third_party/toml/include)
target_link_libraries(publisher ${PROJECT_SOURCE_DIR}/../../../third_party/toml/lib/libtoml11.a
                                ${PROJECT_SOURCE_DIR}/../../../third_party/ullib/lib/libullib.a)

#target_link_libraries(publisher PUBLIC ${PROJECT_SOURCE_DIR}/../../../third_party/toml/lib)

install(TARGETS publisher DESTINATION ${PROJECT_SOURCE_DIR}/../../../output/ros2/${PROJECT_NAME}/lib/${PROJECT_NAME})
#install(DIRECTORY ${PROJECT_SOURCE_DIR}/../../../third_party/toml/lib DESTINATION ./)
install(DIRECTORY ${PROJECT_SOURCE_DIR}/cfg DESTINATION ${PROJECT_SOURCE_DIR}/../../../output/ros2/pub_app/)

ament_package()

案例的代码利用了编写的msg文件来指定发布的内容,这里用此案例是为了说明共享内存和msg文件的兼容性,可以直接调用msg中定义的count变量
msg文件如下, 命名是Pubapp2Subapp.msg

int64 count

ros2的msg文件有很多坑,我们在下一篇文章会仔细讲解;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值