ruby-player 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.
@@ -0,0 +1,175 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ module Player
16
+ # The position2d proxy provides an interface to a mobile robot base
17
+ #
18
+ # @example
19
+ # # get proxy object
20
+ # pos2d = client[:position2d, 0]
21
+ # # setup speed of robot
22
+ # pos2d.set_speed(vx: 1.2, vy: 0.1, va: 0.3)
23
+ #
24
+ # #update data from server
25
+ # client.read
26
+ # #read velocityand position by X,Y and angle
27
+ # pos2d.speed #=> { :vx => 1.2, :vy => 0.1, :va => 0.3 }
28
+ # pos2d.odometry #=> { :px => 0.2321, :py => 0,01, :pa => 0.2 }
29
+ # pos2d.stop
30
+ class Position2d
31
+ include CType
32
+ include Common
33
+
34
+ module C
35
+ extend FFI::Library
36
+ ffi_lib "playerc"
37
+
38
+ attach_function :playerc_position2d_create, [:pointer, :int], :pointer
39
+ attach_function :playerc_position2d_destroy, [:pointer], :void
40
+ attach_function :playerc_position2d_subscribe, [:pointer, :int], :int
41
+ attach_function :playerc_position2d_unsubscribe, [:pointer], :int
42
+
43
+ attach_function :playerc_position2d_get_geom, [:pointer], :int
44
+ attach_function :playerc_position2d_set_cmd_vel, [:pointer, :double, :double, :double, :int], :int
45
+ attach_function :playerc_position2d_set_cmd_car, [:pointer, :double, :double], :int
46
+ attach_function :playerc_position2d_enable, [:pointer, :int], :int
47
+ attach_function :playerc_position2d_set_odom, [:pointer, :double, :double, :double], :int
48
+ end
49
+
50
+ def initialize(client, index)
51
+ @pos2d = Position2dStruct.new(C.playerc_position2d_create(client, index))
52
+ try_with_error C.playerc_position2d_subscribe(@pos2d, PLAYER_OPEN_MODE)
53
+
54
+ ObjectSpace.define_finalizer(self, Position2d.finilazer(@pos2d))
55
+ end
56
+
57
+ # Odometry of robot
58
+ # @return [Hash] hash odometry {:px, :py, :pa }
59
+ def odometry
60
+ {
61
+ px: @pos2d[:px],
62
+ py: @pos2d[:py],
63
+ pa: @pos2d[:pa]
64
+ }
65
+ end
66
+
67
+ # Set odometry of robot.
68
+ # @params [Hash] odometry
69
+ # @option odometry :px x position (m)
70
+ # @option odometry :py y position (m)
71
+ # @option odometry :pa angle (rad).
72
+ # @return self
73
+ def set_odometry(odometry)
74
+ args = [
75
+ odometry[:px].to_f || @pos2d[:px],
76
+ odometry[:py].to_f || @pos2d[:py],
77
+ odometry[:pa].to_f || @pos2d[:pa]
78
+ ]
79
+
80
+ try_with_error C.playerc_position2d_set_odom(@pos2d, *args)
81
+ self
82
+ end
83
+
84
+ # Reset odometry to zero
85
+ # @return self
86
+ def reset_odometry
87
+ set_odometry(px: 0, py: 0, pa: 0)
88
+ end
89
+
90
+ # Robot geometry
91
+ # @return [Hash] position :px, :py, :pa, size :sx, :sy
92
+ def geom
93
+ try_with_error C.playerc_position2d_get_geom(@pos2d)
94
+ p = @pos2d[:pose].to_a
95
+ s = @pos2d[:size].to_a
96
+ {
97
+ px: p[0],
98
+ py: p[1],
99
+ pa: p[2],
100
+ sx: s[0],
101
+ sy: s[1]
102
+ }
103
+ end
104
+
105
+
106
+ # Set speed of robot. All speeds are defined in the robot coordinate system.
107
+ # @params [Hash] speeds
108
+ # @option speeds :vx forward speed (m/s)
109
+ # @option speeds :vy sideways speed (m/s); this field is used by omni-drive robots only.
110
+ # @option speeds :va rotational speed (rad/s).
111
+ # @return self
112
+ def set_speed(speeds)
113
+ args = [
114
+ speeds[:vx].to_f || @pos2d[:vx],
115
+ vy = speeds[:vy].to_f || @pos2d[:vy],
116
+ va = speeds[:va].to_f || @pos2d[:va],
117
+ 1
118
+ ]
119
+ try_with_error C.playerc_position2d_set_cmd_vel(@pos2d, *args)
120
+ self
121
+ end
122
+
123
+ # Set speed of carlike robot
124
+ # @params [Hash] speeds
125
+ # @option speeds :vx forward speed (m/s)
126
+ # @option speeds :a angle robot (rad).
127
+ def set_car(speeds)
128
+ args = [
129
+ speeds[:vx].to_f || @pos2d[:vx],
130
+ speeds[:a].to_f || @pos2d[:pa]
131
+ ]
132
+ try_with_error C.playerc_position2d_set_cmd_car(@pos2d, *args)
133
+ self
134
+ end
135
+
136
+ # Velocity of robot
137
+ # @return [Hash] hash of speeds
138
+ def speed
139
+ {
140
+ vx: @pos2d[:vx],
141
+ vy: @pos2d[:vy],
142
+ va: @pos2d[:va]
143
+ }
144
+ end
145
+
146
+ # State of motor
147
+ # @return [Boolean] true - on
148
+ def enable
149
+ @pos2d[:stall] == 1
150
+ end
151
+
152
+ # Turn on\off motor
153
+ # @param [Boolean] true - turn on
154
+ def enable=(val)
155
+ try_with_error C.playerc_position2d_enable(@pos2d, val ? 1 : 0)
156
+ end
157
+
158
+ # Stop robot set speed to 0
159
+ def stop
160
+ set_speed(vx: 0, vy: 0, va: 0)
161
+ end
162
+
163
+ # Check of robot state
164
+ def stoped?
165
+ speed[:vx] == 0 && speed[:vy] == 0 && speed[:va] == 0
166
+ end
167
+
168
+ def Position2d.finilazer(pos)
169
+ lambda{
170
+ try_with_error C.playerc_position2d_unsubscribe(pos)
171
+ C.playerc_position2d_destroy(pos)
172
+ }
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,136 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ module Player
16
+ # The ranger proxy provides an interface to the ranger sensors built into robots
17
+ class Ranger
18
+ include CType
19
+ include Common
20
+
21
+ module C
22
+ extend FFI::Library
23
+ ffi_lib "playerc"
24
+
25
+ attach_function :playerc_ranger_create, [:pointer, :int], :pointer
26
+ attach_function :playerc_ranger_destroy, [:pointer], :void
27
+ attach_function :playerc_ranger_subscribe, [:pointer, :int], :int
28
+ attach_function :playerc_ranger_unsubscribe, [:pointer], :int
29
+
30
+ attach_function :playerc_ranger_power_config, [:pointer, :uint8], :int
31
+ attach_function :playerc_ranger_intns_config, [:pointer, :uint8], :int
32
+ attach_function :playerc_ranger_set_config, [:pointer] + [:double] * 7, :int
33
+ attach_function :playerc_ranger_get_config, [:pointer] + [:pointer] * 7, :int
34
+ end
35
+
36
+ def initialize(client, index)
37
+ @ranger = RangerStruct.new(C.playerc_ranger_create(client, index))
38
+ try_with_error C.playerc_ranger_subscribe(@ranger, PLAYER_OPEN_MODE)
39
+
40
+ ObjectSpace.define_finalizer(self, Ranger.finilazer(@ranger))
41
+ end
42
+
43
+ # Count of sensors
44
+ # Return [Integer] count
45
+ def element_count
46
+ @ranger[:element_count]
47
+ end
48
+
49
+ # Power control
50
+ # @param enable nil or false power off
51
+ def power_enable=(enable)
52
+ try_with_error C.playerc_ranger_power_config(@ranger, enable ? 1 : 0)
53
+ end
54
+
55
+ # Enable intensity
56
+ # @param enable nil or false disable
57
+ def intensity_enable=(enable)
58
+ try_with_error C.playerc_ranger_intns_config(@ranger, enable ? 1 : 0)
59
+ end
60
+
61
+ # Set config of ranger
62
+ # @param [Hash] config params for setup
63
+ # @option :min_angle start angle of scans [rad]
64
+ # @option :max_angle end angle of scans
65
+ # @option :angular_res scan resolution [rad]
66
+ # @option :min_range maximum range [m]
67
+ # @option :max_range minimum range [m]
68
+ # @option :range_res range resolution [m]
69
+ # @option :frequency scanning frequency [Hz]
70
+ def set_config(config)
71
+ args = [
72
+ config[:min_angle].to_f || @ranger[:min_angle],
73
+ config[:max_angle].to_f || @ranger[:max_angle],
74
+ config[:angular_res].to_f || @ranger[:angular_res],
75
+ config[:min_range].to_f || @ranger[:min_range],
76
+ config[:max_range].to_f || @ranger[:max_range],
77
+ config[:range_res].to_f || @ranger[:range_res],
78
+ config[:frequecy].to_f || @ranger[:frequecy]
79
+ ]
80
+
81
+ try_with_error C.playerc_ranger_set_config(@ranger, *args)
82
+ end
83
+
84
+ # Configuration of ranger
85
+ # @see set_config
86
+ def config
87
+ try_with_error C.playerc_ranger_get_config(@ranger, *([nil] * 7))
88
+ {
89
+ min_range: @ranger[:min_angle],
90
+ max_range: @ranger[:max_angle],
91
+ angular_res: @ranger[:angular_res],
92
+ min_range: @ranger[:min_range],
93
+ max_range: @ranger[:max_range],
94
+ range_res: @ranger[:range_res],
95
+ frequecy: @ranger[:frequecy]
96
+ }
97
+ end
98
+
99
+ # Range data [m]
100
+ # @return [Array] fot each sensor
101
+ def ranges
102
+ @ranger[:ranges].read_array_of_type(
103
+ FFI::Type::DOUBLE,
104
+ :read_double,
105
+ @ranger[:ranges_count]
106
+ )
107
+ end
108
+
109
+ # Intensity data [m].
110
+ # @return [Array] fot each sensor
111
+ def intensities
112
+ @ranger[:intensities].read_array_of_type(
113
+ FFI::Type::DOUBLE,
114
+ :read_double,
115
+ @ranger[:intensities_count]
116
+ )
117
+ end
118
+
119
+ # Scan bearings in the XY plane [radians].
120
+ # @return [Array] fot each sensor
121
+ def bearings
122
+ @ranger[:bearings].read_array_of_type(
123
+ FFI::Type::DOUBLE,
124
+ :read_double,
125
+ @ranger[:bearings_count]
126
+ )
127
+ end
128
+
129
+ def Ranger.finilazer(ranger)
130
+ lambda{
131
+ try_with_error C.playerc_ranger_unsubscribe(pos)
132
+ C.playerc_ranger_destroy(pos)
133
+ }
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,17 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ module Player
16
+ VERSION = "0.0.1"
17
+ end
@@ -0,0 +1,23 @@
1
+ # Ruby Player - Ruby client library for Player (tools for robots)
2
+ #
3
+ # Copyright (C) 2012 Timin Aleksey
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+
15
+ require "ffi"
16
+
17
+ require "ruby-player/c_type"
18
+
19
+ require "ruby-player/version"
20
+ require "ruby-player/common"
21
+ require "ruby-player/position2d"
22
+ require "ruby-player/ranger"
23
+ require "ruby-player/client"
@@ -0,0 +1,27 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "ruby-player/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "ruby-player"
7
+ s.version = Player::VERSION
8
+ s.authors = ["Aleksey Timin"]
9
+ s.email = ["atimin@gmail.com"]
10
+ s.homepage = "http://www.github.com/flipback/ruby-player"
11
+ s.summary = %q{Ruby Player - Ruby client library for Player (tools for robots)}
12
+ s.description = %q{Ruby Player - Ruby client library for Player (tools for robots)}
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.required_ruby_version = '>= 1.9.2'
20
+
21
+ s.add_runtime_dependency "ffi", '~>1.0.0'
22
+ s.add_development_dependency "rspec", '~> 2.7'
23
+ s.add_development_dependency "rake", '~> 0.9'
24
+ s.add_development_dependency "pry"
25
+ s.add_development_dependency "yard"
26
+ s.add_development_dependency "redcarpet"
27
+ end
@@ -0,0 +1,32 @@
1
+ require "ruby-player"
2
+
3
+ describe Player::Client do
4
+ before do
5
+ @cl = Player::Client.new("localhost")
6
+ end
7
+
8
+ it "should raise error if connection doesn't success" do
9
+ lambda{ Player::Client.new("localhost", 6666) }.should raise_error(StandardError,
10
+ "connect call on [localhost:6666] failed with error [111:Connection refused]")
11
+ end
12
+
13
+ it "should have close method" do
14
+ @cl.closed?.should be_false
15
+ @cl.close
16
+ @cl.closed?.should be_true
17
+ end
18
+
19
+ it "should have block for connection" do
20
+ @cl.close
21
+ Player::Client.connect("localhost") do |cl|
22
+ @cl = cl
23
+ @cl.closed?.should be_false
24
+ end
25
+
26
+ @cl.closed?.should be_true
27
+ end
28
+
29
+ after do
30
+ @cl.close unless @cl.closed?
31
+ end
32
+ end
@@ -0,0 +1,77 @@
1
+ require "ruby-player"
2
+
3
+ describe Player::Position2d do
4
+ before do
5
+ @cl = Player::Client.connect("localhost")
6
+ @pos2d = @cl[:position2d, 0]
7
+ @pos2d.stop
8
+ @cl.read
9
+ end
10
+
11
+ it 'should set odometry' do
12
+ pending "Don't work with Player/Stage"
13
+ new_od = { px: 1.0, py: 2.0, pa: 3 }
14
+ @pos2d.set_odometry(new_od)
15
+ @pos2d.reset_odometry
16
+
17
+ sleep(1.0)
18
+ @cl.read
19
+
20
+ @pos2d.odometry.should eql(new_od)
21
+ end
22
+
23
+ it 'should move' do
24
+ pos = @pos2d.odometry
25
+ speed = {vx: -0.4, vy: 0.2, va: -0.1 }
26
+ @pos2d.set_speed(speed)
27
+
28
+ sleep(1.1)
29
+ @cl.read
30
+ @pos2d.speed.should eq(speed)
31
+
32
+ #change position
33
+ @pos2d.odometry[:px].should be_within(0.1).of(pos[:px] + speed[:vx]*Math.cos(pos[:pa]) - speed[:vy]*Math.sin(pos[:pa]))
34
+ @pos2d.odometry[:py].should be_within(0.1).of(pos[:py] + speed[:vx]*Math.sin(pos[:pa]) + speed[:vy]*Math.cos(pos[:pa]))
35
+ Math.sin(@pos2d.odometry[:pa]).should be_within(0.1).of(Math.sin(pos[:pa] + speed[:va]))
36
+ end
37
+
38
+
39
+ it 'should move like car' do
40
+ pos = @pos2d.odometry
41
+ speed = { vx: 0.4, a: 0.3 }
42
+ @pos2d.set_car(speed)
43
+
44
+ sleep(1.1)
45
+ @cl.read
46
+ @pos2d.speed.should eq(vx: 0.4, vy: 0.0, va: 0.3)
47
+
48
+ #change position
49
+ @pos2d.odometry[:px].should be_within(0.1).of(pos[:px] + speed[:vx]*Math.cos(pos[:pa]))
50
+ @pos2d.odometry[:py].should be_within(0.1).of(pos[:py] + speed[:vx]*Math.sin(pos[:pa]))
51
+ Math.sin(@pos2d.odometry[:pa]).should be_within(0.1).of(Math.sin(pos[:pa] + speed[:a]))
52
+ end
53
+
54
+ it 'should have stop' do
55
+ # Move robot
56
+ @pos2d.set_speed(vx: 1.0, vy: 0.5, va: -0.2)
57
+ @cl.read
58
+ @pos2d.speed.should eql(vx: 1.0, vy: 0.5, va: -0.2)
59
+ @pos2d.stoped?.should be_false
60
+
61
+ # Stop robot
62
+ @pos2d.stop
63
+ @cl.read
64
+ @pos2d.speed.should eql(vx: 0.0, vy: 0.0, va: 0.0)
65
+ @pos2d.stoped?.should be_true
66
+ end
67
+
68
+ it 'should turn on motor' do
69
+ pending "Don't work with Player/Stage"
70
+ @pos2d.enable.should be_false
71
+ @pos2d.enable = true
72
+ end
73
+
74
+ after do
75
+ @cl.close unless @cl.closed?
76
+ end
77
+ end
@@ -0,0 +1,67 @@
1
+ require "ruby-player"
2
+
3
+ describe Player::Ranger do
4
+ before do
5
+ @cl = Player::Client.connect("localhost")
6
+ @ranger = @cl[:ranger,0]
7
+ @cl.read
8
+ end
9
+
10
+ it 'should have ranges' do
11
+ @ranger.ranges.should eq([3.0, 3.0])
12
+ end
13
+
14
+ it 'should have intensities' do
15
+ @ranger.intensities.should eq([0.0, 0.0])
16
+ end
17
+
18
+ it 'should have bearings' do
19
+ @ranger.bearings.size.should eql(2)
20
+ end
21
+
22
+ it 'should have element count' do
23
+ @ranger.element_count.should eq(0)
24
+ end
25
+
26
+ it 'should have power control' do
27
+ pending "Don't work with Player/Stage"
28
+ #@ranger.power_enable = false
29
+ #@ranger.power_enable = true
30
+ end
31
+
32
+ it 'should have intensity control' do
33
+ pending "Don't work with Player/Stage"
34
+ #@ranger.intensity_enable = false
35
+ #@ranger.intensity_enable = true
36
+ end
37
+
38
+ it 'should porovide method to configurate' do
39
+ pending "Don't work with Player/Stage"
40
+ config = {
41
+ min_angle: 0.3,
42
+ max_angle: 1.0,
43
+ angular_res: 0.1,
44
+ min_range: 0.3,
45
+ max_range: 1,
46
+ range_res: 0.1,
47
+ frequecy: 2
48
+ }
49
+
50
+
51
+ #@ranger.set_config(config)
52
+ end
53
+
54
+ it 'should have configuration' do
55
+ @ranger.config.should eq(
56
+ :min_range=>0.1,
57
+ :max_range=>3.0,
58
+ :angular_res=>0.5235987755982988,
59
+ :range_res=>0.02,
60
+ :frequecy=>10.0
61
+ )
62
+ end
63
+
64
+ after do
65
+ @cl.close unless @cl.closed?
66
+ end
67
+ end
@@ -0,0 +1,18 @@
1
+ # Desc: Player test configuration file
2
+
3
+ driver
4
+ (
5
+ name "stage"
6
+ provides [ "simulation:0" ]
7
+ plugin "stageplugin"
8
+
9
+ worldfile "test.world"
10
+ )
11
+
12
+ driver
13
+ (
14
+ name "stage"
15
+ provides [ "position2d:0" "ranger:0" ]
16
+
17
+ model "bender"
18
+ )
@@ -0,0 +1,89 @@
1
+ quit_time 3600
2
+
3
+ paused 0
4
+
5
+ resolution 0.02
6
+
7
+ window
8
+ (
9
+ size [ 635.000 666.000 ] # in pixels
10
+ scale 36.995 # pixels per meter
11
+ center [ -0.040 -0.274 ]
12
+ rotate [ 0 0 ]
13
+
14
+ show_data 1 # 1=on 0=off
15
+ )
16
+
17
+ define carton model
18
+ (
19
+ color "yelow"
20
+ #carton is retangular
21
+ # so make a square shape and use size[]
22
+ block
23
+ (
24
+ points 4
25
+ point[0] [1 0]
26
+ point[1] [1 4]
27
+ point[2] [0 4]
28
+ point[3] [0 0]
29
+ z [0 1]
30
+ )
31
+ # average litre carton size is ~ 20cm x 10cm x 5cm ish
32
+ size [0.4 4 2]
33
+ )
34
+
35
+
36
+ define bender_ranger ranger
37
+ (
38
+ color "red"
39
+
40
+ sensor
41
+ (
42
+ pose [0 0.1 0.3 15]
43
+ size [0.4 0.4 0.4]
44
+ fov 30
45
+ range [0.1 3]
46
+ )
47
+
48
+ sensor
49
+ (
50
+ pose [0 -0.1 0.3 -15]
51
+ size [0.4 0.4 0.4]
52
+ fov 30
53
+ range [0.1 3]
54
+ )
55
+ )
56
+
57
+ define bender2dx position
58
+ (
59
+ color "grey"
60
+
61
+ block
62
+ (
63
+ points 5
64
+ point[0] [-3 -3]
65
+ point[1] [-3 3]
66
+ point[2] [3 3]
67
+ point[3] [9 0]
68
+ point[4] [3 -3]
69
+ z [0 1]
70
+ )
71
+
72
+ drive "omni"
73
+
74
+ bender_ranger()
75
+ size [1 1 1]
76
+ )
77
+
78
+ #carton
79
+ #(
80
+ # name "c0"
81
+ # pose [ 1 0 0 0.0]
82
+ #)
83
+
84
+ bender2dx
85
+ (
86
+ name "bender"
87
+ pose [ 0 0 0 0.000 ]
88
+
89
+ )