(ROS2-6 시작) 매개변수

ROS2 매개변수


  • 노드 설정, 런타임에 설정된 값
  • 노드별 매개변수
  • ROS2 매개변수 유형
    • 부울, 정수, 복식, 문자열, 목록…

매개변수 선언

number_publisher.cpp

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/msg/int64.hpp"

class NumberPublisherNode : public rclcpp::Node
{
public:
    NumberPublisherNode() : Node("number_publisher"), number_(2)
    {
				// add this line
        this->declare_parameter("name");
        
        number_publisher_ = this->create_publisher<example_interfaces::msg::Int64>("number", 10);
        number_timer_ = this->create_wall_timer(std::chrono::seconds(1),
                                                std::bind(&NumberPublisherNode::publishNumber, this));
        RCLCPP_INFO(this->get_logger(), "Number publisher has been started.");
    }

private:
    void publishNumber()
    {
        auto msg = example_interfaces::msg::Int64();
        msg.data = number_;
        number_publisher_->publish(msg);
    }

    int number_;
    rclcpp::Publisher<example_interfaces::msg::Int64>::SharedPtr number_publisher_;
    rclcpp::TimerBase::SharedPtr number_timer_;
};

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

더 나은 코드

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/msg/int64.hpp"

class NumberPublisherNode : public rclcpp::Node
{
public:
    NumberPublisherNode() : Node("number_publisher")
    {
        this->declare_parameter("number_to_publish", 2);
        this->declare_parameter("publish_frequency", 1.0);

        number_ = this->get_parameter("number_to_publish").as_int();
        double publish_frequency = this->get_parameter("publish_frequency").as_double();

        number_publisher_ = this->create_publisher<example_interfaces::msg::Int64>("number", 10);
        number_timer_ = this->create_wall_timer(std::chrono::milliseconds((int) (1000.0 / publish_frequency)),
                                                std::bind(&NumberPublisherNode::publishNumber, this));
        RCLCPP_INFO(this->get_logger(), "Number publisher has been started.");
    }

private:
    void publishNumber()
    {
        auto msg = example_interfaces::msg::Int64();
        msg.data = number_;
        number_publisher_->publish(msg);
    }

    int number_;
    rclcpp::Publisher<example_interfaces::msg::Int64>::SharedPtr number_publisher_;
    rclcpp::TimerBase::SharedPtr number_timer_;
};

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

number_publisher.py

#!
/usr/bin/env python3 import rclpy from rclpy.node import Node from example_interfaces.msg import Int64 class NumberPublisherNode(Node): def __init__(self): super().__init__("number_publisher") # add this lines self.declare_parameter("test1") self.declare_parameter("test2") # ------------------- self.number_ = 2 self.number_publisher_ = self.create_publisher(Int64, "number", 10) self.number_timer_ = self.create_timer(1.0, self.publish_number) self.get_logger().info("Number publisher has been started.") def publish_number(self): msg = Int64() msg.data = self.number_ self.number_publisher_.publish(msg) def main(args=None): rclpy.init(args=args) node = NumberPublisherNode() rclpy.spin(node) rclpy.shutdown() if __name__ == "__main__": main()
ros2 run my_py_pkg number_publisher
ros2 run my_py_pkg number_counter

ros2 param list
"
/number_publisher:
  test1
	test2
  use_sim_time
/number_counter:
	use_sim_time
"

ros2 param get /number_publisher use_sim_time
# Boolean value is: False

노드를 시작할 때마다 자동으로 ros2에 대한 use_sim_time 매개변수를 갖게 됩니다.

하지만 이 매개변수는 신경쓰지 않습니다.

현재 응용 프로그램에서 실행 중인 매개변수만 쉽게 찾을 수 있습니다.

이름은 같아도 매개변수는 다릅니다.

매개 변수를 설정합시다!

ros2 run my_py_pkg number_publisher --ros-args -p test1:=3
ros2 run my_py_pkg number_publisher --ros-args -p test2:="hello"

ros2 param get /number_publisher test1
# Integer value is: 3
ros2 param get /number_publisher test2
# String value is: hello

매개변수 가져오기

