ruby-player 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ )