こんにちは、のびすけです。Go合宿2018にて記事書いてます。
ということで、今日はGoでドローン制御してみます。
ちなみに環境はmacos high sierra
DJI Tello
DJIとインテルが共同で作ったすごいドローン。最近話題。
制御方法
他のトイドローンはBLEなどが主流でしたが、Telloの場合Wi-Fiのアドホック通信でUDPパケットを送る仕様になっています。なので割とどんな言語でもライブラリなど無しで叩けます。
ただしPCのWi-FiがTelloの接続に取られてしまうのでWi-Fi経由でインターネットにはアクセス出来なくなります。
TelloをPCで制御しつつインターネットに繋ぎたい場合はLANケーブル、Bluetoothテザリング、USBテザリングなどを使いましょう。
GoBotがTello対応
GoBotはGoでハードウェア制御する系フレームワークです。ChatBot的なものではないです。
対象デバイスはスマートトイ系が多いイメージ。
これで準備完了です。
go get -d -u gobot.io/x/gobot/..
GoBotでTelloを飛ばす
以下のコードで離陸して5秒後に着陸
します。
package main
import (
"time"
"gobot.io/x/gobot"
"gobot.io/x/gobot/platforms/dji/tello"
)
func main() {
drone := tello.NewDriver("8888")
work := func() {
drone.TakeOff()
gobot.After(5*time.Second, func() {
drone.Land()
})
}
robot := gobot.NewRobot("tello",
[]gobot.Connection{},
[]gobot.Device{drone},
work,
)
robot.Start()
}
UDPパケットを内部で送ってますがTelloのSDKに仕様が書いています。
参考: https://dl-cdn.ryzerobotics.com/downloads/tello/0228/Tello+SDK+Readme.pdf
GoBotでTelloのカメラにアクセス
TelloのSDKにはカメラアクセスについては記載が無いですが、GoBotのドライバには何故かあります。他の言語でもTello制御はできますが、これだけでGo使う意義ありそう。
サンプルコードがmplayerを内部で起動してパケットを流し込んでるのでmplayerをインストールします。
$ brew install mplayer
package main
import (
"fmt"
"os/exec"
"time"
"gobot.io/x/gobot"
"gobot.io/x/gobot/platforms/dji/tello"
)
func main() {
drone := tello.NewDriver("8890")
work := func() {
mplayer := exec.Command("mplayer", "-fps", "25", "-")
mplayerIn, _ := mplayer.StdinPipe()
if err := mplayer.Start(); err != nil {
fmt.Println(err)
return
}
drone.On(tello.ConnectedEvent, func(data interface{}) {
fmt.Println("Connected")
drone.StartVideo()
drone.SetVideoEncoderRate(4)
gobot.Every(100*time.Millisecond, func() {
drone.StartVideo()
})
})
drone.On(tello.VideoFrameEvent, func(data interface{}) {
pkt := data.([]byte)
if _, err := mplayerIn.Write(pkt); err != nil {
fmt.Println(err)
}
})
}
robot := gobot.NewRobot("tello",
[]gobot.Connection{},
[]gobot.Device{drone},
work,
)
robot.Start()
}
実行するとこんな感じ。ノイズが入りますがまぁ分かる。
キー入力でドローンを制御しながら映像取得
ジョイスティックなどがあればよかったですが今回は持ち合わせがないのでキーボードで。
GoBotのドライバーでキー入力を取得できるのでこちらを併用します。
参考: トイドローンTelloでGo言語プログラミング!フロントカメラのビデオ映像も取得成功!
参考: https://godoc.org/gobot.io/x/gobot/platforms/dji/tello
参考: https://godoc.org/gobot.io/x/gobot/platforms/keyboard
package main
import (
"fmt"
"os/exec"
"time"
"gobot.io/x/gobot"
"gobot.io/x/gobot/platforms/keyboard"
"gobot.io/x/gobot/platforms/dji/tello"
)
func main() {
drone := tello.NewDriver("8890")
keys := keyboard.NewDriver()
work := func() {
/**
ドローンカメラアクセス
*/
mplayer := exec.Command("mplayer", "-fps", "25", "-")
mplayerIn, _ := mplayer.StdinPipe()
if err := mplayer.Start(); err != nil {
fmt.Println(err)
return
}
drone.On(tello.ConnectedEvent, func(data interface{}) {
fmt.Println("Connected")
drone.StartVideo()
drone.SetVideoEncoderRate(4)
gobot.Every(100*time.Millisecond, func() {
drone.StartVideo()
})
})
drone.On(tello.VideoFrameEvent, func(data interface{}) {
pkt := data.([]byte)
if _, err := mplayerIn.Write(pkt); err != nil {
fmt.Println(err)
}
})
/**
ドローン制御
*/
keys.On(keyboard.Key, func(data interface{}) {
key := data.(keyboard.KeyEvent)
if key.Key == keyboard.C {
fmt.Println("Command Test")
} else if key.Key == keyboard.T{
fmt.Println("Take Off!")
drone.TakeOff() //離陸
} else if key.Key == keyboard.L{
fmt.Println("Land")
drone.TakeLand() //着陸
} else if key.Char == keyboard.ArrowUp{
fmt.Println("↑")
drone.Forward(10) //前進
} else if key.Char == keyboard.ArrowDown{
fmt.Println("↓")
drone.Backward(10) //後退
} else if key.Char == keyboard.ArrowRight{
fmt.Println("→")
drone.Right(10) //右へ
} else if key.Char == keyboard.ArrowLeft{
fmt.Println("←")
drone.Left(10) //左へ
} else if key.Key == keyboard.U{
fmt.Println("Up")
drone.Up(10) //上昇
} else if key.Key == keyboard.D{
fmt.Println("Down")
drone.Down(10) //下降
} else if key.Key == keyboard.F{
fmt.Println("Front Flip")
drone.FrontFlip() //フリップ
} else if key.Key == keyboard.B{
fmt.Println("Back Flip")
drone.BackFlip() //バックフリップ
} else {
fmt.Println("keyboard event!", key, key.Char)
}
})
}
robot := gobot.NewRobot("tello",
[]gobot.Connection{},
[]gobot.Device{drone, keys}, //droneとkeysの二つのアダプタ
work,
)
robot.Start()
}
所感
Tello楽しい。映像ストリーミングはWebRTCにつなげて配信とかしてみたいですね。
Wi-Fiのポートが占有されてしまうのが少し扱いが難しいですね。
WebRTCはJS実装が多いので、Node.jsでも無いかなぁと思ったらSovGVD/nodetelloがあったのでこちらも試してみたい。
毎回合宿でドローン触ってる気がする。