Class: Rumba

Inherits:
Object
  • Object
show all
Includes:
Constants, Dsl, Sensor
Defined in:
lib/rumba/dsl.rb,
lib/rumba.rb,
lib/rumba/sensors.rb,
lib/rumba/constants.rb

Overview

This library has a TON of annoying constants… we have quarantined them here to save your eyes

Defined Under Namespace

Modules: Constants, Dsl, Sensor

Constant Summary

Constants included from Dsl

Dsl::DEFAULT_SPEED, Dsl::RADIUS

Constants included from Sensor

Sensor::INFRARED_CHARACTER, Sensor::SENSORS_GROUP_PACKETS, Sensor::SENSORS_PACKETS_SIGNEDNESS, Sensor::SENSORS_PACKETS_SIZE, Sensor::SENSORS_PACKETS_SYMBOL, Sensor::SENSORS_PACKETS_VALUE

Constants included from Constants

Constants::DRIVE, Constants::DRIVE_DIRECT, Constants::FULL_MODE, Constants::LEDS, Constants::MOTORS, Constants::MOTORS_MASK_MAIN_BRUSH, Constants::MOTORS_MASK_SIDE_BRUSH, Constants::MOTORS_MASK_VACUUM, Constants::NOTES, Constants::OPCODES, Constants::PLAY_SONG, Constants::QUERY_LIST, Constants::SAFE_MODE, Constants::SENSORS, Constants::SONG

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Dsl

#backward, #forward, #rotate, #straight_distance

Methods included from Sensor

#get_sensor, #get_sensors, #get_sensors_list, #sensors_bytes_to_packets

Constructor Details

#initialize(port, baud = 57600, &block) ⇒ Rumba

Returns a new instance of Rumba.



197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/rumba.rb', line 197

def initialize(port, baud=57600, &block)
  @leds = {
    advance:   false,
    play:      false,
    color:     0,
    intensity: 0
  }
  
  # Initialize the serialport
  # 115200 for Roomba 5xx
  # 57600 for older models (and iRobot Create)
  @serial = SerialPort.new(port, baud)
  @serial.read_timeout = 15
  self.start

  # initialize the "DSL" here!
  if block_given?
    instance_eval(&block)

    # clean up after ourselves (this is a Roomba, after all!)
    self.power_off
  end
end

Instance Attribute Details

#serialObject

Returns the value of attribute serial.



13
14
15
# File 'lib/rumba.rb', line 13

def serial
  @serial
end

Instance Method Details

#battery_percentageObject



172
173
174
175
# File 'lib/rumba.rb', line 172

def battery_percentage
  sensors = get_sensors(3)
  ((sensors[:battery_charge].to_f / sensors[:battery_capacity].to_f) * 100).to_i
end

#convert_int(int) ⇒ Object

Convert integer to two’s complement signed 16 bit integer. Note that the Roomba is big-endian…I need to fix this code to make it portable across different architectures.



64
65
66
# File 'lib/rumba.rb', line 64

def convert_int(int)
  [int].pack('s').reverse
end

#drive(velocity, radius) ⇒ Object

Raises:

  • (RangeError)


83
84
85
86
87
88
89
90
# File 'lib/rumba.rb', line 83

def drive(velocity, radius)
  raise RangeError if velocity < -500 || velocity > 500
  raise RangeError if (radius < -2000 || radius > 2000) && radius != 0xFFFF
  
  velocity = convert_int(velocity)
  radius   = convert_int(radius)
  write_chars([DRIVE, velocity, radius])
end

#drive_direct(left, right) ⇒ Object

Raises:

  • (RangeError)


92
93
94
95
96
97
98
99
100
101
# File 'lib/rumba.rb', line 92

def drive_direct(left, right)
  raise RangeError if left  < -500 || left  > 500
  raise RangeError if right < -500 || right > 500
  
  left  = convert_int(left)
  right = convert_int(right)
  
  write_chars([DRIVE_DIRECT])
  write_raw([right, left])
end

#full_modeObject



77
78
79
80
81
# File 'lib/rumba.rb', line 77

def full_mode
  safe_mode
  write_chars([FULL_MODE])
  sleep(0.2)
end

#haltObject



164
165
166
# File 'lib/rumba.rb', line 164

def halt
  drive(0,0)
end

#lightsObject



160
161
162
# File 'lib/rumba.rb', line 160

def lights
  write_chars([139, 9, 0, 128])
end

#play_song(song_number) ⇒ Object

Raises:

  • (RangeError)


136
137
138
139
# File 'lib/rumba.rb', line 136

def play_song(song_number)
  raise RangeError if song_number < 0 || song_number > 15
  write_chars([PLAY_SONG,song_number])
