dronekitによる python apiとアプリ開発の概要
TRANSCRIPT
DroneKit-Python とは
• DroneKit の中心的 API• companion computer 上で稼動し
て、 AruduPilot と通信する• 自律運転 ( オートパイロット ) を高度化す
る• MAVLink で通信する• 制御だけでなくテレメータ機能もある• OSS(Apache ライセンス ) で Github にホス
トされている
Python かよ!
• 「 Ruby や C++ じゃねーの?」• ↑ と文法的にかけ離れてるわけじゃない• 後述するようにプログラムとして難しいわけ
じゃない ( 「凄いテクニック」とかいらない )• ぶっちゃけ Python よくわからなくても、サンプ
ル見たらなんとなくわかる ( 私もそうだった )
たいした問題じゃない!
API の機能
• 機体リストの取得• 機体の状態を設定、テレメトリの取得• 非同期に状態変更を受信する• waypoint mission( 通過点を指定した飛行 )
の作成と管理 ( 自動モード )• 指定した場所への誘導 ( 誘導モード )• 機体へのメッセージ送信• 設定済みラジコンチャンネルの書き換え
API 一覧クラス API 機能 値droneapi.lib.APIConnection exit 現在のスレッドが終了しているかどうか 終了していたら True
get_vehicles 現在のコネクションで制御可能な機体の取得 制御可能な Vehicle オブジェクトの集合droneapi.lib.Vehicle location 現在の Location droneapi.lib.Location
attitude 現在の Attitude droneapi.lib.Attitude
velocity 現在の速度 [ vx, vy, vz ]
mode 現在の飛行モードの取得と設定 droneapi.lib.VehicleMode
airspeed 現在の対気速度 double
groundspeed 現在の対地速度 double
gps_0 GPS の情報 droneapi.lib.GPSInfo
armed 装備状態 boolean
mount_status ジンバルの状態 [ pitch, yaw, roll ] or None
battery バッテリの状態 droneapi.lib.Battery
channel_override RC チャネルの直接的な変更 ハッシュ channel_readback RC チャネルの読み出し ハッシュ add_attribute_observer 属性オブザーバの追加 commands 現在の飛行の通過点 (waypoint) の取得 droneapi.lib.CommandSequence
flush() いわゆる flush message_factory 生 MAV Link メッセージを作成するオブジェクトを得る parameters 機体のパラメータ ( 編集可能 ) を得る droneapi.lib.Parameters
remove_attribute_observer 属性オブザーバの削除 send_mavlink 生 MAV Link メッセージの送信 set_mavlink_callback 非同期通知を受け取った時の callback の設定 droneapi.lib.Location 機体の位置 lat Latitude( 緯度 ) double
lon Longitude( 経度 ) alt Altitude( 高度 ) is_relative 高度が絶対 ( 海抜 ) か相対 ( ホーム位置 ) か True or False
droneapi.lib.Attitude 機体の方向 pitch ピッチ radian
yaw ヨー radian
roll ロール radian
droneapi.lib.VehicleMode フライトモード ( 機体特性に依る ) name モードの名前 droneapi.lib.GPSInfo GPS の情報 eph HDOP ( Horizontal Dilution of Precision ) cm
epv VDOP ( Vertical Dilution of Precision ) cm
fix_type GPS の運転モード 0: no, 2:2D, 3:3D
satellites_visible 見えている衛星の数 droneapi.lib.Battery バッテリーの状態 voltage 電圧 mV
current 電流 10mA
level 残量 droneapi.lib.CommandSequence 飛行の通過点 (waypoint) の並び takeoff(altitude) テイクオフ 高度 add(cmd) 通過点の追加 droneapi.lib.Command
clear() コマンドリストの消去 count 通過点の数 download() 機体から通過点をダウンロード goto(location) 指定位置への移動 droneapi.lib.Location
next 現在意味のある通過点の数 wait_valid() 通過点ダウンロードが終了するまでブロック droneapi.lib.Parameters 機体のパラメータ []= パラメータの設定 [] パラメータの参照
droneapi.lib.Vehicle
location 現在の Location droneapi.lib.Location
attitude 現在の Attitude droneapi.lib.Attitude
velocity 現在の速度 [ vx, vy, vz ]
mode 現在の飛行モードの取得と設定 droneapi.lib.VehicleMode
airspeed 現在の対気速度 double
groundspeed 現在の対地速度 double
gps_0 GPS の情報 droneapi.lib.GPSInfo
armed 装備状態 boolean
mount_status ジンバルの状態 [ pitch, yaw, roll ] or None
battery バッテリの状態 droneapi.lib.Battery
channel_override RC チャネルの直接的な変更 ハッシュchannel_readback RC チャネルの読み出し ハッシュ
add_attribute_observer 属性オブザーバの追加
commands 現在の飛行の通過点 (waypoint) の取得 droneapi.lib.CommandSequence
flush() いわゆる flush
message_factory 生 MAV Link メッセージを作成するオブジェクトを得る
parameters 機体のパラメータ ( 編集可能 ) を得る droneapi.lib.Parameters
remove_attribute_observer 属性オブザーバの削除
send_mavlink 生 MAV Link メッセージの送信 set_mavlink_callback 非同期通知を受け取った時の callback の設定
droneapi.lib.Location
lat Latitude( 緯度 ) double
lon Longitude( 経度 )
alt Altitude( 高度 )
is_relative 高度が絶対 ( 海抜 ) か相対 ( ホーム位置 ) か True or False
droneapi.lib.CommandSequence
takeoff(altitude) テイクオフ 高度
add(cmd) 通過点の追加 droneapi.lib.Command
clear() コマンドリストの消去
count 通過点の数
download() 機体から通過点をダウンロード
goto(location) 指定位置への移動 droneapi.lib.Location
next 現在意味のある通過点の数
wait_valid() 通過点ダウンロードが終了するまでブロック
サンプル解説
http://python.dronekit.io/examples/index.htmlにあるサンプルの解説をちょっとだけします。今回は、
• Vehicle State• Simple Go To (Copter)• Follow Me
を解説します。
Vehicle State(1)
from droneapi.lib import VehicleModefrom pymavlink import mavutilimport time
api = local_connect()
v = api.get_vehicles()[0]
ライブラリのインポート
コネクションの確立
コネクション配下にある最初の機体の情報の取得
値の出力をします
Vehicle State(2)
print "\nGet all vehicle attribute values:"print " Location: %s" % v.locationprint " Attitude: %s" % v.attitudeprint " Velocity: %s" % v.velocityprint " GPS: %s" % v.gps_0print " Groundspeed: %s" % v.groundspeedprint " Airspeed: %s" % v.airspeedprint " Mount status: %s" % v.mount_statusprint " Battery: %s" % v.batteryprint " Mode: %s" % v.mode.name # settableprint " Armed: %s" % v.armed # settable
それぞれの値はそれぞれのクラスなのだけど、’ print’ は良きにはからってくれます。
値の出力をします
Vehicle State(2)
Get all vehicle attribute values: Location: Attitude: Attitude:pitch=-0.00405988190323,yaw=-0.0973932668567,roll=-0.00393210304901 Velocity: [0.06, -0.07, 0.0] GPS: GPSInfo:fix=3,num_sat=10 Groundspeed: 0.0 Airspeed: 0.0 Mount status: [None, None, None] Battery: Battery voltage: 12590, current: 0, level: 99 Mode: STABILIZE Armed: False
この辺の実行結果
Vehicle State(3)
print "Set Vehicle.mode=GUIDED (currently: %s)" % v.mode.name v.mode = VehicleMode("GUIDED")
v.flush() while not v.mode.name=='GUIDED' and not api.exit: print " Waiting for mode change ..." time.sleep(1)
print "Set Vehicle.armed=True (currently: %s)" % v.armed v.armed = True
v.flush()while not v.armed and not api.exit: print " Waiting for arming..." time.sleep(1)
フライトモードを’ GUDED’ にします
確実な操作をするために、 flush して状態が変化するまで待ちます
‘armed’ にします
同じく確実に操作するために flush して状態が変化するまで待ちます
機体を「 armed 」にします
Vehicle State(3)
Set Vehicle.mode=GUIDED (currently: STABILIZE) Waiting for mode change ...Got MAVLink msg: COMMAND_ACK {command : 11, result : 0}GUIDED> Mode GUIDEDSet Vehicle.armed=True (currently: False) Waiting for arming...APM: ARMING MOTORSAPM: Initialising APM...Got MAVLink msg: COMMAND_ACK {command : 400, result : 0}ARMED
この辺の実行結果
Vehicle State(4)
def mode_callback(attribute): print " CALLBACK: Mode changed to: ", v.mode.name
print "\nAdd mode attribute observer for Vehicle.mode" v.add_attribute_observer('mode', mode_callback)
print " Set mode=STABILIZE (currently: %s)" % v.mode.name v.mode = VehicleMode("STABILIZE")v.flush()
print " Wait 2s so callback invoked before observer removed"time.sleep(2)
v.remove_attribute_observer('mode', mode_callback)
オブザーバの内容です。「オブザーバ」とか言ってますが、要するにコールバックです。
モード変更のオブザーバとして登録します
モードを‘ STABILIZE’ にします
確実に操作するために flush して状態が変化するまで待ちます
オブザーバを外すのを 2秒待ちます
オブザーバを外します
オブザーバをつけたり外したりします
Vehicle State(4)
Add mode attribute observer for Vehicle.mode Set mode=STABILIZE (currently: GUIDED) Wait 2s so callback invoked before observer removedGot MAVLink msg: COMMAND_ACK {command : 11, result : 0}STABILIZE> Mode STABILIZE CALLBACK: Mode changed to: STABILIZE
この辺の実行結果
Vehicle State(5)
print "\nGet home location" cmds = v.commandscmds.download()
cmds.wait_valid()
print " Home WP: %s" % cmds[0]
現在のミッションの通過点 (waypoint)をダウンロードします
ダウンロードが完了するまで待ちます
一番最初の通過点は初期位置です
機体の初期位置 (home location) を得ます
Vehicle State(5)
Get home locationRequesting 0 waypoints t=Fri May 15 11:35:58 2015 now=Fri May 15 11:35:58 2015 Home WP: MISSION_ITEM {target_system : 255, target_component : 0, seq : 0, frame : 0, command : 16, current : 0, autocontinue : 1, param1 : 0.0, param2 : 0.0, param3 : 0.0, param4 : 0.0, x : -35.3632621765, y : 149.165237427, z : 583.729980469}
この辺の実行結果
Vehicle State(6)
print "\nRead vehicle param 'THR_MIN': %s" % v.parameters['THR_MIN']
print "Write vehicle param 'THR_MIN' : 10"v.parameters['THR_MIN']=10
v.flush()
print "Read new value of param 'THR_MIN': %s" % v.parameters['THR_MIN']
パラメータ‘ THR_MIN’ を読みます。
パラメータ’ THR_MIN’ を 10 に設定します
完了するまで待ちます
あらためてパラメータ’ THR_MIN’ を読みます
なお、’ THR_MIN’ とはストットルの最小値を意味します。
機体のパラメータの読み出し書き込みをします
Vehicle State(6)
Read vehicle param 'THR_MIN': 130.0Write vehicle param 'THR_MIN' : 10timeout setting THR_MIN to 10.000000Read new value of param 'THR_MIN': 10.0
この辺の実行結果
Vehicle State(7)
print "\nOverriding RC channels for roll and yaw"v.channel_override = { "1" : 900, "4" : 1000 }
v.flush()
print " Current overrides are:", v.channel_override
print " Channel default values:", v.channel_readback # All channel values before override
# Cancel override by setting channels to 0print " Cancelling override"v.channel_override = { "1" : 0, "4" : 0 }
v.flush()
チャネルの値を変更します
反映させます
上書きされた値を表示します
元の値を表示します
上書きをやめてコントローラの値に戻します (0 を設定するのはそういう意味 )
反映させます
RC チャンネルの上書き
Vehicle State(7)
Overriding RC channels for roll and yaw Current overrides are: {'1': 900, '4': 1000} Channel default values: {'1': 1500, '3': 1000, '2': 1500, '5': 1800, '4': 1500, '7': 1000, '6': 1000, '8': 1800} Cancelling override
この辺の実行結果
Vehicle State(8)
print "\nReset vehicle atributes/parameters and exit“
v.mode = VehicleMode("STABILIZE")
v.armed = False
v.parameters['THR_MIN']=130
v.flush()
機体モードを’ STABILIZE’ に
armed を False に
スロットル最小値を 130 に
反映させます
ヤバそうな値は元に戻しておきます
Vehicle State(8)
Reset vehicle atributes/parameters and exitGot MAVLink msg: COMMAND_ACK {command : 11, result : 0}APM: DISARMING MOTORSGot MAVLink msg: COMMAND_ACK {command : 400, result : 0}DISARMEDtimeout setting THR_MIN to 130.000000APIThread-0 exiting...
この辺の実行結果
Simple Go To (Copter) (1)
import timefrom droneapi.lib import VehicleModefrom pymavlink import mavutil
api = local_connect()
v = api.get_vehicles()[0]
ライブラリのインポート
コネクションの確立
コネクション配下にある最初の機体の情報の取得
目的の場所に移動させるサンプルです
Simple Go To (Copter) (2)
def arm_and_takeoff(aTargetAltitude):
print "Basic pre-arm checks"if vehicle.mode.name == "INITIALISING":
print "Waiting for vehicle to initialise“
time.sleep(1)
while vehicle.gps_0.fix_type < 2:print “Waiting for GPS...:”, vehicle. gps_0. fix_typetime.sleep(1)
armed にし、目的の高度まで飛び上がる関数 (手続 ) を定義します
メッセージを出しますモードが’ INITIALISING’ であれば、「初期化待ち」を表示して
1秒待ちます
GPS が有効になるまでメッセージを出して1秒待ちます
機体と GPS の初期化をします
GPS の fix_type が 2次元未満の場合は、GPS は無効の状態です
Simple Go To (Copter) (3)
print "Arming motors“
vehicle.mode = VehicleMode("GUIDED")vehicle.armed = True
vehicle.flush()
while not vehicle.armed and not api.exit:print " Waiting for arming...“time.sleep(1)
メッセージを出します
モードが’ GUIDED’ にしてarmed にします
変更を反映させて、
armed になるまでメッセージを出して1秒待ちます
armed にします
モードの’ GUIDED’ とは、通過点通りに飛行する以外のモードです
Simple Go To (Copter) (4)
print "Taking off!“ vehicle.commands.takeoff(aTargetAltitude)
vehicle.flush()
メッセージを出します
目的の高度まで飛行するコマンドを出し
反映させます
飛び立ちます
Simple Go To (Copter) (5)
while not api.exit:
print " Altitude: ", vehicle.location.alt
if vehicle.location.alt >= aTargetAltitude * 0.95:
print "Reached target altitude“break;
time.sleep(1)
API が生きている限り
高度を表示します
目的の高度であるか調べ、目的の高度であればメッセージを出して、ループを抜けます
そうでなければ 1秒待ちます
目的の高度になるまで処理を待ちます
Simple Go To (Copter) (6)
arm_and_takeoff(20)
print "Going to first point..."point1 = Location(-35.361354, 149.165218, 20, is_relative=True)vehicle.commands.goto(point1)vehicle.flush()time.sleep(30)
print "Going to second point..."point2 = Location(-35.363244, 149.168801, 20, is_relative=True)vehicle.commands.goto(point2)vehicle.flush()time.sleep(20)
print "Returning to Launch"vehicle.mode = VehicleMode("RTL")vehicle.flush()
目的高度まで飛び立たせます
最初のポイントに飛行します最初の点の Location を作ります
移動するよう指示して反映させます30秒待ちます (多分その間に飛行する )
次のポイントに飛行します次のポイントの Location を作ります
移動するよう指示して反映させます20秒待ちます (多分その間に飛行する )
帰投モードにします反映させます
メインのコントロールです
Follow Me(1)
import gpsimport socketimport timefrom droneapi.lib import VehicleMode, Location
ライブラリのインポートこのサンプルでは、 GPS デーモンと通信して、その位置に移動させるために、今までとはちょっと違うライブラリもインポートしています
「付いて来る」
Follow Me(2)
def followme():try:
api = local_connect()v = api.get_vehicles()[0]
if v.mode.name == "INITIALISING":print "Vehicle still booting, try again later"return
cmds = v.commandsis_guided = False
gpsd = gps. gps ( mode = gps. WATCH_ENABLE)
「付いて来る」関数を定義します例外処理を考慮します
いつもの準備
モードが’ INITIALISING’ であれば、「後にしろ」を表示して
おしまい
Command を取得します
GPS が取得出来るようにします
機体と GPS の初期化をします
Follow Me(3)
while not api.exit:gpsd.next()if is_guided and v.mode.name != "GUIDED":
print "User has changed flight modes - aborting follow-me“break
if (gpsd.valid & gps.LATLON_SET) != 0:altitude = 30dest = Location(gpsd.fix.latitude, gpsd.fix.longitude, altitude, is_relative=True)print "Going to: %s" % destcmds.goto(dest)is_guided = Truev.flush()time.sleep(2)
API が生きている間GPS データを取得しますモードに矛盾があったら停止
GPS データが有効であれば高さを 30m にしてGPS から取得した位置でLocation を作り、Location を表示し
Location に行くように指示
反映させて2秒待ちます
「付いて来る」の本体
Follow Me(4)
except socket.error: print "Error: gpsd service does not seem to be running, plug in USB GPS or run run-fake-gps.sh"
socket の例外の場合メッセージを出します
例外処理
おまけ (DroneKit の build)
git clone git://github.com/diydrones/ardupilot.git
sudo apt-get install python-matplotlib python-serial python-wxgtk2.8 python-lxmlsudo apt-get install python-scipy python-opencv ccache gawk git python-pip python-pexpectsudo pip install pymavlink MAVProxy
cd ardupilot
export PATH=$PATH:$HOME/ardupilot/jsbsim/srcexport PATH=$PATH:$HOME/ardupilot/Tools/autotest
sim_vehicle.sh -w
ソースを取得
いろいろ必要なものをインストール
環境変数作る
Build もこの中で勝手にしてくれる
IA64 、 RaspberryPi 上で可能 (Ubuntu 14)