Gazebo 내의 데이터를 가져오기 위해 gazebo plugin을 사용해 ros2 topic으로 구독하려는 과정에서 libgazebo_gps_plugin.so 파일을 로딩할 수 없다는 에러 메시지를 확인할 수 있었다. 해당 파일은 있었지만 gazebo가 해당 파일이 위치하는 디렉터리의 경로를 찾지 못하는 것으로 판단됐다. 찾다보니 리눅스에서 공유 라이브러리를 찾을 때 사용하는 환경변수 LD_LIBRARY_PATH 설정이 필요했고 아래 명령을 .bashrc 파일에 작성하여 셸이 열릴 때 마다 실행되도록 해주었다.

 

export LD_LIBRARY_PATH=/path/plugin_dir/:$LD_LIBRARY_PATH

 

이러한 리눅스에서 사용하는 환경변수 외에도 Gazebo에서 사용하는 주요 환경변수들을 찾다보니 아래와 같은 환경변수를 확인할 수 있었다.

 

GAZEBO_PLUGIN_PATH

  • Gazebo plugin을 검색할 경로를 지정하는 변수다. 이는 LD_LIBRARY_PATH와 유사해보인다. 어떻게 같고 다를까? LD_LIBRARY_PATH는 실행 중인 프로그램이 공유 라이브러리 파일을 검색할 경로를 지정할 때 사용하는 환경변수다. 반면 GAZEBO_PLUGIN_PATH는 Gazebo 플러그인을 검색할 경로를 의미하는 환경변수다. 즉 GAZEBO_PLUGIN_PATH를 통해 Gazebo plugin을 찾고 LD_LIBRARY_PATH를 통해 Gazebo plugin이 필요로 하고 의존하는 공유 라이브러리 파일을 찾는다.

 

GAZEBO_MODEL_PATH

  • Gazebo에서 모델을 검색할 경로를 지정하는 변수다. 이를 통해 사용자 정의 모델이나 외부 모델 경로를 추가할 수 있다.

 

GAZEBO_RESOURCE_PATH

  • Gazebo에서 리소스 파일을 검색할 경로를 지정하는 변수다. 여기서 리소스란 월드, 모델, 플러그인 등을 뜻한다.

 

GAZEBO_MASTER_URI

  • Gazebo 마스터 서버의 URI를 설정하는 변수다. Gazebo의 다중 인스턴스를 실행하거나 원격 Gazebo 서버와 통신할 때 사용한다.

 

GAZEBO_MODEL_DATABASE_URI

  • Gazebo 모델 데이터베이스 서버의 URI를 설정하는 변수다. 즉 원격으로 Gazebo 모델 데이터베이스에 접근하고 모델을 다운로드 받을 때 사용한다

PX4에서 앱을 만들고 SITL 상에서 실행시키는 'Hello World' 수행 예시를 정리하고자 하는 목적으로 작성한다. PX4에서 새로운 앱을 만들어 구동시키고자 한다면 PX4-Autopilot/src/ 폴더에서 수행해야 한다. 본 예제를 위해서는 새 디렉토리 'px4_simple_app'을 PX4-Autopilot/src/examples 하위에 생성한다. 이후 폴더와 동일한 이름의 px4_simple_app.c를 생성하고 아래 Hello World가 수행되는 코드를 붙여준다.

 

1. px4_simple_app.c 파일 생성

#include <px4_platform_common/log.h>

__EXPORT int px4_simple_app_main(int argc, char *argv[]);

int px4_simple_app_main(int argc, char *argv[])
{
   PX4_INFO("Hello roytravel!");
   return 0;
}

 

코드를 간단히 설명하자면 #include <px4_platform_common/log.h>를 통해 C언어의 printf와 같은 PX4의 출력 함수인 PX4_INFO를 실행할 수 있도록 라이브러리를 불러온다. 그리고 main 함수를 만들어주되 main 앞에 추후 PX4 상에서 사용할 모듈 이름을 함께 사용해준다. 이후 위 .c 파일과 마찬가지로 PX4-Autopilot/src/examples/px4_simple_app/ 하위에 CMakeLists.txt 파일을 만들어준다.

 

2. CMakeLists.txt 파일 생성

px4_add_module(
 MODULE examples__px4_simple_app
 MAIN px4_simple_app
 SRCS
     px4_simple_app.c
 DEPENDS
 )

 

