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,4 @@
1
+ Autotest.add_hook :initialize do |at|
2
+ # Ignore the ._* files TextMate likes to leave about.
3
+ at.add_exception(/\/\._[^\/]*$/)
4
+ end
@@ -0,0 +1,3 @@
1
+ == Writing a Rubot Adapter
2
+
3
+ FIXME (stub)
@@ -0,0 +1,4 @@
1
+ == 0.5.0 / 2008-04-22
2
+
3
+ * First Release
4
+ * Major Bug: Segfaults when multiple behaviors run at once.
@@ -0,0 +1,47 @@
1
+ .autotest
2
+ Adapters.txt
3
+ History.txt
4
+ Manifest.txt
5
+ README.txt
6
+ Rakefile
7
+ bin/rubot
8
+ examples/navigate.rbt
9
+ ext/rubot_aria/Makefile
10
+ ext/rubot_aria/RAGenericAction.cpp
11
+ ext/rubot_aria/RAGenericAction.h
12
+ ext/rubot_aria/RAGenericAction.o
13
+ ext/rubot_aria/RARobotManager.cpp
14
+ ext/rubot_aria/RARobotManager.h
15
+ ext/rubot_aria/RARobotManager.o
16
+ ext/rubot_aria/extconf.rb
17
+ ext/rubot_aria/rubot_aria.cpp
18
+ ext/rubot_aria/rubot_aria.o
19
+ ext/rubot_aria/rubot_aria.so
20
+ lib/rubot.rb
21
+ lib/rubot/adapters.rb
22
+ lib/rubot/adapters/aria.rb
23
+ lib/rubot/adapters/aria/action_desired.rb
24
+ lib/rubot/adapters/aria/robot.rb
25
+ lib/rubot/adapters/asimov.rb
26
+ lib/rubot/dsl.rb
27
+ lib/rubot/meta.rb
28
+ spec/load_paths.rb
29
+ spec/rubot/adapters/aria/robot_manager_spec.rb
30
+ spec/rubot/adapters/aria/robot_spec.rb
31
+ spec/rubot/adapters/aria_spec.rb
32
+ spec/rubot/adapters/spec_helper.rb
33
+ spec/rubot/dsl_spec.rb
34
+ spec/rubot_spec.rb
35
+ spec/spec.opts
36
+ spec/spec_helper.rb
37
+ tasks/ann.rake
38
+ tasks/annotations.rake
39
+ tasks/doc.rake
40
+ tasks/gem.rake
41
+ tasks/manifest.rake
42
+ tasks/post_load.rake
43
+ tasks/rubyforge.rake
44
+ tasks/setup.rb
45
+ tasks/spec.rake
46
+ tasks/svn.rake
47
+ tasks/test.rake
@@ -0,0 +1,53 @@
1
+ IMPORTANT:
2
+ This version of Rubot is incomplete and presented publicly for the sole purpose (currently) of discussion and testing. Many things are broken, many files are incomplete. Even this README needs a good deal of work.
3
+
4
+ =====
5
+
6
+ rubot
7
+ by Peter Jaros (Peeja) <peter.a.jaros@gmail.com>
8
+ http://rubot.org/ (pending)
9
+
10
+ == DESCRIPTION:
11
+
12
+ FIXME (describe your package)
13
+
14
+ == FEATURES/PROBLEMS:
15
+
16
+ * FIXME (list of features or problems)
17
+
18
+ == SYNOPSIS:
19
+
20
+ rubot mycode.rbt
21
+
22
+ == REQUIREMENTS:
23
+
24
+ * FIXME (list of requirements)
25
+
26
+ == INSTALL:
27
+
28
+ * FIXME (sudo gem install, anything else)
29
+
30
+ == LICENSE:
31
+
32
+ (The MIT License)
33
+
34
+ Copyright (c) 2008
35
+
36
+ Permission is hereby granted, free of charge, to any person obtaining
37
+ a copy of this software and associated documentation files (the
38
+ 'Software'), to deal in the Software without restriction, including
39
+ without limitation the rights to use, copy, modify, merge, publish,
40
+ distribute, sublicense, and/or sell copies of the Software, and to
41
+ permit persons to whom the Software is furnished to do so, subject to
42
+ the following conditions:
43
+
44
+ The above copyright notice and this permission notice shall be
45
+ included in all copies or substantial portions of the Software.
46
+
47
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
48
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
50
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
51
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
52
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
53
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ # Look in the tasks/setup.rb file for the various options that can be
2
+ # configured in this Rakefile. The .rake files in the tasks directory
3
+ # are where the options are used.
4
+
5
+ load 'tasks/setup.rb'
6
+
7
+ ensure_in_path 'lib'
8
+ require 'rubot'
9
+
10
+ task :default => 'spec:run'
11
+
12
+ PROJ.name = 'rubot'
13
+ PROJ.authors = 'Peter Jaros (Peeja)'
14
+ PROJ.email = 'peter.a.jaros@gmail.com'
15
+ PROJ.url = 'http://rubot.org/'
16
+ # PROJ.rubyforge_name = 'rubot'
17
+ PROJ.version = Rubot.version
18
+
19
+ PROJ.executables = ['rubot']
20
+ PROJ.dependencies << ['rice', '>= 1.0.1'] << ['facets', '>= 2.3.0']
21
+
22
+ PROJ.spec_opts += File.read('spec/spec.opts').split
23
+ PROJ.spec_opts << '-fs'
24
+
25
+ # Don't expect test coverage of any file with an absolute path.
26
+ PROJ.rcov_opts << '--exclude' << '^/' << '--exclude' << 'meta.rb$'
27
+ PROJ.rcov_threshold_exact = true
28
+
29
+ PROJ.exclude << '^\.git/' << '\.gitignore$' << '/\.DS_Store$' << '^\.DS_Store$' << '/\._' << '^\._' << 'mkmf.log'
30
+
31
+ # EOF
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ # require 'main'
5
+ require 'rubot'
6
+
7
+ # Main do
8
+ # argument 'file' do
9
+ # required
10
+ # description 'Rubot file to run'
11
+ # end
12
+ #
13
+ # def run
14
+ # include Rubot::DSL
15
+ # load params['file']
16
+ # end
17
+ # end
18
+
19
+ include Rubot::DSL
20
+ load ARGV[0]
@@ -0,0 +1,60 @@
1
+ # navigate.rbt
2
+
3
+ # Make a behavior to go forward, slowing when we approach an obstacle.
4
+
5
+ behavior :go => [:max_speed, :stop_distance] do
6
+ sensors :sonar
7
+
8
+ fire do
9
+ range = sonar.range(-70,70) - robot.radius
10
+ if range > stop_distance
11
+ speed = range * 0.3
12
+ speed = max_speed if (speed > max_speed)
13
+ desired.velocity = speed
14
+ else
15
+ desired.velocity = 0
16
+ end
17
+ end
18
+ end
19
+
20
+
21
+ # Make another behavior to turn us around objects we can avoid.
22
+
23
+ behavior :turn => [:turn_threshold, :turn_amount] do
24
+ sensors :sonar
25
+
26
+ fire do
27
+ # Get the left readings and right readings off of the sonar
28
+ left_range = sonar.range(0,100) - robot.radius
29
+ right_range = sonar.range(-100,0) - robot.radius
30
+ if left_range > turn_threshold && right_range > turn_threshold
31
+ # if neither left nor right range is within the turn threshold,
32
+ # reset the turning variable and don't turn
33
+ turn_direction = nil
34
+ desired.delta_heading = 0;
35
+ else
36
+ turn_direction ||= (left_range < right_range ? :left : :right)
37
+ desired.delta_heading = turn_amount * ( turn_direction == :left ? -1 : 1 )
38
+ end
39
+ end
40
+ end
41
+
42
+
43
+ # Set up a robot.
44
+
45
+ robot :fred do
46
+ adapter :aria
47
+ host 'localhost'
48
+
49
+ sensors :sonar
50
+
51
+ behaviors do
52
+ go :priority => 50, :max_speed => 240, :stop_distance => 300
53
+ turn :priority => 49, :turn_threshold => 400, :turn_amount => 10
54
+ end
55
+ end
56
+
57
+
58
+ # Run it.
59
+
60
+ run :fred
@@ -0,0 +1,87 @@
1
+ #include "rice/Object.hpp"
2
+ #include "rice/Data_Type.hpp"
3
+ #include "rice/Symbol.hpp"
4
+ #include "rice/Exception.hpp"
5
+ #include "Aria.h"
6
+
7
+ #include "RAGenericAction.h"
8
+
9
+ using namespace Rice;
10
+
11
+ RAGenericAction::RAGenericAction(const char *name)
12
+ : ArAction(name)
13
+ {
14
+ ArLog::log(ArLog::Normal, "Created generic action \"%s\".", name);
15
+ myFireProc = NULL;
16
+ myFireProc_guard = NULL;
17
+
18
+ // Sensors
19
+ mySonar = NULL;
20
+ }
21
+
22
+ RAGenericAction::~RAGenericAction()
23
+ {
24
+ if (myFireProc != NULL) {
25
+ delete myFireProc;
26
+ delete myFireProc_guard;
27
+ }
28
+ ArLog::log(ArLog::Normal, "Destroyed generic action \"%s\".", getName());
29
+ }
30
+
31
+ ArActionDesired *RAGenericAction::fire(ArActionDesired currentDesired)
32
+ {
33
+ myDesired.reset();
34
+
35
+ // FIXME: myFireProc eventually has type 0 (T_NONE), and calling #call segfaults.
36
+ // Only happens when multiple behaviors are used at once.
37
+ // if (myFireProc != NULL && myFireProc->rb_type() == 0)
38
+ // ArLog::log(ArLog::Normal, "Proc has type: %d.", myFireProc->rb_type());
39
+
40
+ if (myFireProc != NULL)
41
+ myFireProc->call("call");
42
+
43
+ return &myDesired;
44
+ }
45
+
46
+ void RAGenericAction::setFireProc(Object proc)
47
+ {
48
+ if (!proc.is_a(rb_cProc))
49
+ throw Exception(rb_eArgError, "proc needs to be a Proc.");
50
+ if (myFireProc != NULL) {
51
+ delete myFireProc;
52
+ delete myFireProc_guard;
53
+ }
54
+ myFireProc = new Object(proc);
55
+ myFireProc_guard = new Address_Registration_Guard(myFireProc);
56
+ }
57
+
58
+ void RAGenericAction::setSensors(Object sensors)
59
+ {
60
+ // TODO: Make sure rubot_aria supports the given sensors.
61
+ // ArLog::log(ArLog::Normal, "Action \"%s\"'s sensors started with \"%s\".", getName(), Symbol(mySensors.call("first")).c_str());
62
+ mySensors.call("replace", Array(sensors));
63
+ // ArLog::log(ArLog::Normal, "Action \"%s\"'s sensors now start with \"%s\".", getName(), Symbol(mySensors.call("first")).c_str());
64
+ }
65
+
66
+ void RAGenericAction::setRobot(ArRobot *robot)
67
+ {
68
+ ArAction::setRobot(robot);
69
+ ArLog::log(ArLog::Normal, "Setting robot for action \"%s\".", getName());
70
+
71
+ // Acquire sensors.
72
+ // TODO: Handle robot not supporting sensors better.
73
+ for (Array::iterator it = mySensors.begin(); it != mySensors.end(); ++it) {
74
+ if (*it == Symbol("sonar")) {
75
+ ArLog::log(ArLog::Normal, "Adding sonar.");
76
+ mySonar = robot->findRangeDevice("sonar");
77
+ }
78
+ }
79
+ }
80
+
81
+ Object RAGenericAction::getSensor(Symbol sensor)
82
+ {
83
+ if (sensor == Symbol("sonar") && mySonar)
84
+ return to_ruby(mySonar);
85
+ else
86
+ return Object(Qnil);
87
+ }
@@ -0,0 +1,96 @@
1
+ #pragma once
2
+
3
+ #include "rice/Array.hpp"
4
+ #include "rice/Object.hpp"
5
+ #include "rice/Data_Object.hpp"
6
+ #include "rice/Address_Registration_Guard.hpp"
7
+ #include "Aria.h"
8
+
9
+ /*
10
+ * RAGenericAction
11
+ * Generic ArAction that runs a Ruby proc when it fires.
12
+ *
13
+ */
14
+
15
+ class RAGenericAction : public ArAction
16
+ {
17
+ public:
18
+ RAGenericAction(const char *name);
19
+ virtual ~RAGenericAction(void);
20
+ virtual ArActionDesired *fire(ArActionDesired currentDesired);
21
+ void setFireProc(Rice::Object proc);
22
+ void setSensors(Rice::Object sensors);
23
+ Rice::Object getSensor(Rice::Symbol sensor);
24
+ virtual void setRobot(ArRobot *robot);
25
+ ArActionDesired *getActionDesired() { return &myDesired; }
26
+
27
+ protected:
28
+ ArActionDesired myDesired;
29
+ Rice::Object *myFireProc;
30
+ Rice::Address_Registration_Guard *myFireProc_guard;
31
+ Rice::Array mySensors;
32
+
33
+ // Sensors
34
+ ArRangeDevice *mySonar;
35
+ };
36
+
37
+
38
+ // We need a disposable wrapper for ArActionDesired which Ruby can GC at its
39
+ // pleasure. This class delegates all calls to its wrapped ArActionDesired.
40
+ // We have to duplicate the entirety of the interface we want Ruby to be able
41
+ // to use. It would be nice to automate this somehow with macros.
42
+
43
+ class ArActionDesiredWrap
44
+ {
45
+ public:
46
+ ArActionDesiredWrap(ArActionDesired *obj) { myObj = obj; }
47
+ virtual ~ArActionDesiredWrap() {}
48
+
49
+ double getVel() const { return myObj->getVel(); }
50
+ double getVelStrength() const { return myObj->getVelStrength(); }
51
+ void setVel(double vel, double strength) const { myObj->setVel(vel, strength); }
52
+
53
+ double getDeltaHeading() const { return myObj->getDeltaHeading(); }
54
+ double getDeltaHeadingStrength() const { return myObj->getDeltaHeadingStrength(); }
55
+ void setDeltaHeading(double deltaHeading, double strength) const { myObj->setDeltaHeading(deltaHeading, strength); }
56
+
57
+ double getHeading() const { return myObj->getHeading(); }
58
+ double getHeadingStrength() const { return myObj->getHeadingStrength(); }
59
+ void setHeading(double heading, double strength) const { myObj->setHeading(heading, strength); }
60
+
61
+ private:
62
+ ArActionDesired *myObj;
63
+ };
64
+
65
+ template<>
66
+ inline
67
+ Rice::Object to_ruby<ArActionDesired *>(ArActionDesired * const & x)
68
+ {
69
+ return Rice::Data_Object<ArActionDesiredWrap>(new ArActionDesiredWrap(x));
70
+ }
71
+
72
+
73
+ // We also need a wrapper for ArRangeDevice.
74
+
75
+ class ArRangeDeviceWrap
76
+ {
77
+ public:
78
+ ArRangeDeviceWrap(ArRangeDevice *obj) { myObj = obj; }
79
+ virtual ~ArRangeDeviceWrap() { }
80
+
81
+ double currentReadingPolar(double startAngle, double endAngle)
82
+ {
83
+ return myObj->currentReadingPolar(startAngle, endAngle, NULL);
84
+ }
85
+
86
+ private:
87
+ ArRangeDevice *myObj;
88
+ };
89
+
90
+
91
+ template<>
92
+ inline
93
+ Rice::Object to_ruby<ArRangeDevice *>(ArRangeDevice * const & x)
94
+ {
95
+ return Rice::Data_Object<ArRangeDeviceWrap>(new ArRangeDeviceWrap(x));
96
+ }
@@ -0,0 +1,73 @@
1
+ #include "Aria.h"
2
+ #include "RARobotManager.h"
3
+
4
+ using namespace Rice;
5
+
6
+
7
+ RARobotManager::RARobotManager()
8
+ : myRobot(), myStopCB(this, &RARobotManager::stop)
9
+ {
10
+ ArLog::log(ArLog::Normal, "Created robot manager.");
11
+ myRobotKeyHandler = NULL;
12
+
13
+ // Sensors
14
+ mySonar = NULL;
15
+ }
16
+
17
+ RARobotManager::~RARobotManager()
18
+ {
19
+ if (myRobotKeyHandler != NULL)
20
+ delete myRobotKeyHandler;
21
+ if (mySonar != NULL)
22
+ delete mySonar;
23
+ ArLog::log(ArLog::Normal, "Destroyed robot manager.");
24
+ }
25
+
26
+ // Connect to robot and run.
27
+ void RARobotManager::go(const char *argString="")
28
+ {
29
+ ArArgumentBuilder args;
30
+ args.add(argString);
31
+ ArSimpleConnector conn(&args);
32
+ conn.parseArgs();
33
+ // TODO: Handle connection error
34
+ conn.connectRobot(&myRobot);
35
+ myRobot.enableMotors();
36
+
37
+ if (myRobotKeyHandler != NULL)
38
+ delete myRobotKeyHandler;
39
+ myRobotKeyHandler = new ArKeyHandler(false, false);
40
+ myRobotKeyHandler->addKeyHandler(ArKeyHandler::ESCAPE, &myStopCB);
41
+ myRobot.attachKeyHandler(myRobotKeyHandler, false);
42
+
43
+ myRobot.run(true);
44
+ }
45
+
46
+
47
+ void RARobotManager::stop()
48
+ {
49
+ myRobot.stopRunning();
50
+ if (myRobotKeyHandler != NULL) {
51
+ delete myRobotKeyHandler;
52
+ myRobotKeyHandler = NULL;
53
+ }
54
+ }
55
+
56
+
57
+ void RARobotManager::addAction(RAGenericAction *action, int priority)
58
+ {
59
+ ArLog::log(ArLog::Normal, "Adding action \"%s\" with priority %d.", action->getName(), priority);
60
+ myRobot.addAction(action, priority);
61
+ }
62
+
63
+
64
+ void RARobotManager::addSensor(Symbol sensor)
65
+ {
66
+ if (sensor == Symbol("sonar") && mySonar == NULL) {
67
+ mySonar = new ArSonarDevice;
68
+ myRobot.addRangeDevice(mySonar);
69
+ }
70
+ else {
71
+ // TODO: Tell user if sensor is not supported.
72
+ }
73
+ }