PX4 and ROS Programming Day 1
수업
- 목표: 드론 제어 소프트웨어에 대해 이해할 수 있고, 프로그래밍 환경을 구축할 수 있다.
- 교재: https://learn.dronemap.io/
- 코치: 박동희 dongheepark@gmail.com
드론 제어 소프트웨어 소개 및 설치
- 워크숍 소개, 참가자 소개
- PX4 소개, ROS 소개
- Linux 사용하기
PX4 소개
- https://px4.io/
- Pixhawk
- PX4 Firmware
- Mavlink
- QGroundControl
- https://learn.dronemap.io/px4-workbook/px4-intro.html
- 소프트웨어 아키텍처
- 시뮬레이터 포트 구성
PX4 미들웨어 및 앱 구조 소개
- 디렉토리 구조 소개
- uORB
- PX4 shell 사용하기
- hello-skyworld
Linux 사용하기
- Ubuntu 18.04 설치
- 주요 명령어 소개(파일 조작, 프로그램설치, 쉘스크립트, git)
ls: 파일 또는 디렉토리의 목록을 출력
ls
ls -al
cd: 디렉토리 이동
cd ~
cd ~/Downloads
pwd: 현재 디렉토리 출력
pwd
mkdir: 디렉토리 생성
mkdir tmp
rm: 파일 또는 디렉토리 지우기
rm -rf tmp
cat: 파일 입력 또는 출력
cat ~/.bashrc
cat > ~/.hello.c
cp: 파일 또는 디렉토리 복사
cp hello.c world.c
chmod: 파일의 퍼미션 지정
chmod +x hello
wget: url에서 파일 다운로드
wget https://google.com
source: 현재 쉘에서 파일을 읽고 실행
source ~/.bashrc
PX4 개발환경 구성 (+ROS)
https://dev.px4.io/master/en/setup/dev_env_linux_ubuntu.html
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
PX4 Firmware Build
- https://dev.px4.io
- Gazebo 사용하기
- Qgroundcontrol
PX4 v.10.1 다운로드
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
Gazebo 실행
cd ~/Firmware
make px4_sitl gazebo
QGroundControl 사용
다운로드: https://docs.qgroundcontrol.com/en/getting_started/download_and_install.html
QGroundControl 다운로드 및 실행
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
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
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";
}
Perception: Sense
- Sensor Fusion
- Filtering
- Localization
Dicesion Making: Decide
- Path Planning
- Prediction
- Behavior Planning
Actuation: Act
- PID Control
- Model Predictive Control
ROS Master Process
노드 관리
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";
}
}
Topics
노드간 통신 인터페이스. 구독 발행의 이름
digraph {
rankdir=LR
node [color="#40e0d0"]
edge [fontname="MS Gothic"];
node1 [label= ""]
node2 [label= ""]
node1 -> node2 [label="/topic_name"];
}
Publish and Subscribe
발행과 구독. 신문/잡지 발행 구독에 비유
digraph {
rankdir=LR
node [color="#40e0d0"]
edge [fontname="MS Gothic"];
label = " PUBLISH SUBSCRIBER";
node1 [label= ""]
node2 [label= ""]
node1 -> node2
node2 -> node1
}
실제 예제
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"]
}
ROS Message Passing
메시지: 노드간 통신할때 이동하는 실제 데이터
- 메시지는 텍스트로 구성. 메시지를 이해하기 쉽다.
미리 정의된 메시지 타입 :
- http://wiki.ros.org/common_msgs
- https://github.com/ros/common_msgs
ROS Services
- Request-Response, 1:1 통신
- PubSub이 필요 없는 경우 사용, 요청 할때만 데이터가 제공. 네트워크 부하가 적다.
예시: 카메라 이미지 얻기
digraph {
rankdir=LR;
node [color="#40e0d0"];
edge [fontname="MS Gothic"];
label = "Publicate and Subscribe";
"Camera" -> "Behavior Executor" [label="/camera_images\limage"]
}
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"]
}
ROS Turtlesim
Turtle

Turtlesim 실행하기

- 환경 변수 설정
source /opt/ros/melodic/setup.bash
- roscore 실행
- roscore: Master + rosout + parameter server
- Master: 네임 서비스
- rosout: stdout/stderr 로깅
- parameter server: 파라미터 저장 서버
- roscore: Master + rosout + parameter server
roscore
- turtlesim 패키지의
turtlesim_node실행
rosrun turtlesim turtlesim_node
- turtlesim 패키지의
turtle_teleop_key실행
rosrun turtlesim turtle_teleop_key
Turtlesim 노드 목록
rosnode list
/rosout : ROS 메시지 로깅.
Turtlesim 토픽 목록
rostopic list
Turtlesim 토픽 정보
rostopic info /turtle1/cmd_vel
Turtlesim 메시지 정보
$ 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
or
rosed geometry_msgs Twist.msg
Turtlesim Echo a Topic
디버깅시 편리
rostopic echo /turtle1/cmd_vel
rqt_graph
rqt_graph

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

