ROS 2.0 기반 QT Widget 빌드용 CMakeFileList.txt

|

ROS 2.0 with QT

ROS 2.0에서 QT Widget 프로그램을 빌드하는 방법에 대해 포스팅합니다.

먼저 QT Widget 샘플 코드입니다. QTCreator를 이용해서 생성한 프로젝트라서 mainwindow.h, mainwindow.cpp, mainwindow.ui 등의 파일도 생성이 되는데 여기서는 CMakeLists.txt 파일에 대해서만 포스팅합니다.

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(qt_widget)

set(REQUIRED_QT_VERSION 5.9.0)

# Default to C++14
if(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 -fPIC)
endif()

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(Qt5Core REQUIRED)
find_package(Qt5Widgets REQUIRED)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

add_executable(${PROJECT_NAME} main.cpp mainwindow.cpp)

ament_target_dependencies(${PROJECT_NAME} rclcpp Qt5Core Qt5Widgets)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()

QT Console 프로그램을 ROS 2.0으로 빌드하기

|

ROS 2.0 with QT

ROS 2.0에서 QT 콘솔 프로그램을 빌드하는 방법에 대해 포스팅합니다.

먼저 QT 콘솔 샘플 코드입니다.

main.cpp

#include <QCoreApplication>
#include <QDebug>

int main(int argc, char *argv[]) {
  QCoreApplication a(argc, argv);

  qDebug() << "snowdeer QT Console";

  return a.exec();
}


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(qt_console)

set(REQUIRED_QT_VERSION 5.9.0)

# Default to C++14
if(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 -fPIC)
endif()

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTOUIC ON)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

find_package(Qt5Core REQUIRED)
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)

ament_target_dependencies(${PROJECT_NAME} rclcpp Qt5Core)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()

Simple Message Publisher 및 Subscriber 예제 (Node 클래스 상속)

|

간단하게 메시지를 발행/수신하는 예제 코드는 다음과 같습니다.

snow_publisher_using_class

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_publisher</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Publisher</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_publisher_using_class)

# Default to C++14
if(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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

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

using namespace std;
using namespace std::chrono_literals;

class SnowPublisher : public rclcpp::Node {
public:
  SnowPublisher()
  : Node("minimal_publisher") {
    mCount = 0;
    mPublisher = this->create_publisher<std_msgs::msg::String>("snowdeer_channel");
    mTimer = this->create_wall_timer(
      1000ms, std::bind(&SnowPublisher::publish_message, this));
  }

private:
  int mCount;
  rclcpp::TimerBase::SharedPtr mTimer;
  rclcpp::Publisher<std_msgs::msg::String>::SharedPtr mPublisher;
  
  void publish_message();
 
};

void SnowPublisher::publish_message() {
  mCount++;

  auto message = std_msgs::msg::String();
  message.data = "Hello, SnowDeer! " + std::to_string(mCount);

  RCLCPP_INFO(this->get_logger(), "Publishing: '%s'", message.data.c_str())
  mPublisher->publish(message);
}

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Publisher.\n");

  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SnowPublisher>());
  rclcpp::shutdown();

  return 0;
}


snow_subscriber_using_class

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_subscriber</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Subscriber</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_subscriber_using_class)

# Default to C++14
if(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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

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

using namespace std;
using std::placeholders::_1;

class SnowSubscriber : public rclcpp::Node {
public:
  SnowSubscriber()
  : Node("snowdeer_msg_subscriber") {
    mSubscriber = this->create_subscription<std_msgs::msg::String>(
      "snowdeer_channel", std::bind(&SnowSubscriber::receive_message, this, _1));
  }

private:
  rclcpp::Subscription<std_msgs::msg::String>::SharedPtr mSubscriber;

  void receive_message(const std_msgs::msg::String::SharedPtr msg);
  
};

void SnowSubscriber::receive_message(const std_msgs::msg::String::SharedPtr msg) {
  RCLCPP_INFO(this->get_logger(), "Received Message: '%s'", msg->data.c_str())
}

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Subscriber.\n");

  rclcpp::init(argc, argv);
  rclcpp::spin(std::make_shared<SnowSubscriber>());
  rclcpp::shutdown();

  return 0;
}

