Python을 이용한 ROS 개발 환경 구성 및 예제

2022. 7. 26. 02:24Ubuntu/ROS

이번 포스팅에서는 Python을 이용한 ROS 노드 작성 및 ROS 개발 환경 구성을 다룹니다.


Workspace 구성

우선 ROS 개발 환경(workspace)를 준비합니다. 통상적으로 많이 사용되는 이름인 catkin_ws로 설정해보겠습니다.

workspace는 통상적으로 catkin_ws라는 이름을 많이 사용하지만, 정해진 규칙은 없고 편한 이름으로 사용할 수 있습니다.

 

-p command는 parent의 약자로, 부모 디렉토리와 자식 디렉토리를 한번에 생성하라는 뜻입니다. 여기서는 catkin_ws가 부모 디렉토리, src가 자식 디렉토리가 되겠네요.

 

mkdir -p catkin_ws/src
cd ~/catkin_ws/src
catkin_init_workspace

cd .. #move to ~/catkin_ws directory
catkin_make
source devel/setup.bash

 

해당 과정을 수행하면 아래 터미널처럼 계층 구조가 만들어집니다.

 

tree 명령어를 이용한 계층 구조 조회 결과

 


Package 생성

cd ~/catkin_ws/src

catkin_create_pkg hello_ros rospy # creating package with rospy dependency

 

여기서 hello_ros는 만들고자 하는 패키지 이름이며, 뒤의 rospy는 만들고자 하는 패키지가 가지는 의존성 패키지를 의미합니다.

 

catkin_create_pkg my_first_package roscpp rospy std_msgs

 

위와 같이 패키지 이름 뒤에 의존성 패키지들을 열거하면 됩니다.

이럴 경우, 패키지 빌드와 관련된 내용들을 서술하는 CMakeLists.txt, package.xml 파일에 자동으로 의존성 패키지들이 기록되므로 편리합니다.

Python을 이용하여 개발하는 과정을 소개하고 있으므로, 우선 rospy만을 이용하여 패키지를 만들어 보겠습니다. 

 

 

다음으로 bashrc 파일에 해당 workspace를 등록해줍니다. bashrc 파일은 터미널이 실행될 때마다 실행되는 명령어들을 모아놓은 파일이라고 생각하시면 쉽습니다. 이 파일에 어떤 workspace를 주로 사용할 건지 명시하는 과정입니다.

 

시스템에 직접 설치한 패키지가 아닌, 사용자가 직접 workspace 내에 작성한 ROS 패키지의 경우, 해당 workspace의 devel/setup.bash 파일을 source 명령어를 통해 재실행 시켜주어야 패키지로 인식되며, 노드든 런치파일이든 수행할 수 있게 됩니다.

 

하지만 매번 source devel/setup.bash를 타이핑 하는 것은 매우 번거롭습니다. bashrc 파일 상에 alias(대체어)를 등록하여 간편하게 입력하는 방법도 있지만, shellscripts로 여러 런치파일을 돌릴 때는 완전히 새로운 개별 터미널에서 수행되는 것이므로, 이러한 방법도 한계가 있습니다. 

 

echo "source ~/catkin_ws/devel/setup.bash" >> ~/.bashrc

 

따라서 위와 같은 명령어로 bashrc 파일 상에 "터미널이 새로 실행될 때 마다 ~/catkin_ws/devel/ 경로에 있는 setup.bash 파일을 최신화하기" 라는 명령어를 심어주는 겁니다. 이 과정을 수행하면 터미널을 실행할 때 마다 source devel/setup.bash 명령어를 입력할 필요가 없어집니다. 이후 다음 터미널을 열 때 부터 수정사항이 적용됩니다.


이렇게 생성한 패키지의 경우, 다음 명령어로 조회할 수 있습니다.

 

rospack find hello_ros

roscd hello_ros

 

rospack find 명령어는 해당 패키지가 위치하는 경로를 보여주며,
roscd 명령어는 해당 디렉토리로 이동할 수 있는 명령어입니다.

 

패키지 관련 명령어 수행 결과

 


노드 작성


패키지 디렉토리로 들어가서,  소스 파일들을 저장할 scripts 디렉토리를 생성하고, 노드 파일(.py)을 작성합니다.

 

catkin_create_pkg 명령어를 통해 패키지를 생성하면, 하위 디렉토리에 노드 파일(.cpp)을 보관할 수 있는 src 디렉토리가 생성되지만, 보통 src 디렉토리에는 c++로 작성된 노드만 보관하고, 그 이외의 파일들은 scripts 디렉토리에 보관한다고 나와 있어, scripts 디렉토리에 노드를 작성해보겠습니다. 

 

cd hello_ros
mkdir scripts # a directory to save the source file(.py)

gedit talker.py # publisher node
gedit listener.py # subscriber node

 

gedit이라는 텍스트 편집기를 이용했으며, VS Code 등 각자 편한 편집기를 사용하셔도 됩니다. 아래 소스들을 그대로 복사하여 붙여넣기 하시면 됩니다.

 

talker.py

#!/usr/bin/env python3

import rospy
from std_msgs.msg import String

def talker():
    pub = rospy.Publisher('chatter', String, queue_size=10)
    rospy.init_node('talker', anonymous=False)
    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

 

listener.py

 

#!/usr/bin/env python3
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=False)
    rospy.Subscriber("chatter", String, callback)
    rospy.spin()

if __name__ == '__main__':
    listener()

 

