ruby-nxt 0.8.1

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.
@@ -0,0 +1,82 @@
1
+ # ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
2
+ # Copyright (C) 2006 Tony Buser <tbuser@gmail.com> - http://juju.org
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software Foundation,
15
+ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+
17
+ require "commands/mixins/sensor"
18
+ require "nxt_comm"
19
+
20
+ # Implements (and extens) the "Light Sensor" block in NXT-G
21
+ class Commands::LightSensor
22
+
23
+ include Commands::Mixins::Sensor
24
+
25
+ attr_reader :port, :generate_light
26
+ attr_accessor :trigger_point, :comparison
27
+
28
+ def initialize(nxt)
29
+ @nxt = nxt
30
+
31
+ # defaults the same as NXT-G
32
+ @port = 3
33
+ @trigger_point = 50
34
+ @comparison = ">"
35
+ @generate_light = true
36
+ set_mode
37
+ end
38
+
39
+ # Turns off the sensor's LED light.
40
+ def ambient_mode
41
+ self.generate_light = false
42
+ end
43
+
44
+ # Turns on the sensor's LED light.
45
+ def illuminated_mode
46
+ self.generate_light = true
47
+ end
48
+
49
+ # Turns the sensor's LED on or off.
50
+ # Takes true or false as the argument; if true, light will be turned on,
51
+ # if false, light will be turned off.
52
+ def generate_light=(on)
53
+ @generate_light = on
54
+ set_mode
55
+ end
56
+
57
+ # intensity of light detected 0-100 in %
58
+ def intensity
59
+ value_scaled
60
+ end
61
+ alias light_level intensity
62
+
63
+ # returns the raw value of the sensor
64
+ def raw_value
65
+ value_raw
66
+ end
67
+
68
+ # sets up the sensor port
69
+ def set_mode
70
+ @generate_light ? mode = NXTComm::LIGHT_ACTIVE : mode = NXTComm::LIGHT_INACTIVE
71
+ @nxt.set_input_mode(
72
+ NXTComm.const_get("SENSOR_#{@port}"),
73
+ mode,
74
+ NXTComm::PCTFULLSCALEMODE
75
+ )
76
+ end
77
+
78
+ # attempt to return the input_value requested
79
+ def method_missing(cmd)
80
+ @nxt.get_input_values(NXTComm.const_get("SENSOR_#{@port}"))[cmd]
81
+ end
82
+ end
@@ -0,0 +1,84 @@
1
+ # ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
2
+ # Copyright (c) 2006 Tony Buser <tbuser@gmail.com> - http://juju.org
3
+ # Copyright (c) 2006 Matt Zukowski <matt@roughest.net> - http://blog.roughest.net
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
+
18
+ # Common methods used in motor commands.
19
+ module Commands
20
+ module Mixins
21
+ module Motor
22
+ # Sets the duration of the motor movement.
23
+ # The parameter should be a Hash like one of the following:
24
+ # m.duration = {:seconds => 4 }
25
+ # m.duration = {:degrees => 180 }
26
+ # m.duration = {:rotations => 2 }
27
+ # To set the duration to unlimited (i.e. rotate indefinitely) you should set
28
+ # the duration to :unlimited, although this is equivalent to simply setting it to nil;
29
+ # the following expressions are equivalent:
30
+ # m.duration = nil
31
+ # m.duration = :unlimited
32
+ # If you assign an integer, it will be assumed that you are specifying seconds;
33
+ # the following are equivalent:
34
+ # m.duration = 4
35
+ # m.duration = {:seconds => 4}
36
+ # If you assign a float, it will be assumed that youa re specifying rotations;
37
+ # the following expressions are equivalent:
38
+ # m.duration = 2.0
39
+ # m.duration = {:rotations => 2}
40
+ def duration=(duration)
41
+ if duration.kind_of? Hash
42
+ @duration = duration
43
+ elsif duration.kind_of? Integer
44
+ @duration = {:seconds => duration}
45
+ elsif duration.kind_of? Float
46
+ @duration = {:rotations => duration}
47
+ elsif duration == :unlimited
48
+ @duration = nil
49
+ else
50
+ @duration = duration
51
+ end
52
+ end
53
+
54
+ def duration
55
+ if duration.nil?
56
+ :unlimited
57
+ else
58
+ @duration
59
+ end
60
+ end
61
+
62
+ protected
63
+ def tacho_limit
64
+ if @duration.kind_of? Hash
65
+ if @duration[:rotations]
66
+ tacho_limit = @duration[:rotations] * 360
67
+ end
68
+
69
+ if @duration[:degrees]
70
+ tacho_limit = @duration[:degrees]
71
+ end
72
+
73
+ if @duration[:seconds]
74
+ tacho_limit = 0
75
+ end
76
+ else
77
+ tacho_limit = 0
78
+ end
79
+
80
+ tacho_limit
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,38 @@
1
+ # ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
2
+ # Copyright (c) 2006 Tony Buser <tbuser@gmail.com> - http://juju.org
3
+ # Copyright (c) 2006 Matt Zukowski <matt@roughest.net> - http://blog.roughest.net
4
+ #
5
+ # This program is free software; you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation; either version 2 of the License
8
+ #
9
+ # This program is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # GNU General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with this program; if not, write to the Free Software Foundation,
16
+ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
+
18
+ # Common methods used in sensor commands.
19
+ module Commands
20
+ module Mixins
21
+ module Sensor
22
+ def port=(port)
23
+ @port = port
24
+ set_mode
25
+ end
26
+
27
+ def comparison=(op)
28
+ raise ArgumentError, "'#{op}' is not a valid comparison operator." unless op =~ /^([<>=]=?|!=)$/
29
+ @comparison = op
30
+ end
31
+
32
+ # Returns true or false based on comparison and trigger point.
33
+ def logic
34
+ eval "value_scaled #{@comparison} @trigger_point"
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,136 @@
1
+ # ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
2
+ # Copyright (C) 2006 Tony Buser <tbuser@gmail.com> - http://juju.org
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software Foundation,
15
+ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+
17
+ require "nxt_comm"
18
+ require "commands/mixins/motor"
19
+
20
+ # Implements the "Motor" block in NXT-G
21
+ class Commands::Motor
22
+
23
+ include Commands::Mixins::Motor
24
+
25
+ attr_accessor :port
26
+ attr_accessor :direction
27
+ attr_accessor :steering
28
+ attr_accessor :action
29
+ attr_accessor :power
30
+ attr_accessor :control_power
31
+ attr_accessor :wait
32
+ attr_accessor :next_action
33
+
34
+ def initialize(nxt = NXTComm.new($DEV))
35
+ @nxt = nxt
36
+
37
+ # defaults the same as NXT-G
38
+ @port = :a
39
+ @direction = :forward
40
+ @action = :constant
41
+ @power = 75
42
+ @control_power = false
43
+ @duration = nil # Same as :unlimited
44
+ @wait = false
45
+ @next_action = :brake
46
+ end
47
+
48
+ # execute the Motor command based on the properties specified
49
+ def start
50
+ @nxt.reset_motor_position(NXTComm.const_get("MOTOR_#{@port.to_s.upcase}"))
51
+
52
+ if @direction == :stop
53
+ motor_power = 0
54
+ mode = NXTComm::COAST
55
+ run_state = NXTComm::MOTOR_RUN_STATE_IDLE
56
+ else
57
+ @direction == :forward ? motor_power = @power : motor_power = -@power
58
+ mode = NXTComm::MOTORON | NXTComm::BRAKE
59
+ run_state = NXTComm::MOTOR_RUN_STATE_RUNNING
60
+ end
61
+
62
+ turn_ratio = 0
63
+
64
+ if @control_power
65
+ mode |= NXTComm::REGULATED
66
+ reg_mode = NXTComm::REGULATION_MODE_MOTOR_SPEED
67
+ else
68
+ reg_mode = NXTComm::REGULATION_MODE_IDLE
69
+ end
70
+
71
+ if @duration
72
+ if @duration[:degrees] or @duration[:seconds]
73
+ case @action
74
+ when :constant
75
+ run_state = NXTComm::MOTOR_RUN_STATE_RUNNING
76
+ when :ramp_up
77
+ run_state = NXTComm::MOTOR_RUN_STATE_RAMPUP
78
+ when :ramp_down
79
+ run_state = NXTComm::MOTOR_RUN_STATE_RAMPDOWN
80
+ end
81
+ end
82
+ end
83
+
84
+ @nxt.set_output_state(
85
+ NXTComm.const_get("MOTOR_#{@port.to_s.upcase}"),
86
+ motor_power,
87
+ mode,
88
+ reg_mode,
89
+ turn_ratio,
90
+ run_state,
91
+ tacho_limit
92
+ )
93
+
94
+ if (@duration and @duration[:seconds]) or @wait
95
+ if @duration and @duration[:seconds]
96
+ sleep(@duration[:seconds])
97
+ else
98
+ until self.run_state == NXTComm::MOTOR_RUN_STATE_IDLE
99
+ sleep(0.25)
100
+ end
101
+ end
102
+ self.stop
103
+ end
104
+ end
105
+
106
+ # stop the Motor command based on the next_action property
107
+ def stop
108
+ if @next_action == :brake
109
+ @nxt.set_output_state(
110
+ NXTComm.const_get("MOTOR_#{@port.to_s.upcase}"),
111
+ 0,
112
+ NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
113
+ NXTComm::REGULATION_MODE_MOTOR_SPEED,
114
+ 0,
115
+ NXTComm::MOTOR_RUN_STATE_RUNNING,
116
+ 0
117
+ )
118
+ else
119
+ @nxt.set_output_state(
120
+ NXTComm.const_get("MOTOR_#{@port.to_s.upcase}"),
121
+ 0,
122
+ NXTComm::COAST,
123
+ NXTComm::REGULATION_MODE_IDLE,
124
+ 0,
125
+ NXTComm::MOTOR_RUN_STATE_IDLE,
126
+ 0
127
+ )
128
+ end
129
+ end
130
+
131
+ # attempt to return the output_state requested
132
+ def method_missing(cmd)
133
+ @nxt.get_output_state(NXTComm.const_get("MOTOR_#{@port.to_s.upcase}"))[cmd]
134
+ end
135
+
136
+ end
@@ -0,0 +1,210 @@
1
+ # ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
2
+ # Copyright (C) 2006 Tony Buser <tbuser@gmail.com> - http://juju.org
3
+ #
4
+ # This program is free software; you can redistribute it and/or modify
5
+ # it under the terms of the GNU General Public License as published by
6
+ # the Free Software Foundation; either version 2 of the License
7
+ #
8
+ # This program is distributed in the hope that it will be useful,
9
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
10
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
+ # GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License
14
+ # along with this program; if not, write to the Free Software Foundation,
15
+ # Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
16
+
17
+ require "nxt_comm"
18
+ require "commands/mixins/motor"
19
+
20
+ # Implements the "Move" block in NXT-G
21
+ class Commands::Move
22
+
23
+ include Commands::Mixins::Motor
24
+
25
+ attr_reader :ports
26
+ attr_accessor :direction
27
+ attr_accessor :left_motor, :right_motor
28
+ attr_accessor :power
29
+ attr_accessor :next_action
30
+
31
+ def initialize(nxt = NXTComm.new($DEV))
32
+ @nxt = nxt
33
+
34
+ # defaults the same as NXT-G
35
+ @ports = [:b, :c]
36
+ @direction = :forward
37
+ @power = 75
38
+ @duration = {:rotations => 1}
39
+ @next_action = :brake
40
+ self.turn_ratio = :straight
41
+ end
42
+
43
+ def ports=(value)
44
+ # make it flexible, let them specify just :a, or "A", or :a,:b to do two etc.
45
+ case value.class.to_s
46
+ when "Symbol" then @ports = [value]
47
+ when "String" then @ports = [value.intern]
48
+ when "Array" then @ports = value
49
+ else raise "Invalid port type #{value.class}"
50
+ end
51
+ end
52
+ alias port= ports=
53
+
54
+ def turn_ratio=(turn_ratio)
55
+ # simplified steering... if the user wants fine control, they should just specify -100 to 100
56
+ case turn_ratio
57
+ when :straight then @turn_ratio = 0
58
+ when :spin_left then @turn_ratio = -100
59
+ when :spin_right then @turn_ratio = 100
60
+ when :left then @turn_ratio = -50
61
+ when :right then @turn_ration = 50
62
+ else @turn_ratio = turn_ratio
63
+ end
64
+
65
+ # DEPRECATED: for backwards compatibility we parse the argument as a hash... I think though that this should be deprecated
66
+ if turn_ratio.kind_of? Hash
67
+ old_steering = turn_ratio
68
+ self.left_motor = old_steering[:left_motor] if old_steering.has_key? :left_motor
69
+ self.right_motor = old_steering[:right_motor] if old_steering.has_key? :right_motor
70
+ if old_steering[:power]
71
+ self.turn_ratio = old_steering[:power] * (old_steering[:direction] == :left ? -1 : 1)
72
+ else
73
+ self.turn_ratio = old_steering[:direction]
74
+ end
75
+ end
76
+ end
77
+ alias steering= turn_ratio=
78
+
79
+ def turn_ratio
80
+ if @ports.size > 1
81
+ @turn_ratio
82
+ else
83
+ 0
84
+ end
85
+ end
86
+ alias steering turn_ratio
87
+
88
+
89
+ # execute the Move command based on the properties specified
90
+ def start
91
+ @ports.each do |p|
92
+ @nxt.reset_motor_position(NXTComm.const_get("MOTOR_#{p.to_s.upcase}"))
93
+ end
94
+
95
+ if @direction == :stop
96
+ motor_power = 0
97
+ mode = NXTComm::COAST
98
+ run_state = NXTComm::MOTOR_RUN_STATE_IDLE
99
+ else
100
+ @direction == :forward ? motor_power = @power : motor_power = -@power
101
+ mode = NXTComm::MOTORON | NXTComm::BRAKE
102
+ run_state = NXTComm::MOTOR_RUN_STATE_RUNNING
103
+ end
104
+
105
+ if @ports.size == 2
106
+ mode |= NXTComm::REGULATED
107
+ reg_mode = NXTComm::REGULATION_MODE_MOTOR_SYNC
108
+ else
109
+ reg_mode = NXTComm::REGULATION_MODE_IDLE
110
+ end
111
+
112
+ if @ports.include?(:a) and @ports.include?(:b) and @ports.include?(:c)
113
+ @nxt.set_output_state(
114
+ NXTComm::MOTOR_ALL,
115
+ motor_power,
116
+ mode,
117
+ reg_mode,
118
+ turn_ratio,
119
+ run_state,
120
+ tacho_limit
121
+ )
122
+ else
123
+ @ports.each do |p|
124
+ @nxt.set_output_state(
125
+ NXTComm.const_get("MOTOR_#{p.to_s.upcase}"),
126
+ motor_power,
127
+ mode,
128
+ reg_mode,
129
+ turn_ratio,
130
+ run_state,
131
+ tacho_limit
132
+ )
133
+ end
134
+ end
135
+
136
+ unless @duration.nil?
137
+ if @duration[:seconds]
138
+ sleep(@duration[:seconds])
139
+ else
140
+ until self.run_state[@ports[0]] == NXTComm::MOTOR_RUN_STATE_IDLE
141
+ sleep(0.25)
142
+ end
143
+ end
144
+ self.stop
145
+ end
146
+ end
147
+
148
+ # stop the Move command based on the next_action property
149
+ def stop
150
+ if @next_action == :brake
151
+ if @ports.include?(:a) and @ports.include?(:b) and @ports.include?(:c)
152
+ @nxt.set_output_state(
153
+ NXTComm::MOTOR_ALL,
154
+ 0,
155
+ NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
156
+ NXTComm::REGULATION_MODE_MOTOR_SPEED,
157
+ 0,
158
+ NXTComm::MOTOR_RUN_STATE_RUNNING,
159
+ 0
160
+ )
161
+ else
162
+ @ports.each do |p|
163
+ @nxt.set_output_state(
164
+ NXTComm.const_get("MOTOR_#{p.to_s.upcase}"),
165
+ 0,
166
+ NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
167
+ NXTComm::REGULATION_MODE_MOTOR_SPEED,
168
+ 0,
169
+ NXTComm::MOTOR_RUN_STATE_RUNNING,
170
+ 0
171
+ )
172
+ end
173
+ end
174
+ else
175
+ if @ports.include?(:a) and @ports.include?(:b) and @ports.include?(:c)
176
+ @nxt.set_output_state(
177
+ NXTComm::MOTOR_ALL,
178
+ 0,
179
+ NXTComm::COAST,
180
+ NXTComm::REGULATION_MODE_IDLE,
181
+ 0,
182
+ NXTComm::MOTOR_RUN_STATE_IDLE,
183
+ 0
184
+ )
185
+ else
186
+ @ports.each do |p|
187
+ @nxt.set_output_state(
188
+ NXTComm.const_get("MOTOR_#{p.to_s.upcase}"),
189
+ 0,
190
+ NXTComm::COAST,
191
+ NXTComm::REGULATION_MODE_IDLE,
192
+ 0,
193
+ NXTComm::MOTOR_RUN_STATE_IDLE,
194
+ 0
195
+ )
196
+ end
197
+ end
198
+ end
199
+ end
200
+
201
+ # attempt to return the output_state requested
202
+ def method_missing(cmd)
203
+ states = {}
204
+ @ports.each do |p|
205
+ states[p] = @nxt.get_output_state(NXTComm.const_get("MOTOR_#{p.to_s.upcase}"))[cmd]
206
+ end
207
+ states
208
+ end
209
+
210
+ end