Class: FB::Arduino

Inherits:
Object
  • Object
show all
Defined in:
lib/arduino.rb

Overview

Software abstraction layer for the Arduino’s serial interface. Translates Ruby method calls into serial commands.

Defined Under Namespace

Classes: Position

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(serial_port: DefaultSerialPort.new, logger: STDOUT) ⇒ Arduino

Initialize and provide a serial object, as well as an IO object to send log messages to. Default SerialPort is DefaultSerialPort. Default logger is STDOUT



19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/arduino.rb', line 19

def initialize(serial_port: DefaultSerialPort.new, logger: STDOUT)
  @outbound_queue = [] # Pi -> Arduino Gcode
  @inbound_queue  = EM::Channel.new # Pi <- Arduino

  @serial_port = serial_port
  @logger      = logger
  @commands    = FB::OutgoingHandler.new(self)
  @inputs      = FB::IncomingHandler.new(self)
  @status      = FB::Status.new

  start_event_listeners
end

Instance Attribute Details

#commandsObject

Returns the value of attribute commands.



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

def commands
  @commands
end

#inbound_queueObject

Returns the value of attribute inbound_queue.



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

def inbound_queue
  @inbound_queue
end

#inputsObject

Returns the value of attribute inputs.



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

def inputs
  @inputs
end

#loggerObject

Returns the value of attribute logger.



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

def logger
  @logger
end

#outbound_queueObject

Returns the value of attribute outbound_queue.



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

def outbound_queue
  @outbound_queue
end

#serial_portObject

Returns the value of attribute serial_port.



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

def serial_port
  @serial_port
end

#statusObject

Returns the value of attribute status.



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

def status
  @status
end

Instance Method Details

#can_execute?Boolean

If the device is ready and commands are in the queue

Returns:

  • (Boolean)


76
77
78
# File 'lib/arduino.rb', line 76

def can_execute? # If the device is ready and commands are in the queue
  @outbound_queue.any? && status.ready?
end

#current_positionObject



61
62
63
# File 'lib/arduino.rb', line 61

def current_position
  Position.new(status[:X], status[:Y], status[:Z])
end

#disconnectObject

Handle loss of serial connection



56
57
58
59
# File 'lib/arduino.rb', line 56

def disconnect
  log "Connection to device lost"
  @onclose.call if @onclose
end

#execute_now(gcode) ⇒ Object



80
81
82
83
84
85
# File 'lib/arduino.rb', line 80

def execute_now(gcode)
  log "RPI MSG: #{gcode}"
  serial_port.puts gcode
  status[:last] = gcode.name
  status[:BUSY] = 1 # If not, pi will race arduino and "talk too fast"
end

#log(message) ⇒ Object

Log to screen/file/IO stream



33
34
35
# File 'lib/arduino.rb', line 33

def log(message)
  logger.puts(message)
end

#maybe_execute_commandObject

This method smells procedural. Refactor?



69
70
71
72
73
74
# File 'lib/arduino.rb', line 69

def maybe_execute_command # This method smells procedural. Refactor?
  sleep 0.08 # Throttle CPU
  return unless can_execute?
  gcode = @outbound_queue.pop
  gcode.is_a?(FB::Gcode) ? execute_now(gcode) : reject_gcode(gcode)
end

#next_cmdObject



65
66
67
# File 'lib/arduino.rb', line 65

def next_cmd
  outbound_queue.first
end

#onchange(&blk) ⇒ Object



42
43
44
# File 'lib/arduino.rb', line 42

def onchange(&blk)
  @onchange = blk
end

#onclose(&blk) ⇒ Object



51
52
53
# File 'lib/arduino.rb', line 51

def onclose(&blk)
  @onclose = blk
end

#onmessage(&blk) ⇒ Object

Handle incoming text from arduino into pi



47
48
49
# File 'lib/arduino.rb', line 47

def onmessage(&blk)
  @onmessage = blk
end

#reject_gcode(gcode) ⇒ Object



87
88
89
90
# File 'lib/arduino.rb', line 87

def reject_gcode(gcode)
  log "Outbound messages must be GCode objects. Use of "\
      "#{gcode.class}:#{gcode.inspect} is not permitted."
end

#start_event_listenersObject



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

def start_event_listeners
  EM.tick_loop { maybe_execute_command }
  status.onchange { |diff| @onchange.call(diff) if @onchange }
  inbound_queue.subscribe do |gcodes|
    Array(gcodes).each do |gcode|
      parse_incoming(gcode)
      @onmessage.call(gcode) if @onmessage
    end
  end
end

#write(gcode) ⇒ Object

Send outgoing test to arduino from pi



38
39
40
# File 'lib/arduino.rb', line 38

def write(gcode)
  @outbound_queue.unshift gcode
end