노드 작성이 끝나면, ctrl+s 로 해당 파일을 저장합니다. 

이후, 다음 명령어를 통해 각 노드 파일들에 대해 실행 권한을 부여합니다.

 

chmod +x listener.py

chmod +x talker.py

 

chmod 명령어는 파일 또는 디렉토리에 대한 접근 권한, 즉 모드를 변경하는 데 사용하는 명령어입니다.

+x는 executable한 권한을 추가한다는 뜻으로, 실행 권한을 부여한다는 의미입니다.

 

위 수행 결과를 보시면, 처음 ls 명령어를 통해 조회한 것과 달리 마지막 ls의 결과로 listener.py와 talker.py의 글자 색상이 초록색으로 바뀌어 있는데, 정상적으로 실행 권한이 부여되었음을 의미합니다.


Package Build

 

이후 아래 명령어 중 하나를 통해 패키지를 빌드합니다. catkin_make의 경우 통상적인 빌드 방식이며 catkin_ws 디렉토리에서만 빌드가 가능합니다. 반면 catkin build는 workspace 하위 디렉토리 어느 곳에서나 빌드가 가능하다는 장점이 있습니다.

 

catkin_make
catkin build

 

 

빌드 후에는 setup.bash파일을 재실행 시켜주어야 합니다. 위 과정처럼 bashrc에 workspace를 등록하였다면 터미널 창을 새로 여는 것도 하나의 방법일 수 있겠네요.

 

source ~/catkin_ws/devel/setup.bash

 


노드 실행

예제의 경우, talker(publisher)와 listener(subscriber)가 chatter라는 String 형태의 토픽으로 통신하는 간단한 예제입니다. listener는 talker로부터 /chatter 토픽을 수신받을 때 해당 토픽과 i heard 를 결합한 문자열을 출력합니다.

실제로 talker를 실행하지 않고 listener만 실행할 시 아무것도 출력되지 않습니다.


Terminal 1

 

먼저 노드 관리를 위한 ros master를 실행합니다.

 

roscore

 


Terminal 2 (Publisher)

 

이후 작성한 노드를 rosrun 명령어를 통해 수행합니다. rosrun 패키지명 노드명 순입니다.

rosrun hello_ros talker.py

 


Terminal 3 (Subscriber)

 

rosrun hello_ros listener.py

 


수행 결과 

 

수행 결과

 

수행 결과로, talker(2번째 터미널)에서 출력되는 메세지가 listener(3번째 터미널)에서도 동일하게 출력되며, 이 메세지는 /chatter 라는 토픽으로 정상적으로 통신이 이루어짐을 확인할 수 있습니다.

 

rqt_graph

 


roslaunch를 이용하여 여러 노드를 한번에 수행하기

 

위의 경우처럼, 두 노드를 수행하기 위해 ros master를 포함하여 3개의 터미널에 각 커맨드를 입력하는 것은 매우 번거롭습니다.

이 때 사용할 수 있는 것이 launch파일을 이용하여 여러 노드를 한꺼번에 수행하는 것입니다.

 

launch 파일에 각 노드 실행에 필요한 arguments, parameter 등을 기록해 놓을 수 있고, roslaunch 명령어를 통해 런치 파일을 수행하면 작성한 대로 여러 노드들을 수행할 수 있게 됩니다.

 

roscd hello_ros
mkdir launch && cd launch
gedit hello.launch

 

hello.launch

<launch>
  <node pkg="hello_ros" type="talker.py" name="talker" output="screen"/>
  <node pkg="hello_ros" type="listener.py" name="listener" output="screen"/>
</launch>

 

 각 파라미터들의 의미는 다음과 같습니다.

param​
의미
비고
pkg
해당 노드가 위치한 패키지명
type
실제 수행할 노드 파일 명
C++ 노드의 경우 talker.cpp가 아닌 talker로 기재
name
해당 노드를 어떤 이름으로 수행할 지 설정
파일명과는 별개로, 해당 노드의 이름 지정
output
터미널 출력 설정
output="screen"

 

name에서 지정하는 노드 이름은 launch 시작 지점에서 다음과 같이 표시됩니다.

 

node name

 

이제 roslaunch 명령어를 통해 두 노드를 동시에 수행할 수 있습니다.

 

launch파일을 이용한 실행의 또 다른 장점은, ROS master를 별도로 실행하지 않아도 된다는 것입니다.

이전에는 개별 노드 실행을 위하여 roscore 명령어를 통해 ROS master를 별도로 실행해야 했습니다만, 위 roslaunch 한 줄로 3개의 터미널에 각각 ROS master와 두 노드를 수행하는 것과 같은 효과를 내는 것입니다.

 

roslaunch hello_ros hello.launch

 


수행 결과

 

수행 결과

 

하나의 터미널에서 두 노드가 동시에 수행되는 것을 확인하실 수 있습니다. launch파일에서 두 노드에 모두 output 설정을 해놓았으므로 talker와 listener가 메세지를 번갈아서 출력하는 것을 확인하실 수 있습니다.

 


참고 링크

 

http://wiki.ros.org/ROS/Tutorials/WritingPublisherSubscriber%28python%29

 

ROS/Tutorials/WritingPublisherSubscriber(python) - ROS Wiki

Writing the Publisher Node "Node" is the ROS term for an executable that is connected to the ROS network. Here we'll create the publisher ("talker") node which will continually broadcast a message. Change directory into the beginner_tutorials package, you

wiki.ros.org