+STARTUP: showeverything

+AUTHOR: Donghee Park

Creative Commons, Share-Alike (cc)

+EMAIL: dongheepark@gmail.com

+TITLE: PX4 and ROS Programming Day 1

+HTML_HEAD_EXTRA:

+HTML_HEAD:

  • 수업

  • 드론 제어 소프트웨어 소개 및 설치

  1. 워크숍 소개, 참가자 소개

  2. PX4 소개, ROS 소개

  3. Linux 사용하기

** PX4 미들웨어 및 앱 구조 소개

  • 디렉토리 구조 소개
  • uORB
  • PX4 shell 사용하기
  • hello-skyworld
  • Linux 사용하기
    • Ubuntu 18.04 설치
    • 주요 명령어 소개(파일 조작, 프로그램설치, 쉘스크립트, git)

ls: 파일 또는 디렉토리의 목록을 출력

+BEGIN_SRC

ls ls -al

+END_SRC

cd: 디렉토리 이동

+BEGIN_SRC

cd ~ cd ~/Downloads

+END_SRC

pwd: 현재 디렉토리 출력

+BEGIN_SRC

pwd

+END_SRC

mkdir: 디렉토리 생성

+BEGIN_SRC

mkdir tmp

+END_SRC

rm: 파일 또는 디렉토리 지우기

+BEGIN_SRC

rm -rf tmp

+END_SRC

cat: 파일 입력 또는 출력

+BEGIN_SRC

cat ~/.bashrc cat > ~/.hello.c

+END_SRC

cp: 파일 또는 디렉토리 복사

+BEGIN_SRC

cp hello.c world.c

+END_SRC

chmod: 파일의 퍼미션 지정

+BEGIN_SRC

chmod +x hello

+END_SRC

wget: url에서 파일 다운로드

+BEGIN_SRC

wget https://google.com

+END_SRC

source: 현재 쉘에서 파일을 읽고 실행

+BEGIN_SRC

source ~/.bashrc

+END_SRC

  • PX4 개발환경 구성 (+ROS)

https://dev.px4.io/master/en/setup/dev_env_linux_ubuntu.html

+BEGIN_SRC

cd ~ wget https://raw.githubusercontent.com/PX4/Devguide/master/build_scripts/ubuntu_sim_ros_melodic.sh chmod +x ubuntu_sim_ros_melodic.sh ./ubuntu_sim_ros_melodic.sh

+END_SRC

** PX4 v.10.1 다운로드

+BEGIN_SRC

cd ~ git clone https://github.com/PX4/Firmware.git --recursive cd ~/Firmware bash ./Tools/setup/ubuntu.sh git checkout v1.10.1 git submodule update --init --recursive

+END_SRC

** Gazebo 실행

+BEGIN_SRC

cd ~/Firmware make px4_sitl gazebo

+END_SRC

** QGroundControl 사용

다운로드: https://docs.qgroundcontrol.com/en/getting_started/download_and_install.html

QGroundControl 다운로드 및 실행

+BEGIN_SRC

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

cd ~/Downloads chmod +x ./QGroundControl.AppImage ./QGroundControl.AppImage

+END_SRC

  • ROS 프로그래밍

** ROS

  • Robot Operating System: 로봇 빌드에 사용되는 라이브러리 어플리케이션 모음 http://www.ros.org/
  • 목표: 로봇을 만들때 기존의 재활용 하고 공유하자.
  • History:
    • 2000s: Standford Artificial intelligence
    • 2007: Willow Garage
    • 2013: Open Source Robotics Foundation
  • 사용 분야: Drone, Kinematic ARMS(로봇암), Wheeled(바퀴), Bi-pedal(이족)

** ROS Nodes and Topics

https://misohena.jp/article/emacs_org_textfigures/dot.html

+begin_src dot :file ros_nodes_and_topics1.png :cmdline -Kdot -Tpng

digraph { rankdir=LR graph [fontname="MS Gothic"]; node [shape=rect, color="#40e0d0"] edge [fontname="MS Gothic"]; label = "Robot Communication Sequence"; "Perception" -> "Dicesion Making"; "Dicesion Making" -> "Actuation"; }

