이번 시간에는 turtlesim 노드에서 발행하는 거북이의 위치 정보를 구독(Subscribe)하여 화면에 출력하는 노드를 만들어 보겠습니다.
토픽(Topic) 분석
우선 우리가 구독할 토픽의 이름과 데이터 타입, 메시지를 확인해야 합니다.
토픽의 이름을 확인하기 위하여 turtlesim을 실행 합니다.
$ ros2 run turtlesim turtlesim_node
ros2 topic list 명령으로 토픽의 리스트를 보면 /turtle1/pose 토픽이 발행되고 있는 것을 볼 수 있습니다.
$ ros2 topic list
/parameter_events
/rosout
/turtle1/cmd_vel
/turtle1/color_sensor
/turtle1/pose
ros2 topic info 명령으로 토픽의 데이터 타입을 확인 합니다.
$ ros2 topic info /turtle1/pose
Type: turtlesim/msg/Pose
Publisher count: 1
Subscription count: 0
마지막으로 /turtlesim/msg/Pose의 메시지 데이터를 확인 합니다.
$ ros2 interface show turtlesim/msg/Pose
float32 x
float32 y
float32 theta
float32 linear_velocity
float32 angular_velocity
2차원 위치 값인 x, y와 거북이의 방향을 나타내는 theta 메시지와 직선 속도인 linear_velocity, 회전 속도인 angular_velocity 메시지의 데이터를 가지고 있다는 것을 알 수 있습니다.
ros2 topic echo /turtle1/pose 명령을 이용해서 실제 데이터 값을 확인해 봅니다.
$ ros2 topic echo /turtle1/pose
x: 5.544444561004639
y: 5.544444561004639
theta: 0.0
linear_velocity: 0.0
angular_velocity: 0.0
자, 이제 우리가 구독해야 할 토픽의 데이터 타입과 메시지 데이터에 대한 구조를 파악 했으니 본격적으로 Subscriber 노드를 작성해 보겠습니다.
코드 작성
my_robot_controller 패키지의 노드 디렉토리로 이동해 pose_subscriber.py 파일을 만들어 주고 실행 권한을 부여 합니다.
$ cd ~/ros2_ws/src/my_robot_controller/my_robot_controller
$ touch pose_subscriber.py
$ chmod +x pose_subscriber.py
vscode를 이용하여 코드를 작성 합니다.
#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from turtlesim.msg import Pose
class PoseSubscriberNode(Node):
def __init__(self):
super().__init__("pose_subscriberd")
self.pose_subscriber_ = self.create_subscription(Pose, "/turtle1/pose", self.pose_callback, 10)
def pose_callback(self, msg: Pose):
self.get_logger().info(str(msg))
def main(args=None):
rclpy.init(args=args)
node = PoseSubscriberNode()
rclpy.spin(node)
rclpy.shutdown()
코드 분석
우선 프로그램에서 사용할 의존성 dj패키지를 import 합니다.
import rclpy
from rclpy.node import Node
from turtlesim.msg import Pose
기본적인 main() 함수 구조 입니다.
def main(args=None):
rclpy.init(args=args)
# 노드 생성 및 실행
node = PoseSubscriberNode()
rclpy.spin(node)
rclpy.shutdown()
PoseSubscriberNode() 클래스 생성자를 이용하여 node 객체를 생성 하였습니다.
class PoseSubscriberNode(Node):
def __init__(self):
super().__init__("pose_subscriberd")
self.pose_subscriber_ = self.create_subscription(Pose, "/turtle1/pose", self.pose_callback, 10)
__init__ 생성자로 "pose_subscriber" 라는 이름의 구독자 노드를 초기화 합니다.
다음으로 create_subscription 이라는 메소드를 이용하여 구독자 노드를 생성 합니다. 여기서 매개변수는 첫번째로 구독할 토픽의 데이터 타입, 두번째로 토픽명,, 세번째는 역시 콜백 함수 입니다.
우리는 Pose 데이터 타입의 /turtle1/pose 토픽을 구독할 것이고 토픽을 구독할 때 마다 pose_callback 이라는 콜백 함수를 기동시킬 것입니다.
def pose_callback(self, msg: Pose):
self.get_logger().info(str(msg))
콜백 함수에서는 단지 전달된 Pose 메시지를 출력 합니다.
entry_point 추가
노드 프로그램을 실행하기에 앞서 setup.py에entry_point를 추가해 줍니다.
entry_points={
'console_scripts': [
"test_node = my_robot_controller.my_first_node:main",
"draw_circle = my_robot_controller.draw_circle:main",
"pose_subscriber = my_robot_controller.pose_subscriber:main"
],
실행 노드 이름은 pose_subscriber, 패키지 이름은 my_robot_controller, 노드 파일명은 pose_subscriber, 마지막으로 실행 함수인 main을 적어 줍니다.
빌드
이제 우리가 작성한 새로운 노드 pose_subscriber.py 프로그램을 빌드해 봅시다.
$ colcon build --symlink-install
Finished <<< my_robot_controller [1.09s]
Summary: 1 packages finished [1.26s]
에러 없이 빌드가 잘 수행 되었습니다.
실행
환경 소싱 후 터미널에서 turtlesim 노드를 실행 합니다.
$ ros2 run turtlesim turtlesim_node
새로운 터미널을 열고 작업 환경 소싱 후 pose_subscriber 노드를 실행 합니다.
$ . ~/ros2_ws/install/setup.bash
$ ros2 run my_robot_controller pose_subscriber
INFO] [1687244208.760672961] [pose_subscriber]: turtlesim.msg.Pose(x=5.544444561004639, y=5.544444561004639, theta=0.0, linear_velocity=0.0, angular_velocity=0.0)
[INFO] [1687244208.777618960] [pose_subscriber]: turtlesim.msg.Pose(x=5.544444561004639, y=5.544444561004639, theta=0.0, linear_velocity=0.0, angular_velocity=0.0)
[INFO] [1687244208.793083936] [pose_subscriber]: turtlesim.msg.Pose(x=5.544444561004639, y=5.544444561004639, theta=0.0, linear_velocity=0.0, angular_velocity=0.0)
거북이의 현재 Pose 정보를 가져오는 걸 볼 수 있습니다. 이제 turtlesim 거북이를 움직이면서 포지션 정보가 변하는지 확인해 보겠습니다.
$ ros2 run my_robot_controller pose_subscriber
[INFO] [1687244285.448426297] [pose_subscriber]: turtlesim.msg.Pose(x=4.946533679962158, y=9.457897186279297, theta=-2.854370594024658, linear_velocity=2.0, angular_velocity=1.0)
[INFO] [1687244285.465325357] [pose_subscriber]: turtlesim.msg.Pose(x=4.915993690490723, y=9.448342323303223, theta=-2.8383705615997314, linear_velocity=2.0, angular_velocity=1.0)
[INFO] [1687244285.480438606] [pose_subscriber]: turtlesim.msg.Pose(x=4.885610103607178, y=9.438300132751465, theta=-2.8223705291748047, linear_velocity=2.0, angular_velocity=1.0)
Pose 정보가 변하는 걸 볼 수 있습니다. 이제 rqt_graph 명령으로 노드와 토픽의 관계를 살펴 보겠습니다.
/draw_circle 노드에서 발행된 /turtle1/cmd_vel 토픽이 /turtlesim 노드에 전달되고 변경된 /turtle1/pose 토픽이 /pose_subscriber 노드에 전달되는 것을 볼 수 있습니다.
Last updated