Peeja-rubot 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.autotest +4 -0
- data/Adapters.txt +3 -0
- data/History.txt +4 -0
- data/Manifest.txt +47 -0
- data/README.txt +53 -0
- data/Rakefile +31 -0
- data/bin/rubot +20 -0
- data/examples/navigate.rbt +60 -0
- data/ext/rubot_aria/RAGenericAction.cpp +87 -0
- data/ext/rubot_aria/RAGenericAction.h +96 -0
- data/ext/rubot_aria/RARobotManager.cpp +73 -0
- data/ext/rubot_aria/RARobotManager.h +30 -0
- data/ext/rubot_aria/extconf.rb +9 -0
- data/ext/rubot_aria/rubot_aria.cpp +63 -0
- data/lib/rubot.rb +14 -0
- data/lib/rubot/adapters.rb +39 -0
- data/lib/rubot/adapters/aria.rb +5 -0
- data/lib/rubot/adapters/aria/action_desired.rb +18 -0
- data/lib/rubot/adapters/aria/robot.rb +30 -0
- data/lib/rubot/adapters/asimov.rb +2 -0
- data/lib/rubot/dsl.rb +161 -0
- data/lib/rubot/meta.rb +13 -0
- data/spec/load_paths.rb +9 -0
- data/spec/rubot/adapters/aria/robot_manager_spec.rb +12 -0
- data/spec/rubot/adapters/aria/robot_spec.rb +38 -0
- data/spec/rubot/adapters/aria_spec.rb +5 -0
- data/spec/rubot/adapters/spec_helper.rb +16 -0
- data/spec/rubot/dsl_spec.rb +22 -0
- data/spec/rubot_spec.rb +4 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/ann.rake +76 -0
- data/tasks/annotations.rake +22 -0
- data/tasks/doc.rake +48 -0
- data/tasks/gem.rake +110 -0
- data/tasks/manifest.rake +49 -0
- data/tasks/post_load.rake +26 -0
- data/tasks/rubyforge.rake +57 -0
- data/tasks/setup.rb +227 -0
- data/tasks/spec.rake +54 -0
- data/tasks/svn.rake +44 -0
- data/tasks/test.rake +38 -0
- metadata +121 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
#pragma once
|
2
|
+
|
3
|
+
#include "Aria.h"
|
4
|
+
#include "RAGenericAction.h"
|
5
|
+
|
6
|
+
/*
|
7
|
+
* RARobotManager
|
8
|
+
* Encapsulates an ArRobot and its connection.
|
9
|
+
*
|
10
|
+
*/
|
11
|
+
|
12
|
+
class RARobotManager
|
13
|
+
{
|
14
|
+
public:
|
15
|
+
RARobotManager();
|
16
|
+
virtual ~RARobotManager();
|
17
|
+
void go(const char *argString);
|
18
|
+
void stop();
|
19
|
+
void addAction(RAGenericAction *action, int priority);
|
20
|
+
void addSensor(Rice::Symbol sensor);
|
21
|
+
double getRobotRadius() { return myRobot.getRobotRadius(); }
|
22
|
+
|
23
|
+
private:
|
24
|
+
ArRobot myRobot;
|
25
|
+
ArFunctorC<RARobotManager> myStopCB;
|
26
|
+
ArKeyHandler *myRobotKeyHandler;
|
27
|
+
|
28
|
+
// Sensors
|
29
|
+
ArSonarDevice *mySonar;
|
30
|
+
};
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#include "rice/Module.hpp"
|
2
|
+
#include "rice/Data_Type.hpp"
|
3
|
+
#include "rice/Constructor.hpp"
|
4
|
+
#include "rice/Exception.hpp"
|
5
|
+
#include "rice/Array.hpp"
|
6
|
+
#include "Aria.h"
|
7
|
+
|
8
|
+
#include "RAGenericAction.h"
|
9
|
+
#include "RARobotManager.h"
|
10
|
+
|
11
|
+
using namespace std;
|
12
|
+
using namespace Rice;
|
13
|
+
|
14
|
+
extern "C"
|
15
|
+
void Init_rubot_aria()
|
16
|
+
{
|
17
|
+
static char inited = 0;
|
18
|
+
if (!inited) Aria::init(Aria::SIGHANDLE_NONE);
|
19
|
+
inited = 1;
|
20
|
+
|
21
|
+
Object rb_MRubot = Class(rb_cObject).const_get("Rubot");
|
22
|
+
Object rb_MAdapters = Module(rb_MRubot).const_get("Adapters");
|
23
|
+
Object rb_MAria = Module(rb_MAdapters)
|
24
|
+
.define_module("Aria")
|
25
|
+
;
|
26
|
+
|
27
|
+
|
28
|
+
Data_Type<RARobotManager> rb_cRobotManager = Module(rb_MAria)
|
29
|
+
.define_class<RARobotManager>("RobotManager")
|
30
|
+
.define_constructor(Constructor<RARobotManager>())
|
31
|
+
.define_method("go", &RARobotManager::go)
|
32
|
+
.define_method("add_behavior", &RARobotManager::addAction)
|
33
|
+
.define_method("add_sensor", &RARobotManager::addSensor)
|
34
|
+
.define_method("robot_radius", &RARobotManager::getRobotRadius)
|
35
|
+
;
|
36
|
+
|
37
|
+
Data_Type<RAGenericAction> rb_cBehavior = Module(rb_MAria)
|
38
|
+
.define_class<RAGenericAction>("Behavior")
|
39
|
+
.define_constructor(Constructor<RAGenericAction, const char *>())
|
40
|
+
.define_method("set_fire_proc", &RAGenericAction::setFireProc)
|
41
|
+
.define_method("set_sensors", &RAGenericAction::setSensors)
|
42
|
+
.define_method("get_sensor", &RAGenericAction::getSensor)
|
43
|
+
.define_method("get_desired", &RAGenericAction::getActionDesired)
|
44
|
+
;
|
45
|
+
|
46
|
+
Data_Type<ArActionDesiredWrap> rb_cActionDesired = Module(rb_MAria)
|
47
|
+
.define_class<ArActionDesiredWrap>("ActionDesired")
|
48
|
+
.define_method("velocity", &ArActionDesiredWrap::getVel)
|
49
|
+
.define_method("velocity_strength", &ArActionDesiredWrap::getVelStrength)
|
50
|
+
.define_method("set_velocity", &ArActionDesiredWrap::setVel)
|
51
|
+
.define_method("delta_heading", &ArActionDesiredWrap::getDeltaHeading)
|
52
|
+
.define_method("delta_heading_strength", &ArActionDesiredWrap::getDeltaHeadingStrength)
|
53
|
+
.define_method("set_delta_heading", &ArActionDesiredWrap::setDeltaHeading)
|
54
|
+
.define_method("heading", &ArActionDesiredWrap::getHeading)
|
55
|
+
.define_method("heading_strength", &ArActionDesiredWrap::getHeadingStrength)
|
56
|
+
.define_method("set_heading", &ArActionDesiredWrap::setHeading)
|
57
|
+
;
|
58
|
+
|
59
|
+
Data_Type<ArRangeDeviceWrap> rb_cRangeDevice = Module(rb_MAria)
|
60
|
+
.define_class<ArRangeDeviceWrap>("RangeDevice")
|
61
|
+
.define_method("range", &ArRangeDeviceWrap::currentReadingPolar)
|
62
|
+
;
|
63
|
+
}
|
data/lib/rubot.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# Require everything except things under rubot/adapters/ (which load lazily).
|
2
|
+
# (Dir[File.join(::File.dirname(__FILE__), '**', '*.rb')] -
|
3
|
+
# Dir[File.join(::File.dirname(__FILE__), 'rubot', 'adapters', '**')]).sort.each {|rb| require rb}
|
4
|
+
|
5
|
+
unless defined? Rubot
|
6
|
+
|
7
|
+
module Rubot; end
|
8
|
+
|
9
|
+
require 'rubot/meta'
|
10
|
+
|
11
|
+
require 'rubot/adapters'
|
12
|
+
require 'rubot/dsl'
|
13
|
+
|
14
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'facets/string/snakecase'
|
2
|
+
require 'facets/module/alias'
|
3
|
+
|
4
|
+
# This module contains the robotics adapters. For instance, the ACME
|
5
|
+
# Robotics adapter would be <tt>Rubot::Adapters::AcmeRobotics</tt>. Its robot
|
6
|
+
# class would be <tt>Rubot::Adapters::AcmeRobotics::Robot</tt>, and one can be
|
7
|
+
# created with
|
8
|
+
#
|
9
|
+
# fred = Rubot::Adapters::AcmeRobotics::Robot.new
|
10
|
+
#
|
11
|
+
# or, in Rubot syntax,
|
12
|
+
#
|
13
|
+
# robot :fred do
|
14
|
+
# adapter :acme_robotics
|
15
|
+
# end
|
16
|
+
module Rubot
|
17
|
+
# Raised when attempting to create a robot with an unrecognized adapter.
|
18
|
+
class AdapterMissingError < Exception; end
|
19
|
+
|
20
|
+
module Adapters
|
21
|
+
class << self
|
22
|
+
def const_missing_with_autoload(name)
|
23
|
+
# TODO: Handle missing adapter without obscuring all LoadErrors.
|
24
|
+
# begin
|
25
|
+
req_name = "rubot/adapters/#{name.to_s.snakecase}"
|
26
|
+
require req_name
|
27
|
+
if const_defined? name
|
28
|
+
return const_get(name)
|
29
|
+
else
|
30
|
+
raise AdapterMissingError, "Adapter #{name} not loaded by '#{req_name}'."
|
31
|
+
end
|
32
|
+
# rescue LoadError
|
33
|
+
# raise AdapterMissingError, "Adapter #{name} not found."
|
34
|
+
# end
|
35
|
+
end
|
36
|
+
alias_method_chain :const_missing, :autoload
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rubot::Adapters::Aria
|
2
|
+
class ActionDesired
|
3
|
+
%w[ velocity delta_heading heading ].each do |channel|
|
4
|
+
eval <<-CHAN_DEF
|
5
|
+
private :set_#{channel}
|
6
|
+
|
7
|
+
def #{channel}=(val)
|
8
|
+
# Use current channel strength, or maximum (1) if not set.
|
9
|
+
set_#{channel} val, (#{channel}_strength != 0 ? #{channel}_strength : 1)
|
10
|
+
end
|
11
|
+
|
12
|
+
def #{channel}_strength=(strength)
|
13
|
+
set_#{channel} #{channel}, strength
|
14
|
+
end
|
15
|
+
CHAN_DEF
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Rubot::Adapters::Aria
|
2
|
+
class Robot
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
def initialize
|
6
|
+
@options = {}
|
7
|
+
@manager = RobotManager.new
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
args = ''
|
12
|
+
args << "-remoteHost #{@options[:host]} " if @options[:host]
|
13
|
+
args << "-remoteRobotTcpPort #{@options[:port]} " if @options[:port]
|
14
|
+
@manager.go args
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_behavior(behavior, priority)
|
18
|
+
raise ArgumentError, "Behavior must be an Aria::Behavior" unless behavior.instance_of? Behavior
|
19
|
+
@manager.add_behavior(behavior, priority)
|
20
|
+
end
|
21
|
+
|
22
|
+
def add_sensor(sensor)
|
23
|
+
@manager.add_sensor(sensor)
|
24
|
+
end
|
25
|
+
|
26
|
+
def radius
|
27
|
+
@manager.robot_radius
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/lib/rubot/dsl.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'facets/string/camelcase'
|
2
|
+
require 'facets/symbol/to_proc'
|
3
|
+
|
4
|
+
module Rubot::DSL
|
5
|
+
BehaviorFactories = {}
|
6
|
+
Robots = {}
|
7
|
+
|
8
|
+
class BehaviorFactoryBuilder
|
9
|
+
def initialize(name, args, &block)
|
10
|
+
@name = name.to_sym
|
11
|
+
@args = args
|
12
|
+
@sensors = []
|
13
|
+
self.instance_eval(&block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Defines the block of code to run when this behavior fires.
|
17
|
+
#
|
18
|
+
# behavior :do_stuff do
|
19
|
+
# fire do
|
20
|
+
# # Do stuff
|
21
|
+
# end
|
22
|
+
# end
|
23
|
+
def fire(&block)
|
24
|
+
@fire = block
|
25
|
+
end
|
26
|
+
|
27
|
+
# Specifies sensors to make available to the fire block.
|
28
|
+
#
|
29
|
+
# behavior :log_sonar do
|
30
|
+
# sensors :sonar
|
31
|
+
# fire do
|
32
|
+
# puts "Sonar is reading #{sonar.range(-70,70)}"
|
33
|
+
# end
|
34
|
+
# end
|
35
|
+
def sensors(*sensors)
|
36
|
+
@sensors += sensors.map(&:to_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build
|
40
|
+
BehaviorFactory.new(@name, @args, @fire, @sensors.uniq)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class BehaviorFactory
|
45
|
+
def initialize(name, accepted_args, fire, sensors)
|
46
|
+
@name = name
|
47
|
+
@accepted_args = accepted_args
|
48
|
+
@fire = fire
|
49
|
+
@sensors = sensors
|
50
|
+
end
|
51
|
+
|
52
|
+
def create_for_robot(robot, adapter, given_args={})
|
53
|
+
BehaviorContext.new(@name, @accepted_args, @fire, @sensors, robot, adapter, given_args).behavior
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
class BehaviorContext
|
58
|
+
attr_reader :behavior, :robot
|
59
|
+
def initialize(name, accepted_args, fire, sensors, robot, adapter, given_args={})
|
60
|
+
@name = name
|
61
|
+
@accepted_args = accepted_args
|
62
|
+
@fire = fire
|
63
|
+
@sensors = sensors
|
64
|
+
@robot = robot
|
65
|
+
@given_args = given_args
|
66
|
+
@behavior = Rubot::Adapters.const_get(adapter)::Behavior.new name.to_s
|
67
|
+
# Have the behavior execute the fire proc in context of this object.
|
68
|
+
@behavior.set_fire_proc Proc.new { self.instance_eval(&@fire) }
|
69
|
+
@behavior.set_sensors @sensors
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return the named sensor or argument.
|
73
|
+
def method_missing(sym, *args)
|
74
|
+
if @sensors.include? sym
|
75
|
+
@behavior.get_sensor(sym)
|
76
|
+
elsif @accepted_args.include? sym
|
77
|
+
@given_args[sym]
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def desired
|
84
|
+
@behavior.get_desired
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class RobotBuilder
|
89
|
+
attr_reader :adapter
|
90
|
+
def initialize(name, &block)
|
91
|
+
@name = name.to_sym
|
92
|
+
@options = {}
|
93
|
+
@sensors = []
|
94
|
+
@behaviors = []
|
95
|
+
self.instance_eval(&block)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Set the adapter for the robot, if name is given.
|
99
|
+
def adapter(name)
|
100
|
+
# TODO: Stop user from changing the adapter once set.
|
101
|
+
@adapter = name.to_s.camelcase(true).to_sym
|
102
|
+
end
|
103
|
+
|
104
|
+
def sensors(*sensors)
|
105
|
+
@sensors += sensors.map(&:to_sym)
|
106
|
+
end
|
107
|
+
|
108
|
+
def behaviors(&block)
|
109
|
+
@behaviors += RobotBehaviorsBuilder.new(&block).behaviors
|
110
|
+
end
|
111
|
+
|
112
|
+
def method_missing(opt, *args)
|
113
|
+
@options[opt] = ( args.size == 1 ? args.first : args )
|
114
|
+
nil
|
115
|
+
end
|
116
|
+
|
117
|
+
def build
|
118
|
+
raise "Robot #{@name} declared without an adapter." unless @adapter
|
119
|
+
robot = Rubot::Adapters.const_get(@adapter)::Robot.new
|
120
|
+
robot.options.merge! @options
|
121
|
+
@sensors.each { |s| robot.add_sensor s }
|
122
|
+
@behaviors.each do |name, priority, args|
|
123
|
+
b = BehaviorFactories[name].create_for_robot(robot, @adapter, args)
|
124
|
+
robot.add_behavior b, priority
|
125
|
+
end
|
126
|
+
robot
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
# Builds up a list of behaviors for the robot.
|
131
|
+
class RobotBehaviorsBuilder
|
132
|
+
attr_reader :behaviors
|
133
|
+
def initialize(&block)
|
134
|
+
@behaviors = []
|
135
|
+
self.instance_eval(&block)
|
136
|
+
end
|
137
|
+
|
138
|
+
def method_missing(name, args={})
|
139
|
+
priority = args.delete(:priority) do |_|
|
140
|
+
# TODO: raise hell if priority is not given.
|
141
|
+
end
|
142
|
+
@behaviors << [name.to_sym, priority, args]
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def behavior(name, &block)
|
147
|
+
name, args = name.to_a.first if name.instance_of? Hash
|
148
|
+
args ||= []
|
149
|
+
bb = BehaviorFactoryBuilder.new(name, args, &block)
|
150
|
+
BehaviorFactories[name.to_sym] = bb.build
|
151
|
+
end
|
152
|
+
|
153
|
+
def robot(name, &block)
|
154
|
+
rb = RobotBuilder.new(name, &block)
|
155
|
+
Robots[name.to_sym] = rb.build
|
156
|
+
end
|
157
|
+
|
158
|
+
def run(name)
|
159
|
+
Robots[name].run
|
160
|
+
end
|
161
|
+
end
|
data/lib/rubot/meta.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Rubot
|
2
|
+
# :stopdoc:
|
3
|
+
VERSION = '0.5.0'
|
4
|
+
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
5
|
+
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
6
|
+
# :startdoc:
|
7
|
+
|
8
|
+
# Returns the version string for the library.
|
9
|
+
#
|
10
|
+
def self.version
|
11
|
+
VERSION
|
12
|
+
end
|
13
|
+
end
|
data/spec/load_paths.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# Adds load paths to extensions for RSpec. At build, extensions end up in lib/ anyhow.
|
2
|
+
Dir['ext/*'].each do |dir|
|
3
|
+
if test ?d, dir
|
4
|
+
$LOAD_PATH.unshift dir
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
# The rake task takes care of this for us, but autotest needs it.
|
9
|
+
$LOAD_PATH.unshift 'lib' unless $LOAD_PATH.include? 'lib'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. .. .. spec_helper])
|
2
|
+
|
3
|
+
describe Rubot::Adapters::Aria::RobotManager do
|
4
|
+
it "should be creatable" do
|
5
|
+
lambda { Rubot::Adapters::Aria::RobotManager.new }.should_not raise_error
|
6
|
+
end
|
7
|
+
|
8
|
+
# We can't really test that #go works, but we can make sure it's defined.
|
9
|
+
it "should connect to robot" do
|
10
|
+
Rubot::Adapters::Aria::RobotManager.instance_methods.should include("go")
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), %w[.. .. .. spec_helper])
|
2
|
+
|
3
|
+
# fred = Rubot::Adapters::Aria::Robot.new
|
4
|
+
# fred.options[:host] = 'localhost'
|
5
|
+
|
6
|
+
include Rubot::Adapters::Aria
|
7
|
+
|
8
|
+
describe Robot do
|
9
|
+
before(:each) do
|
10
|
+
@mock_manager = mock("manager")
|
11
|
+
RobotManager.stub!(:new).and_return(@mock_manager)
|
12
|
+
@robot = Robot.new
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have options hash" do
|
16
|
+
@robot.options[:be_awesome] = true
|
17
|
+
@robot.options.keys.should include(:be_awesome)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should run the robot" do
|
21
|
+
@mock_manager.should_receive(:go)
|
22
|
+
@robot.run
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should connect to the specified host" do
|
26
|
+
@robot.options[:host] = 'robothost'
|
27
|
+
@mock_manager.should_receive(:go).with(/-remoteHost robothost/)
|
28
|
+
@robot.run
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should connect to the specified port" do
|
32
|
+
@robot.options[:port] = 3456
|
33
|
+
@mock_manager.should_receive(:go).with(/-remoteRobotTcpPort 3456/)
|
34
|
+
@robot.run
|
35
|
+
end
|
36
|
+
|
37
|
+
# TODO: Add serial connection support.
|
38
|
+
end
|