#!
/usr/bin/env python3 import rclpy from rclpy.node import Node from example_interfaces.msg import Int64 class NumberPublisherNode(Node): def __init__(self): super().__init__("number_publisher") self.declare_parameter("number_to_publish", 2) # second parameter is default value self.declare_parameter("publish_frequency", 1.0) self.number_ = self.get_parameter("number_to_publish").value self.publisher_frequeny_ = self.get_parameter("publish_frequency").value self.number_publisher_ = self.create_publisher(Int64, "number", 10) self.number_timer_ = self.create_timer( 1.0 / self.publisher_frequeny_, self.publish_number) self.get_logger().info("Number publisher has been started.") def publish_number(self): msg = Int64() msg.data = self.number_ self.number_publisher_.publish(msg) def main(args=None): rclpy.init(args=args) node = NumberPublisherNode() rclpy.spin(node) rclpy.shutdown() if __name__ == "__main__": main()
ros2 run my_py_pkg number_publisher --ros-args -p number_to_publish:=3 -p publish_frequency:=4

ros2 topic echo /number 
"
data: 2
---
data: 2
---
"

ros2 topic hz /number 
"
average rate: 4.000
	min: 0.235s max: 0.261s std dev: 0.00800s window: 6
average rate: 4.000
	min: 0.235s max: 0.261s std dev: 0.00597s window: 11
average rate: 4.000
	min: 0.235s max: 0.261s std dev: 0.00534s window: 16
"

활동

매개변수로 조금 더 연습해 봅시다.

여기에는 2가지 빠른 활동이 있습니다.

1. 로봇 뉴스캐스트 주제 섹션에서 만든 첫 번째 노드 중 하나를 기억하십니까? 노드는 주제에 대해 “안녕하세요, 로봇 뉴스 스테이션의 R2D2입니다!
”와 같은 문자열을 게시합니다.

이제 런타임에 봇의 이름을 설정할 수 있다면 더 좋을 것이므로 다른 봇 이름으로 노드를 여러 번 시작할 수 있습니다.

“robot_name” 매개변수를 추가하고 해당 값을 사용하여 “robot_news” 주제에 문자열을 게시합니다.

문자열 템플릿(“안녕하세요. !
“)는 이제 런타임에 설정한 이름을 사용합니다.

2. “led_panel_node”로 돌아갑니다.

LED 상태를 나타내는 int 배열이 있습니다(0은 꺼짐, 1은 켜짐). “led_states”라는 매개변수로 이 배열을 설정합니다.


이렇게 하면 문자열, 정수 및 배열 매개변수를 연습할 수 있습니다.

이러한 변경 사항은 Python 및 Cpp 노드 모두에 적용할 수 있습니다.

해결책

로봇 뉴스 station.py

#!
/usr/bin/env python3 import rclpy from rclpy.node import Node from example_interfaces.msg import String class RobotNewsStationNode(Node): def __init__(self): super().__init__("robot_news_station") self.declare_parameter("robot_name", "C3PO") self.robot_name_ = self.get_parameter("robot_name").value self.publisher_ = self.create_publisher(String, "robot_news", 10) self.timer_ = self.create_timer(0.5, self.publish_news) self.get_logger().info("Robot News Station has been started") def publish_news(self): msg = String() msg.data = "Hi, this is " + \\ str(self.robot_name_) + " from the robot news station." self.publisher_.publish(msg) def main(args=None): rclpy.init(args=args) node = RobotNewsStationNode() rclpy.spin(node) rclpy.shutdown() if __name__ == "__main__": main()

led_panel.py