Simple Message Publisher 및 Subscriber 예제

|

간단하게 메시지를 발행/수신하는 예제 코드는 다음과 같습니다.

snowdeer_publisher

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_publisher</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Publisher</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_publisher)

# Default to C++14
if(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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

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

using namespace std;
using namespace std::chrono_literals;

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Publisher.\n");

  rclcpp::init(argc, argv);
  auto node = rclcpp::Node::make_shared("snowdeer_msg_publisher");
  auto publisher = node->create_publisher<std_msgs::msg::String>("snowdeer_topic");
  auto message = std::make_shared<std_msgs::msg::String>();
  auto publish_count = 0;

  rclcpp::WallRate loop_rate(1000ms);

  while (rclcpp::ok()) {
    message->data = "Hello, SnowDeer! " + std::to_string(publish_count++);

    RCLCPP_INFO(node->get_logger(), "Publishing: '%s'", message->data.c_str())
    publisher->publish(message);
    
    rclcpp::spin_some(node);

    loop_rate.sleep();
  }

  rclcpp::shutdown();
  
  return 0;
}


snowdeer_subscriber

package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>snow_subscriber</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Subscriber</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>
  <build_depend>std_msgs</build_depend>

  <exec_depend>rclcpp</exec_depend>
  <exec_depend>std_msgs</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_subscriber)

# Default to C++14
if(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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

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

using namespace std;

rclcpp::Node::SharedPtr node = nullptr;

void callback_from_topic(const std_msgs::msg::String::SharedPtr msg) {
  RCLCPP_INFO(node->get_logger(), "Received Message: '%s'", msg->data.c_str())
}

int main(int argc, char * argv[]) {
  
  printf("This is SnowDeer's ROS Message Subscriber.\n");

  rclcpp::init(argc, argv);
  node = rclcpp::Node::make_shared("snowdeer_msg_subscriber");

  auto subscription = node->create_subscription<std_msgs::msg::String>
      ("snowdeer_topic", callback_from_topic);

  rclcpp::spin(node);
  rclcpp::shutdown();

  node = nullptr;

  return 0;
}

Hello, ROS 예제 코드

|

패키지 구성

ROS 2.0의 각 노드의 패키지 구성은 다음과 같습니다.

  • package.xml
  • CMakeLists.txt
  • 소스 코드들

package.xml은 안드로이드의 manifest.xml과 같은 역할을 하며, 노드의 이름이나 라이센스, 설명 등의 내용이 들어있습니다.

CMakeLists.txt는 ROS2 만의 독특한 명령어가 조금 들어있긴 하지만 기본적으로 일반적인 CMakeLists 파일과 거의 유사합니다.

‘Hello, ROS’의 예제 코드는 다음과 같습니다. ROS적인 요소는 아예 들어있지 않지만 ament를 이용해서 빌드를 할 수 있다는 데 의의를 가질 수 있을 것 같습니다.


package.xml

<?xml version="1.0"?>
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
  <name>hello_ros</name>
  <version>0.4.0</version>
  <description>Snow ROS Message Publisher using class</description>
  <maintainer email="snowdeer0314@gmail.com">snowdeer</maintainer>
  <license>Apache License 2.0</license>

  <buildtool_depend>ament_cmake</buildtool_depend>

  <build_depend>rclcpp</build_depend>

  <exec_depend>rclcpp</exec_depend>
  
  <export>
    <build_type>ament_cmake</build_type>
  </export>
</package>


CMakeLists.txt

cmake_minimum_required(VERSION 3.5)
project(snow_publisher)

# Default to C++14
if(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_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(std_msgs REQUIRED)

add_executable(${PROJECT_NAME} main.cpp)
ament_target_dependencies(${PROJECT_NAME} rclcpp std_msgs)

install(TARGETS ${PROJECT_NAME}
  DESTINATION lib/${PROJECT_NAME})

ament_package()


main.cpp

#include <cstdio>

using namespace std;

int main(int argc, char * argv[]) {
  
  printf("Hello ROS. I am snowdeer.\n");

  return 0;
}