MODULE은 PX4-Autopilot/src 하위의 examples에서 '/'를 '__'로 치환한 다음 모듈 이름을 적어주는 것 같다.

MAIN은 PX4 셸 또는 SITL 콘솔에서 호출할 수 있도록 NuttX에 명령을 등록하는 모듈의 진입점이라고 한다.

SRCS는 말그대로 빌드할 소스코드들을 기술한다. DEPENDS는 의존 라이브러리가 없으므로 널 값으로 보인다.

 

3. Kconfig 파일 생성

마찬가지로 PX4-Autopilot/src/examples/px4_simple_app/ 하위에 별도 확장자 없이 Kconfig 파일을 생성해주고 아래와 같이 값을 추가해준다.

 bool "PX4 Simple app"
 default n
 ---help---
     Enable PX4 simple app

 

4. boardconfig 설정

 

이후 PX4-Autopilot/ 경로에서 make px4_sitl_default boardconfig 명령을 통해 examples에 들어가 px4_simple_app을 추가해준다. 이는 px4_simple_app 모듈이 펌웨어로 컴파일 될 수 있도록 설정하는 것이다.

 

 

 

 

 

 

5. px4_simple_app 실행

PX4-Autopilot/ 디렉터리에서 make px4_sitl_default gazebo 명령을 수행한 뒤 pxh 셸에서 help를 수행해보면 다음과 같이 px4_simple_app 모듈이 명령어로써 사용가능 하도록 추가되어 있다.

 

이후 px4_simple_app 명령을 수행하면 다음과 같이 모듈이 구동되는 것을 확인할 수 있다.

 

Reference

[1] https://docs.px4.io/main/ko/modules/hello_sky.html

'Computer Science > 로봇공학' 카테고리의 다른 글

TIL (230626)  (0) 2023.06.26
Gazebo 환경변수 목록  (0) 2023.06.24
[PX4] Lockstep이란?  (0) 2023.06.19
uXRCE-DDS 미들웨어와 드론 비행제어  (0) 2023.06.19
ROS2 커스텀 interface 생성하기  (0) 2023.06.11

PX4에서 lockstep이란 PX4와 시뮬레이터(ex: Gazebo) 간 동기화/비동기화 여부를 의미한다. Lockstep이 설정되어 있을 경우 PX4와 시뮬레이터는 자체 속도로 실행되지 않고 센서와 액츄에이터 메시지를 서로 기다리게 된다. 만약 설정되어 있지 않을 경우 PX4와 시뮬레이터는 각자의 속도로 수행된다. 이를 설정하기 위한 두 방법이 있다. 첫 번째는 PX4에서 설정하는 것이고 두 번째는 시뮬레이션 관련 파일에서 설정하는 것이다. 

 

PX4에서 Lockstep을 해제하기 위해서는 make px4_sitl_default boardconfig 명령을 통해 보드 설정으로 접속하면 다음과 같은 화면을 볼 수 있다.

 

위 화면에서 방향키를 이용해 Toolchain에 들어가면 아래와 같이 “Force disable lockstep”이 있다.

 

기본값으로 활성화로 설정되어 있고 비활성화를 원할경우 엔터를 통해 비활성화 설정이 가능하다.

 

만약 시뮬레이션(Gazebo)에서 Lockstep을 해제하기 위해서는 SDF 파일 수정이 필요하며 아래 요소를 .sdf 파일에 추가해준다.

<enable_lockstep>false</enable_lockstep>

uXRCE-DDS: Extremely Resource Constrained Environment - Data Distribution Service

 

uXRCE-DDS는 미들웨어이자 프로토콜이다. uXRCE-DDS는 ROS2와 PX4 중간에서 통신을 매개하는 역할을 한다. uXRCE-DDS를 통해 ROS2에서 드론 관련 정보를 받아오고 또 명령을 보낼 수 있도록 한다. 아래 아키텍처를 살펴보자.

아주 직관적인 구성이다. PX4와 ROS2로 양분되어 있고 PX4와 ROS2 사이를 uXRCE-DDS 프로토콜로 연결한다. 드론 관련 정보를 ROS2로 제공하는 쪽이 uXRCE-DDS client고 이러한 정보를 가공하여 PX4쪽으로 명령을 내리는 곳이 uXRCE-DDS agent다.

 

