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