+end_src

**** Perception: Sense - Sensor Fusion - Filtering - Localization

**** Dicesion Making: Decide - Path Planning - Prediction - Behavior Planning

**** Actuation: Act - PID Control - Model Predictive Control

*** ROS Master Process

노드 관리

+begin_src dot :file ros_master_process1.png :cmdline -Kdot -Tpng

digraph { graph [fontname="MS Gothic"]; node [shape=box, color="#40e0d0"] edge [fontname="MS Gothic"]; label = "ROS Master Process";

subgraph cluster_perception { node [shape=rect, style="rounded"] label = "Perception"; Camera; "Wheel Encoder"; "Positon Estimator"; }

subgraph cluster_dicesion_making { node [shape=rect, style="rounded"] label = "Dicesion Making"; "Behavior Execution"; }

subgraph cluster_actuation { node [shape=rect, style="rounded"] label = "Actuation"; "Motor Control"; } }

+end_src

*** Topics

노드간 통신 인터페이스. 구독 발행의 이름

+begin_src dot :file ros_topic1.png :cmdline -Kdot -Tpng

digraph { rankdir=LR node [color="#40e0d0"] edge [fontname="MS Gothic"]; node1 [label= ""] node2 [label= ""]

node1 -> node2 [label="/topic_name"]; }

+end_src

*** Publish and Subscribe

발행과 구독. 신문/잡지 발행 구독에 비유

+begin_src dot :file ros_publish_and_subscribe1.png :cmdline -Kdot -Tpng

digraph { rankdir=LR node [color="#40e0d0"] edge [fontname="MS Gothic"]; label = " PUBLISH SUBSCRIBER"; node1 [label= ""] node2 [label= ""]

node1 -> node2 node2 -> node1 }

+end_src

실제 예제

+begin_src dot :file ros_publish_and_subscribe2.png :cmdline -Kdot -Tpng

digraph { node [color="#40e0d0"] edge [fontname="MS Gothic"];

"Wheel Encoder" -> "Positon Estimator" [label="/wheel_encoder\lrotation"] "Behavior Executor" -> "Motor Controller" [label="/motor_controller\lvelocity_cmd"] "Camera" -> "Behavior Executor" [label="/camera_images\limage"] "Positon Estimator" -> "Behavior Executor" [label="/position_estimate\lpose"] }

+end_src

** ROS Message Passing

메시지: 노드간 통신할때 이동하는 실제 데이터

  • 메시지는 텍스트로 구성. 메시지를 이해하기 쉽다.

미리 정의된 메시지 타입 :

** ROS Services

  • Request-Response, 1:1 통신
  • PubSub이 필요 없는 경우 사용, 요청 할때만 데이터가 제공. 네트워크 부하가 적다.

*** 예시: 카메라 이미지 얻기

+begin_src dot :file ros_services1.png :cmdline -Kdot -Tpng

digraph { rankdir=LR; node [color="#40e0d0"]; edge [fontname="MS Gothic"]; label = "Publicate and Subscribe";

"Camera" -> "Behavior Executor" [label="/camera_images\limage"] }

+end_src

+begin_src dot :file ros_services2.png :cmdline -Kdot -Tpng

digraph { rankdir=LR; node [color="#40e0d0"]; edge [fontname="MS Gothic", style=dotted]; label = "Request-Response";

"Behavior Executor" -> "Camera" [label="/capture_image\lrequest: exposure time"] "Camera" -> "Behavior Executor" [label="\nresponse: image"] }

+end_src

** ROS Turtlesim

Turtle

+ATTR_HTML: width="200px"

*** Turtlesim 실행하기

  1. 환경 변수 설정

+begin_src sh

source /opt/ros/melodic/setup.bash

+end_src

  1. roscore 실행
    • roscore: Master + rosout + parameter server
    • Master: 네임 서비스
    • rosout: stdout/stderr 로깅
    • parameter server: 파라미터 저장 서버

+begin_src sh

roscore