PX4는 ROS2와 마찬가지로 토픽을 통해 드론 비행제어를 위한 정보를 주고 받는다. 즉 publisher를 통해 드론 관련 정보를 발행하고 subscriber를 통해 드론을 제어한다. PX4에서는 토픽을 통해 publisher/subscriber을 사용하는 형식은 ROS2와 같지만 ROS2의 publisher/subscriber와 달라 호환되지 않는다. 이러한 호환을 가능하게 하는 것이 uXRCE-DDS인 것이다.

 

PX4는 토픽 publish/subscribe를 uORB를 통해 수행한다. uORB는 PX4의 내부에서 토픽이 동작할 수 있도록 하는 PX4 내부통신 메커니즘이다. PX4에서도 토픽을 사용하기 위해서는 ROS2에서와 마찬가지로 메시지 포맷이 필요하다. ROS2에서와 같이 *.msg 확장자를 가진다. 직접 확인해보자. https://github.com/PX4/PX4-Autopilot에서 소스를 다운로드 받아 msg 폴더를 살펴보면 아래와 같이 미리 정의되어 저장된 msg 파일을 확인할 수 있다.

 

 

간단한 예시를 위해 Airspeed.msg를 살펴보면 다음과 같은 데이터 포맷으로 메시지 파일이 정의가 되어 있다.

 

 

PX4에서는 토픽을 사용하기 위해 *.msg 파일을 사용하지만 *.msg 파일을 바로 읽어 사용하는 것은 아니다. *.msg 파일은 빌드되어 C++ 구조체로 변환되어 사용된다. 실제로 *.msg 파일이 빌드되면 PX4-Autopilot/build/px4_sitl_default/uORB/topics 폴더에 *.h 파일로 저장된다. 아래는 Airspeed.msg가 빌드되어 저장된 airspeed.h 파일이다.

 

 

이렇게 변환된 헤더 파일에 저장된 메시지 포맷을 통해 토픽 publish/subscribe가 이뤄진다. 참고로 토픽은 빌드될 때 *.msg 파일 명과 동일한 이름으로 등록된다. abc.msg를 빌드하면 abc라는 이름의 토픽으로 등록되는 것이다.

 

이러한 토픽은 ROS2에서 노드(Node) 내부에서 구현된다. PX4에서도 마찬가지다. PX4에서는 ROS2의 노드를 모듈(module)이라 부르며 모듈 단위로 토픽을 publish/subscribe한다. 예컨데 카메라 센서 모듈, IMU 센서 모듈 등으로 모듈을 구현하여 토픽을 publish하고 subscribe하는 것이다. 만약 여러 모듈 간의 통신이 필요한 경우라면 PX4는 내부적인 모듈 간의 통신을 uORB를 통해 수행한다.

 

핵심 요약을 하자면 미들웨어라 불리는 XRCE-DDS client와 XRCE-DDS agent가 PX4-ROS2 통신의 핵심이다. 또 ROS2의 노드는 XRCE-DDS agent/client를 거쳐 PX4의 uORB 메시지 형태로 바뀌어 드론에게 전달되고 uORB 메시지는 XRCE-DDS client/agent를 거쳐 ROS2에서 제어 가능한 형태로 바뀌어 전달된다.

 

실제로 uXRCE-DDS client와 uXRCE-DDS agent를 사용해 드론 비행제어를 수행해보자.

 

uXRCE-DDS agent

uXRCE-DDS agent를 실행하기 위해서는 소스코드를 다운로드 받아야 한다.

 

git clone https://github.com/eProsima/Micro-XRCE-DDS-Agent.git
cd Micro-XRCE-DDS-Agent
mkdir build
cd build
cmake ..
make
sudo make install
sudo ldconfig /usr/local/lib/
cd ~/Micro-XRCE-DDS-Agent/build
./MicroXRCEAgent udp4 -p 8888

위 명령을 수행하면 아래와 같이 Agent가 실행됨을 확인할 수 있다.

 

 

uXRCE-DDS client

uXRCE-DDS client는 단순히 make px4_iris_default gazebo 명령을 통해 시뮬레이션 환경을 실행할 때 자동으로 실행된다.

 

cd ~/PX4-Autopilot
make px4_sitl_default gazebo

 

위 명령을 수행하면 아래와 같이 로그에 uxrce_dds_client가 실행되는 것을 확인할 수 있다.

 

 

