[rospy tutorial] 간단한 Publisher와 Subscriber 작성하기
1. 개발환경 및 서론
필자는 rpi 3 B+에 우분투 서버 20.04와 ROS noetic을 설치했다.
https://upgrade-sechan.tistory.com/23
[ROS] rpi에 ROS noetic 설치하기
1. 개발환경 개발환경은 이전에 포스팅했던 내용과 같다. 필자는 rpi 3 B+, 우분투 서버 20.04의 개발환경을 사용한다. https://upgrade-sechan.tistory.com/22 [ROS] rpi에 Ubuntu server 20.04 설치 & 와이파이..
upgrade-sechan.tistory.com
이번 포스팅에서는 ROS.org에 있는 튜토리얼을 따라 해보려 한다.
http://wiki.ros.org/rospy_tutorials/Tutorials/WritingPublisherSubscriber
rospy_tutorials/Tutorials/WritingPublisherSubscriber - ROS Wiki
Please ask about problems and questions regarding this tutorial on answers.ros.org. Don't forget to include in your question the link to this page, the versions of your OS & ROS, and also add appropriate tags. Writing a Simple Publisher and Subscriber Desc
wiki.ros.org
2. workspace 및 패키지 생성
~/catkin_ws/src 디렉터리로 이동해서 beginner_tutorials 패키지를 생성한다. (이때, catkin_ws 디렉터리가 없다면 새로 만들어준다.)
cd ~/catkin_ws/src
catkin_create_pkg beginner_tutorials std_msgs rospy roscpp
beginner_tutorials 디렉터리로 이동해서 src 디렉터리를 생성한다.
roscd beginner_tutorials
mkdir src
cd src
3. 소스코드 다운로드
src 디렉터리에 talker.py 소스코드를 다운받는다.
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/talker.py
chmod +x talker.py
src 디렉터리에 listener.py 소스코드를 다운받는다.
wget https://raw.github.com/ros/ros_tutorials/kinetic-devel/rospy_tutorials/001_talker_listener/listener.py
chmod +x listener.py
4. 소스코드 해석
1) talker.py
talker.py의 소스코드는 다음과 같다.
#!/usr/bin/env python
# license removed for brevity
import rospy
from std_msgs.msg import String
def talker():
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
rate = rospy.Rate(10) # 10hz
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
if __name__ == '__main__':
try:
talker()
except rospy.ROSInterruptException:
pass
이제 한 줄씩 코드를 분석해보자.
#!/usr/bin/env python
ROS의 모든 파이썬 파일은 가장 먼저 이 주석을 작성해야 한다.
import rospy
from std_msgs.msg import String
ROS의 노드를 작성하기 위해서는 rospy가 필요하다.
string 자료형의 메시지를 publish 하기 위해서는 String을 import 해야 한다.
pub = rospy.Publisher('chatter', String, queue_size=10)
rospy.init_node('talker', anonymous=True)
pub에서는 talker의 인터페이스를 정의한다. 이때 3개의 인자가 필요하다.
- topic의 이름 : chatter라는 이름으로 topic을 publish한다.
- 자료형 : 앞에서 import한 String 자료형을 사용한다.
- queue_size : subscriber가 수신하는 메세지의 크기를 제한한다.
rospy.init_node로 노드를 초기화하는데, 2개의 인자가 필요하다.
- 노드의 이름 : 여기서는 노드 이름을 talker로 한다.
- anonymous : True로 설정할 경우 노드 이름 뒤에 랜덤한 숫자를 추가한다.
rate = rospy.Rate(10) # 10hz
이 라인은 Rate 오브젝트를 생성한다. 이 오브젝트의 sleep() 메서드를 이용하면 우리가 원하는 주기로 프로그램을 실행시킬 수 있다. 이 프로그램은 0.1초도 걸리지 않으므로 1초에 10번 프로그램을 실행하기에 충분하다.
while not rospy.is_shutdown():
hello_str = "hello world %s" % rospy.get_time()
rospy.loginfo(hello_str)
pub.publish(hello_str)
rate.sleep()
rospy.is_shutdown()을 통해 프로그램이 종료되었는지 확인할 수 있다.
pub.publish는 chatter이라는 topic에 string을 publish하는 것이다.
rate.sleep에서는 프로그램 주기가 설정한 값이 되도록 하기 위해 대기한다.
rospy.loginfo는 screen, 노드의 log file, rosout에 string을 출력한다.
try:
talker()
except rospy.ROSInterruptException:
pass
여기에서는 rospy.ROSInterruptException를 감지하는데, 그 이유는 sleep() 이후에 코드가 계속 실행되지 않게 하기 위함이다.
2) listener.py
listener.py의 소스코드는 다음과 같다.
#!/usr/bin/env python
import rospy
from std_msgs.msg import String
def callback(data):
rospy.loginfo(rospy.get_caller_id() + "I heard %s", data.data)
def listener():
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
rospy.spin()
if __name__ == '__main__':
listener()
listener.py는 talker.py와 유사하므로 아래의 소스코드만 설명한다.
rospy.init_node('listener', anonymous=True)
rospy.Subscriber("chatter", String, callback)
rospy.spin()
rospy.Subscriber는 chatter를 구독하고 메시지는 String 자료형을 사용한다. 새로운 매시지가 수신되면 callback 함수가 호출되고 인자로 메시지를 넘겨준다.
rospy.init_node를 통해 listener 노드를 생성하고, anoymous-True를 통해 유일한 이름이 되도록 노드 이름 뒤에 랜덤한 숫자를 붙여준다. 만약 이름이 유일하지 않은 상황에서 노드가 실행된다면 이전에 실행되던 이름이 같은 노드와 충돌을 일으킨다. 따라서 여러 개의 listener 노드를 실행시키기 위해서 노드의 이름이 유일하도록 해주어야 한다.
rospy.spin()은 프로그램이 종료될 때까지 노드가 실행되도록 유지하는 역할을 한다.
5. 노드 실행
작성한 프로그램이 제대로 작동이 되는지 확인하기 위해서 빌드를 하고
catkin build
3개의 서로 다른 터미널에서 아래의 명령을 각각 실행한다.
roscore
rosrun beginner_tutorials talker.py
rosrun beginner_tutorials listener.py
talker를 실행한 터미널에서는 다음과 같은 결과가 출력된다.
[INFO] [WallTime: 1394915011.927728] hello world 1394915011.9 [INFO] [WallTime: 1394915012.027887] hello world 1394915012.0 [INFO] [WallTime: 1394915012.127884] hello world 1394915012.1 [INFO] [WallTime: 1394915012.227858] hello world 1394915012.23 ... |
listener를 실행한 터미널에서는 다음과 같은 결과가 출력된다.
[INFO] [WallTime: 1394915043.555022] /listener_9056_1394915043253I heard hello world 1394915043.55 [INFO] [WallTime: 1394915043.654982] /listener_9056_1394915043253I heard hello world 1394915043.65 [INFO] [WallTime: 1394915043.754936] /listener_9056_1394915043253I heard hello world 1394915043.75 [INFO] [WallTime: 1394915043.854918] /listener_9056_1394915043253I heard hello world 1394915043.85 ... |
chatter의 topic을 확인하기 위해 이래의 명령어를 사용한다.
rostopic echo chatter
data: hello world 1394915083.35 --- data: hello world 1394915083.45 --- data: hello world 1394915083.55 --- data: hello world 1394915083.65 --- data: hello world 1394915083.75 --- ... |
축하한다. 이번 튜토리얼은 여기까지다.