系列文章目录

留空



文章目录

  • 系列文章目录
  • 前言
  • 一、题目
  • 二、使用RCLCPP编写参数
  • 三、完整代码
  • 四、测试
  • 1.用命令行查看参数
  • 2.修改参数
  • 总结



前言

自用


一、题目

通过参数实现动态调整 张三买书时 给王五 钱 的金额。

常用的编写参数的函数:
declare_parameter 声明和初始化一个参数
declare_parameters 声明和初始化一堆参数
get_parameter 通过参数名字获取一个参数
get_parameters 获取具有给定前缀的所有参数的参数值
set_parameters 设置一组参数的值

完成张三买书时 给王五 钱 的参数的更改,我们只需要做两步即可,声明参数和获取参数

根据上一篇,稍微粗略的修改了一下代码

wang5.cpp 修改了SellNovel_callback

#include "rclcpp/rclcpp.hpp"
//(1)导入订阅的话题接口类型
#include "std_msgs/msg/string.hpp"
//1.导入服务接口
#include "learning_interfaces1/srv/sell_novel.hpp"
// 引入C++标准库中的队列容器模板(先进先出(FIFO)的数据结构)
#include <queue>

class ReadersAndSellServer : public rclcpp::Node
{
    public:
        ReadersAndSellServer(std::string name) : Node(name)
        {
            RCLCPP_INFO(this->get_logger(),"读者节点%s已启动",name.c_str());
            RCLCPP_INFO(this->get_logger(),"卖书服务端%s已启动",name.c_str());

            //(3)创建订阅者
            sub_readers = this->create_subscription<std_msgs::msg::String>
            ("no_time",10,std::bind(&ReadersAndSellServer::readnovels_callback,this,std::placeholders::_1));

            // 5、创建一个服务回调组
            callback_group_service = this->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);

            // 4、创建服务端
            sellserver = this->create_service<learning_interfaces1::srv::SellNovel>
                        ("sell_novels",std::bind(&ReadersAndSellServer::SellNovel_callback,this,std::placeholders::_1,std::placeholders::_2),
                         rmw_qos_profile_default,callback_group_service);
        }
           
    private:
        //(2)声明订阅者
        rclcpp::Subscription<std_msgs::msg::String>::SharedPtr sub_readers;

        // 3、声明服务端
        rclcpp::Service<learning_interfaces1::srv::SellNovel>::SharedPtr sellserver;

        // 4、声明一个服务回调组
        rclcpp::CallbackGroup::SharedPtr callback_group_service;

        // 创建一个小说章节队列(书库)
        std::queue<std::string> novels_queue;

        //(4)创建订阅回调函数
        void readnovels_callback(const std_msgs::msg::String::SharedPtr novels)
        {
            //(5)编写订阅回调函数
            RCLCPP_INFO(this->get_logger(),"王五已阅读%s",novels->data.c_str());

            //把收到的小说存入书库
            novels_queue.push(novels->data);
        }
        
        // 2、创建服务端回调函数
        void SellNovel_callback(const learning_interfaces1::srv::SellNovel::Request::SharedPtr request,
                                const learning_interfaces1::srv::SellNovel::Response::SharedPtr response)
        {
            //第一步:判断张三给的钱数是否足够(每章1元)
            unsigned int sendnovel_flag = 0; //是否发送小说标志位
            unsigned int buymoney = request -> money; //张三发来的买书钱

            if(buymoney == 5)
            {
                sendnovel_flag = 1;
                RCLCPP_INFO(this->get_logger(),"已收到张三%d元",buymoney);
            }
            else if(buymoney != 5)
            {
                sendnovel_flag = 0;
                RCLCPP_INFO(this->get_logger(),"已收到张三%d元,付款有误,无法发送小说",buymoney);
            }

            //第二步:判断小说章节是否足够五章
            if(novels_queue.size() < 5 && sendnovel_flag == 1)
            {
                RCLCPP_INFO(this->get_logger(),"当前no_time章节存量为%zu:存量不够5章,开始等待",novels_queue.size());

                //设置rate周期为3s,代表3s检查一次
                rclcpp::Rate loop_rate(1.0/3);

                //当书库的章节小于5时,一直循环
                while(novels_queue.size() < 5)
                {

                    //显示当前书库的章节数量及缺少数量
                    RCLCPP_INFO(this->get_logger(),"等待中,目前已有%zu章,还差%zu章",novels_queue.size(),5-novels_queue.size());
                
                    //让整个循环3s运行一次
                    loop_rate.sleep();
                }

            }

            //当章节数量达到5,跳出循环
            if(sendnovel_flag == 1)
            RCLCPP_INFO(this->get_logger(),"当前no_time小说存量为%zu,已满足需求,准备发送",novels_queue.size());

            //第三步:把书发给张三
            
            //把小说从书库中一章一章取出,并放进请求响应对象response中
            if(sendnovel_flag == 1)
            {
             for(unsigned int i = 0 ; i < 5 ;i++)
                {
                    response->novels.push_back(novels_queue.front());
                    novels_queue.pop();
                }                
            }

        }
};

