프로그래밍 with ROS (Robot Operating System)

  • by

ROS 작업공간, ROS 패키지 및 ROS 노드를 작성하는 방법을 설명합니다.

패키지와 기본 ROS 노드를 만든 후에는 이전 장에서 설명한 turtlesim 시뮬레이터를 프로그래밍하는 방법을 살펴 보겠습니다.

주로 사용하는 프로그래밍 언어는 C++와 Python입니다.

다음으로 Gazebo 시뮬레이터와 TurtleBot 로봇 시뮬레이션을 소개하고 기본 ROS 노드를 사용하여 TurtleBot을 시뮬레이션에서 이동하는 방법을 설명합니다.

ROS 프로그래밍은 무슨 뜻인가요? ROS는 ROS 능력을 구현하기 위한 내장 함수를 제공합니다.

예를 들어 새 ROS 주제, ROS 메시지 또는 ROS 서비스를 구현하려면 이러한 ROS 내장 함수를 호출하여 쉽게 만들 수 있습니다.

ROS 기능을 처음부터 구현할 필요는 없습니다.

ROS 내장 함수/응용프로그램 프로그래밍 인터페이스(API)를 사용하는 프로그램을 ROS 노드라고 합니다.

Creating a ROS Workspace and Package

ROS 개발의 첫 번째 단계는 ROS 작업 공간을 만드는 것입니다.

여기에는 ROS 패키지가 저장됩니다.

먼저 ROS 작업공간 폴더를 만들어야 합니다.

원하는 이름으로 지정하고 원하는 위치에 만들 수 있습니다.

일반적으로 우분투 홈 폴더에 만들어집니다.

새 터미널에서 다음 명령을 입력합니다.

$mkdir -p ~/catkin_ws/src

이렇게 하면 catkin_ws라는 폴더가 만들어지며 다른 폴더인 src가 있습니다.

ROS 작업 공간은 catkin 작업 공간이라고도 합니다.

다음 섹션에서 catkin에 대해 자세히 알아보세요. src 폴더의 이름은 변경하지 마십시오. 그러나 workspace 폴더 이름은 변경할 수 있습니다.

위의 명령을 입력한 후 cd 명령을 사용하여 src 폴더로 이동합니다.

$cd catkin_ws/src

다음 명령은 새 ROS 작업 공간을 초기화합니다.

작업 공간을 초기화하지 않으면 패키지를 올바르게 작성하고 빌드할 수 없습니다.

:$catkin_init_workspace

위의 명령을 실행하면 src 폴더에 CMakeLists.txt 파일이 있습니다.

catkin 작업공간을 초기화한 후 작업공간을 빌드할 수 있습니다.

작업공간을 빌드하려면 catkin_ws/src 폴더에서 catkin_ws 폴더로 이동한 후 다음 명령을 사용합니다.

$~/catkin_ws/src$cd..

$~/catkin_ws$ catkin_make


src 폴더 외에도 여러 폴더를 볼 수 있습니다.

src 폴더는 패키지가 저장되는 곳입니다.

패키지를 만들거나 빌드하려면 패키지를 src 폴더에 복사해야 합니다.

작업공간을 작성한 후에는 작업공간 환경을 추가하는 것이 중요합니다.

이는 작업공간 내의 패키지가 액세스 가능하고 볼 수 있도록 작업공간 경로를 설정해야 함을 의미합니다.

이렇게 하려면 다음 단계를 수행해야 합니다.

홈 폴더에서 .bashrc 파일을 열고 파일 끝에 다음 줄(source~/catkin_ws/devel/setup.bash)을 추가합니다.

터미널에서 홈 폴더로 이동하여 .bashrc 파일을 선택합니다.

:$gedit .bashrc


홈 폴더의 .bashrc 스크립트는 새 터미널 세션이 시작될 때 실행됩니다.

따라서 .bashrc 파일에 삽입된 명령어도 실행됩니다.

다음 명령의 setup.bash에는 Linux 환경에 추가할 변수가 포함되어 있습니다.

:source ~/catkin_ws/devel/setup.bash

현재 터미널 세션에 작업 공간 경로가 추가됩니다.

이제 어떤 터미널을 사용하든 이 작업공간의 패키지에 액세스할 수 있습니다.

패키지 작성에 대해 논의하기 전에 ROS의 catkin 빌드 시스템에 대해 논의해야 합니다.

catkin 빌드 시스템을 알면 빌드 프로세스를 더 잘 이해할 수 있습니다.

ROS Build System