+end_src

  1. turtlesim 패키지의 ~turtlesim_node~ 실행

    +begin_src sh

    rosrun turtlesim turtlesim_node

    +end_src

  2. turtlesim 패키지의 ~turtle_teleop_key~ 실행

    +begin_src sh

    rosrun turtlesim turtle_teleop_key

    +end_src

*** Turtlesim 노드 목록

+begin_src sh

rosnode list

+end_src

/rosout : ROS 메시지 로깅.

*** Turtlesim 토픽 목록

+begin_src sh

rostopic list

+end_src

*** Turtlesim 토픽 정보

+begin_src sh

rostopic info /turtle1/cmd_vel

+end_src

*** Turtlesim 메시지 정보

+begin_src sh

$ rosmsg info geometry_msgs/Twist geometry_msgs/Vector3 linear float64 x float64 y float64 z geometry_msgs/Vector3 angular float64 x float64 y float64 z

+end_src

or

+begin_src sh

rosed geometry_msgs Twist.msg

+end_src

*** Turtlesim Echo a Topic

디버깅시 편리

+begin_src sh

rostopic echo /turtle1/cmd_vel

+end_src

*** ~rqt_graph~

+begin_src sh

rqt_graph

+end_src

** MavROS

http://wiki.ros.org/mavros mavlink ros wrapper

*** MavROS 설치 및 실행 (이미 자동설치됨, 안해도됨)

+begin_src sh

Create catkin workspace (ROS build system)

mkdir -p ~/catkin_ws/src cd ~/catkin_ws

Install dependencies

sudo apt-get install python-wstool python-rosinstall-generator python-catkin-tools -y

Initialise wstool

wstool init ~/catkin_ws/src

Build MAVROS

Get source (upstream - released)

rosinstall_generator --upstream mavros --rosdistro kinetic | tee /tmp/mavros.rosinstall

Get latest released mavlink package

rosinstall_generator mavlink --rosdistro kinetic | tee -a /tmp/mavros.rosinstall

Setup workspace & install deps

wstool merge -t src /tmp/mavros.rosinstall wstool update -t src rosdep install --from-paths src --ignore-src --rosdistro kinetic -y

Install GeographicLib datasets

./src/mavros/mavros/scripts/install_geographiclib_datasets.sh

Build source

catkin build

source setup.bash

source devel/setup.bash

+end_src

환경변수 설정: workspace

+begin_src

cd ~/catkin_ws source devel/setup.bash

+end_src

~mavros_node~ 실행

+begin_src sh

rosrun mavros mavros_node _fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:="udp://@127.0.0.1"

+end_src

~mavros_node~ 실행 (roslaunch 사용하는 방법)

+begin_src sh

px4.launch 이용하여 mavros node 실행. fcu ip주소는 127.0.0.1 ip주소를 바꾸면 다른 컴퓨터의 fcu도 연결 가능.

cd ~/catkin_ws roslaunch mavros px4.launch fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:"udp://@127.0.0.1"

+end_src

** Gazebo 실행 시뮬레이터의 홈 위치(위도 경도 해발고도) 지정

+begin_src sh

export PX4_HOME_LAT=35.9012382 export PX4_HOME_LON=128.854495337 export PX4_HOME_ALT=71

cd ~/Firmware make px4_sitl gazebo

+end_src

  • ROS 노드 관리

** ROS 노드 실행 및 관리

**** ROS Core 노드 실행

+begin_src sh

roscore

+end_src

**** MAVROS 노드 실행

+begin_src sh

rosrun mavros mavros_node _fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:="udp://@127.0.0.1"

+end_src

J120 UART2에 PX4 telemetry 2 연결

roslaunch mavros px4.launch fcu_url:="/dev/ttyTHS1:921600" gcs_url:="udp://@192.168.88.53"

**** 토픽 목록

+begin_src sh

rostopic list

+end_src

**** 토픽 내용 보기

***** 메시지 타입 보기

+begin_src sh

rostopic info /mavros/state

+end_src

타입 내부 보기

+begin_src sh

rostopic type /mavros/state | rosmsg show

+end_src

***** 메시지 내용

+begin_src sh

rostopic echo /mavros/state

+end_src

***** 토픽 publish 주기 보기

