본 논문은 2022년 한국소프트웨어종합학술대회에서 나온 논문으로 드론 내부 데이터 추출을 통한 포렌식의 활용 가능성에 대한 논문이다. UAV 시장이 군사, 건설, 물류 산업 등의 분야로 확장되면서 UAV 산업의 중요성이 높아졌다. 이에 따라 UAV를 대상으로 한 취약점 기반 공격이 증가했고 이에 따른 포렌식의 중요성이 대두 된 것이 이 연구의 배경이다. 

 

 

1. PX4 Autopilot 데이터 저장 방식

아래는 PX4 Autopilot의 아키텍처다. 빨간 박스로 표시된 부분이 PX4 Autopilot에서 데이터 저장과 관련된 모듈이다.

 

크게 3가지 모듈로 구성되며 dataman, param, logger다.

 

dataman 모듈: MAVLink로부터 전달받은 비행미션에 관련한 데이터를 SD Card에 저장

param 모듈: 사용자가 셸 커멘드를 통해 설정가능한 PX4 Autopilot 관련 파라미터를 EEPROM, SD Card, Flash 메모리에 저장

logger 모듈: GPS, IMU, 기압계 등의 센서로부터 들어오는 입력이나 Controller, Estimator에서 처리된 데이터를 PX4의 미들웨어인 uORB의 API를 통해 SD card에 저장하며 파일 형식은 ULog로 uORB 토픽 데이터를 저장함.

 

 

2. 드론 주요 데이터 정의 및 분석

 

비행 데이터: 비행 경로 & 미션 수행에 관한 데이터로 dataman 모듈에 의해 파일명이 ‘dataman’인 바이너리 파일로 SD card에 저장된다. dataman 파일에는 드론의 안전귀환지점인 Safe point, 비행구역인 Geofence point, 미션수행 정보인 Way point를 저장한다. Safe point는 UAV가 안전하게 착륙할 수 있는 지점을 의미하고 좌표계와 좌표로 구성된다. Geofence는 UAV가 안전하게 비행할 수 있는 구역으로 각 지점의 좌표와 Fence 형태로 저장한다. Way point는 UAV가 비행하는 경로 또는 수행해야 할 임무를 나타낸다.

 

설정 데이터: 기체 드라이버, 모듈에서 사용되는 파라미터 값으로 param 모듈에 의해 관리된다. 초기 설정 파라미터는 펌웨어에 저장되어 있고 설정값을 변경하는 경우 EEPROM에 저장된 mtd_params 파일에 파라미터 명과 함께 변경된 설정값을 저장한다. PX4 부팅시 퍼웨어에서 초기 파라미터를 RAM에 로드하고 mtd_params 파일에서 변경된 파라미터를 덮어써 기체의 파라미터를 수정한다. GCS에 전달하기 위한 파라미터값은 별도의 /tc/parameters.json.xz 파일에 저장된다.

 

로그 데이터: logger 모듈이 저장하는 uORB 토픽 데이터로 ULog 파일 형태로 SD card에 저장된다. 센서 데이터나 기체 내부 상태, 파라미터 값, 로그 메시지, RC 입력, CPU 부하, EKF 상태 등 여러 데이터가 저장된다.

 

 

3. 드론 내부 데이터 추출 방법

드론 내부의 데이터를 추출하기 위해 드론 기체와 로컬 PC와 USB 시리얼 포트로 연결 후 MAVLink의 하위 프로토콜인 MAVFTP를 이용해 추출한다. 아래는 PX4 Autopilot mini 4의 디렉터리 구조라고 한다.

/bin, /dev, /obj는 가상 파일 시스템에 의해 관리되어 MAVFTP로 폴더 추출이 불가능하다고 한다. proc의 경우도 추출이 불가능했으나 cat을 통해 데이터를 추출했다고 한다. 이외의 /etc와 /fs 디렉터리는 추출이 가능했다. 이렇게 추출 가능한 디렉터리를 활용해 데이터 분석 도구를 개발했고 포렌식에 활용하기 위해 간단히 파일 생성 타임스탬프와 해시값 계산, CSV 추출 기능 등의 기능을 구현했다. 

 

