[ROS2] 프로그래밍 기초

송민영·2021년 12월 18일
0
post-thumbnail
post-custom-banner

rclpy로 파이썬을 활용하여 Topic, Publisher, Subscriber 작성하기

1. 패키지 생성

사용자 작업 폴더에 패키지를 생성한다.

$ ros2 pkg create [패키지이름] --build-type [빌드 타입] --dependencies [의존하는패키지1] [의존하는패키지n]
$ cd ~/ros2_dashing/src/
$ ros2 pkg create my_first_ros_rclpy_pkg --build-type ament_python --dependencies rclpy std_msgs

옵션

  • rclpy : ROS에서 파이썬을 사용하기 위한 클라이언트 라이브러리
  • std_msgs : 표준 메시지 패키지

해당 패키지 생성에 앞서 미리 설치해야 하는 의존 패키지들. 패키지 생성 시 위와 같이 지정할 수도 있지만, 생성한 다음 package.xml에서 직접 입력해도 된다.

생성 후 결과

  • 패키지 기본 구조
.
├── my_first_ros_rclpy_pkg
│   └── __init__.py
├── resource
│   └── my_first_ros_rclpy_pkg
├── test
│   ├── test_copyright.py
│   ├── test_flake8.py
│   └── test_pep257.py
├── package.xml
├── setup.cfg
└── setup.py

3 directories, 8 files

ament_cmake 인지, ament_python 인지에 따라 구성 파일 시스템이 달라짐.

package.xml, setup.cfg, setup.py는 패키지 생성 시 자동으로 생성된다.

2. 패키지 설정

package.xml

패키지 설정 파일. 사용할 RCL (ROS2 Client Libraries)에 따라 달라짐.

  • C++ → ament_cmake
  • python → ament_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>my_first_ros_rclpy_pkg</name>
  <version>0.0.2</version>
  <description>ROS 2 rclpy basic package for the ROS 2 seminar</description>
  <maintainer email="pyo@robotis.com">Pyo</maintainer>
  <license>Apache License 2.0</license>
  <author email="mikael@osrfoundation.org">Mikael Arguedas</author>
  <author email="pyo@robotis.com">Pyo</author>

  <depend>rclpy</depend>
  <depend>std_msgs</depend>

  <test_depend>ament_copyright</test_depend>
  <test_depend>ament_flake8</test_depend>
  <test_depend>ament_pep257</test_depend>
  <test_depend>python3-pytest</test_depend>

  <export>
    <build_type>ament_python</build_type>
  </export>
</package>

setup.py

파이썬 패키지 설정 파일.

entry_points 옵션의 console_scripts 키를 사용한 실행 파일 설정함. (각각의 콘솔 스크립트는 각 모듈의 main 함수를 호출함.)

  • helloworld_publisher → my_first_ros_rclpy_pkg.helloworld_publisher
  • helloworld_subscriber → my_first_ros_rclpy_pkg.helloworld_subscriber
from setuptools import find_packages
from setuptools import setup

package_name = 'my_first_ros_rclpy_pkg'

setup(
    name=package_name,
    version='0.0.2',
    packages=find_packages(exclude=['test']),
    data_files=[
        ('share/ament_index/resource_index/packages',
            ['resource/' + package_name]),
        ('share/' + package_name, ['package.xml']),
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    author='Mikael Arguedas, Pyo',
    author_email='mikael@osrfoundation.org, pyo@robotis.com',
    maintainer='Pyo',
    maintainer_email='pyo@robotis.com',
    keywords=['ROS'],
    classifiers=[
        'Intended Audience :: Developers',
        'License :: OSI Approved :: Apache Software License',
        'Programming Language :: Python',
        'Topic :: Software Development',
    ],
    description='ROS 2 rclpy basic package for the ROS 2 seminar',
    license='Apache License, Version 2.0',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
            'helloworld_publisher = my_first_ros_rclpy_pkg.helloworld_publisher:main',
            'helloworld_subscriber = my_first_ros_rclpy_pkg.helloworld_subscriber:main',
        ],
    },
)

setup.cfg

  • 패키지 이름을 기재해야함
  • /home/[user]/ros2_dashing/install/my_first_ros_rclpy_pkg/lib/my_first_ros_rclpy_pkg 와 같은 지정 폴더에 실행 파일이 생성됨
[develop]
script-dir=$base/lib/my_first_ros_rclpy_pkg
[install]
install-scripts=$base/lib/my_first_ros_rclpy_pkg

