04장 Build system

  • 77Creating a launch file

https://index.ros.org/doc/ros2/Tutorials/Launch-Files/Creating-Launch-Files/#ros2launch

  • Writing a simple publisher and subscriber (Python)

https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Py-Publisher-And-Subscriber/#pypubsub

  • Writing a simple publisher and subscriber (C++)

https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber/#cpppubsub 발표자 : 권준호, 김효민참석자 : 최규남, 류정필, 이태용, 김효민,김경남,박정은,안지훈, 김진성, 이창환, Yu Minsang,SANGYONG, 최종우,정하정

+ Build system 1-1

ROS2를 사용하기전에 작업환경을 구축함.실행을 하기전에 ROS2가 설치 되어있어야 함.

기본자료

https://www.theconstructsim.com/ros2-in-5-mins-007-how-to-create-a-ros2-overlay-workspace/ https://index.ros.org/doc/ros2/Tutorials/Workspace/Creating-A-Workspace/#ros2workspace

디렉토리생성

$ mkdir -p ros2_ws/src && cd ros2_ws

위 코드를 입력하게 되면 다음과 같이 ros2_ws이름의 디렉토리가가 생성 및 디렉토리 안으로 들어가는 것을 볼 수 있음

colcon에 대하여

colcon 은 ROS를 위한 범용 빌드 툴로서 개발되고 있는 툴이다. 이 툴은 ROS1, ROS2, 비 ROS 소프트웨어까지 모두 포괄하여 사용할 수 있도록 설계되었고, 기존에 설명한 catkin_make, catkin_make_isolated, catkin_tools, ament_tools 의 모든 기능을 사용 할 수 있도록 개발되고 있다.

colcon사용법

colcon 사용법 및 옵션들은 기존 툴들과 호환된다. 그 사용법에 대한 설명은 아래의 링크로 대신한다. 원론적으로 왜 이 범용 빌드 툴이 나오게 되었는지에 대한 고민과 의견 수렴에 대해서는 사용자 입장에서는 그렇게 크게 중요하지 않다고 생각한다. 우리에게 더 중요한 자세한 사용 방법은 이어지는 ROS2 실제 프로그래밍에서 더 깊숙히 파헤쳐 보도록 하자. https://cafe.naver.com/openrt/18732 http://design.ros2.org/articles/build_tool.html http://colcon.readthedocs.io/ https://github.com/colcon https://github.com/ros2/ros2/wiki/Colcon-Tutorial https://colcon.readthedocs.io/en/latest/migration/ament_tools.html https://colcon.readthedocs.io/en/latest/migration/catkin_make_isolated.html https://colcon.readthedocs.io/en/latest/migration/catkin_tools.html

$ colcon build

위의 코드를 입력 하게 되면 다음과 같이 나타나는것을 볼 수 있다

다만, 처음 colcon build를 입력하게 된다면 오류 메시지가 뜰 수 있다. 이 경우

$ sudo apt install python3-colcon-common-extensions를 통해 해결할 수 있다.

ll (ls-l) 를 입력하여 현재 디렉토리의 자세한 내용을 알아보자

마지막으로 다음 자료를 다운 받으면 기초적인 개발환경 구축이 완료된다.

$ source install/local_setup.bash && source install/setup.bash

+ Build system 1-2

빌드에 앞서 다음 코드를 이용해 설치 한다.

$ sudo apt install git-all
$ sudo apt update

디렉토리 생성

먼저 dev_ws(development workspace) 라는 이름의 디렉토리를 생성후 디렉토리에 접속해보자.

$ mkdir dev_ws
$ mkdir dev_ws/src
$ cd dev_ws/src

샘플복제

샘플을 복제하기전 dev_ws/src에 들어가 있어야 함. dev_ws/src디렉토리에 들어가 있을 경우, 다음 명령어를 통해 ros_tutorials를 복제해 보자

$ git clone https://github.com/ros/ros_tutorials.git -b eloquent-devel

이렇게 복제를 완료한 뒤에 ros_tutorials list를 확인해 보면 다음과 같이 나타나는 것을 볼 수 있다.

