ROS - helloworld_publisher & _subscriber.py

남생이·2024년 10월 21일

ROS

목록 보기
26/28

1. Publish.py

  • 토픽에 msg를 발행하는 코드는 노드 생성, msg 정의, 발행 파트로 나누어 구조화할 수 있습니다.
  • 아래에서는 보다 자세하게 나누어 핵심적인 파트로 설명하겠습니다.

'Hellow World: [count]` 형식의 메시지 0.5초마다 'topic'이라는 토픽으로 발행하는 간단한 ROS2 Publisher 노드를 정의하고 실행

1.1 package & module import

import rclpy
from rclpy.node import Node
from std_msgs.msg import String
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSHistoryPolicy, QoSDurabilityPolicy
  • 필수 파트
    - rclpy, rclcpp
    - rclpy.node 모듈에서 Node
    - 사용하는 msg type 임포트 필수
  • 선택 파트
    - QoS 프로파일 임포트
    • 이외 참조할 파일 및 소스 코드 임포트

1.2 QoS 설정

qos_profile = QoSProfile(
    reliability=QoSReliabilityPolicy.RELIABLE,
    history=QoSHistoryPolicy.KEEP_LAST,
    depth=10,
    durability=QoSDurabilityPolicy.VOLATILE
)
  • QoSProfile: 메시지의 신뢰성, 히스토리, 깊이, 지속성 등을 설정
  • QoS 설정은 class, main 함수 이전에 정의하여 수정에 용이하도록 한다.
  • https://velog.io/@rlwnd0122/ROS-16-QoS

1.3 class 정의

class MinimalPublisher(Node): 
	def __init__(self):
    	super().__init__('minimal_publisher')
        self.publisher_=self.create_publisher(String, 'topic', qos_profile=qos_profile)
        timer_period = 0.5
        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
  • class <class_name>(Node) : Node 클래스를 상속받아 ROS2 노드를 정의
  • def __init__(self): : 생성자, 클래스의 초기화 및 속성 작업
    • super().__init__('<node_name>)
      : 클래스의 부모 클래스 Node의 메서드에 접근 후 생성자 호출, 노드의 이름 설정
    • self.publisher_=self.create_publisher(<msg_type>,<topic_name>,<QoSProfile>)
      : 메시지 발행을 위한 Publisher 생성
    • self_timer = self.create_timer(<period>, <callback_function>)
      : 주기마다 callback 함수를 호출하는 타이머를 설정

  • def timer_callback(self): : 타이머에 의해 주기적으로 호출되는 함수 정의
    • msg = <msg_type> : 메시지 형식, 타입을 정의, 외부 파일을 호출하여 정의 가능
    • msg.data = 'string...' % self.i : 메시지의 형식을 생성
    • self.publisher_.publish(msg): 위에서 정의한 형식의 메시지를 발행
    • self.get_logger.info(): 해당 메시지를 로깅하여 화면에 출력

1.4 main 함수

def main(args=None):
    rclpy.init(args=args) # ros2 초기화

    minimal_publisher = MinimalPublisher() # minimalpublisher 클래스 인스턴스화

    rclpy.spin(minimal_publisher) # 노드실행 및 이벤트 루프 시작
    minimal_publisher.destroy_node()
    rclpy.shutdown() # ros2 종료
  • def main(args=None): : args라는 인자를 선택하지 않으면 None 값이 사용
    • rclpy.init(args=args) : ROS2 초기화
    • <node_name> = <class_name>(): 클래스 인스턴스 생성
    • rclpy.spin(<node_name>): 노드 실행 및 이벤트 루프 시작
    • <node_name>.destroy_node() : 노드 종료
    • rclpy.shutdown() : ROS2 종료

1.5 main 실행

if __name__ == '__main__':
    main()
  • 스크립트가 직접 실행되면 main() 함수를 호출하여 모든 로직을 시작

2. Subcriber.py

2.1 package & module import

2.2 QoS 설정

  • 2.1, 2.2는 Publisher 코드와 동일하거나 QoS설정은 수정할 수 있음

2.3 class 정의

class MinimalSubscriber(Node):

    def __init__(self):
        super().__init__('minimal_subscriber')
        self.subscription = self.create_subscription(
            String,
            'topic',
            self.listener_callback,
            qos_profile=qos_profile) # 토픽에서 string 메시지를 구독하는 구독자 생성
        self.subscription  # prevent unused variable warning
  • class MinimalSubscriber(Node): Node 클래스를 상속받아 ROS2 노드를 정의

    • super().__init__(<node_name): 노드 초기화 및 노드 생성

    • self.subscription = self.create_subscription(<msg_type, <topic_name>,callback_function, <QoSProfile>)
      : 주어진 토픽에 대한 구독자를 생성, msg가 토픽에 게시될 때마다 콜백함수가 호출

    • self.subscription : Python에서는 정의한 변수가 사용되지 않을 경우 "unused variable" 경고가 발생할 수 있다. 이 코드를 추가하여 변수 사용을 인식시켜 경고 발생을 방지한다.

callback 함수

def listener_callback(self, msg):
        self.get_logger().info('I heard: "%s"' % msg.data)    

- 토픽에 게시된 메시지를 수신할 때 호출되는 콜백함수
- 수신된 메시지의 내용을 로그에 기록

2.4 main 함수

    rclpy.init(args=args)

    minimal_subscriber = MinimalSubscriber()

    rclpy.spin(minimal_subscriber)

    # Destroy the node explicitly
    minimal_subscriber.destroy_node()
    rclpy.shutdown()
  • subcriber 인스턴스를 생성한다는 점을 제외하면 publisher 코드와 동일

2.5 main 실행

동일

3. 핵심 내용

  • 토픽으로 msg를 발행, 구독하기 위해서는 2개의 코드에서 같은 노드를 통해 통신하도록 설정
  • create_publisher, create_subscriber를 사용하여 각 객체를 생성
  • timer를 이용해서 주기적인 루프를 생성
  • msg의 타입, 객체 선언은 필수
publisherself.publisher_ = self.create_publisher(msg_type,topic_name,qos_profile=qos_profile)
subscriberself.subscription = self.create_subscription(msg_type,topic_name,callback_function,qos_profile=qos_profile)
profile
공부하는 거북이

0개의 댓글