//go:build example // +build example // // Do not build by default. /* You must have ffmpeg and OpenCV installed in order to run this code. It will connect to the Tello and then open a window using OpenCV showing the streaming video. How to run go run examples/tello_opencv.go */ package main import ( "fmt" "io" "os/exec" "strconv" "time" "gobot.io/x/gobot/v2" "gobot.io/x/gobot/v2/platforms/dji/tello" "gocv.io/x/gocv" ) const ( frameX = 960 frameY = 720 frameSize = frameX * frameY * 3 ) func main() { drone := tello.NewDriver("8890") window := gocv.NewWindow("Tello") ffmpeg := exec.Command("ffmpeg", "-hwaccel", "auto", "-hwaccel_device", "opencl", "-i", "pipe:0", "-pix_fmt", "bgr24", "-s", strconv.Itoa(frameX)+"x"+strconv.Itoa(frameY), "-f", "rawvideo", "pipe:1") ffmpegIn, _ := ffmpeg.StdinPipe() ffmpegOut, _ := ffmpeg.StdoutPipe() work := func() { if err := ffmpeg.Start(); err != nil { fmt.Println(err) return } _ = drone.On(tello.ConnectedEvent, func(data interface{}) { fmt.Println("Connected") if err := drone.StartVideo(); err != nil { fmt.Println(err) } if err := drone.SetVideoEncoderRate(tello.VideoBitRateAuto); err != nil { fmt.Println(err) } if err := drone.SetExposure(0); err != nil { fmt.Println(err) } gobot.Every(100*time.Millisecond, func() { if err := drone.StartVideo(); err != nil { fmt.Println(err) } }) }) _ = drone.On(tello.VideoFrameEvent, func(data interface{}) { pkt := data.([]byte) if _, err := ffmpegIn.Write(pkt); err != nil { fmt.Println(err) } }) } robot := gobot.NewRobot("tello", []gobot.Connection{}, []gobot.Device{drone}, work, ) // calling Start(false) lets the Start routine return immediately without an additional blocking goroutine robot.Start(false) // now handle video frames from ffmpeg stream in main thread, to be macOS/Windows friendly for { buf := make([]byte, frameSize) if _, err := io.ReadFull(ffmpegOut, buf); err != nil { fmt.Println(err) continue } img, _ := gocv.NewMatFromBytes(frameY, frameX, gocv.MatTypeCV8UC3, buf) if img.Empty() { continue } window.IMShow(img) if window.WaitKey(1) >= 0 { break } } }