ROS #14 Param

남생이·2024년 10월 24일

ROS

목록 보기
15/28

1. 파라미터 설정

  • argument 노드에서 파라미터를 선언하고 파라미터 값이 변경되는 함수
  • 파라미터 사용을 위한 3가지 요소
  1. declare_parameter 함수 : 노드에서 사용할 파라미터의 고유 이름을 지정하고 초기값 설정
  2. get_parameter 함수
    : 노드에서 사용할 파라미터의 값을 호출 --> yaml 형태의 파라미터 파일의 값을 불러오는데 사용된다.
  3. add_on_set_parameters_callback 함수: 서비스 형태로 파라미터 변경 요청이 있을 때 사용되는 함수로 지정도니 콜백 함수 호출
self.declare_parameter('parameter_name', default_value)
parameter_name = self.get_parameter('parameter_name').value
self.add_on_set_parameters_callback(self.callback_function)
  • ex_calculator/argument.py
# ROS2 노드의 파라미터를 동적으로 변경 시, 그 결과를 나타내는 메시지 타입 호출 --> successful/reason
from rcl_interfaces.msg import SetParametersResult

class Argument(Node):

    def __init__(self):
        super().__init__('argument')
        self.declare_parameter('qos_depth', 10)
        qos_depth = self.get_parameter('qos_depth').value
        self.declare_parameter('min_random_num', 0)
        self.min_random_num = self.get_parameter('min_random_num').value
        self.declare_parameter('max_random_num', 9)
        self.max_random_num = self.get_parameter('max_random_num').value
        self.add_on_set_parameters_callback(self.update_parameter)

    def update_parameter(self, params):
        for param in params:
            if param.name == 'min_random_num' and param.type_ == Parameter.Type.INTEGER:
                self.min_random_num = param.value
            elif param.name == 'max_random_num' and param.type_ == Parameter.Type.INTEGER:
                self.max_random_num = param.value
        return SetParametersResult(successful=True)
  • arithmetic_config.yaml
argument:
  ros__parameters:
    qos_depth: 10  # 메시지 버퍼 크기
    min_random_num: 0  # 무작위 숫자의 최소값
    max_random_num: 9  # 무작위 숫자의 최대값

2. 코드 실행

$ ros2 run ex_calculator argument
$ ros2 param list
$ ros2 param get /argument <parameter_name>
$ ros2 param set /argument <parameter_name>

3. SetParameters 인터페이스 이용

  • 서비스 클라이언트로 서비스 요청을 통해 파라미터 변경

  • Parameter 클래스를 선언하여 매개변수(name, type, integer_value) 등을 설정

  • 이를 이용하여 a노드에서 b노드의 파라미터를 변경 가능

3.1 setup.py 설정

data_files=[
        ('share/ament_index/resource_index/packages', ['resource/' + package_name]),
        (share_dir, ['package.xml']),
        (share_dir + '/launch', glob.glob(os.path.join('launch', '*.launch.py'))),
        (share_dir + '/param', glob.glob(os.path.join('param', '*.yaml'))),

위 코드를 추가하여 launch, yaml 파일을 사용하여 빌드하도록 설정

3.2 launch.py

  • launch 파일에 특정 파라미터 파일을 추가하면 해당 launch 파일로 노드 실행 시 지정 파라미터 파일의 파라미터 이름과 파라미터 값을 확인하여 해당 노드의 파라미터를 초기화하여 사용 가능
import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    param_dir = LaunchConfiguration(
        'param_dir',
        default=os.path.join(
            get_package_share_directory('ex_calculator'),
            'param',
            'arithmetic_config.yaml'))

    return LaunchDescription([
        DeclareLaunchArgument(
            'param_dir',
            default_value=param_dir,
            description='Full path of parameter file'),

        Node(
            package='ex_calculator',
            executable='argument',
            name='argument',
            parameters=[param_dir],
            output='screen'),

        Node(
            package='ex_calculator',
            executable='calculator',
            name='calculator',
            parameters=[param_dir],
            output='screen'),
    ])
  • 위 코드를 통해 해당 함수는 calculator, argument 두 노드를 파라미터 파일을 실행하도록 한다

  • param_dir: 패키지의 공유 디렉토리 경로와 설정된 yaml 파일의 경로를 지정

3.3 실행 코드

  • 실행인자: 프로그램 실행 시 명령어와 함께 전달하는 값 --> 프로그램이 실행 시 특정한 설정이나 값을 전달하여 프로그램의 동작을 제어할 수 있도록 해주는 역할
    - 주로 프로그램의 main() 함수에서 매개변수로 사용되어 처리됨
$ ros2 run ex_calculator checker -g 100

-g 100 : 실행 인자, -g는 옵션 또는 플래그로 해당 옵션에 100에 해당하는 값을 전달

  • parameter: 함수나 메소드가 선언될때 사용되는 매개변수
  • argument: 함수가 어떤 값을 받아들이도록 정의하는 것, 함수 호출 시의 인수 - 실행 인자

import argparse
import sys

import rclpy

from ex_calculator.checker.checker import Checker


def main(argv=sys.argv[1:]):
    parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter)
    parser.add_argument(
        '-g',
        '--goal_total_sum',
        type=int,
        default=50,
        help='Target goal value of total sum')
    parser.add_argument(
        'argv', nargs=argparse.REMAINDER,
        help='Pass arbitrary arguments to the executable')
    args = parser.parse_args()

    rclpy.init(args=args.argv)
    try:
        checker = Checker()
        checker.send_goal_total_sum(args.goal_total_sum)
        try:
            rclpy.spin(checker)
        except KeyboardInterrupt:
            checker.get_logger().info('Keyboard Interrupt (SIGINT)')
        finally:
            checker.arithmetic_action_client.destroy()
            checker.destroy_node()
    finally:
        rclpy.shutdown()


