hybridgroup-crubyflie 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +18 -0
- data/.travis.yml +8 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +674 -0
- data/README.md +127 -0
- data/Rakefile +15 -0
- data/bin/crubyflie +94 -0
- data/configs/joystick_default.yaml +106 -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 +363 -0
- data/lib/crubyflie/exceptions.rb +36 -0
- data/lib/crubyflie/input/input_reader.rb +190 -0
- data/lib/crubyflie/input/joystick_input_reader.rb +328 -0
- data/lib/crubyflie/version.rb +22 -0
- data/lib/crubyflie.rb +36 -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 +228 -0
- data/spec/crtp_packet_spec.rb +79 -0
- data/spec/crubyflie_logger_spec.rb +39 -0
- data/spec/crubyflie_spec.rb +21 -0
- data/spec/input_reader_spec.rb +136 -0
- data/spec/joystick_cfg.yaml +44 -0
- data/spec/joystick_input_reader_spec.rb +323 -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 +53 -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 +225 -0
data/README.md
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
Crubyflie - A Ruby client for Crazyflie
|
2
|
+
=======================================
|
3
|
+
|
4
|
+
[![Build Status](https://travis-ci.org/hsanjuan/crubyflie.png?branch=master)](https://travis-ci.org/hsanjuan/crubyflie) [![Coverage Status](https://coveralls.io/repos/hsanjuan/crubyflie/badge.png)](https://coveralls.io/r/hsanjuan/crubyflie)
|
5
|
+
|
6
|
+
Crubyflie is a Ruby rewrite of the [Crazyflie quadcopter](http://www.bitcraze.se/category/crazyflie/) Python [client libraries](https://bitbucket.org/bitcraze/crazyflie-pc-client), with some customizations.
|
7
|
+
|
8
|
+
The Crazyflie is awesome, but I did not know where to start contributing. Therefore I thought that rewriting the code in Ruby would be one way of knowing what is going on and how it works. Along the way I took the time to document all the code so that others can understand it and create tests.
|
9
|
+
|
10
|
+
You may be also interested in some other unofficial Crazyflie clients:
|
11
|
+
|
12
|
+
* C++: https://github.com/fairlight1337/libcflie
|
13
|
+
* Node.js: https://github.com/ceejbot/aerogel
|
14
|
+
* Haskell: https://github.com/orclev/crazyflie-haskell
|
15
|
+
|
16
|
+
Disclaimer
|
17
|
+
----------
|
18
|
+
|
19
|
+
Crubyflie is in early stage of development, very untested.
|
20
|
+
|
21
|
+
Features
|
22
|
+
--------
|
23
|
+
|
24
|
+
* Crubyflie can be used to fly a Crazyflie device using a Joystick and the Crazyradio USB dongle
|
25
|
+
* Crubyflie exposes an API that allows to control the copter, read logging, parameters and console easily
|
26
|
+
* Crubyflie runs headless
|
27
|
+
* Lightweight: If you just want to fly, Crubyflie consumes around 1/2 memory and 1/3 CPU compared to the original Python `cfheadless` utility.
|
28
|
+
|
29
|
+
Not included...
|
30
|
+
----------------
|
31
|
+
* No fancy UI.
|
32
|
+
* No flash utility (yet?).
|
33
|
+
* No idea how this works in other OSs that are not Linux, but in theory it should work in all with some small fixes. I welcome you to take on this task if you are interested.
|
34
|
+
* No support for Ruby <= 1.8.7 (maybe it works who knows... I haven't tested but since Crubyflie relies heavily on threading probably it does not work so good).
|
35
|
+
|
36
|
+
Installation
|
37
|
+
------------
|
38
|
+
|
39
|
+
Crubyflie depends on `rubysdl`, for which you will need the SDL library and headers. Make sure you install `libsdl-dev` (Debian/Ubuntu), `libSDL-devel` (Opensuse) or whatever your distro calls it. Then:
|
40
|
+
|
41
|
+
gem install crubyflie
|
42
|
+
|
43
|
+
That's all.
|
44
|
+
|
45
|
+
Fyling the Crazyflie
|
46
|
+
--------------------
|
47
|
+
|
48
|
+
The easiest way to do it is to `gem install crubyflie` and then run the `crubyflie` command. This will connect to the first visible quadcopter using the first available joystick on your computer (you can modify this parameters with the appropiate flags):
|
49
|
+
|
50
|
+
> crubyflie2.0 -h
|
51
|
+
Options:
|
52
|
+
--joystick-id, -j <i>: Joystick ID (default: 0)
|
53
|
+
--cf-uri, -f <s>: Crazyflie URI (defaults to first one found in scan)
|
54
|
+
--config, -c <s>: Joystick configuration, defaults to default cfg in configs/ (default:
|
55
|
+
/usr/lib64/ruby/gems/2.0.0/gems/crubyflie-0.0.1/lib/crubyflie/input/../../../configs/joystick_default.yaml)
|
56
|
+
--help, -h: Show this message
|
57
|
+
|
58
|
+
There is a [template/default configuration file](https://github.com/hsanjuan/crubyflie/blob/master/configs/joystick_default.yaml) with instructions (which works for me and my PS3-like controller :) ). You should modify this file to fit it to your needs (configuration parameters are commented). The most tricky parameter in axis is the `:max_change_rate`. Depending on your controller, you will find the input is excessively throotled or not. I recommend that you play with this value.
|
59
|
+
|
60
|
+
If you are wondering about your Joystick's axis IDs, ranges etc, you will find a `sdl-joystick-axis.rb` script under `tools` that lets you open a joystick and check what the SDL library can read from it. It might come handy.
|
61
|
+
|
62
|
+
If you need help just open an issue or contact me.
|
63
|
+
|
64
|
+
Raspberry Pi
|
65
|
+
------------
|
66
|
+
|
67
|
+
If you want to use Crubyflie in your Raspberry Pi you need to:
|
68
|
+
|
69
|
+
sudo apt-get install ruby ruby-dev libsdl-dev
|
70
|
+
sudo gem install crubyflie
|
71
|
+
|
72
|
+
This should provide everything you need to run the `crubyflie` command. Of course you might need to put your user in the `input` group and modify `udev` rules as explained in the [Crazyflie wiki](http://wiki.bitcraze.se/projects:crazyflie:hacks:rasberrypi).
|
73
|
+
|
74
|
+
Using the Crazyflie API
|
75
|
+
-----------------------
|
76
|
+
|
77
|
+
While both Python and Ruby APIs expose access to params, logging, console and commander facilities, Crubyflie does it in sligthly different way.
|
78
|
+
|
79
|
+
Crubyflie access to facilities is offered fully under the Crazyflie instance object, let's see it as code:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
require 'crubyflie'
|
83
|
+
include Crubyflie
|
84
|
+
|
85
|
+
# Connect
|
86
|
+
@cf = Crazyflie.new()
|
87
|
+
@cf.open_link(@radio_uri)
|
88
|
+
|
89
|
+
# Interface to the logging facility
|
90
|
+
@cf.log.create_log_block(...)
|
91
|
+
@cf.log.start_logging(...) do |log_values|
|
92
|
+
...
|
93
|
+
end
|
94
|
+
@cf.log.stop_logging(...)
|
95
|
+
@cf.log.delete_log(...)
|
96
|
+
|
97
|
+
|
98
|
+
# Interface to the param facility
|
99
|
+
@cf.param.get_value(...) do |value|
|
100
|
+
...
|
101
|
+
end
|
102
|
+
|
103
|
+
@cf.param.get_value(...) do |value|
|
104
|
+
...
|
105
|
+
end
|
106
|
+
|
107
|
+
@cf.param.set_value(...)
|
108
|
+
|
109
|
+
# Interface to the commander facility
|
110
|
+
@cf.commander.send_setpoint(...)
|
111
|
+
|
112
|
+
# Interface to the console facility
|
113
|
+
@cf.console.read do |value|
|
114
|
+
...
|
115
|
+
end
|
116
|
+
```
|
117
|
+
|
118
|
+
That's pretty much all. As you see, instead of declaring callbacks, registering them etc. We let the user pass blocks, which are run when the data is available.
|
119
|
+
In Crubyflie, params are read and set synchronously, while the block passed to `start_logging()` will be called repeteadly and asynchrnously until `stop_logging()` is invoked. Console offers both synchronous `read()` and asynchronous `start_reading()` options.
|
120
|
+
|
121
|
+
There are some examples in the `examples` folder. Read the gem documentation to get full information of the parameters for each function call.
|
122
|
+
|
123
|
+
|
124
|
+
Contributing
|
125
|
+
------------
|
126
|
+
|
127
|
+
Contributions are awesome! :) I'd love some help here, so be invited to open issues, send pull requests or give me your opinion.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "yard"
|
4
|
+
require "yard/rake/yardoc_task"
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
7
|
+
t.pattern = 'spec/crubyflie_spec.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
YARD::Rake::YardocTask.new(:yard)
|
11
|
+
|
12
|
+
task :doc => :yard
|
13
|
+
task :test => :spec
|
14
|
+
task :default => [:spec, :doc]
|
15
|
+
|
data/bin/crubyflie
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Copyright (C) 2013 Hector Sanjuan
|
4
|
+
|
5
|
+
# This file is part of Crubyflie.
|
6
|
+
|
7
|
+
# Crubyflie is free software: you can redistribute it and/or modify
|
8
|
+
# it under the terms of the GNU General Public License as published by
|
9
|
+
# the Free Software Foundation, either version 3 of the License, or
|
10
|
+
# (at your option) any later version.
|
11
|
+
|
12
|
+
# Crubyflie is distributed in the hope that it will be useful,
|
13
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
+
# GNU General Public License for more details.
|
16
|
+
|
17
|
+
# You should have received a copy of the GNU General Public License
|
18
|
+
# along with Crubyflie. If not, see <http://www.gnu.org/licenses/>
|
19
|
+
|
20
|
+
require 'crubyflie'
|
21
|
+
require 'trollop'
|
22
|
+
|
23
|
+
# This script allows to fly the Crazyflie usingi the Joystick controller
|
24
|
+
# and initializing a Crazyflie. It might need a bit of cleanup but it does
|
25
|
+
# the job.
|
26
|
+
|
27
|
+
opts = Trollop::options do
|
28
|
+
opt(:joystick_id, "Joystick ID",
|
29
|
+
:type => :int,
|
30
|
+
:default => 0,
|
31
|
+
:short => '-j')
|
32
|
+
opt(:cf_uri, "Crazyflie URI (defaults to first one found in scan)",
|
33
|
+
:type => :string,
|
34
|
+
:short => '-f')
|
35
|
+
opt(:config, "Joystick configuration, defaults to default cfg in configs/",
|
36
|
+
:type => :string,
|
37
|
+
:default => Crubyflie::Joystick::DEFAULT_CONFIG_PATH,
|
38
|
+
:short => '-c')
|
39
|
+
opt(:debug, "Enable debug messages",
|
40
|
+
:short => '-d')
|
41
|
+
end
|
42
|
+
|
43
|
+
include Crubyflie
|
44
|
+
$debug = true if opts[:debug]
|
45
|
+
|
46
|
+
cf = Crazyflie.new('/tmp/crubyflie')
|
47
|
+
|
48
|
+
# Before opening any link, scan for interfaces
|
49
|
+
uris = cf.scan_interface
|
50
|
+
if uris.empty?
|
51
|
+
logger.error("No crazyflies found")
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
logger.info("Found copters at: #{uris}")
|
55
|
+
if uri = opts[:cf_uri] && !uris.include?(opts[:cf_uri])
|
56
|
+
logger.error("Provided URI not found")
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
|
60
|
+
uri ||= uris.first
|
61
|
+
|
62
|
+
# Open a link to the copter
|
63
|
+
cf.open_link(uri)
|
64
|
+
# Make sure everything is still good
|
65
|
+
exit 1 if !cf.active?
|
66
|
+
|
67
|
+
# Initialize the joystick - ID defaults to 0
|
68
|
+
joystick = Joystick.new(opts[:config], opts[:joystick_id])
|
69
|
+
joystick.init()
|
70
|
+
|
71
|
+
exit = false
|
72
|
+
Signal.trap("SIGINT") do
|
73
|
+
exit = true
|
74
|
+
end
|
75
|
+
|
76
|
+
logger.info("Cleared for take-off!")
|
77
|
+
|
78
|
+
while cf.active? && !exit do
|
79
|
+
start_time = Time.now.to_f
|
80
|
+
joystick.read_input()
|
81
|
+
joystick.apply_input(cf)
|
82
|
+
# We should be good sending 10 ticks per second,
|
83
|
+
# as it says that somewhere in the docs, so we have
|
84
|
+
# 1/10 secs of time per loop. If we are fast, we can sleep
|
85
|
+
# a little bit
|
86
|
+
consumed_time = Time.now.to_f - start_time
|
87
|
+
sleep_time = 0.1 - consumed_time
|
88
|
+
sleep sleep_time if sleep_time > 0
|
89
|
+
end
|
90
|
+
|
91
|
+
joystick.quit()
|
92
|
+
cf.close_link()
|
93
|
+
warn "\n"
|
94
|
+
logger.info("Bye bye!")
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# Default joystick configuration file. A file looks like:
|
2
|
+
# --------------------------------------------------------------------------
|
3
|
+
# :type: Joystick
|
4
|
+
# :axis:
|
5
|
+
# <axis_id>:
|
6
|
+
# :action: <action>
|
7
|
+
# :description: A short description to remember what this is
|
8
|
+
# :input_range: "<start>:<end>"
|
9
|
+
# The range read from the joystick.
|
10
|
+
# Defaults to -32768:32767 which is SDL-dependant
|
11
|
+
#
|
12
|
+
# :output_range: "<start>:<end>"
|
13
|
+
# The values we should yield to
|
14
|
+
# the Crazyflie, normally degrees (roll, pitch...). For
|
15
|
+
# thrust it is expressed in % of thrust
|
16
|
+
#
|
17
|
+
# :max_change_rate: <number>
|
18
|
+
# The output_range change rate per second. Must
|
19
|
+
# e a number. Defaults to 10000 (so a lot). For thrust
|
20
|
+
# it is expressed in % of thrust
|
21
|
+
# :dead_zone: "<start>:<end>"
|
22
|
+
# The dead range around 0. Defaults to 0:0
|
23
|
+
#
|
24
|
+
# :invert: true|false - Invert this axis
|
25
|
+
#
|
26
|
+
# :calibration: <number>
|
27
|
+
# This value is added to the raw joystick reading
|
28
|
+
#
|
29
|
+
# <axis_id2>: ...
|
30
|
+
#
|
31
|
+
# :buttons:
|
32
|
+
# <button_id>:
|
33
|
+
# :action: <action>
|
34
|
+
# :value: <value when pressed>
|
35
|
+
# A number, optional, defaults to 1.
|
36
|
+
#
|
37
|
+
# <button_id2>: ...
|
38
|
+
#
|
39
|
+
# --------------------------------------------------------------------------
|
40
|
+
# Valid actions:
|
41
|
+
# :roll - Controls roll. Assignable a axis or a button with value tag.
|
42
|
+
# :pitch - Controls pitch. Assignable a axis or a button with value tag.
|
43
|
+
# :thrust - Controls thrust. Assignable a axis or a button with value tag.
|
44
|
+
# :yaw - Controls yaw. Assignable a axis or a button with value tag.
|
45
|
+
# :switch_xmode - Enables/disables xmode. Assignable to a button.
|
46
|
+
# :close_link - Kills the link and shuts Crubyflie. Assignable to a button.
|
47
|
+
# :switch_scaled_output_mode - Enables/disabled scaled output mode. Assignable
|
48
|
+
# to a button with value tag (the multiplier)
|
49
|
+
# :roll_inc_cal, :roll_dec_cal - Increase/decrease calibration for :roll axis.
|
50
|
+
# Assignable to a button with optional value.
|
51
|
+
#
|
52
|
+
# :pitch_inc_cal, :pitch_dec_cal - Increase/decrease calibration for :pitch
|
53
|
+
# axis. Assignable to a button with optional
|
54
|
+
# value.
|
55
|
+
# ---------------------------------------------------------------------------
|
56
|
+
:type: "Joystick"
|
57
|
+
:axis:
|
58
|
+
0:
|
59
|
+
:description: "Roll Axis"
|
60
|
+
:action: :roll
|
61
|
+
:input_range: "-32768:32767" # Optional - SDL dependant. Defaults to this.
|
62
|
+
:output_range: "-30:30" # Min/Max crazyflie angle in degrees.
|
63
|
+
:max_change_rate: 600 # Max angle change rate per second. Optional
|
64
|
+
:dead_zone: "-100:100" # Deadzone, within input range
|
65
|
+
:invert: false # Invert the axis
|
66
|
+
:calibration: 0 # This value is added to the raw value read from joystick
|
67
|
+
1:
|
68
|
+
:description: "Pitch Axis"
|
69
|
+
:action: :pitch
|
70
|
+
:input_range: "-32768:32767"
|
71
|
+
:output_range: "-30:30"
|
72
|
+
:max_change_rate: 600
|
73
|
+
:dead_zone: "-100:100"
|
74
|
+
:invert: true
|
75
|
+
:calibration: 0
|
76
|
+
2:
|
77
|
+
:description: "Yaw Axis"
|
78
|
+
:action: :yaw
|
79
|
+
:input_range: "-32768:32767"
|
80
|
+
:output_range: "-150:150"
|
81
|
+
:max_change_rate: 800
|
82
|
+
:dead_zone: "-1000:1000"
|
83
|
+
:invert: false
|
84
|
+
:calibration: 0
|
85
|
+
3:
|
86
|
+
:description: "Thrust axis"
|
87
|
+
:action: :thrust
|
88
|
+
:input_range: "-32768:32767"
|
89
|
+
# Exception: Min/max thrust output is represented in 0-100%!
|
90
|
+
:output_range: "0:80"
|
91
|
+
# Max change rate per second when lowering thrust in % of thrust
|
92
|
+
:max_change_rate: 70
|
93
|
+
:dead_zone: "-100:100"
|
94
|
+
:invert: true
|
95
|
+
:calibration: 0
|
96
|
+
|
97
|
+
:buttons:
|
98
|
+
0:
|
99
|
+
:action: :switch_xmode
|
100
|
+
1:
|
101
|
+
:action: :close_link
|
102
|
+
4:
|
103
|
+
# When enabled, this mode will will multiply axis readings (except thrust)
|
104
|
+
# by the value of the button (must be a positive number)
|
105
|
+
:action: :switch_scaled_output_mode
|
106
|
+
:value: 0.50 # Softer output, useful for landing
|
data/crubyflie.gemspec
ADDED
@@ -0,0 +1,50 @@
|
|
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
|
+
lib = File.expand_path('../lib', __FILE__)
|
20
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
21
|
+
require 'crubyflie/version'
|
22
|
+
|
23
|
+
Gem::Specification.new do |spec|
|
24
|
+
spec.name = "hybridgroup-crubyflie"
|
25
|
+
spec.version = Crubyflie::VERSION
|
26
|
+
spec.authors = ["Hector Sanjuan", "Adrian Zankich"]
|
27
|
+
spec.email = ["hector@convivencial.org", "adrian@hybridgroup.com"]
|
28
|
+
spec.description = <<EOF
|
29
|
+
Client library to control a Crazyflie. This library allows to talk to a
|
30
|
+
crazyflie using the USB radio dongle.
|
31
|
+
EOF
|
32
|
+
spec.summary = "A Ruby client for the Crazyflie quadcopter"
|
33
|
+
spec.homepage = "https://github.com/hybridgroup/crubyflie"
|
34
|
+
spec.license = "GPLv3"
|
35
|
+
|
36
|
+
spec.files = `git ls-files`.split($/)
|
37
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
38
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
39
|
+
spec.require_paths = ["lib"]
|
40
|
+
|
41
|
+
spec.add_dependency "libusb"
|
42
|
+
spec.add_dependency "trollop"
|
43
|
+
|
44
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
45
|
+
spec.add_development_dependency "rake"
|
46
|
+
spec.add_development_dependency "rspec"
|
47
|
+
spec.add_development_dependency "yard"
|
48
|
+
spec.add_development_dependency "simplecov"
|
49
|
+
spec.add_development_dependency "coveralls"
|
50
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
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
|
+
# Require the Crubyflie gem
|
20
|
+
require 'crubyflie'
|
21
|
+
include Crubyflie # easy to use things in namespace
|
22
|
+
|
23
|
+
# Create a new Crazyflie with cache folder "cache"
|
24
|
+
cf = Crazyflie.new('cache')
|
25
|
+
# Before opening any link, scan for interfaces
|
26
|
+
ifaces = cf.scan_interface
|
27
|
+
if ifaces.empty?
|
28
|
+
logger.error("No crazyflies found")
|
29
|
+
exit 1
|
30
|
+
end
|
31
|
+
logger.info("Found interfaces: #{ifaces}")
|
32
|
+
|
33
|
+
# Open a link to the first interface
|
34
|
+
cf.open_link(ifaces.first)
|
35
|
+
# Make sure everything is still good
|
36
|
+
exit 1 if !cf.active?
|
37
|
+
|
38
|
+
# Write the TOCs to stdout
|
39
|
+
puts "Log TOC"
|
40
|
+
puts cf.log.toc.to_s
|
41
|
+
puts
|
42
|
+
puts "Param TOC"
|
43
|
+
puts cf.param.toc.to_s
|
44
|
+
|
45
|
+
# Read some parameters
|
46
|
+
puts "--------"
|
47
|
+
cf.param.get_value("attitudepid.kp_pitch") do |value|
|
48
|
+
puts "kp_pitch: #{value}"
|
49
|
+
end
|
50
|
+
cf.param.get_value("attitudepid.ki_pitch") do |value|
|
51
|
+
puts "ki_pitch: #{value}"
|
52
|
+
end
|
53
|
+
cf.param.get_value("attitudepid.kd_pitch") do |value|
|
54
|
+
puts "kd_pitch: #{value}"
|
55
|
+
end
|
56
|
+
puts "--------"
|
57
|
+
|
58
|
+
|
59
|
+
# We use 1 variable, is_toc = true
|
60
|
+
# The last two 7 means it is stored and fetched as float
|
61
|
+
log_conf_var = LogConfVariable.new("stabilizer.pitch", true, 7, 7)
|
62
|
+
|
63
|
+
# We create a configuration object
|
64
|
+
# We want to fetch it every 0.1 secs
|
65
|
+
log_conf = LogConf.new([log_conf_var], {:period => 10})
|
66
|
+
|
67
|
+
# With the configuration object, register a log_block
|
68
|
+
block_id = cf.log.create_log_block(log_conf)
|
69
|
+
|
70
|
+
# Start logging
|
71
|
+
# Counter on how many times we have logged the pitch
|
72
|
+
logged = 0
|
73
|
+
cf.log.start_logging(block_id) do |data|
|
74
|
+
warn "Pitch: #{data['stabilizer.pitch']}"
|
75
|
+
logged += 1
|
76
|
+
end
|
77
|
+
|
78
|
+
# Wait until we have hit the log_cb 10 times
|
79
|
+
while (logged < 10)
|
80
|
+
sleep 1
|
81
|
+
end
|
82
|
+
|
83
|
+
# Stop logging
|
84
|
+
cf.log.stop_logging(block_id)
|
85
|
+
|
86
|
+
# After finishing, close the link!
|
87
|
+
cf.close_link()
|
@@ -0,0 +1,54 @@
|
|
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
|
+
# The Commander facility is used to send control information to the
|
21
|
+
# Crazyflie. You want to use this class to fly your Crazyflie
|
22
|
+
class Commander
|
23
|
+
# Initialize the facility
|
24
|
+
def initialize(crazyflie)
|
25
|
+
@crazyflie = crazyflie
|
26
|
+
end
|
27
|
+
|
28
|
+
# Send a setpoint to the Crazyflie
|
29
|
+
#
|
30
|
+
# The roll, pitch, yaw values are floats with positive or negative
|
31
|
+
# values. The range should be the value read from the controller
|
32
|
+
# ([-1,1]) multiplied by the maximum angle change rate
|
33
|
+
# @param roll [float] the roll value
|
34
|
+
# @param pitch [float] the pitch value
|
35
|
+
# @param yaw [float] the yaw value
|
36
|
+
# @param thrust [Integer] thrust is an integer value ranging
|
37
|
+
# from 10001 (next to no power) to
|
38
|
+
# 60000 (full power)
|
39
|
+
def send_setpoint(roll, pitch, yaw, thrust, xmode=false)
|
40
|
+
if xmode
|
41
|
+
roll = 0.707 * (roll - pitch)
|
42
|
+
pitch = 0.707 * (roll + pitch)
|
43
|
+
end
|
44
|
+
|
45
|
+
packet = CRTPPacket.new()
|
46
|
+
packet.modify_header(nil, Crazyflie::CRTP_PORTS[:commander], nil)
|
47
|
+
data = [roll, -pitch, yaw, thrust]
|
48
|
+
# send 3 floats and one unsigned short (16 bits) (all little endian)
|
49
|
+
data = data.pack('eeeS<')
|
50
|
+
packet.data = data.unpack('C*')
|
51
|
+
@crazyflie.send_packet(packet, false)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,67 @@
|
|
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
|
+
module Crubyflie
|
21
|
+
# The Console facility is used to read characters that have been
|
22
|
+
# printer using printf in the crazyflie firmware
|
23
|
+
class Console
|
24
|
+
|
25
|
+
# Initialize the console
|
26
|
+
# @param crazyflie [Crazyflie]
|
27
|
+
def initialize(crazyflie)
|
28
|
+
@crazyflie = crazyflie
|
29
|
+
@in_queue = crazyflie.crtp_queues[:console]
|
30
|
+
@read_thread = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Reads all the characters from the Crazyflie that are queued, until
|
34
|
+
# the queue is empty, and then return only after executing the
|
35
|
+
# given block for each packet that was in the queue.
|
36
|
+
# @param block [Proc] a block to call with the read information
|
37
|
+
def read(&block)
|
38
|
+
while @in_queue.size > 0 do
|
39
|
+
packet = @in_queue.pop() # block
|
40
|
+
yield(packet.data_repack) if block_given?
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
# Reads all the characters from the Crazyflie constantly
|
46
|
+
# and yields on the the given block is called with the payload.
|
47
|
+
# This call will return immediately, but the block will be
|
48
|
+
# called asynchronously until #stop_reading() is called.
|
49
|
+
# Use stop_read() to stop.
|
50
|
+
# @param block [Proc] a block to call with the read information
|
51
|
+
def start_reading(&block)
|
52
|
+
stop_reading()
|
53
|
+
@read_thread = Thread.new do
|
54
|
+
loop do
|
55
|
+
read(&block)
|
56
|
+
sleep 0.3 # no hurries?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Stops reading characters from the Crazyflie
|
62
|
+
def stop_reading
|
63
|
+
@read_thread.kill() if @read_thread
|
64
|
+
@read_thread = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|