공부#Robotics#자율주행/(ROS2) 기초

(ROS2 기초)5. ROS에서 코딩하기 전 알아야할 내용

BrainKimDu 2023. 5. 8. 23:19

참고도서 1. ROS 2로 시작하는 로봇 프로그래밍. 표윤석 .  루비페이퍼 . 2021 
참고도서 2. ROS2 혼자공부하는 로봇SW 직접 만들고 코딩하자 . 민형기 .  잇플 . 2022
참고자료 1. PinkWink(민형기)님의 ROS2 강의자료
참고자료 2. ROS2 humble documeation

ROS2를 복습하는 김에 제대로 다시 한 번 정리하고 넘어가고 싶어서 이 시리즈를 작성합니다. 
이 글은 Turtlebot3 패키지를 제대로 이해하고, 다양한 센서를 부착하면서 활용하는 것을 목표로 합니다.
또한 글이 끝날 때 ROS와 관련된 문제를 하나 만들어서 직접 풀어보도록 합니다.

드디어 turtlesim이 끝났습니다. 이번 시간에는 ROS에서 코딩하기전 약속과도 같은 것들과, 코딩을 위해 필요한 프로그램들을 다룹니다.


ROS2의 약속

https://cafe.naver.com/openrt/24272

 

017 ROS 2의 물리량 표준 단위

Created Date: 2020.09.18 Modified Date: 2020.09.21 revision 5 * 로봇 운영체제 ROS 강좌 목차: https://cafe....

cafe.naver.com

https://cafe.naver.com/openrt/24274

 

018 ROS 2의 좌표 표현

Created Date: 2020.09.21 Modified Date: 2020.09.21 revision 5 * 로봇 운영체제 ROS 강좌 목차: https://cafe....

cafe.naver.com

표윤석님께서 정리하신 ROS에서의 약속을 다루는 내용입니다. 저는 기초를 다루기 때문에 넘어가도록 하겠습니다. 

 

ROS2의 파일 시스템

ROS2에서 노드들을 모아놓은 것을 패키지라고 하며, 이러한 패키지들을 모아놓은 것을 메타패키지라고 합니다. Turtlebot3 패키지를 한 번 살펴보도록 합시다.

Turtlebot3는 ROS를 활용하는 교육용 로봇으로 한국에 있는 로보티즈라는 회사에서 생산과 판매를 담당 하고 있습니다.

이렇게 생긴 아이들입니다. 여기서 turtlebot3라는 레포지토리를 살펴보면 다음과 같습니다.

https://github.com/ROBOTIS-GIT/turtlebot3

 

GitHub - ROBOTIS-GIT/turtlebot3: ROS packages for Turtlebot3

ROS packages for Turtlebot3. Contribute to ROBOTIS-GIT/turtlebot3 development by creating an account on GitHub.

github.com

(여기에 contributors를 보면 ROS2로 시작하는 로봇프로그래밍의 저자 표윤석님께서 계십니다.)

지금 우리는 Turtlebot3라는 메타패키지를 보고 있습니다. 그리고 이안에 들어있는 여러 패키지들입니다. 위에서 부터 3개 정도만 설명을 하면 turtlebot3_bringup 패키지는 로봇의 시동을 담당하는 패키지입니다. turtlebot3_description은 turtlebot3란 로봇이 어떻게 생겼는지를 표현하는 패키지입니다. (이에 대한 내용은 나중에 추가하겠습니다.) turtlebot3_example은 turtlebot3에 대한 여러 예제 코드들을 담아놓은 파일입니다.

 

이러한 메타패키지들을 설치하는 방법은 두 가지입니다. 

첫 번째 방법은 내 local의 보기좋은 공간에 설치하는 방법입니다. (이를 소스코드  설치라고 합니다.)

cd
mkdir turtlebot_ws
cd turtlebot_ws
mkdir src
cd src
git clone https://github.com/ROBOTIS-GIT/turtlebot3.git -b humble-devel

 

두 번째는 ROS에서 공식적으로 지원한다면 다음과 같은 설치를 할 수 있습니다. (이를 바이너리 설치라고 합니다.)

sudo apt install ros-humble-turtlebot3

이렇게 설치하게 되면 /opt/ros/humble/share 에 설치되게 됩니다. 보통 ROS에서 핵심적인 내용이 아닌 이상은 두번째 방법보다는 첫 번째 방법으로 별도의 ws에 설치하는 것이 좋습니다.