MavROS 설치 및 실행 (이미 자동설치됨, 안해도됨)
## 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
환경변수 설정: workspace
cd ~/catkin_ws source devel/setup.bash
mavros_node 실행
rosrun mavros mavros_node _fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:="udp://@127.0.0.1"
mavros_node 실행 (roslaunch 사용하는 방법)
# 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"
Gazebo 실행
시뮬레이터의 홈 위치(위도 경도 해발고도) 지정
export PX4_HOME_LAT=35.9012382
export PX4_HOME_LON=128.854495337
export PX4_HOME_ALT=71
cd ~/Firmware
make px4_sitl gazebo
ROS 노드 관리
ROS 노드 실행 및 관리
ROS Core 노드 실행
roscore
MAVROS 노드 실행
rosrun mavros mavros_node _fcu_url:="udp://:14540@127.0.0.1:14557" _gcs_url:="udp://@127.0.0.1"
토픽 목록
rostopic list
토픽 내용 보기
메시지 타입 보기
rostopic info /mavros/state
타입 내부 보기
rostopic type /mavros/state | rosmsg show
메시지 내용
rostopic echo /mavros/state
토픽 publish 주기 보기
rostopic hz /mavros/state
실행 노드 확인
rqt_graph
ROS 노드 명령 실행하기. (MAVROS 위주)
http://wiki.ros.org/ROS/Tutorials/UnderstandingTopics
Subscribe
rostopic echo [topic]
STATE
rostopic echo /mavros/state
LOCAL_POSITION 확인
rostopic echo /mavros/local_position/pose
Services
서비스 목록
rosservice list
서비스 실행(call) 하기
rosservice call [topic] [msg_type] [args]
SET_MODE
# 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'"
ARMING
rosservice call /mavros/cmd/arming "value: true"
TAKEOFF
rosservice call /mavros/cmd/takeoff "{min_pitch: 0.0, yaw: 0.0, latitude: 47.3977508, longitude: 8.5456074, altitude: 2.5}"
Land
rosservice call /mavros/cmd/land "{min_pitch: 0.0, yaw: 0.0, latitude: 47.3977508, longitude: 8.5456074, altitude: 0.0}"
Publish
rostopic pub [topic] [msg_type] [args]
SETPOINT_POSITION
OFFBOARD 모드에서 동작
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"
SETPOINT_VELOCITY
OFFBOARD 모드에서 동작
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}}}"
실습
준비: 순서대로 실행
- 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 순서 오일러->쿼터니언 변환
\begin{align}
\begin{bmatrix}
x
y \
z \
w \
\end{bmatrix}
& =
\begin{bmatrix}
cos (φ /2) cos (θ /2) cos (ψ /2) + sin (φ /2) sin (θ /2) sin (ψ /2) \
sin (φ /2) cos (θ /2) cos (ψ /2) - cos (φ /2) sin (θ /2) sin (ψ /2) \
cos (φ /2) sin (θ /2) cos (ψ /2) + sin (φ /2) cos (θ /2) sin (ψ /2) \
cos (φ /2) cos (θ /2) sin (ψ /2) - sin (φ /2) sin (θ /2) cos (ψ /2) \
\end{bmatrix} \
\end{align}
변환 코드(python): https://gist.github.com/donghee/e3b4fa8ec789cec0e287bf3b91ddb79e
유용한 mavros 명령(노드) 모음
mavros 패키지의 mavsafety 노드: arm, disarm, safetyarea
rosrun mavros mavsafety arm
mavcmd 노드:
예시: takeoff from current position (10도 각도 피치, 90도 방향 보고, 5m 위로 takeoff)
rosrun mavros mavcmd takeoffcur 10 90 5
예시: home 지정(RTL 위치, 위도 35.9012382 경도 128.85449537 해발고도 71m) google earth: https://earth.google.com/web/search/35.9012382+128.85449537
rosrun mavros mavcmd sethome 35.9012382 128.854495337 71
mavsetp 노드: setpoint 한번 보내기 (setpoint 테스트용, position, velocity, acceleration 가능)
예시: x=1m, y=1m, z=1m, yaw=90도 setpoint 보내기
rosrun mavros mavsetp local -p 1 1 2 90
mavsys 노드: change mode
rosrun mavros mavsys mode -c OFFBOARD
mavparam 노드: parameter set, get, load, dump
예시: 파라미터 덤프
rosrun mavros mavparam dump /tmp/params
mavftp 노드: px4의 파일 시스템 접근
예시: 로그 다운로드
rosrun mavros mavftp download log/2020-08-03/14_37_15.ul
토픽 레코드: rosbag
리뷰할때 유용
토픽 저장하기
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
참고
- https://github.com/mavlink/mavros/tree/master/mavros
ROS 노드 만들기
새로운 노드 만들기
패키지 만들기
source ~/catkin_ws/devel/setup.bash
cd ~/catkin_ws/src
catkin_create_pkg drone_control mavros sensor_msgs roscpp rospy
노드 코드 작성
~~/catkin_ws/src/drone_control/src/drone_state.cpp~
#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;
}
빌드 스크립트 추가
~~/catkin_ws/src/drone_control/CMakeLists.txt~ 파일 끝에 다음 3줄 추가
include_directories(include ${catkin_INCLUDE_DIRS})
add_executable(drone_state src/drone_state.cpp)
target_link_libraries(drone_state ${catkin_LIBRARIES})
환경 변수 다시 로드!
source ~/catkin_ws/devel/setup.bash
패키지 빌드
cd ~/catkin_ws
catkin build
패키지 노드 실행
drone_control 패키지의 drone_state 노드 실행
rosrun drone_control drone_state
해보기: /mavros/state 읽어서 1초마다 비행 mode 한번씩 출력
-
/mavros/state타입 체크하여 헤더 include
#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;
}
해보기 결과:
$ rosrun drone_control drone_state
[ INFO] [1539297808.077868114]:
Drone mode: OFFBOARD
[ INFO] [1539297808.525173697]:
Drone mode: OFFBOARD
[ INFO] [1539297809.565387356]:
Drone mode: OFFBOARD
rqt_graph