$ cd dev_ws/src
$ ls ros_tutorials

작업 공간을 샘플 패키지로 채웠으나 아직 완전히 작동하는 작업 공간은 아니다. 종속성을 해결하고 작업 공간을 먼저 구축해야 한다.

패키지 종속 해결

작업 공간을 구축하기 전 패키지 종속성을 해결해야 한다. 이미 모든 종속성을 가지고 있을 수 있지만, 최선의 방법은 복제할 때마다 종속성을 확인하는 것이다.

다음의 명령을 통해 종속을 해결할 수 있다.

$ sudo rosdep install -i --from-path src --rosdistro dashing -y

다만 그 전에 rosdep가 설치되어있지 않다면 정상적으로 작동되지 않을것이다다음과 같이 ros dep 를 설치하자

$ sudo apt-get install python-rosdep
$ sudo rosdep init
$ rosdep update

colcon build를 통해 작업환경 구축

이후 colcon build를 이용하여 명령을 내리면 다음과 같은 결과를 얻을 수 있다.

Overlay 수정

turtlesim 창의 제목 표시줄을 편집하여 오버레이에서 turtlesim을 수정할 수 있다. 다음의 디렉토리 내에서 turtle_frame.cpp텍스트를 수정해보자.

$ cd dev_ws/src/ros_tutorials/turtlesim/src
$ gedit turtle_frame.cpp

turtle_frame.cpp텍스트에 들어갔다면 setWindowTitle("TurtleSim") ”TurtleSim” ”MyTurtleSim” 로 수정하고 저장하자

#include "turtlesim/turtle_frame.h"

#include <QPointF>

#include <cstdlib>
#include <ctime>

