hybridgroup-sphero 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.autotest ADDED
@@ -0,0 +1,8 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.testlib = 'minitest/autorun'
7
+ at.find_directories = ARGV unless ARGV.empty?
8
+ end
data/.gemtest ADDED
File without changes
data/CHANGELOG.rdoc ADDED
@@ -0,0 +1,13 @@
1
+ === 1.0.0 / 2012-07-20
2
+
3
+ * 1 major enhancement
4
+
5
+ * Birthday!
6
+
7
+ === 1.0.1 / 2012-10-28
8
+
9
+ * 3 minor fixes/enhancements
10
+
11
+ * Works with Ruby 1.9.2 for us regular folks
12
+ * Sphero.start method to endlessly retry when connecting
13
+ * I think heading might work again, not too sure
data/Manifest.txt ADDED
@@ -0,0 +1,10 @@
1
+ .autotest
2
+ CHANGELOG.rdoc
3
+ Manifest.txt
4
+ README.markdown
5
+ Rakefile
6
+ bin/sphero
7
+ lib/sphero.rb
8
+ lib/sphero/request.rb
9
+ lib/sphero/response.rb
10
+ test/test_sphero.rb
data/README.markdown ADDED
@@ -0,0 +1,66 @@
1
+ # sphero
2
+
3
+ * http://github.com/tenderlove/sphero
4
+
5
+ ## DESCRIPTION:
6
+
7
+ A ruby gem for controlling your Sphero ball. Sends commands over the TTY
8
+ provided by the bluetooth connection.
9
+
10
+ ## FEATURES/PROBLEMS:
11
+
12
+ * You need a Sphero
13
+
14
+ ## SYNOPSIS:
15
+
16
+ ```ruby
17
+ s = Sphero.new "/dev/tty.Sphero-PRG-RN-SPP"
18
+ s.ping
19
+
20
+ # Roll 0 degrees, speed 125
21
+ s.roll(125, 0)
22
+
23
+ # Turn 360 degrees, 30 degrees at a time
24
+ 0.step(360, 30) { |h|
25
+ h = 0 if h == 360
26
+
27
+ # Set the heading to h degrees
28
+ s.heading = h
29
+ sleep 1
30
+ }
31
+ sleep 1
32
+ s.stop
33
+ ```
34
+
35
+ ## REQUIREMENTS:
36
+
37
+ * A Sphero ball connected to your computer
38
+
39
+ ## INSTALL:
40
+
41
+ * gem install sphero
42
+
43
+ ## LICENSE:
44
+
45
+ (The MIT License)
46
+
47
+ Copyright (c) 2012 Aaron Patterson
48
+
49
+ Permission is hereby granted, free of charge, to any person obtaining
50
+ a copy of this software and associated documentation files (the
51
+ 'Software'), to deal in the Software without restriction, including
52
+ without limitation the rights to use, copy, modify, merge, publish,
53
+ distribute, sublicense, and/or sell copies of the Software, and to
54
+ permit persons to whom the Software is furnished to do so, subject to
55
+ the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be
58
+ included in all copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
61
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
62
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
63
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
64
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
65
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
66
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugins.delete :rubyforge
7
+ Hoe.plugin :minitest
8
+ Hoe.plugin :gemspec # `gem install hoe-gemspec`
9
+ Hoe.plugin :git # `gem install hoe-git`
10
+
11
+ Hoe.spec 'hybridgroup-sphero' do
12
+ developer('Aaron Patterson', 'aaron@tenderlovemaking.com')
13
+ self.readme_file = 'README.markdown'
14
+ self.history_file = 'CHANGELOG.rdoc'
15
+ self.extra_rdoc_files = FileList['*.{rdoc,markdown}']
16
+ self.extra_deps << ['serialport']
17
+
18
+ self.spec_extras = {
19
+ :required_ruby_version => '>= 1.9.2'
20
+ }
21
+ end
22
+
23
+ # vim: syntax=ruby
data/bin/sphero ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ abort "you need to write me"
@@ -0,0 +1,117 @@
1
+ class Sphero
2
+ class Request
3
+ SOP1 = 0xFF
4
+ SOP2 = 0xFF
5
+
6
+ attr_reader :data
7
+
8
+ def initialize seq, data = []
9
+ @seq = seq
10
+ @data = data
11
+ @did = 0x00
12
+ end
13
+
14
+ def header
15
+ [SOP1, SOP2, @did, @cid, @seq, dlen]
16
+ end
17
+
18
+ # The data to write to the socket
19
+ def to_str
20
+ bytes
21
+ end
22
+
23
+ def response header, body
24
+ name = self.class.name.split('::').last
25
+ klass = if Response.const_defined?(name)
26
+ Response.const_get(name).new header, body
27
+ else
28
+ Response.new header, body
29
+ end
30
+ end
31
+
32
+ def packet_header
33
+ header.pack 'CCCCCC'
34
+ end
35
+
36
+ def packet_body
37
+ @data.pack 'C*'
38
+ end
39
+
40
+ def checksum
41
+ ~((packet_header + packet_body).unpack('C*').drop(2).reduce(:+) % 256) & 0xFF
42
+ end
43
+
44
+ def bytes
45
+ packet_header + packet_body + checksum.chr
46
+ end
47
+
48
+ def dlen
49
+ packet_body.bytesize + 1
50
+ end
51
+
52
+ class Sphero < Request
53
+ def initialize seq, data = []
54
+ super
55
+ @did = 0x02
56
+ end
57
+ end
58
+
59
+ def self.make_command klass, cid, &block
60
+ Class.new(klass) {
61
+ define_method(:initialize) do |seq, *args|
62
+ super(seq, args)
63
+ @cid = cid
64
+ end
65
+ }
66
+ end
67
+
68
+ SetBackLEDOutput = make_command Sphero, 0x21
69
+ SetRotationRate = make_command Sphero, 0x03
70
+ SetRGB = make_command Sphero, 0x20
71
+ GetRGB = make_command Sphero, 0x22
72
+
73
+ Ping = make_command Request, 0x01
74
+ GetVersioning = make_command Request, 0x02
75
+ GetBluetoothInfo = make_command Request, 0x11
76
+ SetAutoReconnect = make_command Request, 0x12
77
+ GetAutoReconnect = make_command Request, 0x13
78
+ GetPowerState = make_command Request, 0x20
79
+
80
+ class Roll < Sphero
81
+ def initialize seq, speed, heading, delay
82
+ super(seq, [speed, heading, delay])
83
+ @cid = 0x30
84
+ end
85
+
86
+ private
87
+ def packet_body
88
+ @data.pack 'CnC'
89
+ end
90
+ end
91
+
92
+ class Heading < Request
93
+ def initialize seq, heading
94
+ super(seq, [heading])
95
+ @cid = 0x01
96
+ end
97
+
98
+ private
99
+ def packet_body
100
+ @data.pack 'n'
101
+ end
102
+ end
103
+
104
+ class Sleep < Request
105
+ def initialize seq, wakeup, macro
106
+ super(seq, [wakeup, macro])
107
+ @cid = 0x22
108
+ end
109
+
110
+ private
111
+
112
+ def packet_body
113
+ @data.pack 'nC'
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,88 @@
1
+ class Sphero
2
+ class Response
3
+ SOP1 = 0
4
+ SOP2 = 1
5
+ MRSP = 2
6
+ SEQ = 3
7
+ DLEN = 4
8
+
9
+ CODE_OK = 0
10
+
11
+ def initialize header, body
12
+ @header = header
13
+ @body = body
14
+ end
15
+
16
+ def empty?
17
+ @header[DLEN] == 1
18
+ end
19
+
20
+ def success?
21
+ @header[MRSP] == CODE_OK
22
+ end
23
+
24
+ def seq
25
+ @header[SEQ]
26
+ end
27
+
28
+ def body
29
+ @body.unpack 'C*'
30
+ end
31
+
32
+ class GetAutoReconnect < Response
33
+ def time
34
+ body[1]
35
+ end
36
+ end
37
+
38
+ class GetPowerState < Response
39
+ # constants for power_state
40
+ CHARGING = 0x01
41
+ OK = 0x02
42
+ LOW = 0x03
43
+ CRITICAL = 0x04
44
+
45
+ def body
46
+ @body.unpack 'CCnnnC'
47
+ end
48
+
49
+ def rec_ver
50
+ body[0]
51
+ end
52
+
53
+ def power_state
54
+ body[1]
55
+ end
56
+
57
+ # Voltage * 100
58
+ def batt_voltage
59
+ body[2]
60
+ end
61
+
62
+ def num_charges
63
+ body[3]
64
+ end
65
+
66
+ # Time since awakened in seconds
67
+ def time_since_charge
68
+ body[4]
69
+ end
70
+ end
71
+
72
+ class GetBluetoothInfo < Response
73
+ def name
74
+ body.take(16).slice_before(0x00).first.pack 'C*'
75
+ end
76
+
77
+ def bta
78
+ body.drop(16).slice_before(0x00).first.pack 'C*'
79
+ end
80
+ end
81
+
82
+ class GetRGB < Response
83
+ def r; body[0]; end
84
+ def g; body[1]; end
85
+ def b; body[2]; end
86
+ end
87
+ end
88
+ end
data/lib/sphero.rb ADDED
@@ -0,0 +1,154 @@
1
+ require 'serialport'
2
+ require 'sphero/request'
3
+ require 'sphero/response'
4
+ require 'thread'
5
+
6
+ class Sphero
7
+ VERSION = '1.0.1'
8
+
9
+ class << self
10
+ def start(dev)
11
+ self.new dev
12
+ rescue Errno::EBUSY
13
+ retry
14
+ end
15
+ end
16
+
17
+ def initialize dev
18
+ @sp = SerialPort.new dev, 115200, 8, 1, SerialPort::NONE
19
+ @dev = 0x00
20
+ @seq = 0x00
21
+ @lock = Mutex.new
22
+ end
23
+
24
+ def ping
25
+ write Request::Ping.new(@seq)
26
+ end
27
+
28
+ def version
29
+ write Request::GetVersioning.new(@seq)
30
+ end
31
+
32
+ def bluetooth_info
33
+ write Request::GetBluetoothInfo.new(@seq)
34
+ end
35
+
36
+ def auto_reconnect= time_s
37
+ write Request::SetAutoReconnect.new(@seq, time_s)
38
+ end
39
+
40
+ def auto_reconnect
41
+ write(Request::GetAutoReconnect.new(@seq)).time
42
+ end
43
+
44
+ def disable_auto_reconnect
45
+ write Request::SetAutoReconnect.new(@seq, 0, 0x00)
46
+ end
47
+
48
+ def power_state
49
+ write Request::GetPowerState.new(@seq)
50
+ end
51
+
52
+ def sleep wakeup = 0, macro = 0
53
+ write Request::Sleep.new(@seq, wakeup, macro)
54
+ end
55
+
56
+ def roll speed, heading, state = true
57
+ write Request::Roll.new(@seq, speed, heading, state ? 0x01 : 0x00)
58
+ end
59
+
60
+ def stop
61
+ roll 0, 0
62
+ end
63
+
64
+ def heading= h
65
+ write Request::Heading.new(@seq, h)
66
+ end
67
+
68
+ def rgb r, g, b, persistant = false
69
+ write Request::SetRGB.new(@seq, r, g, b, persistant ? 0x01 : 0x00)
70
+ end
71
+
72
+ # This retrieves the "user LED color" which is stored in the config block
73
+ # (which may or may not be actively driven to the RGB LED).
74
+ def user_led
75
+ write Request::GetRGB.new(@seq)
76
+ end
77
+
78
+ # Brightness 0x00 - 0xFF
79
+ def back_led_output= h
80
+ write Request::SetBackLEDOutput.new(@seq, h)
81
+ end
82
+
83
+ # Rotation Rate 0x00 - 0xFF
84
+ def rotation_rate= h
85
+ write Request::SetRotationRate.new(@seq, h)
86
+ end
87
+
88
+ private
89
+
90
+ def write packet
91
+ header = nil
92
+ body = nil
93
+
94
+ @lock.synchronize do
95
+ @sp.write packet.to_str
96
+ @seq += 1
97
+
98
+ header = @sp.read(5).unpack 'C5'
99
+ body = @sp.read header.last
100
+ end
101
+
102
+ response = packet.response header, body
103
+
104
+ if response.success?
105
+ response
106
+ else
107
+ raise response
108
+ end
109
+ end
110
+ end
111
+
112
+ if $0 == __FILE__
113
+ begin
114
+ s = Sphero.new "/dev/tty.Sphero-BRR-RN-SPP"
115
+ rescue Errno::EBUSY
116
+ retry
117
+ end
118
+
119
+ 10.times {
120
+ p s.ping
121
+ }
122
+
123
+ trap(:INT) {
124
+ s.stop
125
+ exit!
126
+ }
127
+
128
+ #s.roll 100, 0
129
+
130
+ p s.user_led
131
+ exit
132
+ loop do
133
+ [0, 180].each do |dir|
134
+ s.heading = dir
135
+ sleep 10
136
+ end
137
+
138
+ #[
139
+ # [0, 0, 0xFF],
140
+ # [0xFF, 0, 0],
141
+ # [0, 0xFF, 0],
142
+ #].each do |color|
143
+ # s.rgb(*color)
144
+ # sleep 5
145
+ #end
146
+ end
147
+
148
+ #36.times {
149
+ # i = 10
150
+ # p :step => i
151
+ # s.heading = i
152
+ # sleep 0.5
153
+ #}
154
+ end
@@ -0,0 +1,14 @@
1
+ require 'minitest/autorun'
2
+ require 'sphero'
3
+
4
+ class TestSphero < MiniTest::Unit::TestCase
5
+ def test_ping_checksum
6
+ ping = Sphero::Request::Ping.new 0
7
+ assert_equal "\xFF\xFF\x00\x01\x00\x01\xFD", ping.to_str
8
+ end
9
+
10
+ def test_sleep_dlen
11
+ sleep = Sphero::Request::Sleep.new 0, 0, 0
12
+ assert_equal 0x04, sleep.dlen
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hybridgroup-sphero
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aaron Patterson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: serialport
16
+ requirement: &2152670780 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2152670780
25
+ - !ruby/object:Gem::Dependency
26
+ name: minitest
27
+ requirement: &2152670180 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.11'
33
+ type: :development
34
+ prerelease: false
35
+ version_requirements: *2152670180
36
+ - !ruby/object:Gem::Dependency
37
+ name: rdoc
38
+ requirement: &2152669620 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ version: '3.10'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: *2152669620
47
+ - !ruby/object:Gem::Dependency
48
+ name: hoe
49
+ requirement: &2152669060 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *2152669060
58
+ description: ! 'A ruby gem for controlling your Sphero ball. Sends commands over
59
+ the TTY
60
+
61
+ provided by the bluetooth connection.'
62
+ email:
63
+ - aaron@tenderlovemaking.com
64
+ executables:
65
+ - sphero
66
+ extensions: []
67
+ extra_rdoc_files:
68
+ - CHANGELOG.rdoc
69
+ - Manifest.txt
70
+ - README.markdown
71
+ files:
72
+ - .autotest
73
+ - CHANGELOG.rdoc
74
+ - Manifest.txt
75
+ - README.markdown
76
+ - Rakefile
77
+ - bin/sphero
78
+ - lib/sphero.rb
79
+ - lib/sphero/request.rb
80
+ - lib/sphero/response.rb
81
+ - test/test_sphero.rb
82
+ - .gemtest
83
+ homepage: http://github.com/tenderlove/sphero
84
+ licenses: []
85
+ post_install_message:
86
+ rdoc_options:
87
+ - --main
88
+ - README.markdown
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ none: false
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: 1.9.2
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ none: false
99
+ requirements:
100
+ - - ! '>='
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubyforge_project: hybridgroup-sphero
105
+ rubygems_version: 1.8.6
106
+ signing_key:
107
+ specification_version: 3
108
+ summary: A ruby gem for controlling your Sphero ball
109
+ test_files:
110
+ - test/test_sphero.rb