이후부터는 ROS를 통해서 직접 코딩이 가능해야함으로 소스코드 설치방법으로 설치를 진행한 경우라고 생각하고 진행하겠습니다.

 

ROS2의 빌드

다음처럼 Turtlebot3 메타패키지를 다운로드 받았습니다.

ROS의 빌드 시스템은 단일 패키지를 대상으로 하며, 빌드 툴은 시스템 전체를 대상으로 합니다. 단일 패키지 개념과 시스템 전체를 나누게된 것은 의존성 문제 때문입니다. ROS는 코드의 재사용성을 위해 패키지와 노드 단위로 구성되어 있고, 각 패키지는 다른 패키지와 의존성을 갖게 됩니다. ROS의 C++에서는 CMAKE 기반의 catkin과 ament_cmake를 사용하고 있고, python의 경우는 setuptools를 사용하고 있습니다. 

뭐 여튼 쉽게 말해서 ROS는 코드를 재사용하기 용이하게 만들어졌습니다. 그래서 의존성 문제가 중요한데, 이러한 의존성 문제를 해석하면서 빌드한다고 합니다. ROS에서 가장 널리 사용되는 빌드 툴은 colcon입니다. CMakeList.txt와 setup.py에 빌드담당 정보를 적는다고 합니다.

 

빌드 시스템에 필요한 부가 기능

vcstool(버전 컨트롤 시스템 툴)

.repos라는 파일이 있다면 여기에 있는 레포지토리를 설치해주는 프로그램입니다.

vcs import src < ros2.repos

다음처럼 src폴더에다가 ros2.repos에서 설명하는 레포지토리를 다운로드 해놓아라 우선은 이렇게 이해하고 넘어갑시다.

 

rosdep(의존성관리툴)

ros의 의존성을 해결하기 위해서 사용하는 툴로 package.xml을 참고해서 의존성을 해결하게 됩니다. ROS에서 사후지원이 종료된 버전이라고 한다면, 이 기능이 동작을 하지 않게 됩니다. 그래서 rosdep이 작동하는지 확인하는 과정은 다음과 같습니다.

rosdep init
rosdep update

 init은 설치가 정상적으로 되어 있다면 오류가 발생하는게 정상입니다.

보는 것과 같이 지원이 종료된 버전은 skip을 하고, 그 외는 update를 하는 모습을 보여줍니다. 그래서 turtlebot3 패키지의 의존성을 해결하려면 다음과 같이 진행하면 됩니다.

(폴더 위치에 주의하십쇼)

rosdep install --from-paths src --ignore-src -r -y

그러면 자동으로 Turtlebot3를 위해 필요한 의존성 패키지들을 자동으로 설치할 것 입니다.

그리고 이제 패키지를 colcon 을 이용해서 빌드를 하게 된다면 다음과 같습니다.

colcon build --symlink-install

보통 colcon build만 진행하기도 합니다. 두 명령어의 차이점은 colcon build만 하면 모두다 복사하는 것이고, colcon build --symlink-intall로 하면 빌드된 파일을 실제로 설치하지 않고 심볼릭 링크를 사용해 더 적은 디스크를 사용합니다. 만약에 이러한 빌드가 문제가 생긴다면 그냥 colcon build를 하면됩니다. (colcon build전에 폴더가 일치하지 않는다거나, ros환경을 불러오지 않는다거나 하면 오류가 발생합니다.)

빌드에 성공하면 다음처럼 3개의 폴더가 생성됩니다. build는 build에 대한 내용이 Log에는 log에 대한 내용이 install에는 src의 패키지에 있던 파일을 실행가능하게 가져오는 느낌이라고 일단 이해하면 됩니다.

만약 이런식으로 빌드가 된다면 ros 상에서 사용이 가능하다는 것을 의미합니다. 근데, 일단 이 뒤의 내용은 나중으로 미루고, 여기서는 외부의 패키지를 들고와서 의존성을 해결하면서 빌드를 할 수 있다 이정도만 보고 넘어가도록 합시다. 다음으로는 패키지를 직접 만들어봅시다.

 

ROS2의 패키지를 직접 만들자.

패키지를 만들기 전에 다음의 약속을 지켜주어야합니다. 메타패키지를 위한 작업공간(workspace)를 만들자. 작업공간의 src폴더 안에 패키지를 작성하도록 하자.