3. 퍼블리셔 노드 작성

  • 파일 위치 : ~/ros2_dashing/src/my_first_ros_rclpy_pkg/my_first_ros_rclpy_pkg/
  • 파일명 : helloworld_publisher.py
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile # 퍼블리셔의 QoS 설정 
from std_msgs.msg import String # 퍼블리시 메시지 타입 

class HelloworldPublisher(Node): # Node 클래스 상속

    def __init__(self):
        super().__init__('helloworld_publisher') # 노드 이름 지정 
        qos_profile = QoSProfile(depth=10) # 퍼블리시할 데이터를 버퍼에 10개까지 저장
        self.helloworld_publisher = self.create_publisher(String, 'helloworld', qos_profile)
				# 퍼블리셔 설정 : 토픽 메시지 타입, 이름, QoS 설정 
        self.timer = self.create_timer(1, self.publish_helloworld_msg)
				# 콜백함수 : n초마다 지정한 콜백함수 실행 
        self.count = 0

    def publish_helloworld_msg(self): 
        msg = String() # 퍼블리시할 메시지 
        msg.data = 'Hello World: {0}'.format(self.count) # 메시지 저장 
        self.helloworld_publisher.publish(msg) # 메시지 퍼블리시
        self.get_logger().info('Published message: {0}'.format(msg.data)) # 콘솔창에 출력 (==print함수) 
        # logger 종류 : debug, info, warning, error, fatal
				self.count += 1

def main(args=None):
    rclpy.init(args=args) # 초기화 
    node = HelloworldPublisher() 
    try:
        rclpy.spin(node) # 콜백함수 실행 
    except KeyboardInterrupt: # 'Ctrl+c'와 같은 인터럽트 시그널 예외 상황 
        node.get_logger().info('Keyboard Interrupt (SIGINT)')
    finally: 
        node.destroy_node() # 노드 소멸 
        rclpy.shutdown() # 함수 종료

if __name__ == '__main__':
    main()
  • 콜백 함수
    1. 다른 함수의 인자로써 이용되는 함수
    2. 어떤 이벤트에 의해 호출되어지는 함수

4. 서브스크라이버 노드 생성

  • 파일 위치 : ~/ros2_dashing/src/my_first_ros_rclpy_pkg/my_first_ros_rclpy_pkg/
  • 파일명 : helloworld_subscriber.py
import rclpy
from rclpy.node import Node
from rclpy.qos import QoSProfile
from std_msgs.msg import String

class HelloworldSubscriber(Node):

    def __init__(self):
        super().__init__('Helloworld_subscriber') # Node 클래스 생성자 호출
        qos_profile = QoSProfile(depth=10) # 서브스크라이브 데이터를 버퍼에 10개까지 저장
        self.helloworld_subscriber = self.create_subscription(
            String, # 토픽 메시지 타입
            'helloworld', # 토픽 이름
            self.subscribe_topic_message, # 콜백함수 
            qos_profile) # QoS 설정 
				# 받은 메시지는 msg.data에 저장

    def subscribe_topic_message(self, msg):
        self.get_logger().info('Received message: {0}'.format(msg.data))

def main(args=None):
    rclpy.init(args=args)
    node = HelloworldSubscriber()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        node.get_logger().info('Keyboard Interrupt (SIGINT)')
    finally:
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

5. 빌드

  • colcon 사용 소스 코드가 있는 workspace로 이동 → colcon build 명령어로 전체를 빌드
(워크스페이스내의 모든 패키지 빌드하는 방법) 
$ cd ~/robot_ws && colcon build --symlink-install

(특정 패키지만 빌드하는 방법)
$ cd ~/robot_ws && colcon build --symlink-install --packages-select [패키지 이름1] [패키지 이름2] [패키지 이름N]

(특정 패키지 및 의존성 패키지를 함께 빌드하는 방법)
$ cd ~/robot_ws && colcon build --symlink-install --packages-up-to [패키지 이름]
  • 튜토리얼 코드 빌드 예시
$ cd ~/robot_ws
$ colcon build --symlink-install --packages-select my_first_ros_rclpy_pkg

Starting >>> my_first_ros_rclpy_pkg
Finished <<< my_first_ros_rclpy_pkg [0.66s]

Summary: 1 package finished [0.87s]
  • 첫 빌드 때에는 환경 설정 파일을 불러와서 실행 가능한 패키지의 노드 설정들을 해줘야함.
. ~/robot_ws/install/local_setup.bash

6. 실행

각 터미널 창에서 아래 코드 실행

$ ros2 run my_first_ros_rclpy_pkg helloworld_subscriber
$ ros2 run my_first_ros_rclpy_pkg helloworld_publisher
post-custom-banner

0개의 댓글