토픽을 통해 문자열 메시지 형식으로 정보를 서로 전달하는 노드를 만듭니다 . 여기에 사용된 예는 간단한 "talker" 및 "listener" 시스템입니다. 한 노드는 데이터를 게시하고 다른 노드는 해당 데이터를 받을 수 있도록 주제를 구독합니다.
이 예제에 사용된 코드는 여기에서 찾을 수 있습니다 .
실습
1. 패키지 생성
명령이 작동하도록 새 터미널을 열고 ROS 2 설치를 소싱합니다 . ros2
이전 자습서 에서 만든 ros2_ws
디렉터리 로 이동합니다 .
패키지는 작업 영역의 루트가 아닌 src
디렉터리 에 만들어야 한다는 점을 기억하십시오. 따라서 ros2_ws/src
로 이동하여 패키지 생성 명령을 실행합니다.
Copy ros2 pkg create --build-type ament_python py_pubsub
터미널은 패키지 py_pubsub
와 필요한 모든 파일 및 폴더 생성을 확인하는 메시지를 반환합니다.
2. 게시자 노드 작성하기
ros2_ws/src/py_pubsub/py_pubsub
로 이동합니다. 이 디렉터리는 중첩된 ROS2 패키지와 이름이 같은 Python 패키지 라는 점을 기억하세요.
다음 명령을 입력하여 예제 Talker 코드를 다운로드합니다.
Copy wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py
이제 __init__.py
인접한 이름의 새 파일 publisher_member_function.py 가 생긴걸 볼 수 있습니다
.
원하는 텍스트 편집기를 사용하여 파일을 엽니다.
Copy import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalPublisher(Node):
def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
2.1 코드 검토
주석 import 이후의 첫 번째 코드 줄은 rclpy의
Node
클래스를 사용할 수 있도록 합니다.
Copy import rclpy
from rclpy.node import Node
다음 명령문은 노드가 주제에서 전달하는 데이터를 구조화하는 데 사용하는 기본 제공 문자열 메시지 유형을 가져옵니다.
Copy from std_msgs.msg import String
이들은 라인들은 노드의 종속성을 나타냅니다. package.xml
에 종속성을 추가해야 하며 다음 섹션에서 수행할 것임을 기억하십시오.
다음으로 MinimalPublisher
에서 상속하는(또는 하위 클래스인) Node
클래스가 생성됩니다.
Copy class MinimalPublisher(Node):
다음은 클래스 생성자의 정의입니다. super().__init__은 Node
클래스의 생성자를 호출하고 여기에 노드 이름(minimal_publisher
)을 제공합니다
create_publisher
를 통해 String
유형의 메시지를 게시 하고 "대기열 크기"가 10인 토픽을 선언합니다. 대기열 크기는 구독자가 빠르게 처리하지 못할 경우를 대비해 준비할 메세지의 양을 제한하는 필수 QoS(서비스 품질) 설정입니다.
다음으로 0.5초마다 실행되는 콜백과 함께 타이머가 생성됩니다. self.i는
콜백에 사용되는 카운터입니다.
Copy def __init__(self):
super().__init__('minimal_publisher')
self.publisher_ = self.create_publisher(String, 'topic', 10)
timer_period = 0.5 # seconds
self.timer = self.create_timer(timer_period, self.timer_callback)
self.i = 0
timer_callback
는 카운터 값이 추가된 메시지를 0.5초 마다 생성 합니다. self.i는 콜백에 사용되는 카운터 입니다.
Copy def timer_callback(self):
msg = String()
msg.data = 'Hello World: %d' % self.i
self.publisher_.publish(msg)
self.get_logger().info('Publishing: "%s"' % msg.data)
self.i += 1
마지막으로 main 함수를 정의합니다.
Copy def main(args=None):
rclpy.init(args=args)
minimal_publisher = MinimalPublisher()
rclpy.spin(minimal_publisher)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_publisher.destroy_node()
rclpy.shutdown()
먼저 rclpy
라이브러리가 초기화되고 minimal_publisher 노드가 생성된 다음 콜백이 호출되도록 노드를 "spin" 합니다.
2.2 종속성 추가
setup.py, setup.cfg 그리고 package.xml 파일이 있는 ros2_ws/src/py_pubsub 디렉토리로 이동 합니다.
package.xml 파일을 편집기로엽니다.
이전 튜토리얼 에서 언급했듯이 <description>
, <maintainer>
및 <license>
태그를 입력해야 합니다.
Copy <description>Examples of minimal publisher/subscriber using rclpy</description>
<maintainer email="you@email.com">Your Name</maintainer>
<license>Apache License 2.0</license>
위 줄 뒤에 노드의 가져오기 문에 해당하는 다음 종속성을 추가합니다.
Copy <exec_depend>rclpy</exec_depend>
<exec_depend>std_msgs</exec_depend>
이것은 해당 코드가 실행되는 시기에 rclpy
과 std_msgs
가 필요함을 선언합니다.
파일을 저장하십시오.
2.3 진입점 추가
setup.py 파일을 편집기로 엽니다. 다시한번 package.xml 파일의
maintainer
, maintainer_email
, description
,license
필드를 확인 합니다.
Copy maintainer='YourName',
maintainer_email='you@email.com',
description='Examples of minimal publisher/subscriber using rclpy',
license='Apache License 2.0',
entry_points
필드의 console_scripts
대괄호 안에 다음 줄을 추가합니다 .
Copy entry_points={
'console_scripts': [
'talker = py_pubsub.publisher_member_function:main',
],
},
저장하는 것을 잊지 마십시오.
2.4 setup.cfg 확인
setup.cfg
파일의 내용은 다음과 같이 자동으로 올바르게 채워져야 합니다.
Copy [develop]
script-dir=$base/lib/py_pubsub
[install]
install-scripts=$base/lib/py_pubsub
이것은 단순히 setuptools에게 ros2 run
실행 파일을 찾기 위해 lib
에 넣도록 지시하는 것 입니다 .
지금 패키지를 빌드하고 로컬 설정 파일을 소싱하여 실행할 수 있지만 작업 중인 전체 시스템을 볼 수 있도록 구독자 노드를 먼저 생성해 보겠습니다.
3. 구독자 노드 작성하기
구독자 노드를 생성하려면 ros2_ws/src/py_pubsub/py_pubsub
로 돌아갑니다 . 터미널에 다음 코드를 입력하십시오.
Copy wget https://raw.githubusercontent.com/ros2/examples/humble/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py
이제 디렉토리에 다음 파일이 있어야 합니다.
Copy __init__.py publisher_member_function.py subscriber_member_function.py
3.1 코드 검토
subscriber_member_function.py을
텍스트 편집기로 를 엽니다.
Copy import rclpy
from rclpy.node import Node
from std_msgs.msg import String
class MinimalSubscriber(Node):
def __init__(self):
super().__init__('minimal_subscriber')
self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
self.subscription # prevent unused variable warning
def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
def main(args=None):
rclpy.init(args=args)
minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
# Destroy the node explicitly
# (optional - otherwise it will be done automatically
# when the garbage collector destroys the node object)
minimal_subscriber.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
구독자 노드의 코드는 게시자의 코드와 거의 동일합니다. 생성자는 게시자와 동일한 인수를 사용하여 구독자를 만듭니다. 주제 자습서 에서 게시자와 구독자가 사용하는 주제 이름과 메시지 유형이 서로 통신할 수 있도록 일치해야 한다는 점을 상기하십시오.
Copy self.subscription = self.create_subscription(
String,
'topic',
self.listener_callback,
10)
구독자의 생성자와 콜백에는 타이머 정의가 필요하지 않기 때문에 타이머 정의가 포함되어 있지 않습니다. 콜백은 메시지를 받자마자 호출됩니다.
콜백 정의는 수신한 데이터와 함께 정보 메시지를 콘솔에 간단히 인쇄합니다. 게시자가 정의하는 것을 기억하십시오.msg.data = 'Hello World: %d' % self.i
Copy def listener_callback(self, msg):
self.get_logger().info('I heard: "%s"' % msg.data)
정의 main
은 거의 동일하며 게시자의 생성 및 spin 대상을 구독자로 대체합니다.
Copy minimal_subscriber = MinimalSubscriber()
rclpy.spin(minimal_subscriber)
이 노드는 게시자와 동일한 종속성을 가지므로 package.xml
에 새로 추가할 항목이 없습니다. 파일 setup.cfg
은 그대로 유지될 수도 있습니다.
3.2 진입점 추가
게시자의 진입점 아래에 구독자 노드에 대한 진입점을 setup.py를
다시 열고 추가합니다. 이제 필드 entry_points
는 다음과 같이 표시됩니다.
Copy entry_points={
'console_scripts': [
'talker = py_pubsub.publisher_member_function:main',
'listener = py_pubsub.subscriber_member_function:main',
],
},
파일을 저장했는지 확인하면 게시/구독 시스템이 준비 완료됩니다.
4. 빌드 및 실행
ROS2 시스템의 일부로 이미 rclpy
및 패키지가 설치되어 있을 수 있습니다. 작업 공간의 루트(ros2_ws
)에서 rosdep
를 실행하여 빌드하기 전에 누락된 종속성을 확인하는 것이 좋습니다.
Copy rosdep install -i --from-path src --rosdistro humble -y
작업 공간의 루트ros2_ws
에서 새 패키지를 빌드합니다.
Copy colcon build --packages-select py_pubsub
새 터미널을 열고 ros2_ws
로 이동하여 설정 파일을 소싱합니다.
Copy source install/setup.bash
이제 talker 노드를 실행합니다.
Copy ros2 run py_pubsub talker
터미널은 다음과 같이 0.5초마다 정보 메시지 게시를 시작해야 합니다.
Copy [INFO] [minimal_publisher]: Publishing: "Hello World: 0"
[INFO] [minimal_publisher]: Publishing: "Hello World: 1"
[INFO] [minimal_publisher]: Publishing: "Hello World: 2"
[INFO] [minimal_publisher]: Publishing: "Hello World: 3"
[INFO] [minimal_publisher]: Publishing: "Hello World: 4"
...
다른 터미널을 열고 ros2_ws
내부에서 설정 파일을 다시 소싱한 다음 리스너 노드를 시작합니다.
Copy ros2 run py_pubsub listener
리스너는 다음과 같이 해당 시점에 게시자가 사용 중인 메시지 수부터 시작하여 콘솔에 메시지 인쇄를 시작합니다.
Copy [INFO] [minimal_subscriber]: I heard: "Hello World: 10"
[INFO] [minimal_subscriber]: I heard: "Hello World: 11"
[INFO] [minimal_subscriber]: I heard: "Hello World: 12"
[INFO] [minimal_subscriber]: I heard: "Hello World: 13"
[INFO] [minimal_subscriber]: I heard: "Hello World: 14"
실행이 완료되면 노드가 더이상 spin 하지 않도록 각 터미널에 Ctrl+C
입력하십시오.