BBB 0.1.3 → 0.2.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 +13 -5
- data/Gemfile +2 -2
- data/Guardfile +46 -0
- data/examples/analog_pin.rb +2 -16
- data/examples/ldr_light_switch.rb +56 -0
- data/examples/led.rb +5 -14
- data/examples/light_switch.rb +42 -47
- data/examples/nunchuck.rb +99 -0
- data/examples/servo_ldr.rb +11 -10
- data/lib/BBB.rb +2 -19
- data/lib/BBB/application.rb +5 -21
- data/lib/BBB/circuit.rb +49 -42
- data/lib/BBB/components.rb +9 -0
- data/lib/BBB/components/analog_component.rb +0 -9
- data/lib/BBB/components/button.rb +25 -0
- data/lib/BBB/components/esc.rb +68 -19
- data/lib/BBB/components/led.rb +0 -9
- data/lib/BBB/components/nunchuck.rb +197 -0
- data/lib/BBB/components/pinnable.rb +70 -18
- data/lib/BBB/components/servo.rb +21 -11
- data/lib/BBB/components/wii_motion_plus.rb +229 -0
- data/lib/BBB/pins.rb +13 -0
- data/lib/BBB/pins/i2c.rb +22 -0
- data/lib/BBB/pins/io/gpio.rb +6 -2
- data/lib/BBB/pins/io/i2c.rb +10 -9
- data/lib/BBB/pins/io/pin_mapper.rb +2 -2
- data/lib/BBB/pins/pinnable.rb +3 -3
- data/lib/BBB/version.rb +1 -1
- data/spec/application_spec.rb +4 -14
- data/spec/circuit_spec.rb +6 -9
- data/spec/components/analog_component_spec.rb +7 -2
- data/spec/components/led_spec.rb +1 -1
- data/spec/components/pinnable_spec.rb +16 -6
- data/spec/components/servo_spec.rb +47 -1
- data/spec/examples/led_spec.rb +40 -0
- data/spec/pins/digital_pin_spec.rb +1 -0
- data/spec/pins/io/pin_mapper_spec.rb +0 -4
- metadata +24 -14
data/lib/BBB/application.rb
CHANGED
@@ -1,33 +1,17 @@
|
|
1
1
|
module BBB
|
2
2
|
class Application
|
3
|
-
|
4
|
-
def self.circuit(circuit)
|
5
|
-
@_circuit = circuit
|
6
|
-
define_convenience_methods(circuit)
|
7
|
-
end
|
8
|
-
|
9
|
-
def self._circuit
|
10
|
-
@_circuit
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.define_convenience_methods(c)
|
14
|
-
c.components.keys.each do |name|
|
15
|
-
define_method(name) do
|
16
|
-
circuit.send(name)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
def circuit
|
22
|
-
self.class._circuit
|
23
|
-
end
|
3
|
+
include Attachable
|
24
4
|
|
25
5
|
def start
|
6
|
+
activate_components
|
26
7
|
loop do
|
27
8
|
run
|
28
9
|
end
|
29
10
|
end
|
30
11
|
|
12
|
+
def activate_components
|
13
|
+
end
|
14
|
+
|
31
15
|
def run
|
32
16
|
raise NotImplementedError
|
33
17
|
end
|
data/lib/BBB/circuit.rb
CHANGED
@@ -1,9 +1,56 @@
|
|
1
1
|
module BBB
|
2
|
+
module Attachable
|
3
|
+
module ClassMethods
|
4
|
+
|
5
|
+
def class_components
|
6
|
+
@class_components ||= {}
|
7
|
+
end
|
8
|
+
|
9
|
+
##
|
10
|
+
# Attach a component of a certain type to the circuit
|
11
|
+
#
|
12
|
+
# @param component [Class] The class of the object you # want to attach.
|
13
|
+
# @param opts [Hash] Hash of options that setup the component
|
14
|
+
#
|
15
|
+
# @option opts [Symbol] :pin The pin position for the component
|
16
|
+
# @option opts [Array<Symbol>] :pins The list of pin numbers used on the
|
17
|
+
# circuit.
|
18
|
+
# @options opts [Symbol] :as The name of the component
|
19
|
+
#
|
20
|
+
def attach(object, opts={})
|
21
|
+
name = opts.delete(:as)
|
22
|
+
class_components[name] = object
|
23
|
+
define_method_for_object(object, name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def define_method_for_object(component, name)
|
27
|
+
define_method(name) do
|
28
|
+
value = components[name]
|
29
|
+
return value if value
|
30
|
+
|
31
|
+
object = self.class.class_components[name]
|
32
|
+
value = object.kind_of?(Class) ? object.new : object
|
33
|
+
|
34
|
+
components[name] = value
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.included(base)
|
40
|
+
base.extend(ClassMethods)
|
41
|
+
end
|
42
|
+
|
43
|
+
def components
|
44
|
+
@components ||= {}
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
2
49
|
##
|
3
50
|
# The idea here is to attach a piece of equipment to a circuit.
|
4
51
|
#
|
5
52
|
# A component (e.g. Led or Servo) will define generic pins, like
|
6
|
-
# DigitalInput or AnalogOutput. And then, when the component gets
|
53
|
+
# DigitalInput or AnalogOutput. And then, when the component gets connected to
|
7
54
|
# the circuit those pins will be initialized using the file system.
|
8
55
|
#
|
9
56
|
# For now the attachment will be made onto specific pin numbers. For the BBB
|
@@ -12,46 +59,6 @@ module BBB
|
|
12
59
|
# boards. For example by mapping P8_3 on BBB to P1 on an Arduino.
|
13
60
|
#
|
14
61
|
class Circuit
|
15
|
-
|
16
|
-
|
17
|
-
def components
|
18
|
-
@components ||= {}
|
19
|
-
end
|
20
|
-
|
21
|
-
def mock?
|
22
|
-
@mock == true
|
23
|
-
end
|
24
|
-
|
25
|
-
##
|
26
|
-
# Attach a component of a certain type to the circuit
|
27
|
-
#
|
28
|
-
# @param component [Class] The class of the object you # want to attach.
|
29
|
-
# @param opts [Hash] Hash of options that setup the component
|
30
|
-
#
|
31
|
-
# @option opts [Symbol] :pin The pin position for the component
|
32
|
-
# @option opts [Array<Symbol>] :pins The list of pin numbers used on the
|
33
|
-
# circuit.
|
34
|
-
# @options opts [Symbol] :as The name of the component
|
35
|
-
#
|
36
|
-
def attach(component, opts={})
|
37
|
-
name = opts.delete(:as)
|
38
|
-
component = component.new if component.kind_of?(Class)
|
39
|
-
pin_positions = opts.delete(:pins) || [opts.delete(:pin)]
|
40
|
-
pin_options = {:mock=>self.mock?}.merge!(opts)
|
41
|
-
|
42
|
-
component.initialize_pins(pin_positions, pin_options)
|
43
|
-
define_method_for_component(component, name)
|
44
|
-
end
|
45
|
-
|
46
|
-
def define_method_for_component(component, name)
|
47
|
-
components[name] = component
|
48
|
-
eigenclass = class << self; self; end
|
49
|
-
eigenclass.class_eval do
|
50
|
-
define_method(name) do
|
51
|
-
components[name]
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
62
|
+
include Attachable
|
56
63
|
end
|
57
64
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require "BBB/components/pinnable"
|
2
|
+
require "BBB/components/button"
|
3
|
+
require "BBB/components/analog_component"
|
4
|
+
require "BBB/components/led"
|
5
|
+
require "BBB/components/esc"
|
6
|
+
require "BBB/components/servo"
|
7
|
+
require "BBB/components/wii_motion_plus"
|
8
|
+
require "BBB/components/nunchuck"
|
9
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module BBB
|
2
|
+
module Components
|
3
|
+
class Button
|
4
|
+
include Pinnable
|
5
|
+
|
6
|
+
uses BBB::Pins::DigitalInputPin
|
7
|
+
|
8
|
+
def high?
|
9
|
+
pin.on?
|
10
|
+
end
|
11
|
+
alias_method :on?, :high?
|
12
|
+
|
13
|
+
def low?
|
14
|
+
!high
|
15
|
+
end
|
16
|
+
alias_method :off?, :low?
|
17
|
+
|
18
|
+
def status
|
19
|
+
pin.status
|
20
|
+
end
|
21
|
+
alias_method :state, :status
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
data/lib/BBB/components/esc.rb
CHANGED
@@ -2,45 +2,94 @@ module BBB
|
|
2
2
|
module Components
|
3
3
|
class ESC
|
4
4
|
include Pinnable
|
5
|
-
uses Pins::PWMPin
|
5
|
+
uses Pins::PWMPin
|
6
6
|
|
7
7
|
attr_accessor :min_duty, :max_duty, :period
|
8
|
-
attr_reader :duty
|
9
8
|
|
10
|
-
|
11
|
-
@period = period
|
12
|
-
@min_duty = min_duty
|
13
|
-
@max_duty = max_duty
|
14
|
-
end
|
9
|
+
after_connect :setup_pin
|
15
10
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
11
|
+
##
|
12
|
+
# Initialize a new ESC using default values for period, min_duty and
|
13
|
+
# max_duty if present. Please beware that at initialization stage there
|
14
|
+
# is no initialized PWM pin yet. So you can set the period and the
|
15
|
+
# min/max_duty instance variables, but not the variables on the pin.
|
16
|
+
# Only after "connecting" the esc to a board can you set the duty and
|
17
|
+
# period of the pin. Use the "after pin initialization" method for that.
|
18
|
+
#
|
19
|
+
def initialize(options={})
|
20
|
+
set_options
|
21
|
+
|
22
|
+
@period = options.fetch(:period, 20e6)
|
23
|
+
@speed = 0
|
24
|
+
|
25
|
+
@min_duty = options.fetch(:min_duty, 17.5e6)
|
26
|
+
@max_duty = options.fetch(:max_duty, 19e6)
|
21
27
|
end
|
22
28
|
|
23
29
|
def speed(value)
|
24
|
-
|
30
|
+
@speed = value
|
31
|
+
@duty = max_duty - value * duty_range
|
32
|
+
synchronize_duty
|
33
|
+
end
|
34
|
+
|
35
|
+
def calibrate
|
36
|
+
pwm.run = 0
|
37
|
+
puts "Disconnect the battery of the motor (press any key)"; gets
|
38
|
+
puts "Get ready to connect the battery after 2 seconds, ready? (press any key)"; gets
|
39
|
+
speed(1)
|
40
|
+
pwm.run = 1
|
41
|
+
puts "one missisipi"; sleep(1)
|
42
|
+
puts "two missisipi"; sleep(1)
|
43
|
+
puts "connect the battery"; sleep(1)
|
44
|
+
speed(0)
|
45
|
+
puts "Calibrated and ready to go"
|
46
|
+
end
|
47
|
+
|
48
|
+
def arm
|
49
|
+
pwm.run=1
|
50
|
+
end
|
51
|
+
|
52
|
+
def armed?
|
53
|
+
pwm.run == 1
|
54
|
+
end
|
55
|
+
|
56
|
+
def disarm
|
57
|
+
pwm.run=0
|
58
|
+
end
|
59
|
+
|
60
|
+
def disarmed?
|
61
|
+
!armed?
|
25
62
|
end
|
26
63
|
|
27
64
|
def duty=(value)
|
28
65
|
@duty = value
|
29
|
-
|
66
|
+
synchronize_duty
|
30
67
|
end
|
31
68
|
|
32
|
-
def
|
33
|
-
|
69
|
+
def period=(value)
|
70
|
+
@period = value
|
71
|
+
synchronize_period
|
34
72
|
end
|
35
73
|
|
36
74
|
def pwm
|
37
|
-
|
75
|
+
pin
|
38
76
|
end
|
39
77
|
|
40
|
-
|
41
|
-
|
78
|
+
private
|
79
|
+
|
80
|
+
def duty_range
|
81
|
+
max_duty - min_duty
|
82
|
+
end
|
83
|
+
|
84
|
+
def synchronize_period
|
85
|
+
pwm.period = @period
|
42
86
|
end
|
43
87
|
|
88
|
+
def after_pin_initialization
|
89
|
+
disarm
|
90
|
+
synchronize_period
|
91
|
+
speed(0)
|
92
|
+
end
|
44
93
|
end
|
45
94
|
end
|
46
95
|
end
|
data/lib/BBB/components/led.rb
CHANGED
@@ -15,15 +15,6 @@ module BBB
|
|
15
15
|
|
16
16
|
uses BBB::Pins::DigitalOutputPin
|
17
17
|
|
18
|
-
##
|
19
|
-
# Convenience method to grab the first pin in the pins array
|
20
|
-
#
|
21
|
-
# @return BBB::Pins::DigitalOutputPin
|
22
|
-
#
|
23
|
-
def pin
|
24
|
-
pins.first
|
25
|
-
end
|
26
|
-
|
27
18
|
##
|
28
19
|
# Turns on the LED
|
29
20
|
# @return void
|
@@ -0,0 +1,197 @@
|
|
1
|
+
module BBB
|
2
|
+
module Components
|
3
|
+
class Nunchuck
|
4
|
+
include Pinnable
|
5
|
+
uses Pins::I2C
|
6
|
+
|
7
|
+
attr_reader :accelerometer, :controls
|
8
|
+
|
9
|
+
def initialize(options={})
|
10
|
+
@started = false
|
11
|
+
@positions = options[:i2c] || []
|
12
|
+
@accelerometer = Accelerometer.new
|
13
|
+
@controls = Controls.new
|
14
|
+
@decoder = Decoder.new
|
15
|
+
end
|
16
|
+
|
17
|
+
def start
|
18
|
+
begin
|
19
|
+
raw_read
|
20
|
+
rescue I2C::AckError
|
21
|
+
i2c.write(0x52, 0x40, 0x00)
|
22
|
+
end
|
23
|
+
@started = true
|
24
|
+
end
|
25
|
+
|
26
|
+
def started?
|
27
|
+
@started
|
28
|
+
end
|
29
|
+
|
30
|
+
def update
|
31
|
+
bytes = raw_read.bytes.to_a
|
32
|
+
@accelerometer.update(bytes)
|
33
|
+
@controls.update(bytes)
|
34
|
+
end
|
35
|
+
|
36
|
+
def raw_read
|
37
|
+
decoder.decode i2c.read(0x52, 6, 0x00)
|
38
|
+
end
|
39
|
+
|
40
|
+
def z; controls.z; end
|
41
|
+
def c; controls.c; end
|
42
|
+
def x; controls.x; end
|
43
|
+
def y; controls.z; end
|
44
|
+
def accel; accelerometer; end
|
45
|
+
|
46
|
+
class Decoder
|
47
|
+
def decode(bytes)
|
48
|
+
bytes.map{|b| b^0x17 + 0x17}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Accelerometer
|
53
|
+
def initialize
|
54
|
+
@x = AccelAccess.new
|
55
|
+
@y = AccelAccess.new
|
56
|
+
@z = AccelAccess.new
|
57
|
+
end
|
58
|
+
|
59
|
+
def update(bytes)
|
60
|
+
set_x(bytes)
|
61
|
+
set_y(bytes)
|
62
|
+
set_z(bytes)
|
63
|
+
end
|
64
|
+
|
65
|
+
def set_x(bytes)
|
66
|
+
value = (bytes[2] << 2) | ((bytes[5] & 0b00001100) >> 2)
|
67
|
+
x.update(value)
|
68
|
+
end
|
69
|
+
|
70
|
+
def set_y(bytes)
|
71
|
+
value = (bytes[3] << 2) | ((bytes[5] & 0b00110000) >> 4)
|
72
|
+
y.update(value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def set_z(bytes)
|
76
|
+
value = (bytes[4] << 2) | ((bytes[5] & 0b11000000) >> 6)
|
77
|
+
z.update(value)
|
78
|
+
end
|
79
|
+
|
80
|
+
class AccelAccess
|
81
|
+
attr_reader :value
|
82
|
+
|
83
|
+
def update(value)
|
84
|
+
@value = value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Controls
|
90
|
+
def initialize
|
91
|
+
initialize_buttons
|
92
|
+
initialize_axis
|
93
|
+
end
|
94
|
+
|
95
|
+
def initialize_buttons
|
96
|
+
@buttons = Hash.new
|
97
|
+
@buttons[:z] = Button.new
|
98
|
+
@buttons[:c] = Button.new
|
99
|
+
end
|
100
|
+
|
101
|
+
def c
|
102
|
+
@buttons[:c]
|
103
|
+
end
|
104
|
+
|
105
|
+
def z
|
106
|
+
@buttons[:z]
|
107
|
+
end
|
108
|
+
|
109
|
+
def initialize_axis
|
110
|
+
@axis = Hash.new
|
111
|
+
@axis[:x] = ControlAxis.new
|
112
|
+
@axis[:y] = ControlAxis.new
|
113
|
+
end
|
114
|
+
|
115
|
+
def update(bytes)
|
116
|
+
update_buttons(bytes)
|
117
|
+
update_axis(bytes)
|
118
|
+
end
|
119
|
+
|
120
|
+
def update_buttons(bytes)
|
121
|
+
x = bytes[5] & 0b00000010 >> 1
|
122
|
+
y = bytes[5] & 0b00000001
|
123
|
+
|
124
|
+
@buttons[:x].update(x)
|
125
|
+
@buttons[:y].update(y)
|
126
|
+
end
|
127
|
+
|
128
|
+
def update_axis(bytes)
|
129
|
+
@axis[:x].update(bytes[0])
|
130
|
+
@axis[:y].update(bytes[1])
|
131
|
+
end
|
132
|
+
|
133
|
+
class Button
|
134
|
+
attr_reader :status
|
135
|
+
attr_accessor :release_callbacks, :press_callbacks
|
136
|
+
|
137
|
+
def initialize
|
138
|
+
@status = :released
|
139
|
+
@release_callbacks = []
|
140
|
+
@press_callbacks = []
|
141
|
+
end
|
142
|
+
|
143
|
+
def pressed?
|
144
|
+
status == :pressed
|
145
|
+
end
|
146
|
+
|
147
|
+
def press!
|
148
|
+
@status = :pressed
|
149
|
+
on_press if old_state != status
|
150
|
+
end
|
151
|
+
|
152
|
+
def release!
|
153
|
+
old_state = status
|
154
|
+
@status = :released
|
155
|
+
on_release if old_state != status
|
156
|
+
end
|
157
|
+
|
158
|
+
def released?
|
159
|
+
!pressed
|
160
|
+
end
|
161
|
+
|
162
|
+
def update(value)
|
163
|
+
value == true ? release! : press!
|
164
|
+
end
|
165
|
+
|
166
|
+
def on_release
|
167
|
+
@release_callbacks.each{ |c| c.call(status) }
|
168
|
+
end
|
169
|
+
|
170
|
+
def on_press
|
171
|
+
@press_callbacks.each{ |c| c.call(status) }
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
class ControlAxis
|
177
|
+
attr_accessor :value
|
178
|
+
attr_accessor :change_callbacks
|
179
|
+
|
180
|
+
def initialize
|
181
|
+
@change_callbacks = []
|
182
|
+
end
|
183
|
+
|
184
|
+
def update(value)
|
185
|
+
old_value = self.value
|
186
|
+
@value = value
|
187
|
+
on_change if old_value != value
|
188
|
+
end
|
189
|
+
|
190
|
+
def on_change
|
191
|
+
@change_callbacks.each{|c| c.call(value) }
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|