スポンサーリンク

市販ドローン

トイドローンTelloでGo言語プログラミング!フロントカメラのビデオ映像も取得成功!

TelloのメーカーであるRyze Techは
ホームページでPython用のSDKを公開しています。
詳細は、メーカーホームページからドキュメントをダウンロードできます。
https://www.ryzerobotics.com/tello/downloads

で、ドキュメントを眺めてみたんですが、
基本的な離陸、着陸、上下左右、回転、前進後退などの他に、
フリップも可能なようです。

しかし、残念ながらフロントカメラの映像の取得方法についての記述はどこにもありません。
これだけだと、応用効かないですよね。

やはり、フロントカメラの映像をプログラムから取得し、OpenCVに渡して
顔の検出、オブジェクトトラッキング、ハンドジェスチャー
など、したいじゃないですか。

正規のiPhoneアプリではリアルタイムにストリーム映像が見えてますので、
SDKとしては公開していないだけで、なにかしらの方法で取得できるはずです。
WifiのどこかのポートにUDPで送られてるんだと思います。

で、同じようなことを考えて、仕組みを解析し、
はたまたライブラリを公開くださっている方はいないかどうか
調査したところ、ありがたいことにいらっしゃいました。

現時点で見つけたライブラリの一つはGo言語のライブラリで
Gobotというロボット・IoT系のライブラリの子ライブラリとして
Telloが追加されています。
https://gobot.io/documentation/platforms/tello/

さらに、このサイトのExamplesに、
Tello + Video という項目があり、このサンプルコードを動かしてみたところ、
SDKでは公開されていないはずの、Telloのフロントカメラの映像取得が可能になり、
Macの画面上に映し出すことができました。

今までGo言語は触ったことがなかったので、少しずつ勉強していきたいと思います。
はじめの一歩として、同じくGobotにJoystickというライブラリがあるので、それを組み合わせ、
PS4コントローラーからTelloを操作できるまでを作りましたので、
サンプルコードを記載します。

package main

import (
	"fmt"
	"gobot.io/x/gobot"
	"gobot.io/x/gobot/platforms/dji/tello"
	"gobot.io/x/gobot/platforms/joystick"
	"os/exec"
	"sync/atomic"
	"time"
)

type pair struct {
	x float64
	y float64
}

var leftX, leftY, rightX, rightY atomic.Value

const offset = 32767.0

func main() {
	drone := tello.NewDriver("8890")
	joystickAdaptor := joystick.NewAdaptor()
	stick := joystick.NewDriver(joystickAdaptor, "dualshock4")

	work := func() {
		leftX.Store(float64(0.0))
		leftY.Store(float64(0.0))
		rightX.Store(float64(0.0))
		rightY.Store(float64(0.0))
		mplayer := exec.Command("mplayer", "-fps", "35", "-")
		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)
			}
		})

		stick.On(joystick.SquarePress, func(data interface{}) {
			fmt.Println("SquarePress")
			drone.BackFlip()
		})

		stick.On(joystick.TriangleRelease, func(data interface{}) {
			fmt.Println("TakeOff")
			drone.TakeOff()
		})
		stick.On(joystick.CirclePress, func(data interface{}) {
			fmt.Println("Land")
			drone.Land()
		})
		stick.On(joystick.LeftX, func(data interface{}) {
			val := float64(data.(int16))
			leftX.Store(val)
		})
		stick.On(joystick.LeftY, func(data interface{}) {
			val := float64(data.(int16))
			leftY.Store(val)
		})
		stick.On(joystick.RightX, func(data interface{}) {
			val := float64(data.(int16))
			rightX.Store(val)
		})
		stick.On(joystick.RightY, func(data interface{}) {
			val := float64(data.(int16))
			rightY.Store(val)
		})
		gobot.Every(10*time.Millisecond, func() {
			rightStick := getRightStick()

			switch {
			case rightStick.y < -10:
				drone.Forward(tello.ValidatePitch(rightStick.y, offset))
			case rightStick.y > 10:
				drone.Backward(tello.ValidatePitch(rightStick.y, offset))
			default:
				drone.Forward(0)
			}

			switch {
			case rightStick.x > 10:
				drone.Right(tello.ValidatePitch(rightStick.x, offset))
			case rightStick.x < -10:
				drone.Left(tello.ValidatePitch(rightStick.x, offset))
			default:
				drone.Right(0)
			}
		})

		gobot.Every(10*time.Millisecond, func() {
			leftStick := getLeftStick()
			switch {
			case leftStick.y < -10:
				drone.Up(tello.ValidatePitch(leftStick.y, offset))
			case leftStick.y > 10:
				drone.Down(tello.ValidatePitch(leftStick.y, offset))
			default:
				drone.Up(0)
			}

			switch {
			case leftStick.x > 20:
				drone.Clockwise(tello.ValidatePitch(leftStick.x, offset))
			case leftStick.x < -20:
				drone.CounterClockwise(tello.ValidatePitch(leftStick.x, offset))
			default:
				drone.Clockwise(0)
			}
		})

	}

	robot := gobot.NewRobot("tello",
		[]gobot.Connection{joystickAdaptor},
		[]gobot.Device{drone, stick},
		work,
	)

	robot.Start()
}

