PinkLAB - 민형기 ROS2 응용 실습 5일차 - 2개 이상의 토픽 다루기 실습

안상훈·2024년 8월 18일
0

ROS2 실습

목록 보기
9/13
post-thumbnail

본 블로그 포스팅은 https://www.youtube.com/@pinklab_studio/playlists
에서 현재 강의 중에 있는

ROS2 무작정 따라하기강의의 내용을 필자가 다시 복기하여 기록하는 내용에 관한 것이다.


1. 작업개요

그간 다른공부를 좀 하느라 두달 가까이 ROS2 무작정 따라하기포스팅이 밀렸고 다시 시리즈를 이어서 복기를 하려니 조금 헤멘 감이 있었다.

역시 공부는 끊기면 안된다.
기존 내용을 다시 복기한 후 마지막 영상이
2-4.내가 정의한 메세지 사용해보기까지 진행했었고

이번 실습 파트는 2-5, 2-6에 관한 내용이다.

실습내용을 요약하면 아래와 같다.

  1. 신규 패키지 my_second_package 생성

기존 my_first_package에 신규 노드(파이선파일)을 추가하는 것보다는 포스팅 텀이 길어졌기에 신규 패키지 my_second_package를 새로 생성해서

해당 패키지 내 실습 목표일 2종 이상의 토픽 핸들링 노드 작성을 수행한다.

  1. 2종 이상의 토픽 핸들링

Subscriber : /turtel1/pose, /turtle1/cmd_vel 2개의 토픽을 수신

custom_msg : 커스텀 메세지 CmdAndPosVelSubscriber로 수신한 메세지 정보를 전달하는데

1) 단순 print : my_second_node.py에서는 CmdAndPosVel에 저장된 정보를 단순히 print

2) 별도 토픽으로 Publish : my_sec_subpub.py에서는 CmdAndPosVel에 저장된 정보를 1.0 sec 단위로 /cmd_and_pos_vel토픽 명으로 Publish


2.신규 패키지 생성

my_second_package패키지의 생성은 이전 포스트 PinkLAB - 민형기 ROS2 응용 실습 1일차 - 패키지 만들기 를 참조하여
./[ROS_Workspace]/src폴더에서 아래의 명령어 수행을 통해 패키지 생성을 진행한다

$ ros2 pkg create --build-type ament_python --node-name my_second_node my_second_pkg --license Apache-2.0 

pkg create의 옵션별 설명은 아래와 같다.

1) --build-type : ROS2의 Python기반 패키지 생성 ament_python
2) --node-name : 생성할 패키지 안에 기본 노드를 하나 만듬 my_second_node로 노드를 하나 만들며, 해당 노드와 매칭되는 my_second_node.py파일이 자동 생성됨

3) --license : 패키지의 라이센스를 지정안하면 waring 메세지가 출력됨, 지정 가능한 옵션은 아래와 같다.

생성한 패키지 my_second_package에는 --node-name옵션으로 기본 노드파이썬 파일 my_second_node.py이 자동생성 및 등록되고 두번째 실습용 노드 파이썬 파일인 my_sec_subpub.py는 새로 생성해야 하며, 패키지 관리파일인 setup.py에 신규 노드로 등록을 해줘야 한다.


3. my_second_node.py

/turtel1/pose, /turtle1/cmd_vel 두개의 토픽을 수신받아서 데이터를 처리한 뒤

커스텀 메세지 CmdAndPosVel으로 처리된 데이터를 저장하고, 이를 단순 print하는 코드를 작성한다.

라이브러리 import

import rclpy as rp #ros2 사용을 위한 python 라이브러리
from rclpy.node import Node #ros2에서 노드 작성시 필요한 라이브러리

# ros2 run turtlesim turtlesim_node 터틀심 노드 구동
# ros2 topic list 터틀심 노드 구동 후 Pub/Sub토픽 리스트 확인
# Sub할 토픽 항목 : /turtle1/pose, /turtle1/cmd_vel

# 각 항목별 토픽의 메세지 타입 확인하기
# ros2 topic type /turtle1/pose : turtlesim/msg/Pose
# ros2 topic type /turtle1/cmd_vel : geometry_msgs/msg/Twist
from turtlesim.msg import Pose
from geometry_msgs.msg import Twist

# 임의 커스텀 메세지 : my_first_package_msgs의 커스텀 메세지
from my_first_package_msgs.msg import CmdAndPosVel

라이브러리는 크게 ROS2-Python을 사용하기 위한
rclpy, rclpy.node 라이브러리

그리고 나머지 3개는 메세지타입을 다루기 위한 라이브러리 이다.

이때 어떤 메세지를 사용해야 할 지?
에 대한것은 주석으로 메세지를 찾는 명령어를 주석으로 달았다.


main 구문

