crubyflie 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +674 -0
- data/README.md +99 -0
- data/Rakefile +15 -0
- data/bin/crubyflie +85 -0
- data/configs/joystick_default.yaml +48 -0
- data/crubyflie.gemspec +50 -0
- data/examples/params_and_logging.rb +87 -0
- data/lib/crubyflie/crazyflie/commander.rb +54 -0
- data/lib/crubyflie/crazyflie/console.rb +67 -0
- data/lib/crubyflie/crazyflie/log.rb +383 -0
- data/lib/crubyflie/crazyflie/log_conf.rb +57 -0
- data/lib/crubyflie/crazyflie/param.rb +220 -0
- data/lib/crubyflie/crazyflie/toc.rb +239 -0
- data/lib/crubyflie/crazyflie/toc_cache.rb +87 -0
- data/lib/crubyflie/crazyflie.rb +282 -0
- data/lib/crubyflie/crazyradio/crazyradio.rb +301 -0
- data/lib/crubyflie/crazyradio/radio_ack.rb +48 -0
- data/lib/crubyflie/crubyflie_logger.rb +74 -0
- data/lib/crubyflie/driver/crtp_packet.rb +146 -0
- data/lib/crubyflie/driver/radio_driver.rb +333 -0
- data/lib/crubyflie/exceptions.rb +36 -0
- data/lib/crubyflie/input/input_reader.rb +168 -0
- data/lib/crubyflie/input/joystick_input_reader.rb +280 -0
- data/lib/crubyflie/version.rb +22 -0
- data/lib/crubyflie.rb +31 -0
- data/spec/commander_spec.rb +67 -0
- data/spec/console_spec.rb +76 -0
- data/spec/crazyflie_spec.rb +176 -0
- data/spec/crazyradio_spec.rb +226 -0
- data/spec/crtp_packet_spec.rb +79 -0
- data/spec/crubyflie_logger_spec.rb +39 -0
- data/spec/crubyflie_spec.rb +20 -0
- data/spec/input_reader_spec.rb +136 -0
- data/spec/joystick_cfg.yaml +48 -0
- data/spec/joystick_input_reader_spec.rb +238 -0
- data/spec/log_spec.rb +266 -0
- data/spec/param_spec.rb +166 -0
- data/spec/radio_ack_spec.rb +43 -0
- data/spec/radio_driver_spec.rb +227 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/toc_cache_spec.rb +87 -0
- data/spec/toc_spec.rb +187 -0
- data/tools/sdl-joystick-axis.rb +69 -0
- metadata +222 -0
@@ -0,0 +1,333 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
|
20
|
+
require 'thread'
|
21
|
+
require 'uri'
|
22
|
+
|
23
|
+
require 'exceptions'
|
24
|
+
require 'driver/crtp_packet'
|
25
|
+
require 'crazyradio/crazyradio'
|
26
|
+
|
27
|
+
module Crubyflie
|
28
|
+
# This layer takes care of connecting to the crazyradio and
|
29
|
+
# managing the incoming and outgoing queues. This is done
|
30
|
+
# by spawing a thread.
|
31
|
+
# It also provides the interface to scan for available crazyflies
|
32
|
+
# to which connect
|
33
|
+
class RadioDriver
|
34
|
+
# Currently used callbacks that can be passed to connect()
|
35
|
+
CALLBACKS = [:link_quality_cb,
|
36
|
+
:link_error_cb]
|
37
|
+
# Default size for the outgoing queue
|
38
|
+
OUT_QUEUE_MAX_SIZE = 50
|
39
|
+
# Default number of retries before disconnecting
|
40
|
+
RETRIES_BEFORE_DISCONNECT = 20
|
41
|
+
|
42
|
+
attr_reader :uri
|
43
|
+
attr_reader :retries_before_disconnect, :out_queue_max_size
|
44
|
+
|
45
|
+
# Initialize the driver. Creates new empty queues.
|
46
|
+
def initialize()
|
47
|
+
@uri = nil
|
48
|
+
@in_queue = Queue.new()
|
49
|
+
@out_queue = Queue.new()
|
50
|
+
Thread.abort_on_exception = true
|
51
|
+
@radio_thread = nil
|
52
|
+
@callbacks = {}
|
53
|
+
@crazyradio = nil
|
54
|
+
@out_queue_max_size = nil
|
55
|
+
@retries_before_disconnect = nil
|
56
|
+
@shutdown_thread = false
|
57
|
+
end
|
58
|
+
|
59
|
+
# Connect to a Crazyflie in the specified URI
|
60
|
+
# @param uri_s [String] a radio uri like radio://<dongle>/<ch>/<rate>
|
61
|
+
# @param callbacks [Hash] blocks to call (see CALLBACKS contant values)
|
62
|
+
# @param opts [Hash] options. Currently supported
|
63
|
+
# :retries_before_disconnect (defaults to 20) and
|
64
|
+
# :out_queue_max_size (defaults to 50)
|
65
|
+
# @raise [CallbackMissing] when a necessary callback is not provided
|
66
|
+
# (see CALLBACKS constant values)
|
67
|
+
# @raise [InvalidURIType] when the URI is not a valid radio URI
|
68
|
+
# @raise [OpenLink] when a link is already open
|
69
|
+
def connect(uri_s, callbacks={}, opts={})
|
70
|
+
# Check if apparently there is an open link
|
71
|
+
|
72
|
+
if @crazyradio
|
73
|
+
m = "Active link to #{@uri.to_s}. Disconnect first"
|
74
|
+
raise OpenLink.new(m)
|
75
|
+
end
|
76
|
+
|
77
|
+
# Parse URI to initialize Crazyradio
|
78
|
+
# @todo: better control input. It defaults to 0
|
79
|
+
@uri = URI(uri_s)
|
80
|
+
dongle_number = @uri.host.to_i
|
81
|
+
channel, rate = @uri.path.split('/')[1..-1] # remove leading /
|
82
|
+
channel = channel.to_i
|
83
|
+
# @todo this should be taken care of in crazyradio
|
84
|
+
|
85
|
+
case rate
|
86
|
+
when "250K"
|
87
|
+
rate = CrazyradioConstants::DR_250KPS
|
88
|
+
when "1M"
|
89
|
+
rate = CrazyradioConstants::DR_1MPS
|
90
|
+
when "2M"
|
91
|
+
rate = CrazyradioConstants::DR_2MPS
|
92
|
+
else
|
93
|
+
raise InvalidURIType.new("Bad radio rate")
|
94
|
+
end
|
95
|
+
|
96
|
+
# Fill in the callbacks Hash
|
97
|
+
CALLBACKS.each do |cb|
|
98
|
+
if passed_cb = callbacks[cb]
|
99
|
+
@callbacks[cb] = passed_cb
|
100
|
+
else
|
101
|
+
raise CallbackMissing.new("Callback #{cb} mandatory")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@retries_before_disconnect = opts[:retries_before_disconnect] ||
|
106
|
+
RETRIES_BEFORE_DISCONNECT
|
107
|
+
@out_queue_max_size = opts[:out_queue_max_size] ||
|
108
|
+
OUT_QUEUE_MAX_SIZE
|
109
|
+
|
110
|
+
# Initialize Crazyradio and run thread
|
111
|
+
cradio_opts = {
|
112
|
+
:channel => channel,
|
113
|
+
:data_rate => rate
|
114
|
+
}
|
115
|
+
@crazyradio = Crazyradio.factory(cradio_opts)
|
116
|
+
start_radio_thread()
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
# Disconnects from the crazyradio
|
121
|
+
# @param force [TrueClass, FalseClass]. Kill the thread right away, or
|
122
|
+
# wait for out_queue to empty
|
123
|
+
def disconnect(force=nil)
|
124
|
+
kill_radio_thread(force)
|
125
|
+
@in_queue.clear()
|
126
|
+
@out_queue.clear()
|
127
|
+
|
128
|
+
return if !@crazyradio
|
129
|
+
@crazyradio.close()
|
130
|
+
@crazyradio = nil
|
131
|
+
end
|
132
|
+
|
133
|
+
# Place a packet in the outgoing queue
|
134
|
+
# When not connected it will do nothing
|
135
|
+
# @param packet [CRTPPacket] The packet to send
|
136
|
+
def send_packet(packet)
|
137
|
+
return if !@crazyradio
|
138
|
+
if (s = @out_queue.size) >= @out_queue_max_size
|
139
|
+
m = "Reached #{s} elements in outgoing queue"
|
140
|
+
@callbacks[:link_error_cb].call(m)
|
141
|
+
disconnect()
|
142
|
+
end
|
143
|
+
|
144
|
+
@out_queue << packet if !@shutdown_thread
|
145
|
+
end
|
146
|
+
|
147
|
+
# Fetch a packet from the incoming queue
|
148
|
+
# @return [CRTPPacket,nil] a packet from the queue,
|
149
|
+
# or nil when there is none
|
150
|
+
def receive_packet(non_block=true)
|
151
|
+
begin
|
152
|
+
return @in_queue.pop(non_block)
|
153
|
+
rescue ThreadError
|
154
|
+
return nil
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# List available Crazyflies in the provided channels
|
159
|
+
# @param start [Integer] channel to start
|
160
|
+
# @param stop [Intenger] channel to stop
|
161
|
+
# @return [Array] list of channels where a Crazyflie was found
|
162
|
+
def scan_radio_channels(start = 0, stop = 125)
|
163
|
+
return @crazyradio.scan_channels(start, stop)
|
164
|
+
end
|
165
|
+
private :scan_radio_channels
|
166
|
+
|
167
|
+
# List available Crazyflies
|
168
|
+
# @return [Array] List of radio URIs where a crazyflie was found
|
169
|
+
# @raise [OpenLink] if the Crazyradio is connected already
|
170
|
+
def scan_interface
|
171
|
+
raise OpenLink.new("Cannot scan when link is open") if @crazyradio
|
172
|
+
begin
|
173
|
+
@crazyradio = Crazyradio.factory()
|
174
|
+
results = {}
|
175
|
+
@crazyradio[:arc] = 1
|
176
|
+
@crazyradio[:data_rate] = Crazyradio::DR_250KPS
|
177
|
+
results["250K"] = scan_radio_channels()
|
178
|
+
@crazyradio[:data_rate] = Crazyradio::DR_1MPS
|
179
|
+
results["1M"] = scan_radio_channels()
|
180
|
+
@crazyradio[:data_rate] = Crazyradio::DR_2MPS
|
181
|
+
results["2M"] = scan_radio_channels()
|
182
|
+
|
183
|
+
uris = []
|
184
|
+
results.each do |rate, channels|
|
185
|
+
channels.each do |ch|
|
186
|
+
uris << "radio://0/#{ch}/#{rate}"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
return uris
|
190
|
+
rescue USBDongleException
|
191
|
+
raise
|
192
|
+
rescue Exception
|
193
|
+
retries ||= 0
|
194
|
+
logger.error("Unknown error scanning interface: #{$!}")
|
195
|
+
@crazyradio.reopen()
|
196
|
+
retries += 1
|
197
|
+
if retries < 2
|
198
|
+
logger.error("Retrying")
|
199
|
+
sleep 0.5
|
200
|
+
retry
|
201
|
+
end
|
202
|
+
return []
|
203
|
+
ensure
|
204
|
+
@crazyradio.close() if @crazyradio
|
205
|
+
@crazyradio = nil
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
# Get status from the crazyradio. @see Crazyradio#status
|
211
|
+
def get_status
|
212
|
+
return Crazyradio.status()
|
213
|
+
end
|
214
|
+
|
215
|
+
|
216
|
+
# Privates
|
217
|
+
# The body of the communication thread
|
218
|
+
# Sends packets and tries to read the ACK
|
219
|
+
# @todo it is long and ugly
|
220
|
+
# @todo why the heck do we care here if we need to wait? Should the
|
221
|
+
# crazyradio do the waiting?
|
222
|
+
def start_radio_thread
|
223
|
+
@radio_thread = Thread.new do
|
224
|
+
Thread.current.priority = 5
|
225
|
+
out_data = [0xFF]
|
226
|
+
retries = @retries_before_disconnect
|
227
|
+
should_sleep = 0
|
228
|
+
error = "Unknown"
|
229
|
+
while true do
|
230
|
+
begin
|
231
|
+
ack = @crazyradio.send_packet(out_data)
|
232
|
+
# possible outcomes
|
233
|
+
# -exception - no usb dongle?
|
234
|
+
# -nil - bad comm
|
235
|
+
# -AckStatus class
|
236
|
+
rescue Exception
|
237
|
+
error = "Error talking to Crazyradio: #{$!.to_s}"
|
238
|
+
break
|
239
|
+
end
|
240
|
+
|
241
|
+
if ack.nil?
|
242
|
+
error = "Dongle communication error (ack is nil)"
|
243
|
+
break
|
244
|
+
end
|
245
|
+
|
246
|
+
# Set this in function of the retries
|
247
|
+
quality = (10 - ack.retry_count) * 10
|
248
|
+
@callbacks[:link_quality_cb].call(quality)
|
249
|
+
|
250
|
+
# Retry if we have not reached the limit
|
251
|
+
if !ack.ack
|
252
|
+
retries -= 1
|
253
|
+
next if retries > 0
|
254
|
+
error = "Too many packets lost"
|
255
|
+
break
|
256
|
+
else
|
257
|
+
retries = @retries_before_disconnect
|
258
|
+
end
|
259
|
+
|
260
|
+
# If there is data we queue it in incoming
|
261
|
+
# Otherwise we increase should_sleep
|
262
|
+
# If there is no data for more than 10 times
|
263
|
+
# we will sleep 0.01s when our outgoing queue
|
264
|
+
# is empty. Otherwise, we just send what we have
|
265
|
+
# of the 0xFF packet
|
266
|
+
data = ack.data
|
267
|
+
if data.length > 0
|
268
|
+
@in_queue << CRTPPacket.unpack(data)
|
269
|
+
should_sleep = 0
|
270
|
+
else
|
271
|
+
should_sleep += 1
|
272
|
+
end
|
273
|
+
|
274
|
+
break if @shutdown_thread && @out_queue.empty?()
|
275
|
+
|
276
|
+
begin
|
277
|
+
out_packet = @out_queue.pop(true) # non-block
|
278
|
+
should_sleep += 1
|
279
|
+
rescue ThreadError
|
280
|
+
out_packet = CRTPPacket.new(0xFF)
|
281
|
+
sleep 0.01 if should_sleep >= 10
|
282
|
+
end
|
283
|
+
|
284
|
+
out_data = out_packet.pack
|
285
|
+
end
|
286
|
+
if !@shutdown_thread
|
287
|
+
# If we reach here it means we are dying because of
|
288
|
+
# an error. The callback will likely call disconnect, which
|
289
|
+
# tries to kills us, but cannot because we are running the
|
290
|
+
# callback. Therefore we set @radio_thread to nil and then
|
291
|
+
# run the callback.
|
292
|
+
@radio_thread = nil
|
293
|
+
@callbacks[:link_error_cb].call(error)
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
private :start_radio_thread
|
298
|
+
|
299
|
+
def kill_radio_thread(force=false)
|
300
|
+
if @radio_thread
|
301
|
+
if force
|
302
|
+
@radio_thread.kill()
|
303
|
+
else
|
304
|
+
@shutdown_thread = true
|
305
|
+
@radio_thread.join()
|
306
|
+
end
|
307
|
+
@radio_thread = nil
|
308
|
+
@shutdown_thread = false
|
309
|
+
end
|
310
|
+
end
|
311
|
+
private :kill_radio_thread
|
312
|
+
|
313
|
+
|
314
|
+
|
315
|
+
# def pause_radio_thread
|
316
|
+
# @radio_thread.stop if @radio_thread
|
317
|
+
# end
|
318
|
+
# private :pause_radio_thread
|
319
|
+
|
320
|
+
|
321
|
+
# def resume_radio_thread
|
322
|
+
# @radio_thread.run if @radio_thread
|
323
|
+
# end
|
324
|
+
# private :resume_radio_thread
|
325
|
+
|
326
|
+
|
327
|
+
# def restart_radio_thread
|
328
|
+
# kill_radio_thread()
|
329
|
+
# start_radio_thread()
|
330
|
+
# end
|
331
|
+
# private :restart_radio_thread
|
332
|
+
end
|
333
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
module Crubyflie
|
20
|
+
# Raised when the radio URI is invalid
|
21
|
+
class InvalidURIType < Exception; end
|
22
|
+
# Raised when an radio link is already open
|
23
|
+
class OpenLink < Exception; end
|
24
|
+
# Raised when a radio driver callback parameter is missing
|
25
|
+
class CallbackMissing < Exception; end
|
26
|
+
# Raised when no USB dongle can be found
|
27
|
+
class NoDongleFound < Exception; end
|
28
|
+
# Raised when a problem occurs with the USB dongle
|
29
|
+
class USBDongleException < Exception; end
|
30
|
+
# Raised when a problem happens in the radio driver communications thread
|
31
|
+
class RadioThreadException < Exception; end
|
32
|
+
# Expected a package but it took to long to get it
|
33
|
+
class WaitTimeoutException < Exception; end
|
34
|
+
# Raised when there is a problem initializing a joystick
|
35
|
+
class JoystickException < Exception; end
|
36
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# Copyright (C) 2013 Hector Sanjuan
|
3
|
+
|
4
|
+
# This file is part of Crubyflie.
|
5
|
+
|
6
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
|
11
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU General Public License for more details.
|
15
|
+
|
16
|
+
# You should have received a copy of the GNU General Public License
|
17
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
18
|
+
|
19
|
+
module Crubyflie
|
20
|
+
|
21
|
+
# This class provides functionality basic to all controllers.
|
22
|
+
# Specific controller classes inherit from here.
|
23
|
+
#
|
24
|
+
# To read an input we must declare axis and buttons.
|
25
|
+
# The axis are analog float readings (range decided by the
|
26
|
+
# controller) while the buttons are integer where <= 0 means not pressed
|
27
|
+
# and > 0 means pressed.
|
28
|
+
#
|
29
|
+
# The reading of the values is implemented by children classes.
|
30
|
+
#
|
31
|
+
# The InputReader will also apply the #INPUT_ACTIONS to a given
|
32
|
+
# Crazyflie. In order to do that it will go through all the
|
33
|
+
# read values and perform actioins associated to them, like sending
|
34
|
+
# a setpoint or shutting down the connection or altering the calibration.
|
35
|
+
class InputReader
|
36
|
+
|
37
|
+
# List of current recognized actions that controllers can declare
|
38
|
+
INPUT_ACTIONS = [:roll, :pitch, :yaw, :thrust,
|
39
|
+
:roll_inc_cal, :roll_dec_cal,
|
40
|
+
:pitch_inc_cal, :pitch_dec_cal,
|
41
|
+
:switch_xmode, :close_link]
|
42
|
+
|
43
|
+
attr_reader :axis, :buttons, :axis_readings, :button_readings
|
44
|
+
attr_accessor :xmode
|
45
|
+
# An input is composed by several necessary axis, buttons and
|
46
|
+
# calibrations.
|
47
|
+
# @param axis [Hash] A hash of keys identifying axis IDs
|
48
|
+
# (the controller should know to what the
|
49
|
+
# ID maps, and values from #INPUT_ACTIONS
|
50
|
+
# @param buttons [Hash] A hash of keys identifying button IDs (the
|
51
|
+
# controller should know to what the ID maps,
|
52
|
+
# and values from #INPUT_ACTIONS
|
53
|
+
def initialize(axis, buttons)
|
54
|
+
@axis = axis
|
55
|
+
@buttons = buttons
|
56
|
+
@calibrations = {}
|
57
|
+
@xmode = false
|
58
|
+
|
59
|
+
# Calibrate defaults to 0
|
60
|
+
INPUT_ACTIONS.each do |action|
|
61
|
+
@calibrations[action] = 0
|
62
|
+
end
|
63
|
+
|
64
|
+
@axis_readings = {}
|
65
|
+
@button_readings = {}
|
66
|
+
end
|
67
|
+
|
68
|
+
# Read inputs will call read_axis() on all the declared axis
|
69
|
+
# and read_button() on all the declared buttons.
|
70
|
+
# After obtaining the reading, it will apply calibrations to
|
71
|
+
# the result. Apply the read values with #apply_input
|
72
|
+
def read_input
|
73
|
+
poll() # In case we need to poll the device
|
74
|
+
actions_to_axis = @axis.invert()
|
75
|
+
actions_to_axis.each do |action, axis_id|
|
76
|
+
@axis_readings[action] = read_axis(axis_id)
|
77
|
+
@axis_readings[action] += @calibrations[action]
|
78
|
+
end
|
79
|
+
|
80
|
+
actions_to_buttons = @buttons.invert()
|
81
|
+
actions_to_buttons.each do |action, button_id|
|
82
|
+
@button_readings[action] = read_button(button_id)
|
83
|
+
@button_readings[action] += @calibrations[action]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# This will act on current axis readings (by sendint a setpoint to
|
88
|
+
# the crazyflie) and on button readings (by, for example, shutting
|
89
|
+
# down the link or modifying the calibrations.
|
90
|
+
# If the link to the crazyflie is down, it will not send anything.
|
91
|
+
# @param crazyflie [Crazyflie] A crazyflie instance to send the
|
92
|
+
# setpoint to.
|
93
|
+
def apply_input(crazyflie)
|
94
|
+
return if !crazyflie.active?
|
95
|
+
setpoint = {
|
96
|
+
:roll => nil,
|
97
|
+
:pitch => nil,
|
98
|
+
:yaw => nil,
|
99
|
+
:thrust => nil
|
100
|
+
}
|
101
|
+
|
102
|
+
@button_readings.each do |action, value|
|
103
|
+
case action
|
104
|
+
when :roll
|
105
|
+
setpoint[:roll] = value
|
106
|
+
when :pitch
|
107
|
+
setpoint[:pitch] = value
|
108
|
+
when :yaw
|
109
|
+
setpoint[:yaw] = value
|
110
|
+
when :thrust
|
111
|
+
setpoint[:thrust] = value
|
112
|
+
when :roll_inc_cal
|
113
|
+
@calibrations[:roll] += 1
|
114
|
+
when :roll_dec_cal
|
115
|
+
@calibrations[:roll] -= 1
|
116
|
+
when :pitch_inc_cal
|
117
|
+
@calibrations[:pitch] += 1
|
118
|
+
when :pitch_dec_cal
|
119
|
+
@calibrations[:pitch] -= 1
|
120
|
+
when :switch_xmode
|
121
|
+
@xmode = !@xmode if value > 0
|
122
|
+
logger.info("Xmode is #{@xmode}") if value > 0
|
123
|
+
when :close_link
|
124
|
+
crazyflie.close_link() if value > 0
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
return if !crazyflie.active?
|
129
|
+
|
130
|
+
@axis_readings.each do |action, value|
|
131
|
+
case action
|
132
|
+
when :roll
|
133
|
+
setpoint[:roll] = value
|
134
|
+
when :pitch
|
135
|
+
setpoint[:pitch] = value
|
136
|
+
when :yaw
|
137
|
+
setpoint[:yaw] = value
|
138
|
+
when :thrust
|
139
|
+
setpoint[:thrust] = value
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
pitch = setpoint[:pitch]
|
144
|
+
roll = setpoint[:roll]
|
145
|
+
yaw = setpoint[:yaw]
|
146
|
+
thrust = setpoint[:thrust]
|
147
|
+
|
148
|
+
if pitch && roll && yaw && thrust
|
149
|
+
m = "Sending R: #{roll} P: #{pitch} Y: #{yaw} T: #{thrust}"
|
150
|
+
#logger.debug(m)
|
151
|
+
crazyflie.commander.send_setpoint(roll, pitch, yaw, thrust,
|
152
|
+
@xmode)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
private
|
157
|
+
def read_axis(axis_id)
|
158
|
+
raise Exception.new("Not implemented!")
|
159
|
+
end
|
160
|
+
|
161
|
+
def read_button(button_id)
|
162
|
+
raise Exception.new("Not implemented!")
|
163
|
+
end
|
164
|
+
|
165
|
+
def poll
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|