여기까지하면 ROS2를 통해 드론 비행제어할 준비가 된 것이다. 마지막으로 이를 제어하기 위한 소스코드를 다운로드 받아 실행시켜보자.

 

mkdir -p ~/ws_offboard_control/src
cd ~/ws_offboard_control/src

git clone https://github.com/PX4/px4_msgs.git
git clone https://github.com/PX4/px4_ros_com.git

cd ..
source /opt/ros/humble/setup.bash
colcon build

source install/local_setup.bash
ros2 run px4_ros_com offboard_control

 

위 명령을 수행하게 되면 아래와 같이 ROS2를 통해 PX4에서 실행된 gazebo 환경에서 드론 비행이 가능한 것을 확인할 수 있다.

 

 

이제 드론 비행제어를 위해 각자 필요한 코드를 구현해 사용하면 될 것이다.

 

 

Reference

[1] https://docs.px4.io/main/ko/ros/ros2_offboard_control.html

[2] https://kwangpil.tistory.com/55

파이썬으로 데이터베이스 처리를 위해 pymysql을 사용해 MySQL 쿼리는 자주 다뤘지만 pymongo를 이용한 MongoDB 쿼리는 많이 다뤄보지 못했다. pymongo 쿼리문은 pipeline으로 만들어 실행하는 것이 깔끔하게 작성하고 실행할 수 있다 생각들었다. 작성하고보니 pipeline은 단 3줄 밖에 안되지만 레퍼런스가 적다고 느꼈고 익숙하지 않아 조금의 시간이 소요됐다. 추후에도 많이 사용할 코드 스니펫일 것 같아 기록.

 

import os
from pymongo import MongoClient
from operator import itemgetter

client = MongoClient(host=os.environ.get('MONGO_HOST'), 
                     port=int(os.environ.get('MONGO_PORT')), 
                     username=os.environ.get('MONGO_USERNAME'), 
                     password=os.environ.get('MONGO_PASSWORD'))
db = client[os.environ.get('MONGO_DB')]
collection = db['name']

pipeline = []
pipeline.append({'$match': {'col1': val1, 'col2': {'$gte', 1682899200}}})
pipeline.append({'$project': {'_id': True, 'col1': True, 'col2': True, 'col3': True}})
pipeline.append({'$limit': 100000})

unsorted_docs = collection.aggregate(pipeline)

unsorted_documents = []
unsorted_documents.extend(unsorted_docs)

documents = sorted(unsorted_documents, key=itemgetter('event_time'))

for document in documents:
	...

ROS2에서 통신을 구현하기 위해 사용하는 서비스, 액션, 메시지에서 사용하는 interfaces를 커스텀하여 정의해야 하는 경우가 있다. 이를 커스텀하기 위해 별도의 폴더를 만들고 빌드해주지 않으면 파이썬에서 라이브러리로 불러오거나 C++에서 include할 때 에러가 발생한다.

 

1. interfaces 패키지 생성

ros2 pkg create interfaces --buile-type ament_cmake interfaces
  • srv, action, msg를 담는 인터페이스 폴더 역시 하나의 패키지로 생성해주어야 한다.
  • 개발언어가 파이썬이라도 buile-type을 ament_cmake로 설정이 필요하다.

 

2. 커스텀 파일 생성

mkdir srv
cd srv
touch AddTwoInts.srv
  • action이면 *.action, msg면 *.msg로 만들어준다. 예시를 위해 임의로 srv를 커스텀 하며, 두 개의 입력값을 더해주고 반환하는 서비스를 구현한다고 가정한다.

 

3. srv 파일 사용자 기입

int64 a
int64 b
---
int64 sum
  • vim AddTwoInts.srv 명령이후 위 내용 기입

 

4. CMakeLists.txt 파일에 내용 추가

find_package(rosidl_default_generators REQUIRED)

rosidl_generate_interfaces(${PROJECT_NAME}
	"srv/AddTwoInts.srv"
)

 

 

5. package.xml 내용 추가

<build_depend>rosidl_default_generators</build_depend>
<exec_depend>rosidl_default_ruintime</exec_depend>
<member_of_group>rosidl_interface_packages</member_of_group>


이후 colcon build 수행시 interfaces 패키지도 함께 빌드

