ruby-nxt 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +340 -0
- data/README +49 -0
- data/examples/commands.rb +180 -0
- data/examples/drb_client.rb +11 -0
- data/examples/drb_server.rb +40 -0
- data/examples/mary.rb +78 -0
- data/examples/move_by_degrees.rb +42 -0
- data/examples/nxt_comm_demo.rb +65 -0
- data/examples/nxt_remote_control.rb +70 -0
- data/examples/socket_server.rb +37 -0
- data/lib/autodetect_nxt.rb +36 -0
- data/lib/brick.rb +53 -0
- data/lib/commands.rb +40 -0
- data/lib/commands/light_sensor.rb +82 -0
- data/lib/commands/mixins/motor.rb +84 -0
- data/lib/commands/mixins/sensor.rb +38 -0
- data/lib/commands/motor.rb +136 -0
- data/lib/commands/move.rb +210 -0
- data/lib/commands/rotation_sensor.rb +72 -0
- data/lib/commands/sound.rb +102 -0
- data/lib/commands/sound_sensor.rb +67 -0
- data/lib/commands/touch_sensor.rb +84 -0
- data/lib/commands/ultrasonic_sensor.rb +84 -0
- data/lib/motor.rb +235 -0
- data/lib/nxt.rb +189 -0
- data/lib/nxt_comm.rb +596 -0
- data/lib/sensors/light_sensor.rb +45 -0
- data/lib/sensors/sensor.rb +93 -0
- data/lib/sensors/sound_sensor.rb +48 -0
- data/lib/sensors/touch_sensor.rb +35 -0
- data/lib/sensors/ultrasonic_sensor.rb +95 -0
- data/lib/ultrasonic_comm.rb +102 -0
- data/test/bt_test.rb +10 -0
- data/test/interactive/interactive_test_helper.rb +89 -0
- data/test/interactive/test_sensors.rb +236 -0
- data/test/test.rb +22 -0
- data/test/test_helper.rb +1 -0
- data/test/unit/motor_test.rb +177 -0
- data/test/unit/nxt_comm_test.rb +155 -0
- data/test/unit/nxt_test.rb +60 -0
- metadata +95 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# example code showing how to make a drb server to communicate with nxt
|
3
|
+
# it also spawns a thread that periodically calls keep_alive to prevent
|
4
|
+
# the nxt from going to sleep
|
5
|
+
|
6
|
+
require "drb"
|
7
|
+
require "thread"
|
8
|
+
require "nxt_comm"
|
9
|
+
|
10
|
+
$DEBUG = false
|
11
|
+
$DEV = '/dev/tty.NXT-DevB-1'
|
12
|
+
$SAFE = 1 # disable eval() and friends
|
13
|
+
|
14
|
+
class NXTServer
|
15
|
+
def initialize(dev=$DEV,port=9000)
|
16
|
+
@nxt = NXTComm.new(dev)
|
17
|
+
@last_keep_alive = Time.now
|
18
|
+
@keep_alive_time = 300
|
19
|
+
|
20
|
+
Thread.new do
|
21
|
+
DRb.start_service "druby://localhost:#{port}", @nxt
|
22
|
+
puts "NXTServer ready at: #{DRb.uri}"
|
23
|
+
end
|
24
|
+
|
25
|
+
Thread.new do
|
26
|
+
loop do
|
27
|
+
if Time.now - @last_keep_alive > @keep_alive_time / 2
|
28
|
+
@keep_alive_time = @nxt.keep_alive / 1000
|
29
|
+
puts "Sending next keep alive in #{@keep_alive_time / 2} seconds..."
|
30
|
+
@last_keep_alive = Time.now
|
31
|
+
end
|
32
|
+
# need small sleep time or DRb thread won't have time to fire
|
33
|
+
# I can't get it to work if I just sleep the keep_alive interval
|
34
|
+
sleep 1
|
35
|
+
end
|
36
|
+
end.join # make thread block
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
server = NXTServer.new
|
data/examples/mary.rb
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
# Plays "Mary Had A Little Lamb"
|
4
|
+
# Author: Christopher Continanza <christopher.continanza@villanova.edu>
|
5
|
+
|
6
|
+
require "nxt_comm"
|
7
|
+
|
8
|
+
$DEBUG = true
|
9
|
+
|
10
|
+
def sleeper
|
11
|
+
sleep(0.5)
|
12
|
+
end
|
13
|
+
|
14
|
+
@nxt = NXTComm.new("/dev/tty.NXT-DevB-1")
|
15
|
+
|
16
|
+
#E D C D E E E
|
17
|
+
@nxt.play_tone(659,500)
|
18
|
+
sleeper
|
19
|
+
@nxt.play_tone(587,500)
|
20
|
+
sleeper
|
21
|
+
@nxt.play_tone(523,500)
|
22
|
+
sleeper
|
23
|
+
@nxt.play_tone(587,500)
|
24
|
+
sleeper
|
25
|
+
@nxt.play_tone(659,500)
|
26
|
+
sleeper
|
27
|
+
@nxt.play_tone(659,500)
|
28
|
+
sleeper
|
29
|
+
@nxt.play_tone(659,500)
|
30
|
+
sleeper
|
31
|
+
sleeper
|
32
|
+
#D D D E G G
|
33
|
+
@nxt.play_tone(587,500)
|
34
|
+
sleeper
|
35
|
+
@nxt.play_tone(587,500)
|
36
|
+
sleeper
|
37
|
+
@nxt.play_tone(587,500)
|
38
|
+
sleeper
|
39
|
+
sleeper
|
40
|
+
@nxt.play_tone(659,500)
|
41
|
+
sleeper
|
42
|
+
@nxt.play_tone(784,500)
|
43
|
+
sleeper
|
44
|
+
@nxt.play_tone(784,500)
|
45
|
+
sleeper
|
46
|
+
sleeper
|
47
|
+
#E D C D E E E
|
48
|
+
@nxt.play_tone(659,500)
|
49
|
+
sleeper
|
50
|
+
@nxt.play_tone(587,500)
|
51
|
+
sleeper
|
52
|
+
@nxt.play_tone(523,500)
|
53
|
+
sleeper
|
54
|
+
@nxt.play_tone(587,500)
|
55
|
+
sleeper
|
56
|
+
@nxt.play_tone(659,500)
|
57
|
+
sleeper
|
58
|
+
@nxt.play_tone(659,500)
|
59
|
+
sleeper
|
60
|
+
@nxt.play_tone(659,500)
|
61
|
+
sleeper
|
62
|
+
#E D D E D C
|
63
|
+
@nxt.play_tone(659,500)
|
64
|
+
sleeper
|
65
|
+
@nxt.play_tone(587,500)
|
66
|
+
sleeper
|
67
|
+
@nxt.play_tone(587,500)
|
68
|
+
sleeper
|
69
|
+
@nxt.play_tone(659,500)
|
70
|
+
sleeper
|
71
|
+
@nxt.play_tone(587,500)
|
72
|
+
sleeper
|
73
|
+
@nxt.play_tone(523,750)
|
74
|
+
sleeper
|
75
|
+
sleeper
|
76
|
+
sleeper
|
77
|
+
|
78
|
+
@nxt.close
|
@@ -0,0 +1,42 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
|
3
|
+
require "nxt_comm"
|
4
|
+
|
5
|
+
$DEBUG = false
|
6
|
+
|
7
|
+
@nxt = NXTComm.new('/dev/tty.NXT-DevB-1')
|
8
|
+
@degrees = 360
|
9
|
+
@motor = NXTComm::MOTOR_B
|
10
|
+
|
11
|
+
# set the tacho_count = 0
|
12
|
+
@nxt.reset_motor_position(@motor)
|
13
|
+
|
14
|
+
puts @nxt.get_output_state(@motor).inspect
|
15
|
+
|
16
|
+
# ramps up to (close to) requested degrees and then if no other command is sent, it will
|
17
|
+
# try to return to the requested degrees if force moves motor
|
18
|
+
|
19
|
+
# have to start at least power = 1 to ramp up
|
20
|
+
@nxt.set_output_state(@motor,1,NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
|
21
|
+
NXTComm::REGULATION_MODE_MOTOR_SPEED,0,NXTComm::MOTOR_RUN_STATE_RUNNING,0)
|
22
|
+
|
23
|
+
# ramp up to the requested degrees
|
24
|
+
@nxt.set_output_state(@motor,75,NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
|
25
|
+
NXTComm::REGULATION_MODE_MOTOR_SPEED,0,NXTComm::MOTOR_RUN_STATE_RAMPUP,@degrees)
|
26
|
+
|
27
|
+
until @nxt.get_output_state(@motor)[:run_state] == NXTComm::MOTOR_RUN_STATE_IDLE
|
28
|
+
puts @nxt.get_output_state(@motor).inspect
|
29
|
+
sleep(0.5)
|
30
|
+
end
|
31
|
+
|
32
|
+
# abruptly break and use power to prevent movement
|
33
|
+
# @nxt.set_output_state(@motor,0,NXTComm::MOTORON | NXTComm::BRAKE | NXTComm::REGULATED,
|
34
|
+
# NXTComm::REGULATION_MODE_MOTOR_SPEED,0,NXTComm::MOTOR_RUN_STATE_RUNNING,0)
|
35
|
+
|
36
|
+
# coast to a stop and allow force to move motor
|
37
|
+
# @nxt.set_output_state(@motor,0,NXTComm::COAST,
|
38
|
+
# NXTComm::REGULATION_MODE_IDLE,0,NXTComm::MOTOR_RUN_STATE_IDLE,0)
|
39
|
+
|
40
|
+
puts @nxt.get_output_state(@motor).inspect
|
41
|
+
|
42
|
+
@nxt.close
|
@@ -0,0 +1,65 @@
|
|
1
|
+
#!/usr/local/bin/ruby
|
2
|
+
|
3
|
+
require "nxt_comm"
|
4
|
+
|
5
|
+
$DEBUG = false
|
6
|
+
|
7
|
+
@nxt = NXTComm.new("/dev/tty.NXT-DevB-1")
|
8
|
+
# puts "Connected!"
|
9
|
+
#
|
10
|
+
# puts "Starting program"
|
11
|
+
# @nxt.start_program("Try-Touch.rtm")
|
12
|
+
# sleep(3)
|
13
|
+
# puts "Currently running: " + @nxt.get_current_program_name
|
14
|
+
# puts "Stopping program"
|
15
|
+
# @nxt.stop_program
|
16
|
+
#
|
17
|
+
# @nxt.play_sound_file("Good Job.rso")
|
18
|
+
|
19
|
+
@nxt.play_tone(500,500)
|
20
|
+
|
21
|
+
# @nxt.set_output_state(
|
22
|
+
# NXTComm::MOTOR_A,
|
23
|
+
# 100,
|
24
|
+
# NXTComm::REGULATED,
|
25
|
+
# NXTComm::REGULATION_MODE_MOTOR_SPEED,
|
26
|
+
# 100,
|
27
|
+
# NXTComm::MOTOR_RUN_STATE_RUNNING,
|
28
|
+
# 0
|
29
|
+
# )
|
30
|
+
# sleep(3)
|
31
|
+
# @nxt.set_output_state(
|
32
|
+
# NXTComm::MOTOR_A,
|
33
|
+
# 100,
|
34
|
+
# NXTComm::BRAKE,
|
35
|
+
# NXTComm::REGULATION_MODE_MOTOR_SPEED,
|
36
|
+
# 0,
|
37
|
+
# NXTComm::MOTOR_RUN_STATE_RAMPDOWN,
|
38
|
+
# 0
|
39
|
+
# )
|
40
|
+
|
41
|
+
# set_input_mode(port,type,mode)
|
42
|
+
# @nxt.set_input_mode(NXTComm::SENSOR_3,NXTComm::LIGHT_INACTIVE,NXTComm::RAWMODE)
|
43
|
+
# while true
|
44
|
+
# s = @nxt.get_input_values(NXTComm::SENSOR_3)
|
45
|
+
# puts s.inspect
|
46
|
+
# sleep(1)
|
47
|
+
# end
|
48
|
+
|
49
|
+
# puts @nxt.get_output_state(NXTComm::MOTOR_B).inspect
|
50
|
+
|
51
|
+
# puts @nxt.get_input_values(NXTComm::SENSOR_1).inspect
|
52
|
+
|
53
|
+
# @nxt.reset_input_scaled_value(NXTComm::SENSOR_1)
|
54
|
+
|
55
|
+
# @nxt.message_write(1,"Chunky Robotic Bacon!")
|
56
|
+
|
57
|
+
# @nxt.reset_motor_position(NXTComm::MOTOR_B)
|
58
|
+
|
59
|
+
# puts "Battery Level: #{@nxt.get_battery_level/1000.0} V"
|
60
|
+
|
61
|
+
#@nxt.play_sound_file("Woops.rso",true)
|
62
|
+
#sleep(2)
|
63
|
+
#@nxt.stop_sound_playback
|
64
|
+
|
65
|
+
@nxt.close
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "tk"
|
4
|
+
require "nxt"
|
5
|
+
|
6
|
+
class NXTRemoteControl
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@nxt = NXTComm.new($DEV)
|
10
|
+
ph = { 'padx' => 10, 'pady' => 10 }
|
11
|
+
root = TkRoot.new { title "NXT Remote Control" }
|
12
|
+
top = TkFrame.new(root)
|
13
|
+
|
14
|
+
_forward = proc{forward}
|
15
|
+
_backward = proc{backward}
|
16
|
+
_left = proc{left}
|
17
|
+
_right = proc{right}
|
18
|
+
_stop = proc{stop}
|
19
|
+
|
20
|
+
@text = TkVariable.new
|
21
|
+
@entry = TkEntry.new(top, 'textvariable' => @text)
|
22
|
+
@entry.pack(ph)
|
23
|
+
|
24
|
+
TkButton.new(top) {text 'Forward'; command _forward; pack ph}
|
25
|
+
TkButton.new(top) {text 'Backward'; command _backward; pack ph}
|
26
|
+
TkButton.new(top) {text 'Left'; command _left; pack ph}
|
27
|
+
TkButton.new(top) {text 'Right'; command _right; pack ph}
|
28
|
+
TkButton.new(top) {text 'Stop'; command _stop; pack ph}
|
29
|
+
|
30
|
+
TkButton.new(top) {text 'Exit'; command {proc exit}; pack ph}
|
31
|
+
|
32
|
+
top.pack('fill'=>'both', 'side' =>'top')
|
33
|
+
end
|
34
|
+
|
35
|
+
def forward
|
36
|
+
@text.value = "Moving forward..."
|
37
|
+
@m = Commands::Move.new(@nxt)
|
38
|
+
@m.start
|
39
|
+
end
|
40
|
+
|
41
|
+
def backward
|
42
|
+
@text.value = "Moving backward..."
|
43
|
+
@m = Commands::Move.new(@nxt)
|
44
|
+
@m.direction = :backward
|
45
|
+
@m.start
|
46
|
+
end
|
47
|
+
|
48
|
+
def left
|
49
|
+
@text.value = "Turning left"
|
50
|
+
@m = Commands::Move.new(@nxt)
|
51
|
+
@m.steering = :left
|
52
|
+
@m.start
|
53
|
+
end
|
54
|
+
|
55
|
+
def right
|
56
|
+
@text.value = "Turning right"
|
57
|
+
@m = Commands::Move.new(@nxt)
|
58
|
+
@m.steering = :right
|
59
|
+
@m.start
|
60
|
+
end
|
61
|
+
|
62
|
+
def stop
|
63
|
+
@text.value = "Stopping"
|
64
|
+
@m = Commands::Move.new(@nxt)
|
65
|
+
@m.stop
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
NXTRemoteControl.new
|
70
|
+
Tk.mainloop
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby -w
|
2
|
+
# example code showing how to make a socket server to communicate with nxt
|
3
|
+
# To use it via telnet:
|
4
|
+
# telnet localhost 3001
|
5
|
+
# type forward then enter
|
6
|
+
|
7
|
+
require "socket"
|
8
|
+
require "nxt_comm"
|
9
|
+
|
10
|
+
$DEBUG = true
|
11
|
+
|
12
|
+
@port = (ARGV[0] || 3001).to_i
|
13
|
+
@server = TCPServer.new('localhost', @port)
|
14
|
+
@nxt = NXTComm.new('/dev/tty.NXT-DevB-1')
|
15
|
+
|
16
|
+
@move = Commands::Move.new(@nxt)
|
17
|
+
|
18
|
+
puts "Ready."
|
19
|
+
|
20
|
+
while (@session = @server.accept)
|
21
|
+
|
22
|
+
@request = @session.gets
|
23
|
+
|
24
|
+
puts "Request: #{@request}"
|
25
|
+
|
26
|
+
case @request.chomp
|
27
|
+
when "forward"
|
28
|
+
@move.start
|
29
|
+
when "stop"
|
30
|
+
@move.stop
|
31
|
+
else
|
32
|
+
@session.puts "Unknown request: #{@request}"
|
33
|
+
end
|
34
|
+
|
35
|
+
@session.close
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
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
|
+
|
18
|
+
# This script attempts to automatically set the global $DEV variable
|
19
|
+
# by searching for a NXT tty device node.
|
20
|
+
|
21
|
+
# TODO: This curently only works on *nix based systems (MacOS X too!)
|
22
|
+
# I don't know how to implement this for Win32 :(
|
23
|
+
|
24
|
+
# If there is an NXT or DEV environment variable, or a $DEV global,
|
25
|
+
# we'll use that and not try to auto-set it ourselves.
|
26
|
+
$DEV = $DEV || ENV['NXT'] || ENV['DEV']
|
27
|
+
|
28
|
+
unless $DEV or ENV['NXT'] or ENV['DEV']
|
29
|
+
begin
|
30
|
+
devices = Dir["/dev/*NXT*"]
|
31
|
+
$DEV = devices[0] if devices.size > 0
|
32
|
+
puts "Auto-detected NXT at #{$DEV}"
|
33
|
+
rescue
|
34
|
+
# the /dev directory probably doesn't exist... maybe we're on Win32?
|
35
|
+
end
|
36
|
+
end
|
data/lib/brick.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# ruby-nxt Control Mindstorms NXT via Bluetooth Serial Port Connection
|
2
|
+
# Copyright (C) 2006 Matt Zukowski <matt@roughest.net>
|
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 "yaml"
|
18
|
+
require "logger"
|
19
|
+
require "nxt_comm"
|
20
|
+
|
21
|
+
#Logger::Formatter::Format = "%s, [%s#%d] %5s -- %s:\n%s\n"
|
22
|
+
|
23
|
+
# Abstract parent class of motor and sensor bricks.
|
24
|
+
# Currently provides only very basic common functionality but may
|
25
|
+
# be expanded in the future.
|
26
|
+
class Brick
|
27
|
+
|
28
|
+
attr_reader :port
|
29
|
+
attr_reader :log
|
30
|
+
|
31
|
+
def initialize(nxt, port)
|
32
|
+
logfile = File.expand_path(File.dirname(File.expand_path(__FILE__)))+"/../log/#{self.class}_#{port}.log"
|
33
|
+
@log = Logger.new logfile
|
34
|
+
@log.level = Logger::DEBUG
|
35
|
+
#puts "Logging to #{logfile}"
|
36
|
+
|
37
|
+
debug("#{self.class}::#{nxt}(#{port})", :initialize)
|
38
|
+
|
39
|
+
@nxt = nxt
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def debug(msg, method = false)
|
44
|
+
@log.info(method) do
|
45
|
+
if msg.kind_of? String
|
46
|
+
msg
|
47
|
+
else
|
48
|
+
msg.to_yaml
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
data/lib/commands.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# Command object based interface that implements the "blocks" in NXT-G. This should
|
2
|
+
# be easy to understand if you are familiar with the NXT-G graphical programming
|
3
|
+
# system. This is automatically included in NXTComm.
|
4
|
+
#
|
5
|
+
# === Example
|
6
|
+
#
|
7
|
+
# require 'nxt_comm'
|
8
|
+
#
|
9
|
+
# @nxt = NXTComm.new('/dev/tty.NXT-DevB-1')
|
10
|
+
#
|
11
|
+
# # more examples can be found in examples/commands.rb
|
12
|
+
#
|
13
|
+
# us = Commands::UltrasonicSensor.new(@nxt)
|
14
|
+
# us.mode = :centimeters
|
15
|
+
# puts "Distance: #{us.distance}cm"
|
16
|
+
# us.mode = :inches
|
17
|
+
# puts "Distance: #{us.distance}in"
|
18
|
+
#
|
19
|
+
# us.comparison = "<"
|
20
|
+
# us.trigger_point = 5
|
21
|
+
#
|
22
|
+
# while us.logic == false
|
23
|
+
# sleep(0.5)
|
24
|
+
# puts "Move #{us.comparison} #{us.trigger_point} #{us.mode} from the sensor..."
|
25
|
+
# puts "Distance: #{us.distance}in"
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# puts "Got it!"
|
29
|
+
#
|
30
|
+
module Commands
|
31
|
+
require 'commands/move'
|
32
|
+
require 'commands/sound'
|
33
|
+
require 'commands/motor'
|
34
|
+
|
35
|
+
require 'commands/touch_sensor'
|
36
|
+
require 'commands/sound_sensor'
|
37
|
+
require 'commands/light_sensor'
|
38
|
+
require 'commands/ultrasonic_sensor'
|
39
|
+
require 'commands/rotation_sensor'
|
40
|
+
end
|