def main(args=None):
    rp.init(args=args) #ros2 노드 초기화 + 명령줄 구문으로 node조정이 가능함

    #클래스 SecondNode의 설계도에 맞춰 `my_second_node`를 인스턴스화
    my_second_node = SecondNode() 
    rp.spin(my_second_node) #객체 `my_second_node`를 반복 호출

    #키보드 인터럽트(ctrl+c)들어오면 아래 명령 수행됨
    my_second_node.destroy_node() #노드 삭제 및 노드 기능 종료
    rp.shutdown()

if __name__ == '__main__':
    main() # main 함수 구동

main 함수는 ros2 Node에 대한 초기화 / 구동방식 / 종료 방법에 관한 코드를 포함한다

여기서 rp.init(args=args)는 ROS 2 노드를 초기화하면서, 노드가 커맨드 라인에서 전달된 인자를 받아들여 실행 중에 해당 인자에 따라 노드의 동작을 조정할 수 있도록 설정하는 역할을 한다.


노드의 구동방식(설계도) \rightarrow 클래스 설계 부

class SecondNode(Node): #클래스 SecondNode는 Node클래스를 상속함

    def __init__(self):
        super().__init__('my_second_node') #노드 이름명 정의
        self.sub_topic_1 = self.create_subscription(
            msg_type=Pose,
            topic= '/turtle1/pose',
            callback= self.callback_pose,
            qos_profile=10,
        )
        self.sub_topic_2 = self.create_subscription(
            msg_type=Twist,
            topic='/turtle1/cmd_vel',
            callback=self.callback_cmd_val,
            qos_profile=10
        )
        # 커스텀 메세지는 print용으로만 구현하기
        self.cmd_pos_val = CmdAndPosVel()

    # Pose의 메세지 타입 내 인자 확인하기
    # ros2 interface show turtlesim/msg/Pose
    def callback_pose(self, msg):
        # 커스텀 메세지 CmdAndPosVel의 pose_x에 msg.x인자값 넘기기
        self.cmd_pos_val.pose_x = msg.x
        self.cmd_pos_val.pose_y = msg.y

        self.cmd_pos_val.linear_vel = msg.linear_velocity
        self.cmd_pos_val.angular_vel = msg.angular_velocity

    # Twist의 메세지 타입 내 인자 확인
    # ros2 interface show geometry_msgs/msg/Twist
    def callback_cmd_val(self, msg):
        self.cmd_pos_val.cmd_vel_linear = msg.linear.x
        self.cmd_pos_val.cmd_vel_angular = msg.angular.z

        print(self.cmd_pos_val) #입력받은 메세지 항목 전체 출력

노드의 작동 방식을 설계하는 것은 class를 통해 정의하며,
위 코드를 해석한다면

1) subscribertopic을 수신하는데 이때 2종의 topic를 수신한다.

topicQuality of Service (QoS) 정책은 Message queue10개로 제한하는 정책으로, 최신 10개의 메세지만을 히스토리에 유지해 통신 안정성과 성능을 보증한다.

2) 각각의 subscribertopic를 수신 시 정의한 callback function : callback_pose, callback_cmd_val을 호출하고

호출된콜백 함수는 수신받은 topic 메세지 내 인자값들을 추출 \rightarrow 사용자 정의 메세지 타입 CmdAndPosVel객체의 클래스 변수에 각각 데이터를 전달한다.


3.1 my_second_node.py 구동

패키지 빌드 + 등록

아래의 명령어를 신규 커맨드창을 열고 차례로 입력하여 수정한 my_second_pkg를 빌드하고 빌드한 package내 새로 생성된 node를 등록한다.

$ humble # -> 예전 포스팅에서 ros2활성화를 위해 등록한 커스텀 명령어
$ colcon build --packages-select my_second_pkg # `my_second_pkg` 패키지만 선택해서 빌드
$ r2pkgsetup # -> 예전 포스팅에서 변경된 패키지 정보를 현재 셀에서 인식 가능하게 등록


노드 구동

1) bash 1번 스크립트

$ humble
$ ros2 run turtlesim turtlesim_node #터틀심 노드 구동

2) bash 2번 스크립트

$ r2pkgsetup
$ ros2 run my_first_package my_publisher #터틀심 제어 퍼블리셔 구동

3) bash 3번 스크립트

$ r2pkgsetup
$ ros2 rum my_second_pkg my_second_node #실습목표 노드 구동


노드 구성 분석

1) bash 4번 스크립트

$ r2pkgsetup
$ ros2 topic list # 현재 실행중인 토픽 리스트 확인

2) bash 5번 스크립트

$ r2pkgsetup
$ rqt_graph #현재 구동중인 도드 간 연결 구성도 확인

총 3개의 노드 turtlesim_publisher, turtle1, my_second_node에서 각각의 메세지가 전달되는 구조를 확인할 수 있다.

이때 my_second_node는 실습 목표처럼 2개 이상의 topic을 구독중인 것을 확인할 수 있다.


4. my_sec_subpub.py

