pangdudu-robots 0.2.1 → 0.2.2
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.
- data/README.rdoc +3 -4
- data/config/org.robots.service.conf +0 -2
- data/config/remote.session.dbus.conf +41 -0
- data/config/start_dbus_session.sh +2 -0
- data/funky-examples/memory-agent/memory_agent.rb +5 -2
- data/funky-examples/memory-agent/memory_generator_agent.rb +5 -2
- data/funky-examples/talking-swift-agent/talking_swift_agent.rb +5 -2
- data/funky-examples/talking-swift-agent/text_generator.rb +6 -2
- data/funky-examples/visualizer-agent/flow_physics.rb +99 -0
- data/funky-examples/visualizer-agent/qt_visual.rb +117 -0
- data/funky-examples/visualizer-agent/visualizer_agent.rb +102 -0
- data/lib/robots.rb +3 -1
- data/lib/robots_agent.rb +69 -14
- data/lib/robots_infrastructure.rb +1 -1
- data/lib/robots_prototype.rb +4 -1
- data/lib/robots_xml.rb +12 -0
- metadata +16 -1
data/README.rdoc
CHANGED
@@ -1,11 +1,9 @@
|
|
1
1
|
= ROBOTS
|
2
2
|
|
3
|
-
Start your clocks boys and girls, it's weekend coding time!
|
4
|
-
|
5
|
-
On monday I want: working messaging, data-mapper/mysql memory agent, visualizer agent with agent introspection, slim agent that requests modules,classes over the net and evals them online.
|
6
|
-
|
7
3
|
Local messaging with dbus working, need to make service avahi discoverable.
|
8
4
|
|
5
|
+
Well, fork, dbus is not really remote capable right now. Ohh, I so much don't want to write that myself,... ;(...
|
6
|
+
|
9
7
|
Let's try to built a nice easy to use multiagent framework
|
10
8
|
based on all the cool stuff we can get for ruby.
|
11
9
|
|
@@ -17,6 +15,7 @@ rObOts!
|
|
17
15
|
sudo apt-get install avahi-daemon avahi-utils libavahi-client-dev libavahi-common-dev libavahi-compat-libdnssd-dev libnss-mdns libdbus-1-dev libdbus-glib-1-dev
|
18
16
|
#essential gems
|
19
17
|
sudo gem install pangdudu-ruby-dbus --source=http://gems.github.com
|
18
|
+
sudo gem install pangdudu-ruby-dbus-daemon --source=http://gems.github.com
|
20
19
|
sudo gem install pangdudu-rofl --source=http://gems.github.com
|
21
20
|
sudo gem install pangdudu-robots --source=http://gems.github.com
|
22
21
|
#for xml parsing and building
|
@@ -1,5 +1,4 @@
|
|
1
1
|
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
2
|
-
<!-- place this file under /etc/dbus-1/system.d/ -->
|
3
2
|
<busconfig>
|
4
3
|
<policy user="root">
|
5
4
|
<allow own="org.robots.Service" />
|
@@ -30,4 +29,3 @@
|
|
30
29
|
<allow send_destination="org.ruby.Service" send_interface="org.freedesktop.DBus.Introspectable" />
|
31
30
|
</policy>
|
32
31
|
</busconfig>
|
33
|
-
|
@@ -0,0 +1,41 @@
|
|
1
|
+
<!-- This configuration file controls the per-user-login-session message bus.
|
2
|
+
Add a session-local.conf and edit that rather than changing this
|
3
|
+
file directly. -->
|
4
|
+
|
5
|
+
<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-Bus Bus Configuration 1.0//EN"
|
6
|
+
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
7
|
+
<busconfig>
|
8
|
+
<!-- Our well-known bus type, don't change this -->
|
9
|
+
<type>session</type>
|
10
|
+
|
11
|
+
<!-- If we fork, keep the user's original umask to avoid affecting
|
12
|
+
the behavior of child processes. -->
|
13
|
+
<keep_umask/>
|
14
|
+
|
15
|
+
<!-- Listen to everything on tcp! -->
|
16
|
+
<listen>tcp:host=0.0.0.0,port=2687,family=ipv4</listen>
|
17
|
+
<!-- Listen on socket at this file location -->
|
18
|
+
<listen>unix:path=/tmp/robots_session_bus_socket</listen>
|
19
|
+
|
20
|
+
<standard_session_servicedirs />
|
21
|
+
|
22
|
+
<policy context="default">
|
23
|
+
<!-- Allow everything to be sent -->
|
24
|
+
<allow send_destination="*" eavesdrop="true"/>
|
25
|
+
<!-- Allow everything to be received -->
|
26
|
+
<allow eavesdrop="true"/>
|
27
|
+
<!-- Allow anyone to own anything -->
|
28
|
+
<allow own="*"/>
|
29
|
+
</policy>
|
30
|
+
|
31
|
+
<!-- Config files are placed here that among other things,
|
32
|
+
further restrict the above policy for specific services. -->
|
33
|
+
<include>org.robots.service.conf</include>
|
34
|
+
|
35
|
+
<!-- raise the service start timeout to 40 seconds as it can timeout
|
36
|
+
on the live cd on slow machines -->
|
37
|
+
<limit name="service_start_timeout">60000</limit>
|
38
|
+
|
39
|
+
<include if_selinux_enabled="yes" selinux_root_relative="yes">contexts/dbus_contexts</include>
|
40
|
+
|
41
|
+
</busconfig>
|
@@ -67,8 +67,11 @@ class MemoryAgent
|
|
67
67
|
include Robots
|
68
68
|
include RobotsXml
|
69
69
|
|
70
|
+
attr_accessor :roboname
|
71
|
+
|
70
72
|
def initialize
|
71
|
-
|
73
|
+
@roboname = "Active Memory" #name used in alive messages
|
74
|
+
ilog "#{@roboname} initialized"
|
72
75
|
end
|
73
76
|
|
74
77
|
#process an incoming memory message
|
@@ -245,6 +248,6 @@ ma.release_robots #start the robot agent module
|
|
245
248
|
loop do
|
246
249
|
sleep 1
|
247
250
|
#send an xml message over the system
|
248
|
-
ma.send_msg ma.
|
251
|
+
ma.send_msg ma.create_xml_alive_msg
|
249
252
|
end
|
250
253
|
#=end
|
@@ -12,8 +12,11 @@ class MemoryGeneratorAgent
|
|
12
12
|
include Robots
|
13
13
|
include RobotsXml
|
14
14
|
|
15
|
+
attr_accessor :roboname
|
16
|
+
|
15
17
|
def initialize
|
16
|
-
|
18
|
+
@roboname = "Memory Generator" #name used in alive messages
|
19
|
+
ilog "#{@roboname} initialized"
|
17
20
|
end
|
18
21
|
|
19
22
|
#ROBOTS message parsing stuff
|
@@ -45,7 +48,7 @@ mga.release_robots #start the robot agent module
|
|
45
48
|
loop do
|
46
49
|
sleep 3
|
47
50
|
#send an xml message over the system
|
48
|
-
mga.send_msg mga.
|
51
|
+
mga.send_msg mga.create_xml_alive_msg
|
49
52
|
#generate some bogus memory remember
|
50
53
|
mga.send_msg mga.create_xml_msg { |b| b.memory("something happened","action" => "remember");b.question("what happened?","action"=>"remember");b.keyword("stuff");b.keyword("happening") }
|
51
54
|
#generate bogus ask question
|
@@ -14,8 +14,11 @@ class SwiftAgent
|
|
14
14
|
include Robots
|
15
15
|
include RobotsXml
|
16
16
|
|
17
|
+
attr_accessor :roboname
|
18
|
+
|
17
19
|
def initialize
|
18
|
-
|
20
|
+
@roboname = "Swift Talker" #name used in alive messages
|
21
|
+
ilog "#{@roboname} initialized"
|
19
22
|
end
|
20
23
|
|
21
24
|
#method that gets called when a new message arrives
|
@@ -40,5 +43,5 @@ sa.release_robots #start the robot agent module
|
|
40
43
|
loop do
|
41
44
|
sleep 1
|
42
45
|
#send an xml message over the system
|
43
|
-
sa.send_msg sa.
|
46
|
+
sa.send_msg sa.create_xml_alive_msg
|
44
47
|
end
|
@@ -11,9 +11,12 @@ require 'robots_xml'
|
|
11
11
|
class TextGenerator
|
12
12
|
include Robots
|
13
13
|
include RobotsXml
|
14
|
+
|
15
|
+
attr_accessor :roboname
|
14
16
|
|
15
17
|
def initialize
|
16
|
-
|
18
|
+
@roboname = "Text Generator" #name used in alive messages
|
19
|
+
ilog "#{@roboname} initialized"
|
17
20
|
end
|
18
21
|
|
19
22
|
#method that gets called when a new message arrives
|
@@ -34,5 +37,6 @@ tg.release_robots #start the robot agent module
|
|
34
37
|
loop do
|
35
38
|
sleep 5
|
36
39
|
#send an xml message over the system
|
37
|
-
tg.send_msg tg.
|
40
|
+
tg.send_msg tg.create_xml_alive_msg
|
41
|
+
tg.send_msg tg.create_xml_msg { |b| b.speak("the robots are coming!"); b.info("timestamp" => "#{Time.now}") }
|
38
42
|
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'matrix'
|
3
|
+
#require 'unprof'
|
4
|
+
class Physics
|
5
|
+
include Math
|
6
|
+
|
7
|
+
attr_accessor :widht,:height,:objects,:singularity
|
8
|
+
|
9
|
+
def initialize width,height,parent=nil
|
10
|
+
@width,@height = width,height
|
11
|
+
@center = PhysicsObject.new(@width/2,@height/2)
|
12
|
+
@objects = []
|
13
|
+
@parent = parent
|
14
|
+
@force = Force.new
|
15
|
+
@singularity = false
|
16
|
+
start_loop
|
17
|
+
end
|
18
|
+
|
19
|
+
#add an object to the physics module
|
20
|
+
def add_object object
|
21
|
+
#object need attribute x,y to be valid
|
22
|
+
@objects << object
|
23
|
+
end
|
24
|
+
|
25
|
+
#apply the forces
|
26
|
+
def apply_physics
|
27
|
+
while @singularity
|
28
|
+
sleep 0.1
|
29
|
+
end
|
30
|
+
#apply force pushing nodes to center
|
31
|
+
@objects.each do |o|
|
32
|
+
delta = @force.center_mom(Vector.[](o.x-@center.x,o.y-@center.y))
|
33
|
+
o.x += delta[0]; o.y += delta[1]
|
34
|
+
end
|
35
|
+
#apply force pushing nodes apart
|
36
|
+
@objects.each do |o|
|
37
|
+
@objects.each do |oo|
|
38
|
+
unless o === oo
|
39
|
+
delta = @force.field_mom(Vector.[](o.x-oo.x,o.y-oo.y))
|
40
|
+
o.x += delta[0]; o.y += delta[1]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
#a loop
|
47
|
+
def start_loop
|
48
|
+
Thread.new do
|
49
|
+
loop {sleep(1/45);update_physics}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
#update the physics model
|
54
|
+
def update_physics
|
55
|
+
unless @parent.nil?
|
56
|
+
unless @parent.physics.nil?
|
57
|
+
apply_physics
|
58
|
+
@parent.update unless @parent.updating
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Force
|
65
|
+
#push nodes apart
|
66
|
+
def field_mom(delta)
|
67
|
+
r = delta.r
|
68
|
+
r = 1e-5 if r < 1e-5
|
69
|
+
delta *= 1/r
|
70
|
+
delta *= (1./(r**1.5 + 1e-5)*5000)
|
71
|
+
return delta
|
72
|
+
end
|
73
|
+
|
74
|
+
# delta is PVector, diff between the nodes, deg is the strength of the edge
|
75
|
+
def edge_mom(delta, deg)
|
76
|
+
r = delta.r
|
77
|
+
r = 1e-5 if r < 1e-5
|
78
|
+
delta *= 1/r
|
79
|
+
delta *= (r*4e-3)
|
80
|
+
return delta;
|
81
|
+
end
|
82
|
+
|
83
|
+
#pull nodes to center
|
84
|
+
def center_mom(delta)
|
85
|
+
r = delta.r
|
86
|
+
r = 1e-5 if r < 1e-5
|
87
|
+
delta *= 1/r
|
88
|
+
delta *= (r*-1e-2)
|
89
|
+
return delta;
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#simple physics object
|
94
|
+
class PhysicsObject
|
95
|
+
attr_accessor :x,:y
|
96
|
+
def initialize x,y
|
97
|
+
@x,@y = x,y
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'Qt4'
|
2
|
+
require 'flow_physics'
|
3
|
+
|
4
|
+
class Agent
|
5
|
+
attr_accessor :x, :y, :rel_angle, :agentname
|
6
|
+
|
7
|
+
def initialize agentname, x=0, y=0
|
8
|
+
@agentname = agentname
|
9
|
+
@x, @y= x, y
|
10
|
+
end
|
11
|
+
|
12
|
+
#get the relative angle
|
13
|
+
def get_rel_angle x,y
|
14
|
+
#angle in radian (up -0.5, left -1/1, down 0.5, right 0)
|
15
|
+
@rel_angle = Math.atan2(@y-y,@x-x)/Math::PI
|
16
|
+
#we want a range from -1 to +1
|
17
|
+
@rel_angle = @rel_angle * 180
|
18
|
+
return @rel_angle
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class DragInfo
|
23
|
+
attr_accessor :x, :y, :object
|
24
|
+
|
25
|
+
def initialize startx, starty, object=nil
|
26
|
+
@x, @y, @object = startx, starty, object
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class Gui < Qt::Widget
|
31
|
+
|
32
|
+
attr_accessor :agents,:physics, :updating
|
33
|
+
|
34
|
+
@@r = 15 #circle radius
|
35
|
+
|
36
|
+
def initialize(parent = nil)
|
37
|
+
super()
|
38
|
+
@agents = {}
|
39
|
+
setPalette(Qt::Palette.new(Qt::Color.new(250, 250, 250)))
|
40
|
+
setAutoFillBackground(true)
|
41
|
+
@cur1 = self.cursor
|
42
|
+
@cur2 = Qt::Cursor.new(Qt::PointingHandCursor)
|
43
|
+
self.mouseTracking = true
|
44
|
+
@updating = false
|
45
|
+
end
|
46
|
+
|
47
|
+
#add an agent to the model
|
48
|
+
def add_agent agent
|
49
|
+
@agents[agent.agentname] = agent
|
50
|
+
@physics.add_object agent unless @physics.nil?
|
51
|
+
puts "Agent: #{agent.agentname} added."
|
52
|
+
end
|
53
|
+
|
54
|
+
#gets called when a repaint is necessary
|
55
|
+
def paintEvent(event)
|
56
|
+
@updating = true
|
57
|
+
painter = Qt::Painter.new(self)
|
58
|
+
painter.setRenderHint(Qt::Painter::Antialiasing)
|
59
|
+
painter.setBrush(Qt::Brush.new(Qt::Color.new(255,250,250,150)))
|
60
|
+
@agents.each do |agentname,agent|
|
61
|
+
painter.resetMatrix
|
62
|
+
painter.translate(agent.x,agent.y)
|
63
|
+
painter.setPen(Qt::Pen.new(Qt::blue))
|
64
|
+
painter.drawEllipse Qt::Rect.new(-@@r,-@@r, 2*@@r, 2*@@r)
|
65
|
+
painter.setPen(Qt::Pen.new(Qt::blue))
|
66
|
+
painter.drawEllipse Qt::Rect.new(-3*@@r,-3*@@r, @@r/2, @@r/2)
|
67
|
+
painter.setPen(Qt::Pen.new(Qt::blue))
|
68
|
+
painter.drawLine Qt::LineF.new(-2.5*@@r,-2.5*@@r, -0.8*@@r, -0.8*@@r)
|
69
|
+
painter.setPen(Qt::Pen.new(Qt::blue))
|
70
|
+
painter.drawText(-2*@@r,-2.5*@@r,"#{agentname}")
|
71
|
+
end
|
72
|
+
painter.end()
|
73
|
+
@updating = false
|
74
|
+
end
|
75
|
+
|
76
|
+
#mouse press event
|
77
|
+
def mousePressEvent event
|
78
|
+
@draginfo = nil
|
79
|
+
@physics.singularity = true unless @physics.nil?
|
80
|
+
if event.buttons == Qt::RightButton
|
81
|
+
elsif event.buttons == Qt::LeftButton
|
82
|
+
agent = object_at(event.x, event.y)
|
83
|
+
@draginfo = DragInfo.new(event.x, event.y, agent) unless agent.nil?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
#returns object at x,y
|
88
|
+
def object_at x,y
|
89
|
+
@agents.each do |name,agent|
|
90
|
+
return agent if (agent.x-x)**2 + (agent.y-y)**2 <= @@r**2
|
91
|
+
end
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
|
95
|
+
#release mouse event
|
96
|
+
def mouseReleaseEvent event
|
97
|
+
update_drag_object event.x, event.y unless @draginfo.nil?
|
98
|
+
@physics.singularity = false unless @physics.nil?
|
99
|
+
end
|
100
|
+
|
101
|
+
#update dragged object
|
102
|
+
def update_drag_object x,y
|
103
|
+
@draginfo.object.x = x
|
104
|
+
@draginfo.object.y = y
|
105
|
+
update
|
106
|
+
end
|
107
|
+
|
108
|
+
#a mouse move event
|
109
|
+
def mouseMoveEvent event
|
110
|
+
self.cursor = object_at(event.x, event.y).nil? ? @cur1 : @cur2
|
111
|
+
if event.buttons == Qt::LeftButton and not @draginfo.nil?
|
112
|
+
update_drag_object event.x, event.y unless @draginfo.nil?
|
113
|
+
elsif event.buttons == Qt::RightButton
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'Qt4'
|
3
|
+
require 'flow_physics'
|
4
|
+
require 'qt_visual'
|
5
|
+
#require 'rofl' #sudo gem install pangdudu-rofl --source=http://gems.github.com
|
6
|
+
require 'robots' #sudo gem install pangdudu-robots --source=http://gems.github.com
|
7
|
+
require 'robots_xml'
|
8
|
+
|
9
|
+
class VisualizerAgent
|
10
|
+
include Robots
|
11
|
+
include RobotsXml
|
12
|
+
|
13
|
+
attr_accessor :roboname
|
14
|
+
|
15
|
+
def initialize argv
|
16
|
+
@roboname = "Visualizer" #name used in alive messages
|
17
|
+
ilog "#{@roboname} initialized"
|
18
|
+
@width, @height = 800,600
|
19
|
+
@app = Qt::Application.new(argv)
|
20
|
+
@agents = {} #thats where we register the agents in
|
21
|
+
end
|
22
|
+
|
23
|
+
#process an info message
|
24
|
+
def process_info xml_msg
|
25
|
+
infos = parse_xml_msg xml_msg,"//info"
|
26
|
+
infos.each do |i|
|
27
|
+
unless i.attributes["alive"].nil?
|
28
|
+
agentname = i.attributes["alive"]
|
29
|
+
@agents[agentname] = "#{i.attributes["timestamp"]}"
|
30
|
+
unless @gui.nil?
|
31
|
+
x_rnd = 23-rand(46)/2
|
32
|
+
y_rnd = 23-rand(46)/2
|
33
|
+
@gui.add_agent Agent.new(agentname,@width/2+x_rnd,@height/2+y_rnd) unless @gui.agents.has_key? agentname
|
34
|
+
end
|
35
|
+
#cleanup gui agent model - not yet implemented
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
#ROBOTS message parsing stuff
|
41
|
+
|
42
|
+
#method that gets called when a new message arrives
|
43
|
+
def receive_msg msg
|
44
|
+
check_for_interests msg
|
45
|
+
end
|
46
|
+
|
47
|
+
#check if this msg interests us
|
48
|
+
def check_for_interests xml_msg
|
49
|
+
#message filter callback looks like this now
|
50
|
+
info = parse_xml_msg xml_msg,"//info"
|
51
|
+
process_info xml_msg unless info.empty?
|
52
|
+
end
|
53
|
+
|
54
|
+
def start_qt_visualizer
|
55
|
+
@gui = Gui.new
|
56
|
+
@physics = Physics.new(@width,@height,@gui)
|
57
|
+
#dirty qt timer magic to make ruby threads work
|
58
|
+
sleep 0.5
|
59
|
+
block=Proc.new{ Thread.pass }
|
60
|
+
timer=Qt::Timer.new(@gui)
|
61
|
+
invoke=Qt::BlockInvocation.new(timer, block, "invoke()")
|
62
|
+
Qt::Object.connect(timer, SIGNAL("timeout()"), invoke, SLOT("invoke()"))
|
63
|
+
sleep 0.5
|
64
|
+
timer.start(1000/60) #in millis
|
65
|
+
#end of dirty timer hack
|
66
|
+
@gui.physics = @physics
|
67
|
+
@gui.resize(@width, @height)
|
68
|
+
@gui.show()
|
69
|
+
#just because it's fun
|
70
|
+
add_dbug_agents
|
71
|
+
@app.exec()
|
72
|
+
end
|
73
|
+
|
74
|
+
#debug method to add agents quickly
|
75
|
+
def add_dbug_agents
|
76
|
+
dbug_agents = ["Jeanette","Kurt","Maurice","Patrice"]
|
77
|
+
dbug_agents.each do |agentname|
|
78
|
+
x_rnd = 23-rand(46)/2
|
79
|
+
y_rnd = 23-rand(46)/2
|
80
|
+
@gui.add_agent Agent.new("dbug.#{agentname}",@width/2+x_rnd,@height/2+y_rnd)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
#start the app
|
86
|
+
va = VisualizerAgent.new(ARGV)
|
87
|
+
va.release_robots #start the robot agent module
|
88
|
+
|
89
|
+
Thread.new do
|
90
|
+
sleep 1
|
91
|
+
#build you own loop if you need one
|
92
|
+
loop do
|
93
|
+
sleep 1
|
94
|
+
#send an xml message over the system
|
95
|
+
#alive_msg = va.create_xml_alive_msg
|
96
|
+
#dlog "alive_msg: #{alive_msg.to_s}"
|
97
|
+
#va.send_msg alive_msg
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
va.start_qt_visualizer
|
102
|
+
|
data/lib/robots.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'socket' #to get hostname etc.
|
1
2
|
require 'rubygems'
|
2
3
|
require 'rofl' #gem install pangdudu-rofl --source=http://gems.github.com
|
3
4
|
#local requires, actually don't need them, just to let you know whats going on
|
@@ -5,7 +6,7 @@ require 'robots_agent'
|
|
5
6
|
|
6
7
|
module Robots
|
7
8
|
|
8
|
-
attr_accessor :robotsagent,:haz_robots
|
9
|
+
attr_accessor :robotsagent,:haz_robots,:hostname
|
9
10
|
|
10
11
|
#release the robots
|
11
12
|
def release_robots
|
@@ -27,6 +28,7 @@ module Robots
|
|
27
28
|
@haz_robots = @robotsagent.nil?
|
28
29
|
if @haz_robots
|
29
30
|
@robotsagent = Robot.new
|
31
|
+
@hostname = @robotsagent.hostname
|
30
32
|
@robotsagent.run
|
31
33
|
@robotsagent.add_listener self
|
32
34
|
end
|
data/lib/robots_agent.rb
CHANGED
@@ -1,27 +1,36 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'dbus' #gem install
|
2
|
+
require 'dbus' #gem install pangdudu-ruby-dbus --source=http://gems.github.com
|
3
|
+
require 'dbus-daemon' #gem install pangdudu-ruby-dbus-daemon --source=http://gems.github.com
|
3
4
|
require 'rofl' #gem install pangdudu-rofl --source=http://gems.github.com
|
4
5
|
#local requires, actually don't need them, just to let you know whats going on
|
5
6
|
require 'robots_infrastructure'
|
6
7
|
|
7
8
|
class Robot
|
8
|
-
attr_accessor :
|
9
|
-
attr_accessor :
|
9
|
+
attr_accessor :dbusdaemon #in case we use a custom dbus-daemon
|
10
|
+
attr_accessor :avahi #for mdns service discovery
|
11
|
+
attr_accessor :emitters,:infrastructure,:listeners #stuff a robot needs
|
12
|
+
attr_accessor :hostname #infos
|
10
13
|
|
11
14
|
def initialize
|
12
15
|
dlog "new Robot initialized."
|
16
|
+
@hostname = Socket.gethostname
|
17
|
+
@sessiontype = "system" #could be session,system or robots (use robots, if you want it to work over multiple hosts)
|
18
|
+
@daemonconfig = "~/.robots/config/remote.session.dbus.conf" #listens on path and tcp
|
19
|
+
@dbusdaemon = nil #we'll start our own dbus-daemon if we have to
|
20
|
+
@dbussession = nil #get_bus will get one for us
|
21
|
+
@coreservice = nil #the service we use to export objects with
|
13
22
|
@robotsservice = "org.robots.Service"
|
14
23
|
@emitterpath = "/org/robots/Service/Emitter"
|
15
24
|
@emitterinterface = "org.ruby.Service.EmitterInterface"
|
16
|
-
@coreservice = nil
|
17
25
|
@listeners = [] # listeners for incoming messages are here
|
18
26
|
@emitters = {} #holds emitters we use
|
19
27
|
@infrastructure = {} #holds infrastructure objects
|
20
|
-
@servicetypes = fill_servicetypes
|
28
|
+
@servicetypes = fill_servicetypes #refer to robots_infrastructure.rb
|
21
29
|
end
|
22
30
|
|
23
31
|
#start the mojo
|
24
32
|
def run
|
33
|
+
check_for_dbus_daemon if @sessiontype.eql? "robots" #will start a daemon if necessary
|
25
34
|
setup_robots_service
|
26
35
|
register_callbacks
|
27
36
|
#test_messages; #main_loop;
|
@@ -45,6 +54,28 @@ class Robot
|
|
45
54
|
the following methods are only called, if the robots service is not already running
|
46
55
|
=end
|
47
56
|
|
57
|
+
#check if a dbus-daemon suitable for robots is running, otherwise start one
|
58
|
+
def check_for_dbus_daemon
|
59
|
+
@daemonconfig = File.expand_path(@daemonconfig) #dbus-daemon won't accept otherwise
|
60
|
+
#ok, no config file, not good!
|
61
|
+
unless File.exist? @daemonconfig
|
62
|
+
wlog "no daemon config: #{@daemonconfig}!"
|
63
|
+
wlog "will sleep for 5 seconds,..."
|
64
|
+
sleep 5 #give the user time to realize
|
65
|
+
end
|
66
|
+
#if the config file is there
|
67
|
+
if File.exist? @daemonconfig
|
68
|
+
@dbusdaemon = DbusDaemon.new @daemonconfig
|
69
|
+
got_twins = @dbusdaemon.got_twin_daemon? #check if a daemon like this is already running
|
70
|
+
ilog "custom dbus-daemon is already running." if got_twins #inform user
|
71
|
+
unless got_twins #no suitable dbus-daemon running, start one
|
72
|
+
@dbusdaemon.start_daemon
|
73
|
+
ilog "custom dbus-daemon started and running, check \"ps x | grep \"dbus-daemon\", if plan a CTRL-C."
|
74
|
+
#@dbusdaemon.stop_daemon #must get called sometimes, super nasty, use " ps x | grep "dbus-daemon" "
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
48
79
|
#setup the infrastructure objects for communication
|
49
80
|
def init_robots_infrastructure
|
50
81
|
emitter = Emitter.new(@emitterpath,self)
|
@@ -60,7 +91,7 @@ class Robot
|
|
60
91
|
|
61
92
|
#start a service
|
62
93
|
def start_core_service service_name=@robotsservice
|
63
|
-
bus =
|
94
|
+
bus = get_bus
|
64
95
|
#first of all check if the service we want to launch is already started
|
65
96
|
dlog "skipping service: #{service_name} has already been started." if running? service_name
|
66
97
|
unless running? service_name
|
@@ -78,7 +109,7 @@ class Robot
|
|
78
109
|
def get_object_from_service service_name,obj_path,default_iface
|
79
110
|
begin
|
80
111
|
if running? service_name
|
81
|
-
bus =
|
112
|
+
bus = get_bus
|
82
113
|
ruby_service = bus.service(service_name)
|
83
114
|
obj = ruby_service.object(obj_path)
|
84
115
|
obj.introspect
|
@@ -94,10 +125,10 @@ class Robot
|
|
94
125
|
|
95
126
|
#register callback methods
|
96
127
|
def register_callbacks
|
97
|
-
bus = DBus::system_bus
|
98
128
|
#setup callbacks for infrastructure emitters
|
99
129
|
@emitters.each { |name,emitter| register_emitter_callback name,emitter }
|
100
130
|
#setup service browser
|
131
|
+
bus = DBus::SystemBus.instance #needs to be the system bus for the avahi stuff
|
101
132
|
proxy = bus.introspect("org.freedesktop.Avahi","/")
|
102
133
|
@avahi = proxy["org.freedesktop.Avahi.Server"]
|
103
134
|
@servicetypes.each { |name,type| register_service_callback name,type }
|
@@ -105,7 +136,8 @@ class Robot
|
|
105
136
|
|
106
137
|
#register an emitter callback
|
107
138
|
def register_emitter_callback name,emitter
|
108
|
-
bus =
|
139
|
+
bus = get_bus
|
140
|
+
#dlog "emitter.inspect #{emitter.inspect}"
|
109
141
|
dlog "registering callback for #{name} on path #{emitter.path}"
|
110
142
|
mr = DBus::MatchRule.new
|
111
143
|
mr.type = "signal"
|
@@ -128,7 +160,7 @@ class Robot
|
|
128
160
|
|
129
161
|
#builds a service type specific callback
|
130
162
|
def register_service_callback name,type
|
131
|
-
bus = DBus::
|
163
|
+
bus = DBus::SystemBus.instance #needs to be the system bus for the avahi stuff
|
132
164
|
sb = @avahi.ServiceBrowserNew(-1,-1,"_#{type}._tcp","local",0)
|
133
165
|
#now we start the match rule definition
|
134
166
|
mr = DBus::MatchRule.new
|
@@ -150,7 +182,7 @@ class Robot
|
|
150
182
|
|
151
183
|
#check if a service is running
|
152
184
|
def running? service_name
|
153
|
-
bus =
|
185
|
+
bus = get_bus
|
154
186
|
return bus.proxy.ListNames[0].include? service_name
|
155
187
|
end
|
156
188
|
|
@@ -174,6 +206,26 @@ class Robot
|
|
174
206
|
end
|
175
207
|
end
|
176
208
|
|
209
|
+
#get the bus session, cleaner then creating new sessions all over
|
210
|
+
def get_bus
|
211
|
+
if @dbussession.nil?
|
212
|
+
@dbussession = DBus::SystemBus.instance if @sessiontype.eql? "system"
|
213
|
+
@dbussession = DBus::SessionBus.instance if @sessiontype.eql? "session"
|
214
|
+
if @sessiontype.eql? "robots"
|
215
|
+
#i somehow feel bad for doing it like this with ENV[]:
|
216
|
+
@robots_socket_name = "unix:path=/tmp/robots_session_bus_socket" #look at: config/remote.session.dbus.conf
|
217
|
+
DBus.const_set("SessionSocketName", @robots_socket_name) #overwrite the modules constant
|
218
|
+
@dbussession = DBus::SessionBus.instance
|
219
|
+
end
|
220
|
+
end
|
221
|
+
#no point if this is still true :)
|
222
|
+
if @dbussession.nil?
|
223
|
+
elog "@dbussession is nil! will exit now, sorry."
|
224
|
+
exit(0)
|
225
|
+
end
|
226
|
+
return @dbussession
|
227
|
+
end
|
228
|
+
|
177
229
|
#functions used by the module end here
|
178
230
|
|
179
231
|
#dbus main loop
|
@@ -187,7 +239,7 @@ class Robot
|
|
187
239
|
def test_messages
|
188
240
|
Thread.new do
|
189
241
|
loop do
|
190
|
-
msg = "it worx from
|
242
|
+
msg = "it worx from robots agent!"
|
191
243
|
send_msg msg
|
192
244
|
sleep 1
|
193
245
|
end
|
@@ -195,9 +247,12 @@ class Robot
|
|
195
247
|
end
|
196
248
|
|
197
249
|
#list names of a proxy object
|
198
|
-
def list_names proxy
|
250
|
+
def list_names proxy=nil
|
251
|
+
if proxy.nil?
|
252
|
+
bus = get_bus
|
253
|
+
proxy = bus.proxy
|
254
|
+
end
|
199
255
|
dlog "listnames:"
|
200
256
|
proxy.ListNames[0].each { |name| dlog name }
|
201
|
-
@services.each { |name,service| dlog "service introspection for #{name} introspection: #{service.introspect}" }
|
202
257
|
end
|
203
258
|
end
|
@@ -2,7 +2,7 @@
|
|
2
2
|
this includes all the necessary dbus objects we need for the robots infrastructure
|
3
3
|
=end
|
4
4
|
require 'rubygems'
|
5
|
-
require 'dbus' #gem install
|
5
|
+
require 'dbus' #gem install pangdudu-ruby-dbus --source=http://gems.github.com
|
6
6
|
require 'rofl' #gem install pangdudu-rofl --source=http://gems.github.com
|
7
7
|
|
8
8
|
#basic emitter class
|
data/lib/robots_prototype.rb
CHANGED
@@ -12,7 +12,10 @@ class RobotsProto
|
|
12
12
|
include Robots
|
13
13
|
include RobotsXml
|
14
14
|
|
15
|
+
attr_accessor :roboname
|
16
|
+
|
15
17
|
def initialize
|
18
|
+
@roboname = "Robots Prototype" #name used in alive messages
|
16
19
|
ilog "RobotsProto initialized"
|
17
20
|
end
|
18
21
|
|
@@ -41,5 +44,5 @@ rp.release_robots #start the robot agent module
|
|
41
44
|
loop do
|
42
45
|
sleep 1
|
43
46
|
#send an xml message over the system
|
44
|
-
rp.send_msg rp.
|
47
|
+
rp.send_msg rp.create_xml_alive_msg
|
45
48
|
end
|
data/lib/robots_xml.rb
CHANGED
@@ -22,5 +22,17 @@ module RobotsXml
|
|
22
22
|
return xml = Hpricot.XML("<msg>parsing error</msg>")
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
#SPECIALS
|
27
|
+
|
28
|
+
#create an alive message
|
29
|
+
def create_xml_alive_msg
|
30
|
+
@hostname = "localhost" if @hostname.nil? #more fun with hostname
|
31
|
+
@roboname = "Nameless" if @roboname.nil? #at least it's nameless
|
32
|
+
robotsid = "#{@hostname}.#{@roboname.gsub(" ","_")}" #looks cooler
|
33
|
+
msg = create_xml_msg { |b| b.info("#{@roboname} alive","alive"=>"#{robotsid}","timestamp" => "#{Time.now}") }
|
34
|
+
return msg
|
35
|
+
end
|
36
|
+
|
25
37
|
end
|
26
38
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pangdudu-robots
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- pangdudu
|
@@ -22,6 +22,16 @@ dependencies:
|
|
22
22
|
- !ruby/object:Gem::Version
|
23
23
|
version: "0"
|
24
24
|
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: pangdudu-rofl
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
25
35
|
description: robots!
|
26
36
|
email: pangdudu@github
|
27
37
|
executables:
|
@@ -39,6 +49,11 @@ files:
|
|
39
49
|
- lib/robots_xml.rb
|
40
50
|
- lib/robots_prototype.rb
|
41
51
|
- config/org.robots.service.conf
|
52
|
+
- config/remote.session.dbus.conf
|
53
|
+
- config/start_dbus_session.sh
|
54
|
+
- funky-examples/visualizer-agent/flow_physics.rb
|
55
|
+
- funky-examples/visualizer-agent/qt_visual.rb
|
56
|
+
- funky-examples/visualizer-agent/visualizer_agent.rb
|
42
57
|
- funky-examples/talking-swift-agent/README
|
43
58
|
- funky-examples/talking-swift-agent/talking_swift_agent.rb
|
44
59
|
- funky-examples/talking-swift-agent/text_generator.rb
|