Class: FB::Arduino
- Inherits:
-
Object
- Object
- FB::Arduino
- 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
-
#commands ⇒ Object
Returns the value of attribute commands.
-
#inbound_queue ⇒ Object
Returns the value of attribute inbound_queue.
-
#inputs ⇒ Object
Returns the value of attribute inputs.
-
#logger ⇒ Object
Returns the value of attribute logger.
-
#outbound_queue ⇒ Object
Returns the value of attribute outbound_queue.
-
#serial_port ⇒ Object
Returns the value of attribute serial_port.
-
#status ⇒ Object
Returns the value of attribute status.
Instance Method Summary collapse
-
#can_execute? ⇒ Boolean
If the device is ready and commands are in the queue.
- #current_position ⇒ Object
-
#disconnect ⇒ Object
Handle loss of serial connection.
- #execute_now(gcode) ⇒ Object
-
#initialize(serial_port: DefaultSerialPort.new, logger: STDOUT) ⇒ Arduino
constructor
Initialize and provide a serial object, as well as an IO object to send log messages to.
-
#log(message) ⇒ Object
Log to screen/file/IO stream.
-
#maybe_execute_command ⇒ Object
This method smells procedural.
- #next_cmd ⇒ Object
- #onchange(&blk) ⇒ Object
- #onclose(&blk) ⇒ Object
-
#onmessage(&blk) ⇒ Object
Handle incoming text from arduino into pi.
- #reject_gcode(gcode) ⇒ Object
- #start_event_listeners ⇒ Object
-
#write(gcode) ⇒ Object
Send outgoing test to arduino from pi.
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
#commands ⇒ Object
Returns the value of attribute commands.
13 14 15 |
# File 'lib/arduino.rb', line 13 def commands @commands end |
#inbound_queue ⇒ Object
Returns the value of attribute inbound_queue.
13 14 15 |
# File 'lib/arduino.rb', line 13 def inbound_queue @inbound_queue end |
#inputs ⇒ Object
Returns the value of attribute inputs.
13 14 15 |
# File 'lib/arduino.rb', line 13 def inputs @inputs end |
#logger ⇒ Object
Returns the value of attribute logger.
13 14 15 |
# File 'lib/arduino.rb', line 13 def logger @logger end |
#outbound_queue ⇒ Object
Returns the value of attribute outbound_queue.
13 14 15 |
# File 'lib/arduino.rb', line 13 def outbound_queue @outbound_queue end |
#serial_port ⇒ Object
Returns the value of attribute serial_port.
13 14 15 |
# File 'lib/arduino.rb', line 13 def serial_port @serial_port end |
#status ⇒ Object
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
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_position ⇒ Object
61 62 63 |
# File 'lib/arduino.rb', line 61 def current_position Position.new(status[:X], status[:Y], status[:Z]) end |
#disconnect ⇒ Object
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() logger.puts() end |
#maybe_execute_command ⇒ Object
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_cmd ⇒ Object
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 (&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_listeners ⇒ Object
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 |