ROS2——什么是接口

ROS2——什么是接口

接口简介

在机器人系统中, 往往有许许多多的硬件, 比如摄像头, 激光雷达, 每一个硬件发送的数据/数据类型是不同的, 那么ROS2是如何使用这些数据的呢?

前文KFCHamburger中我们使用过这些定义:

#include "std_msgs/msg/string.hpp"
#include "std_msgs/msg/u_int32.hpp"
...
<std_msgs::msg::String>
<std_msgs::msg::UInt32>

这里的std_msgs是ROS2内置的一个接口功能包.

查看某一个接口包下所有的接口:

ros2 interface package std_msgs
ros2-interface-package-std_msgs

当然, 这些内置接口也许不能满足你的需求, 此时就可以自定义接口.

自定义接口

针对ROS2的通信方式, 接口可以分为:

  • 话题接口

    文件名: *.msg

    int64 num
    

    This is your custom message that transfers a single 64-bit integer called num.

  • 服务接口

    文件名:*.srv

    int64 a
    int64 b
    int64 c
    ---
    int64 sum
    

    This is your custom service that requests three integers named a, b, and c, and responds with an integer called sum.

  • 动作接口

    文件名:*.action

    int32 order
    ---
    int32[] sequence
    ---
    int32[] partial_sequence
    

自定义话题接口

前情提要: 前面的KFC实例中, KFC会定时发送一条广告话题, 如果要发送图片信息怎么办? 这就需要自定义KFC专属消息接口.

编辑.msg文件

cd到工作空间的/src文件夹下, 新建接口包

cd ros2_ws/src
ros2 pkg create topic_interfaces --build-type ament_cmake

cd进入topic_interfaces文件夹, 新建KFC.msg文件(首字母要求大写)

mkdir msg
touch msg/KFC.msg

编辑KFC.msg

# 原始数据类型string
string txt

# 原始数据类型 uint32
uint32 money

# 图像消息,调用sensor_msgs下的Image类型
sensor_msgs/Image image
修改Cmakelist.txt

注意:rosidl_generate_interfaces()必须在 ament_package()

# 这两句添加依赖
find_package(sensor_msgs REQUIRED)
find_package(rosidl_default_generators REQUIRED)

# 声明msg文件所属的工程名字, 文件位置, 依赖DEPENDENCIES
rosidl_generate_interfaces(${PROJECT_NAME}
  "msg/Ad.msg"
   DEPENDENCIES sensor_msgs
 )
修改package.xml
<!-- 添加如下内容 -->
<depend>sensor_msgs</depend>
<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_runtime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>
编译并刷新环境变量
colcon build --packages-select topic_interfaces
source ~/.bashrc
使用自定义话题接口修改KFC与Customer

上代码! 请读者自行对比区别, // CHANGE为修改的地方

新建文件Customer_with_interfaces.cpp

#include "rclcpp/rclcpp.hpp"
// 这个头文件是topic_interfaces接口包编译后自动生成的
#include "topic_interfaces/msg/kfc.hpp" // CHANGE

using namespace std::chrono_literals;

using std::placeholders::_1;

class CustomerNode : public rclcpp::Node
{
public:
    CustomerNode(std::string name) : Node(name)
    {
        RCLCPP_INFO(this->get_logger(), "大家好,我是一个%s.",name.c_str());

        sub_hamburger = this->create_subscription<topic_interfaces::msg::KFC>("hamburger", 10, std::bind(&CustomerNode::hamburger_callback, this, _1)); // CHANGE
        
        sub_advertisement = this->create_subscription<topic_interfaces::msg::KFC>("advertisement", 10, std::bind(&CustomerNode::advertisement_callback, this, _1)); // CHANGE
        
        hungry_timer = this->create_wall_timer(1000ms, std::bind(&CustomerNode::hungry_timer_callback, this));

        pub_money = this->create_publisher<topic_interfaces::msg::KFC>("money_of_hamburger", 10); // CHANGE
        
        money.money = 10; // CHANGE

        pub_money->publish(money);
        RCLCPP_INFO(this->get_logger(), "我饿了, 我要吃汉堡! 付款 %d 元", money.money); // CHANGE

    }
private:
    topic_interfaces::msg::KFC money; // CHANGE

    rclcpp::TimerBase::SharedPtr hungry_timer;

    rclcpp::Subscription<topic_interfaces::msg::KFC>::SharedPtr sub_hamburger; // CHANGE

    rclcpp::Publisher<topic_interfaces::msg::KFC>::SharedPtr pub_money; // CHANGE

    rclcpp::Subscription<topic_interfaces::msg::KFC>::SharedPtr sub_advertisement; // CHANGE
    
    void hamburger_callback(const topic_interfaces::msg::KFC::SharedPtr msg) // CHANGE
    {
        RCLCPP_INFO(this->get_logger(), "这是我吃的 %s ", msg->txt.c_str()); // CHANGE
    }