+begin_src sh

rostopic hz /mavros/state

+end_src

***** 실행 노드 확인

+begin_src sh

rqt_graph

+end_src

** ROS 노드 명령 실행하기. (MAVROS 위주)

http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics

*** Subscribe

+begin_src sh

rostopic echo [topic]

+end_src

**** ~STATE~

+begin_src sh

rostopic echo /mavros/state

+end_src

**** ~LOCAL_POSITION~ 확인

+begin_src sh

rostopic echo /mavros/local_position/pose

+end_src

*** Services

서비스 목록

+begin_src sh

rosservice list

+end_src

서비스 실행(call) 하기

+begin_src sh

rosservice call [topic] [msg_type] [args]

+end_src

**** ~SET_MODE~

+begin_src sh

https://github.com/mavlink/mavros/blob/master/mavros_msgs/srv/SetMode.srv

http://wiki.ros.org/mavros/CustomModes

Manual Mode

rosservice call /mavros/set_mode "base_mode: 64 custom_mode: ''"

rosservice call /mavros/set_mode "base_mode: 0 custom_mode: 'MANUAL'"

rosservice call /mavros/set_mode "base_mode: 0 custom_mode: 'POSCTL'"

rosservice call /mavros/set_mode "base_mode: 0 custom_mode: 'OFFBOARD'"

rosservice call /mavros/set_mode "base_mode: 0 custom_mode: 'AUTO.LAND'"

+end_src

**** ~ARMING~

+begin_src sh

rosservice call /mavros/cmd/arming "value: true"

+end_src

**** ~TAKEOFF~

+begin_src sh

rosservice call /mavros/cmd/takeoff "{min_pitch: 0.0, yaw: 0.0, latitude: 47.3977508, longitude: 8.5456074, altitude: 2.5}"

+end_src

**** ~Land~

+begin_src sh

rosservice call /mavros/cmd/land "{min_pitch: 0.0, yaw: 0.0, latitude: 47.3977508, longitude: 8.5456074, altitude: 0.0}"

+end_src

*** Publish

+begin_src sh

rostopic pub [topic] [msg_type] [args]

+end_src

**** ~SETPOINT_POSITION~

OFFBOARD 모드에서 동작

+begin_src sh

rostopic pub -r 10 /mavros/setpoint_position/local geometry_msgs/PoseStamped "header: auto pose: position: x: 5.0 y: 0.0 z: 1.0 orientation: x: 0.0 y: 0.0 z: 0.0 w: 0.0"

+end_src

**** ~SETPOINT_VELOCITY~

OFFBOARD 모드에서 동작

+begin_src sh

rostopic pub -r 10 /mavros/setpoint_velocity/cmd_vel geometry_msgs/TwistStamped "{header: auto, twist: {linear: {x: 10.0, y: 0.0, z: 0.0}, angular: {x: 0.0, y: 0.0, z: 0.0}}}"

+end_src

*** 실습

준비: 순서대로 실행

  • Gazebo 실행: ~cd ~/Firmware; make px4_sitl gazebo~
  • PC의 MAVROS를 PC(127.0.0.1)의 Gazebo와 연결 ~rosrun mavros mavros_node _fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:="udp://@127.0.0.1"~ \ 또는 Raspberry PI의 MAVROS를 PC(192.168.88.53)의 Gazebo와 연결. Raspberry PI에서 다음 명령을 실행 ~roslaunch mavros px4.launch fcu_url:="udp://:14540@192.168.88.53:14557" gcs_url:="udp://@192.168.88.53"~
  • QGroundControl 실행: PX4 Parameter ~COM_OF_LOSS_T~ 파라미터 15초로 바꾸기. Failsafe timeout을 15초로 바꾸어야 커맨드라인에서 드론을 조정하기 편하다.

\

해보기: 커맨드 라인에서 다음 명령을 수행하여, QGroundControl에 아래와 같은 자취를 남겨보자.

  • 1. ARM
  • 2. TAKEOFF 하고. (옵션)
  • 3. 현재 위치를 지정한다. ~/mavros/setpoint_position~ 이용하여, (0,0,0) 위치를 10hz로 지정
  • 3-1. MODE 변환. OFFBOARD
  • 4. 20m 간격으로 정사각형을 따라 움직인다. ~/mavros/setpoint_position~ 이용
  • 5. HOME 자리에 오면 LAND 한다.
  • 6. DISARM