ROS에서 명령을 실행하는 방법은 두 가지로 run과 launch가 있다. run은 단일한 명령이고 launch는 run의 집합이다. 만약 두 개의 ros 명령을 수행하려면 터미널 두 개를 띄우거나 실행하려는 두 명령을 다 입력해주어야 한다. ROS를 다루다보면 여러 ROS 명령을 수행해야 하므로 효율성을 위해 사실상 launch를 실질적으로 더 많이 사용한다. 파이썬을 이용해 launch 파일을 만들고 gazebo와 rviz를 띄우는 일종의 hello world를 수행해보자.

 

이를 위해 가장 먼저 작업 디렉터리를 생성하고 작업 디렉터리로 들어간다.

mkdir -p test_ws/src
cd test_ws/src

 

ROS는 패키지 단위로 프로그래밍이 이뤄지므로 아래 ROS 명령을 통해 패키지를 생성한다.

ros2 pkg create gazebo_pkg --build-type ament_python

 

“gazebo_pkg”는 생성할 패키지 명이다. --buile-type은 사용할 빌드 시스템을 의미한다. ROS1에서는 catkin이 사용되었으나 ROS2에서는 catkin의 업그레이드 버전인 ament를 사용한다. 여기서 ament_python은 파이썬 전용 ament 빌드 시스템이다. 위 명령어를 수행하면 다음과 같이 패키지 폴더가 생성되며 폴더로 들어가면 아래와 같은 파일이 자동으로 생성된다.

 

 

목표는 시뮬레이션을 위한 gazebo와 시각화를 위한 rviz를 같이 띄우는 것이다. 이를 위해 launch 파일을 만들어야 하며 이러한 launch 파일이 담길 폴더를 ‘launch’로 생성해준다. 이는 ROS 개발에 있어 컨벤션으로 가급적 지켜주면 좋다. 이후 test.launch.py를 만들어 준다.

 

 

이후 gazebo와 rviz2를 실행하는 아래 코드를 test.launch.py 파일에 작성해준다

from launch import LaunchDescription
from launch.actions import ExecuteProcess

def generate_launch_description():
    
    return LaunchDescription([
        ExecuteProcess(
            cmd=["gazebo"], output="screen"
        ),

        ExecuteProcess(
            cmd=["ros2", "run", "rviz2", "rviz2"], output="screen"
        ),
    ])


코드를 살펴보자면 launch 파일이 실행되기 위해 반드시 generate_launch_description 함수를 만들어야 한다. 이후 LaunchDescription에 수행할 명령을 리스트로 담아주면 된다. LaunchDescription은 해당 launch 파일이 실행해야 할 목록을 기술하는 클래스다. 안을 살펴보면 ExecuteProcess 클래스가 두 개 있다. 사용법이 매우 간단한 형태로 수행할 명령을 cmd 인자에 입력해주고 output 인자를 통해 로그를 터미널에 출력해줄 수 있도록 screen을 입력한다.

 

cd ~/test_ws

 

source /opt/ros/humble/local_setup.bash

  • ROS2 환경을 현재 셸 세션에 로드하여 ROS2 실행에 필요한 실행파일, 라이브러리, 환경변수 등에 접근할 수 있도록 하는 명령어다.
  • 터미널이 새로 열릴 때 마다 새로운 세션이 생성되므로 매번 입력해주어야 한다. 귀찮다면 .bashrc에 해당 명령어를 입력해두면 터미널이 생성될 때 마다 자동으로 실행된다.
  • 참고로 setup.bash가 있고 local_setup.bash가 있다. 둘 간의 차이점은 전자는 전역적으로 설치된 패키지 설정이고 후자는 지역적으로 설치된 패키지에 대한 설정을 수행한다. setup.bash를 수행하면 전역적으로 수행되어 간편하지만 다른 패키지와 충돌(?)이 발생할 수 있으므로 가급적(?) local_setup.bash를 사용한다.

만약 위 명령을 수행하지 않고 launch 파일을 실행하면 다음과 같이 만들어주었던 패키지 폴더를 찾지 못했다는 에러를 확인할 수 있다.

 

 

위 명령을 수행하고 다시 실행해보자. 이번엔 다른 에러가 발생했다. gazebo_pkg 폴더 안에 test.launch.py가 없다고 한다.

 

이렇게 에러가 발생하는 이유는 빌드 당시 setup.py를 제대로 설정해주지 않아서 발생한다.

 

