Module: Tello::Client

Defined in:
lib/tello/client.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#connectedObject

Returns the value of attribute connected.



7
8
9
# File 'lib/tello/client.rb', line 7

def connected
  @connected
end

#ipObject

Returns the value of attribute ip.



7
8
9
# File 'lib/tello/client.rb', line 7

def ip
  @ip
end

#pingObject

Returns the value of attribute ping.



7
8
9
# File 'lib/tello/client.rb', line 7

def ping
  @ping
end

#portObject

Returns the value of attribute port.



7
8
9
# File 'lib/tello/client.rb', line 7

def port
  @port
end

#stateObject

Returns the value of attribute state.



7
8
9
# File 'lib/tello/client.rb', line 7

def state
  @state
end

Class Method Details

.connect(ssid = nil, ip = nil, bind_port = 8890) ⇒ Object

Create a UDP connection



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/tello/client.rb', line 12

def connect(ssid = nil, ip = nil, bind_port=8890)

  # Connect to Tello wifi
  if ssid.to_s.upcase == 'AP'
    unless valid_ipv4?(ip)
      puts "Error: Cannot connect to Tello#{$edu} in AP mode due to invalid IPv4: '#{ip}'"
      return false
    end
  else
    if !Tello::Wifi.connect(ssid)
      puts "Error: Could not connect to Tello#{$edu} 😢"
      return false
    end
    ip = '192.168.10.1'
  end

  # If already connected, disconnect
  if @connected
    puts "Reconnecting..."
    disconnect
  end

  p({ssid: ssid, ip: ip})

  # Set IP and port numbers
  @ip = (Tello.testing ? 'localhost' : ip)
  @port = 8889

  # Create UDP client, bind to a previous source IP and port if availble
  @client = UDPSocket.new unless @client
  if @source_ip && @source_port
    p({source_ip: @source_ip, source_port: @source_port})
    @client.bind(@source_ip, @source_port)
  end

  # Connect to destination, save IP and port assigned by the OS
  @client.connect(@ip, @port)
  @source_ip = @client.addr[3]
  @source_port = @client.addr[1]

  # Create server to get Tello state
  unless @state_server
    @state_server = UDPSocket.new
    @state_server.bind('0.0.0.0', bind_port)
  end

  # Check to see if test server is up
  if Tello.testing
    print "Connecting to test server..."
    @client.send('command', 0)
    sleep 0.5
    unless read_nonblock
      puts "\n#{'Error:'.error} Could not find Tello#{$edu} test server.",
            "Did you run `tello#{$edu.to_s.downcase} server` in another terminal window?"
      return false
    end
    puts "connected!"
  end

  # Tello should be connected over wifi and UDP
  @connected = true

  # Threads for real Tello connection only
  unless Tello.testing
    # Create thread to keep Tello alive (must recieve command every 15 sec)
    if @ping then @ping.exit end
    @ping = Thread.new do
      loop do
        begin
          @client.send('command', 0)
        rescue Errno::EADDRNOTAVAIL
          puts "#{'Error:'.error} No response from Tello#{$edu}! Try reconnecting."
          @ping.exit
        end
        sleep(14.5)
      end
    end

    # Get Tello state
    if @state then @state.exit end
    @state = Thread.new do
      loop do
        Tello.store_state(@state_server.recv(256))
      end
    end
  end

  puts "Ready to fly! 🚁"
  true
end

.connected?Boolean

Get Tello connection status



104
105
106
107
108
109
110
111
# File 'lib/tello/client.rb', line 104

def connected?
  if @connected
    true
  else
    puts "Tello#{$edu} is not yet connected. Run `connect` first."
    false
  end
end

.disconnectObject

Disconnect the Tello



114
115
116
117
118
119
120
121
122
123
124
# File 'lib/tello/client.rb', line 114

def disconnect
  return false unless @connected
  unless Tello.testing
    @state.exit
    @ping.exit
  end
  @client.close
  @client = nil
  @connected = false
  true
end

.read_nonblockObject

Read the UDP response without blocking



127
128
129
130
131
132
133
134
135
136
# File 'lib/tello/client.rb', line 127

def read_nonblock
  begin
    res = @client.recv_nonblock(256)
  rescue IO::WaitReadable
    res = nil
  rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL
    puts "#{'Error:'.error} Cannot communicate with Tello!"
    @connected
  end
end

.return_bool(res) ⇒ Object

Change ‘ok’ and ‘error’ to boolean response instead



147
148
149
150
151
152
153
154
# File 'lib/tello/client.rb', line 147

def return_bool(res)
  case res
  when 'ok'
    true
  when 'error'
    false
  end
end

.return_num(res) ⇒ Object

Change string to number response instead



157
158
159
# File 'lib/tello/client.rb', line 157

def return_num(res)
  if res then res.to_i else res end
end

.send(cmd) ⇒ Object

Send a native Tello command string



139
140
141
142
143
144
# File 'lib/tello/client.rb', line 139

def send(cmd)
  return false unless connected?
  while read_nonblock do end  # flush previous response data
  @client.send(cmd, 0)
  @client.recv(256).strip
end

.valid_ipv4?(ip) ⇒ Boolean



161
162
163
164
# File 'lib/tello/client.rb', line 161

def valid_ipv4?(ip)
  ## May be improved further
  (ip.to_s) =~ /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/
end