더해보기: 드론의 머리방향이 진행 방향을 향하도록 하자.

  • Body 3-2-1 순서 오일러->쿼터니언 변환

+HTML_MATHJAX: align: left indent: 5em tagside: left font: Neo-Euler

\begin{align} \begin{bmatrix} x \ y \ z \ w \ \end{bmatrix} & = \begin{bmatrix} \cos (\phi /2) \cos (\theta /2) \cos (\psi /2) + \sin (\phi /2) \sin (\theta /2) \sin (\psi /2) \ \sin (\phi /2) \cos (\theta /2) \cos (\psi /2) - \cos (\phi /2) \sin (\theta /2) \sin (\psi /2) \ \cos (\phi /2) \sin (\theta /2) \cos (\psi /2) + \sin (\phi /2) \cos (\theta /2) \sin (\psi /2) \ \cos (\phi /2) \cos (\theta /2) \sin (\psi /2) - \sin (\phi /2) \sin (\theta /2) \cos (\psi /2) \ \end{bmatrix} \ \end{align}

변환 코드(python): https://gist.github.com/donghee/e3b4fa8ec789cec0e287bf3b91ddb79e

https://www.andre-gaschler.com/rotationconverter/

*** 유용한 mavros 명령(노드) 모음

mavros 패키지의 mavsafety 노드: arm, disarm, safetyarea

+begin_src

rosrun mavros mavsafety arm

+end_src

mavcmd 노드:

예시: takeoff from current position (10도 각도 피치, 90도 방향 보고, 5m 위로 takeoff)

+begin_src

rosrun mavros mavcmd takeoffcur 10 90 5

+end_src

예시: home 지정(RTL 위치, 위도 35.9012382 경도 128.85449537 해발고도 71m) google earth: https://earth.google.com/web/search/35.9012382+128.85449537

+begin_src

rosrun mavros mavcmd sethome 35.9012382 128.854495337 71

+end_src

mavsetp 노드: setpoint 한번 보내기 (setpoint 테스트용, position, velocity, acceleration 가능)

예시: x=1m, y=1m, z=1m, yaw=90도 setpoint 보내기

+begin_src

rosrun mavros mavsetp local -p 1 1 2 90

+end_src

mavsys 노드: change mode

+begin_src

rosrun mavros mavsys mode -c OFFBOARD

+end_src

mavparam 노드: parameter set, get, load, dump

예시: 파라미터 덤프

+begin_src

rosrun mavros mavparam dump /tmp/params

+end_src

mavftp 노드: px4의 파일 시스템 접근

예시: 로그 다운로드

+begin_src

rosrun mavros mavftp download log/2020-08-03/14_37_15.ul

+end_src

** 토픽 레코드: rosbag 리뷰할때 유용

토픽 저장하기

+begin_src

rostopic list -v mkdir ~/bagfiles cd ~/bagfiles rosbag record -O iris_default_1 /mavros/local_position/pose rosbag info iris_default_1.bag rqt_bag

+end_src

** 참고

  • ROS 노드 만들기

** 새로운 노드 만들기

*** 패키지 만들기

+begin_src sh

source ~/catkin_ws/devel/setup.bash cd ~/catkin_ws/src catkin_create_pkg drone_control mavros sensor_msgs roscpp rospy

+end_src

*** 노드 코드 작성

~~/catkin_ws/src/drone_control/src/drone_state.cpp~

+begin_src c++

include "ros/ros.h"

include "sensor_msgs/Imu.h"

void imuDataCallback(const sensor_msgs::Imu::ConstPtr& msg){ ROS_INFO("\nlinear acceleration\ \nx: [%f]\ny:[%f]\nz:[%f]", msg->linear_acceleration.x, msg->linear_acceleration.y, msg->linear_acceleration.z); }