새로운 노드 만들기: 드론 이륙 착륙
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"];
}
drone_control 패키지에 takeoff_and_land 노드를 만들어 보자.
2.5m 이륙후 10초 있다가 착륙
~~/catkin_ws/src/drone_control/src/takeoff_and_land.cpp~
#include <cstdlib>
#include <ros/ros.h>
#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/CommandTOL.h>
#include <mavros_msgs/SetMode.h>
#include <geometry_msgs/PoseStamped.h>
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;
}
\~/catkin_ws/src/drone_control/CMakeLists.txt 파일 끝에 다음 2줄 추가
add_executable(takeoff_and_land src/takeoff_and_land.cpp)
target_link_libraries(takeoff_and_land ${catkin_LIBRARIES})
- 컴파일:
cd ~/catkin_ws; source devel/setup.bash; catkin build - 실행:
rosrun drone_control takeoff_and_land
새로운 노드 만들기: offb_node
drone_control 패키지에 offb_node 노드를 만들어 보자.
2m 이륙.
/**
* @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 <ros/ros.h>
#include <geometry_msgs/PoseStamped.h>
#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/SetMode.h>
#include <mavros_msgs/State.h>
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;
}
- 실행:
rosrun drone_control offb_node
launch 파일을 이용하여 노드 한번에 실행 (옵션)
roscore, gazebo, mavros, offb_node 노드를 한번에 실행하기 위해서 roslaunch를 이용해보자.
~~/catkin_ws/src/drone_control/launch/offb_node.launch~ 파일에 다음 내용 추가
<launch>
<node name="offb_node" pkg="drone_control" type="offb_node"/>
<include file="$(find px4)/launch/mavros_posix_sitl.launch">
<arg name="vehicle" value="iris"/>
</include>
</launch>
~~/.bashrc~ 파일의 끝에 다음 내용을 추가 환경 변수 추가
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
source ~/.bashrc
catkin build
roslaunch drone_control offb_node.launch
새로운 노드 만들기: circle
출처: https://github.com/Jaeyoung-Lim/modudculab_ros/blob/master/src/pub_setpoints_traj.cpp
/**
* @file circle.cpp
* @brief offboard example node, written with mavros version 0.14.2, px4 flight
* stack and tested in Gazebo SITL
*/
#include <ros/ros.h>
#include <geometry_msgs/PoseStamped.h>
#include <mavros_msgs/CommandBool.h>
#include <mavros_msgs/SetMode.h>
#include <mavros_msgs/State.h>
#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;
}
- 실행:
rosrun drone_control circle
해보기: 원의 너비와 속도를 바꾸어 보자. 힌트 (wn, r)
과제: 키보드로 OFFBOARD 모드 제어하기
-
offb_node코드를 참고하여, 키보드로 x,y,z 위치를 제어하여 보자. - 참고: http://wiki.ros.org/teleop_twist_keyboard_cpp
참고
- https://github.com/mavlink/mavros/tree/master/mavros
- https://github.com/Jaeyoung-Lim/modudculab_ros/blob/master/src/pub_setpoints_traj.cpp
