ROS 환경에서 2개 이상의 node는 topic을 통해 통신을 하게 된다. 이때 Topic을 발행하는 쪽이publisher, 이를 수령하는 쪽이 Subscriber의 역할을 한다. 간단하게 tutorial로 준 talker, listener node의 동작을 본다.
좌측 상단이 talker, 우측 상단이 listener
위 화면을 보면 talker node에서 listener node로 /chatter라는 이름의 topic을 전달하는 것을 확인할 수 있다. 현재 시행되는 node, topic은 아래 명령들로 확인이 가능하다.
rosnode list # node
rostopic list # topic
rostopic info *topic_name* #t opic and node info
rqt_graph # graphical analysis
rostopic echo *topic_name* # display topic contents on terminal
같은 방식으로 turtlesim에서 시도해본다.
위에서 볼 수 있듯이 node는 turtlesim과 draw_square 두 개가 켜져있다.
turtlesim node는 graphical interface를 표출해주는 node이며 draw_square는 turtlesim node를 실제적으로 움직이는 node이다. 서로 주고받는 topic은 아래와 같다.
turtlesim에서 draw_square에 보내는 topic /turtle1/pose는 turtlesim/Pose
draw_square에서 turtlesim에 보내는 topic /turtle1/cmd_vel는 geometry_msgs/Twist
draw_square는 turtlesim의 현재 위치와 orientation에 대한 정보를 받아와서 turtlesim에 다음 방향의 각도와 속도 정보를 발행한다.
Publisher
turtlesim의 거북이가 원형으로 돌게 만드는 node를 만들어본다.
다시 my_robot_pkg/scripts에 새로운 python 파일을 생성하고 아래와 같은 코드를 작성한다.
#!/usr/bin/env python3
import rospy
from geometry_msgs.msg import Twist
def main():
# pub = rospy.Publisher("name_of_topic", type of data, queue size)
pub = rospy.Publisher(**"/turtle1/cmd_vel"**, Twist, queue_size=10)
rate = rospy.Rate(5)
while not rospy.is_shutdown():
# write message to publish
msg = Twist() # this is a Twist object
msg.linear.x = 2.0
msg.angular.z = 1.0
# publish the message
pub.publish(msg)
rate.sleep()
if __name__=='__main__':
rospy.init_node("draw_circle")
rospy.loginfo("circle node init")
main()
여기서 주목할 부분이 몇 가지 있다.
line 7: Publisher에서 발행하는 topic의 이름을 정확히 맞춰주어야 한다. turtlesim 노드는 /turtle1/cmd_vel을 받으므로 이와 동일하게 설정한다.
추가적으로 이 topic의 type은 /geometry_msgs_Twist이므로 이도 지정해준다.
line 3: 위 내용과 연관되어 message의 형식을 정할 때는 그 형식의 라이브러리를 불러줘야 하며 이렇게 import한 package는 package.xml에 바로 추가해준다.
위 node를 turtlesim과 함께 실행하면 다음과 같은 결과를 볼 수 있다.
rqt graph로 봐도 이제 앞에서 draw circle node가 cmd_vel을 보내주는 것을 알 수 있다.
Subscriber
이제 Subscriber를 만들 것이다. 동일하게 turtlesim을 이용할건데 아무도 subscribe 하지 않고 있는 /turtle1/pose를 사용해본다. 확인하는 김에 데이터 모양도 같이 살펴봤다.
이제 subscriber 코드를 작성한다. 동일한 폴더에 새로 파일을 만든다.
#!/usr/bin/env python3
from math import sqrt
import rospy
from turtlesim.msg import Pose
def pose_callback(msg: Pose):
rospy.loginfo(msg)
sum = msg.x + msg.y
rospy.loginfo("sum : "+ str(sum))
def main():
# we need callback function!!!
sub = rospy.Subscriber("/turtle1/pose", Pose, callback = pose_callback)
if __name__=='__main__':
rospy.init_node("turtle_subscriber")
rospy.loginfo("subscriber node init")
main()
rospy.spin() # kind of infinite loop
# more passive than actual loop
line 7 : Publisher 때와 동일하게 읽을 topic의 이름을 정확히 일치시키고 읽은 message의 type도 맞춰줘야 한다.
*callback : 매우 중요하다!
line 21 : rospy.spin()은 callback 루프를 시행시켜주는 아주 중요한 아이이다.
실행 결과와 rqt 화면은 아래와 같다.