rumba 0.1.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 +7 -0
- data/lib/rumba.rb +193 -0
- metadata +58 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 115b8d8b186d7f86152bbff988ac8b0fae8fcc39
|
4
|
+
data.tar.gz: ba6345f5aaaf814e2c4a10aa55b2493c26cd7e4d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f71cc909ed9079bb10054cdd86b972e9fa1daa5d7561fdb4d97796829bdd3aefbed720eedd63140be9388c2bed6957ceb0cdce642a4aa5146dae77724d3965ce
|
7
|
+
data.tar.gz: 9eb5465a3e7dbaca2e72b782a07955420edf819ceaab878090867cbc754924e9dcf7238a84517c4730b94f8be4aaf57ae9741da2dfdc743c948c2a15f10361b7
|
data/lib/rumba.rb
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'serialport'
|
3
|
+
require 'timeout'
|
4
|
+
|
5
|
+
class Roomba
|
6
|
+
# These opcodes require no arguments
|
7
|
+
OPCODES = {
|
8
|
+
start: 128,
|
9
|
+
control: 130,
|
10
|
+
dock: 143,
|
11
|
+
play_script: 153,
|
12
|
+
show_script: 154
|
13
|
+
}
|
14
|
+
|
15
|
+
# Create a method for each opcode that writes its data.
|
16
|
+
# This allows us to simply call roomba.code,
|
17
|
+
# and it's a cool excuse to do some metaprogramming :)
|
18
|
+
OPCODES.each do |name,val|
|
19
|
+
send :define_method, name do
|
20
|
+
write_chars([val])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
SAFE_MODE = 131
|
25
|
+
FULL_MODE = 132
|
26
|
+
|
27
|
+
# These opcodes require arguments
|
28
|
+
DRIVE = 137
|
29
|
+
LEDS = 139
|
30
|
+
SONG = 140
|
31
|
+
PLAY_SONG = 141
|
32
|
+
DRIVE_DIRECT = 145
|
33
|
+
|
34
|
+
# Used for making the Roomba sing!
|
35
|
+
# Note that nil is simply a rest
|
36
|
+
NOTES = {
|
37
|
+
'A' => 69, 'A#' => 70, 'B' => 71, 'C' => 72, 'C#' => 73, 'D' => 74,
|
38
|
+
'D#' => 75, 'E' => 76, 'F' => 77, 'F#' => 78, 'G' => 79, 'G#' => 80,
|
39
|
+
nil => 0
|
40
|
+
}
|
41
|
+
|
42
|
+
#############################################################################
|
43
|
+
# HELPERS #
|
44
|
+
#############################################################################
|
45
|
+
|
46
|
+
# Converts input data (an array) into bytes before
|
47
|
+
# sending it over the serial connection.
|
48
|
+
def write_chars(data);
|
49
|
+
data.map! do |c|
|
50
|
+
if c.class == String
|
51
|
+
result = c.bytes.to_a.map { |b| [b].pack("C") }
|
52
|
+
else
|
53
|
+
result = [c].pack("C")
|
54
|
+
end
|
55
|
+
|
56
|
+
result
|
57
|
+
end
|
58
|
+
|
59
|
+
data = data.flatten.join
|
60
|
+
|
61
|
+
@serial.write(data)
|
62
|
+
@serial.flush
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert integer to two's complement signed 16 bit integer.
|
66
|
+
# Note that the Roomba is big-endian...I need to fix this
|
67
|
+
# code to make it portable across different architectures.
|
68
|
+
def convert_int(int)
|
69
|
+
[int].pack('s').reverse
|
70
|
+
end
|
71
|
+
|
72
|
+
#############################################################################
|
73
|
+
# COMMANDS #
|
74
|
+
#############################################################################
|
75
|
+
|
76
|
+
def safe_mode
|
77
|
+
write_chars([SAFE_MODE])
|
78
|
+
sleep(0.2)
|
79
|
+
end
|
80
|
+
|
81
|
+
def full_mode
|
82
|
+
safe_mode
|
83
|
+
write_chars([FULL_MODE])
|
84
|
+
sleep(0.2)
|
85
|
+
end
|
86
|
+
|
87
|
+
def drive(velocity, radius)
|
88
|
+
raise RangeError if velocity < -500 || velocity > 500
|
89
|
+
raise RangeError if (radius < -2000 || radius > 2000) && radius != 0xFFFF
|
90
|
+
|
91
|
+
velocity = convert_int(velocity)
|
92
|
+
radius = convert_int(radius)
|
93
|
+
write_chars([DRIVE, velocity, radius])
|
94
|
+
end
|
95
|
+
|
96
|
+
def drive_direct(left, right)
|
97
|
+
raise RangeError if left < -500 || left > 500
|
98
|
+
raise RangeError if right < -500 || right > 500
|
99
|
+
|
100
|
+
left = convert_int(left)
|
101
|
+
right = convert_int(right)
|
102
|
+
|
103
|
+
write_chars([DRIVE_DIRECT])
|
104
|
+
write_raw([right, left])
|
105
|
+
end
|
106
|
+
|
107
|
+
# Turn LEDs on and off
|
108
|
+
# Arguments are a hash in the following format:
|
109
|
+
# :advance => true/false | sets the "advance" LED (the >> one)
|
110
|
+
# :play => true/false | sets the "play" LED (the > one)
|
111
|
+
# :color => 0-255 | sets the color of the power LED (0 = green, 255 = red)
|
112
|
+
# :intensity => 0-255 | sets the intensity of the power LED (0 = off)
|
113
|
+
def set_leds(args)
|
114
|
+
@leds[:advance] = args[:advance] unless args[:advance].nil?
|
115
|
+
@leds[:play] = args[:play] unless args[:play].nil?
|
116
|
+
@leds[:color] = args[:color] unless args[:color].nil?
|
117
|
+
@leds[:intensity] = args[:intensity] unless args[:intensity].nil?
|
118
|
+
led_bits = 0b00000000
|
119
|
+
led_bits |= 0b00001000 if @leds[:advance]
|
120
|
+
led_bits |= 0b00000010 if @leds[:play]
|
121
|
+
|
122
|
+
write_chars([LEDS, led_bits, @leds[:color], @leds[:intensity]])
|
123
|
+
end
|
124
|
+
|
125
|
+
# Songs are cool. Here's the format:
|
126
|
+
# The song number designates which song this is so you can recall it later.
|
127
|
+
# The notes are specified in the NOTES hash, and are fed into the program
|
128
|
+
# as a 2D array, where the first element is the note number and the second
|
129
|
+
# is the duration of the note. The duration is specified in seconds.
|
130
|
+
# Example:
|
131
|
+
# [[note1,5], [note2,6]]
|
132
|
+
def song(song_number, notes)
|
133
|
+
raise RangeError if song_number < 0 || song_number > 15
|
134
|
+
|
135
|
+
notes.map! { |n| [NOTES[n[0]],n[1]*64] }
|
136
|
+
# The protocol requires us to send the number of notes and the song number first
|
137
|
+
write_chars([SONG, song_number, notes.size] + notes.flatten)
|
138
|
+
end
|
139
|
+
|
140
|
+
def play_song(song_number)
|
141
|
+
raise RangeError if song_number < 0 || song_number > 15
|
142
|
+
write_chars([PLAY_SONG,song_number])
|
143
|
+
end
|
144
|
+
|
145
|
+
#############################################################################
|
146
|
+
# Convenience methods #
|
147
|
+
#############################################################################
|
148
|
+
|
149
|
+
def straight(speed)
|
150
|
+
speed = convert_int(speed)
|
151
|
+
write_chars([DRIVE, speed, convert_int(32768)])
|
152
|
+
end
|
153
|
+
|
154
|
+
def spin_left(speed)
|
155
|
+
speed = convert_int(speed)
|
156
|
+
write_chars([DRIVE, speed, convert_int(1)])
|
157
|
+
end
|
158
|
+
|
159
|
+
def spin_right(speed)
|
160
|
+
speed = convert_int(speed)
|
161
|
+
write_chars([DRIVE, speed, convert_int(-1)])
|
162
|
+
end
|
163
|
+
|
164
|
+
def lights
|
165
|
+
write_chars([139, 9, 0, 128])
|
166
|
+
end
|
167
|
+
|
168
|
+
def halt
|
169
|
+
drive(0,0)
|
170
|
+
end
|
171
|
+
|
172
|
+
def power_off
|
173
|
+
@serial.close
|
174
|
+
end
|
175
|
+
|
176
|
+
def initialize(port, timeout=10)
|
177
|
+
@leds = {
|
178
|
+
advance: false,
|
179
|
+
play: false,
|
180
|
+
color: 0,
|
181
|
+
intensity: 0
|
182
|
+
}
|
183
|
+
|
184
|
+
@timeout = timeout
|
185
|
+
Timeout::timeout(@timeout) do
|
186
|
+
# Initialize the serialport
|
187
|
+
@serial = SerialPort.new(port, 57600)
|
188
|
+
@serial.read_timeout = 1000
|
189
|
+
self.start
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
metadata
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rumba
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Eric Wood
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-27 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: serialport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
description: Control your Roomba using Ruby!
|
28
|
+
email: eric@ericwood.org
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- lib/rumba.rb
|
34
|
+
homepage: http://github.com/eric-wood/roomba
|
35
|
+
licenses:
|
36
|
+
- BSD
|
37
|
+
metadata: {}
|
38
|
+
post_install_message:
|
39
|
+
rdoc_options: []
|
40
|
+
require_paths:
|
41
|
+
- lib
|
42
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '0'
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '0'
|
52
|
+
requirements: []
|
53
|
+
rubyforge_project:
|
54
|
+
rubygems_version: 2.2.2
|
55
|
+
signing_key:
|
56
|
+
specification_version: 4
|
57
|
+
summary: Ruby bindings for the iRobot Roomba
|
58
|
+
test_files: []
|