int main(int argc, char **argv){ ros::init(argc, argv, "drone_state"); ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe("/mavros/imu/data", 1000, imuDataCallback); ros::spin(); return 0; }

+end_src

빌드 스크립트 추가

~~/catkin_ws/src/drone_control/CMakeLists.txt~ 파일 끝에 다음 3줄 추가

+begin_src cmake

include_directories(include ${catkin_INCLUDE_DIRS}) add_executable(drone_state src/drone_state.cpp) target_link_libraries(drone_state ${catkin_LIBRARIES})

+end_src

환경 변수 다시 로드!

+begin_src sh

source ~/catkin_ws/devel/setup.bash

+end_src

*** 패키지 빌드

+begin_src sh

cd ~/catkin_ws catkin build

+end_src

*** 패키지 노드 실행

~drone_control~ 패키지의 ~drone_state~ 노드 실행

+begin_src sh

rosrun drone_control drone_state

+end_src

*** 해보기: /mavros/state 읽어서 1초마다 비행 mode 한번씩 출력

  • ~/mavros/state~ 타입 체크하여 헤더 include

+BEGIN_SRC c++

include "ros/ros.h"

include "mavros_msgs/State.h"

void droneStateCallback(const mavros_msgs::State::ConstPtr& msg){ ROS_INFO("\nDrone mode: %s", msg->mode.c_str()); }

int main(int argc, char **argv){ ros::init(argc, argv, "drone_state"); ros::NodeHandle nh; ros::Subscriber sub = nh.subscribe("/mavros/state", 1000, droneStateCallback); ros::spin(); return 0; }

+END_SRC

*** 해보기 결과:

+begin_src c++

$ rosrun drone_control drone_state [ INFO] [1539297808.077868114]: Drone mode: OFFBOARD [ INFO] [1539297808.525173697]: Drone mode: OFFBOARD [ INFO] [1539297809.565387356]: Drone mode: OFFBOARD

+end_src

~rqt_graph~

** 새로운 노드 만들기: 드론 이륙 착륙

+begin_src dot :file mavros_takeoff_and_land1.png :cmdline -Kdot -Tpng

digraph { rankdir=LR graph [fontname="NanumSquare"]; node [shape=rect, color="#40e0d0"] edge [style=dashed, fontname="NanumSquare"]; node1 [label= "/takeoff_and_land"] node2 [label= "/mavros"]

node1 -> node2 [label="1. /mavros/cmd/arming"]; node1 -> node2 [label="2. /mavros/cmd/takeoff"]; node1 -> node2 [label="3. /mavros/cmd/land"]; }

+end_src

~drone_control~ 패키지에 ~takeoff_and_land~ 노드를 만들어 보자.

2.5m 이륙후 10초 있다가 착륙

~~/catkin_ws/src/drone_control/src/takeoff_and_land.cpp~

+begin_src c++

include

include

include

include

include

include

int main(int argc, char **argv) {

int rate = 20;

ros::init(argc, argv, "takeoff_and_land");
ros::NodeHandle n;

ros::Rate r(rate);

///////////////////ARM//////////////////////
ros::ServiceClient arming_client = n.serviceClient<mavros_msgs::CommandBool>("/mavros/cmd/arming");
mavros_msgs::CommandBool arm_cmd;
arm_cmd.request.value = true;

if (arming_client.call(arm_cmd) && arm_cmd.response.success)
{
    ROS_INFO("Vehicle armed");
} else {
    ROS_ERROR("Failed arming or disarming");
}

/////////////////TAKEOFF////////////////////
ros::ServiceClient takeoff_client = n.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/takeoff");
mavros_msgs::CommandTOL takeoff_cmd;
takeoff_cmd.request.altitude = 10;
takeoff_cmd.request.latitude = 47.3977508;
takeoff_cmd.request.longitude = 8.5456074;
takeoff_cmd.request.min_pitch = 0;
takeoff_cmd.request.yaw = 0;
if(takeoff_client.call(takeoff_cmd) && takeoff_cmd.response.success){
    ROS_INFO("Okay Takeoff");
}else{
    ROS_ERROR("Failed Takeoff");
}

/////////////////DO STUFF///////////////////
sleep(10);


///////////////////LAND/////////////////////
ros::ServiceClient land_client = n.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/land");
mavros_msgs::CommandTOL land_cmd;
land_cmd.request.altitude = 0;
land_cmd.request.latitude = 47.3977508;
land_cmd.request.longitude = 8.5456074;
land_cmd.request.min_pitch = 0;
land_cmd.request.yaw = 0;
if(land_client.call(land_cmd) && land_cmd.response.success){
    ROS_INFO("Okay Land");
}else{
    ROS_ERROR("Failed Land");
}

while (n.ok())
{
  ros::spinOnce();
  r.sleep();
}

return 0;

}