그래서 다음처럼 패키지를 만들 준비를 하면 됩니다. 패키지를 만들기 전에는 꼭 ROS 환경을 불러와주어야합니다. 

ros2 pkg create --build-type ament_python ros_study

이 명령어는 파이썬으로 패키지를 만들 때 사용하는 명령어입니다.

ros2 pkg create --build-type ament_cmake ros_study

이 명령어는 C++로 패키지를 만들 때 사용하는 명령어입니다.

추가로 패키지를 만들 때 의존성패키지를 지정하거나, 노드의 이름을 지정하는 등의 방법을 사용할 수 있습니다. 일단은 그런 내용은 빼고 진행을 합시다.

만약 공부가 목적이라면 우선 python을 사용하는 패키지를 만드는 것을 추천합니다.

처음은 python을 통해서 패키지를 제작해보도록 하겠습니다.

ros2 pkg create --build-type ament_python ros_study_py

그러면 src폴더 내부에 다음과 같은 파일들이 만들어집니다.

setup.py는 빌드관련, package.xml은 의존성 관련으로 생각하면 됩니다. 우선 각각의 파일을 조금 집중적으로 탐구를 해보도록 하겠습니다.

 

다시 src로 가서 이번에는 C++형식의 패키지를 만들어봅시다.

ros2 pkg create --build-type ament_cmake ros_study_cpp

 

두 패키지의 차이점은 python은 setup.py로 나타나고, C++은 CMakeLists.txt로 나타난다는 점입니다. 그러나 두 패키지 모두 package.xml이라는 파일을 가지고 있습니다.

 

생성한 패키지 파일 톺아보기

package.xml

ROS 패키지의 필수 구성요소로 패키지의 정보를 기술하는 파일입니다. 패키지 이름, 저작자, 라이선스,의존성 패키지 등이 있으며 XML형식을 사용해서 기술하게 됩니다. 두 파일은 CPP이냐 Python이냐에 따라 내용이 다릅니다.

먼저 보게될 코드는 Cpp입니다.

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>ros_study_cpp</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="dubook@todo.todo">dubook</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

다음은 Python입니다.

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
  <name>ros_study_py</name>
  <version>0.0.0</version>
  <description>TODO: Package description</description>
  <maintainer email="dubook@todo.todo">dubook</maintainer>
  <license>TODO: License declaration</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <test_depend>ament_lint_auto</test_depend>
  <test_depend>ament_lint_common</test_depend>

  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>

 

우리가 주의할 부분은 라이센스입니다. 뭔가 어디선가 패키지를 들고왔다면, 저작권에 주의해야합니다.

"잘보이라고 이렇게 하지만 보통 주석은 <!-- --> 으로 답니다."
<?xml version="1.0"?>
"문서 문법을 정의하며 xml은 버전 1.0을 따르고 있다"
<?xml-model href="http://download.ros.org/schema/package_format3.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="3">
"ROS의 패키지를 설정하는 부분입니다."

  <name>ros_study_py</name>
  "패키지 이름"
  <version>0.0.0</version>
  "패키지 버전"
  <description>TODO: Package description</description>
  "패키지 설명"
  <maintainer email="dubook@todo.todo">dubook</maintainer>
  "이메일"
  <license>TODO: License declaration</license>
  "라이센스"

  <buildtool_depend>ament_cmake</buildtool_depend>
  "빌드 툴의 의존성을 기술"
  
  <depend>~~~</depend>
  "의존성에 적는 부분"

  <build_depend>~~</build_depend>
  "패키지를 빌드할 때 필요한 의존 패키지"
  
  <test_depend>ament_lint_auto</test_depend>  
  <test_depend>ament_lint_common</test_depend>
  "패키지를 테스트할 때 필요한 의존 패키지"

  <test_depend>~~</test_depend>
  "패키지를 테스트할 때 필요한 의존 패키지"

  <export>
    <build_type>ament_cmake</build_type>
  </export>
  "위에서 명시하지 않은 확장 태크명을 명시하는 부분"
</package>

 

CMakeList.txt

위 파일은 C++환경으로 만들어진 패키지에서 빌드 환경을 기술합니다. 이 빌드 설정 파일에 실행 파일 생성, 의존성 패키지 우선 빌드, 링크 생성 등을 설정합니다. 내용은 다음과 같습니다.

