pangdudu-robots 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|