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.
@@ -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 attached to
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
- attr_reader :components, :mock
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
+
@@ -31,15 +31,6 @@ module BBB
31
31
  def value
32
32
  read
33
33
  end
34
-
35
- ##
36
- # Convenience method to grab the first pin in the pins array
37
- #
38
- # @return BBB::Pins::AnalogPin
39
- #
40
- def pin
41
- pins.first
42
- end
43
34
  end
44
35
  end
45
36
  end
@@ -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
+
@@ -2,45 +2,94 @@ module BBB
2
2
  module Components
3
3
  class ESC
4
4
  include Pinnable
5
- uses Pins::PWMPin, Pins::DigitalOutputPin
5
+ uses Pins::PWMPin
6
6
 
7
7
  attr_accessor :min_duty, :max_duty, :period
8
- attr_reader :duty
9
8
 
10
- def initialize(period=10e6, min_duty=0.8e6, max_duty=2e6)
11
- @period = period
12
- @min_duty = min_duty
13
- @max_duty = max_duty
14
- end
9
+ after_connect :setup_pin
15
10
 
16
- def after_pin_initialization
17
- power.off!
18
- pwm.period = period
19
- pwm.duty = min_duty
20
- pwm.run = 1
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
- self.duty = min_duty + value * duty_range
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
- pwm.duty = @duty
66
+ synchronize_duty
30
67
  end
31
68
 
32
- def duty_range
33
- max_duty - min_duty
69
+ def period=(value)
70
+ @period = value
71
+ synchronize_period
34
72
  end
35
73
 
36
74
  def pwm
37
- pins.first
75
+ pin
38
76
  end
39
77
 
40
- def power
41
- pins.last
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
@@ -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