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 }