end

#power_offObject



168
169
170
# File 'lib/rumba.rb', line 168

def power_off
  @serial.close
end

#safe_modeObject

COMMANDS #



72
73
74
75
# File 'lib/rumba.rb', line 72

def safe_mode
  write_chars([SAFE_MODE])
  sleep(0.2)
end

#set_leds(args) ⇒ Object

Turn LEDs on and off Arguments are a hash in the following format: :advance => true/false | sets the “advance” LED (the >> one) :play => true/false | sets the “play” LED (the > one) :color => 0-255 | sets the color of the power LED (0 = green, 255 = red) :intensity => 0-255 | sets the intensity of the power LED (0 = off)



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/rumba.rb', line 109

def set_leds(args)
  @leds[:advance]   = args[:advance]   unless args[:advance].nil?
  @leds[:play]      = args[:play]      unless args[:play].nil?
  @leds[:color]     = args[:color]     unless args[:color].nil?
  @leds[:intensity] = args[:intensity] unless args[:intensity].nil?
  led_bits  = 0b00000000
  led_bits |= 0b00001000 if @leds[:advance]
  led_bits |= 0b00000010 if @leds[:play]
  
  write_chars([LEDS, led_bits, @leds[:color], @leds[:intensity]])
end

#song(song_number, notes) ⇒ Object

Songs are cool. Here’s the format: The song number designates which song this is so you can recall it later. The notes are specified in the NOTES hash, and are fed into the program as a 2D array, where the first element is the note number and the second is the duration of the note. The duration is specified in seconds. Example:

[note1,5], [note2,6]

Raises:

  • (RangeError)


128
129
130
131
132
133
134
# File 'lib/rumba.rb', line 128

def song(song_number, notes)
  raise RangeError if song_number < 0 || song_number > 15
  
  notes.map! { |n| [NOTES[n[0]],n[1]*64] }
  # The protocol requires us to send the number of notes and the song number first
  write_chars([SONG, song_number, notes.size] + notes.flatten)
end

#spin_left(speed) ⇒ Object



150
151
152
153
# File 'lib/rumba.rb', line 150

def spin_left(speed)
  speed = convert_int(speed)
  write_chars([DRIVE, speed, convert_int(1)])
end

#spin_right(speed) ⇒ Object



155
156
157
158
# File 'lib/rumba.rb', line 155

def spin_right(speed)
  speed = convert_int(speed)
  write_chars([DRIVE, speed, convert_int(-1)])
end

#start_all_motorsObject



181
182
183
# File 'lib/rumba.rb', line 181

def start_all_motors
  write_chars([MOTORS,MOTORS_MASK_SIDE_BRUSH|MOTORS_MASK_VACUUM|MOTORS_MASK_MAIN_BRUSH])
end

#start_main_brush_motorObject



193
194
195
# File 'lib/rumba.rb', line 193

def start_main_brush_motor
  write_chars([MOTORS,MOTORS_MASK_MAIN_BRUSH])
end

#start_side_brush_motorObject



185
186
187
# File 'lib/rumba.rb', line 185

def start_side_brush_motor
  write_chars([MOTORS,MOTORS_MASK_SIDE_BRUSH])
end

#start_vacumm_motorObject



189
190
191
# File 'lib/rumba.rb', line 189

def start_vacumm_motor
  write_chars([MOTORS,MOTORS_MASK_VACUUM])
end

#stop_all_motorsObject



177
178
179
# File 'lib/rumba.rb', line 177

def stop_all_motors
  write_chars([MOTORS,0])
end

#straight(speed) ⇒ Object

Convenience methods #



145
146
147
148
# File 'lib/rumba.rb', line 145

def straight(speed)
  speed = convert_int(speed)
  write_chars([DRIVE, speed, convert_int(32768)])
end

#write_chars(data) ⇒ Object

Converts input data (an array) into bytes before sending it over the serial connection.



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/rumba.rb', line 21

def write_chars(data)
  data.map! do |c|
    if c.class == String
      result = c.bytes.to_a.map { |b| [b].pack("C") }
    else
      result = [c].pack("C")
    end
    
    result
  end
  
  data = data.flatten.join
  
  @serial.write(data)
  @serial.flush
end

#write_chars_with_read(data) ⇒ Object

Write data then read response



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/rumba.rb', line 39

def write_chars_with_read(data)
  data.map! do |c|
    if c.class == String
      result = c.bytes.to_a.map { |b| [b].pack("C") }
    else
      result = [c].pack("C")
    end
    
    result
  end
  
  data = data.flatten.join
  
  @serial.write(data)
  sleep(0.05)
  data=""
  while(data.length==0)
    data += @serial.read
  end
  data
end