#!
/usr/bin/env python3 import rclpy from rclpy.node import Node from my_robot_interfaces.msg import LedStateArray from my_robot_interfaces.srv import SetLed class LedPanelNode(Node): def __init__(self): super().__init__("led_panel") self.declare_parameter("led_states", (0, 0, 0)) self.led_states_ = self.get_parameter("led_states").value self.led_states_publisher_ = self.create_publisher( LedStateArray, "led_states", 10) self.led_states_timer_ = self.create_timer(4, self.publish_led_states) self.set_led_service_ = self.create_service( SetLed, "set_led", self.callback_set_led) self.get_logger().info("LED panel node has been started.") def publish_led_states(self): msg = LedStateArray() msg.led_states = self.led_states_ self.led_states_publisher_.publish(msg) def callback_set_led(self, request, response): led_number = request.led_number state = request.state if led_number > len(self.led_states_) or led_number <= 0: response.success = False return response if state not in (0, 1): response.success = False return response self.led_states_(led_number - 1) = state response.success = True self.publish_led_states() return response def main(args=None): rclpy.init(args=args) node = LedPanelNode() rclpy.spin(node) rclpy.shutdown() if __name__ == "__main__": main()

로봇 뉴스 Station.cpp

#include "rclcpp/rclcpp.hpp"
#include "example_interfaces/msg/string.hpp"

class RobotNewsStationNode : public rclcpp::Node
{
public:
    RobotNewsStationNode() : Node("robot_news_station"), robot_name_("R2D2")
    {
        this->declare_parameter("robot_name", "R2D2");
        robot_name_ = this->get_parameter("robot_name").as_string();

        publisher_ = this->create_publisher<example_interfaces::msg::String>("robot_news", 10);
        timer_ = this->create_wall_timer(std::chrono::milliseconds(500),
                                         std::bind(&RobotNewsStationNode::publishNews, this));
        RCLCPP_INFO(this->get_logger(), "Robot News Station has been started.");
    }

private:
    void publishNews()
    {
        auto msg = example_interfaces::msg::String();
        msg.data = std::string("Hi, this is ") + robot_name_ + std::string(" from the Robot News Station");
        publisher_->publish(msg);
    }

    std::string robot_name_;
    rclcpp::Publisher<example_interfaces::msg::String>::SharedPtr publisher_;
    rclcpp::TimerBase::SharedPtr timer_;
};

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

led_panel.cpp

#include "rclcpp/rclcpp.hpp"
#include "my_robot_interfaces/msg/led_state_array.hpp"
#include "my_robot_interfaces/srv/set_led.hpp"

class LedPanelNode : public rclcpp::Node
{
public:
    LedPanelNode() : Node("led_panel")
    {
        this->declare_parameter("led_states", std::vector<int64_t>{0, 0, 0});
        led_states_ = this->get_parameter("led_states").as_integer_array();

        led_states_publisher_ =
            this->create_publisher<my_robot_interfaces::msg::LedStateArray>("led_states", 10);
        led_states_timer_ =
            this->create_wall_timer(std::chrono::seconds(4),
                                    std::bind(&LedPanelNode::publishLedStates, this));
        set_led_service_ = this->create_service<my_robot_interfaces::srv::SetLed>(
            "set_led",
            std::bind(&LedPanelNode::callbackSetLed, this, std::placeholders::_1, std::placeholders::_2));
        RCLCPP_INFO(this->get_logger(), "Led panel node has been started");
    }

private:
    void publishLedStates()
    {
        auto msg = my_robot_interfaces::msg::LedStateArray();
        msg.led_states = led_states_;
        led_states_publisher_->publish(msg);
    }

    void callbackSetLed(const my_robot_interfaces::srv::SetLed::Request::SharedPtr request,
                        const my_robot_interfaces::srv::SetLed::Response::SharedPtr response)
    {
        int64_t led_number = request->led_number;
        int64_t state = request->state;

        if (led_number > (int64_t)led_states_.size() || led_number <= 0)
        {
            response->success = false;
            return;
        }

        if (state !
= 0 && state !
= 1) { response->success = false; return; } led_states_.at(led_number - 1) = state; response->success = true; publishLedStates(); } std::vector<int64_t> led_states_; rclcpp::Publisher<my_robot_interfaces::msg::LedStateArray>::SharedPtr led_states_publisher_; rclcpp::TimerBase::SharedPtr led_states_timer_; rclcpp::Service<my_robot_interfaces::srv::SetLed>::SharedPtr set_led_service_; }; int main(int argc, char **argv) { rclcpp::init(argc, argv); auto node = std::make_shared<LedPanelNode>(); rclcpp::spin(node); rclcpp::shutdown(); return 0; }