Embedded/ROS

ROS2 - (5) Python을 이용한 Topic, Service 구현

잇(IT) 2024. 9. 24. 13:03

ROS2는 python을 공식 지원하며 Jupyter를 이용하여 python으로 Topic에 접근해 볼 것이다.

(Uubuntu Jupyter 설치의 경우 구글에 많이 나와있으니 찾아보길 바랍니다.)


Python으로 Topic 접근 코드 예제 결과

 

특정 범위 안에서 거북이가 random하게 움직이는 시뮬레이션


Topic

 

Topic 구독 코드 작성

 

터미널에서 turtlesim_node를 실행하고, ROS2를 실행한 후 VS-Code를 실행한다.

 

 

jupyter notebook을 통해 아래 코드를 입력하고 실행 시킨다.

import rclpy as rp
from turtlesim.msg import Pose

첫째 라인의 rclpy(ROS Client Library for Python)라는 ROS2를 Python에서 사용할 수 있게 해주는 Module을 rp라는 이름으로 import 한다.

둘째 라인은 Subscribe하고자 하는 Topic인 /turtle1/pose의 type을 참고하여 turtlesim/msg/Pose에서 Pose를 사용할 수 있도록 import 해준다.

 

rp.init()
test_node = rp.create_node('First')

rclpy 초기화 및 해당 라이브러리의 create_node() 메서드를 이용하여 'First'라는 이름의 노드를 생성하고 test_node로 객체화 한다.

 

position_x = 0.0
position_y = 0.0

def pose_callback(data) :
        global position_x, position_y
        position_x = data.x
        position_y = data.y
        
        print("X : ", data.x)
        print("X : ", position_x)
        print("Y : ", data.y)
        print("Y : ", position_y)
        print("Theta : ", data.theta)

Topic을 수신할 때 마다 실행하는 메서드는 callback()이다.

Topic 수신 시 처리할 내용은 callback() 메서드에 작성하여 사용한다.

위 코드는 파라미터로 넘어온 data의 x, y값을 position_x,y에 넣고, print를 통해 출력하는 함수에 해당한다.

 

test_node.create_subscription(Pose, '/turtle1/pose', pose_callback, 10)

Python 코드로 생성한 Node인 test_node에서 Subscription을 생성한다.

위 코드는 Subscription을 생성하는 코드이며 Subscription을 실행하는 코드는 아니다.

 

 

위와 같이 Topic과 Subscription을 생성하게 되면 rqt를 통해 GUI로 각 Node의 관계를 파악할 수 있다.

/turtlesim 노드에서 /turtle1/pose 토픽으로 message를 날리게 되면 /First_Day_try 노드에서 해당 message를 읽는 구조에 해당한다.

 

rp.spin_once(test_node)
///
rp.spin(test_node)

rp.spin_once를 통해 Topic을 한번만 구독할 수 있고, spin을 통해 계속해서 Topic을 구독할 수 있다.


Topic 발행 코드 작성

Twist의 형태를 가지는 msg 객체를 생성 후 내용을 출력한다.

msg에 linear, angular 데이터가 존재하고 다시 x, y, z값이 존재함을 확인할 수 있다.

 

msg 내부 데이터를 변경한 후 실행하게 되면 데이터가 변경된 것을 확인할 수 있다.

Topic을 발행하는 코드를 작성하고, 발행하게 되면 아래와 같이 거북이가 변경된 데이터에 따라 움직이는 것을 확인할 수 있다.

Topic 발행코드까지 작성하게 되면 위와 같은 관계를 가지는 것을 확인할 수 있다.


Service

 

Service Client 코드 작성

rclpy 초기화 및 해당 라이브러리의 create_node() 메서드를 이용하여 service_test라는 이름의 노드를 생성한다.

추가로 service 패키지에서 TeleportAbsolute 서비스 import한다. 

 

/turtle1/teleport_absolute의 서비스를 이용할 것이기 때문에 변수에 저장하여 create_client() 메서드를 통해 Client를 생성하고 cli_T라는 객체를 생성한다.

 

Service Client가 Request에서 사용할 데이터 객체 생성 및 초기값을 확인한다.

 

Request의 값을 변경하고 값을 확인한다.

 

 

Service call을 실행하는 방법에는 아래와 같이 3가지가 있다.

 

cli_T.call_async(req)
rp.spin_once(test_node)

단순하게 실행하는 방법이다.

* 하지만 위 방법은 노드가 실행되어 있지 않은 상황에서도 실행되기 때문에 에러가 발생할 수 있다.

 

# while not cli.wait_for_service(timeout_sec=1.0) :
#     print("Waiting for service...")

# cli_T.call_async(req)
# rp.spin_once(test_node)

두번째 방법은 Service Server가 실행될 때까지 기다렸다가 Service Server가 실행되는 것이 확인되면 실행하는 방법이다.

 

# future = cli_T.call_async(req)

# while not future.done() :
#     rp.spin_once(test_node)
#     print(future.done(), future.result())

세번째 방법은 요청한 Request에 대해 수행되었다는 Response가 도착할 때 까지 반복문을 계속해서 실행하게 된다.

Service Client 호출 후의 상황을 알려줄 때 사용한다.

 

Service에 의해 움직인 거북이 모습을 확인할 수 있다.

728x90