Peeja-rubot 0.5.0

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,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