+end_src

~~/catkin_ws/src/drone_control/CMakeLists.txt~ 파일 끝에 다음 2줄 추가

+begin_src cmake

add_executable(takeoff_and_land src/takeoff_and_land.cpp) target_link_libraries(takeoff_and_land ${catkin_LIBRARIES})

+end_src

  • 컴파일: ~cd ~/catkin_ws; source devel/setup.bash; catkin build~
  • 실행: ~rosrun drone_control takeoff_and_land~

** 새로운 노드 만들기: ~offb_node~

~drone_control~ 패키지에 ~offb_node~ 노드를 만들어 보자.

2m 이륙.

+begin_src c++

/**

  • @file offb_node.cpp
  • @brief Offboard control example node, written with MAVROS version 0.19.x, PX4 Pro Flight
  • Stack and tested in Gazebo SITL */

include

include

include

include

include

mavros_msgs::State current_state; void state_cb(const mavros_msgs::State::ConstPtr& msg){ current_state = *msg; }

int main(int argc, char **argv) { ros::init(argc, argv, "offb_node"); ros::NodeHandle nh;

ros::Subscriber state_sub = nh.subscribe<mavros_msgs::State>
        ("mavros/state", 10, state_cb);
ros::Publisher local_pos_pub = nh.advertise<geometry_msgs::PoseStamped>
        ("mavros/setpoint_position/local", 10);
ros::ServiceClient arming_client = nh.serviceClient<mavros_msgs::CommandBool>
        ("mavros/cmd/arming");
ros::ServiceClient set_mode_client = nh.serviceClient<mavros_msgs::SetMode>
        ("mavros/set_mode");

//the setpoint publishing rate MUST be faster than 2Hz
ros::Rate rate(20.0);

// wait for FCU connection
while(ros::ok() && !current_state.connected){
    ros::spinOnce();
    rate.sleep();
}

geometry_msgs::PoseStamped pose;
pose.pose.position.x = 0;
pose.pose.position.y = 0;
pose.pose.position.z = 2;

//send a few setpoints before starting
for(int i = 100; ros::ok() && i > 0; --i){
    local_pos_pub.publish(pose);
    ros::spinOnce();
    rate.sleep();
}

mavros_msgs::SetMode offb_set_mode;
offb_set_mode.request.custom_mode = "OFFBOARD";

mavros_msgs::CommandBool arm_cmd;
arm_cmd.request.value = true;

ros::Time last_request = ros::Time::now();

while(ros::ok()){
    if( current_state.mode != "OFFBOARD" &&
        (ros::Time::now() - last_request > ros::Duration(5.0))){
        if( set_mode_client.call(offb_set_mode) &&
            offb_set_mode.response.mode_sent){
            ROS_INFO("Offboard enabled");
        }
        last_request = ros::Time::now();
    } else {
        if( !current_state.armed &&
            (ros::Time::now() - last_request > ros::Duration(5.0))){
            if( arming_client.call(arm_cmd) &&
                arm_cmd.response.success){
                ROS_INFO("Vehicle armed");
            }
            last_request = ros::Time::now();
        }
    }

    local_pos_pub.publish(pose);

    ros::spinOnce();
    rate.sleep();
}

return 0;

}

+end_src

  • 실행: ~rosrun drone_control offb_node~

*** launch 파일을 이용하여 노드 한번에 실행 (옵션) roscore, gazebo, mavros, offb_node 노드를 한번에 실행하기 위해서 roslaunch를 이용해보자.