    void hungry_timer_callback()
    {
        RCLCPP_INFO(this->get_logger(), "我又饿了, 还想再吃一个! 付款 %d 元", money.money); // CHANGE
        pub_money->publish(money);
    }

    void advertisement_callback(const topic_interfaces::msg::KFC::SharedPtr msg) // CHANGE
    {
        RCLCPP_INFO(this->get_logger(), "我收到了一条广告: %s ", msg->txt.c_str()); // CHANGE
    }
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<CustomerNode>("Customer");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

新建文件KFC_with_interfaces.cpp

#include "rclcpp/rclcpp.hpp"
#include "topic_interfaces/msg/kfc.hpp" // CHANGE

using namespace std::chrono_literals;

using std::placeholders::_1;

class KFCNode : public rclcpp::Node
{
public:
    KFCNode(std::string name) : Node(name), count(1)
    {
        RCLCPP_INFO(this->get_logger(), "大家好, 我是%s的服务员.",name.c_str());
        
        pub_hamburger = this->create_publisher<topic_interfaces::msg::KFC>("hamburger", 10); // CHANGE
        
        pub_advertisement = this->create_publisher<topic_interfaces::msg::KFC>("advertisement", 10); // CHANGE
        
        advertisement_timer = this->create_wall_timer(5000ms, std::bind(&KFCNode::advertisement_timer_callback, this));
        
        sub_money = this->create_subscription<topic_interfaces::msg::KFC>("money_of_hamburger", 10, std::bind(&KFCNode::money_callback, this, _1)); // CHANGE
    }
private:
    size_t count;

    rclcpp::TimerBase::SharedPtr advertisement_timer;

    rclcpp::Publisher<topic_interfaces::msg::KFC>::SharedPtr pub_hamburger; // CHANGE
    
    rclcpp::Subscription<topic_interfaces::msg::KFC>::SharedPtr sub_money; // CHANGE

    rclcpp::Publisher<topic_interfaces::msg::KFC>::SharedPtr pub_advertisement; // CHANGE

    void advertisement_timer_callback()
    {
        auto str_advertisement = topic_interfaces::msg::KFC(); // CHANGE
        str_advertisement.txt = "大鸡腿降价啦"; // CHANGE
        RCLCPP_INFO(this->get_logger(), "KFC发布了一个广告:%s", str_advertisement.txt.c_str()); // CHANGE
        pub_advertisement->publish(str_advertisement);
    }
    
    void money_callback(const topic_interfaces::msg::KFC::SharedPtr msg) // CHANGE
    {
        if(msg->money == 10) // CHANGE
        {
            RCLCPP_INFO(this->get_logger(), "收款 %d 元", msg->money); // CHANGE

            auto str_hamburger_num = topic_interfaces::msg::KFC(); // CHANGE
            str_hamburger_num.txt = "第" + std::to_string(count++) + "个汉堡"; // CHANGE
            RCLCPP_INFO(this->get_logger(), "这是我卖出的%s", str_hamburger_num.txt.c_str()); // CHANGE
            
            pub_hamburger->publish(str_hamburger_num);
        }
        
    }
};

int main(int argc, char **argv)
{
    rclcpp::init(argc, argv);
    auto node = std::make_shared<KFCNode>("KFC");
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

修改Cmakelist.txt, 添加/修改:

find_package(topic_interfaces REQUIRED)

add_executable(Customer_with_interfaces_node src/Customer_with_interfaces.cpp)
ament_target_dependencies(Customer_with_interfaces_node rclcpp topic_interfaces)

add_executable(KFC_with_interfaces_node src/KFC_with_interfaces.cpp)
ament_target_dependencies(KFC_with_interfaces_node rclcpp topic_interfaces)

install(TARGETS
  Customer_node
  KFC_node
  Customer_with_interfaces_node
  KFC_with_interfaces_node
  DESTINATION lib/${PROJECT_NAME}
)

修改package.xml, 添加:

<depend>topic_interfaces</depend>

编译并刷新环境

colcon build --packages-select customer_and_kfc
source ~/.bashrc

开启两个终端, 分别运行使用自定义接口的KFC与Customer

ros2 run customer_and_kfc Customer_with_interfaces_node
ros2 run customer_and_kfc KFC_with_interfaces_node

成功~

详细查看接口

要想详细查看接口, 可以使用ros2 interface命令

  1. 查看包下所有接口

    ros2 interface package topic_interfaces
    
    ros2-interface-package-topic-interfaces
  2. 查看内容

    ros2 interface show topic_interfaces/msg/Ad
    
    ros2-interface-show-topic-interfaces-msg-Ad
  3. 显示属性

    ros2 interface proto topic_interfaces/msg/Ad
    
    ros2-interface-proto-topic-interfaces-msg-Ad

自定义服务接口

自定义服务接口将在下一篇文章讲解服务时一起讲解.

更多教程欢迎进入我的博客学习~

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范子琦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值