dronekitによる python apiとアプリ開発の概要

38
Dronekit ににに Python API に にににににににに @ogochan 2015 に にに に に 720

Upload: masami-ogoshi

Post on 12-Aug-2015

1.034 views

Category:

Devices & Hardware


0 download

TRANSCRIPT

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 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が理解出来れば、

だいたい OK

他はほとんどデータ操作

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.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)