Jetson Nano 에서 QT 기반 패키지를 개발하고 사용하는 법을 정리했습니다.
Jetson Nano
Jetson Nano 보드는 NVIDA 사에서 개발한 소형 PC입니다. NVIDIA 사의 젯슨 컴퓨팅 보드 시리즈 중 하나로 가격대비 성능이 뛰어나 널리 사용되는 보드 중 하나입니다. 작은 크기와 리눅스에 최적화되어 있고 클러스터 등으로 제작하여 사용되기도 합니다.
[Jetson Nano A02 & Raspberry PI 4]
제가 사용하고 있는 Jetson Nano A02 와 Raspberry PI 4 성능 비교표입니다. CPU 성능에서 Raspberry PI와 차이가 있지만 GPU성능에 있어서는 비교가 되지 않기 때문에 비전처리와 같은 용도로 사용하기에 좋습니다. Jetson Nano는 기본적으로 Wifi와 Bluetooth를 모듈 내에서 지원하지 않기 때문에 m.2 슬롯에 랜카드를 사용하거나 usb 동글 등을 연결해서 사용해야 합니다.
Jetson Nano with ROS and QT
Jetson Nano 에서 ROS melodic을 사용하는 데에는 큰 문제가 없습니다. 제가 정리해 둔 아래 글을 통해 설치를 할 수 있습니다.
-> [ROS melodic] 001 : ROS melodic 한 줄 설치 & 개별 설치 정리 (Ubuntu 18.04) <-
[ROS melodic] 001 : ROS melodic 한줄 설치 & 개별 설치 정리 (Ubuntu 18.04)
Ubuntu 18.04 OS에 ROS melodic을 설치하는 방법을 설명하겠습니다. 한 줄 설치하는 방법과 따로 직접 설치하는 방법 모두 설명하려 합니다. 우선 한줄 설치 방법은 쉘 스크립트를 이용하여 자동으로 ROS
menggu1234.tistory.com
문제는 ROS melodic 설치 이후에 발생합니다.
우선 Jetson Nano 는 ARM 기반의 프로세서를 사용하는 PC입니다. 하지만 qt ros plugin은 AMD 기반의 PC에서만 설치가 가능합니다.
이로 인해 QT 기반의 GUI package 개발이 어렵습니다. 패키지를 뜯어 이를 해결할 방법에 대해 고민해 보았고 우선 CMakeLists에 QT를 링크시켜 UI를 사용할 수 있도록 하였습니다.
CMakeLists.txt
cmake_minimum_required(VERSION 3.0.2)
project("패키지 이름")
find_package(catkin REQUIRED COMPONENTS
roscpp
std_msgs
)
include_directories(${catkin_INCLUDE_DIRS})
catkin_package(
INCLUDE_DIRS LIBRARIES "패키지 이름"
CATKIN_DEPENDS
roscpp
std_msgs
DEPENDS
)
##############################################################################
# Qt Environment
##############################################################################
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5 COMPONENTS Core Gui Widgets)
##############################################################################
# Sections
##############################################################################
file(GLOB QT_FORMS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ui/*.ui)
file(GLOB QT_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} resources/*.qrc)
file(GLOB_RECURSE QT_MOC RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} FOLLOW_SYMLINKS include/"패키지 이름"/*.h)
QT5_ADD_RESOURCES(QT_RESOURCES_CPP ${QT_RESOURCES})
#QT5_WARP_UI(QT_FORMS_HPP ${QT_FORMS})
include_directories(
${Qt5Core_INCLUDE_DIRS}
${Qt5Gui_INCLUDE_DIRS}
${Qt5Widgets_INCLUDE_DIRS}
)
add_definitions( -std=c++11 -fPIC)
##############################################################################
# Sources
##############################################################################
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
set( QT_SOURCES
src/main.cpp
include/"패키지 이름"/mainwindow.h
src/mainwindow.cpp
)
##############################################################################
# Binaries
##############################################################################
add_executable("패키지 이름" ${QT_SOURCES} ${QT_RESOURCES_CPP} ${QT_FORMS_HPP} ${QT_MOC_HPP})
target_link_libraries("패키지 이름" ${QT_LIBRARIES} ${catkin_LIBRARIES})
target_link_libraries("패키지 이름"
${catkin_LIBRARIES}
Qt5::Core
Qt5::Gui
Qt5::Widgets
)
install(TARGETS "패키지 이름" RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
QT를 패키지에 링크 시킨 후에 catkin_make를 해준 후 rosrun을 해 보았더니 UI는 정상적으로 출력이 되는 것을 확인할 수 있었습니다. 하지만 궁극적인 목적인 ROS 관련 함수가 작동하지 않았고 이를 해결하기 위해 mainwindow.cpp 파일에 ROS 루프 부분을 이식한 후 멀티 스레드를 이용해 ROS 부분과 UI(show 함수) 부분을 분리해 주었습니다.
MainWindow.cpp
#include "../include/"패키지 이름"/mainwindow.h"
#include "ui_mainwindow.h"
using namespace std;
using namespace Qt;
MainWindow::MainWindow(int argc, char** argv, QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowIcon(QIcon(":/images/icon.jpg"));
ros::init(init_argc,init_argv,""패키지 이름"");
if ( ! ros::master::check() ) {
return;
}
ros::start(); // explicitly needed since our nodehandle is going out of scope.
ros::NodeHandle n;
th=std::thread(&MainWindow::run,this);
return;
}
MainWindow::~MainWindow()
{
if(ros::isStarted()) {
ROS_INFO("exiting");
ros::shutdown(); // explicitly needed since we use ros::start();
}
th.join();
delete ui;
}
void MainWindow::run(){
ros::Rate loop_rate(33);
while ( ros::ok() ) {
ros::spinOnce();
loop_rate.sleep();
}
}
" #include <thread> 를 mainwindow.h 파일에 추가해 주셔야 멀티스레드를 이용하실 수 있습니다! "
위와 같이 개발한 패키지의 템플릿은 아래 Github에서 받아서 사용할 수 있습니다.
-> https://github.com/mjlee111/qtros <-
GitHub - mjlee111/qtros
Contribute to mjlee111/qtros development by creating an account on GitHub.
github.com
또는 catkin_ws/src 폴더에 git clone 명령어를 통해 받아 사용하실 수 있습니다.
$ git clone https://github.com/mjlee111/qtros.git
이 템플릿 패키지는 기본적으로 roscpp, std_msgs를 포함하고 있습니다. 또한 기본적으로 qtros라는 패키지명을 가지고 있으므로 수정이 필요하시다면 패키지 내부 파일에서 직접 수정하시거나 아래에서 설명할 catkin_make_qt_pkg 패키지를 사용하여 패키지명과 의존성 패키지들을 추가하셔도 됩니다.
catkin_create_qt_pkg [package name] [dependencies]
ROS 패키지를 생성할 때 catkin_create_pkg [package name] [dependencies] 와 같은 명령어를 사용하듯이, 아래에서 설명할 패키지를 사용한다면 명령어를 통해 QT ROS 패키지를 생성할 수 있습니다.
catkin_create_qt_pkg는 qt_create 를 참조하여 만들었습니다. qt_create 아래 링크를 참조하시면 될 것 같습니다.
-> http://wiki.ros.org/qt_create <-
qt_create - ROS Wiki
Currently we're installing a simple script, catkin_create_qt_pkg to the global bin directory. In the future we may move this to a rosdistro independant python package. Refer to the Qt App Templates tutorials for an example on how to use it and details on t
wiki.ros.org
제가 만든 패키지의 create.py의 내용은 아래와 같습니다.
create.py
import os
import shutil
from utils import author_name
from utils import read_template
from utils import instantiate_template
##############################################################################
# Template
##############################################################################
def get_qt_text_templates(package, type):
template_dir = os.path.join(os.path.dirname(__file__),'templates',type)
templates = {}
templates['CMakeLists.txt'] = read_template(os.path.join(template_dir,'CMakeLists.txt'))
templates['package.xml'] = read_template(os.path.join(template_dir,'package.xml'))
templates[os.path.join('src','mainwindow.ui')] = read_template(os.path.join(template_dir,'src','mainwindow.ui'))
templates[os.path.join('src','main.cpp')] = read_template(os.path.join(template_dir,'src','main.cpp'))
templates[os.path.join('src','mainwindow.cpp')] = read_template(os.path.join(template_dir,'src','mainwindow.cpp'))
templates[os.path.join('resources','images.qrc')] = read_template(os.path.join(template_dir,'resources','images.qrc'))
templates[os.path.join('include',package,'mainwindow.h')] = read_template(os.path.join(template_dir,'include','PACKAGE_NAME','mainwindow.h'))
return templates
def create_qt_ros_package(package, depends, type):
p = os.path.abspath(package)
os.makedirs(os.path.join(p,"src"))
os.makedirs(os.path.join(p,"include"))
os.makedirs(os.path.join(p,"include",package))
os.makedirs(os.path.join(p,"resources"))
os.makedirs(os.path.join(p,"resources","images"))
print "Created qt package directories."
# Qt text files
templates = get_qt_text_templates(package, type)
for filename, template in templates.iteritems():
contents = instantiate_template(template, package, package, author_name(), depends)
try:
p = os.path.abspath(os.path.join(package, filename))
f = open(p, 'w')
f.write(contents)
print "Created package file", p
finally:
f.close()
# Qt binary files
template_dir = os.path.join(os.path.dirname(__file__),'templates',type)
shutil.copy(os.path.join(template_dir,'resources','images','icon.jpg'),
os.path.join(os.path.abspath(package),'resources','images','icon.jpg'))
def create_qt_ros_catkin_package(package, depends):
create_qt_ros_package(package, depends, 'qtros')
위 패키지는 아래 Github 링크에서 받아서 사용하시면 됩니다.
-> https://github.com/mjlee111/qt_create.git <-
GitHub - mjlee111/qt_create
Contribute to mjlee111/qt_create development by creating an account on GitHub.
github.com
또는 catkin_ws/src 폴더에 git clone 명령어를 통해 받아 사용하실 수 있습니다.
$ git clone https://github.com/mjlee111/qt_create.git
'ROS > ROS1' 카테고리의 다른 글
[ROS1] 005 : ROS 1 turtlesim 패키지 사용해보기 (0) | 2023.08.26 |
---|---|
[ROS1] 004 : ROS 1 구조 및 빌드 시스템, 용어 정리 (0) | 2023.03.09 |
[ROS1] 002 : ROS melodic 명령어 정리 (0) | 2023.02.18 |
[ROS1] 001 : ROS 1 melodic && noetic 한줄 설치 & 개별 설치 정리 (Ubuntu 20.04) (0) | 2023.02.17 |