if __name__ == '__main__':
    main()

parser=argparse.ArgumentParser: 명령줄 인자를 처리하기 위한 도구, 실행 시 인자를 정의하고 해석, 파서 만들기
parser.add_argument(): 명령줄에서 사용할 수 있는 옵션을 정의, 인자 추가
args = parser.parse_args(): 인자 파싱하기
args.xxx): 인자사용하기

  • -g, --goal_total_sum: 옵션이름 설정
  • type=int: 옵션의 타입 설정
  • default=50: 사용자가 인자 제공하지 않을 경우 기본값 설정
  • help: --help입력시 설명 확인 가능 -->
    - formatter_class=argparse.ArgumentDefaultsHelpFormatter: --help를 실행할 때 기본값을 포함한 설명을 출력할 수 있게 해줍니다.
  • 실행 인자 처리
int main(int argc, char*argv[])
{
 rclcpp::init(argc, argv):
 ...
def main(argv=sys.arbv[1:]:
 (argparse 구문 추가)
 rclpy.init(args=argv)
  • 실행 인자 사용을 위해서는 첫 argv인 실행명 및 실행 경로인 첫번째 인자를 삭제한 것을 argv에 저장하고 이를 rclpy 모듈의 init 함수에 넘긴다. 이때 argparse 모듈을 이용하여 실행인자를 위한 구문 해석 프로그램을 작성한다.
nameexplanation
argcargument count
argvargument vector or value
argsarguments

4. launch system

  • 하나 이상의 정해진 노드를 실행 가능
  • 노드 실행 시 패키지의 매개변수나 노드 이름 변경, 노드 네임스페이스 설정, 환경 변수 변경 등의 옵션 사용 가능

4.1 arithmetic.launch.py

import os

from ament_index_python.packages import get_package_share_directory
from launch import LaunchDescription
from launch.actions import DeclareLaunchArgument
from launch.substitutions import LaunchConfiguration
from launch_ros.actions import Node

def generate_launch_description():
    param_dir = LaunchConfiguration(
        'param_dir',
        default=os.path.join(
            get_package_share_directory('ex_calculator'),
            'param',
            'arithmetic_config.yaml'))

    return LaunchDescription([
        DeclareLaunchArgument(
            'param_dir',
            default_value=param_dir,
            description='Full path of parameter file'),

        Node(
            package='ex_calculator',
            executable='argument',
            name='argument',
            parameters=[param_dir],
            output='screen'),

        Node(
            package='ex_calculator',
            executable='calculator',
            name='calculator',
            parameters=[param_dir],
            output='screen'),
    ])
# 필요시 실행 관련 설정을 선언하고 메소드의 리턴값으로 'LaunchDescription` 클래스로 반환함
def generate_launch_description():
	xxx = LaunchConfiguration(yyy)
    
    return LaunchDescription(yyy)
    
    	DeClareLaunchArgument(aaa),
        Node(bbb),
        Node(ccc),
    ])
  • param_dir: 파라미터 디렉토리를 설정하는 부분
Node(
		package=''
        executable = ''
        name=''
        parameters=[param_dir]
        output='screen'),
  • remappings: 특정 이름을 변경할 수 있는것, 내부 코드 변경없이 토픽, 서비스, 액션 등의 고유 이름을 변경할 수 있는 유용한 기능

  • namespace: 고유의 이름을 바꾸어 독립적인 네트워크 그룹핑이 가능

  • LaunchDescription.add_action: return값이 많은 경우 사용가능

profile
공부하는 거북이

0개의 댓글