[Research] Visual-Lidar SLAM for UAV
드론에 RGBD 카메라와 Lidar 센서를 부착하여 SLAM을 하는 프로젝트를 진행한다.
먼저 개발환경을 세팅해야 하는데,
참고한 사이트는 다음과 같다.
dnddnjs.gitbooks.io/drone-autonomous-flight/content/
시작전에 개발 환경에 대해서 언급해야 겠다.
2020년 10월 8일 기준 드론을 ROS로 구동하기 위한 펌웨어인 PX4는 더 이상 Ubuntu 16.04를 지원하지 않는다.
예를 들어 Ubuntu 16.04에서는 Gazebo7 버전이 사용되지만, Ubuntu 18.04에서는 Gazebo9 버전이 사용되며, PX4는 Gazebo7을 더 이상 호환하지 않는다. 따라서 위 링크를 참고하되 버전에 대한 수정을 포함하여 진행한다.
순서는 다음과 같다.
- Ubuntu 18.04 설치
- ROS Melodic & Gazebo9 설치
- PX4 설치
- 시뮬레이션 실행 (takeoff)
- modulab의 경우
1. Ubuntu 18.04 설치
Ubuntu 18.04 설치 관련하여서는 이미 잘 정리해놓은 블로거 분들이 많기 때문에 링크로 대신하겠다.
[Ubuntu] 윈도우가 설치된 컴퓨터에 듀얼부팅 우분투 18.04 LTS 설치하기
2. ROS Melodic & Gazebo9 설치
아래 링크를 참고하여 스크립트로 설치 진행.
dev.px4.io/master/en/setup/dev_env_linux_ubuntu.html
pre-packages install
sudo apt-get install python3-pip
pip install future
sudo apt-get install ros-melodic-libgeographic-dev
sudo apt-get install ros-melodic-geographic-msgs ros-melodic-geographic-info
## Download the script in a bash shell:
$ wget https://raw.githubusercontent.com/PX4/Devguide/master/build_scripts/ubuntu_sim_ros_melodic.sh
## Run the script:
$ bash ubuntu_sim_ros_melodic.sh
이 후, gazebo를 다시 실행하려 하면 의존성 패키지 에러가 발생한다.
이를 예방하기 위해 아래 명령어로 의존성 패키지를 설치한다.
sudo apt install libgstreamer1.0-dev
sudo apt install gstreamer1.0-plugins-good
sudo apt install gstreamer1.0-plugins-bad
sudo apt install gstreamer1.0-plugins-ugly
3. PX4 설치
이제 PX4 Firmware를 설치한다.
cd <path>
git clone https://github.com/PX4/Firmware.git
cd Firmware
git submodule update --init --recursive
이제 시뮬레이션을 돌려보자.
4. 시뮬레이션 실행 (takeoff)
이제 드론을 한번 띄워보자.
참고할 링크는 다음과 같다.
INSTALLING ROS GAZEBO MAVROS AND PX4
$ no_sim=1 make px4_sitl_default gazebo
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris.world
Gazebo가 켜지면 드론을 추가해준다.
이 후, sitl에서 gazebo와 연결되면 다음 명령어를 통해 드론을 띄워본다.
pxh> commander takeoff
5. modulab의 경우
다음 명령어를 통해 드론을 띄울 수 있다.
# terminal_1
$ roscore
# terminal_2
$ cd ~/Firmware
$ make px4_sitl_default gazebo
# terminal_3
$ roslaunch modudculab_ros ctrl_pos_gazebo.launch
# terminal_4
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
6. 가상의 실내환경
실내 지도작성이 목적이기 때문에 실내환경을 가져와 보도록 하겠다.
참고 링크는 다음과 같다.
Gazebo Simulation > Loading a Specific World
다음 명령어를 사용하여 warehous map을 가져올 수 있다.
# terminal_1
$ roscore
# terminal_2
$ cd ~/Firmware
$ make px4_sitl_default gazebo___warehouse ## "_" 가 총 3개 인 것에 주의
# terminal_3
$ roslaunch modudculab_ros ctrl_pos_gazebo.launch
# terminal_4
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
7. 다운로드 Gazebo 모델 데이터
Gazebo의 더 다양한 환경을 얻기 위해 데이터를 다운로드 한다.
아래 두 개 링크를 참고하였으며,
sdf 파일이 들어 있는 폴더들을
"~/.gazebo/models"
폴더로 옮겨주면 gazebo를 켰을 때, 인식이 되게 된다.
data.nvision2.eecs.yorku.ca/3DGEMS/
3DGEMS 에서는 기존에 만들어진 world도 제공한다.
이를 열기 위해서는 다음의 명령어를 사용한다.
$ gazebo "world 파일의 경로"/"world 파일의 이름"
8. 개발환경 만들기 (재난환경 및 드론)
3DGEMS 의 world 파일들을
"~/Firmware/Tools/sitl_gazebo/worlds"로 옮긴다.
다음 명령어를 이용해 3DFEMS 의 world 중 하나인 offic_earthquake.world를 연다.
"sudo"를 사용하는 이유는 world에 변화를 준 뒤, 저장하기 위해서이다.
관리자 권한이 없으면 저장할 수 없다.
$ sudo gazebo ~/Firmware/Tools/sitl_gazebo/worlds/office_earthquake.world
그리고 3DR iris를 추가한 뒤, 다른 이름으로 저장한다.
혹시 3DR iris가 안보인다면 아래 명령어를 통해 model path를 인식시킨 뒤 gazebo 를 다시 켜보면 된다.
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ sudo gazebo ~/Firmware/Tools/sitl_gazebo/worlds/office_earthquake.world
이 후, 다음 명령어를 통해 새로만든 world를 실행시키면 iris가 존재하는 것을 확인할 수 있다.
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_office_earthquake.world
9. 드론 주행시키기
이제 아래 명령어를 통해 드론을 띄울 수 있게 되었다.
# terminal_1
$ roscore
# terminal_2
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_3
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_office_earthquake.world
# terminal_4
$ roslaunch modudculab_ros ctrl_pos_gazebo.launch
# terminal_5
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
그리고 다음 코드를 통해 주행시킬 수 있다.
#include <ros/ros.h>
#include <std_msgs/String.h>
#include <stdio.h>
#include "geometry_msgs/PoseStamped.h"
#include "geometry_msgs/Vector3Stamped.h"
int count = 1;
int proc = 0;
void poseCallback(const geometry_msgs::PoseStamped::ConstPtr& pose_msg,ros::Publisher _pub) {
float x = pose_msg->pose.position.x;
float y = pose_msg->pose.position.y;
float z = pose_msg->pose.position.z;
//ROS_INFO("x = %f", x);
//ROS_INFO("y = %f", y);
//ROS_INFO("z = %f", z);
geometry_msgs::PoseStamped msg;
if(!proc) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = 0.0;//0.001*some_object.position_x;
msg.pose.position.y = 0.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x > -0.1 && x < 0.1 && y > -0.1 && y < 0.1 && z > 0.9 && z < 1.1) proc++;
}
else if(proc == 1) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = 5.0;//0.001*some_object.position_x;
msg.pose.position.y = 0.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x > 4.9 && x < 5.1 && y > -0.1 && y < 0.1 && z > 0.9 && z < 1.1) proc++;
}
else if(proc == 2) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = 5.0;//0.001*some_object.position_x;
msg.pose.position.y = 10.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x > 4.9 && x < 5.1 && y > 9.9 && y < 10.1 && z > 0.9 && z < 1.1) proc++;
}
else if(proc == 3) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = -5.0;//0.001*some_object.position_x;
msg.pose.position.y = 10.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x < -4.9 && x > -5.1 && y > 9.9 && y < 10.1 && z > 0.9 && z < 1.1) proc++;
}
else if(proc == 4) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = -5.0;//0.001*some_object.position_x;
msg.pose.position.y = 0.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x < -4.9 && x > -5.1 && y > -0.1 && y < 0.1 && z > 0.9 && z < 1.1) proc++;
}
else if(proc == 5) {
msg.header.stamp = ros::Time::now();
msg.header.seq=count;
msg.header.frame_id = 1;
msg.pose.position.x = 0.0;//0.001*some_object.position_x;
msg.pose.position.y = 0.0;//0.001*some_object.position_y;
msg.pose.position.z = 1.0;//0.001*some_object.position_z;
msg.pose.orientation.x = 0;
msg.pose.orientation.y = 0;
msg.pose.orientation.z = 0;
msg.pose.orientation.w = 1;
if(x > -0.1 && x < 0.1 && y > -0.1 && y < 0.1 && z > 0.9 && z < 1.1) proc=0;
}
_pub.publish(msg);
ros::spinOnce();
count++;
ROS_INFO("proc = %d", proc);
}
int main(int argc, char **argv)
{
// ros initialize
ros::init(argc, argv, "nav_route");
ros::NodeHandle n;
// ros publisher
ros::Publisher chatter_pub = n.advertise<geometry_msgs::PoseStamped>("/mavros/setpoint_position/local",100);
// ros subscriber
ros::Subscriber pose_sub = n.subscribe<geometry_msgs::PoseStamped>("/mavros/local_position/pose", 100, boost::bind(poseCallback, _1, chatter_pub));
ros::spin();
return 0;
}
guithub는 다음과 같다.
10. hector_slam 설치
이제 hector_slam을 설치해본다.
일단 hector_slam 에서는 QT4를 쓰기 때문에, 다음 명령어를 통해 QT4를 설치한다.
$ sudo apt-get install qt4-default
이 후에, 다음 명령어를 통해 hector_slam을 설치한다.
$ cd ~/catkin_ws/src
$ git clone git clone https://github.com/tu-darmstadt-ros-pkg/hector_slam.git
$ cd ~/catkin_ws
$ catkin build
$ source devel/setup.bash
11. 드론에 lidar 센서 달기
Firmware 모델 중 lidar 센서가 달린 iris model을 불러와 개발환경을 만들어 준다.
모델 명은 "iris with rplidar lidar" 이다.
12. 드론 trajectory
아래 명령어로 trajectory를 수행할 수 있다.
# terminal_1
$ roscore
# terminal_2
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_3
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_with_rplidar_lidar_office_earthquake.world
# terminal_4
$ roslaunch ros_uav ctrl_traj_gazebo.launch
# terminal_5
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
13. RViz에 Lidar 센서 출력
"ctrl_traj_gazebo.launch" 같은 작업할 launch 파일에 다음 내용을 추가한다.
lidar 센서의 rplidar_link는 독립적인 상태이기 때문에 map frame과 연결시켜주기 위한 작업이다.
<node pkg="tf" type="static_transform_publisher" name="map_rplidar_link_broadcaster" args="0 0 0 0 0 0 map rplidar_link 10"/>
그리고 아래 명령어를 실행하면 결과를 확인할 수 있다.
# terminal_1
$ roscore
# terminal_2
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_3
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_with_rplidar_lidar_office_earthquake.world
# terminal_4
$ roslaunch ros_uav ctrl_traj_gazebo.launch
# terminal_5
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
14. GMapping
Hector SLAM을 적용하려 하였으나 역시 적용하기가 마냥 쉽지 않았다. 따라서 GMapping을 먼저 수행해보았다.
다음 명령어를 통해 진행한다.
# terminal_1
$ roscore
# terminal_2
$ rviz
# terminal_3
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_4
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_with_rplidar_lidar_office_earthquake.world
# terminal_5
$ roslaunch ros_uav ctrl_traj_gazebo.launch
# terminal_6
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
# terminal_7
$ rosrun tf static_transform_publisher 0 0 0 0 0 0 base_link rplidar_link 100
# terminal_8
$ rosrun gmapping slam_gmapping scan:=/laser/scan
15. Depth Camera 추가하기
PX4 Firmware 안에 존재하는 depth camera 모델 (iris_triple_depth_camera.sdf) 를 참고하여
아래 라인을 iris_rplidar.sdf에 추가한 뒤, Gazebo에서 아래 모델을 불러와 world를 저장한다.
<model name="front_camera">
<pose>0.1 0 -0.03 0 1.07 0</pose>
<link name="link">
<inertial>
<pose>0.01 0.025 0.025 0 0 0</pose>
<mass>0.01</mass>
<inertia>
<ixx>4.15e-6</ixx>
<ixy>0</ixy>
<ixz>0</ixz>
<iyy>2.407e-6</iyy>
<iyz>0</iyz>
<izz>2.407e-6</izz>
</inertia>
</inertial>
<visual name="visual">
<pose>0 0 0 0 0 0</pose>
<geometry>
<mesh>
<uri>model://realsense_camera/meshes/realsense.dae</uri>
</mesh>
</geometry>
</visual>
<sensor name="depth_camera" type="depth">
<update_rate>20</update_rate>
<camera>
<horizontal_fov>1.02974</horizontal_fov>
<image>
<format>R8G8B8</format>
<width>64</width>
<height>48</height>
</image>
<clip>
<near>0.5</near>
<far>18</far>
</clip>
</camera>
<plugin filename="libgazebo_ros_openni_kinect.so" name="camera_controller">
<cameraName>camera_front</cameraName>
<alwaysOn>true</alwaysOn>
<updateRate>20</updateRate>
<pointCloudCutoff>0.2</pointCloudCutoff>
<pointCloudCutoffMax>20</pointCloudCutoffMax>
<imageTopicName>rgb/image_raw</imageTopicName>
<cameraInfoTopicName>rgb/camera_info</cameraInfoTopicName>
<depthImageTopicName>depth/image_raw</depthImageTopicName>
<depthImageCameraInfoTopicName>depth/camera_info</depthImageCameraInfoTopicName>
<pointCloudTopicName>depth/points</pointCloudTopicName>
<frameName>front_camera_link</frameName>
<distortion_k1>0.0</distortion_k1>
<distortion_k2>0.0</distortion_k2>
<distortion_k3>0.0</distortion_k3>
<distortion_t1>0.0</distortion_t1>
<distortion_t2>0.0</distortion_t2>
</plugin>
</sensor>
</link>
</model>
<joint name="depth_camera_joint_front" type="revolute">
<child>front_camera::link</child>
<parent>iris::base_link</parent>
<axis>
<xyz>0 0 1</xyz>
<limit>
<upper>0</upper>
<lower>0</lower>
</limit>
</axis>
</joint>
그리고 launch 파일에 base_link 프레임과 rplidar_link 프레임, front_camera_link 프레임을 연결해주기 위해 다음 구문을 추가한다.
참고로 arguments를 본인 환경에 맞추어 다 수정해주어야 한다.
<node pkg="tf" type="static_transform_publisher" name="base_link_rplidar_link_broadcaster" args="0 0 0 0 0 0 base_link rplidar_link 10"/>
<node pkg="tf" type="static_transform_publisher" name="base_link_front_camera_link_broadcaster" args="0 0 0 -1.5708 0 -2.61799 base_link front_camera_link 10"/>
이 후, 다음과 같이 코드를 실행한 뒤, PointCloud2를 디스플레이 하면 다음과 같은 결과를 얻을 수 있다.
# terminal_1
$ roscore
# terminal_2
$ rviz
# terminal_3
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_4
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_with_rplidar_lidar_depthcamera_down_office_earthquake.world
# terminal_5
$ roslaunch ros_uav mavros_teleop_key.launch
# terminal_6
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
# terminal_7
$ rosrun gmapping slam_gmapping scan:=/laser/scan
16. Octomap 실행
Octomap은 용량이 큰 3D Data로 맵핑을 할 수 있는 대표적인 오픈소스다. 이를 이용해보자.
Octomap 설치는 다음 명령어를 통해 진행한다.
$ sudo apt-get install ros-indigo-octomap ros-indigo-octomap-mapping
$ rosdep install octomap_mapping
$ rosmake octomap_mapping
Octomap의 frame은 world 이므로 map 프레임과 world 프레임을 이어줄 필요가 있다.
다음 구문을 launch 파일에 추가해주자.
<node pkg="tf" type="static_transform_publisher" name="world_map_broadcaster" args="0 0 0 0 0 0 world map 10"/>
이 후, 다음 명령어를 통해 프로그램을 실행한다.
# terminal_1
$ roscore
# terminal_2
$ rviz
# terminal_3
$ cd ~/Firmware
$ no_sim=1 make px4_sitl_default gazebo
# terminal_4
$ cd ~/Firmware
$ source Tools/setup_gazebo.bash $(pwd) $(pwd)/build/px4_sitl_default
$ export ROS_PACKAGE_PATH=$ROS_PACKAGE_PATH:$(pwd):$(pwd)/Tools/sitl_gazebo
$ roslaunch gazebo_ros empty_world.launch world_name:=$(pwd)/Tools/sitl_gazebo/worlds/iris_with_rplidar_lidar_depthcamera_down_office_earthquake.world
# terminal_5
$ roslaunch ros_uav mavros_teleop_key.launch
# terminal_6
$ rosrun mavros mavsafety arm
$ rosrun mavros mavsys mode -c OFFBOARD
# terminal_7
$ rosrun gmapping slam_gmapping scan:=/laser/scan
# terminal_8
$ roslaunch octomap_server octomap_tracking_server.launch frame_id:="world" cloud_in:="/camera_front/depth/points"
or
$ roslaunch octomap_server octomap_mapping.launch frame_id:="world" cloud_in:="/camera_front/depth/points"
# 차이점은?
17. Jetson Nano Ubuntu 18.04 설치
시뮬레이션으로 돌려보니 /tf 값이 너무 완벽할 정도로 안정적이다.
이대로는 실험 진행이 불가능하니 이제는 실제 드론을 사용할 때다.
먼저 Jetson Nano에 Ubuntu 18.04를 설치하자.
다음 링크를 참고하자.
전원을 켤 때에는 J48 두 개의 핀을 연결해야 하는데, 그에 관해서는 아래 링크를 참고하자.
18. 이 후 셋팅
하... 이 부분에서 거진 일주일을 소모했다.
시뮬레이션 부분에서 사용한 드론의 펌웨어는 "px4"이다.
하지만 내가 사용하는 실제 드론에서의 펌웨어는 "ardupilot" 이었기 때문에,
px4와 관련된 내용이 먹힐리가 없었다.
그래서 px4 펌웨어로 새로 설치하고 캘리브레이션도 다시 수행하고 시도하려 하였다.
하지만 큰 문제가 몇가지 있었다.
1. px4에서 GPS 센서 없이 조작하기가 매우 까다롭다. 파라미터에서 GPS를 쓰지 않도록 하는게 매우 힘든 것이다.
2. GPS 센서를 쓰지 않도록 어찌어찌 성공했다. 너무 정신이 없어서 제대로 기록하지 못한것이 아쉽지만, 가능은 하다. 하지만 모든 세팅이 끝난 후, 제어기 쪽 전원이 4.7v여서 구동이 불가능하다는 에러를 계속 접했다. 제어기는 전원이 5v 이상이여야 안정적이지만 실제 제어기의 전원이 4.7v여서 생기는 에러인 것이다.
해결해보려 했지만, 최종적으로는 해당 오류는 px4에서 존재하는 에러이며, ardupilot에서는 이러한 문제가 없는 것으로 확인하였다. 관련된 링크가 있었는데, 역시나 정신없는 와중에 기록하지 못했다.
그래서 결국 다시 ardupilot 펌웨어를 다시 설치하게 되었다. 이 때도 과정이 순탄친 않았다.
1. calibration
캘리브레이션을 하는 과정이 복잡했는데, 결국에는 성공했다.
사실 어떤 툴로 캘리브레이션에 성공했는지 정확히 기억이 나진 않는다.
QGroundControl / APM Planner 2 / Mission Planner 등등 상황에 따라 필요한 것들은 다 썼던 것 같다.
그래도 역시 가장 UI가 깔끔한 QGroundControl 가 주가 되었던거 같다.
2. power calibration
배터리를 캘리브레이션 하는 과정도 고역이었다. 성공하긴 했는데 어찌했는지 모르겠다.
기억 나는 것은 QGroundControl에 usb를 꽂고 "calibration" 버튼을 누른 후에 usb를 빼고 배터리를 꽂으면
각각 비프음과 함께 캘리브레이션이 수행되고, 마지막 긴 비프음 후에 배터리를 다시 뺏다 꽂으면 되었던 것이다.
그런데 대부분의 시도에서 마지막 긴 비프음이 들리지 않고, 배터리 셀 개수를 의미하는 3번의 비프음이 길게 테스트해봤을 때는 30분 넘도록 삑삑거렸던 것 같다.
어쩌다 되긴 했는데 어떻게 된건진 모르겠다.
3. hardware safety switch
원래 드론에는 safety switch를 부착하여 긴급상황시에 드론을 정지시키는 기능을 수행하게 된다.
하지만 내 경우에는 safety switch가 없는 하드웨어를 사용하고 있었기 때문에 아래 링크와 같이
BRD_SAFETYENABLE 를 0으로 설정하여 해결하였다.
ardupilot.org/copter/docs/common-safety-switch-pixhawk.html
아마 더 자세한 내용들도 있을 것 같지만, 일단 현재는 이 내용으로 진행하도록 하겠다.
19. ardupilot gazebo 시뮬레이션 환경 구축
실제 로봇으로 개발을 수행하려 했는데, 드론을 조작하는 부분의 코드 개발이 생각보다 변수가 많다.
이대로 실제 드론으로 작업하면 사고가 많을 것으로 예상되어 일전에 사용한 px4 펌웨어의 SITL이 아닌
Ardupilot의 SITL 환경을 구축하게 되었다.
먼저 다음 링크를 참고해 Ardupilot Firmware를 설치한다.
이후에 다음 링크를 참고하여 Ardupilot Gazebo 시뮬레이션 환경을 설치한다.
ardupilot.org/dev/docs/using-gazebo-simulator-with-sitl.html
이 후에 gazebo에 Ardupilot의 모델과 월드 정보를 알려주기 위해 다음 작업을 수행한다.
다음 링크를 참고했다.
github.com/khancyr/ardupilot_gazebo
echo 'source /usr/share/gazebo/setup.sh' >> ~/.bashrc
# Set Path of Gazebo Models (Adapt the path to where to clone the repo)
echo 'export GAZEBO_MODEL_PATH=~/ardupilot_gazebo/models' >> ~/.bashrc
# Set Path of Gazebo Worlds (Adapt the path to where to clone the repo)
echo 'export GAZEBO_RESOURCE_PATH=~/ardupilot_gazebo/worlds:${GAZEBO_RESOURCE_PATH}' >> ~/.bashrc
source ~/.bashrc
이후에 다음 명령어를 통해 시뮬레이션 환경을 불러올 수 있다.
# terminal_1
$ gazebo --verbose worlds/iris_arducopter_runway.world
# teminal_2
$ cd ~/ardupilot/ArduCopter
$ ../Tools/autotest/sim_vehicle.py -f gazebo-iris --console --map
이 후에 다음 링크를 참조해 mavros의 apm.launch 파일의 fcu_url을 바꾸어 준다.
<arg name="fcu_url" default="udp://127.0.0.1:14551@14555" />
ardupilot.org/dev/docs/ros-sitl.html
이 후, 다음 명령어들을 통해 ardupilot gazebo와 mavros를 구동시킬 수 있다.
# terminal_1
$ roscore
# teminal_2
$ gazebo --verbose worlds/iris_arducopter_runway.world
# teminal_3
$ cd ~/ardupilot/ArduCopter
$ ../Tools/autotest/sim_vehicle.py -f gazebo-iris --console --map
# teminal_4
$ roslaunch mavros apm.launch
# terminal_5
$ rosrun mavros mavsys mode -c GUIDED_NOGPS
$ rosrun mavros mavsafety arm