gobot.io/x/gobot/v2@v2.1.0/examples/bebop_ps3_video.go (about)

     1  //go:build example
     2  // +build example
     3  
     4  //
     5  // Do not build by default.
     6  
     7  /*
     8  This example will connect to the Parrot Bebop allowing you to control
     9  it using a PS3 controller.
    10  
    11  It also streams the drone video to a webpage via ffserver.
    12  
    13  This requires you to have both ffmpeg and ffserver installed
    14  on your computer.
    15  
    16  In order to run this example you will first need to start ffserver with:
    17  
    18  	$ ffserver -f ff.conf
    19  
    20  then in a separate terminal run this program:
    21  
    22  	$ go run bebop_ps3_video.go
    23  
    24  You can view the video feed by navigating to
    25  http://localhost:8090/bebop.mjpeg in a web browser.
    26  *NOTE* firefox works best for viewing the video feed.
    27  */
    28  package main
    29  
    30  import (
    31  	"fmt"
    32  	"io"
    33  	"io/ioutil"
    34  	"os/exec"
    35  	"sync/atomic"
    36  	"time"
    37  
    38  	"gobot.io/x/gobot/v2"
    39  	"gobot.io/x/gobot/v2/platforms/joystick"
    40  	"gobot.io/x/gobot/v2/platforms/parrot/bebop"
    41  )
    42  
    43  type pair struct {
    44  	x float64
    45  	y float64
    46  }
    47  
    48  var leftX, leftY, rightX, rightY atomic.Value
    49  
    50  const offset = 32767.0
    51  
    52  func ffmpeg() (stdin io.WriteCloser, stderr io.ReadCloser, err error) {
    53  	ffmpeg := exec.Command("ffmpeg", "-i", "pipe:0", "http://localhost:8090/bebop.ffm")
    54  
    55  	stderr, err = ffmpeg.StderrPipe()
    56  
    57  	if err != nil {
    58  		return
    59  	}
    60  
    61  	stdin, err = ffmpeg.StdinPipe()
    62  
    63  	if err != nil {
    64  		return
    65  	}
    66  
    67  	if err = ffmpeg.Start(); err != nil {
    68  		return
    69  	}
    70  
    71  	go func() {
    72  		for {
    73  			buf, err := ioutil.ReadAll(stderr)
    74  			if err != nil {
    75  				fmt.Println(err)
    76  			}
    77  			if len(buf) > 0 {
    78  				fmt.Println(string(buf))
    79  			}
    80  		}
    81  	}()
    82  
    83  	return stdin, stderr, nil
    84  }
    85  
    86  func main() {
    87  	joystickAdaptor := joystick.NewAdaptor()
    88  	stick := joystick.NewDriver(joystickAdaptor, "dualshock3")
    89  
    90  	bebopAdaptor := bebop.NewAdaptor()
    91  	drone := bebop.NewDriver(bebopAdaptor)
    92  
    93  	work := func() {
    94  		drone.VideoEnable(true)
    95  		video, _, _ := ffmpeg()
    96  
    97  		go func() {
    98  			for {
    99  				if _, err := video.Write(<-drone.Video()); err != nil {
   100  					fmt.Println(err)
   101  					return
   102  				}
   103  			}
   104  		}()
   105  
   106  		leftX.Store(float64(0.0))
   107  		leftY.Store(float64(0.0))
   108  		rightX.Store(float64(0.0))
   109  		rightY.Store(float64(0.0))
   110  
   111  		recording := false
   112  
   113  		stick.On(joystick.CirclePress, func(data interface{}) {
   114  			if recording {
   115  				drone.StopRecording()
   116  			} else {
   117  				drone.StartRecording()
   118  			}
   119  			recording = !recording
   120  		})
   121  
   122  		stick.On(joystick.SquarePress, func(data interface{}) {
   123  			drone.HullProtection(true)
   124  			drone.TakeOff()
   125  		})
   126  		stick.On(joystick.TrianglePress, func(data interface{}) {
   127  			drone.Stop()
   128  		})
   129  		stick.On(joystick.XPress, func(data interface{}) {
   130  			drone.Land()
   131  		})
   132  		stick.On(joystick.LeftX, func(data interface{}) {
   133  			val := float64(data.(int16))
   134  			leftX.Store(val)
   135  		})
   136  
   137  		stick.On(joystick.LeftY, func(data interface{}) {
   138  			val := float64(data.(int16))
   139  			leftY.Store(val)
   140  		})
   141  
   142  		stick.On(joystick.RightX, func(data interface{}) {
   143  			val := float64(data.(int16))
   144  			rightX.Store(val)
   145  		})
   146  
   147  		stick.On(joystick.RightY, func(data interface{}) {
   148  			val := float64(data.(int16))
   149  			rightY.Store(val)
   150  		})
   151  
   152  		gobot.Every(10*time.Millisecond, func() {
   153  			leftStick := getLeftStick()
   154  
   155  			switch {
   156  			case leftStick.y < -10:
   157  				drone.Forward(bebop.ValidatePitch(leftStick.y, offset))
   158  			case leftStick.y > 10:
   159  				drone.Backward(bebop.ValidatePitch(leftStick.y, offset))
   160  			default:
   161  				drone.Forward(0)
   162  			}
   163  
   164  			switch {
   165  			case leftStick.x > 10:
   166  				drone.Right(bebop.ValidatePitch(leftStick.x, offset))
   167  			case leftStick.x < -10:
   168  				drone.Left(bebop.ValidatePitch(leftStick.x, offset))
   169  			default:
   170  				drone.Right(0)
   171  			}
   172  		})
   173  
   174  		gobot.Every(10*time.Millisecond, func() {
   175  			rightStick := getRightStick()
   176  			switch {
   177  			case rightStick.y < -10:
   178  				drone.Up(bebop.ValidatePitch(rightStick.y, offset))
   179  			case rightStick.y > 10:
   180  				drone.Down(bebop.ValidatePitch(rightStick.y, offset))
   181  			default:
   182  				drone.Up(0)
   183  			}
   184  
   185  			switch {
   186  			case rightStick.x > 20:
   187  				drone.Clockwise(bebop.ValidatePitch(rightStick.x, offset))
   188  			case rightStick.x < -20:
   189  				drone.CounterClockwise(bebop.ValidatePitch(rightStick.x, offset))
   190  			default:
   191  				drone.Clockwise(0)
   192  			}
   193  		})
   194  	}
   195  
   196  	robot := gobot.NewRobot("bebop",
   197  		[]gobot.Connection{joystickAdaptor, bebopAdaptor},
   198  		[]gobot.Device{stick, drone},
   199  		work,
   200  	)
   201  
   202  	robot.Start()
   203  }
   204  
   205  func getLeftStick() pair {
   206  	s := pair{x: 0, y: 0}
   207  	s.x = leftX.Load().(float64)
   208  	s.y = leftY.Load().(float64)
   209  	return s
   210  }
   211  
   212  func getRightStick() pair {
   213  	s := pair{x: 0, y: 0}
   214  	s.x = rightX.Load().(float64)
   215  	s.y = rightY.Load().(float64)
   216  	return s
   217  }