~~/catkin_ws/src/drone_control/launch/offb_node.launch~ 파일에 다음 내용 추가

+begin_src

+end_src

~~/.bashrc~ 파일의 끝에 다음 내용을 추가 환경 변수 추가

+begin_src

PX4_SRC_DIR=$HOME/Firmware source $PX4_SRC_DIR/Tools/setup_gazebo.bash $PX4_SRC_DIR $PX4_SRC_DIR/build/px4_sitl_default > /dev/null export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$PX4_SRC_DIR:$PX4_SRC_DIR/Tools/sitl_gazebo

+end_src

+begin_src sh

source ~/.bashrc catkin build

+end_src

+begin_src sh

roslaunch drone_control offb_node.launch

+end_src

** 새로운 노드 만들기: ~circle~

출처: https://github.com/Jaeyoung-Lim/modudculab_ros/blob/master/src/pub_setpoints_traj.cpp

+begin_src

/**

  • @file circle.cpp
  • @brief offboard example node, written with mavros version 0.14.2, px4 flight
  • stack and tested in Gazebo SITL */

include

include

include

include

include

include "math.h"

double r; double theta; double count=0.0; double wn;

mavros_msgs::State current_state; void state_cb(const mavros_msgs::State::ConstPtr& msg){ current_state = *msg; }

int main(int argc, char **argv) { ros::init(argc, argv, "circle"); ros::NodeHandle nh;

ros::Subscriber state_sub = nh.subscribe<mavros_msgs::State>
        ("mavros/state", 10, state_cb);
ros::Publisher local_pos_pub = nh.advertise<geometry_msgs::PoseStamped>
        ("mavros/setpoint_position/local", 10);
ros::ServiceClient arming_client = nh.serviceClient<mavros_msgs::CommandBool>
        ("mavros/cmd/arming");
ros::ServiceClient set_mode_client = nh.serviceClient<mavros_msgs::SetMode>
        ("mavros/set_mode");

//the setpoint publishing rate MUST be faster than 2Hz
ros::Rate rate(20.0);


nh.param("pub_setpoints_traj/wn", wn, 1.0);
nh.param("pub_setpoints_traj/r", r, 1.0);
// wait for FCU connection
while(ros::ok() && current_state.connected){
    ros::spinOnce();
    rate.sleep();
}

geometry_msgs::PoseStamped pose;
pose.pose.position.x = 0;
pose.pose.position.y = 0;
pose.pose.position.z = 2;

//send a few setpoints before starting
for(int i = 100; ros::ok() && i > 0; --i){
    local_pos_pub.publish(pose);
    ros::spinOnce();
    rate.sleep();
}

mavros_msgs::SetMode offb_set_mode;
offb_set_mode.request.custom_mode = "OFFBOARD";

mavros_msgs::CommandBool arm_cmd;
arm_cmd.request.value = true;

j ros::Time last_request = ros::Time::now();

while(ros::ok()){
    if( current_state.mode != "OFFBOARD" &&
        (ros::Time::now() - last_request > ros::Duration(5.0))){
        if( set_mode_client.call(offb_set_mode) &&
            offb_set_mode.response.mode_sent){
            ROS_INFO("Offboard enabled");
        }
        last_request = ros::Time::now();
    } else {
        if( !current_state.armed &&
            (ros::Time::now() - last_request > ros::Duration(5.0))){
            if( arming_client.call(arm_cmd) &&
                arm_cmd.response.success){
                ROS_INFO("Vehicle armed");
            }
            last_request = ros::Time::now();
        }
    }

    theta = wn*count*0.05;

    pose.pose.position.x = r*sin(theta);
    pose.pose.position.y = r*cos(theta);
    pose.pose.position.z = 2;

    count++;

    local_pos_pub.publish(pose);
    ros::spinOnce();
    rate.sleep();
}

return 0;

}

+end_src

  • 실행: ~rosrun drone_control circle~ *** 해보기: 원의 너비와 속도를 바꾸어 보자. 힌트 (wn, r)

** 과제: 키보드로 OFFBOARD 모드 제어하기

** 참고