func getLeftStick() pair {
	s := pair{x: 0, y: 0}
	s.x = leftX.Load().(float64)
	s.y = leftY.Load().(float64)
	return s
}

func getRightStick() pair {
	s := pair{x: 0, y: 0}
	s.x = rightX.Load().(float64)
	s.y = rightY.Load().(float64)
	return s
}

これで、PS4コントローラーをMacにつなげば、
△ボタンで離陸、◯ボタンで着地、□ボタンでフリップ。
左右のジョイスティックは、モード2のプロポと同じ設定になっています。

そして、映像はmplayerで表示されます。ノイズはそこまで頻度はなく、また量も少なめです。
(Parrot Bebop2のときは、ノイズもレイテンシーももっとひどかった。。)

次回は、OpenCVを組み合わせた応用例を紹介したいと思います。

[Amazon] 【国内正規品】 Ryze トイドローン Tello Powered by DJI

ピックアップ記事

  1. 新世代フライトコントローラーSP Racing F3
  2. 210サイズドローンの制作
  3. Parrot Bebop2のカメラ映像をリアルタイムにYouTube配信する方法…
  4. QAV250をリニューアル制作
  5. トイドローンTelloでGo言語プログラミング!フロントカメラのビデオ映像も取得…

関連記事

  1. 市販ドローン

    DJIとIntelの最新技術の結晶 80gの小型ドローンTello

    中国のRyze Tech というメーカーの小型ドローンを購入しました。…

  2. 市販ドローン

    Parrot bebop2をNode.jsで操作してみた

    Parrot bebop2はプログラミング可能な市販ドローンという…

  3. 市販ドローン

    プログラミングができる市販ドローン”Parrot Bebop2″開封レビュー…

    今回、新たに一台ドローンを迎え入れました。購入したドローンは・・・…

  4. Webプログラミング

    Parrot Bebop2のカメラ映像をリアルタイムにYouTube配信する方法

    Node.jsを使い、Parrot Bebop2をどこまでコントロール…

おすすめ記事

最近の記事

  1. トイドローンTelloでGo言語プログラミング!フロントカメ…
  2. DJIとIntelの最新技術の結晶 80gの小型ドローンTe…
  3. Parrot Bebop2のカメラ映像をリアルタイムにYou…
  4. Parrot bebop2をNode.jsで操作してみた
  5. プログラミングができる市販ドローン”Parrot…

月別アーカイブ

  1. ドローンのパーツ

    かっこいいアンテナホルダーを自作する方法
  2. 市販ドローン

    プログラミングができる市販ドローン”Parrot Bebop2…
  3. RaspberryPi

    ラズパイで3Gデータ通信をするには
  4. ドローン制作

    QAV250をリニューアル制作
  5. ドローン練習

    ドローンシミュレーター”Liftoff”でレベルアップを…
PAGE TOP