int main(int argc,char** argv)
{
    rclcpp::init(argc,argv);
    auto node = std::make_shared<ReadersAndSellServer>("wang5");
    //rclcpp::spin(node);
    //将之前的节点执行器换成多线程执行器
    rclcpp::executors::MultiThreadedExecutor exector;
    exector.add_node(node);
    exector.spin();
    rclcpp::shutdown();
    return 0;
}

zhang3.cpp使用了定时器,修改了buynovel_callback

#include "rclcpp/rclcpp.hpp"
// 1、导入服务接口
#include "learning_interfaces1/srv/sell_novel.hpp" 

class BuyNovelClient : public rclcpp::Node
{
    public:
        BuyNovelClient(std::string name) : Node(name)
        {
            RCLCPP_INFO(this->get_logger(),"买书客户端%s已启动",name.c_str());

            // 5、创建客户端
            buyclient = this->create_client<learning_interfaces1::srv::SellNovel>("sell_novels");

            // 10、创建定时器
            sendbuy_timer = this->create_wall_timer
            (std::chrono::milliseconds(10000), std::bind(&BuyNovelClient::buy_novel, this));
        }

         // 2、创建请求函数
        void buy_novel()
        {
            // 6、编写请求函数
            RCLCPP_INFO(this->get_logger(),"去找王五买小说啦!!");
            //等待服务端上线
            while(!buyclient->wait_for_service(std::chrono::seconds(3))) //若上线则退出循环
            {
                RCLCPP_INFO(this->get_logger(),"等待卖书服务端上线中..."); 
            }
            
            //构造请求数据
            auto request = std::make_shared<learning_interfaces1::srv::SellNovel_Request>(); //创建了一个“钱袋”
            request->money = 5; //在“钱袋”里装入了5块钱

            //发送异步请求
            buyclient ->async_send_request
            (request,std::bind(&BuyNovelClient::buynovel_callback,this,std::placeholders::_1));
        }
    
    private:
        // 4、声明客户端
        rclcpp::Client<learning_interfaces1::srv::SellNovel>::SharedPtr buyclient;

        // 9、声明定时器
        rclcpp::TimerBase::SharedPtr sendbuy_timer;

        // 3、创建请求结果接收回调函数
        void buynovel_callback(rclcpp::Client<learning_interfaces1::srv::SellNovel>::SharedFuture response)
        {
            // 7、编写请求结果接收回调函数
            //获取回复的结果
            auto buy_result = response.get();
            RCLCPP_INFO(this->get_logger(),"已收到王五发来的小说共%zu章,准备开读",buy_result->novels.size());

            //打印出小说内容
            for(std::string novels : buy_result->novels)
            {
                RCLCPP_INFO(this->get_logger(),"在读:%s",novels.c_str());
            }

            RCLCPP_INFO(this->get_logger(), "小说读完了,好期待下面的章节呀!");
        }   
};