#define DEFAULT_BG_R 0x45
#define DEFAULT_BG_G 0x56
#define DEFAULT_BG_B 0xff
https://www.icbanq.com/A03_webinar/B01_webiWork/seminar_view.do?seminar_number=403https://www.icbanq.com/A03_webinar/B01_webiWork/seminar_view.do?seminar_number=403
namespace turtlesim
{

TurtleFrame::TurtleFrame(rclcpp::Node::SharedPtr& node_handle, QWidget* parent, Qt::WindowFlags f)
: QFrame(parent, f)
, path_image_(500, 500, QImage::Format_ARGB32)
, path_painter_(&path_image_)
, frame_count_(0)
, id_counter_(0)
{
  setFixedSize(500, 500);
  setWindowTitle("TurtleSim");

  srand(time(NULL));

  update_timer_ = new QTimer(this);
  update_timer_->setInterval(16);
  update_timer_->start();

  connect(update_timer_, SIGNAL(timeout()), this, SLOT(onUpdate()));

  nh_ = node_handle;
  rcl_interfaces::msg::IntegerRange range;
  range.from_value = 0;
  range.to_value = 255;
 중략..._value = 255;
 중략...

이후 이전에 colcon build를 실행한 터미널 창으로 돌아가 colcon build를 재실행한다. 다음을 통해 주 ROS 2 환경을 "언더레이"로 제공하므로 오버레이를 "위에" 구축할 수 있다

$ source /opt/ros/dashing/setup.bash

그후 dev_ws디렉토리에서 오버레이를 소싱한다

$. install/local_setup.bash

+ Creating a launch file

노드를 실행할 때 마다 terminal을 새로 열어서 실행을 한다는 것은 귀찮은 일임.여러노드를 한번에 열수 있게 Launch file을 제공함.

$ mkdir launch
$ touch turtlesim_mimic_launch.py

turtlesim_mimic_launch.py

from  launch import LaunchDescription
from launch_ros.actions import Node

def generate_launch_description():
    return LaunchDescription([
        Node(
            package='turtlesim',
            node_namespace='turtlesim1',
            node_executable='turtlesim_node',
            node_name='sim'
        ),
        Node(
            package='turtlesim',
            node_namespace='turtlesim2',
            node_executable='turtlesim_node',
            node_name='sim'
        ),
        Node(
            package='turtlesim',
            node_executable='mimic',
            node_name='mimic',
            remappings=[
                ('/input/pose', '/turtlesim1/turtle1/pose'),
                ('/output/cmd_vel', '/turtlesim2/turtle1/cmd_vel'),
            ]
        )
    ])

위의 sim node가 동일해 보이지만 node_namespace로 구분되기 때문에 괜찮음.

https://github.com/ros/ros_tutorials/blob/melodic-devel/turtlesim/tutorials/mimic.cpp

mimic node의 경우 remapping을 사용하는 것을 살펴보면,mimic의 /input/pose topic을 /turtlesim1/turtle1/pose로 /output/cmd_vel topic을 /turtlesim2/turtle1/cmd_vel로 재설정 함.

결국 /turtlesim1/turtle1/pose(위치)가 mimic의 /input/pose 입력으로 들어가고 mimic의 출력 /output/cmd_vel(속도)이 /turtlesim2/turtle1/cmd_vel로 연결된다.

$ ros2 launch turtlesim_mimic_launch.py

* 실행시 turtlesim이 설치되어 있어야 동작 되는 것으로 보임.

$ sudo apt install ros-dashing-turtlesim

rqt_graph로 현재 node의 관계를 좀더 직관적으로 살펴볼수 있다.

$ rqt_graph

실제 동작을 확인해 보자.

$ ros2 topic pub -r 1 /turtlesim1/turtle1/cmd_vel geometry_msgs/msg/Twist '{linear: {x: 2.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: -1.8}}'

rqt_graph에 Group을 0으로 설정하면 예와 동일하게 출력됨.

+ Creating a ROS 2 package

기본 자료 : https://index.ros.org/doc/ros2/Tutorials/Creating-A-ROS2-Package/#createpkg

패키지에 대하여

패키지는 ROS 2 코드를 위한 컨테이너라고 생각할 수 있다. 만약 코드를 설치하거나 다른 사람들과 공유할 수 있기를 원한다면, 그것을 패키지로 정리해야 한다. 이것으로, 자신의 작품을 공유할 수 있고 다른 사람들이 그것을 쉽게 만들고 사용할 수 있게 할 수 있다. ROS 2의 패키지 생성은 ament를 빌드 시스템으로, colcon을 빌드 도구로 사용한다. 다른 빌드 유형이 존재하나 공식적으로 지원되는 CMake 또는 Python을 사용하여 패키지를 생성할 수 있다.

패키지 생성

다음과 같이 dev_ws/src 디렉토리 내에서 패키지를 생성한다

$ ros2 pkg create --build-type ament_cmake --node-name my_node my_package

이 튜토리얼의 경우 패키지에 간단한 Hello World 유형 실행 파일을 생성하는 선택적 인수 --node-name을 사용한다. 다음의 명령어를 통해 본 메시지를 받게된다.이 를통해 새 패키지에 대해 자동으로 생성된 파일을 볼 수 있다

패키지 구축

작업영역에 패키지를 넣는 것은 작업영역 루트에서 콜콘 빌드를 실행하여 한 번에 많은 패키지를 만들 수 있기 때문에 특히 중요하다. 그렇지 않으면 각 패키지를 개별적으로 만들어야 할 것이다.

다음 번에 my_package 패키지만 구축하려면 다음을 실행하십시오.

$ colcon build --packages-select my_package

그런 다음 dev_ws 디렉터리 내부에서 다음 명령을 실행하여 작업 공간을 소싱한다.

$ . install/setup.bash

이제 작업 공간이 경로에 추가되었으므로 새 패키지의 실행 파일을 사용할 수 있다. 패키지 생성 중 --node-name 인수를 사용하여 생성한 실행 파일을 실행하려면 다음 명령을 입력한다.

$ ros2 run my_package my_node

그결과 다음과 같은 메시지를 받게 된다. dev_ws/src/my_package 내부에는 자동으로 생성된 2pkg의 파일과 폴더가 표시된다.

CMakeLists.txt  include  package.xml  src
 Customize package.xml
<?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_package</name>
 <version>0.0.0</version>
 <description>TODO: Package description</description>
 <maintainer email="user@todo.todo">user</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>

내용중 7번 라인이자동으로 채워지지 않은 경우 7번 라인에 이름과 이메일을 입력하십시오. 그런 다음 라인 6에서 다음 설명을 편집하여 패키지를 요약한다.

<description>Beginner developer tutorials practice package</description>

그다음, 다음과 같이 8번라인의 라이센스를 업데이트한다

<license>Apache License 2.0</license>

라이센스 태그 아래에 _depended로 끝나는 태그 이름이 있다. 여기가 package.xml이 colcon을 검색할 다른 패키지에 대한 의존성을 나열할 것이다. my_package는 단순하고 의존성이 전혀 없지만 이 공간이 다가오는 튜토리얼에서 활용되고 있는 것을 볼 수 있을 것이다.

+ Writing a simple publisher and subscriber (Python)

topic으로 string message를 처리하는 node를 작성한다.

rclpy

http://docs.ros2.org/eloquent/api/rclpy/

create_publisher(msg_type, topic, qos_profile, *, callback_group=None, event_callbacks=None)Create a new publisher.Parameters

  • msg_type – The type of ROS messages the publisher will publish.

  • topic (str) – The name of the topic the publisher will publish to.

  • qos_profile (Union[QoSProfile, int]) – A QoSProfile or a history depth to apply to the publisher. In the case that a history depth is provided, the QoS history is set to RMW_QOS_POLICY_HISTORY_KEEP_LAST, the QoS history depth is set to the value of the parameter, and all other QoS settings are set to their default values.

  • callback_group (Optional[CallbackGroup]) – The callback group for the publisher’s event handlers. If None, then the node’s default callback group is used.

  • event_callbacks (Optional[PublisherEventCallbacks]) – User-defined callbacks for middleware events.

Return typePublisherReturnsThe new publisher.

create_subscription(msg_type, topic, callback, qos_profile, *, callback_group=None, event_callbacks=None, raw=False)Create a new subscription.Parameters

  • msg_type – The type of ROS messages the subscription will subscribe to.

  • topic (str) – The name of the topic the subscription will subscribe to.

  • callback (Callable[[~MsgType], None]) – A user-defined callback function that is called when a message is received by the subscription.

  • qos_profile (Union[QoSProfile, int]) – A QoSProfile or a history depth to apply to the subscription. In the case that a history depth is provided, the QoS history is set to RMW_QOS_POLICY_HISTORY_KEEP_LAST, the QoS history depth is set to the value of the parameter, and all other QoS settings are set to their default values.

  • callback_group (Optional[CallbackGroup]) – The callback group for the subscription. If None, then the nodes default callback group is used.

  • event_callbacks (Optional[SubscriptionEventCallbacks]) – User-defined callbacks for middleware events.

  • raw (bool) – If True, then received messages will be stored in raw binary representation.

Return typeSubscription

rclpy.spin(node, executor=None)Execute work and block until the context associated with the executor is shutdown.Callbacks will be executed by the provided executor.This function blocks.Parameters

  • node (Node) – A node to add to the executor to check for work.

  • executor (Executor) – The executor to use, or the global executor if None.

Return typeNone

publish(msg)Send a message to the topic for the publisher.Parametersmsg (~MsgType) – The ROS message to publish.RaisesTypeError if the type of the passed message isn’t an instance of the provided type when the publisher was constructed.Return typeNone

$ ros2 pkg create --build-type ament_python py_pubsub

$ wget https://raw.githubusercontent.com/ros2/examples/master/rclpy/topics/minimal_publisher/examples_rclpy_minimal_publisher/publisher_member_function.py 

$ wget 
https://raw.githubusercontent.com/ros2/examples/master/rclpy/topics/minimal_subscriber/examples_rclpy_minimal_subscriber/subscriber_member_function.py 

$ ls
__init__.py  publisher_member_function.py

$ tree
.
├── package.xml
├── py_pubsub
│   ├── __init__.py
│   ├── publisher_member_function.py
│   └── subscriber_member_function.py
├── resource
│   └── py_pubsub
├── setup.cfg
├── setup.py
└── test
    ├── test_copyright.py
    ├── test_flake8.py
    └── test_pep257.py

publisher_member_function.py

Column 1

import rclpyfrom rclpy.node import Node from std_msgs.msg import String class MinimalPublisher(Node):=> Node를 상속받아서 새로운 class를 생성 def __init__(self): super().__init__('minimal_publisher') => 부모 class에게 현재 Node name 전달 self.publisher_ = self.create_publisher(String, 'topic', 10) => node publisher가 Message type String을 사용하고 ‘topic’ 이라는 topic name을 사용하며 queue의 크기 10 으로 정의함. timer_period = 0.5 # seconds self.timer = self.create_timer(timer_period, self.timer_callback) => 0.5초 마다 callback 함수를 호출하도록 timer 설정 self.i = 0 def timer_callback(self): msg = String() msg.data = 'Hello World: %d' % self.i => message 정의 self.publisher_.publish(msg) => message 전송 self.get_logger().info('Publishing: "%s"' % msg.data) => console에 출력 self.i += 1 def main(args=None): rclpy.init(args=args) minimal_publisher = MinimalPublisher() rclpy.spin(minimal_publisher) # Destroy the node explicitly # (optional - otherwise it will be done automatically # when the garbage collector destroys the node object) minimal_publisher.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

Column 1

import rclpyfrom rclpy.node import Node from std_msgs.msg import String class MinimalSubscriber(Node):=> Node를 상속받아서 새로운 class를 생성 def __init__(self): super().__init__('minimal_subscriber') self.subscription = self.create_subscription( String, 'topic', self.listener_callback, 10) => create_publish()와의 차이점은 message 수신시 대응할 callback 함수만 연결해 주면 된다. self.subscription # prevent unused variable warning def listener_callback(self, msg): self.get_logger().info('I heard: "%s"' % msg.data) => 수신한 message를 console에 출력함. def main(args=None): rclpy.init(args=args) minimal_subscriber = MinimalSubscriber() rclpy.spin(minimal_subscriber) # Destroy the node explicitly # (optional - otherwise it will be done automatically # when the garbage collector destroys the node object) minimal_subscriber.destroy_node() rclpy.shutdown() if __name__ == '__main__': main()

Column 1

<?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>py_pubsub</name> <version>0.0.0</version> <description>Examples of minimal publisher /subscriber using rclpy</description> <maintainer email="mrthinks@gmail.com">mrthink</maintainer> <license>Apache License 2.0</license> <buildtool_depend>ament_python</buildtool_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> <exec_depend>rclpy</exec_depend> <exec_depend>std_msgs</exec_depend> </export></package>

수정 사항중 dependency부부은 python code에서 import하는 python package를 추가하면 된다.

Column 1

from setuptools import setup package_name = 'py_pubsub' 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='mrthink', maintainer_email='mrthinks@gmail.com', description='Examples of minimal publisher/subscriber using rclpy', license='Apache License 2.0', tests_require=['pytest'], entry_points={ 'console_scripts': [ 'talker = py_pubsub.publisher_member_function:main', 'listener = py_pubsub.subscriber_member_function:main', ], },)

Column 1

setup.cfg는 수정없이 사용. setuptool에게 생성한 실행결과물이 lib 디렉토리에 있다고 알려줌. 새로운 package build를 하자.$ colcon build --packages-select py_pubsub 이제 두 node의 동작을 확인하자.$ . install/setup.bash$ ros2 run py_pubsub talker $ . install/setup.bash$ ros2 run py_pubsub listener

+ Writing a simple publisher and subscriber (C++)

전체 흐름은 python과 동일함. $ ros2 pkg create --build-type ament_cmake cpp_pubsub $ wget -O publisher_member_function.cpp https://raw.githubusercontent.com/ros2/examples/master/rclcpp/minimal_publisher/member_function.cpp $ wget -O subscriber_member_function.cpp https://raw.githubusercontent.com/ros2/examples/master/rclcpp/minimal_subscriber/member_function.cpp $ tree.├── CMakeLists.txt├── include│ └── cpp_pubsub├── package.xml└── src ├── publisher_member_function.cpp └── subscriber_member_function.cpp https://github.com/ros2/rclcpp: rclcpp provides the standard C++ API for interacting with ROS 2.

Column 1

#include <chrono>#include <memory>#include "rclcpp/rclcpp.hpp"#include "std_msgs/msg/string.hpp"using namespace std::chrono_literals;/* This example creates a subclass of Node and uses std::bind() to register a * member function as a callback from the timer. */class MinimalPublisher : public rclcpp::Node{public: MinimalPublisher() : Node("minimal_publisher"), count_(0) => count_를 0으로 초기화 { publisher_ = this->create_publisher<std_msgs::msg::String>("topic", 10); => Message type으로 String을 사용하고 topic 이름을 "topic"으로 정하고 queue 크기를 10으로 설정함. timer_ = this->create_wall_timer( 500ms, std::bind(&MinimalPublisher::timer_callback, this)); => 0.5초마다 callback 함수를 호출하도록 설정함. }private: void timer_callback() { auto message = std_msgs::msg::String(); message.data = "Hello, world! " + std::to_string(count_++); => message 생성. RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str()); => console에 내용 출력. publisher_->publish(message); => Message 발송. } rclcpp::TimerBase::SharedPtr timer_; rclcpp::Publisher<std_msgs::msg::String>::SharedPtr publisher_; size_t count_;};int main(int argc, char * argv[]){ rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<MinimalPublisher>()); rclcpp::shutdown(); return 0;}

Column 1

#include <memory> #include "rclcpp/rclcpp.hpp" #include "std_msgs/msg/string.hpp" using std::placeholders::_1; class MinimalSubscriber : public rclcpp::Node { public: MinimalSubscriber() : Node("minimal_subscriber") { subscription_ = this->create_subscription<std_msgs::msg::String>( "topic", 10, std::bind(&MinimalSubscriber::topic_callback, this, _1)); } private: void topic_callback(const std_msgs::msg::String::SharedPtr msg) const { RCLCPP_INFO(this->get_logger(), "I heard: '%s'", msg->data.c_str()); } rclcpp::Subscription<std_msgs::msg::String>::SharedPtr subscription_; }; int main(int argc, char * argv[]) { rclcpp::init(argc, argv); rclcpp::spin(std::make_shared<MinimalSubscriber>()); rclcpp::shutdown(); return 0; }

Column 1

<?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_package2</name> <version>0.0.0</version> <description>Beginner developer tutorials practice package</description> <maintainer email="mrthinks@gmail.com">mrthink</maintainer> <license>Apache License 2.0</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> <exec_depend>rclcpp</exec_depend> <exec_depend>std_msgs</exec_depend> </export></package>

Column 1

cmake_minimum_required(VERSION 3.5)project(cpp_pubsub)# Default to C99if(NOT CMAKE_C_STANDARD) set(CMAKE_C_STANDARD 99)endif()# Default to C++14if(NOT CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 14)endif()if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") add_compile_options(-Wall -Wextra -Wpedantic)endif()# find dependenciesfind_package(ament_cmake REQUIRED)find_package(rclcpp REQUIRED)find_package(std_msgs REQUIRED)# uncomment the following section in order to fill in# further dependencies manually.# find_package(<dependency> REQUIRED)add_executable(talker src/publisher_member_function.cpp)ament_target_dependencies(talker rclcpp std_msgs)add_executable(listener src/subscriber_member_function.cpp)ament_target_dependencies(listener rclcpp std_msgs)install(TARGETS talker listener DESTINATION lib/${PROJECT_NAME})if(BUILD_TESTING) find_package(ament_lint_auto REQUIRED) # the following line skips the linter which checks for copyrights # uncomment the line when a copyright and license is not present in all source files #set(ament_cmake_copyright_FOUND TRUE) # the following line skips cpplint (only works in a git repo) # uncomment the line when this package is not in a git repo #set(ament_cmake_cpplint_FOUND TRUE) ament_lint_auto_find_test_dependencies()endif()ament_package()

$ sudo rosdep install -i --from-path src --rosdistro dashing -y $ colcon build --packages-select cpp_pubsub $ . install/setup.bash$ ros2 run cpp_pubsub listener $ . install/setup.bash$ ros2 run cpp_pubsub talker ls

+ 미션

Last updated