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;
}