코드의 전체 구조는 3. my_second_node.py를 거의 따르며, 커스텀 메세지 CmdAndPosVel타입으로 /cmd_and_pos_vel토픽을 Publish하는 기능을 추가하는 것이기에 변경된 코드 부분만 하이라이트 하겠다.

class SecondNode(Node): #클래스 SecondNode는 Node클래스를 상속함

    def __init__(self):
        super().__init__('my_second_node') #노드 이름명 정의
        self.sub_topic_1 = self.create_subscription(
            msg_type=Pose,
            topic= '/turtle1/pose',
            callback= self.callback_pose,
            qos_profile=10,
        )
        self.sub_topic_2 = self.create_subscription(
            msg_type=Twist,
            topic='/turtle1/cmd_vel',
            callback=self.callback_cmd_val,
            qos_profile=10
        )
        # 커스텀 메세지를 퍼블리싱 하기
        self.pub_topic = self.create_publisher(
            msg_type=CmdAndPosVel,
            topic='/cmd_and_pos_vel',
            qos_profile=10
        )
        #타이머 형태로 퍼블리싱 하려고 타이머 주기 설정
        self.timer_period = 1.0 
        self.timer = self.create_timer(
            timer_period_sec=self.timer_period,
            callback=self.timer_callback,
        )
        self.cmd_pos_val = CmdAndPosVel() #Sub메세지를 여기에 담는다.

    # Pose의 메세지 타입 내 인자 확인하기
    # ros2 interface show turtlesim/msg/Pose
    def callback_pose(self, msg):
        # 커스텀 메세지 CmdAndPosVel의 pose_x에 msg.x인자값 넘기기
        self.cmd_pos_val.pose_x = msg.x
        self.cmd_pos_val.pose_y = msg.y

        self.cmd_pos_val.linear_vel = msg.linear_velocity
        self.cmd_pos_val.angular_vel = msg.angular_velocity

    # Twist의 메세지 타입 내 인자 확인
    # ros2 interface show geometry_msgs/msg/Twist
    def callback_cmd_val(self, msg):
        self.cmd_pos_val.cmd_vel_linear = msg.linear.x
        self.cmd_pos_val.cmd_vel_angular = msg.angular.z

    # 타이머 콜백 함수를 통해 커스텀 메시지 타입의 토픽을 발행
    def timer_callback(self):
        # self.cmd_pos_val여기에 있는 메세지 정보를 퍼블리싱해라
        self.pub_topic.publish(msg=self.cmd_pos_val)

기존의 클래스 설계도 SecondNode에서
토픽 퍼블리싱을 위한 기능 pub_topic
토픽 발행주기를 다루는 기능 timer
을 추가하고 timer콜백 함수 timer_callback에서 Publish를 수행한다.

설계한 신규노드 my_sec_subpub.py setup.py 수행

위 사진처럼 , '노드명' = 패키지명.파이썬파일명:main' 순으로 추가하면 된다.


4.1 my_sec_subpub.py 구동

패키지 빌드 + 등록

신규 노드 my_sec_subpub_nodemy_second_pkg에 신설했으니 아래의 명령어를 다시 수행한다.

$ humble # -> 예전 포스팅에서 ros2활성화를 위해 등록한 커스텀 명령어
$ colcon build --packages-select my_second_pkg # `my_second_pkg` 패키지만 선택해서 빌드
$ r2pkgsetup # -> 예전 포스팅에서 변경된 패키지 정보를 현재 셀에서 인식 가능하게 등록

노드 구동

1) bash 1번 스크립트

$ humble
$ ros2 run turtlesim turtlesim_node #터틀심 노드 구동

2) bash 2번 스크립트

$ r2pkgsetup
$ ros2 run my_first_package my_publisher #터틀심 제어 퍼블리셔 구동

3) bash 3번 스크립트

$ r2pkgsetup
$ ros2 rum my_second_pkg my_sec_subpub_node #실습목표 노드 구동

이번에는 print기능을 삭제하고 신규 토픽으로 퍼블리싱을 하는 것이기에 위 코드까지만 수행하면 구동이 잘 되고있는지 확인하기 어렵다.

4) bash 4번 스크립트

$ r2pkgsetup
$ ros2 topic list #신규 토픽이 발행중인지 확인하기

5) bash 5번 스크립트

$ r2pkgsetup
$ ros2 topic echo /cma_and_pos_vel #신규토픽 `/cmd_and_pos_vel` 메세지를 확인하기

위와 같이 신규 발행중인 토픽 : /cmd_and_pos_velecho옵션으로 디버그를 수행해야 제대로 발행되는지 여부를 확인할 수 있다.

rqt_graph 기능을 사용하면 신규 발행중인 토픽 : /cmd_and_pos_vel을 확인할 수 있다.



오랜만에 포스트를 다시 이어가려니 민형기교수님 진도가 많이 앞서나가고 있기에 빨리빨리 해야겠다....

profile
자율차 공부중

0개의 댓글

관련 채용 정보