int main(int argc,char** argv)
{
    rclcpp::init(argc,argv);
    auto node = std::make_shared<BuyNovelClient>("zhang3");
    //修改main函数调用请求函数
    node->buy_novel();
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

二、使用RCLCPP编写参数

打开zhang3.cpp

(1)声明参数

声明参数模版代码
this->declare_parameter("参数名", 参数默认值);

//(1)声明参数
this->declare_parameter("buymoney", 5);

声明了一个名为buymoney的参数,并为其提供了一个默认值5。如果在节点启动时没有为buymoney参数提供值,它将默认为5。

(2)获取参数

获取参数的模板代码
this->get_parameter("参数名");

//(2)获取参数
int money = this->get_parameter("buymoney").as_int();

获取名为buymoney的参数,并将其转换为整数类型赋值给money变量。虽然get_parameter是获取参数的基本调用,但直接这样调用返回的是一个rclcpp::Parameter对象,而不是参数的实际值。我们就要转换成整数类型,.as_int()是一个成员函数,用于将获取到的参数值转换为整数类型。

三、完整代码

#include "rclcpp/rclcpp.hpp"
// 1、导入服务接口
#include "learning_interfaces1/srv/sell_novel.hpp" 

class BuyNovelClient : public rclcpp::Node
{
    public:
        BuyNovelClient(std::string name) : Node(name)
        {
            RCLCPP_INFO(this->get_logger(),"买书客户端%s已启动",name.c_str());

            // 5、创建客户端
            buyclient = this->create_client<learning_interfaces1::srv::SellNovel>("sell_novels");

            //(1)声明参数
            this->declare_parameter("buymoney", 5);

            // 10、创建定时器
            sendbuy_timer = this->create_wall_timer
            (std::chrono::milliseconds(10000), std::bind(&BuyNovelClient::buy_novel, this));
        }

         // 2、创建请求函数
        void buy_novel()
        {
            // 6、编写请求函数
            RCLCPP_INFO(this->get_logger(),"去找王五买小说啦!!");
            //等待服务端上线
            while(!buyclient->wait_for_service(std::chrono::seconds(3))) //若上线则退出循环
            {
                RCLCPP_INFO(this->get_logger(),"等待卖书服务端上线中..."); 
            }
            
            //(2)设置参数
            int money = this->get_parameter("buymoney").as_int();
            RCLCPP_INFO(this->get_logger(), "已付款%d", money); 

            //构造请求数据
            auto request = std::make_shared<learning_interfaces1::srv::SellNovel_Request>(); //创建了一个“钱袋”
            //request->money = 5; //在“钱袋”里装入了5块钱
            request->money = money;

            //发送异步请求
            buyclient ->async_send_request
            (request,std::bind(&BuyNovelClient::buynovel_callback,this,std::placeholders::_1));
        }
    
    private:
        // 4、声明客户端
        rclcpp::Client<learning_interfaces1::srv::SellNovel>::SharedPtr buyclient;

        // 9、声明定时器
        rclcpp::TimerBase::SharedPtr sendbuy_timer;

        // 3、创建请求结果接收回调函数
        void buynovel_callback(rclcpp::Client<learning_interfaces1::srv::SellNovel>::SharedFuture response)
        {
            // 7、编写请求结果接收回调函数
            //获取回复的结果
            auto buy_result = response.get();

            if(buy_result->novels.size() != 0)
            RCLCPP_INFO(this->get_logger(),"已收到王五发来的小说共%zu章,准备开读",buy_result->novels.size());
            else
            RCLCPP_INFO(this->get_logger(),"未收到小说");

            //打印出小说内容
            for(std::string novels : buy_result->novels)
            {
                RCLCPP_INFO(this->get_logger(),"在读:%s",novels.c_str());
            }

            if(buy_result->novels.size() != 0)
            RCLCPP_INFO(this->get_logger(), "小说读完了,好期待下面的章节呀!");
        }   
};

int main(int argc,char** argv)
{
    rclcpp::init(argc,argv);
    auto node = std::make_shared<BuyNovelClient>("zhang3");
    //修改main函数调用请求函数
    node->buy_novel();
    rclcpp::spin(node);
    rclcpp::shutdown();
    return 0;
}

四、测试

测试之前,先将三个节点运行起来。
打开三个终端

第一个

colcon build
source install/setup.sh
ros2 run learning_service zhang3_node

第二个

source install/setup.sh
ros2 run learning_service wang5_node

第三个

source install/setup.sh
ros2 run learning_topic li4_node

ros2镜像_c++

1.用命令行查看参数

(1)查看参数列表

ros2 param list

ros2镜像_ros2镜像_02


(2)查看描述

ros2 param describe /zhang3 buymoney

ros2镜像_c++_03

(3)获取参数值

ros2 param get /zhang3 buymoney

ros2镜像_笔记_04

2.修改参数

ros2镜像_c++_05

ros2 param set /zhang3 buymoney 6

ros2镜像_笔记_06

ros2 param set /zhang3 buymoney 10

ros2镜像_开发语言_07

还可以使用rqt修改参数

rqt

打开后点击右上角的刷新,点击zhang3

ros2镜像_机器人_08


总结

自用