cmake_minimum_required(VERSION 3.8)
project(ros_study_py)

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

주석을 달면서 알아봅시다.

cmake_minimum_required(VERSION 3.8)
"요구하는 cmake의 버전"
project(ros_study_py)
"여기서 package.xml과 이름이 다르면 빌드되지 않는다."

if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
  add_compile_options(-Wall -Wextra -Wpedantic)
endif()
"C언어와 C++의 컴파일러의 버전을 기재하는 부분"

# find dependencies
find_package(ament_cmake REQUIRED)
# uncomment the following section in order to fill in
# further dependencies manually.
# find_package(<dependency> REQUIRED)
"ament 빌드 할 때 요구되는 구성 요소 패키지이다. 사용자가 만든 패키지가 의존하는 다른 패키지를 먼저 설치하게"
"만드는 옵션"

"만약 사용자가 메시지 인터페이스를 직접 작성하게된다면 다음처럼 추가시켜주어야한다."
set(msg_files
  "msg/mypose.msg"
)

set(srv_files
  "msg/myspawn.srv"
)

set(action_files
  "msg/myteleop.action"
)

rosidl_generate_interfaces(${PROJECT_NAME}
  ${msg_files}
  ${srv_files}
  ${action_files}
  DEPEMDEMCOES std_msgs action_msgs
  ADD_LINTER_TESTS
)
 
"이 외의 과정은 코드를 작성하면서 알아보도록 합니다."

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  # the following line skips the linter which checks for copyrights
  # comment the line when a copyright and license is added to all source files
  set(ament_cmake_copyright_FOUND TRUE)
  # the following line skips cpplint (only works in a git repo)
  # comment the line when this package is in a git repo and when
  # a copyright and license is added to all source files
  set(ament_cmake_cpplint_FOUND TRUE)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

 

Setup.py

파이썬 패키지에서 CMakeList.txt와 package.xml의 기능을 하나로 묶어서 사용하는 파일이라고 생각하면 됩니다. 다음과 같은 내용으로 구성되어 있습니다.

from setuptools import setup

package_name = 'ros_study_py'

setup(
    name=package_name,
    version='0.0.0',
    packages=[package_name],
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='dubook',
    maintainer_email='dubook@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        ],
    },
)

다음처럼 생긴 파일입니다. 

from setuptools import setup

package_name = 'ros_study_py'

setup(
    name=package_name,
    # ()안에 들어가는거라 이거 긁으면 작동 안됩니다. 패키지의 이름
    version='0.0.0',
    # 패키지의 버전
    packages=[package_name],
    # 의존하는 패키지 find_package()기입하면 알아서 패키지를 찾는다.
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    # package에서 사용하는 파일을 기입한다. ROS에서는 주로 resource 폴더 내에 있는 ament_index를
    # 위한 패키지의 이름의 빈 파일이나 package.xml, *.launch.py, *.yaml 등을 기입한다.
    install_requires=['setuptools'],
    # 의존하는 패키지, 이 패키지를 pip을 통해 설치할 때 이곳에 기술된 패키지들을 함께 설치하게 된다.
	# ROS에서는 pip로 설치하지 않기에 setuptools, launch만을 기입한다.
    zip_safe=True,
	# 설치시 zip파일로 아카이브 할지 여부
    maintainer='dubook',
    maintainer_email='dubook@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
 
    entry_points={
        'console_scripts': [
        ],
    },
    # 엔트리 포인트, 콘솔 프크립트를 설치하도록 콘솔 스크립트 이름과 호출 함수를 기입한다.
    # 여기 적히면 cmd에서 명령을 내릴 수 있다.
)

 

setup.cfg

ROS2 파이썬 패키지에서만 사용하는 배포를 위한 구성 파일

[develop]
script_dir=$base/lib/ros_study_py
[install]
install_scripts=$base/lib/ros_study_py

 

그 외 

plugin.xml, CHANGELOG.rst, LICENSE, README.md 와 같은 파일들이 있습니다.

 

 

본격적으로 코딩을 하기전에 우선적으로 패키지의 구성요소를 살펴보았습니다.. 어려운 내용이 계속 등장했으나, 이 부분은 하다보면 자연스럽게 관심이 가고, 하다보면서 자연스럽게 능숙해지는 부분입니다.