gobot.io/x/gobot@v1.16.0/platforms/dji/tello/driver.go (about)

     1  package tello
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"math"
    10  	"net"
    11  	"strconv"
    12  	"sync"
    13  	"time"
    14  
    15  	"gobot.io/x/gobot"
    16  )
    17  
    18  const (
    19  	// BounceEvent event
    20  	BounceEvent = "bounce"
    21  
    22  	// ConnectedEvent event
    23  	ConnectedEvent = "connected"
    24  
    25  	// FlightDataEvent event
    26  	FlightDataEvent = "flightdata"
    27  
    28  	// TakeoffEvent event
    29  	TakeoffEvent = "takeoff"
    30  
    31  	// LandingEvent event
    32  	LandingEvent = "landing"
    33  
    34  	// PalmLandingEvent event
    35  	PalmLandingEvent = "palm-landing"
    36  
    37  	// FlipEvent event
    38  	FlipEvent = "flip"
    39  
    40  	// TimeEvent event
    41  	TimeEvent = "time"
    42  
    43  	// LogEvent event
    44  	LogEvent = "log"
    45  
    46  	// WifiDataEvent event
    47  	WifiDataEvent = "wifidata"
    48  
    49  	// LightStrengthEvent event
    50  	LightStrengthEvent = "lightstrength"
    51  
    52  	// SetExposureEvent event
    53  	SetExposureEvent = "setexposure"
    54  
    55  	// VideoFrameEvent event
    56  	VideoFrameEvent = "videoframe"
    57  
    58  	// SetVideoEncoderRateEvent event
    59  	SetVideoEncoderRateEvent = "setvideoencoder"
    60  )
    61  
    62  // the 16-bit messages and commands stored in bytes 6 & 5 of the packet
    63  const (
    64  	messageStart   = 0x00cc // 204
    65  	wifiMessage    = 0x001a // 26
    66  	videoRateQuery = 0x0028 // 40
    67  	lightMessage   = 0x0035 // 53
    68  	flightMessage  = 0x0056 // 86
    69  	logMessage     = 0x1050 // 4176
    70  
    71  	videoEncoderRateCommand = 0x0020 // 32
    72  	videoStartCommand       = 0x0025 // 37
    73  	exposureCommand         = 0x0034 // 52
    74  	timeCommand             = 0x0046 // 70
    75  	stickCommand            = 0x0050 // 80
    76  	takeoffCommand          = 0x0054 // 84
    77  	landCommand             = 0x0055 // 85
    78  	flipCommand             = 0x005c // 92
    79  	throwtakeoffCommand     = 0x005d // 93
    80  	palmLandCommand         = 0x005e // 94
    81  	bounceCommand           = 0x1053 // 4179
    82  )
    83  
    84  // FlipType is used for the various flips supported by the Tello.
    85  type FlipType int
    86  
    87  const (
    88  	// FlipFront flips forward.
    89  	FlipFront FlipType = 0
    90  
    91  	// FlipLeft flips left.
    92  	FlipLeft FlipType = 1
    93  
    94  	// FlipBack flips backwards.
    95  	FlipBack FlipType = 2
    96  
    97  	// FlipRight flips to the right.
    98  	FlipRight FlipType = 3
    99  
   100  	// FlipForwardLeft flips forwards and to the left.
   101  	FlipForwardLeft FlipType = 4
   102  
   103  	// FlipBackLeft flips backwards and to the left.
   104  	FlipBackLeft FlipType = 5
   105  
   106  	// FlipBackRight flips backwards and to the right.
   107  	FlipBackRight FlipType = 6
   108  
   109  	// FlipForwardRight flips forewards and to the right.
   110  	FlipForwardRight FlipType = 7
   111  )
   112  
   113  // VideoBitRate is used to set the bit rate for the streaming video returned by the Tello.
   114  type VideoBitRate int
   115  
   116  const (
   117  	// VideoBitRateAuto sets the bitrate for streaming video to auto-adjust.
   118  	VideoBitRateAuto VideoBitRate = 0
   119  
   120  	// VideoBitRate1M sets the bitrate for streaming video to 1 Mb/s.
   121  	VideoBitRate1M VideoBitRate = 1
   122  
   123  	// VideoBitRate15M sets the bitrate for streaming video to 1.5 Mb/s
   124  	VideoBitRate15M VideoBitRate = 2
   125  
   126  	// VideoBitRate2M sets the bitrate for streaming video to 2 Mb/s.
   127  	VideoBitRate2M VideoBitRate = 3
   128  
   129  	// VideoBitRate3M sets the bitrate for streaming video to 3 Mb/s.
   130  	VideoBitRate3M VideoBitRate = 4
   131  
   132  	// VideoBitRate4M sets the bitrate for streaming video to 4 Mb/s.
   133  	VideoBitRate4M VideoBitRate = 5
   134  )
   135  
   136  // FlightData packet returned by the Tello
   137  type FlightData struct {
   138  	BatteryLow               bool
   139  	BatteryLower             bool
   140  	BatteryPercentage        int8
   141  	BatteryState             bool
   142  	CameraState              int8
   143  	DownVisualState          bool
   144  	DroneBatteryLeft         int16
   145  	DroneFlyTimeLeft         int16
   146  	DroneHover               bool
   147  	EmOpen                   bool
   148  	Flying                   bool
   149  	OnGround                 bool
   150  	EastSpeed                int16
   151  	ElectricalMachineryState int16
   152  	FactoryMode              bool
   153  	FlyMode                  int8
   154  	FlyTime                  int16
   155  	FrontIn                  bool
   156  	FrontLSC                 bool
   157  	FrontOut                 bool
   158  	GravityState             bool
   159  	VerticalSpeed            int16
   160  	Height                   int16
   161  	ImuCalibrationState      int8
   162  	ImuState                 bool
   163  	LightStrength            int8
   164  	NorthSpeed               int16
   165  	OutageRecording          bool
   166  	PowerState               bool
   167  	PressureState            bool
   168  	SmartVideoExitMode       int16
   169  	TemperatureHigh          bool
   170  	ThrowFlyTimer            int8
   171  	WindState                bool
   172  }
   173  
   174  // WifiData packet returned by the Tello
   175  type WifiData struct {
   176  	Disturb  int8
   177  	Strength int8
   178  }
   179  
   180  // Driver represents the DJI Tello drone
   181  type Driver struct {
   182  	name           string
   183  	reqAddr        string
   184  	cmdConn        io.WriteCloser // UDP connection to send/receive drone commands
   185  	videoConn      *net.UDPConn   // UDP connection for drone video
   186  	respPort       string
   187  	videoPort      string
   188  	cmdMutex       sync.Mutex
   189  	seq            int16
   190  	rx, ry, lx, ly float32
   191  	throttle       int
   192  	bouncing       bool
   193  	gobot.Eventer
   194  	doneCh chan struct{}
   195  }
   196  
   197  // NewDriver creates a driver for the Tello drone. Pass in the UDP port to use for the responses
   198  // from the drone.
   199  func NewDriver(port string) *Driver {
   200  	d := &Driver{name: gobot.DefaultName("Tello"),
   201  		reqAddr:   "192.168.10.1:8889",
   202  		respPort:  port,
   203  		videoPort: "11111",
   204  		Eventer:   gobot.NewEventer(),
   205  		doneCh:    make(chan struct{}, 1),
   206  	}
   207  
   208  	d.AddEvent(ConnectedEvent)
   209  	d.AddEvent(FlightDataEvent)
   210  	d.AddEvent(TakeoffEvent)
   211  	d.AddEvent(LandingEvent)
   212  	d.AddEvent(PalmLandingEvent)
   213  	d.AddEvent(BounceEvent)
   214  	d.AddEvent(FlipEvent)
   215  	d.AddEvent(TimeEvent)
   216  	d.AddEvent(LogEvent)
   217  	d.AddEvent(WifiDataEvent)
   218  	d.AddEvent(LightStrengthEvent)
   219  	d.AddEvent(SetExposureEvent)
   220  	d.AddEvent(VideoFrameEvent)
   221  	d.AddEvent(SetVideoEncoderRateEvent)
   222  
   223  	return d
   224  }
   225  
   226  // NewDriverWithIP creates a driver for the Tello EDU drone. Pass in the ip address and UDP port to use for the responses
   227  // from the drone.
   228  func NewDriverWithIP(ip string, port string) *Driver {
   229  	d := &Driver{name: gobot.DefaultName("Tello"),
   230  		reqAddr:   ip + ":8889",
   231  		respPort:  port,
   232  		videoPort: "11111",
   233  		Eventer:   gobot.NewEventer(),
   234  	}
   235  
   236  	d.AddEvent(ConnectedEvent)
   237  	d.AddEvent(FlightDataEvent)
   238  	d.AddEvent(TakeoffEvent)
   239  	d.AddEvent(LandingEvent)
   240  	d.AddEvent(PalmLandingEvent)
   241  	d.AddEvent(BounceEvent)
   242  	d.AddEvent(FlipEvent)
   243  	d.AddEvent(TimeEvent)
   244  	d.AddEvent(LogEvent)
   245  	d.AddEvent(WifiDataEvent)
   246  	d.AddEvent(LightStrengthEvent)
   247  	d.AddEvent(SetExposureEvent)
   248  	d.AddEvent(VideoFrameEvent)
   249  	d.AddEvent(SetVideoEncoderRateEvent)
   250  
   251  	return d
   252  }
   253  
   254  // Name returns the name of the device.
   255  func (d *Driver) Name() string { return d.name }
   256  
   257  // SetName sets the name of the device.
   258  func (d *Driver) SetName(n string) { d.name = n }
   259  
   260  // Connection returns the Connection of the device.
   261  func (d *Driver) Connection() gobot.Connection { return nil }
   262  
   263  // Start starts the driver.
   264  func (d *Driver) Start() error {
   265  	reqAddr, err := net.ResolveUDPAddr("udp", d.reqAddr)
   266  	if err != nil {
   267  		fmt.Println(err)
   268  		return err
   269  	}
   270  	respPort, err := net.ResolveUDPAddr("udp", ":"+d.respPort)
   271  	if err != nil {
   272  		fmt.Println(err)
   273  		return err
   274  	}
   275  	cmdConn, err := net.DialUDP("udp", respPort, reqAddr)
   276  	if err != nil {
   277  		fmt.Println(err)
   278  		return err
   279  	}
   280  	d.cmdConn = cmdConn
   281  
   282  	// handle responses
   283  	go func() {
   284  		d.On(d.Event(ConnectedEvent), func(interface{}) {
   285  			d.SendDateTime()
   286  			d.processVideo()
   287  		})
   288  
   289  	cmdLoop:
   290  		for {
   291  			select {
   292  			case <-d.doneCh:
   293  				break cmdLoop
   294  			default:
   295  				err := d.handleResponse(cmdConn)
   296  				if err != nil {
   297  					fmt.Println("response parse error:", err)
   298  				}
   299  			}
   300  		}
   301  	}()
   302  
   303  	// starts notifications coming from drone to video port normally 11111
   304  	d.SendCommand(d.connectionString())
   305  
   306  	// send stick commands
   307  	go func() {
   308  		for {
   309  			err := d.SendStickCommand()
   310  			if err != nil {
   311  				fmt.Println("stick command error:", err)
   312  			}
   313  			time.Sleep(20 * time.Millisecond)
   314  		}
   315  	}()
   316  
   317  	return nil
   318  }
   319  
   320  // Halt stops the driver.
   321  func (d *Driver) Halt() (err error) {
   322  	// send a landing command when we disconnect, and give it 500ms to be received before we shutdown
   323  	d.Land()
   324  	d.doneCh <- struct{}{}
   325  	time.Sleep(500 * time.Millisecond)
   326  
   327  	d.cmdConn.Close()
   328  	if d.videoConn != nil {
   329  		d.videoConn.Close()
   330  	}
   331  	return
   332  }
   333  
   334  // TakeOff tells drones to liftoff and start flying.
   335  func (d *Driver) TakeOff() (err error) {
   336  	buf, _ := d.createPacket(takeoffCommand, 0x68, 0)
   337  	d.seq++
   338  	binary.Write(buf, binary.LittleEndian, d.seq)
   339  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   340  
   341  	_, err = d.cmdConn.Write(buf.Bytes())
   342  	return
   343  }
   344  
   345  // Throw & Go support
   346  func (d *Driver) ThrowTakeOff() (err error) {
   347  	buf, _ := d.createPacket(throwtakeoffCommand, 0x48, 0)
   348  	d.seq++
   349  	binary.Write(buf, binary.LittleEndian, d.seq)
   350  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   351  
   352  	_, err = d.cmdConn.Write(buf.Bytes())
   353  	return
   354  }
   355  
   356  // Land tells drone to come in for landing.
   357  func (d *Driver) Land() (err error) {
   358  	buf, _ := d.createPacket(landCommand, 0x68, 1)
   359  	d.seq++
   360  	binary.Write(buf, binary.LittleEndian, d.seq)
   361  	binary.Write(buf, binary.LittleEndian, byte(0x00))
   362  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   363  
   364  	_, err = d.cmdConn.Write(buf.Bytes())
   365  	return
   366  }
   367  
   368  // StopLanding tells drone to stop landing.
   369  func (d *Driver) StopLanding() (err error) {
   370  	buf, _ := d.createPacket(landCommand, 0x68, 1)
   371  	d.seq++
   372  	binary.Write(buf, binary.LittleEndian, d.seq)
   373  	binary.Write(buf, binary.LittleEndian, byte(0x01))
   374  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   375  
   376  	_, err = d.cmdConn.Write(buf.Bytes())
   377  	return
   378  }
   379  
   380  // PalmLand tells drone to come in for a hand landing.
   381  func (d *Driver) PalmLand() (err error) {
   382  	buf, _ := d.createPacket(palmLandCommand, 0x68, 1)
   383  	d.seq++
   384  	binary.Write(buf, binary.LittleEndian, d.seq)
   385  	binary.Write(buf, binary.LittleEndian, byte(0x00))
   386  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   387  
   388  	_, err = d.cmdConn.Write(buf.Bytes())
   389  	return
   390  }
   391  
   392  // StartVideo tells Tello to send start info (SPS/PPS) for video stream.
   393  func (d *Driver) StartVideo() (err error) {
   394  	buf, _ := d.createPacket(videoStartCommand, 0x60, 0)
   395  	binary.Write(buf, binary.LittleEndian, int16(0x00)) // seq = 0
   396  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   397  
   398  	_, err = d.cmdConn.Write(buf.Bytes())
   399  	return
   400  }
   401  
   402  // SetExposure sets the drone camera exposure level. Valid levels are 0, 1, and 2.
   403  func (d *Driver) SetExposure(level int) (err error) {
   404  	if level < 0 || level > 2 {
   405  		return errors.New("Invalid exposure level")
   406  	}
   407  
   408  	buf, _ := d.createPacket(exposureCommand, 0x48, 1)
   409  	d.seq++
   410  	binary.Write(buf, binary.LittleEndian, d.seq)
   411  	binary.Write(buf, binary.LittleEndian, byte(level))
   412  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   413  
   414  	_, err = d.cmdConn.Write(buf.Bytes())
   415  	return
   416  }
   417  
   418  // SetVideoEncoderRate sets the drone video encoder rate.
   419  func (d *Driver) SetVideoEncoderRate(rate VideoBitRate) (err error) {
   420  	buf, _ := d.createPacket(videoEncoderRateCommand, 0x68, 1)
   421  	d.seq++
   422  	binary.Write(buf, binary.LittleEndian, d.seq)
   423  	binary.Write(buf, binary.LittleEndian, byte(rate))
   424  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   425  
   426  	_, err = d.cmdConn.Write(buf.Bytes())
   427  	return
   428  }
   429  
   430  // SetFastMode sets the drone throttle to 1.
   431  func (d *Driver) SetFastMode() error {
   432  	d.cmdMutex.Lock()
   433  	defer d.cmdMutex.Unlock()
   434  
   435  	d.throttle = 1
   436  	return nil
   437  }
   438  
   439  // SetSlowMode sets the drone throttle to 0.
   440  func (d *Driver) SetSlowMode() error {
   441  	d.cmdMutex.Lock()
   442  	defer d.cmdMutex.Unlock()
   443  
   444  	d.throttle = 0
   445  	return nil
   446  }
   447  
   448  // Rate queries the current video bit rate.
   449  func (d *Driver) Rate() (err error) {
   450  	buf, _ := d.createPacket(videoRateQuery, 0x48, 0)
   451  	d.seq++
   452  	binary.Write(buf, binary.LittleEndian, d.seq)
   453  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   454  
   455  	_, err = d.cmdConn.Write(buf.Bytes())
   456  	return
   457  }
   458  
   459  // bound is a naive implementation that returns the smaller of x or y.
   460  func bound(x, y float32) float32 {
   461  	if x < -y {
   462  		return -y
   463  	}
   464  	if x > y {
   465  		return y
   466  	}
   467  	return x
   468  }
   469  
   470  // Vector returns the current motion vector.
   471  // Values are from 0 to 1.
   472  // x, y, z denote forward, side and vertical translation,
   473  // and psi  yaw (rotation around the z-axis).
   474  func (d *Driver) Vector() (x, y, z, psi float32) {
   475  	return d.ry, d.rx, d.ly, d.lx
   476  }
   477  
   478  // AddVector adds to the current motion vector.
   479  // Pass values from 0 to 1.
   480  // See Vector() for the frame of reference.
   481  func (d *Driver) AddVector(x, y, z, psi float32) error {
   482  	d.cmdMutex.Lock()
   483  	defer d.cmdMutex.Unlock()
   484  
   485  	d.ry = bound(d.ry+x, 1)
   486  	d.rx = bound(d.rx+y, 1)
   487  	d.ly = bound(d.ly+z, 1)
   488  	d.lx = bound(d.lx+psi, 1)
   489  
   490  	return nil
   491  }
   492  
   493  // SetVector sets the current motion vector.
   494  // Pass values from 0 to 1.
   495  // See Vector() for the frame of reference.
   496  func (d *Driver) SetVector(x, y, z, psi float32) error {
   497  	d.cmdMutex.Lock()
   498  	defer d.cmdMutex.Unlock()
   499  
   500  	d.ry = x
   501  	d.rx = y
   502  	d.ly = z
   503  	d.lx = psi
   504  
   505  	return nil
   506  }
   507  
   508  // SetX sets the x component of the current motion vector
   509  // Pass values from 0 to 1.
   510  // See Vector() for the frame of reference.
   511  func (d *Driver) SetX(x float32) error {
   512  	d.cmdMutex.Lock()
   513  	defer d.cmdMutex.Unlock()
   514  
   515  	d.ry = x
   516  
   517  	return nil
   518  }
   519  
   520  // SetY sets the y component of the current motion vector
   521  // Pass values from 0 to 1.
   522  // See Vector() for the frame of reference.
   523  func (d *Driver) SetY(y float32) error {
   524  	d.cmdMutex.Lock()
   525  	defer d.cmdMutex.Unlock()
   526  
   527  	d.rx = y
   528  
   529  	return nil
   530  }
   531  
   532  // SetZ sets the z component of the current motion vector
   533  // Pass values from 0 to 1.
   534  // See Vector() for the frame of reference.
   535  func (d *Driver) SetZ(z float32) error {
   536  	d.cmdMutex.Lock()
   537  	defer d.cmdMutex.Unlock()
   538  
   539  	d.ly = z
   540  
   541  	return nil
   542  }
   543  
   544  // SetPsi sets the psi component (yaw) of the current motion vector
   545  // Pass values from 0 to 1.
   546  // See Vector() for the frame of reference.
   547  func (d *Driver) SetPsi(psi float32) error {
   548  	d.cmdMutex.Lock()
   549  	defer d.cmdMutex.Unlock()
   550  
   551  	d.lx = psi
   552  
   553  	return nil
   554  }
   555  
   556  // Up tells the drone to ascend. Pass in an int from 0-100.
   557  func (d *Driver) Up(val int) error {
   558  	d.cmdMutex.Lock()
   559  	defer d.cmdMutex.Unlock()
   560  
   561  	d.ly = float32(val) / 100.0
   562  	return nil
   563  }
   564  
   565  // Down tells the drone to descend. Pass in an int from 0-100.
   566  func (d *Driver) Down(val int) error {
   567  	d.cmdMutex.Lock()
   568  	defer d.cmdMutex.Unlock()
   569  
   570  	d.ly = float32(val) / 100.0 * -1
   571  	return nil
   572  }
   573  
   574  // Forward tells the drone to go forward. Pass in an int from 0-100.
   575  func (d *Driver) Forward(val int) error {
   576  	d.cmdMutex.Lock()
   577  	defer d.cmdMutex.Unlock()
   578  
   579  	d.ry = float32(val) / 100.0
   580  	return nil
   581  }
   582  
   583  // Backward tells drone to go in reverse. Pass in an int from 0-100.
   584  func (d *Driver) Backward(val int) error {
   585  	d.cmdMutex.Lock()
   586  	defer d.cmdMutex.Unlock()
   587  
   588  	d.ry = float32(val) / 100.0 * -1
   589  	return nil
   590  }
   591  
   592  // Right tells drone to go right. Pass in an int from 0-100.
   593  func (d *Driver) Right(val int) error {
   594  	d.cmdMutex.Lock()
   595  	defer d.cmdMutex.Unlock()
   596  
   597  	d.rx = float32(val) / 100.0
   598  	return nil
   599  }
   600  
   601  // Left tells drone to go left. Pass in an int from 0-100.
   602  func (d *Driver) Left(val int) error {
   603  	d.cmdMutex.Lock()
   604  	defer d.cmdMutex.Unlock()
   605  
   606  	d.rx = float32(val) / 100.0 * -1
   607  	return nil
   608  }
   609  
   610  // Clockwise tells drone to rotate in a clockwise direction. Pass in an int from 0-100.
   611  func (d *Driver) Clockwise(val int) error {
   612  	d.cmdMutex.Lock()
   613  	defer d.cmdMutex.Unlock()
   614  
   615  	d.lx = float32(val) / 100.0
   616  	return nil
   617  }
   618  
   619  // CounterClockwise tells drone to rotate in a counter-clockwise direction.
   620  // Pass in an int from 0-100.
   621  func (d *Driver) CounterClockwise(val int) error {
   622  	d.cmdMutex.Lock()
   623  	defer d.cmdMutex.Unlock()
   624  
   625  	d.lx = float32(val) / 100.0 * -1
   626  	return nil
   627  }
   628  
   629  // Hover tells the drone to stop moving on the X, Y, and Z axes and stay in place
   630  func (d *Driver) Hover() {
   631  	d.cmdMutex.Lock()
   632  	defer d.cmdMutex.Unlock()
   633  
   634  	d.rx = float32(0)
   635  	d.ry = float32(0)
   636  	d.lx = float32(0)
   637  	d.ly = float32(0)
   638  }
   639  
   640  // CeaseRotation stops any rotational motion
   641  func (d *Driver) CeaseRotation() {
   642  	d.cmdMutex.Lock()
   643  	defer d.cmdMutex.Unlock()
   644  
   645  	d.lx = float32(0)
   646  }
   647  
   648  // Bounce tells drone to start/stop performing the bouncing action
   649  func (d *Driver) Bounce() (err error) {
   650  	buf, _ := d.createPacket(bounceCommand, 0x68, 1)
   651  	d.seq++
   652  	binary.Write(buf, binary.LittleEndian, d.seq)
   653  	if d.bouncing {
   654  		binary.Write(buf, binary.LittleEndian, byte(0x31))
   655  	} else {
   656  		binary.Write(buf, binary.LittleEndian, byte(0x30))
   657  	}
   658  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   659  	_, err = d.cmdConn.Write(buf.Bytes())
   660  	d.bouncing = !d.bouncing
   661  	return
   662  }
   663  
   664  // Flip tells drone to flip
   665  func (d *Driver) Flip(direction FlipType) (err error) {
   666  	buf, _ := d.createPacket(flipCommand, 0x70, 1)
   667  	d.seq++
   668  	binary.Write(buf, binary.LittleEndian, d.seq)
   669  	binary.Write(buf, binary.LittleEndian, byte(direction))
   670  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   671  
   672  	_, err = d.cmdConn.Write(buf.Bytes())
   673  	return
   674  }
   675  
   676  // FrontFlip tells the drone to perform a front flip.
   677  func (d *Driver) FrontFlip() (err error) {
   678  	return d.Flip(FlipFront)
   679  }
   680  
   681  // BackFlip tells the drone to perform a back flip.
   682  func (d *Driver) BackFlip() (err error) {
   683  	return d.Flip(FlipBack)
   684  }
   685  
   686  // RightFlip tells the drone to perform a flip to the right.
   687  func (d *Driver) RightFlip() (err error) {
   688  	return d.Flip(FlipRight)
   689  }
   690  
   691  // LeftFlip tells the drone to perform a flip to the left.
   692  func (d *Driver) LeftFlip() (err error) {
   693  	return d.Flip(FlipLeft)
   694  }
   695  
   696  // ParseFlightData from drone
   697  func (d *Driver) ParseFlightData(b []byte) (fd *FlightData, err error) {
   698  	buf := bytes.NewReader(b)
   699  	fd = &FlightData{}
   700  	var data byte
   701  
   702  	if buf.Len() < 24 {
   703  		err = errors.New("Invalid buffer length for flight data packet")
   704  		fmt.Println(err)
   705  		return
   706  	}
   707  
   708  	err = binary.Read(buf, binary.LittleEndian, &fd.Height)
   709  	if err != nil {
   710  		return
   711  	}
   712  	err = binary.Read(buf, binary.LittleEndian, &fd.NorthSpeed)
   713  	if err != nil {
   714  		return
   715  	}
   716  	err = binary.Read(buf, binary.LittleEndian, &fd.EastSpeed)
   717  	if err != nil {
   718  		return
   719  	}
   720  	err = binary.Read(buf, binary.LittleEndian, &fd.VerticalSpeed)
   721  	if err != nil {
   722  		return
   723  	}
   724  	err = binary.Read(buf, binary.LittleEndian, &fd.FlyTime)
   725  	if err != nil {
   726  		return
   727  	}
   728  
   729  	err = binary.Read(buf, binary.LittleEndian, &data)
   730  	if err != nil {
   731  		return
   732  	}
   733  	fd.ImuState = (data >> 0 & 0x1) == 1
   734  	fd.PressureState = (data >> 1 & 0x1) == 1
   735  	fd.DownVisualState = (data >> 2 & 0x1) == 1
   736  	fd.PowerState = (data >> 3 & 0x1) == 1
   737  	fd.BatteryState = (data >> 4 & 0x1) == 1
   738  	fd.GravityState = (data >> 5 & 0x1) == 1
   739  	fd.WindState = (data >> 7 & 0x1) == 1
   740  
   741  	err = binary.Read(buf, binary.LittleEndian, &fd.ImuCalibrationState)
   742  	if err != nil {
   743  		return
   744  	}
   745  	err = binary.Read(buf, binary.LittleEndian, &fd.BatteryPercentage)
   746  	if err != nil {
   747  		return
   748  	}
   749  	err = binary.Read(buf, binary.LittleEndian, &fd.DroneFlyTimeLeft)
   750  	if err != nil {
   751  		return
   752  	}
   753  	err = binary.Read(buf, binary.LittleEndian, &fd.DroneBatteryLeft)
   754  	if err != nil {
   755  		return
   756  	}
   757  
   758  	err = binary.Read(buf, binary.LittleEndian, &data)
   759  	if err != nil {
   760  		return
   761  	}
   762  	fd.Flying = (data >> 0 & 0x1) == 1
   763  	fd.OnGround = (data >> 1 & 0x1) == 1
   764  	fd.EmOpen = (data >> 2 & 0x1) == 1
   765  	fd.DroneHover = (data >> 3 & 0x1) == 1
   766  	fd.OutageRecording = (data >> 4 & 0x1) == 1
   767  	fd.BatteryLow = (data >> 5 & 0x1) == 1
   768  	fd.BatteryLower = (data >> 6 & 0x1) == 1
   769  	fd.FactoryMode = (data >> 7 & 0x1) == 1
   770  
   771  	err = binary.Read(buf, binary.LittleEndian, &fd.FlyMode)
   772  	if err != nil {
   773  		return
   774  	}
   775  	err = binary.Read(buf, binary.LittleEndian, &fd.ThrowFlyTimer)
   776  	if err != nil {
   777  		return
   778  	}
   779  	err = binary.Read(buf, binary.LittleEndian, &fd.CameraState)
   780  	if err != nil {
   781  		return
   782  	}
   783  
   784  	err = binary.Read(buf, binary.LittleEndian, &data)
   785  	if err != nil {
   786  		return
   787  	}
   788  	fd.ElectricalMachineryState = int16(data & 0xff)
   789  
   790  	err = binary.Read(buf, binary.LittleEndian, &data)
   791  	if err != nil {
   792  		return
   793  	}
   794  	fd.FrontIn = (data >> 0 & 0x1) == 1
   795  	fd.FrontOut = (data >> 1 & 0x1) == 1
   796  	fd.FrontLSC = (data >> 2 & 0x1) == 1
   797  
   798  	err = binary.Read(buf, binary.LittleEndian, &data)
   799  	if err != nil {
   800  		return
   801  	}
   802  	fd.TemperatureHigh = (data >> 0 & 0x1) == 1
   803  
   804  	return
   805  }
   806  
   807  // SendStickCommand sends the joystick command packet to the drone.
   808  func (d *Driver) SendStickCommand() (err error) {
   809  	d.cmdMutex.Lock()
   810  	defer d.cmdMutex.Unlock()
   811  
   812  	buf, _ := d.createPacket(stickCommand, 0x60, 11)
   813  	binary.Write(buf, binary.LittleEndian, int16(0x00)) // seq = 0
   814  
   815  	// RightX center=1024 left =364 right =-364
   816  	axis1 := int16(660.0*d.rx + 1024.0)
   817  
   818  	// RightY down =364 up =-364
   819  	axis2 := int16(660.0*d.ry + 1024.0)
   820  
   821  	// LeftY down =364 up =-364
   822  	axis3 := int16(660.0*d.ly + 1024.0)
   823  
   824  	// LeftX left =364 right =-364
   825  	axis4 := int16(660.0*d.lx + 1024.0)
   826  
   827  	// speed control
   828  	axis5 := int16(d.throttle)
   829  
   830  	packedAxis := int64(axis1)&0x7FF | int64(axis2&0x7FF)<<11 | 0x7FF&int64(axis3)<<22 | 0x7FF&int64(axis4)<<33 | int64(axis5)<<44
   831  	binary.Write(buf, binary.LittleEndian, byte(0xFF&packedAxis))
   832  	binary.Write(buf, binary.LittleEndian, byte(packedAxis>>8&0xFF))
   833  	binary.Write(buf, binary.LittleEndian, byte(packedAxis>>16&0xFF))
   834  	binary.Write(buf, binary.LittleEndian, byte(packedAxis>>24&0xFF))
   835  	binary.Write(buf, binary.LittleEndian, byte(packedAxis>>32&0xFF))
   836  	binary.Write(buf, binary.LittleEndian, byte(packedAxis>>40&0xFF))
   837  
   838  	now := time.Now()
   839  	binary.Write(buf, binary.LittleEndian, byte(now.Hour()))
   840  	binary.Write(buf, binary.LittleEndian, byte(now.Minute()))
   841  	binary.Write(buf, binary.LittleEndian, byte(now.Second()))
   842  	binary.Write(buf, binary.LittleEndian, byte(now.UnixNano()/int64(time.Millisecond)&0xff))
   843  	binary.Write(buf, binary.LittleEndian, byte(now.UnixNano()/int64(time.Millisecond)>>8))
   844  
   845  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   846  
   847  	_, err = d.cmdConn.Write(buf.Bytes())
   848  
   849  	return
   850  }
   851  
   852  // SendDateTime sends the current date/time to the drone.
   853  func (d *Driver) SendDateTime() (err error) {
   854  	d.cmdMutex.Lock()
   855  	defer d.cmdMutex.Unlock()
   856  
   857  	buf, _ := d.createPacket(timeCommand, 0x50, 11)
   858  	d.seq++
   859  	binary.Write(buf, binary.LittleEndian, d.seq)
   860  
   861  	now := time.Now()
   862  	binary.Write(buf, binary.LittleEndian, byte(0x00))
   863  	binary.Write(buf, binary.LittleEndian, int16(now.Hour()))
   864  	binary.Write(buf, binary.LittleEndian, int16(now.Minute()))
   865  	binary.Write(buf, binary.LittleEndian, int16(now.Second()))
   866  	binary.Write(buf, binary.LittleEndian, int16(now.UnixNano()/int64(time.Millisecond)&0xff))
   867  	binary.Write(buf, binary.LittleEndian, int16(now.UnixNano()/int64(time.Millisecond)>>8))
   868  
   869  	binary.Write(buf, binary.LittleEndian, CalculateCRC16(buf.Bytes()))
   870  
   871  	_, err = d.cmdConn.Write(buf.Bytes())
   872  	return
   873  }
   874  
   875  // SendCommand is used to send a text command such as the initial connection request to the drone.
   876  func (d *Driver) SendCommand(cmd string) (err error) {
   877  	_, err = d.cmdConn.Write([]byte(cmd))
   878  	return
   879  }
   880  
   881  func (d *Driver) handleResponse(r io.Reader) error {
   882  	var buf [2048]byte
   883  	var msgType uint16
   884  	n, err := r.Read(buf[0:])
   885  	if err != nil {
   886  		return err
   887  	}
   888  
   889  	// parse binary packet
   890  	if buf[0] == messageStart {
   891  		msgType = (uint16(buf[6]) << 8) | uint16(buf[5])
   892  		switch msgType {
   893  		case wifiMessage:
   894  			buf := bytes.NewReader(buf[9:10])
   895  			wd := &WifiData{}
   896  			binary.Read(buf, binary.LittleEndian, &wd.Strength)
   897  			binary.Read(buf, binary.LittleEndian, &wd.Disturb)
   898  			d.Publish(d.Event(WifiDataEvent), wd)
   899  		case lightMessage:
   900  			buf := bytes.NewReader(buf[9:9])
   901  			var ld int8
   902  			binary.Read(buf, binary.LittleEndian, &ld)
   903  			d.Publish(d.Event(LightStrengthEvent), ld)
   904  		case logMessage:
   905  			d.Publish(d.Event(LogEvent), buf[9:])
   906  		case timeCommand:
   907  			d.Publish(d.Event(TimeEvent), buf[7:8])
   908  		case bounceCommand:
   909  			d.Publish(d.Event(BounceEvent), buf[7:8])
   910  		case takeoffCommand:
   911  			d.Publish(d.Event(TakeoffEvent), buf[7:8])
   912  		case landCommand:
   913  			d.Publish(d.Event(LandingEvent), buf[7:8])
   914  		case palmLandCommand:
   915  			d.Publish(d.Event(PalmLandingEvent), buf[7:8])
   916  		case flipCommand:
   917  			d.Publish(d.Event(FlipEvent), buf[7:8])
   918  		case flightMessage:
   919  			fd, _ := d.ParseFlightData(buf[9:])
   920  			d.Publish(d.Event(FlightDataEvent), fd)
   921  		case exposureCommand:
   922  			d.Publish(d.Event(SetExposureEvent), buf[7:8])
   923  		case videoEncoderRateCommand:
   924  			d.Publish(d.Event(SetVideoEncoderRateEvent), buf[7:8])
   925  		default:
   926  			fmt.Printf("Unknown message: %+v\n", buf[0:n])
   927  		}
   928  		return nil
   929  	}
   930  
   931  	// parse text packet
   932  	if buf[0] == 0x63 && buf[1] == 0x6f && buf[2] == 0x6e {
   933  		d.Publish(d.Event(ConnectedEvent), nil)
   934  	}
   935  
   936  	return nil
   937  }
   938  
   939  func (d *Driver) processVideo() error {
   940  	videoPort, err := net.ResolveUDPAddr("udp", ":11111")
   941  	if err != nil {
   942  		return err
   943  	}
   944  	d.videoConn, err = net.ListenUDP("udp", videoPort)
   945  	if err != nil {
   946  		return err
   947  	}
   948  
   949  	go func() {
   950  	videoConnLoop:
   951  		for {
   952  			select {
   953  			case <-d.doneCh:
   954  				break videoConnLoop
   955  			default:
   956  				buf := make([]byte, 2048)
   957  				n, _, err := d.videoConn.ReadFromUDP(buf)
   958  				if err != nil {
   959  					fmt.Println("Error: ", err)
   960  					continue
   961  				}
   962  
   963  				d.Publish(d.Event(VideoFrameEvent), buf[2:n])
   964  			}
   965  		}
   966  	}()
   967  
   968  	return nil
   969  }
   970  
   971  func (d *Driver) createPacket(cmd int16, pktType byte, len int16) (buf *bytes.Buffer, err error) {
   972  	l := len + 11
   973  	buf = &bytes.Buffer{}
   974  
   975  	binary.Write(buf, binary.LittleEndian, byte(messageStart))
   976  	binary.Write(buf, binary.LittleEndian, l<<3)
   977  	binary.Write(buf, binary.LittleEndian, CalculateCRC8(buf.Bytes()[0:3]))
   978  	binary.Write(buf, binary.LittleEndian, pktType)
   979  	binary.Write(buf, binary.LittleEndian, cmd)
   980  
   981  	return buf, nil
   982  }
   983  
   984  func (d *Driver) connectionString() string {
   985  	x, _ := strconv.Atoi(d.videoPort)
   986  	b := [2]byte{}
   987  	binary.LittleEndian.PutUint16(b[:], uint16(x))
   988  	res := fmt.Sprintf("conn_req:%s", b)
   989  	return res
   990  }
   991  
   992  func (f *FlightData) AirSpeed() float64 {
   993  	return math.Sqrt(
   994  		math.Pow(float64(f.NorthSpeed), 2) +
   995  			math.Pow(float64(f.EastSpeed), 2) +
   996  			math.Pow(float64(f.VerticalSpeed), 2))
   997  }
   998  
   999  func (f *FlightData) GroundSpeed() float64 {
  1000  	return math.Sqrt(
  1001  		math.Pow(float64(f.NorthSpeed), 2) +
  1002  			math.Pow(float64(f.EastSpeed), 2))
  1003  }