우리가 사용하는 빌드 시스템의 이름은 catkin입니다 (http://wiki.ros.org/catkin). catkin은 CMake 빌드 시스템과 Python 스크립트를 기반으로 작성된 사용자 정의 빌드 시스템입니다.

그렇다면 왜 CMake를 직접 사용하지 않습니까? 그 이유는 간단합니다.

ROS 패키지 세트를 만드는 것은 복잡합니다.

패키지 수와 패키지 간의 종속성이 증가할수록 복잡성이 높아집니다.

catkin 빌드 시스템은 이러한 모든 것을 처리합니다.

우리는 catkin 작업 공간을 만들었지만 어떻게 작동하는지 논의하지 않았습니다.

작업 공간에는 여러 폴더가 있습니다.

각 폴더의 기능을 살펴 보겠습니다.

src 폴더

catkin 작업공간 폴더의 src 폴더는 리포지토리에 새 패키지를 생성하거나 복제하기 위한 공간입니다.

ROS 패키지는 src 폴더에 있는 경우에만 빌드하여 실행 파일을 생성합니다.

작업공간 폴더에서 catkin_make 명령을 실행하면 src 폴더 내에서 각 패키지를 빌드합니다.

빌드 폴더

ROS 작업 공간에서 catkin_make 명령을 실행하면 catkin 도구는 빌드 파일과 중간 캐시 CMake 파일을 빌드 폴더에 작성합니다.

이러한 캐시 파일은 catkin_make 명령을 실행할 때 모든 패키지를 다시 작성하는 것을 방지합니다.

build 폴더를 삭제하면 모든 패키지가 다시 작성됩니다.

devel Folder

catkin_make 명령을 실행하면 각 패키지가 빌드되고 빌드 프로세스가 성공하면 대상 실행 파일이 생성됩니다.

실행 파일은 devel 폴더에 저장되며 현재 작업 공간을 ROS 작업 공간 경로에 추가하는 쉘 스크립트 파일을 포함합니다.

이 스크립트를 실행하지 않으면 현재 작업 공간 패키지에 액세스할 수 없습니다.

일반적으로 다음 명령을 사용합니다.


source ~//devel/setup.bash

이 명령을 .bashrc 파일에 추가하여 모든 터미널 세션에서 작업공간 패키지에 액세스할 수 있습니다.

install Folder

대상 실행 파일을 로컬로 빌드한 후 다음 명령을 실행하여 실행 파일을 설치합니다.


$catkin_make install
이 명령은 ROS 작업 공간 폴더에서 실행해야 합니다.

그러면 작업공간에 install 폴더가 작성됩니다.

이 폴더에는 설치할 파일이 저장됩니다.

실행 파일을 실행하면 install 폴더에서 실행됩니다.

Creating a ROS Package

이것으로 ROS 작업 공간 작성이 완료되었습니다.

이제 ROS 패키지를 만드는 방법을 살펴 보겠습니다.

ROS 패키지는 ROS 노드, 라이브러리 등이 구성되는 곳입니다.

다음 명령을 사용하여 catkin ROS 패키지를 작성할 수 있습니다.


$ catkin_create_pkg ros_package_name package_dependencies


패키지를 만드는 데 사용되는 명령은 catkin_create_pkg입니다.

이 명령의 첫 번째 매개 변수는 패키지 이름이며 패키지 종속성이옵니다.

예를 들어 종속성이 있는 hello_world 패키지를 만듭니다.

catkin 작업 공간의 src 폴더에서 명령을 실행해야 합니다.


$/catkin_ws/src$ catkin_create_pkg hello_world roscpp rospy std_msgs

이렇게 하면 ROS 패키지를 만들 수 있습니다.


패키지 내에는 src 폴더, package.xml, CMakeLists.txt 및 include 폴더가 있습니다.

CMakeLists.txt: 이 파일에는 패키지에 ROS 소스 코드를 빌드하고 실행 파일을 생성하는 모든 명령어가 들어 있습니다.

package.xml: 주로 패키지 종속성, 정보 등을 포함합니다.


src:ROS 패키지의 소스 코드는 이 폴더에 저장됩니다.

일반적으로 C++ 파일은 src 폴더에 저장됩니다.

Python 스크립트를 아카이브하려면 패키지 폴더에 scripts라는 다른 폴더를 만들 수 있습니다.


include: 이 폴더에는 패키지 헤더 파일이 들어 있습니다.

자동으로 만들거나 타사 라이브러리 파일을 포함할 수 있습니다.

ROS Client Libraries

지금까지 주제, 서비스, 메시지 등 다양한 ROS 개념을 다루었습니다.

이러한 개념을 어떻게 구현합니까? 그 대답은 ROS 클라이언트 라이브러리를 사용하는 것입니다.

ROS 클라이언트 라이브러리는 ROS 개념을 구현하는 데 사용되는 함수를 모은 일련의 코드입니다.

우리는 이러한 라이브러리 함수를 우리의 코드에 포함시켜 ROS 노드로 만들 수 있습니다.

클라이언트 라이브러리는 ROS 응용 프로그램을 만드는 데 필요한 내장 함수를 제공하므로 개발 시간을 절약할 수 있습니다.

모든 프로그래밍 언어에서 ROS 노드를 만들 수 있습니다.

해당 프로그래밍 언어에 ROS 클라이언트가 있는 경우 ROS 노드를 만드는 것이 더 쉽습니다.

그렇지 않으면 우리 자신의 ROS 개념을 구현해야 할 수도 있습니다.

다음은 주요 ROS 클라이언트 라이브러리입니다.

roscpp: 이것은 C++용 ROS 클라이언트 라이브러리입니다.

높은 성능으로 ROS 애플리케이션 개발에 널리 사용됩니다.

rospy: 이것은 파이썬 용 ROS 클라이언트 라이브러리입니다.

개발 시간을 절약하는 이점이 있습니다.

roscpp보다 적은 시간에 ROS 노드를 만들 수 있습니다.

고속 프로토타이핑 애플리케이션에 이상적이지만 성능은 roscpp보다 낮습니다.

ROS의 대부분의 명령 행 도구 (roslaunch, roscore 등)는 rospy를 사용하여 작성되었습니다.

roslisp: 이것은 Lisp 언어의 ROS 클라이언트 라이브러리입니다.

주로 ROS의 모션 플랜 라이브러리에서 사용되지만 roscpp와 rospy만큼 인기가 없습니다.

rosjava, rosnodejs, roslua와 같은 실험적인 클라이언트 라이브러리도 있습니다.

ROS 클라이언트 라이브러리의 전체 목록은 http://wiki.ros.org/Client%20Libraries에서 확인할 수 있습니다.

우리는 주로 roscpp와 rospy를 사용합니다.

다음은 roscpp와 rospy를 사용하여 만든 ROS 노드의 기본 예입니다.

roscpp and rospy

Header Files and ROS Modules

C++ 코드를 작성할 때 첫 번째 섹션에는 헤더 파일이 포함됩니다.

마찬가지로 파이썬 코드를 작성할 때 첫 번째 섹션에서 파이썬 모듈을 가져옵니다.

이 절에서는 ROS 노드에서 가져와야 하는 중요한 헤더 파일과 모듈에 대해 설명합니다.

ROS C++ 노드를 만들려면 다음 헤더 파일을 포함해야 합니다.

#include “ros/ros.h”

ros.h에는 ROS 기능을 구현하는 데 필요한 모든 헤더가 포함되어 있습니다.

이 헤더 파일을 포함하지 않으면 ROS 노드를 만들 수 없습니다.

노드에서 특정 메시지 유형을 사용하려면 해당 메시지 헤더 파일을 포함해야 합니다.

ROS에는 몇 가지 기본 제공 메시지 정의가 있으며 사용자는 새 메시지 정의를 만들 수도 있습니다.

ROS에는 int, float, string과 같은 표준 데이터 유형의 메시지 정의를 포함하는 std_msgs라는 기본 제공 메시지 패키지가 있습니다.

예를 들어 코드에 문자열 메시지를 포함하려면 다음 코드를 사용할 수 있습니다.


#include “std_msgs/String.h”

여기서 첫 번째 부분은 패키지 이름이고 다음 부분은 메시지 유형 이름입니다.

사용자 지정 메시지 유형이 있는 경우 다음 구문을 사용하여 호출할 수 있습니다.


#include “msg_pkg_name/message_name.h”‘


Python에서 ROS 노드를 만들려면 모듈을 가져와야 합니다.

가져올 ROS 모듈은 다음과 같습니다.

import rospy

rospy에는 모든 중요한 ROS 기능이 포함되어 있습니다.

메시지 유형을 가져오려면 C++와 같이 특정 모듈을 가져와야 합니다.

다음은 Python에서 문자열 메시지 유형을 검색하는 예입니다.


from std_msgs.msg import String
package_name.msg를 사용하여 필요한 메시지 유형을 가져와야 합니다.

Initializing a ROS Node

어떤 ROS 노드를 시작하기 전에 먼저 호출되는 함수는 노드를 초기화합니다.

이것은 모든 ROS 노드에서 필수적인 단계입니다.

C++에서는 다음 코드 줄을 사용하여 초기화합니다.

int main(int argc, char **argv)
{
ros::init(argc, argv, “name_of_node”)
…………………
}

int main() 함수 뒤에는 ROS 노드를 초기화하는 ros::init() 함수가 포함되어야 합니다.

이 함수에 argc, argv 명령행 인수와 노드명을 건네줄 수가 있습니다.

이것은 ROS 노드 이름이며 rosnode list를 사용하여 노드 목록을 검색할 수 있습니다.

Python에서는 다음 코드 행을 사용합니다.

rospy.init_node(‘name_of_node’, anonymous=True);

첫 번째 인수는 노드의 이름이고 두 번째 인수는 anonymous=True입니다.

이는 노드가 여러 인스턴스에서 실행될 수 있음을 의미합니다.

Printing Messages in a ROS Node

ROS는 메시지를 기록하기 위한 API를 제공합니다.

이 메시지는 노드의 상태를 전달하는 문자열입니다.


C++에서는 다음 함수를 사용하여 노드의 메시지를 기록할 수 있습니다.

ROS_INFO(string_msg,args): Logging the information of node
ROS_WARN(string_msg,args): Logging warning of the node
ROS_DEBUG(string_msg ,args): Logging debug messages
ROS_ERROR(string_msg ,args): Logging error messages
ROS_FATAL(string_msg ,args): Logging Fatal messages
Eg: ROS_DEBUG("Hello %s","World");

Python에는 로깅 작업과 관련된 다른 함수가 있습니다.

rospy.logdebug(msg, *args)
rospy.logerr(msg, *args)
rospy.logfatal(msg, *args)
rospy.loginfo(msg, *args)
rospy.logwarn(msg, *args)

Creating a Node Handle
노드를 초기화한 후 ROS 노드와 동일한 작업(예: 주제 게시/구독)을 수행하려면 ros::NodeHandle 인스턴스를 만들어야 합니다.

C++에서는 다음과 같이 ros::NodeHandle 인스턴스를 만듭니다.

ros::NodeHandle nh;

노드의 다른 태스크는 nh 인스턴스를 사용합니다.

Python에서는 핸들을 만들 필요가 없으며 rospy 모듈이 내부적으로 처리합니다.

Creating a ROS Message Definition

주제를 발행하기 전에 ROS 메시지 정의를 작성해야 합니다.

메시지 정의는 다음 방법을 사용하여 생성됩니다.

C++에서는 다음 코드 행을 사용하여 ROS 메시지 인스턴스를 만들 수 있습니다.

예를 들어, 이것은 우리가 std_msgs / String의 인스턴스를 생성하는 방법입니다.

std_msgs::String msg;

ROS 메시지 인스턴스를 만든 후에는 다음 코드를 사용하여 데이터를 추가할 수 있습니다.


msg.data = “문자열 데이터”

파이썬에서는 다음 코드를 사용하여 문자열 메시지에 데이터를 추가합니다.


msg = String()
msg.data = “string data”

Publishing a Topic in ROS Node

ROS 노드에서 주제를 게시하는 방법을 보여줍니다.

C++에서는 다음 구문을 사용합니다.

ros::Publisher publisher_object = node_handle.advertise(“topic_name”,1000)

게시자 개체를 만든 후 publish() 명령을 사용하여 해당 주제를 통해 ROS 메시지를 보냅니다.

publisher_object.publish(message)
예:
ros :: Publisher chatter_pub = nh.advertise
msgs::String>(“chatter”, 1000);
chatter_pub.publish(msg);

이 예에서 chatter_pub는 ROS publisher 인스턴스이고 메시지 유형이 std_msgs/String이고 chatter가 주제 이름인 주제를 노출합니다.

큐 크기는 1000입니다.

파이썬이 발행하는 구문은 다음과 같습니다.

Syntax:
publisher_instance = rospy.Publisher(‘topic_name’, message_
type, queue_size)
예:
pub = rospy.Publisher(‘chatter’, String, queue_size=10)
pub.publish(hello_str)

이 예에서는 queue_size가 10이고 std_msgs/String 메시지 유형이 있는 chatter라는 주제를 발행합니다.

Subscribing a Topic in ROS Node

주제를 게시할 때 메시지 유형을 생성하고 주제를 통해 제출해야 합니다.

주제를 구독하면 메시지가 주제에서 수신됩니다.

C++에서 주제를 구독하는 구문은 다음과 같습니다.