픽스호크
를 사용하고 있고, PX4
펌웨어를 항상 사용해왔는데, 좀 무거운 감이 있고 항상 알수 없는 문제들이 발생할 때가 많아서 조금 더 역사가 오래된 Ardupilot
펌웨어로 갈아타기로 했다.Ardupilot
에서도 드론 온보드 PC에서 바로 픽스호크
로 명령을 줄 수 있고, MAVROS
를 사용해서 GPS
없이 자율 비행 하도록 구현이 가능한데, 조금 헤맸어서 필요한 기초만 정리해두려고 한다.Ardupilot
용 SITL
과 Gazebo
, ROS
를 연동하는 법에 대해서 다뤘다.GPS
/GNSS
없이 SLAM
등의 외부 위치 추정값으로 드론을 비행하도록 파라미터 설정하는 방법과/mavros/vision_pose/pose
topic에 geometry_msgs/PoseStamped
형태로 쏴주면 되고, GPS
없이 비행하기 위해서는 다음과 같이 파라미터를 설정하면 된다.
SLAM
이 발산하는 등의 비상 상황에만 동작하므로 위해 PosZ는 Barometer, Yaw는 compass 등으로 적절히 설정하면 된다. 근데 저는 그냥 다 ExternalNav로 설정함PX4
펌웨어를 사용할때는 그냥 OFFBOARD
모드에서 /mavros/setpoint_position/local
topic에 명령 값을 주면 이륙과 착륙이 가능했는데, Ardupilot
에서는 그게 안된다.Lua script
사용 - 위도와 경도는 10의 7제곱을 곱해주어야하고, 고도는 cm단위이므로 100을 곱해주면 된다.
SCR_ENABLE
= 1 로 설정 (enable)픽스호크
SD카드의 APM/scripts 폴더에 파일을 넣으면 된다.픽스호크
가 켜질때 자동으로 실행됨 function update ()
if not ahrs:initialised() then
return update, 5000
end
origin = assert(not ahrs:get_origin(),"Refused to set EKF origin - already set")
location = Location() location:lat(-353632640) location:lng(1491652352) location:alt(58409)
if ahrs:set_origin(location) then
gcs:send_text(6, string.format("Origin Set - Lat:%.7f Long:%.7f Alt:%.1f", location:lat()/10000000, location:lng()/10000000, location:alt()/100))
else
gcs:send_text(0, "Refused to set EKF origin")
end
return
end
return update()
MAVROS
사용 - 위도와 경도 고도 모두 MAVROS
내에서 알맞게 곱해주므로 그대로 넣어주면 된다.
/mavros/global_position/set_gp_origin
topic에 값을 쏘면 된다 #include <ros/ros.h>
#include <geographic_msgs/GeoPointStamped.h> //ekf origin setter
ros::Publisher m_ekf_ahrs_origin_setter_pub = m_nh.advertise<geographic_msgs::GeoPointStamped>("/mavros/global_position/set_gp_origin", 3);
geographic_msgs::GeoPointStamped ekf_origin_;
ekf_origin_.header.stamp = ros::Time::now();
ekf_origin_.position.latitude = -35.3632640;
ekf_origin_.position.longitude = 149.1652352;
ekf_origin_.position.altitude = 584.09;
m_ekf_ahrs_origin_setter_pub.publish(ekf_origin_);
GUIDED
모드 명령 값이 아닌, land
명령을 줘야만 함 - MAV_CMD_NAV_LANDMAVROS
패키지를 사용하는 경우 /mavros/cmd/land
service에 명령 값을 쏴주면 되고 위 링크처럼 아무 값도 안넣고 쏘면 된다. 위도와 경도를 명시해주면 해당 위도와 경도로 날아가서 착륙한다는데, GPS
가 없을 때는 함부로 하지 말자.GUIDED
모드 명령 값이 아닌, takeoff
명령을 줘야만 함 - MAV_CMD_NAV_TAKEOFFMAVROS
패키지를 사용하는 경우 /mavros/cmd/takeoff
service에 명령 값을 쏴주면 되고 위 링크처럼 원하는 이륙 고도 값을 넣고 쏘면 된다. #include <ros/ros.h>
#include <mavros_msgs/SetMode.h> //GUIDED mode
#include <mavros_msgs/CommandTOL.h> //takeoff, land
#include <geographic_msgs/GeoPointStamped.h> //ekf origin setter
ros::Publisher m_position_controller_pub = m_nh.advertise<geometry_msgs::PoseStamped>("/mavros/setpoint_position/local", 3);
ros::Publisher m_ekf_ahrs_origin_setter_pub = m_nh.advertise<geographic_msgs::GeoPointStamped>("/mavros/global_position/set_gp_origin", 3);
ros::ServiceClient m_set_mode_client = m_nh.serviceClient<mavros_msgs::SetMode>("/mavros/set_mode");
ros::ServiceClient m_takeoff_client = m_nh.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/takeoff");
ros::ServiceClient m_land_client = m_nh.serviceClient<mavros_msgs::CommandTOL>("/mavros/cmd/land");
// Skip
...
...
...
geographic_msgs::GeoPointStamped ekf_origin_;
ekf_origin_.header.stamp = ros::Time::now();
ekf_origin_.position.latitude = -35.3632640;
ekf_origin_.position.longitude = 149.1652352;
ekf_origin_.position.altitude = 584.09;
m_ekf_ahrs_origin_setter_pub.publish(ekf_origin_);
mavros_msgs::SetMode mode_switch_command_;
mode_switch_command_.request.custom_mode = "GUIDED";
m_set_mode_client.call(mode_switch_command_);
mavros_msgs::CommandTOL mav_cmd_;
mav_cmd_.request.altitude = m_first_taking_off_altitude;
m_takeoff_client.call(mav_cmd_);
if (mav_cmd_.response.success)
{
ROS_WARN("Take off success!!");
}
geometry_msgs::PoseStamped goal_pose_stamped;
goal_pose_stamped.header.stamp = ros::Time::now(); //important
goal_pose_stamped.pose.position.x = 5.0;
goal_pose_stamped.pose.position.y = 0.0;
goal_pose_stamped.pose.position.z = 5.0;
goal_pose_stamped.pose.orientation.w = 1.0;
m_position_controller_pub.publish(goal_pose_stamped);
mavros_msgs::CommandTOL mav_cmd_;
m_land_client.call(mav_cmd_);
if (mav_cmd_.response.success)
{
ROS_WARN("Land success!!");
}