결론적으로 드론 포렌식을 위해 MAVFTP 프로토콜로 접근 드론 내부 데이터에 접근해 추출하는 방안을 제시했고, 데이터 추출을 위해 GUI 도구를 개발하였다. 

 

-- Question

Q1. Waypoint는 UAV가 비행하는 경로만을 나타내는 것이 아닌가? 수행해야 할 임무를 나타낸단 건 무슨 의미인가? 같은 의미로 볼 수 있는가?

Q2. MAVLink의 하위 프로토콜 종류는 무엇이 있는가?

Q3. 가상 파일시스템은 무엇이고 동작원리는 무엇인가?

2020년 대한전자공학회에서 나온 논문이다. 핵심은 제목 그대로 자율주행드론을 위한 위치제어와 고도제어가 핵심이다. 연구배경은 GPS와 같은 센서는 외부환경에서는 사용할 수 있지만 실내와 같은 내부환경에 들어오게 되면 차폐된 내부로 인해 GPS 신호가 단절될 수 있어 자율주행의 한계가 있다는 점이다. 따라서 실내환경에서 드론의 자율비행 임무수행을 위한 위치제어와 고도제어 방법에 대해 제시한다.

 

1. 위치제어

위치제어란 실내에서 장애물회피 임무를 수행할 뿐아니라 드론 기체가 외력을 받아 Drift되지 않도록 위치를 제어하는 것을 말한다. 논문에서는 위치제어를 위한 방법으로 px4flow를 사용해 컴퓨터비전 알고리즘을 적용했다. px4flow란 optical flow 센서 중 하나인데 optical flow는 영상을 통해 호버링 시 기체의 위치가 흔들리지 않도록 도와주는 센서다. (https://docs.px4.io/v1.13/ko/sensor/px4flow.html)

px4flow: 영상 변화에 따른 빛의 변화를 계산하는 기능의 카메라

 

 

2. 고도제어

고도제어란 지면으로부터 거리를 조절하는 것이다. 

자율주행에 고도제어가 필요한 이유는 3차원 공간(x, y, z)의 특정지점에서 비행이 가능해야 하기 때문이다. 드론의 고도제어를 위해 사용하는 센서는 적외선 센서, 기압센서, 초음파센서, 라이다센서가 있다. 결론부터 말하면 논문에선 다 사용해보았으나 라이다센서가 가장 높은 정확성을 보였다. 서술한 센서의 실험 결과를 차례대로 기술해보자면,

 

2.1 적외선 센서

적외선 센서를 사용한 결과 온도에 영향을 받아 외부환경 파악에 신뢰성 떨어지는 신호를 수신했다.

 

2.2 기압 센서

Pixhawk에 내장되어 있다고만 서술되어 있고 이에 대한 실험 내용은 누락되어 있음.

 

2.3 초음파 센서

초음파 센서는 초음파 방출 후 물체에 반사되어 돌아오는 시간을 통해 물체와의 거리를 구하는 센서다. 초음파 센서를 사용한 결과 비교적 고른 값을 수신하나 중간값, 평균값에 차이가 많이나는 이상치가 수신되는 경우가 발생했다. 이 이상치는 확장칼만필터(EKF)로 보정을 했음에도 고도제어에 부정확성을 야기하는 것이 관찰되었다. 

 

실험에 사용한 초음파센서는 Maxbotix사의 HRLV-MaxSonar-EZ4 센서이며, EZ4에서 0~4는 빔폭을 나타내고 클수록 빔폭이 좁아진다. 초음파 센서에 들어온 아날로그 신호를 ADC 포트를 거쳐 디지털 신호로 바뀐다음 Pixhawk로 전달된다. 초음파 센서의 입력값을 정확히 이용하기 위해선 Scaling 파라미터를 조절해주어야 한다. 이는 Ardupilot 공식 홈페이지에서 제시하는 값이 있으나 오차가 커서 잘 들어맞지 않았다.

 

2.4 라이다 센서

라이다 센서를 px4flow 센서와 함께 사용한 결과 드론 위치와 고도를 제어할 수 있었고 실내 환경에서 높은 신뢰성을 얻었다. 실험에 사용한 제품은 Benewake 사의 TF mini LiDAR를 사용했다. 이는 단거리 측정을 목적으로 개발된 센서로 실내에서 최대 12m, 실외에서 최대 7m 거리를 측정가능하다. TF mini Lidar는 Serial, UART, I2C 통신 등 다양한 방법으로 연결할 수 있고 실험에선 Serial 포트를 통해 연결했다. LiDAR 센서를 통한 실험의 결과로는 별다른 센서 calibration 없이 비교적 정확한 값을 측정할 수 있었다. 논문에선 Pixhawk와 LiDAR 센서의 Serial 통신에서 BaudRate를 115200으로 설정해줘야 한다고 한다.

 

TF Mini LiDAR

 

3. 실험 결과

 

초록선이 라이다 센서고 빨간선이 초음파 센서다. 초음파의 경우 드론이 움직일 때 마다 값의 변화가 크다. 즉 노이즈가 많이 추가되는 것을 볼 수 있다. 반면 라이다 센서는 안정적인 고도값을 측정했다. 초음파 센서는 0.5m 이상 오차가 발생했지만 라이다 센서는 0.05m의 오차만 발생했다고 한다. 위에서도 기술했지만 초음파 센서 값을 EKF로 보정했으나 오히려 이착륙시 고도제어가 더 불안정하게 되었고 결론적으로 고도제어에는 초음파 센서가 적합하지 않다는 결론을 내렸다.

 

--- 결론 ---

다른 적외선 센서나 기압 센서와의 비교가 없으나 결론적으로 라이다 센서가 가장 드론 위치제어와 고도제어에 안정적이라고 한다.

 

--- 이외 기타 내용 정리 ---

- px4flow 사용을 위해 초점 조절과 calibration을 수행해야 하는데 이는 파라미터로서 지원되고 파라미터 설정이 가능한 GCS를 사용해 가능함. 논문에선 Mission Planner 사용

- px4flow calibration은 기체의 자이로 정보와 px4flow의 자이로 정보를 일치시킴으로써 수행함. 이를 위해 기체 프로펠러를 뺀 체 손으로 roll, pitch 동작을 반복하고 이후 로그를 통해 pixhawk의 자이로 값과 px4flow의 자이로 값을 비교해 오차가 있다면 파라미터를 변경해 오차를 줄이는 방식을 사용함.

- px4flow 정상작동을 위한 전원공급을 위해 BEC를 이용해 5V 전원 별도 공급

- px4flow와 pixhawk 간의 연결을 위해 I2C 통신포트를 사용.

 

--- Question ---

Q1. 위 그래프의 초록선은 저자가 간단히만 언급했던 라이다 센서와 px4flow 센서를 함께 결합한 성능인가 라이다 센서의 독립적인 성능인가? 

Q2. 라이다 센서 vs 카메라 센서를 비교하면 어떨까?

Q3. PMW란 무엇인가?

Q4. QGroundController에서도 px4flow calibration을 수행할 수 있는가?

2019년 한국통신학회에서 나온 논문이다. Gazebo 시뮬레이션 환경에서 드론에 LiDAR를 장착한 다음 장애물 회피 알고리즘을 통해 테스트를 한 것이 핵심이다. 장애물 회피 알고리즘은 가장 처음 직관적으로 떠올릴 수 있는 로직이자 심플한 절차로 수행된다. 

목표를 정하고 장애물을 인식하고 장애물과 이에 반대 방향의 벡터를 만들고 목표 벡터와 반대 방향의 벡터를 결합하는 것이 골자다. 위와 같은 장애물 회피 알고리즘을 적용했을 때 아래와 같은 경로로 드론이 장애물을 회피하며 목표지점에 도달하게 된다.

 

 

이외에 몇 가지 팁이있다면 첫 번째는 드론을 너무 빠른 속도로 움직이면 관성에 의해 장애물에 부딪히기 때문에 드론의 최대 비행 속도를 적절히 제어해야 한다. 두 번째는 Gazebo 시뮬레이션은 URDF, SDF를 사용하는데 URDF가 SDF에 비해 ROS와 호환성이 좋아 로봇 모델링에 많이 사용한다는 것이다. SDF는 Gazebo 시뮬레이션에 사용할 수 있지만 ROS와 호환성이 좋지 않다고 한다. 따라서 URDF로 모델링하는 것이 최선이라고 함. 저자들은 URDF로 기술된 드론 모델에 추가코드를 통해 PX4Flow, SF-10a, RPLIDAR 센서가 장착된 드론을 모델링 했다. 세 번째는 원하는 모델(메쉬)이 없다면 Blender나 Sketchup와 같은 모델링 툴을 이용해 직접 모델을 구성할 수 있다. 

 

Q1. 목적지 지정 방법은? GPS 좌표 기반?

Q2. 과정 5에서 드론 이동 방향과 속도 결정은 구체적으로 어떻게 이뤄지는가?

Q3. 장애물이 조밀하게 있을 경우에도 알고리즘이 동작할 수 있는가?

Q4. SDF 포맷이 공개된 것처럼 URDF도 공개된 포맷이 있을까?

Q5. 모델링 툴로 만들면 곧 바로 Gazebo에 적용할 수 있는가?

2021년 한국항공우주학회에서 나온 논문이다. 내용의 핵심은 드론이 장애물을 회피하면서도 안전하게 비행할 수 있는 전역 경로 플래너(Global Path Planner)를 개발한 것으로 아래와 같은 아키텍처를 갖는다. 비행제어 S/W로는 PX4를 활용했고 미션 컴퓨터로는 Jetson Nano를 사용했다. 

위 아키텍처의 핵심은 Mission Computer 내의 Global Planner Node와 Octomap Node 두 가지다. Global Planner Node는 PX4로부터 드론의 자세정보(vehicle_attitude)와 위치정보(vehicle_local_position, vehicle_global_position)를 수신하고 동시에 Depth data를 수신한다. 이후 Depth data의 정확한 위치를 계산한 값을 Octomap Node로 보낸다. Octomap Node는 수신 받은 데이터를 사용해 비행 구역의 장애물 유무를 3차원 occupancy grid map으로 만들어 Global Planner Node로 전달한다. 이후 Global Planner Node는 Octomap Node에서 전달받은 3차원 지형정보를 기반으로 드론이 목표지점까지 장애물과 충돌하지 않고 안전히 비행할 수 있는 경로를 지속적으로 계산하여 PX4에 다음 위치를 명령하는 방식으로 비행이 이뤄진다. 

 

위와 같이 구성한 아키텍처는 gazebo 환경에서 PX4-ROS2 기반의 경로 계획을 수행하는 시뮬레이션을 통해 그 동작을 확인하였다. 인식한 장애물을 우측상단의 rviz를 통해 3차원 맵으로 시각화하였고 또 목적지까지 장애물을 회피하며 비행하였다. 

 

 

실질적으로 얼마나 잘 동작했는지는 확인할 수 없었지만 목표지점 도달을 위해 경로 계획(Path planning)이 필요하고 이러한 경로 계획에 필요한 여러 파라미터 값을 알 수 있었다. 예컨데 vehicle_command를 통해 드론의 위치 명령을 내리거나 up_cost, down_cost를 조정해 드론의 수직이동에 소모되는 에너지를 다르게 계산한다는 점, 또 risk_factor, neighbor_risk_flow를 조정해 지형지물의 위험도 수준을 다르게 줄 수 있다는 점을 알게 됐다. 또 새롭게 접하게 Octomap과 occupancy grid map이 있었고 향후 이에 대해 알아보고자 한다.

최근 드론의 수평제어를 위해 PX4의 gazebo에서 출력하는 IMU 센서 데이터를 기반으로 calibration을 수행하여 보정값을 다시 드론으로 전달하는 기능 구현이 필요하다 생각됐다. 결론부터 말하자면 삽질이었고 이미 PX4 펌웨어에서는 센서 데이터에 대해 확장칼만필터를 적용하여 제공하고 있어서 별도로 기능 구현을 할 필요가 없었다. 그래도 간단히나마 삽질 과정을 기록해본다.

 

찾다보니 IMU 센서 데이터를 보정하기 위해 칼만필터와 확장칼만필터가 사용되는 것을 알 수 있었다. 칼만필터는 선형시스템의 상태추정을 위해 사용되고 확장칼만필터는 비선형시스템의 상태추정을 위해 사용된다. 이러한 칼만필터와 확장칼만필터을 통해 드론의 자세추정과 수평제어에 사용할 수 있어 비행의 안정성을 가져올 수 있기 때문에 필수적이다. 칼만필터는 선형시스템의 실제상태와 추정상태 간의 차이를 나타내는 '오차공분산'을 최소화하는 알고리즘이다. 통계 기반 알고리즘이며 이전 추정상태가 다음 상태추정에 영향을 미치므로 마르코프 연쇄를 가정한 알고리즘이다. 이러한 칼만필터는 선형시스템일 경우 최적화된 상태 추정이 가능하다는 것이 수학적으로 증명되어 있다고 한다. 하지만 대부분의 경우 비선형시스템을 따르므로 모델링을 위해서는 확장칼만필터를 사용한다. 확장칼만필터는 비선형시스템을 나타내는 상태식을 매 순간 미분하여 선형시스템으로 근사한 다음 칼만필터를 적용하여 비선형시스템의 상태를 추정한다. 아래는 칼만필터의 알고리즘이다. 

 

칼만필터에 사용되는 주요 변수는 A, H, Q, R, P, K로 여섯 가지다. 이 중 네 가지(A, H, Q, R)는 이미 정해진 값이며 칼만이득인 K는 자연스럽게 계산되는 값이다. 실제로 구해야할 것은 P 밖에 없다. 이 P가 오차공분산이며 이를 계산하여 다음 상태추정에도 활용한다. 이 P를 최소화하는 것이 칼만필터 알고리즘의 목표다. 이러한 칼만필터를 활용해 IMU 센서 데이터를 보정하여 드론 수평제어 기능을 만들고 싶었다. 나이브했던 접근은 PX4 uORB topic 중 IMU 센서 관련 토픽을 구독해 칼만필터 알고리즘을 적용해 보정하고 보정값을 다시 토픽 발행을 통해 적용해주려 했다. 

 

 

PX4 uORB의 topic 중 /fmu/out/sensor_combined에서 IMU 센서값을 얻을 수 있었고 C++로 /fmu/out/sensor_combined 데이터를 구독하는 기능을 구현했다. 다만 칼만필터 알고리즘 적용이전 간단히 하드코딩된 값으로 설정해 발행해보았지만 적용되는 것 같지 않았다. 알고보니 /fmu/in/sensor_combined가 있을 것이고 여기로 보정값을 전달하면 수평제어가 되지 않을까 했었는데 /fmu/in/sensor_combined 토픽 자체가 없었던 것이다. 왜 없을까 생각해보았을 때 어쩌면 안정성을 추구하는 PX4의 철학때문이지 않을까 싶다. 잘은 알지 못하겠다. 아무튼 이렇게 IMU 센서 관련 정보를 직접적으로 calibration할 수 없다면 어떻게 이뤄질까하며 찾다보니 /fmu/out/sensor_combined는 이미 확장칼만필터가 적용된 센서값임을 알 수 있었다. PX4에는 이러한 확장칼만필터와 같은 기능을 활성화할지 비활성화할지를 결정하는 여러 개의 'parameter'가 있다. 이러한 paramter는 PX4의 펌웨어에 접근하거나 QGroundController 내부에서 변경이 가능하다. (https://docs.px4.io/v1.11/en/advanced_config/parameter_reference.html)

 

위 parameter reference에서 보다보면 확장칼만필터(EKF) 관련 parameter가 수 십여 개가 있는 것을 확인할 수 있다. EKF2_*로 시작하는 parameter들이다. 이러한 parameter들을 포함하여 PX4에서 사용하는 여러 paramter들은 PX4 셸에서 param show 명령을 통해서도 그 목록을 확인할 수 있다. 또 param show -c 옵션을 통해 default 값에서 바뀐 모든 매개변수를 확인할 수도 있다.

 

 

또 이런 parameter들은 PX4가 실행할 때 start script인 /PX4-Autopilot/ROMFS/px4fmu_common/init.d-posix/rcS 파일에서도 설정할 수 있음을 확인할 수 있었다.

 

 

또 PX4 셸에 구현되어 있는 uORB 앱 중에서 확장칼만필터를 보완한 ekf2를 확인할 수 있었다. ekf2 start를 통해 실행시킬 수도 있는 것 같은데 에러가 발생한다. 잘 모르겠다.

 

 

참고로 이 확장칼만필터인 ekf2는 PX4-Autopilot/src/modules/ekf2에서 구현체를 확인할 수 있다. 워낙 PX4 관련 레퍼런스가 적고 여기저기 찾으면서 부분을 더듬고 있다보니 작성한 글에도 오류가 있을진 모르겠다. PX4에 대해 익숙해진다면 고생하는 초심자들을 위해 관련 가이드 서적을 만들고 싶단 생각이 든다. 다음엔 어떤 기능을 만들어야 할까.

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 모델 데이터베이스에 접근하고 모델을 다운로드 받을 때 사용한다

앞으로 C++로 개발할 일이 많아질 것 같아 기본적인 문법들을 이해하고자 작성함.

 

# 접근지정자

접근 지정자에는 크게 public, private, protected가 있다. 접근지정자는 C++에서 클래스안의 멤버함수와 멤버변수에 접근 여부를 제어할 때 사용한다. public에 멤버함수나 멤버변수를 두면 클래스 외부를 포함한 모든 곳에서 접근가능하다. private에 멤버변수나 멤버변수를 두면 클래스 내부에서만 접근가능하고 외부에서는 접근할 수 없다. protected는 상속과 관련됨 (추가 이해 필요)

 

# this

C++에서 this는 클래스의 실제 인스턴스에 대한 주소를 가리키는 포인터다. 클래스의 모든 함수는 함수가 호출된 객체를 가리키는 this 포인터를 갖는다. 이는 컴파일러가 동작하는 과정에서 implicit하게 this 포인터를 사용가능하도록 만들기 때문이다. this 포인터는 크게 두 가지 측면으로 활용된다. 첫 번째는 멤버변수와 매개변수의 이름이 같을 때 구분할 수 있고, 두 번째는 함수에서 *this를 반환하는 방식으로 함수체이닝으로 코드를 간결하게 작성할 수 있다.

 

# auto

auto는 자료형을 자동으로 추론할 때 사용한다. 예를 들어 다음과 같다.

int main(void)
{
	int a = 5;
    int b = 21;
    auto sum = a + b;
}

별도의 int, float, double, char 등을 지정해주지 않아도 자동 타입추론을 통해 자료형을 할당한다.

 

 

# 람다함수

람다함수는 메모리 효율을 위해 사용한다. 일반 함수와 달리 함수명이 없는 것이 특징이다. 람다함수의 구조는 크게 4가지로 구성된다. [](){}()다. 역할을 먼저 설명하면 가장 첫번째인 []는 캡처, ()는 매개변수, {}는 함수동작, ()는 호출인자다. []인 캡처는 매개변수와 동일하게 값을 받아와 사용할 수 있다. call-by-value 또는 call-by-reference로 받아올 수 있다. call-by-value는 외부변수를 변경하지 않을때 사용하고 call-by-reference는 외부변수를 변경할 때 사용한다. 예를 들어 call-by-reference로 사용할 때는 다음과 같다.

 

int main(void)
{
	int r1 = 1;
    int r2 = 2;
    
    [r1, r2](int a, int b)
    {
    	cout << r1 + r2 + a + b << endl;
    }
}

 

call-by-reference로 사용할 때는 다음과 같다.

int main(void)
{
	int r1 = 1;
    int r2 = 2;
    
    [&r1, &r2](int a, int b)
    {
    	r1 = 2;
        r2 = 4;
        cout << r1 + r2 + a + b << endl;
    }
}

 

캡처는 이외에도 [=]를 통해 외부변수 전체를 복사해 가져올 수도 있고 [&]를 통해 외부변수 전체를 참조할 수도 있다.

 

람다함수 구조의 두 번째인 ()는 매개변수를 의미한다. 위 코드에서 (int a, int b)와 같다. 세 번째인 {}는 동작할 함수 동작이다. 위 코드 예시에서는 값을 더해주고 출력하는 것이다. 네 번째인 ()는 두 번째 매개변수와 다른 호출인자다. (int a, int b)에 실질적으로 넣어줄 값을 의미한다. 

 

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

+ Recent posts