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