Peeja-rubot 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,9 @@
1
+ require 'rubygems'
2
+ require 'mkmf-rice'
3
+
4
+ dir_config("Aria", "/usr/local/Aria/include", "/usr/local/Aria/lib")
5
+ unless have_library('Aria')
6
+ exit
7
+ end
8
+
9
+ create_makefile('rubot_aria')
@@ -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
+ }
@@ -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,5 @@
1
+ require 'rubot' if not defined? Rubot
2
+ require 'rubot_aria'
3
+
4
+ require File.dirname(__FILE__) + "/aria/robot"
5
+ require File.dirname(__FILE__) + "/aria/action_desired"
@@ -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
@@ -0,0 +1,2 @@
1
+ require 'rubot'
2
+ require 'rubot_asimov'
@@ -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
@@ -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
@@ -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