Upload
masami-ogoshi
View
15.302
Download
2
Embed Size (px)
Citation preview
Dronekit による Python API とアプリ開発の概要@ogochan
2015 年7月20日
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 Falsedroneapi.lib.Attitude 機体の方向 pitch ピッチ radian yaw ヨー radian roll ロール radiandroneapi.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が理解出来れば、だいたい OK
他はほとんどデータ操作
droneapi.lib.Vehiclelocation 現在の Location droneapi.lib.Locationattitude 現在の Attitude droneapi.lib.Attitudevelocity 現在の速度 [ vx, vy, vz ]mode 現在の飛行モードの取得と設定 droneapi.lib.VehicleModeairspeed 現在の対気速度 doublegroundspeed 現在の対地速度 doublegps_0 GPS の情報 droneapi.lib.GPSInfoarmed 装備状態 booleanmount_status ジンバルの状態 [ pitch, yaw, roll ] or Nonebattery バッテリの状態 droneapi.lib.Batterychannel_override RC チャネルの直接的な変更 ハッシュchannel_readback RC チャネルの読み出し ハッシュadd_attribute_observer 属性オブザーバの追加 commands 現在の飛行の通過点 (waypoint) の取得 droneapi.lib.CommandSequenceflush() いわゆる flush message_factory 生 MAV Link メッセージを作成するオブジェクトを得る parameters 機体のパラメータ ( 編集可能 ) を得る droneapi.lib.Parametersremove_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.Battery
voltage 電圧 mV
current 電流 10mA
level 残量
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)