~/test_ws/src/gazebo_pkg/setup.py에 들어가서 아래 15번째 줄에 있는 os.path.join(’share’, package_name, ‘launch’), glob(’launch/*.launch.py’))를 추가해주자. (import os, from glob import glob도 함께)

 

 

 

이후 다시 colcon build --symlink-install --packages-select gazebo_pkg 명령을 통해 빌드를 다시 수행한 뒤, launch 파일 실행을 위해 ros2 launch gazebo_pkg test.launch.py를 수행해주면 아래와 같이 gazebo와 rviz2가 함께 실행되는 것을 확인할 수 있다.

 

 

만약 gazebo를 실행할 때 시뮬레이션 환경이 구성되어 있는 world 파일을 넣고자 한다면 test.launch.py와 setup.py를 아래와 같이 살짝만 코드를 바꿔 world 파일 경로 인자를 추가해주는 방식으로 gazebo 실행 시 이미 만들어진 시뮬레이션 환경을 구성할 수 있다. (world 파일이 없다면 이전 포스팅 참고)

 

import os
from glob import glob
from setuptools import setup

package_name = 'gazebo_pkg'

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']),
        (os.path.join('share/', package_name, 'launch'), glob('launch/*.launch.py')),
        (os.path.join('share/', package_name, 'worlds'), glob('worlds/*.world'))
    ],
    install_requires=['setuptools'],
    zip_safe=True,
    maintainer='roytravel',
    maintainer_email='roytravel@todo.todo',
    description='TODO: Package description',
    license='TODO: License declaration',
    tests_require=['pytest'],
    entry_points={
        'console_scripts': [
        ],
    },
)

참고로 리스트 data_files에 담긴 튜플 인자 두 개를 사용해 폴더와 파일을 복사한다. 두 번째 인자의 폴더와 파일을 복사해 첫 번째 인자에 있는 경로로 복사한다.

 

setup.py

import os
from launch import LaunchDescription
from launch.actions import ExecuteProcess
from ament_index_python.packages import get_package_share_directory

def generate_launch_description():
    package_name = 'gazebo_pkg'
    world_filename = 'test.world'
    packge_path = os.path.join(get_package_share_directory(package_name))
    world_path = os.path.join(packge_path, "worlds", world_filename)
    
    return LaunchDescription([
        ExecuteProcess(
            cmd=["gazebo", world_path], output="screen"
        ),

        ExecuteProcess(
            cmd=["ros2", "run", "rviz2", "rviz2"], output="screen"
        ),
    ])

 

위와 같이 작성해주고 재빌드를 해준 뒤 launch 파일을 실행하면 gazebo를 실행할 때 직접 만들어 두었던 world 파일을 적용하여 gazebo를 실행시킬 수 있다.

 

 

 

Gazebo를 통해 시뮬레이션을 수행하기 위해선 시뮬레이션 환경구성에 필요한 모델을 추가해야 한다. 가령 자율주행이라면 모델은 차, 버스, 신호등, 횡단보도 등이 될 수 있다. 이러한 모델을 통해 구성한 시뮬레이션 환경은 반복해서 사용하기 때문에 Gazebo를 실행할 때 마다 이미 만들었던 모델을 불러올 수 있어야 한다. 이를 불러오기 위해서는 모델들을 담은 .world 파일이 필요하다. gazebo에서 모델을 만든 다음 .world 파일로 저장함으로써 생성할 수 있다.

 

gazebo 실행

gazebo --verbose


gazebo가 실행되면 위와 같이 아무 것도 없는 plane world가 나타난다. 이후 Insert 탭을 통해 모델을 추가하여 world를 구성할 수 있다.

 

 

로컬에 저장해둔 모델이 있다면 이를 사용할 수도 있지만 서버에서 제공해주는 모델을 사용해서 world를 구성할 수 있다. 맨 아래 http://models.gazebosim.org를 클릭해보면 해당 서버에서 제공해주는 모델 리스트를 아래와 같이 확인할 수 있다.

 

 

간단한 예시로 Bus와 SUV를 다음과 같이 불러올 수 있다.

 

 

world 파일로 저장하는 단축키인 Ctrl + Shift + S를 통해 저장할 수 있다. test.world 파일로 다음과 같이 저장하고 gazebo를 종료한다.

 

 

두 모델이 담긴 world 파일을 불러오기 위해 gazebo가 실행될 때 아래와 같이 명령어를 입력해주면 구성했던 시뮬레이션 환경을 다시 로딩할 수 있다.

 

gazebo test.world

 

 

1. 필요 패키지 설치

sudo apt-get install build-essential cmake # C/C++ 컴파일러 관련 라이브러리 및 도구
sudo apt-get install pkg-config # 컴파일 및 링크시 필요한 라이브러리 정보를 메타파일로부터 가져옴 
sudo apt-get install libjpeg-dev libtiff5-dev libpng-dev # 이미지 파일 로드 및 저장
sudo apt-get install ffmpeg libavcodec-dev libavformat-dev libswscale-dev libxvidcore-dev libx264-dev libxine2-dev # 특정 코덱의 비디오 파일 읽기/쓰기
sudo apt-get install libv4l-dev v4l-utils # 실시간 웹캠 비디오 캡처를 위한 디바이스 드라이버 및 API
sudo apt-get install libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev # 비디오 스트리밍 라이브러리 설치 (Gstreamer)
sudo apt-get install libgtk-3-dev # opencv GUI (이외: libgtk2.0-dev, libqt4-dev, libqt5-dev)
sudo apt-get install libatlas-base-dev gfortran libeigen3-dev # OpenCV 최적화 라이브러리
sudo apt-get install python3-dev python3-numpy # OpenCV-Python 바인딩 & 행렬 연산
sudo apt-get install libfreetypes6-dev libharfbuzz-dev # opencv 한글 지원
sudo apt install unzip

 

2. OpenCV 소스코드 내려받기

mkdir ~/opencv && cd ~/opencv
git clone https://github.com/opencv/opencv.git
git clone https://github.com/opencv/opencv_contrib.git

 

3. CMake Setup

cd ./opencv
mkdir build && cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \\
-D CMAKE_INSTALL_PREFIX=/usr/local \\
-D WITH_TBB=OFF \\
-D WITH_IPP=OFF \\
-D WITH_1394=OFF \\
-D BUILD_WITH_DEBUG_INFO=OFF \\
-D BUILD_DOCS=OFF \\
-D BUILD_EXAMPLES=OFF \\
-D BUILD_TESTS=OFF \\
-D BUILD_PERF_TESTS=OFF \\
-D WITH_CUDA=ON \\
-D WITH_CUDNN=ON \\
-D OPENCV_DNN_CUDA=ON \\
-D CUDA_FAST_MATH=ON \\
-D CUDA_ARCH_BIN=7.5 \\    # 자신 GPU의 compute capability 값
-D WITH_CUBLAS=ON \\
-D WITH_CUFFT=ON \\
-D WITH_QT=ON \\
-D WITH_GTK=OFF \\
-D WITH_OPENGL=ON \\
-D WITH_V4L=ON \\
-D WITH_FFMPEG=ON \\
-D WITH_XINE=ON \\
-D BUILD_NEW_PYTHON_SUPPORT=ON \\
-D INSTALL_C_EXAMPLES=OFF \\
-D INSTALL_PYTHON_EXAMPLES=OFF \\
-D OPENCV_GENERATE_PKGCONFIG=ON \\
-D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \\
-D OPENCV_ENABLE_NONFREE=ON \\
-D BUILD_EXAMPLES=OFF ..
nproc # 자신 시스템의 코어 수 확인

# build (modify the core number '12' after option -j accordingly)
make -j8 # 자신 시스템 코어 수에 맞게 -j 다음의 숫자를 변경

# install
sudo make install

# check if it is installed successfully
pkg-config --modversion opencv4

 

4. 설치 확인

4.1 OpenCV 동작 여부 확인

아래 코드를 test.cpp라는 파일명으로 저장

#include "opencv2/opencv.hpp"
#include <iostream>  
  
using namespace cv;  
using namespace std;  
  
int main(int, char**)
{
    VideoCapture cap(0);
    if (!cap.isOpened()){
        printf("카메라를 열수 없습니다. \\n");
    }
  
    Mat frame;
    namedWindow("camera1", 1);
    for (;;) 
    {
        cap >> frame;
        imshow("camera1", frame);
        if (waitKey(20) >= 0) break;
    }
    return 0;  
}

아래 내용을 복사해 CMakeLists.txt로 저장

get_filename_component(ProjectId ${CMAKE_CURRENT_LIST_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId} C CXX)

set (CMAKE_CXX_STANDARD 11)
cmake_minimum_required(VERSION 2.8)
find_package( OpenCV REQUIRED )

file(GLOB SOURCES  *.cpp)
 
add_executable(${PROJECT_NAME} ${SOURCES}  )
target_link_libraries( ${PROJECT_NAME} ${OpenCV_LIBS} )

CMake → Make → 실행

mkdir buld && cd build
cmake ../
make
./test

 

4.2 OpenCV GPU 사용 가능 여부 확인

아래 코드를 gpu.cpp라는 파일명으로 저장

#include <iostream>
using namespace std;

#include <opencv2/core.hpp>
using namespace cv;

#include <opencv2/cudaarithm.hpp>
using namespace cv::cuda;

int main()
{
    printShortCudaDeviceInfo(getDevice());

    int cuda_devices_numbers = getCudaEnabledDeviceCount();
    cout << "CUDA Device(s) Compatible: "  << cuda_devices_numbers << endl;
    DeviceInfo _deviceInfo;

    bool _isd_evice_compatible = _deviceInfo.isCompatible();
    cout << "CUDA Device(s) Compatible: " << _isd_evice_compatible << endl;

    return 0;
}

빌드

g++ -o gpu gpu.cpp $(pkg-config opencv4 --libs --cflags)

실행 결과에서 Number와 Compatible에서 모두 1이 나오면 GPU 동작 수행 가능

 

만약 1이 나오지 않는다면 설치과정 3의 옵션 중 아래 두 옵션의 수를 잘못 기입한 것임.

-D CUDA_ARCH_BIN=x.x

-D CUDA_ARCH_PTX=x.x

이를 해결하기 위해 해당 그래픽 카드에 맞는 버전으로 기입해줄 것

 

Reference

[1] https://darkpgmr.tistory.com/184

[2] https://webnautes.tistory.com/1767

[3] https://webnautes.tistory.com/1435

[4] https://mickael-k.tistory.com/211

1. PX4 소스코드 설치 및 Bash 스크립트 실행

git clone https://github.com/PX4/PX4-Autopilot.git --recursive
cd PX4-Autopilot
bash ./Tools/setup/ubuntu.sh

 

2. Gazebo 시뮬레이터 설치

sudo apt-get install gazebo

 

3. Gazeo SITL 시뮬레이터 실행

make px4_sitl gazebo
  • gazebo가 지원하는 기체 전체목록은 make list_config_targets 명령시 확인 가능
  • 만약 위 명령을 수행했을 때 에러가 발생한다면 sudo apt-get upgrade gazebo 명령 필요

 

4. 드론 이륙 및 착륙 명령 실행

pxh> commander takeoff
pxh > commander land

 

5. QGroundControl 설치

5.1 명령어 실행

sudo usermod -a -G dialout $USER
sudo apt-get remove modemmanager -y
sudo apt install gstreamer1.0-plugins-bad gstreamer1.0-libav gstreamer1.0-gl -y
sudo apt install libqt5gui5 -y
sudo apt install libfuse2 -y

 

5.2 QGC 바이너리 다운로드

 

5.3 QGC 바이너리 실행

chmod +x ./QGroundControl.AppImage
./QGroundControl.AppImage

 

 

PX4와 QGC가 mavlink로 연결됨을 확인: INFO [mavlink] partner IP: 127.0.0.1

 

 

6. QGC의 시작 좌표 변경

  • 아래 위치(석촌호수)를 .bashrc에 저장하여 터미널을 실행할 때 마다 설정되도록 내용 추가
export PX4_HOME_LAT=37.506700 #위도
export PX4_HOME_LON=127.097598 #경도
export PX4_HOME_ALT=15 # 고도

 

 

7. 시뮬레이션 속도 변경

  • 실제 시간 대비 시뮬레이션 속도 증감 가능 (아래는 2배)
export PX4_SIM_SPEED_FACTOR=2

 

 

8. GUI 없이 Gazebo 실행

  • 더 빠른 시뮬레이터 실행과 더 적은 리소스 사용
HEADLESS=1 make px4_sitl gazebo
  • 환경변수로 등록하고 싶을 경우 아래은 내용을 .bashrc에 추가
export HEADLESS=1

 

Reference

[1] https://docs.qgroundcontrol.com/master/ko/getting_started/download_and_install.html

[2] https://kwangpil.tistory.com/100

+ Recent posts