AirSimをUbuntuで使う方法をまとめました。
UbuntuでAirSimを使う【C++, ROS】
AirSimをUbuntuで使うのに大苦戦したので、使用方法を残しておきます。記事後半では、ROS Wrapperの使用方法もまとめます。
テスト環境
- Ubuntu 16.04
- ROS Kinetic
AirSimの使用方法
v1.2.0 - Linuxの環境「Block」を例として以下で紹介します。
ビルド済みのバイナリをダウンロード
公式Releaseからzipファイルをダウンロードして解凍します。
$ wget https://github.com/microsoft/AirSim/releases/download/v1.2.0Linux/Blocks.zip $ unzip Blocks.zip
AirSim(Unreal Engine)の起動
$ cd Block $ ./Block.sh
オプションなしだとフルスクリーンで他の作業ができなくなるので、下記のように、ウィンドウサイズを指定するのがオススメです。
$ ./Block.sh -ResX=640 -ResY=480 -windowed
起動するとドローンか自動車か選択するポップアップが出ます。ドローンを動かすにはコントローラやAPIが必要ですが、自動車はキーボードで運転することができます。操縦方法の詳細はF1で表示できるので確認してみてください。
Dockerコンテナ内では上手く起動できなかった
ちなみに、Dockerコンテナ内でダウンロードして同様に起動しようとしたら、以下のエラーが出たので、Dockerコンテナ内での起動はあきらめました。
Refusing to run with the root privileges.
ROS Wrapperの使用方法
ROS Wrapperを使用することで、ROSを通してAirSim(Unreal Engine)と通信できます。
AirSimのビルド
準備
AirSimのビルドに必要なライブラリなどをインストールします。
$ apt-get update $ apt-get install -y rsync g++-8 python-catkin-tools ros-kinetic-mavros*
ビルド
$ git clone https://github.com/Microsoft/AirSim.git $ cd AirSim $ ./setup.sh $ ./build.sh
ROS Wrapperのビルド
CMake3.10以上が必要
公式Releaseからtarファイルをダウンロードして解凍します。(例:v3.17.3)
$ wget https://github.com/Kitware/CMake/releases/download/v3.17.3/cmake-3.17.3.tar.gz $ tar xvf cmake-3.17.3.tar.gz $ cd cmake-3.17.3 $ ./bootstrap && make && make install
filesystem関連のエラー回避
filesystem関連のビルドエラーを回避するために、cppファイルの中身を以下のように書き換える必要があります。
- AirSim/MavLinkCom/MavLinkTest/Commands.cpp
- #include <filesystem>
→ #include <experimental> - using namespace std::filesystem;
→ using namespace std::experimental::filesystem;
- #include <filesystem>
- AirSim/MavLinkCom/MavLinkTest/main.cpp
- #include <filesystem>
→ #include <experimental/filesystem> - using namespace std::filesystem;
→ using namespace std::experimental::filesystem
- #include <filesystem>
ビルド
$ cd ~/AirSim/ros $ catkin build
セットアップ
roslaunchなどを利用するために以下のセットアップが必要です。
$ source ~/AirSim/ros/devel/setup.bash $ echo "source ~/AirSim/ros/devel/setup.bash" >> ~/.bashrc
起動手順
settingファイルを指定
settingファイルを既定の場所に置きます。settingファイルでは、センサの条件などを指定することができます。まずは、以下のように、公式チュートリアルで用意されているsettingファイルを使ってみます。
$ mkdir -p ~/Documents/AirSim $ roscd airsim_tutorial_pkgs $ cp settings/front_stereo_and_center_mono.json ~/Documents/AirSim/settings.json
AirSim(Unreal Engine)の起動
$ cd Block $ ./Block.sh
settingファイルの通りに環境が構築されていることが確認できると思います。
ROS WrapperをLaunch
$ roslaunch airsim_ros_pkgs airsim_node.launch
rvizやrostopic echoで、ROS Wrapperが機能していることを確認できると思います。
おまけ:ROS WrapperをDockerで使う
ROS WrapperをDockerで使う方法を紹介します。
Dockerfile
Dockerfileの実装例です。
FROM osrf/ros:kinetic-desktop-full ########## basis ########## RUN apt-get update && apt-get install -y \ vim \ wget \ unzip \ git ########## AirSim ########## RUN apt-get update &&\ apt-get install -y \ rsync \ g++-8 \ python-catkin-tools \ ros-kinetic-mavros* &&\ mkdir /home/airsim_ws/ &&\ cd /home/airsim_ws/ &&\ git clone https://github.com/Microsoft/AirSim.git &&\ cd AirSim &&\ ./setup.sh &&\ ./build.sh ########## AirSim ROS wrapper ########## ##### CMake >= 3.10 ##### RUN mkdir /home/cmake_ws &&\ cd /home/cmake_ws &&\ wget https://github.com/Kitware/CMake/releases/download/v3.17.3/cmake-3.17.3.tar.gz &&\ tar xvf cmake-3.17.3.tar.gz &&\ cd cmake-3.17.3 &&\ ./bootstrap && make && make install ##### Build ##### RUN sed -i "s/#include <filesystem>/#include <experimental\/filesystem>/g" /home/airsim_ws/AirSim/MavLinkCom/MavLinkTest/Commands.cpp &&\ sed -i "s/using namespace std::filesystem;/using namespace std::experimental::filesystem;/g" /home/airsim_ws/AirSim/MavLinkCom/MavLinkTest/Commands.cpp &&\ sed -i "s/#include <filesystem>/#include <experimental\/filesystem>/g" /home/airsim_ws/AirSim/MavLinkCom/MavLinkTest/main.cpp &&\ sed -i "s/using namespace std::filesystem;/using namespace std::experimental::filesystem;/g" /home/airsim_ws/AirSim/MavLinkCom/MavLinkTest/main.cpp &&\ cd /home/airsim_ws/AirSim/ros &&\ /bin/bash -c "source /opt/ros/kinetic/setup.bash; catkin build" &&\ echo "source /home/airsim_ws/AirSim/ros/devel/setup.bash" >> ~/.bashrc ##### Setting json ##### RUN mkdir -p /root/Documents/AirSim &&\ cp /home/airsim_ws/AirSim/ros/src/airsim_tutorial_pkgs/settings/front_stereo_and_center_mono.json /root/Documents/AirSim/settings.json ######### initial position ########## WORKDIR /home/airsim_ws
Build
$ docker build -t airsim_ros:latest .
Run
$ docker run -it --rm --net=host airsim_ros:latest
使い方
ホスト側での操作
settingファイルを指定
$ mkdir -p ~/Documents/AirSim $ roscd airsim_tutorial_pkgs $ cp settings/front_stereo_and_center_mono.json ~/Documents/AirSim/settings.json
AirSim(Unreal Engine)の起動
$ cd Block $ ./Block.sh
Docker側での操作
$ docker run -it --rm --net=host airsim_ros:latest (コンテナ内)$ roslaunch airsim_ros_pkgs airsim_node.launch
ROS Wrapperでドローンを操縦
ros::ServiceClientやros::Publisherを用いることでシミュレーション内のドローンに指令を与えることができます。以下の手順で、ドローンを操縦するためのパッケージを新たにつくっていきます。
パッケージを作成
airsim_ros_pkgsで定義されているメッセージやサービスを使うので、以下のように依存関係を指定する必要があります。
$ cd ~/AirSim/ros/src $ catkin_create_pkg my_pkg std_msgs rospy roscpp airsim_ros_pkgs
ソースコードを実装
離陸して直進する実装例をご紹介します。ファイル名はgo_straight.cppとしました。topicやserviceの名前は、rostopic listやrosservice listでそれぞれ確認してください。
#include <ros/ros.h> #include <airsim_ros_pkgs/Takeoff.h> #include <airsim_ros_pkgs/VelCmd.h> int main(int argc, char** argv) { ros::init(argc, argv, "test_flight"); ros::NodeHandle nh; /*pub srv*/ ros::ServiceClient client_takeoff = nh.serviceClient<airsim_ros_pkgs::Takeoff>("/airsim_node/drone_1/takeoff"); ros::Publisher pub_vel = nh.advertise<airsim_ros_pkgs::VelCmd>("/airsim_node/drone_1/vel_cmd_body_frame", 1); /*take off*/ airsim_ros_pkgs::Takeoff srv_takeoff; if(client_takeoff.call(srv_takeoff)){ std::cout << "takeoff: true" << std::endl; } else{ std::cout << "takeoff: false" << std::endl; return 1; } /*go straight*/ double mps = 1.0; airsim_ros_pkgs::VelCmd vel_msg; vel_msg.twist.linear.x = mps; vel_msg.twist.linear.y = 0.0; vel_msg.twist.linear.z = 0.0; vel_msg.twist.angular.x = 0.0; vel_msg.twist.angular.y = 0.0; vel_msg.twist.angular.z = 0.0; pub_vel.publish(vel_msg); return 0; }
CMakelists.txtに追加
cmake_minimum_required(VERSION 2.8.3) project(my_pkg) find_package(catkin REQUIRED COMPONENTS airsim_ros_pkgs roscpp rospy std_msgs ) catkin_package( # INCLUDE_DIRS include # LIBRARIES my_pkg # CATKIN_DEPENDS airsim_ros_pkgs roscpp rospy std_msgs # DEPENDS system_lib ) include_directories( ${catkin_INCLUDE_DIRS} ) add_executable(go_straight src/go_straight.cpp) target_link_libraries(go_straight ${catkin_LIBRARIES})
ビルド
$ cd ~/AirSim/ros $ catkin build
TAKE OFF!!!
AirSim(Unreal Engine)の起動
$ cd Block $ ./Block.sh
ROS WrapperをLaunch
$ roslaunch airsim_ros_pkgs airsim_node.launch
指令を送信
$ rosrun my_pkg go_straight
ドローンが浮上して直進するはずです。
C++ APIでドローンを操縦
本当は上記のROS Wrapperで操縦したかったのですが、ロール、ピッチの指令が上手く機能しなかったので、C++のAPIも使ってみました。
ソースコードを実装
公式チュートリアルに載っているソースコードを使います。ファイル名はhello_drone.cppとしました。
#include <iostream> #include "vehicles/multirotor/api/MultirotorRpcLibClient.hpp" int main() { using namespace std; msr::airlib::MultirotorRpcLibClient client; cout << "Press Enter to enable API control" << endl; cin.get(); client.enableApiControl(true); cout << "Press Enter to arm the drone" << endl; cin.get(); client.armDisarm(true); cout << "Press Enter to takeoff" << endl; cin.get(); client.takeoffAsync(5)->waitOnLastTask(); cout << "Press Enter to move 5 meters in x direction with 1 m/s velocity" << endl; cin.get(); auto position = client.getMultirotorState().getPosition(); // from current location client.moveToPositionAsync(position.x() + 5, position.y(), position.z(), 1)->waitOnLastTask(); cout << "Press Enter to land" << endl; cin.get(); client.landAsync()->waitOnLastTask(); return 0; }
CMakeLitsts.txtに追加
cmake_minimum_required(VERSION 3.5.0) project(my_project) add_compile_options(-std=c++11) # set(AIRSIM_ROOT ../AirSim) find_path(AIRSIM_ROOT NAMES AirSim.sln PATHS "./AirSim" "../AirSim" "../../AirSim" "../../../AirSim" "../../../../AirSim" ) message(STATUS "found AIRSIM_ROOT=${AIRSIM_ROOT}") add_subdirectory("${AIRSIM_ROOT}/cmake/AirLib" AirLib) add_subdirectory("${AIRSIM_ROOT}/cmake/rpclib_wrapper" rpclib_wrapper) add_subdirectory("${AIRSIM_ROOT}/cmake/MavLinkCom" MavLinkCom) include_directories( ${AIRSIM_ROOT}/AirLib/include ${AIRSIM_ROOT}/external/rpclib/rpclib-2.2.1/include ${AIRSIM_ROOT}/MavLinkCom/include ${AIRSIM_ROOT}/MavLinkCom/common_utils ${AIRSIM_ROOT}/AirLib/deps/eigen3 ) add_executable(hello_drone src/hello_drone.cpp) target_link_libraries(hello_drone AirLib rpc)
find_path(またはset)で、AirSimのroot pathを${AIRSIM_ROOT}として定義して使っています。自身の環境に合わせて、調整する必要があります。その他の部分は変更する必要ありません。後述のディレクトリ構造の通りにファイルを置けば変更なしでビルドできるはずです。
ディレクトリ構造の確認
ディレクトリ構造の例です。
airsim_ws/
┣ AirSim
┗ my_project
┣ CMakeLitsts.txt
┗ src/
┗ hello_drone.cpp
ビルド
$ cd ~/airsim_ws/my_project $ mkdir build $ cd build $ cmake .. $ make
TAKE OFF!!!
AirSim(Unreal Engine)の起動
$ cd Block $ ./Block.sh
APIを起動
$ cd ~/airsim_ws/my_project/build $ ./hello_drone
確認されたエラー
現時点(2020年7月)では、Linux用のバイナリーのバージョンは、v1.2.0~v1.3.1がリリースされています。v1.2.0では、以下のエラーが確認されました。
- ROS WrapperでIMUのデータを取得できない
$ roslaunch airsim_ros_pkgs airsim_node.launch
↓error
Exception raised by the API:
rpclib: server could not find function 'getImuData' with argument count 2. - C++のAPIでロール、ピッチ、ヨーの指令が出せない
client.moveByRollPitchYawZAsync(roll, pitch, yaw, z, duration)->waitOnLastTask();
↓terminate called after throwing an instance of 'rpc::rpc_error'
what(): rpc::rpc_error during call
Aborted (core dumped)
v1.3.1では上記のエラーが出ないのですが、環境の種類が少なかったり、全体的に処理が重いといった問題があります。
※もし私側のミスによるエラーでしたら申し訳ありません。
NOTE:座標系
ちなみに、AirSimの座標系は下図の通りになっているようです。姿勢などを考えるときは座標系に注意してください。
さいごに
AirSimをUbuntuで使う方法をまとめてみました。参考になれば幸いです。
以上です。
コメント