2 분 소요

패키지 생성

$ ros2 pkg create [패키지 이름] --build-type [빌드 타입] --dependencies [의존하는 패키지1] [의존하는 패키지n]

dependencies를 설정하는 것은 패키지의 기능을 그대로 사용한다고 이해하면 된다.

패키지를 생성할 때 옵션으로 달아주지 않았다면 패키지를 생성한 후에도 package.xml에서 설정할 수 있다.

빌드 설정

(생성한 패키지에 helloworld_publisher, helloworld_subscriber 두 노드를 바탕으로 설명한다.)

패키지의 사용자 작업환경 디렉토리에서 CMakeLists.txt에 다음과 같이 추가를 해준다.

Screenshot from 2024-02-05 17-38-05

퍼블리셔 노드 작성

패키지의 사용자 작업환경 디렉토리에서 소스파일을 다음과 같이 작성한다.

#include <chrono>
#include <functional>
#include <memory>
#include <string>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using namespace std::chrono_literals;

class HelloworldPublisher : public rclcpp::Node
{
  public:
    HelloworldPublisher()
    : Node("helloworld_publisher"), count_(0)
    {
      auto qos_profile = rclcpp::QoS(rclcpp::KeepLast(10)); // 클래스 생성자의 로컬 변수, 퍼블리셔를 생성할 때만 사용한다. 
      helloworld_publisher_ = this->create_publisher<std_msgs::msg::String>(
        "helloworld", qos_profile); // 토픽의 타입, 토픽의 이름, qos 설정
        timer_ = this->create_wall_timer(
          1s, std::bind(&HelloworldPublisher::publish_helloworld_msg, this)); // 콜백함수를 설정, 1초마다 publish
    }

    private:
      void publish_helloworld_msg() // 콜백함수
      {
        auto msg = std_msgs::msg::String();
        msg.data = "Hello World: " + std::to_string(count_++);
        RCLCPP_INFO(this->get_logger(), "Published message: '%s'", msg.data.c_str());
        helloworld_publisher_->publish(msg);
      }

      rclcpp::TimerBase::SharedPtr timer_;
      rclcpp::Publisher<std_msgs::msg::String>::SharedPtr helloworld_publisher_;
      size_t count_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<HelloworldPublisher>(); //HelloworldPublisher 타입의 객체를 생성하고, 이 객체를 가리키는          std::shared_ptr<T>를 반환
  rclcpp::spin(node); // 노드를 실행
  rclcpp::shutdown();
  return 0;
}

자세한 설명은 책을 참고하도록 하자!

서브스크라이버 노드 작성

#include <functional>
#include <memory>

#include "rclcpp/rclcpp.hpp"
#include "std_msgs/msg/string.hpp"

using std::placeholders::_1; //인수를 고정하는 place holder

class HelloworldSubscriber : public rclcpp::Node
{
public:
  HelloworldSubscriber()
  : Node("Helloworld_subscriber")
  {
    auto qos_profile = rclcpp::QoS(rclcpp::KeepLast(10));
    helloworld_subscriber_ = this->create_subscription<std_msgs::msg::String>( // interface 지정
      "helloworld", // 토픽 이름
      qos_profile,
      std::bind(&HelloworldSubscriber::subscribe_topic_message, this, _1)); // 콜백함수 지정 이 때 콜백함수가 msg를 첫번째 인자로 받기
      																		// 때문에 _1 place holder를 지정한다. 
  }

private:
  void subscribe_topic_message(const std_msgs::msg::String::SharedPtr msg) const
  {
    RCLCPP_INFO(this->get_logger(), "Received message: '%s'", msg->data.c_str());
  }
  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr helloworld_subscriber_;
};

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);
  auto node = std::make_shared<HelloworldSubscriber>();
  rclcpp::spin(node);
  rclcpp::shutdown();
  return 0;
}

빌드

$ cd ~/workspace && colcon build --symlink-install
$ cd ~/workspace && colcon build --symlink-install --packages-select [패키지이름1][패키지이름N] #선택적으로 빌드를 한다.

실행

$ ros2 run my_first_ros_rclcpp_pkg helloworld_subscriber # tab을 눌러주면서 하면 빠르게 패키지와 노드를 선택할 수 있다. 
$ ros2 run my_first_ros_rclcpp_pkg helloworld_publisher

실행을 하기 위해서는 setup script를 사용해야 한다.

~/.bashrc에 저장후 사용하거나 alias를 이용한다.

$ source ~/workspace/install/local_setup.bash

일반적으로는 underlay 개발환경의 setup.bash를 우선 소싱한 후 자신의 워크스페이스인 overlay 개발환경의 local_setup.bash를 소싱한다.

$ source /opt/ros/버전/setup.bash # underlay 개발환경 setup.bash 소싱
$ source ~/workspace/install/local_setup.bash # overlay 개발환경 setup.bash 소싱

# 위와 동일
$ source ~/workspace/install/setup.bash # 워크스페이스 뿐만 아니라 설치된 개발환경의 경로를 포함하도록 환경을 설정

ROS_DOMAIN_ID, Namespace

ROS_DOMAIN_ID

기본적으로 물리적으로 다른 네트워크를 쓴다면 독립적으로 작업할 수 있지만, 그럴 수 없다면 Domain을 다르게 설정한다.

같은 도메인에 있는 토픽들에 대해 퍼블리시 및 서브스크라이브를 할 수 있다.

$ export ROS_DOMAIN_ID=11 # 기본적으로 0~101의 정수를 사용한다.

Namespace

노드 이름에 Namespace를 붙혀주어 자신만의 네트워크를 그룹화 할 수 있다.

$ ros2 run turtlesim turtlesim_node --ros-args -r __ns:=/robot1
$ ros2 run turtlesim turtlesim_node --ros-args -r __ns:=/robot2

두 노드는 각 다른 Namespace에서 독립적으로 존재해 충돌하지 않는다.

댓글남기기