smalrubot 0.0.1
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/.gitignore +22 -0
- data/.travis.yml +4 -0
- data/Gemfile +4 -0
- data/LEGAL +82 -0
- data/LICENSE +22 -0
- data/README.md +48 -0
- data/Rakefile +35 -0
- data/bin/smalrubot +82 -0
- data/examples/test.rb +13 -0
- data/lib/smalrubot.rb +32 -0
- data/lib/smalrubot/board.rb +104 -0
- data/lib/smalrubot/board_not_found.rb +3 -0
- data/lib/smalrubot/components.rb +9 -0
- data/lib/smalrubot/components/base_component.rb +44 -0
- data/lib/smalrubot/components/led.rb +18 -0
- data/lib/smalrubot/components/servo.rb +21 -0
- data/lib/smalrubot/tx_rx.rb +10 -0
- data/lib/smalrubot/tx_rx/base.rb +54 -0
- data/lib/smalrubot/tx_rx/serial.rb +70 -0
- data/lib/smalrubot/version.rb +3 -0
- data/sketch/lib/Smalrubot.cpp +158 -0
- data/sketch/lib/Smalrubot.h +60 -0
- data/sketch/sr/sr.ino +18 -0
- data/smalrubot.gemspec +26 -0
- data/spec/lib/board_not_found_spec.rb +8 -0
- data/spec/lib/board_spec.rb +120 -0
- data/spec/lib/components/base_component_spec.rb +66 -0
- data/spec/lib/components/led_spec.rb +49 -0
- data/spec/lib/components/servo_spec.rb +58 -0
- data/spec/lib/tx_rx/serial_spec.rb +81 -0
- data/spec/spec_helper.rb +12 -0
- metadata +140 -0
@@ -0,0 +1,9 @@
|
|
1
|
+
module Smalrubot
|
2
|
+
module Components
|
3
|
+
require 'smalrubot/components/base_component'
|
4
|
+
autoload :Led, 'smalrubot/components/led'
|
5
|
+
autoload :Button, 'smalrubot/components/button'
|
6
|
+
autoload :Sensor, 'smalrubot/components/sensor'
|
7
|
+
autoload :Servo, 'smalrubot/components/servo'
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Smalrubot
|
2
|
+
module Components
|
3
|
+
class BaseComponent
|
4
|
+
attr_reader :board, :pin, :pullup
|
5
|
+
alias :pins :pin
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
self.board = options[:board]
|
9
|
+
self.pin = options[:pin] || options[:pins]
|
10
|
+
self.pullup = options[:pullup]
|
11
|
+
|
12
|
+
raise 'board and pin or pins are required for a component' if self.board.nil? || self.pin.nil?
|
13
|
+
after_initialize(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
#
|
17
|
+
# As BaseComponent does a lot of work for you with regarding to setting up, it is
|
18
|
+
# best not to override #initialize and instead define an #after_initialize method
|
19
|
+
# within your subclass.
|
20
|
+
#
|
21
|
+
# @note This method should be implemented in the BaseComponent subclass.
|
22
|
+
#
|
23
|
+
def after_initialize(options={}) ; end
|
24
|
+
|
25
|
+
protected
|
26
|
+
|
27
|
+
attr_writer :board, :pin, :pullup
|
28
|
+
alias :pins= :pin=
|
29
|
+
|
30
|
+
def digital_write(pin=self.pin, value)
|
31
|
+
self.board.digital_write(pin, value)
|
32
|
+
end
|
33
|
+
|
34
|
+
def analog_write(pin=self.pin, value)
|
35
|
+
self.board.analog_write(pin, value)
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_pin_mode(pin=self.pin, mode)
|
39
|
+
self.board.set_pin_mode(pin, mode, pullup)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Smalrubot
|
2
|
+
module Components
|
3
|
+
class Led < BaseComponent
|
4
|
+
def after_initialize(options={})
|
5
|
+
set_pin_mode(:out)
|
6
|
+
off
|
7
|
+
end
|
8
|
+
|
9
|
+
def on
|
10
|
+
digital_write(Board::HIGH)
|
11
|
+
end
|
12
|
+
|
13
|
+
def off
|
14
|
+
digital_write(Board::LOW)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Smalrubot
|
2
|
+
module Components
|
3
|
+
class Servo < BaseComponent
|
4
|
+
attr_reader :position
|
5
|
+
|
6
|
+
def after_initialize(options={})
|
7
|
+
set_pin_mode(:out)
|
8
|
+
board.servo_toggle(pin, 1)
|
9
|
+
self.position = options[:position] || 0
|
10
|
+
end
|
11
|
+
|
12
|
+
def position=(value)
|
13
|
+
board.servo_write(pin, @position = angle(value))
|
14
|
+
end
|
15
|
+
|
16
|
+
def angle(value)
|
17
|
+
value == 180 ? value : value % 180
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'observer'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module Smalrubot
|
5
|
+
module TxRx
|
6
|
+
class Base
|
7
|
+
def read(timeout = 0.005)
|
8
|
+
line = gets(timeout)
|
9
|
+
if line && line.match(/\A\d+:/)
|
10
|
+
pin, message = line.chomp.split(/:/)
|
11
|
+
if pin && message
|
12
|
+
return pin, message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def write(message)
|
18
|
+
n = io.write(message)
|
19
|
+
Smalrubot.debug_log('write: %s(A:%d, E:%d)', message, n, message.length)
|
20
|
+
if n != message.length
|
21
|
+
raise "FATAL: n(#{n}) != message.length(#{message.length})"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def handshake
|
26
|
+
5.times do
|
27
|
+
write("!9000000.")
|
28
|
+
line = gets(1)
|
29
|
+
if line && line.match(/ACK:/)
|
30
|
+
flush_read
|
31
|
+
return line.chomp.split(/:/)[1].to_i
|
32
|
+
end
|
33
|
+
end
|
34
|
+
raise BoardNotFound
|
35
|
+
end
|
36
|
+
|
37
|
+
def flush_read
|
38
|
+
gets until gets == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
RETURN_CODE = "\n".ord
|
42
|
+
|
43
|
+
def gets(timeout=0.005)
|
44
|
+
Timeout.timeout(timeout) do
|
45
|
+
s = io.gets
|
46
|
+
Smalrubot.debug_log("gets: %s", s)
|
47
|
+
return s
|
48
|
+
end
|
49
|
+
rescue Exception
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'rubyserial'
|
2
|
+
|
3
|
+
module Smalrubot
|
4
|
+
module TxRx
|
5
|
+
class Serial < Base
|
6
|
+
BAUD = 115200
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@device = options[:device]
|
10
|
+
@baud = options[:baud] || BAUD
|
11
|
+
@first_write = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def io
|
15
|
+
@io ||= connect
|
16
|
+
end
|
17
|
+
|
18
|
+
def handshake
|
19
|
+
while tty_devices.length > 0
|
20
|
+
begin
|
21
|
+
if on_windows?
|
22
|
+
io; sleep 3
|
23
|
+
end
|
24
|
+
|
25
|
+
return super
|
26
|
+
rescue BoardNotFound
|
27
|
+
@tty_devices.shift
|
28
|
+
@io.close
|
29
|
+
@io = nil
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def connect
|
37
|
+
tty_devices.dup.each do |device|
|
38
|
+
begin
|
39
|
+
serial = ::Serial.new(device, @baud)
|
40
|
+
Smalrubot.debug_log('found board: %s (%d)', device, @baud)
|
41
|
+
return serial
|
42
|
+
rescue Exception
|
43
|
+
@tty_devices.shift
|
44
|
+
Smalrubot.debug_log('could not access: %s', device)
|
45
|
+
Smalrubot.show_backtrace($!)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
raise BoardNotFound
|
49
|
+
end
|
50
|
+
|
51
|
+
def tty_devices
|
52
|
+
if !@tty_devices
|
53
|
+
if @device
|
54
|
+
@tty_devices = [@device]
|
55
|
+
elsif on_windows?
|
56
|
+
@tty_devices = (1..256).map { |n| "COM#{n}" }
|
57
|
+
else
|
58
|
+
@tty_devices =
|
59
|
+
`ls /dev`.split("\n").grep(/usb|ACM/i).map{ |d| "/dev/#{d}" }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
@tty_devices
|
63
|
+
end
|
64
|
+
|
65
|
+
def on_windows?
|
66
|
+
RUBY_PLATFORM.match /mswin|mingw/i
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,158 @@
|
|
1
|
+
/*
|
2
|
+
Library for smalrubot ruby gem.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include "Arduino.h"
|
6
|
+
#include "Smalrubot.h"
|
7
|
+
|
8
|
+
Smalrubot::Smalrubot(){
|
9
|
+
reset();
|
10
|
+
}
|
11
|
+
|
12
|
+
void Smalrubot::parse(char c) {
|
13
|
+
if (c == '!') index = 0; // Reset request
|
14
|
+
else if (c == '.') process(); // End request and process
|
15
|
+
else request[index++] = c; // Append to request
|
16
|
+
}
|
17
|
+
|
18
|
+
void Smalrubot::process() {
|
19
|
+
response[0] = '\0';
|
20
|
+
|
21
|
+
// Parse the request.
|
22
|
+
strncpy(cmdStr, request, 2); cmdStr[2] = '\0';
|
23
|
+
strncpy(pinStr, request + 2, 2); pinStr[2] = '\0';
|
24
|
+
strncpy(valStr, request + 4, 3); valStr[3] = '\0';
|
25
|
+
cmd = atoi(cmdStr);
|
26
|
+
pin = atoi(pinStr);
|
27
|
+
val = atoi(valStr);
|
28
|
+
|
29
|
+
#ifdef debug
|
30
|
+
Serial.print("Received request - "); Serial.println(request);
|
31
|
+
Serial.print("Command - "); Serial.println(cmdStr);
|
32
|
+
Serial.print("Pin - "); Serial.println(pinStr);
|
33
|
+
Serial.print("Value - "); Serial.println(valStr);
|
34
|
+
#endif
|
35
|
+
|
36
|
+
// Call the command.
|
37
|
+
switch(cmd) {
|
38
|
+
case 0: setMode (); break;
|
39
|
+
case 1: dWrite (); break;
|
40
|
+
case 2: dRead (); break;
|
41
|
+
case 3: aWrite (); break;
|
42
|
+
case 4: aRead (); break;
|
43
|
+
case 8: servoToggle (); break;
|
44
|
+
case 9: servoWrite (); break;
|
45
|
+
case 90: reset (); break;
|
46
|
+
default: break;
|
47
|
+
}
|
48
|
+
|
49
|
+
// Write the response.
|
50
|
+
if (response[0] != '\0') writeResponse();
|
51
|
+
|
52
|
+
#ifdef debug
|
53
|
+
Serial.print("Responded with - "); Serial.println(response);
|
54
|
+
Serial.println();
|
55
|
+
#endif
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
|
60
|
+
// WRITE CALLBACK
|
61
|
+
void Smalrubot::setupWrite(void (*writeCallback)(char *str)) {
|
62
|
+
_writeCallback = writeCallback;
|
63
|
+
}
|
64
|
+
void Smalrubot::writeResponse() {
|
65
|
+
_writeCallback(response);
|
66
|
+
}
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
// API FUNCTIONS
|
74
|
+
// CMD = 00 // Pin Mode
|
75
|
+
void Smalrubot::setMode() {
|
76
|
+
if (val == 0) {
|
77
|
+
pinMode(pin, OUTPUT);
|
78
|
+
#ifdef debug
|
79
|
+
Serial.print("Set pin "); Serial.print(pin); Serial.print(" to "); Serial.println("OUTPUT mode");
|
80
|
+
#endif
|
81
|
+
}
|
82
|
+
else {
|
83
|
+
pinMode(pin, INPUT);
|
84
|
+
#ifdef debug
|
85
|
+
Serial.print("Set pin "); Serial.print(pin); Serial.print(" to "); Serial.println("INPTUT mode");
|
86
|
+
#endif
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
// CMD = 01 // Digital Write
|
91
|
+
void Smalrubot::dWrite() {
|
92
|
+
if (val == 0) {
|
93
|
+
digitalWrite(pin, LOW);
|
94
|
+
#ifdef debug
|
95
|
+
Serial.print("Digital write "); Serial.print(LOW); Serial.print(" to pin "); Serial.println(pin);
|
96
|
+
#endif
|
97
|
+
}
|
98
|
+
else {
|
99
|
+
digitalWrite(pin, HIGH);
|
100
|
+
#ifdef debug
|
101
|
+
Serial.print("Digital write "); Serial.print(HIGH); Serial.print(" to pin "); Serial.println(pin);
|
102
|
+
#endif
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
// CMD = 02 // Digital Read
|
107
|
+
void Smalrubot::dRead() {
|
108
|
+
rval = digitalRead(pin);
|
109
|
+
sprintf(response, "%02d:%02d", pin, rval);
|
110
|
+
}
|
111
|
+
|
112
|
+
// CMD = 03 // Analog (PWM) Write
|
113
|
+
void Smalrubot::aWrite() {
|
114
|
+
analogWrite(pin,val);
|
115
|
+
#ifdef debug
|
116
|
+
Serial.print("Analog write "); Serial.print(val); Serial.print(" to pin "); Serial.println(pin);
|
117
|
+
#endif
|
118
|
+
}
|
119
|
+
|
120
|
+
// CMD = 04 // Analog Read
|
121
|
+
void Smalrubot::aRead() {
|
122
|
+
rval = analogRead(pin);
|
123
|
+
sprintf(response, "%02d:%02d", pin, rval);
|
124
|
+
}
|
125
|
+
|
126
|
+
// CMD = 08
|
127
|
+
// Attach the servo object to pin or detach it.
|
128
|
+
void Smalrubot::servoToggle() {
|
129
|
+
if (val == 0) {
|
130
|
+
#ifdef debug
|
131
|
+
Serial.print("Detaching servo"); Serial.print(" on pin "); Serial.println(pin);
|
132
|
+
#endif
|
133
|
+
servos[pin - SERVO_OFFSET].detach();
|
134
|
+
}
|
135
|
+
else {
|
136
|
+
#ifdef debug
|
137
|
+
Serial.print("Attaching servo"); Serial.print(" on pin "); Serial.println(pin);
|
138
|
+
#endif
|
139
|
+
servos[pin - SERVO_OFFSET].attach(pin);
|
140
|
+
}
|
141
|
+
}
|
142
|
+
|
143
|
+
// CMD = 09
|
144
|
+
// Write a value to the servo object.
|
145
|
+
void Smalrubot::servoWrite() {
|
146
|
+
#ifdef debug
|
147
|
+
Serial.print("Servo write "); Serial.print(val); Serial.print(" to pin "); Serial.println(pin);
|
148
|
+
#endif
|
149
|
+
servos[pin - SERVO_OFFSET].write(val);
|
150
|
+
}
|
151
|
+
|
152
|
+
// CMD = 90
|
153
|
+
void Smalrubot::reset() {
|
154
|
+
#ifdef debug
|
155
|
+
Serial.println("Reset the board to defaults.");
|
156
|
+
#endif
|
157
|
+
sprintf(response, "ACK:%02d", A0);
|
158
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
/*
|
2
|
+
Library for smalrubot ruby gem.
|
3
|
+
*/
|
4
|
+
|
5
|
+
#ifndef Smalrubot_h
|
6
|
+
#define Smalrubot_h
|
7
|
+
|
8
|
+
#include "Arduino.h"
|
9
|
+
#include <Servo.h>
|
10
|
+
|
11
|
+
// Allocate listener storage based on what board we're running.
|
12
|
+
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
13
|
+
# define PIN_COUNT 70
|
14
|
+
# define SERVO_OFFSET 22
|
15
|
+
#else
|
16
|
+
# define PIN_COUNT 22
|
17
|
+
# define SERVO_OFFSET 2
|
18
|
+
#endif
|
19
|
+
|
20
|
+
// Uncomment this line to enable debugging mode.
|
21
|
+
// #define debug true
|
22
|
+
|
23
|
+
class Smalrubot {
|
24
|
+
public:
|
25
|
+
Smalrubot();
|
26
|
+
void setupWrite(void (*writeCallback)(char *str));
|
27
|
+
void parse(char c);
|
28
|
+
void process();
|
29
|
+
|
30
|
+
private:
|
31
|
+
// Request storage.
|
32
|
+
char request[8];
|
33
|
+
int index;
|
34
|
+
char cmdStr[3];
|
35
|
+
byte cmd;
|
36
|
+
char pinStr[3];
|
37
|
+
byte pin;
|
38
|
+
char valStr[4];
|
39
|
+
int val;
|
40
|
+
|
41
|
+
// Value and response storage.
|
42
|
+
int rval;
|
43
|
+
char response[8];
|
44
|
+
void (*_writeCallback)(char *str);
|
45
|
+
void writeResponse();
|
46
|
+
|
47
|
+
Servo servos[12];
|
48
|
+
|
49
|
+
// API-accessible functions.
|
50
|
+
void setMode ();
|
51
|
+
void dWrite ();
|
52
|
+
void dRead ();
|
53
|
+
void aWrite ();
|
54
|
+
void aRead ();
|
55
|
+
void servoToggle ();
|
56
|
+
void servoWrite ();
|
57
|
+
void reset ();
|
58
|
+
};
|
59
|
+
|
60
|
+
#endif
|